github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/integration-cli/docker_cli_restart_test.go (about)

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