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  }