diff --git a/command/agent/agent.go b/command/agent/agent.go index 418c5fef4c..eb284efa8a 100644 --- a/command/agent/agent.go +++ b/command/agent/agent.go @@ -14,6 +14,9 @@ import ( "github.com/hashicorp/serf/serf" ) +// The internal service ID of the consul service +const internalServiceID = "consul" + /* The agent is the long running process that is run on every machine. It exposes an RPC interface that is used by the CLI to control the @@ -114,6 +117,14 @@ func Create(config *Config, logOutput io.Writer) (*Agent, error) { if config.Server { err = agent.setupServer() agent.state.SetIface(agent.server) + + // Automatically register the "consul" service on server nodes + consulService := structs.NodeService{ + Service: internalServiceID, + ID: internalServiceID, + Port: agent.config.Ports.Server, + } + agent.state.AddService(&consulService) } else { err = agent.setupClient() agent.state.SetIface(agent.client) @@ -452,6 +463,12 @@ func (a *Agent) AddService(service *structs.NodeService, chkType *CheckType) err // RemoveService is used to remove a service entry. // The agent will make a best effort to ensure it is deregistered func (a *Agent) RemoveService(serviceID string) error { + // Protect "consul" service from deletion by a user + if a.server != nil && serviceID == internalServiceID { + return fmt.Errorf( + "Deregistering the %s service is not allowed", internalServiceID) + } + // Remove service immeidately a.state.RemoveService(serviceID) diff --git a/command/agent/agent_test.go b/command/agent/agent_test.go index 3343c4afc1..1525bcefff 100644 --- a/command/agent/agent_test.go +++ b/command/agent/agent_test.go @@ -146,6 +146,11 @@ func TestAgent_RemoveService(t *testing.T) { t.Fatalf("err: %v", err) } + // Remove the consul service + if err := agent.RemoveService("consul"); err == nil { + t.Fatalf("should have errored") + } + srv := &structs.NodeService{ ID: "redis", Service: "redis", @@ -315,3 +320,14 @@ func TestAgent_UpdateCheck(t *testing.T) { t.Fatalf("bad: %v", status) } } + +func TestAgent_ConsulService(t *testing.T) { + dir, agent := makeAgent(t, nextConfig()) + defer os.RemoveAll(dir) + defer agent.Shutdown() + + services := agent.state.Services() + if _, ok := services[internalServiceID]; !ok { + t.Fatalf("%s service should be registered", internalServiceID) + } +} diff --git a/command/agent/user_event.go b/command/agent/user_event.go index 163b59975f..64891981f7 100644 --- a/command/agent/user_event.go +++ b/command/agent/user_event.go @@ -157,11 +157,6 @@ func (a *Agent) shouldProcessUserEvent(msg *UserEvent) bool { } if msg.ServiceFilter != "" { - // Handle "consul" service on server nodes - if a.server != nil && msg.ServiceFilter == "consul" { - return true - } - re, err := regexp.Compile(msg.ServiceFilter) if err != nil { a.logger.Printf("[ERR] agent: Failed to parse service filter '%s' for event '%s': %v",