func TestConsul_ServiceTags(t *testing.T) { consulConfig := map[string]string{ "path": "seaTech/", "service": "astronomy", "service_tags": "deadbeef, cafeefac, deadc0de, feedface", "redirect_addr": "http://127.0.0.2:8200", "check_timeout": "6s", "address": "127.0.0.2", "scheme": "https", "token": "deadbeef-cafeefac-deadc0de-feedface", "max_parallel": "4", "disable_registration": "false", } logger := log.New(os.Stderr, "", log.LstdFlags) be, err := newConsulBackend(consulConfig, logger) if err != nil { t.Fatal(err) } c, ok := be.(*ConsulBackend) if !ok { t.Fatalf("failed to create physical Consul backend") } expected := []string{"deadbeef", "cafeefac", "deadc0de", "feedface"} actual := c.fetchServiceTags(false) if !strutil.EquivalentSlices(actual, append(expected, "standby")) { t.Fatalf("bad: expected:%s actual:%s", append(expected, "standby"), actual) } actual = c.fetchServiceTags(true) if !strutil.EquivalentSlices(actual, append(expected, "active")) { t.Fatalf("bad: expected:%s actual:%s", append(expected, "active"), actual) } }
// reconcileConsul queries the state of Vault Core and Consul and fixes up // Consul's state according to what's in Vault. reconcileConsul is called // without any locks held and can be run concurrently, therefore no changes // to ConsulBackend can be made in this method (i.e. wtb const receiver for // compiler enforced safety). func (c *ConsulBackend) reconcileConsul(registeredServiceID string, activeFunc activeFunction, sealedFunc sealedFunction) (serviceID string, err error) { // Query vault Core for its current state active := activeFunc() sealed := sealedFunc() agent := c.client.Agent() catalog := c.client.Catalog() serviceID = c.serviceID() // Get the current state of Vault from Consul var currentVaultService *api.CatalogService if services, _, err := catalog.Service(c.serviceName, "", &api.QueryOptions{AllowStale: true}); err == nil { for _, service := range services { if serviceID == service.ServiceID { currentVaultService = service break } } } tags := c.fetchServiceTags(active) var reregister bool switch { case currentVaultService == nil, registeredServiceID == "": reregister = true default: switch { case !strutil.EquivalentSlices(currentVaultService.ServiceTags, tags): reregister = true } } if !reregister { // When re-registration is not required, return a valid serviceID // to avoid registration in the next cycle. return serviceID, nil } service := &api.AgentServiceRegistration{ ID: serviceID, Name: c.serviceName, Tags: tags, Port: int(c.redirectPort), Address: c.redirectHost, EnableTagOverride: false, } checkStatus := api.HealthCritical if !sealed { checkStatus = api.HealthPassing } sealedCheck := &api.AgentCheckRegistration{ ID: c.checkID(), Name: "Vault Sealed Status", Notes: "Vault service is healthy when Vault is in an unsealed status and can become an active Vault server", ServiceID: serviceID, AgentServiceCheck: api.AgentServiceCheck{ TTL: c.checkTimeout.String(), Status: checkStatus, }, } if err := agent.ServiceRegister(service); err != nil { return "", errwrap.Wrapf(`service registration failed: {{err}}`, err) } if err := agent.CheckRegister(sealedCheck); err != nil { return serviceID, errwrap.Wrapf(`service check registration failed: {{err}}`, err) } return serviceID, nil }