From 23536f2b97010c296e86d8e862f2631aa1b43a16 Mon Sep 17 00:00:00 2001 From: James Phillips Date: Wed, 18 Nov 2015 07:40:02 -0800 Subject: [PATCH] Adds Docker checks support to client API. Also changed `DockerContainerId` to `DockerContainerID`, and updated the agent API docs to reflect their support for Docker checks. --- api/agent.go | 16 ++++--- api/agent_test.go | 44 +++++++++++++++++++ command/agent/agent.go | 2 +- command/agent/check.go | 12 ++--- command/agent/check_test.go | 8 ++-- command/agent/config.go | 2 +- command/agent/config_test.go | 2 +- .../docs/agent/http/agent.html.markdown | 6 +++ 8 files changed, 72 insertions(+), 20 deletions(-) diff --git a/api/agent.go b/api/agent.go index 2b950d0a3..e4466a651 100644 --- a/api/agent.go +++ b/api/agent.go @@ -63,13 +63,15 @@ type AgentCheckRegistration struct { // AgentServiceCheck is used to create an associated // check for a service type AgentServiceCheck struct { - Script string `json:",omitempty"` - Interval string `json:",omitempty"` - Timeout string `json:",omitempty"` - TTL string `json:",omitempty"` - HTTP string `json:",omitempty"` - TCP string `json:",omitempty"` - Status string `json:",omitempty"` + Script string `json:",omitempty"` + DockerContainerID string `json:",omitempty"` + Shell string `json:",omitempty"` // Only supported for Docker. + Interval string `json:",omitempty"` + Timeout string `json:",omitempty"` + TTL string `json:",omitempty"` + HTTP string `json:",omitempty"` + TCP string `json:",omitempty"` + Status string `json:",omitempty"` } type AgentServiceChecks []*AgentServiceCheck diff --git a/api/agent_test.go b/api/agent_test.go index 358c12a6c..c49696aeb 100644 --- a/api/agent_test.go +++ b/api/agent_test.go @@ -387,6 +387,50 @@ func TestAgent_Checks_serviceBound(t *testing.T) { } } +func TestAgent_Checks_Docker(t *testing.T) { + t.Parallel() + c, s := makeClient(t) + defer s.Stop() + + agent := c.Agent() + + // First register a service + serviceReg := &AgentServiceRegistration{ + Name: "redis", + } + if err := agent.ServiceRegister(serviceReg); err != nil { + t.Fatalf("err: %v", err) + } + + // Register a check bound to the service + reg := &AgentCheckRegistration{ + Name: "redischeck", + ServiceID: "redis", + AgentServiceCheck: AgentServiceCheck{ + DockerContainerID: "f972c95ebf0e", + Script: "/bin/true", + Shell: "/bin/bash", + Interval: "10s", + }, + } + if err := agent.CheckRegister(reg); err != nil { + t.Fatalf("err: %v", err) + } + + checks, err := agent.Checks() + if err != nil { + t.Fatalf("err: %v", err) + } + + check, ok := checks["redischeck"] + if !ok { + t.Fatalf("missing check: %v", checks) + } + if check.ServiceID != "redis" { + t.Fatalf("missing service association for check: %v", check) + } +} + func TestAgent_Join(t *testing.T) { t.Parallel() c, s := makeClient(t) diff --git a/command/agent/agent.go b/command/agent/agent.go index a9e336328..afe247e1d 100644 --- a/command/agent/agent.go +++ b/command/agent/agent.go @@ -919,7 +919,7 @@ func (a *Agent) AddCheck(check *structs.HealthCheck, chkType *CheckType, persist dockerCheck := &CheckDocker{ Notify: &a.state, CheckID: check.CheckID, - DockerContainerId: chkType.DockerContainerId, + DockerContainerID: chkType.DockerContainerID, Shell: chkType.Shell, Script: chkType.Script, Interval: chkType.Interval, diff --git a/command/agent/check.go b/command/agent/check.go index bdc45c53b..c658bb017 100644 --- a/command/agent/check.go +++ b/command/agent/check.go @@ -44,7 +44,7 @@ type CheckType struct { HTTP string TCP string Interval time.Duration - DockerContainerId string + DockerContainerID string Shell string Timeout time.Duration @@ -68,7 +68,7 @@ func (c *CheckType) IsTTL() bool { // IsMonitor checks if this is a Monitor type func (c *CheckType) IsMonitor() bool { - return c.Script != "" && c.DockerContainerId == "" && c.Interval != 0 + return c.Script != "" && c.DockerContainerID == "" && c.Interval != 0 } // IsHTTP checks if this is a HTTP type @@ -82,7 +82,7 @@ func (c *CheckType) IsTCP() bool { } func (c *CheckType) IsDocker() bool { - return c.DockerContainerId != "" && c.Script != "" && c.Interval != 0 + return c.DockerContainerID != "" && c.Script != "" && c.Interval != 0 } // CheckNotifier interface is used by the CheckMonitor @@ -518,7 +518,7 @@ type CheckDocker struct { Notify CheckNotifier CheckID string Script string - DockerContainerId string + DockerContainerID string Shell string Interval time.Duration Logger *log.Logger @@ -574,7 +574,7 @@ func (c *CheckDocker) Stop() { func (c *CheckDocker) run() { // Get the randomized initial pause time initialPauseTime := randomStagger(c.Interval) - c.Logger.Printf("[DEBUG] agent: pausing %v before first invocation of %s -c %s in container %s", initialPauseTime, c.Shell, c.Script, c.DockerContainerId) + c.Logger.Printf("[DEBUG] agent: pausing %v before first invocation of %s -c %s in container %s", initialPauseTime, c.Shell, c.Script, c.DockerContainerID) next := time.After(initialPauseTime) for { select { @@ -595,7 +595,7 @@ func (c *CheckDocker) check() { AttachStderr: true, Tty: false, Cmd: c.cmd, - Container: c.DockerContainerId, + Container: c.DockerContainerID, } var ( exec *docker.Exec diff --git a/command/agent/check_test.go b/command/agent/check_test.go index 3736f8d3a..95045d9cf 100644 --- a/command/agent/check_test.go +++ b/command/agent/check_test.go @@ -535,7 +535,7 @@ func expectDockerCheckStatus(t *testing.T, dockerClient DockerClient, status str Notify: mock, CheckID: "foo", Script: "/health.sh", - DockerContainerId: "54432bad1fc7", + DockerContainerID: "54432bad1fc7", Shell: "/bin/sh", Interval: 10 * time.Millisecond, Logger: log.New(os.Stderr, "", log.LstdFlags), @@ -595,7 +595,7 @@ func TestDockerCheckDefaultToSh(t *testing.T) { Notify: mock, CheckID: "foo", Script: "/health.sh", - DockerContainerId: "54432bad1fc7", + DockerContainerID: "54432bad1fc7", Interval: 10 * time.Millisecond, Logger: log.New(os.Stderr, "", log.LstdFlags), dockerClient: &fakeDockerClientWithNoErrors{}, @@ -620,7 +620,7 @@ func TestDockerCheckUseShellFromEnv(t *testing.T) { Notify: mock, CheckID: "foo", Script: "/health.sh", - DockerContainerId: "54432bad1fc7", + DockerContainerID: "54432bad1fc7", Interval: 10 * time.Millisecond, Logger: log.New(os.Stderr, "", log.LstdFlags), dockerClient: &fakeDockerClientWithNoErrors{}, @@ -645,7 +645,7 @@ func TestDockerCheckTruncateOutput(t *testing.T) { Notify: mock, CheckID: "foo", Script: "/health.sh", - DockerContainerId: "54432bad1fc7", + DockerContainerID: "54432bad1fc7", Shell: "/bin/sh", Interval: 10 * time.Millisecond, Logger: log.New(os.Stderr, "", log.LstdFlags), diff --git a/command/agent/config.go b/command/agent/config.go index 3577a18c3..c03659116 100644 --- a/command/agent/config.go +++ b/command/agent/config.go @@ -782,7 +782,7 @@ func FixupCheckType(raw interface{}) error { rawMap["serviceid"] = v delete(rawMap, "service_id") case "docker_container_id": - rawMap["DockerContainerId"] = v + rawMap["DockerContainerID"] = v delete(rawMap, "docker_container_id") } } diff --git a/command/agent/config_test.go b/command/agent/config_test.go index 8fb1ae370..000567b26 100644 --- a/command/agent/config_test.go +++ b/command/agent/config_test.go @@ -1133,7 +1133,7 @@ func TestDecodeConfig_Check(t *testing.T) { t.Fatalf("bad: %v", chk) } - if chk.DockerContainerId != "redis" { + if chk.DockerContainerID != "redis" { t.Fatalf("bad: %v", chk) } } diff --git a/website/source/docs/agent/http/agent.html.markdown b/website/source/docs/agent/http/agent.html.markdown index d12e5a7aa..5a7b85c52 100644 --- a/website/source/docs/agent/http/agent.html.markdown +++ b/website/source/docs/agent/http/agent.html.markdown @@ -241,6 +241,8 @@ body must look like: "Name": "Memory utilization", "Notes": "Ensure we don't oversubscribe memory", "Script": "/usr/local/bin/check_mem.py", + "DockerContainerID": "f972c95ebf0e", + "Shell": "/bin/bash", "HTTP": "http://example.com", "TCP": "example.com:22", "Interval": "10s", @@ -259,6 +261,10 @@ The `Notes` field is not used internally by Consul and is meant to be human-read If a `Script` is provided, the check type is a script, and Consul will evaluate the script every `Interval` to update the status. +If a `DockerContainerID` is provided, the check is a Docker check, and Consul will +evaluate the script every `Interval` in the given container using the specified +`Shell`. Note that `Shell` is currently only supported for Docker checks. + An `HTTP` check will perform an HTTP GET request against the value of `HTTP` (expected to be a URL) every `Interval`. If the response is any `2xx` code, the check is `passing`. If the response is `429 Too Many Requests`, the check is `warning`. Otherwise, the check