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