2015-02-15 02:00:47 +03:00
|
|
|
package registry
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/hashicorp/consul/api"
|
|
|
|
"github.com/hashicorp/consul/watch"
|
|
|
|
)
|
|
|
|
|
2015-05-23 22:04:16 +03:00
|
|
|
type consulWatcher struct {
|
|
|
|
Registry *consulRegistry
|
2015-02-15 02:00:47 +03:00
|
|
|
wp *watch.WatchPlan
|
|
|
|
watchers map[string]*watch.WatchPlan
|
|
|
|
}
|
|
|
|
|
|
|
|
type serviceWatcher struct {
|
|
|
|
name string
|
|
|
|
}
|
|
|
|
|
2015-06-01 20:55:27 +03:00
|
|
|
func newConsulWatcher(cr *consulRegistry) (Watcher, error) {
|
2015-05-23 22:04:16 +03:00
|
|
|
cw := &consulWatcher{
|
|
|
|
Registry: cr,
|
|
|
|
watchers: make(map[string]*watch.WatchPlan),
|
|
|
|
}
|
|
|
|
|
|
|
|
wp, err := watch.Parse(map[string]interface{}{"type": "services"})
|
2015-06-01 20:55:27 +03:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2015-05-23 22:04:16 +03:00
|
|
|
}
|
|
|
|
|
2015-06-01 20:55:27 +03:00
|
|
|
wp.Handler = cw.Handle
|
|
|
|
go wp.Run(cr.Address)
|
|
|
|
cw.wp = wp
|
|
|
|
|
|
|
|
return cw, nil
|
2015-05-23 22:04:16 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func (cw *consulWatcher) serviceHandler(idx uint64, data interface{}) {
|
2015-02-15 02:00:47 +03:00
|
|
|
entries, ok := data.([]*api.ServiceEntry)
|
|
|
|
if !ok {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-11-08 04:48:48 +03:00
|
|
|
serviceMap := map[string]*Service{}
|
|
|
|
serviceName := ""
|
2015-02-15 02:00:47 +03:00
|
|
|
|
|
|
|
for _, e := range entries {
|
2015-11-08 04:48:48 +03:00
|
|
|
serviceName = e.Service.Service
|
|
|
|
id := e.Node.Node
|
|
|
|
key := e.Service.Service + e.Service.ID
|
|
|
|
version := e.Service.ID
|
|
|
|
|
|
|
|
// We're adding service version but
|
|
|
|
// don't want to break backwards compatibility
|
|
|
|
if id == version {
|
|
|
|
key = e.Service.Service + "default"
|
|
|
|
version = ""
|
|
|
|
}
|
|
|
|
|
|
|
|
svc, ok := serviceMap[key]
|
|
|
|
if !ok {
|
|
|
|
svc = &Service{
|
|
|
|
Endpoints: decodeEndpoints(e.Service.Tags),
|
|
|
|
Name: e.Service.Service,
|
|
|
|
Version: version,
|
|
|
|
}
|
|
|
|
serviceMap[key] = svc
|
|
|
|
}
|
|
|
|
|
|
|
|
svc.Nodes = append(svc.Nodes, &Node{
|
|
|
|
Id: id,
|
2015-05-26 00:14:28 +03:00
|
|
|
Address: e.Node.Address,
|
|
|
|
Port: e.Service.Port,
|
2015-05-27 00:39:48 +03:00
|
|
|
Metadata: decodeMetadata(e.Service.Tags),
|
2015-02-15 02:00:47 +03:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
cw.Registry.mtx.Lock()
|
2015-11-08 04:48:48 +03:00
|
|
|
var services []*Service
|
|
|
|
for _, service := range serviceMap {
|
|
|
|
services = append(services, service)
|
|
|
|
}
|
|
|
|
cw.Registry.services[serviceName] = services
|
2015-02-15 02:00:47 +03:00
|
|
|
cw.Registry.mtx.Unlock()
|
|
|
|
}
|
|
|
|
|
2015-05-23 22:04:16 +03:00
|
|
|
func (cw *consulWatcher) Handle(idx uint64, data interface{}) {
|
2015-02-15 02:00:47 +03:00
|
|
|
services, ok := data.(map[string][]string)
|
|
|
|
if !ok {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// add new watchers
|
|
|
|
for service, _ := range services {
|
|
|
|
if _, ok := cw.watchers[service]; ok {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
wp, err := watch.Parse(map[string]interface{}{
|
|
|
|
"type": "service",
|
|
|
|
"service": service,
|
|
|
|
})
|
|
|
|
if err == nil {
|
|
|
|
wp.Handler = cw.serviceHandler
|
|
|
|
go wp.Run(cw.Registry.Address)
|
|
|
|
cw.watchers[service] = wp
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cw.Registry.mtx.RLock()
|
|
|
|
rservices := cw.Registry.services
|
|
|
|
cw.Registry.mtx.RUnlock()
|
|
|
|
|
|
|
|
// remove unknown services from registry
|
|
|
|
for service, _ := range rservices {
|
|
|
|
if _, ok := services[service]; !ok {
|
|
|
|
cw.Registry.mtx.Lock()
|
|
|
|
delete(cw.Registry.services, service)
|
|
|
|
cw.Registry.mtx.Unlock()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// remove unknown services from watchers
|
|
|
|
for service, w := range cw.watchers {
|
|
|
|
if _, ok := services[service]; !ok {
|
|
|
|
w.Stop()
|
|
|
|
delete(cw.watchers, service)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-23 22:04:16 +03:00
|
|
|
func (cw *consulWatcher) Stop() {
|
2015-02-15 02:00:47 +03:00
|
|
|
if cw.wp == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
cw.wp.Stop()
|
|
|
|
}
|