moby/integration-cli/docker_cli_service_health_test.go
Aaron Lehmann d012569b78 Update CLI commit hash
Since this new version of the CLI resolves image digests for swarm
services by default, and we do not want integration tests to talk to
Docker Hub, update CLI tests to suppress this behavior.

Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
2017-05-18 12:23:28 -07:00

134 lines
4.7 KiB
Go

// +build !windows
package main
import (
"strconv"
"strings"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/daemon/cluster/executor/container"
"github.com/docker/docker/integration-cli/checker"
"github.com/go-check/check"
)
// start a service, and then make its task unhealthy during running
// finally, unhealthy task should be detected and killed
func (s *DockerSwarmSuite) TestServiceHealthRun(c *check.C) {
testRequires(c, DaemonIsLinux) // busybox doesn't work on Windows
d := s.AddDaemon(c, true, true)
// build image with health-check
// note: use `daemon.buildImageWithOut` to build, do not use `buildImage` to build
imageName := "testhealth"
_, _, err := d.BuildImageWithOut(imageName,
`FROM busybox
RUN touch /status
HEALTHCHECK --interval=1s --timeout=1s --retries=1\
CMD cat /status`,
true)
c.Check(err, check.IsNil)
serviceName := "healthServiceRun"
out, err := d.Cmd("service", "create", "--no-resolve-image", "--detach=true", "--name", serviceName, imageName, "top")
c.Assert(err, checker.IsNil, check.Commentf(out))
id := strings.TrimSpace(out)
var tasks []swarm.Task
waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
tasks = d.GetServiceTasks(c, id)
return tasks, nil
}, checker.HasLen, 1)
task := tasks[0]
// wait for task to start
waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
task = d.GetTask(c, task.ID)
return task.Status.State, nil
}, checker.Equals, swarm.TaskStateRunning)
containerID := task.Status.ContainerStatus.ContainerID
// wait for container to be healthy
waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
out, _ := d.Cmd("inspect", "--format={{.State.Health.Status}}", containerID)
return strings.TrimSpace(out), nil
}, checker.Equals, "healthy")
// make it fail
d.Cmd("exec", containerID, "rm", "/status")
// wait for container to be unhealthy
waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
out, _ := d.Cmd("inspect", "--format={{.State.Health.Status}}", containerID)
return strings.TrimSpace(out), nil
}, checker.Equals, "unhealthy")
// Task should be terminated
waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
task = d.GetTask(c, task.ID)
return task.Status.State, nil
}, checker.Equals, swarm.TaskStateFailed)
if !strings.Contains(task.Status.Err, container.ErrContainerUnhealthy.Error()) {
c.Fatal("unhealthy task exits because of other error")
}
}
// start a service whose task is unhealthy at beginning
// its tasks should be blocked in starting stage, until health check is passed
func (s *DockerSwarmSuite) TestServiceHealthStart(c *check.C) {
testRequires(c, DaemonIsLinux) // busybox doesn't work on Windows
d := s.AddDaemon(c, true, true)
// service started from this image won't pass health check
imageName := "testhealth"
_, _, err := d.BuildImageWithOut(imageName,
`FROM busybox
HEALTHCHECK --interval=1s --timeout=1s --retries=1024\
CMD cat /status`,
true)
c.Check(err, check.IsNil)
serviceName := "healthServiceStart"
out, err := d.Cmd("service", "create", "--no-resolve-image", "--detach=true", "--name", serviceName, imageName, "top")
c.Assert(err, checker.IsNil, check.Commentf(out))
id := strings.TrimSpace(out)
var tasks []swarm.Task
waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
tasks = d.GetServiceTasks(c, id)
return tasks, nil
}, checker.HasLen, 1)
task := tasks[0]
// wait for task to start
waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
task = d.GetTask(c, task.ID)
return task.Status.State, nil
}, checker.Equals, swarm.TaskStateStarting)
containerID := task.Status.ContainerStatus.ContainerID
// wait for health check to work
waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
out, _ := d.Cmd("inspect", "--format={{.State.Health.FailingStreak}}", containerID)
failingStreak, _ := strconv.Atoi(strings.TrimSpace(out))
return failingStreak, nil
}, checker.GreaterThan, 0)
// task should be blocked at starting status
task = d.GetTask(c, task.ID)
c.Assert(task.Status.State, check.Equals, swarm.TaskStateStarting)
// make it healthy
d.Cmd("exec", containerID, "touch", "/status")
// Task should be at running status
waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
task = d.GetTask(c, task.ID)
return task.Status.State, nil
}, checker.Equals, swarm.TaskStateRunning)
}