github.com/jiasir/docker@v1.3.3-0.20170609024000-252e610103e7/integration-cli/docker_cli_health_test.go (about) 1 package main 2 3 import ( 4 "encoding/json" 5 "strconv" 6 "strings" 7 "time" 8 9 "github.com/docker/docker/api/types" 10 "github.com/docker/docker/integration-cli/checker" 11 "github.com/docker/docker/integration-cli/cli/build" 12 "github.com/go-check/check" 13 ) 14 15 func waitForHealthStatus(c *check.C, name string, prev string, expected string) { 16 prev = prev + "\n" 17 expected = expected + "\n" 18 for { 19 out, _ := dockerCmd(c, "inspect", "--format={{.State.Health.Status}}", name) 20 if out == expected { 21 return 22 } 23 c.Check(out, checker.Equals, prev) 24 if out != prev { 25 return 26 } 27 time.Sleep(100 * time.Millisecond) 28 } 29 } 30 31 func getHealth(c *check.C, name string) *types.Health { 32 out, _ := dockerCmd(c, "inspect", "--format={{json .State.Health}}", name) 33 var health types.Health 34 err := json.Unmarshal([]byte(out), &health) 35 c.Check(err, checker.Equals, nil) 36 return &health 37 } 38 39 func (s *DockerSuite) TestHealth(c *check.C) { 40 testRequires(c, DaemonIsLinux) // busybox doesn't work on Windows 41 42 imageName := "testhealth" 43 buildImageSuccessfully(c, imageName, build.WithDockerfile(`FROM busybox 44 RUN echo OK > /status 45 CMD ["/bin/sleep", "120"] 46 STOPSIGNAL SIGKILL 47 HEALTHCHECK --interval=1s --timeout=30s \ 48 CMD cat /status`)) 49 50 // No health status before starting 51 name := "test_health" 52 dockerCmd(c, "create", "--name", name, imageName) 53 out, _ := dockerCmd(c, "ps", "-a", "--format={{.Status}}") 54 c.Check(out, checker.Equals, "Created\n") 55 56 // Inspect the options 57 out, _ = dockerCmd(c, "inspect", 58 "--format=timeout={{.Config.Healthcheck.Timeout}} interval={{.Config.Healthcheck.Interval}} retries={{.Config.Healthcheck.Retries}} test={{.Config.Healthcheck.Test}}", name) 59 c.Check(out, checker.Equals, "timeout=30s interval=1s retries=0 test=[CMD-SHELL cat /status]\n") 60 61 // Start 62 dockerCmd(c, "start", name) 63 waitForHealthStatus(c, name, "starting", "healthy") 64 65 // Make it fail 66 dockerCmd(c, "exec", name, "rm", "/status") 67 waitForHealthStatus(c, name, "healthy", "unhealthy") 68 69 // Inspect the status 70 out, _ = dockerCmd(c, "inspect", "--format={{.State.Health.Status}}", name) 71 c.Check(out, checker.Equals, "unhealthy\n") 72 73 // Make it healthy again 74 dockerCmd(c, "exec", name, "touch", "/status") 75 waitForHealthStatus(c, name, "unhealthy", "healthy") 76 77 // Remove container 78 dockerCmd(c, "rm", "-f", name) 79 80 // Disable the check from the CLI 81 out, _ = dockerCmd(c, "create", "--name=noh", "--no-healthcheck", imageName) 82 out, _ = dockerCmd(c, "inspect", "--format={{.Config.Healthcheck.Test}}", "noh") 83 c.Check(out, checker.Equals, "[NONE]\n") 84 dockerCmd(c, "rm", "noh") 85 86 // Disable the check with a new build 87 buildImageSuccessfully(c, "no_healthcheck", build.WithDockerfile(`FROM testhealth 88 HEALTHCHECK NONE`)) 89 90 out, _ = dockerCmd(c, "inspect", "--format={{.ContainerConfig.Healthcheck.Test}}", "no_healthcheck") 91 c.Check(out, checker.Equals, "[NONE]\n") 92 93 // Enable the checks from the CLI 94 _, _ = dockerCmd(c, "run", "-d", "--name=fatal_healthcheck", 95 "--health-interval=1s", 96 "--health-retries=3", 97 "--health-cmd=cat /status", 98 "no_healthcheck") 99 waitForHealthStatus(c, "fatal_healthcheck", "starting", "healthy") 100 health := getHealth(c, "fatal_healthcheck") 101 c.Check(health.Status, checker.Equals, "healthy") 102 c.Check(health.FailingStreak, checker.Equals, 0) 103 last := health.Log[len(health.Log)-1] 104 c.Check(last.ExitCode, checker.Equals, 0) 105 c.Check(last.Output, checker.Equals, "OK\n") 106 107 // Fail the check 108 dockerCmd(c, "exec", "fatal_healthcheck", "rm", "/status") 109 waitForHealthStatus(c, "fatal_healthcheck", "healthy", "unhealthy") 110 111 failsStr, _ := dockerCmd(c, "inspect", "--format={{.State.Health.FailingStreak}}", "fatal_healthcheck") 112 fails, err := strconv.Atoi(strings.TrimSpace(failsStr)) 113 c.Check(err, check.IsNil) 114 c.Check(fails >= 3, checker.Equals, true) 115 dockerCmd(c, "rm", "-f", "fatal_healthcheck") 116 117 // Check timeout 118 // Note: if the interval is too small, it seems that Docker spends all its time running health 119 // checks and never gets around to killing it. 120 _, _ = dockerCmd(c, "run", "-d", "--name=test", 121 "--health-interval=1s", "--health-cmd=sleep 5m", "--health-timeout=1s", imageName) 122 waitForHealthStatus(c, "test", "starting", "unhealthy") 123 health = getHealth(c, "test") 124 last = health.Log[len(health.Log)-1] 125 c.Check(health.Status, checker.Equals, "unhealthy") 126 c.Check(last.ExitCode, checker.Equals, -1) 127 c.Check(last.Output, checker.Equals, "Health check exceeded timeout (1s)") 128 dockerCmd(c, "rm", "-f", "test") 129 130 // Check JSON-format 131 buildImageSuccessfully(c, imageName, build.WithDockerfile(`FROM busybox 132 RUN echo OK > /status 133 CMD ["/bin/sleep", "120"] 134 STOPSIGNAL SIGKILL 135 HEALTHCHECK --interval=1s --timeout=30s \ 136 CMD ["cat", "/my status"]`)) 137 out, _ = dockerCmd(c, "inspect", 138 "--format={{.Config.Healthcheck.Test}}", imageName) 139 c.Check(out, checker.Equals, "[CMD cat /my status]\n") 140 141 } 142 143 // Github #33021 144 func (s *DockerSuite) TestUnsetEnvVarHealthCheck(c *check.C) { 145 testRequires(c, DaemonIsLinux) // busybox doesn't work on Windows 146 147 imageName := "testhealth" 148 buildImageSuccessfully(c, imageName, build.WithDockerfile(`FROM busybox 149 HEALTHCHECK --interval=1s --timeout=5s --retries=5 CMD /bin/sh -c "sleep 1" 150 ENTRYPOINT /bin/sh -c "sleep 600"`)) 151 152 name := "env_test_health" 153 // No health status before starting 154 dockerCmd(c, "run", "-d", "--name", name, "-e", "FOO", imageName) 155 defer func() { 156 dockerCmd(c, "rm", "-f", name) 157 dockerCmd(c, "rmi", imageName) 158 }() 159 160 // Start 161 dockerCmd(c, "start", name) 162 waitForHealthStatus(c, name, "starting", "healthy") 163 164 }