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