diff --git a/config.yaml b/config.yaml index 2e8c7cc..e002495 100644 --- a/config.yaml +++ b/config.yaml @@ -11,6 +11,9 @@ agent: consul_query_interval: 5m # token to authenticate client if consul requires it consul_token: 00000000-0000-0000-0000-000000000000 + # this tag must be present in consul for Gocast to pickup the service + # by default its enable_gocast + consul_match_tag: enable_gocast bgp: local_as: 12345 diff --git a/config/config.go b/config/config.go index ffdd404..b3b6755 100644 --- a/config/config.go +++ b/config/config.go @@ -16,6 +16,7 @@ type AgentConfig struct { ConsulAddr string `yaml:"consul_addr"` ConsulQueryInterval time.Duration `yaml:"consul_query_interval"` ConsulToken string `yaml:"consul_token"` + ConsulMatchTag string `yaml:"consul_match_tag"` } type BgpConfig struct { diff --git a/controller/consul.go b/controller/consul.go index 18af058..0cd5cac 100644 --- a/controller/consul.go +++ b/controller/consul.go @@ -17,7 +17,7 @@ const ( consulNodeEnv = "CONSUL_NODE" consulToken = "CONSUL_TOKEN" allowStale = "CONSUL_STALE" - matchTag = "enable_gocast" + defaultmatchTag = "enable_gocast" nodeURL = "/catalog/node" remoteHealthCheckurl = "/health/checks" localHealthCheckurl = "/agent/checks" @@ -32,10 +32,11 @@ type Client struct { } type ConsulMon struct { - addr string - token string - node string - client Clienter + addr string + token string + node string + matchTag string + client Clienter } type ConsulServiceData struct { @@ -55,12 +56,15 @@ func contains(inp []string, elem string) bool { return false } -func NewConsulMon(addr string, token string) (*ConsulMon, error) { +func NewConsulMon(addr string, token string, matchTag string) (*ConsulMon, error) { node := os.Getenv(consulNodeEnv) if node == "" { return nil, fmt.Errorf("%s env variable not set", consulNodeEnv) } - return &ConsulMon{addr: addr, token: token, node: node, client: &http.Client{Timeout: 10 * time.Second}}, nil + if matchTag == "" { + matchTag = defaultmatchTag + } + return &ConsulMon{addr: addr, token: token, node: node, client: &http.Client{Timeout: 10 * time.Second}, matchTag: matchTag}, nil } func getHTTPReq(httpMethod string, addr string, tokenFrmCfg string) (*http.Request, error) { @@ -95,10 +99,10 @@ func (c *ConsulMon) queryServices() ([]*App, error) { defer resp.Body.Close() var consulData ConsulServiceData if err := json.NewDecoder(resp.Body).Decode(&consulData); err != nil { - return apps, fmt.Errorf("Unable to decode consul data: %v", err) + return apps, fmt.Errorf("unable to decode consul data: %v", err) } for _, service := range consulData.Services { - if !contains(service.Tags, matchTag) { + if !contains(service.Tags, c.matchTag) { continue } var ( @@ -170,7 +174,7 @@ func (c *ConsulMon) healthCheckLocal(service string) (bool, error) { return false, nil } } - return false, fmt.Errorf("No local healthcheck info found for service %s on node %s in consul", service, c.node) + return false, fmt.Errorf("no local healthcheck info found for service %s on node %s in consul", service, c.node) } // healthCheckRemote queries the consul cluster's healthcheck endpoint to perform service healthchecks @@ -202,7 +206,7 @@ func (c *ConsulMon) healthCheckRemote(service string) (bool, error) { return false, nil } } - return false, fmt.Errorf("No healthcheck info found for node %s in consul", c.node) + return false, fmt.Errorf("no healthcheck info found for node %s in consul", c.node) } // healthCheck determines if we should use the local agent diff --git a/controller/consul_test.go b/controller/consul_test.go index 2e1d9da..101a369 100644 --- a/controller/consul_test.go +++ b/controller/consul_test.go @@ -2,7 +2,7 @@ package controller import ( "bytes" - "io/ioutil" + "io" "net/http" "os" "testing" @@ -119,13 +119,13 @@ func TestQueryServices(t *testing.T) { a := assert.New(t) client := &MockClient{} cm := &ConsulMon{ - addr: "foo", node: "test", client: client, + addr: "foo", node: "test", client: client, matchTag: "enable_gocast", } // test valid app client.do = func(*http.Request) (*http.Response, error) { b := bytes.NewBuffer([]byte(mockConsulData["single-app"])) - return &http.Response{Body: ioutil.NopCloser(b), StatusCode: http.StatusOK}, nil + return &http.Response{Body: io.NopCloser(b), StatusCode: http.StatusOK}, nil } apps, err := cm.queryServices() if err != nil { @@ -140,7 +140,7 @@ func TestQueryServices(t *testing.T) { // test no match client.do = func(*http.Request) (*http.Response, error) { b := bytes.NewBuffer([]byte(mockConsulData["single-app-no-match"])) - return &http.Response{Body: ioutil.NopCloser(b), StatusCode: http.StatusOK}, nil + return &http.Response{Body: io.NopCloser(b), StatusCode: http.StatusOK}, nil } apps, err = cm.queryServices() if err != nil { @@ -151,7 +151,7 @@ func TestQueryServices(t *testing.T) { // test missing vip client.do = func(*http.Request) (*http.Response, error) { b := bytes.NewBuffer([]byte(mockConsulData["single-app-no-vip"])) - return &http.Response{Body: ioutil.NopCloser(b), StatusCode: http.StatusOK}, nil + return &http.Response{Body: io.NopCloser(b), StatusCode: http.StatusOK}, nil } apps, _ = cm.queryServices() a.Equal(0, len(apps)) @@ -160,13 +160,13 @@ func TestQueryServices(t *testing.T) { func TestHealthCheck(t *testing.T) { a := assert.New(t) client := &MockClient{} - cm := &ConsulMon{node: "test-node1", client: client} + cm := &ConsulMon{node: "test-node1", client: client, matchTag: "enable_gocast"} // test remote checks cm.addr = "http://remote/check" client.do = func(*http.Request) (*http.Response, error) { b := bytes.NewBuffer([]byte(mockConsulCheckData["remote-pass"])) - return &http.Response{Body: ioutil.NopCloser(b), StatusCode: http.StatusOK}, nil + return &http.Response{Body: io.NopCloser(b), StatusCode: http.StatusOK}, nil } check, err := cm.healthCheck("test-service") if err != nil { @@ -175,7 +175,7 @@ func TestHealthCheck(t *testing.T) { a.True(check) client.do = func(*http.Request) (*http.Response, error) { b := bytes.NewBuffer([]byte(mockConsulCheckData["remote-fail"])) - return &http.Response{Body: ioutil.NopCloser(b), StatusCode: http.StatusOK}, nil + return &http.Response{Body: io.NopCloser(b), StatusCode: http.StatusOK}, nil } check, _ = cm.healthCheck("test-service") a.False(check) @@ -184,7 +184,7 @@ func TestHealthCheck(t *testing.T) { cm.addr = "http://localhost/check" client.do = func(*http.Request) (*http.Response, error) { b := bytes.NewBuffer([]byte(mockConsulCheckData["local-pass"])) - return &http.Response{Body: ioutil.NopCloser(b), StatusCode: http.StatusOK}, nil + return &http.Response{Body: io.NopCloser(b), StatusCode: http.StatusOK}, nil } check, _ = cm.healthCheck("test-service") if err != nil { @@ -194,7 +194,7 @@ func TestHealthCheck(t *testing.T) { cm.addr = "http://127.0.0.1/check" client.do = func(*http.Request) (*http.Response, error) { b := bytes.NewBuffer([]byte(mockConsulCheckData["local-fail"])) - return &http.Response{Body: ioutil.NopCloser(b), StatusCode: http.StatusOK}, nil + return &http.Response{Body: io.NopCloser(b), StatusCode: http.StatusOK}, nil } check, _ = cm.healthCheck("test-service") a.False(check) diff --git a/controller/monitor.go b/controller/monitor.go index f5b9ddf..da1d73d 100644 --- a/controller/monitor.go +++ b/controller/monitor.go @@ -84,7 +84,7 @@ func NewMonitor(config *c.Config) *MonitorMgr { cleanups: make(map[string]chan bool), } if config.Agent.ConsulAddr != "" { - cmon, err := NewConsulMon(config.Agent.ConsulAddr, config.Agent.ConsulToken) + cmon, err := NewConsulMon(config.Agent.ConsulAddr, config.Agent.ConsulToken, config.Agent.ConsulMatchTag) if err != nil { glog.Errorf("Failed to start consul monitor: %v", err) } else { @@ -184,7 +184,7 @@ func (m *MonitorMgr) Add(app *App) { } // Remove removes an app from monitor manager, stops BGP -/// announcement and cleans up state +// / announcement and cleans up state func (m *MonitorMgr) Remove(appName string) { m.monMu.Lock() defer m.monMu.Unlock() diff --git a/controller/system.go b/controller/system.go index 6e6797c..0ae6c9c 100644 --- a/controller/system.go +++ b/controller/system.go @@ -27,7 +27,7 @@ func gateway(family int) (net.IP, error) { cmdList := getCmdList(cmd) out, err := exec.Command(execCmd, cmdList...).Output() if err != nil { - return nil, fmt.Errorf("Failed to execute command: %s: %v", cmd, err) + return nil, fmt.Errorf("failed to execute command: %s: %v", cmd, err) } return net.ParseIP(strings.TrimSpace(string(out))), nil } @@ -41,7 +41,7 @@ func via(dest net.IP) (net.IP, error) { cmdList := getCmdList(cmd) out, err := exec.Command(execCmd, cmdList...).Output() if err != nil { - return nil, fmt.Errorf("Failed to execute command: %s: %v", cmd, err) + return nil, fmt.Errorf("failed to execute command: %s: %v", cmd, err) } if string(out) == "" { // assume the provided dest is the next hop @@ -63,7 +63,7 @@ func localAddress(gw net.IP) (net.IP, error) { } } } - return nil, fmt.Errorf("Unable to find local address") + return nil, fmt.Errorf("unable to find local address") } func addLoopback(name string, addr *net.IPNet) error { @@ -82,7 +82,7 @@ func addLoopback(name string, addr *net.IPNet) error { cmdList := getCmdList(cmd) _, err := exec.Command(execCmd, cmdList...).Output() if err != nil { - return fmt.Errorf("Failed to Add loopback command: %s: %v", cmd, err) + return fmt.Errorf("failed to Add loopback command: %s: %v", cmd, err) } return nil } @@ -97,7 +97,7 @@ func deleteLoopback(addr *net.IPNet) error { cmdList := getCmdList(cmd) _, err := exec.Command(execCmd, cmdList...).Output() if err != nil { - return fmt.Errorf("Failed to delete loopback command: %s: %v", cmd, err) + return fmt.Errorf("failed to delete loopback command: %s: %v", cmd, err) } return nil } diff --git a/controller/system_test.go b/controller/system_test.go index 44b2219..4f5482c 100644 --- a/controller/system_test.go +++ b/controller/system_test.go @@ -12,9 +12,14 @@ import ( func TestGateway(t *testing.T) { execCmd = os.Args[0] os.Setenv("test_name", "test_gateway") - gw, err := gateway() + gw, err := gateway(4) assert.Nil(t, err) assert.Equal(t, "10.1.1.1", gw.String()) + + os.Setenv("test_name", "test_gateway_v6") + gw, err = gateway(6) + assert.Nil(t, err) + assert.Equal(t, "2001:dead:beef::1", gw.String()) } func TestVia(t *testing.T) { @@ -28,6 +33,11 @@ func TestVia(t *testing.T) { ip, err = via(net.ParseIP("10.1.4.1")) assert.Nil(t, err) assert.Equal(t, "10.1.4.1", ip.String()) + + os.Setenv("test_name", "test_via_v6") + ip, err = via(net.ParseIP("2001:dead:beef::100")) + assert.Nil(t, err) + assert.Equal(t, "2001:dead:beef::1", ip.String()) } func TestAddLoopback(t *testing.T) { @@ -41,14 +51,23 @@ func TestAddLoopback(t *testing.T) { _, ipnet, _ = net.ParseCIDR("1.1.1.1/32") err = addLoopback("test_app", ipnet) assert.NotNil(t, err) + + os.Setenv("test_name", "test_add_v6") + _, ipnet, _ = net.ParseCIDR("2001:dead:beef:1001::100/64") + err = addLoopback("test_app", ipnet) + assert.Nil(t, err) } func TestMain(m *testing.M) { switch os.Getenv("test_name") { case "test_gateway": fmt.Println("10.1.1.1") + case "test_gateway_v6": + fmt.Println("2001:dead:beef::1") case "test_via": fmt.Println("10.1.2.1") + case "test_via_v6": + fmt.Println("2001:dead:beef::1") case "test_via_none": break case "test_add_fail": diff --git a/gocast b/gocast deleted file mode 100755 index 05ab58d..0000000 Binary files a/gocast and /dev/null differ