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