184 lines
4.2 KiB
Go
184 lines
4.2 KiB
Go
package agent
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
|
|
"github.com/hashicorp/consul/agent/cache"
|
|
cachetype "github.com/hashicorp/consul/agent/cache-types"
|
|
"github.com/hashicorp/consul/agent/structs"
|
|
"golang.org/x/net/context"
|
|
)
|
|
|
|
type ServiceManager struct {
|
|
services map[string]*serviceConfigWatch
|
|
agent *Agent
|
|
|
|
sync.Mutex
|
|
}
|
|
|
|
func NewServiceManager(agent *Agent) *ServiceManager {
|
|
return &ServiceManager{
|
|
services: make(map[string]*serviceConfigWatch),
|
|
agent: agent,
|
|
}
|
|
}
|
|
|
|
func (s *ServiceManager) AddService(service *structs.NodeService, chkTypes []*structs.CheckType, persist bool, token string, source configSource) {
|
|
s.Lock()
|
|
defer s.Unlock()
|
|
|
|
reg := serviceRegistration{
|
|
service: service,
|
|
chkTypes: chkTypes,
|
|
persist: persist,
|
|
token: token,
|
|
source: source,
|
|
}
|
|
|
|
// If a service watch already exists, update the registration. Otherwise,
|
|
// start a new config watcher.
|
|
watch, ok := s.services[service.ID]
|
|
if ok {
|
|
watch.updateRegistration(®)
|
|
} else {
|
|
watch := &serviceConfigWatch{
|
|
registration: ®,
|
|
updateCh: make(chan cache.UpdateEvent, 1),
|
|
agent: s.agent,
|
|
}
|
|
|
|
s.services[service.ID] = watch
|
|
watch.Start()
|
|
}
|
|
}
|
|
|
|
func (s *ServiceManager) RemoveService(serviceID string) {
|
|
s.Lock()
|
|
defer s.Unlock()
|
|
|
|
serviceWatch, ok := s.services[serviceID]
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
serviceWatch.Stop()
|
|
delete(s.services, serviceID)
|
|
}
|
|
|
|
type serviceRegistration struct {
|
|
service *structs.NodeService
|
|
chkTypes []*structs.CheckType
|
|
persist bool
|
|
token string
|
|
source configSource
|
|
}
|
|
|
|
type serviceConfigWatch struct {
|
|
registration *serviceRegistration
|
|
config *structs.ServiceDefinition
|
|
|
|
agent *Agent
|
|
|
|
updateCh chan cache.UpdateEvent
|
|
ctx context.Context
|
|
cancelFunc func()
|
|
|
|
sync.RWMutex
|
|
}
|
|
|
|
func (s *serviceConfigWatch) Start() error {
|
|
s.ctx, s.cancelFunc = context.WithCancel(context.Background())
|
|
if err := s.startConfigWatch(); err != nil {
|
|
return err
|
|
}
|
|
go s.runWatch()
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *serviceConfigWatch) runWatch() {
|
|
for {
|
|
select {
|
|
case <-s.ctx.Done():
|
|
return
|
|
case event := <-s.updateCh:
|
|
s.handleUpdate(event)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *serviceConfigWatch) handleUpdate(event cache.UpdateEvent) {
|
|
switch event.Result.(type) {
|
|
case serviceRegistration:
|
|
s.Lock()
|
|
s.registration = event.Result.(*serviceRegistration)
|
|
s.Unlock()
|
|
case structs.ServiceConfigResponse:
|
|
s.Lock()
|
|
s.config = &event.Result.(*structs.ServiceConfigResponse).Definition
|
|
s.Unlock()
|
|
default:
|
|
s.agent.logger.Printf("[ERR] unknown update event type: %T", event)
|
|
}
|
|
|
|
service := s.mergeServiceConfig()
|
|
s.agent.logger.Printf("[INFO] updating service registration: %v, %v", service.ID, service.Meta)
|
|
/*err := s.agent.AddService(service, s.registration.chkTypes, s.registration.persist, s.registration.token, s.registration.source)
|
|
if err != nil {
|
|
s.agent.logger.Printf("[ERR] error updating service registration: %v", err)
|
|
}*/
|
|
}
|
|
|
|
func (s *serviceConfigWatch) startConfigWatch() error {
|
|
s.RLock()
|
|
name := s.registration.service.Service
|
|
s.RUnlock()
|
|
|
|
req := &structs.ServiceConfigRequest{
|
|
Name: name,
|
|
Datacenter: s.agent.config.Datacenter,
|
|
}
|
|
err := s.agent.cache.Notify(s.ctx, cachetype.ResolvedServiceConfigName, req, fmt.Sprintf("service-config:%s", name), s.updateCh)
|
|
|
|
return err
|
|
}
|
|
|
|
func (s *serviceConfigWatch) updateRegistration(registration *serviceRegistration) {
|
|
s.updateCh <- cache.UpdateEvent{
|
|
Result: registration,
|
|
}
|
|
}
|
|
|
|
func (s *serviceConfigWatch) mergeServiceConfig() *structs.NodeService {
|
|
return nil
|
|
}
|
|
|
|
func (s *serviceConfigWatch) Stop() {
|
|
s.cancelFunc()
|
|
}
|
|
|
|
/*
|
|
// Construct the service config request. This will be re-used with an updated
|
|
// index to watch for changes in the effective service config.
|
|
req := structs.ServiceConfigRequest{
|
|
Name: s.registration.service.Service,
|
|
Datacenter: s.agent.config.Datacenter,
|
|
QueryOptions: structs.QueryOptions{Token: s.agent.tokens.AgentToken()},
|
|
}
|
|
|
|
consul.RetryLoopBackoff(s.shutdownCh, func() error {
|
|
var reply structs.ServiceConfigResponse
|
|
if err := s.agent.RPC("ConfigEntry.ResolveServiceConfig", &req, &reply); err != nil {
|
|
return err
|
|
}
|
|
|
|
s.updateConfig(&reply.Definition)
|
|
|
|
req.QueryOptions.MinQueryIndex = reply.QueryMeta.Index
|
|
return nil
|
|
}, func(err error) {
|
|
s.agent.logger.Printf("[ERR] Error getting service config: %v", err)
|
|
})
|
|
*/
|