github.com/containerd/nerdctl@v1.7.7/cmd/nerdctl/container_run_restart_linux_test.go (about) 1 /* 2 Copyright The containerd Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package main 18 19 import ( 20 "fmt" 21 "io" 22 "os/exec" 23 "strings" 24 "testing" 25 "time" 26 27 "github.com/containerd/nerdctl/pkg/testutil" 28 "github.com/containerd/nerdctl/pkg/testutil/nettestutil" 29 30 "gotest.tools/v3/assert" 31 "gotest.tools/v3/poll" 32 ) 33 34 func TestRunRestart(t *testing.T) { 35 const ( 36 hostPort = 8080 37 ) 38 testContainerName := testutil.Identifier(t) 39 if testing.Short() { 40 t.Skipf("test is long") 41 } 42 base := testutil.NewBase(t) 43 if !base.DaemonIsKillable { 44 t.Skip("daemon is not killable (hint: set \"-test.kill-daemon\")") 45 } 46 t.Log("NOTE: this test may take a while") 47 48 defer base.Cmd("rm", "-f", testContainerName).Run() 49 50 base.Cmd("run", "-d", 51 "--restart=always", 52 "--name", testContainerName, 53 "-p", fmt.Sprintf("127.0.0.1:%d:80", hostPort), 54 testutil.NginxAlpineImage).AssertOK() 55 56 check := func(httpGetRetry int) error { 57 resp, err := nettestutil.HTTPGet(fmt.Sprintf("http://127.0.0.1:%d", hostPort), httpGetRetry, false) 58 if err != nil { 59 return err 60 } 61 respBody, err := io.ReadAll(resp.Body) 62 if err != nil { 63 return err 64 } 65 if !strings.Contains(string(respBody), testutil.NginxAlpineIndexHTMLSnippet) { 66 return fmt.Errorf("expected contain %q, got %q", 67 testutil.NginxAlpineIndexHTMLSnippet, string(respBody)) 68 } 69 return nil 70 } 71 assert.NilError(t, check(30)) 72 73 base.KillDaemon() 74 base.EnsureDaemonActive() 75 76 const ( 77 maxRetry = 30 78 sleep = 3 * time.Second 79 ) 80 for i := 0; i < maxRetry; i++ { 81 t.Logf("(retry %d) ps -a: %q", i, base.Cmd("ps", "-a").Run().Combined()) 82 err := check(1) 83 if err == nil { 84 t.Logf("test is passing, after %d retries", i) 85 return 86 } 87 time.Sleep(sleep) 88 } 89 base.DumpDaemonLogs(10) 90 t.Fatalf("the container does not seem to be restarted") 91 } 92 93 func TestRunRestartWithOnFailure(t *testing.T) { 94 base := testutil.NewBase(t) 95 if testutil.GetTarget() == testutil.Nerdctl { 96 testutil.RequireContainerdPlugin(base, "io.containerd.internal.v1", "restart", []string{"on-failure"}) 97 } 98 tID := testutil.Identifier(t) 99 defer base.Cmd("rm", "-f", tID).Run() 100 base.Cmd("run", "-d", "--restart=on-failure:2", "--name", tID, testutil.AlpineImage, "sh", "-c", "exit 1").AssertOK() 101 102 check := func(log poll.LogT) poll.Result { 103 inspect := base.InspectContainer(tID) 104 if inspect.State != nil && inspect.State.Status == "exited" { 105 return poll.Success() 106 } 107 return poll.Continue("container is not yet exited") 108 } 109 poll.WaitOn(t, check, poll.WithDelay(100*time.Microsecond), poll.WithTimeout(60*time.Second)) 110 inspect := base.InspectContainer(tID) 111 assert.Equal(t, inspect.RestartCount, 2) 112 } 113 114 func TestRunRestartWithUnlessStopped(t *testing.T) { 115 base := testutil.NewBase(t) 116 if testutil.GetTarget() == testutil.Nerdctl { 117 testutil.RequireContainerdPlugin(base, "io.containerd.internal.v1", "restart", []string{"unless-stopped"}) 118 } 119 tID := testutil.Identifier(t) 120 defer base.Cmd("rm", "-f", tID).Run() 121 base.Cmd("run", "-d", "--restart=unless-stopped", "--name", tID, testutil.AlpineImage, "sh", "-c", "exit 1").AssertOK() 122 123 check := func(log poll.LogT) poll.Result { 124 inspect := base.InspectContainer(tID) 125 if inspect.State != nil && inspect.State.Status == "exited" { 126 return poll.Success() 127 } 128 if inspect.RestartCount == 2 { 129 base.Cmd("stop", tID).AssertOK() 130 } 131 return poll.Continue("container is not yet exited") 132 } 133 poll.WaitOn(t, check, poll.WithDelay(100*time.Microsecond), poll.WithTimeout(60*time.Second)) 134 inspect := base.InspectContainer(tID) 135 assert.Equal(t, inspect.RestartCount, 2) 136 } 137 138 func TestUpdateRestartPolicy(t *testing.T) { 139 base := testutil.NewBase(t) 140 if testutil.GetTarget() == testutil.Nerdctl { 141 testutil.RequireContainerdPlugin(base, "io.containerd.internal.v1", "restart", []string{"on-failure"}) 142 } 143 tID := testutil.Identifier(t) 144 defer base.Cmd("rm", "-f", tID).Run() 145 base.Cmd("run", "-d", "--restart=on-failure:1", "--name", tID, testutil.AlpineImage, "sh", "-c", "exit 1").AssertOK() 146 base.Cmd("update", "--restart=on-failure:2", tID).AssertOK() 147 check := func(log poll.LogT) poll.Result { 148 inspect := base.InspectContainer(tID) 149 if inspect.State != nil && inspect.State.Status == "exited" { 150 return poll.Success() 151 } 152 return poll.Continue("container is not yet exited") 153 } 154 poll.WaitOn(t, check, poll.WithDelay(100*time.Microsecond), poll.WithTimeout(60*time.Second)) 155 inspect := base.InspectContainer(tID) 156 assert.Equal(t, inspect.RestartCount, 2) 157 } 158 159 // The test is to add a restart policy to a container which has not restart policy before, 160 // and check it can work correctly. 161 func TestAddRestartPolicy(t *testing.T) { 162 base := testutil.NewBase(t) 163 if testutil.GetTarget() == testutil.Nerdctl { 164 testutil.RequireContainerdPlugin(base, "io.containerd.internal.v1", "restart", []string{"on-failure"}) 165 } 166 tID := testutil.Identifier(t) 167 defer base.Cmd("rm", "-f", tID).Run() 168 base.Cmd("run", "-d", "--name", tID, testutil.NginxAlpineImage).AssertOK() 169 base.Cmd("update", "--restart=on-failure", tID).AssertOK() 170 inspect := base.InspectContainer(tID) 171 orgialPid := inspect.State.Pid 172 exec.Command("kill", "-9", fmt.Sprintf("%v", orgialPid)).Run() 173 174 check := func(log poll.LogT) poll.Result { 175 inspect := base.InspectContainer(tID) 176 if inspect.State != nil && inspect.State.Status == "running" && inspect.State.Pid != orgialPid { 177 return poll.Success() 178 } 179 return poll.Continue("container is not yet running") 180 } 181 poll.WaitOn(t, check, poll.WithDelay(100*time.Microsecond), poll.WithTimeout(60*time.Second)) 182 inspect = base.InspectContainer(tID) 183 assert.Equal(t, inspect.RestartCount, 1) 184 }