github.com/flavio/docker@v0.1.3-0.20170117145210-f63d1a6eec47/integration-cli/docker_cli_health_test.go (about) 1 package main 2 3 import ( 4 "encoding/json" 5 6 "strconv" 7 "strings" 8 "time" 9 10 "github.com/docker/docker/api/types" 11 "github.com/docker/docker/integration-cli/checker" 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 _, err := buildImage(imageName, 44 `FROM busybox 45 RUN echo OK > /status 46 CMD ["/bin/sleep", "120"] 47 STOPSIGNAL SIGKILL 48 HEALTHCHECK --interval=1s --timeout=30s \ 49 CMD cat /status`, 50 true) 51 52 c.Check(err, check.IsNil) 53 54 // No health status before starting 55 name := "test_health" 56 dockerCmd(c, "create", "--name", name, imageName) 57 out, _ := dockerCmd(c, "ps", "-a", "--format={{.Status}}") 58 c.Check(out, checker.Equals, "Created\n") 59 60 // Inspect the options 61 out, _ = dockerCmd(c, "inspect", 62 "--format=timeout={{.Config.Healthcheck.Timeout}} "+ 63 "interval={{.Config.Healthcheck.Interval}} "+ 64 "retries={{.Config.Healthcheck.Retries}} "+ 65 "test={{.Config.Healthcheck.Test}}", name) 66 c.Check(out, checker.Equals, "timeout=30s interval=1s retries=0 test=[CMD-SHELL cat /status]\n") 67 68 // Start 69 dockerCmd(c, "start", name) 70 waitForHealthStatus(c, name, "starting", "healthy") 71 72 // Make it fail 73 dockerCmd(c, "exec", name, "rm", "/status") 74 waitForHealthStatus(c, name, "healthy", "unhealthy") 75 76 // Inspect the status 77 out, _ = dockerCmd(c, "inspect", "--format={{.State.Health.Status}}", name) 78 c.Check(out, checker.Equals, "unhealthy\n") 79 80 // Make it healthy again 81 dockerCmd(c, "exec", name, "touch", "/status") 82 waitForHealthStatus(c, name, "unhealthy", "healthy") 83 84 // Remove container 85 dockerCmd(c, "rm", "-f", name) 86 87 // Disable the check from the CLI 88 out, _ = dockerCmd(c, "create", "--name=noh", "--no-healthcheck", imageName) 89 out, _ = dockerCmd(c, "inspect", "--format={{.Config.Healthcheck.Test}}", "noh") 90 c.Check(out, checker.Equals, "[NONE]\n") 91 dockerCmd(c, "rm", "noh") 92 93 // Disable the check with a new build 94 _, err = buildImage("no_healthcheck", 95 `FROM testhealth 96 HEALTHCHECK NONE`, true) 97 c.Check(err, check.IsNil) 98 99 out, _ = dockerCmd(c, "inspect", "--format={{.ContainerConfig.Healthcheck.Test}}", "no_healthcheck") 100 c.Check(out, checker.Equals, "[NONE]\n") 101 102 // Enable the checks from the CLI 103 _, _ = dockerCmd(c, "run", "-d", "--name=fatal_healthcheck", 104 "--health-interval=0.5s", 105 "--health-retries=3", 106 "--health-cmd=cat /status", 107 "no_healthcheck") 108 waitForHealthStatus(c, "fatal_healthcheck", "starting", "healthy") 109 health := getHealth(c, "fatal_healthcheck") 110 c.Check(health.Status, checker.Equals, "healthy") 111 c.Check(health.FailingStreak, checker.Equals, 0) 112 last := health.Log[len(health.Log)-1] 113 c.Check(last.ExitCode, checker.Equals, 0) 114 c.Check(last.Output, checker.Equals, "OK\n") 115 116 // Fail the check 117 dockerCmd(c, "exec", "fatal_healthcheck", "rm", "/status") 118 waitForHealthStatus(c, "fatal_healthcheck", "healthy", "unhealthy") 119 120 failsStr, _ := dockerCmd(c, "inspect", "--format={{.State.Health.FailingStreak}}", "fatal_healthcheck") 121 fails, err := strconv.Atoi(strings.TrimSpace(failsStr)) 122 c.Check(err, check.IsNil) 123 c.Check(fails >= 3, checker.Equals, true) 124 dockerCmd(c, "rm", "-f", "fatal_healthcheck") 125 126 // Check timeout 127 // Note: if the interval is too small, it seems that Docker spends all its time running health 128 // checks and never gets around to killing it. 129 _, _ = dockerCmd(c, "run", "-d", "--name=test", 130 "--health-interval=1s", "--health-cmd=sleep 5m", "--health-timeout=1ms", imageName) 131 waitForHealthStatus(c, "test", "starting", "unhealthy") 132 health = getHealth(c, "test") 133 last = health.Log[len(health.Log)-1] 134 c.Check(health.Status, checker.Equals, "unhealthy") 135 c.Check(last.ExitCode, checker.Equals, -1) 136 c.Check(last.Output, checker.Equals, "Health check exceeded timeout (1ms)") 137 dockerCmd(c, "rm", "-f", "test") 138 139 // Check JSON-format 140 _, err = buildImage(imageName, 141 `FROM busybox 142 RUN echo OK > /status 143 CMD ["/bin/sleep", "120"] 144 STOPSIGNAL SIGKILL 145 HEALTHCHECK --interval=1s --timeout=30s \ 146 CMD ["cat", "/my status"]`, 147 true) 148 c.Check(err, check.IsNil) 149 out, _ = dockerCmd(c, "inspect", 150 "--format={{.Config.Healthcheck.Test}}", imageName) 151 c.Check(out, checker.Equals, "[CMD cat /my status]\n") 152 153 }