diff --git a/main.go b/main.go index 1f4122c64..7ad715f93 100644 --- a/main.go +++ b/main.go @@ -106,7 +106,7 @@ func main() { if registry.Default == nil { return } - registry.Default.Deregister() + registry.Default.Deregister("") }) // init metrics early since that create the global metric registries @@ -284,6 +284,7 @@ func startServers(cfg *config.Config) { ConnFail: metrics.DefaultRegistry.GetCounter("tcp_sni.connfail"), Noroute: metrics.DefaultRegistry.GetCounter("tcp_sni.noroute"), } + if err := proxy.ListenAndServeTCP(l, h, tlscfg); err != nil { exit.Fatal("[FATAL] ", err) } @@ -354,7 +355,7 @@ func initBackend(cfg *config.Config) { } if err == nil { - if err = registry.Default.Register(); err == nil { + if err = registry.Default.Register(""); err == nil { return } } @@ -396,6 +397,8 @@ func watchBackend(cfg *config.Config, first chan bool) { continue } + registry.Default.UpdateAliases(next) + t, err := route.NewTable(next) if err != nil { log.Printf("[WARN] %s", err) diff --git a/registry/backend.go b/registry/backend.go index bec176754..494b3ad42 100644 --- a/registry/backend.go +++ b/registry/backend.go @@ -2,10 +2,13 @@ package registry type Backend interface { // Register registers fabio as a service in the registry. - Register() error + Register(serviceName string) error // Deregister removes the service registration for fabio. - Deregister() error + Deregister(serviceName string) error + + // UpdateAliases() is used to add new aliases and remove obsolete aliases + UpdateAliases(config string) error // ReadManual returns the current manual overrides and // their version as seen by the registry. diff --git a/registry/consul/backend.go b/registry/consul/backend.go index 921e2c222..1f2e7d8f9 100644 --- a/registry/consul/backend.go +++ b/registry/consul/backend.go @@ -6,6 +6,7 @@ import ( "github.com/fabiolb/fabio/config" "github.com/fabiolb/fabio/registry" + "github.com/fabiolb/fabio/route" "github.com/hashicorp/consul/api" ) @@ -15,7 +16,7 @@ type be struct { c *api.Client dc string cfg *config.Consul - dereg chan bool + dereg map[string](chan bool) } func NewBackend(cfg *config.Consul) (registry.Backend, error) { @@ -36,26 +37,47 @@ func NewBackend(cfg *config.Consul) (registry.Backend, error) { return &be{c: c, dc: dc, cfg: cfg}, nil } -func (b *be) Register() error { - if !b.cfg.Register { +func (b *be) Register(serviceName string) error { + if len(serviceName) == 0 { + serviceName = b.cfg.ServiceName + } + + if serviceName == b.cfg.ServiceName && !b.cfg.Register { log.Printf("[INFO] consul: Not registering fabio in consul") return nil } - service, err := serviceRegistration(b.cfg) + service, err := serviceRegistration(b.cfg, serviceName) if err != nil { return err } - b.dereg = register(b.c, service) + if b.dereg == nil { + b.dereg = make(map[string](chan bool)) + } + + b.dereg[serviceName] = register(b.c, service) + return nil } -func (b *be) Deregister() error { - if b.dereg != nil { - b.dereg <- true // trigger deregistration - <-b.dereg // wait for completion +func (b *be) Deregister(serviceName string) error { + if len(serviceName) == 0 { + for name, dereg := range b.dereg { + if dereg != nil { + log.Printf("[INFO]: consul: Deregistering %q", name) + dereg <- true // trigger deregistration + <-dereg // wait for completion + } + } + } else { + if dereg := b.dereg[serviceName]; dereg != nil { + dereg <- true + <-dereg + delete(b.dereg, serviceName) + } } + return nil } @@ -100,6 +122,54 @@ func (b *be) WatchNoRouteHTML() chan string { return html } +func (b *be) UpdateAliases(config string) error { + defs, err := route.Parse(config) + if err != nil { + return err + } + + var aliases []string + + if b.cfg.Register { + aliases = append(aliases, b.cfg.ServiceName) + } + + for _, d := range defs { + if d.Opts["alias"] != "" { + log.Printf("[DEBUG]: consul: Service %q wants alias %q", d.Service, d.Opts["alias"]) + aliases = append(aliases, d.Opts["alias"]) + } + } + + // register new aliases + for _, alias := range aliases { + if _, hasAlias := b.dereg[alias]; hasAlias { + log.Printf("[DEBUG]: consul: Skipping registration for existing alias %q", alias) + continue + } + log.Printf("[DEBUG]: consul: Registering new alias %q", alias) + err := registry.Default.Register(alias) + if err != nil { + log.Printf("[WARN] %q", err) + } + } + + // deregister old aliases + for alias := range b.dereg { + if stringInSlice(alias, aliases) { + log.Printf("[DEBUG]: consul: Keeping alias %q", alias) + continue + } + log.Printf("[DEBUG]: consul: Deregister alias %q", alias) + err := registry.Default.Deregister(alias) + if err != nil { + log.Printf("[WARN] %s", err) + } + } + + return nil +} + // datacenter returns the datacenter of the local agent func datacenter(c *api.Client) (string, error) { self, err := c.Agent().Self() @@ -117,3 +187,12 @@ func datacenter(c *api.Client) (string, error) { } return dc, nil } + +func stringInSlice(str string, strSlice []string) bool { + for _, s := range strSlice { + if s == str { + return true + } + } + return false +} diff --git a/registry/consul/register.go b/registry/consul/register.go index 0ed7d01bc..49e0e4127 100644 --- a/registry/consul/register.go +++ b/registry/consul/register.go @@ -38,10 +38,11 @@ func register(c *api.Client, service *api.AgentServiceRegistration) chan bool { register := func() string { if err := c.Agent().ServiceRegister(service); err != nil { - log.Printf("[ERROR] consul: Cannot register fabio in consul. %s", err) + log.Printf("[ERROR] consul: Cannot register fabio [name:%q] in Consul. %s", service.Name, err) return "" } + log.Printf("[INFO] consul: Registered fabio with name %q", service.Name) log.Printf("[INFO] consul: Registered fabio with id %q", service.ID) log.Printf("[INFO] consul: Registered fabio with address %q", service.Address) log.Printf("[INFO] consul: Registered fabio with tags %q", strings.Join(service.Tags, ",")) @@ -51,7 +52,7 @@ func register(c *api.Client, service *api.AgentServiceRegistration) chan bool { } deregister := func(serviceID string) { - log.Printf("[INFO] consul: Deregistering fabio") + log.Printf("[INFO] consul: Deregistering %s", service.Name) c.Agent().ServiceDeregister(serviceID) } @@ -76,7 +77,7 @@ func register(c *api.Client, service *api.AgentServiceRegistration) chan bool { return dereg } -func serviceRegistration(cfg *config.Consul) (*api.AgentServiceRegistration, error) { +func serviceRegistration(cfg *config.Consul, serviceName string) (*api.AgentServiceRegistration, error) { hostname, err := os.Hostname() if err != nil { return nil, err @@ -101,7 +102,7 @@ func serviceRegistration(cfg *config.Consul) (*api.AgentServiceRegistration, err } } - serviceID := fmt.Sprintf("%s-%s-%d", cfg.ServiceName, hostname, port) + serviceID := fmt.Sprintf("%s-%s-%d", serviceName, hostname, port) checkURL := fmt.Sprintf("%s://%s:%d/health", cfg.CheckScheme, ip, port) if ip.To16() != nil { @@ -110,7 +111,7 @@ func serviceRegistration(cfg *config.Consul) (*api.AgentServiceRegistration, err service := &api.AgentServiceRegistration{ ID: serviceID, - Name: cfg.ServiceName, + Name: serviceName, Address: ip.String(), Port: port, Tags: cfg.ServiceTags, diff --git a/registry/static/backend.go b/registry/static/backend.go index bf686da56..14043a497 100644 --- a/registry/static/backend.go +++ b/registry/static/backend.go @@ -15,11 +15,15 @@ func NewBackend(cfg *config.Static) (registry.Backend, error) { return &be{cfg}, nil } -func (b *be) Register() error { +func (b *be) Register(serviceName string) error { return nil } -func (b *be) Deregister() error { +func (b *be) Deregister(serviceName string) error { + return nil +} + +func (b *be) UpdateAliases(config string) error { return nil }