gopkg.in/docker/docker.v20@v20.10.27/integration-cli/docker_cli_restart_test.go (about) 1 package main 2 3 import ( 4 "os" 5 "strconv" 6 "strings" 7 "testing" 8 "time" 9 10 "github.com/docker/docker/integration-cli/checker" 11 "gotest.tools/v3/assert" 12 is "gotest.tools/v3/assert/cmp" 13 "gotest.tools/v3/poll" 14 ) 15 16 func (s *DockerSuite) TestRestartStoppedContainer(c *testing.T) { 17 dockerCmd(c, "run", "--name=test", "busybox", "echo", "foobar") 18 cleanedContainerID := getIDByName(c, "test") 19 20 out, _ := dockerCmd(c, "logs", cleanedContainerID) 21 assert.Equal(c, out, "foobar\n") 22 23 dockerCmd(c, "restart", cleanedContainerID) 24 25 // Wait until the container has stopped 26 err := waitInspect(cleanedContainerID, "{{.State.Running}}", "false", 20*time.Second) 27 assert.NilError(c, err) 28 29 out, _ = dockerCmd(c, "logs", cleanedContainerID) 30 assert.Equal(c, out, "foobar\nfoobar\n") 31 } 32 33 func (s *DockerSuite) TestRestartRunningContainer(c *testing.T) { 34 out, _ := dockerCmd(c, "run", "-d", "busybox", "sh", "-c", "echo foobar && sleep 30 && echo 'should not print this'") 35 36 cleanedContainerID := strings.TrimSpace(out) 37 38 assert.NilError(c, waitRun(cleanedContainerID)) 39 40 getLogs := func(c *testing.T) (interface{}, string) { 41 out, _ := dockerCmd(c, "logs", cleanedContainerID) 42 return out, "" 43 } 44 45 // Wait 10 seconds for the 'echo' to appear in the logs 46 poll.WaitOn(c, pollCheck(c, getLogs, checker.Equals("foobar\n")), poll.WithTimeout(10*time.Second)) 47 48 dockerCmd(c, "restart", "-t", "1", cleanedContainerID) 49 assert.NilError(c, waitRun(cleanedContainerID)) 50 51 // Wait 10 seconds for first 'echo' appear (again) in the logs 52 poll.WaitOn(c, pollCheck(c, getLogs, checker.Equals("foobar\nfoobar\n")), poll.WithTimeout(10*time.Second)) 53 } 54 55 // Test that restarting a container with a volume does not create a new volume on restart. Regression test for #819. 56 func (s *DockerSuite) TestRestartWithVolumes(c *testing.T) { 57 prefix, slash := getPrefixAndSlashFromDaemonPlatform() 58 out := runSleepingContainer(c, "-d", "-v", prefix+slash+"test") 59 60 cleanedContainerID := strings.TrimSpace(out) 61 out, err := inspectFilter(cleanedContainerID, "len .Mounts") 62 assert.NilError(c, err, "failed to inspect %s: %s", cleanedContainerID, out) 63 out = strings.Trim(out, " \n\r") 64 assert.Equal(c, out, "1") 65 66 source, err := inspectMountSourceField(cleanedContainerID, prefix+slash+"test") 67 assert.NilError(c, err) 68 69 dockerCmd(c, "restart", cleanedContainerID) 70 71 out, err = inspectFilter(cleanedContainerID, "len .Mounts") 72 assert.NilError(c, err, "failed to inspect %s: %s", cleanedContainerID, out) 73 out = strings.Trim(out, " \n\r") 74 assert.Equal(c, out, "1") 75 76 sourceAfterRestart, err := inspectMountSourceField(cleanedContainerID, prefix+slash+"test") 77 assert.NilError(c, err) 78 assert.Equal(c, source, sourceAfterRestart) 79 } 80 81 func (s *DockerSuite) TestRestartDisconnectedContainer(c *testing.T) { 82 testRequires(c, DaemonIsLinux, testEnv.IsLocalDaemon, NotUserNamespace, NotArm) 83 84 // Run a container on the default bridge network 85 out, _ := dockerCmd(c, "run", "-d", "--name", "c0", "busybox", "top") 86 cleanedContainerID := strings.TrimSpace(out) 87 assert.NilError(c, waitRun(cleanedContainerID)) 88 89 // Disconnect the container from the network 90 out, exitCode := dockerCmd(c, "network", "disconnect", "bridge", "c0") 91 assert.Assert(c, exitCode == 0, out) 92 93 // Restart the container 94 out, exitCode = dockerCmd(c, "restart", "c0") 95 assert.Assert(c, exitCode == 0, out) 96 } 97 98 func (s *DockerSuite) TestRestartPolicyNO(c *testing.T) { 99 out, _ := dockerCmd(c, "create", "--restart=no", "busybox") 100 101 id := strings.TrimSpace(out) 102 name := inspectField(c, id, "HostConfig.RestartPolicy.Name") 103 assert.Equal(c, name, "no") 104 } 105 106 func (s *DockerSuite) TestRestartPolicyAlways(c *testing.T) { 107 out, _ := dockerCmd(c, "create", "--restart=always", "busybox") 108 109 id := strings.TrimSpace(out) 110 name := inspectField(c, id, "HostConfig.RestartPolicy.Name") 111 assert.Equal(c, name, "always") 112 113 MaximumRetryCount := inspectField(c, id, "HostConfig.RestartPolicy.MaximumRetryCount") 114 115 // MaximumRetryCount=0 if the restart policy is always 116 assert.Equal(c, MaximumRetryCount, "0") 117 } 118 119 func (s *DockerSuite) TestRestartPolicyOnFailure(c *testing.T) { 120 out, _, err := dockerCmdWithError("create", "--restart=on-failure:-1", "busybox") 121 assert.ErrorContains(c, err, "", out) 122 assert.Assert(c, strings.Contains(out, "maximum retry count cannot be negative")) 123 124 out, _ = dockerCmd(c, "create", "--restart=on-failure:1", "busybox") 125 126 id := strings.TrimSpace(out) 127 name := inspectField(c, id, "HostConfig.RestartPolicy.Name") 128 maxRetry := inspectField(c, id, "HostConfig.RestartPolicy.MaximumRetryCount") 129 130 assert.Equal(c, name, "on-failure") 131 assert.Equal(c, maxRetry, "1") 132 133 out, _ = dockerCmd(c, "create", "--restart=on-failure:0", "busybox") 134 135 id = strings.TrimSpace(out) 136 name = inspectField(c, id, "HostConfig.RestartPolicy.Name") 137 maxRetry = inspectField(c, id, "HostConfig.RestartPolicy.MaximumRetryCount") 138 139 assert.Equal(c, name, "on-failure") 140 assert.Equal(c, maxRetry, "0") 141 142 out, _ = dockerCmd(c, "create", "--restart=on-failure", "busybox") 143 144 id = strings.TrimSpace(out) 145 name = inspectField(c, id, "HostConfig.RestartPolicy.Name") 146 maxRetry = inspectField(c, id, "HostConfig.RestartPolicy.MaximumRetryCount") 147 148 assert.Equal(c, name, "on-failure") 149 assert.Equal(c, maxRetry, "0") 150 } 151 152 // a good container with --restart=on-failure:3 153 // MaximumRetryCount!=0; RestartCount=0 154 func (s *DockerSuite) TestRestartContainerwithGoodContainer(c *testing.T) { 155 out, _ := dockerCmd(c, "run", "-d", "--restart=on-failure:3", "busybox", "true") 156 157 id := strings.TrimSpace(out) 158 err := waitInspect(id, "{{ .State.Restarting }} {{ .State.Running }}", "false false", 30*time.Second) 159 assert.NilError(c, err) 160 161 count := inspectField(c, id, "RestartCount") 162 assert.Equal(c, count, "0") 163 164 MaximumRetryCount := inspectField(c, id, "HostConfig.RestartPolicy.MaximumRetryCount") 165 assert.Equal(c, MaximumRetryCount, "3") 166 } 167 168 func (s *DockerSuite) TestRestartContainerSuccess(c *testing.T) { 169 testRequires(c, testEnv.IsLocalDaemon) 170 // Skipped for Hyper-V isolated containers. Test is currently written 171 // such that it assumes there is a host process to kill. In Hyper-V 172 // containers, the process is inside the utility VM, not on the host. 173 if DaemonIsWindows() { 174 testRequires(c, IsolationIsProcess) 175 } 176 177 out := runSleepingContainer(c, "-d", "--restart=always") 178 id := strings.TrimSpace(out) 179 assert.NilError(c, waitRun(id)) 180 181 pidStr := inspectField(c, id, "State.Pid") 182 183 pid, err := strconv.Atoi(pidStr) 184 assert.NilError(c, err) 185 186 p, err := os.FindProcess(pid) 187 assert.NilError(c, err) 188 assert.Assert(c, p != nil) 189 190 err = p.Kill() 191 assert.NilError(c, err) 192 193 err = waitInspect(id, "{{.RestartCount}}", "1", 30*time.Second) 194 assert.NilError(c, err) 195 196 err = waitInspect(id, "{{.State.Status}}", "running", 30*time.Second) 197 assert.NilError(c, err) 198 } 199 200 func (s *DockerSuite) TestRestartWithPolicyUserDefinedNetwork(c *testing.T) { 201 // TODO Windows. This may be portable following HNS integration post TP5. 202 testRequires(c, DaemonIsLinux, testEnv.IsLocalDaemon, NotUserNamespace, NotArm) 203 dockerCmd(c, "network", "create", "-d", "bridge", "udNet") 204 205 dockerCmd(c, "run", "-d", "--net=udNet", "--name=first", "busybox", "top") 206 assert.NilError(c, waitRun("first")) 207 208 dockerCmd(c, "run", "-d", "--restart=always", "--net=udNet", "--name=second", 209 "--link=first:foo", "busybox", "top") 210 assert.NilError(c, waitRun("second")) 211 212 // ping to first and its alias foo must succeed 213 _, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first") 214 assert.NilError(c, err) 215 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo") 216 assert.NilError(c, err) 217 218 // Now kill the second container and let the restart policy kick in 219 pidStr := inspectField(c, "second", "State.Pid") 220 221 pid, err := strconv.Atoi(pidStr) 222 assert.NilError(c, err) 223 224 p, err := os.FindProcess(pid) 225 assert.NilError(c, err) 226 assert.Assert(c, p != nil) 227 228 err = p.Kill() 229 assert.NilError(c, err) 230 231 err = waitInspect("second", "{{.RestartCount}}", "1", 5*time.Second) 232 assert.NilError(c, err) 233 234 err = waitInspect("second", "{{.State.Status}}", "running", 5*time.Second) 235 assert.NilError(c, err) 236 237 // ping to first and its alias foo must still succeed 238 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "first") 239 assert.NilError(c, err) 240 _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo") 241 assert.NilError(c, err) 242 } 243 244 func (s *DockerSuite) TestRestartPolicyAfterRestart(c *testing.T) { 245 testRequires(c, testEnv.IsLocalDaemon) 246 // Skipped for Hyper-V isolated containers. Test is currently written 247 // such that it assumes there is a host process to kill. In Hyper-V 248 // containers, the process is inside the utility VM, not on the host. 249 if DaemonIsWindows() { 250 testRequires(c, IsolationIsProcess) 251 } 252 253 out := runSleepingContainer(c, "-d", "--restart=always") 254 id := strings.TrimSpace(out) 255 assert.NilError(c, waitRun(id)) 256 257 dockerCmd(c, "restart", id) 258 259 assert.NilError(c, waitRun(id)) 260 261 pidStr := inspectField(c, id, "State.Pid") 262 263 pid, err := strconv.Atoi(pidStr) 264 assert.NilError(c, err) 265 266 p, err := os.FindProcess(pid) 267 assert.NilError(c, err) 268 assert.Assert(c, p != nil) 269 270 err = p.Kill() 271 assert.NilError(c, err) 272 273 err = waitInspect(id, "{{.RestartCount}}", "1", 30*time.Second) 274 assert.NilError(c, err) 275 276 err = waitInspect(id, "{{.State.Status}}", "running", 30*time.Second) 277 assert.NilError(c, err) 278 } 279 280 func (s *DockerSuite) TestRestartContainerwithRestartPolicy(c *testing.T) { 281 out1, _ := dockerCmd(c, "run", "-d", "--restart=on-failure:3", "busybox", "false") 282 out2, _ := dockerCmd(c, "run", "-d", "--restart=always", "busybox", "false") 283 284 id1 := strings.TrimSpace(out1) 285 id2 := strings.TrimSpace(out2) 286 waitTimeout := 15 * time.Second 287 if testEnv.OSType == "windows" { 288 waitTimeout = 150 * time.Second 289 } 290 err := waitInspect(id1, "{{ .State.Restarting }} {{ .State.Running }}", "false false", waitTimeout) 291 assert.NilError(c, err) 292 293 dockerCmd(c, "restart", id1) 294 dockerCmd(c, "restart", id2) 295 296 // Make sure we can stop/start (regression test from a705e166cf3bcca62543150c2b3f9bfeae45ecfa) 297 dockerCmd(c, "stop", id1) 298 dockerCmd(c, "stop", id2) 299 dockerCmd(c, "start", id1) 300 dockerCmd(c, "start", id2) 301 302 // Kill the containers, making sure they are stopped at the end of the test 303 dockerCmd(c, "kill", id1) 304 dockerCmd(c, "kill", id2) 305 err = waitInspect(id1, "{{ .State.Restarting }} {{ .State.Running }}", "false false", waitTimeout) 306 assert.NilError(c, err) 307 err = waitInspect(id2, "{{ .State.Restarting }} {{ .State.Running }}", "false false", waitTimeout) 308 assert.NilError(c, err) 309 } 310 311 func (s *DockerSuite) TestRestartAutoRemoveContainer(c *testing.T) { 312 out := runSleepingContainer(c, "--rm") 313 314 id := strings.TrimSpace(out) 315 dockerCmd(c, "restart", id) 316 err := waitInspect(id, "{{ .State.Restarting }} {{ .State.Running }}", "false true", 15*time.Second) 317 assert.NilError(c, err) 318 319 out, _ = dockerCmd(c, "ps") 320 assert.Assert(c, is.Contains(out, id[:12]), "container should be restarted instead of removed: %v", out) 321 322 // Kill the container to make sure it will be removed 323 dockerCmd(c, "kill", id) 324 }