diff --git a/cmd/nerdctl/container/container_run_restart_linux_test.go b/cmd/nerdctl/container/container_run_restart_linux_test.go index 17761188e39..8423fd6389d 100644 --- a/cmd/nerdctl/container/container_run_restart_linux_test.go +++ b/cmd/nerdctl/container/container_run_restart_linux_test.go @@ -382,3 +382,75 @@ func TestRunRestartStatusLabel(t *testing.T) { testCase.Run(t) } + +func TestRunRestartAlwaysStop(t *testing.T) { + testCase := nerdtest.Setup() + if !nerdtest.IsDocker() { + testCase.Require = nerdtest.ContainerdPlugin("io.containerd.internal.v1", "restart", []string{"always"}) + } + + testCase.Setup = func(data test.Data, helpers test.Helpers) { + helpers.Ensure("run", "-d", "--restart=always", "--name", data.Identifier(), testutil.CommonImage, "sleep", "infinity") + helpers.Ensure("stop", data.Identifier()) + } + + testCase.Cleanup = func(data test.Data, helpers test.Helpers) { + helpers.Anyhow("rm", "-f", data.Identifier()) + } + + testCase.Command = func(data test.Data, helpers test.Helpers) test.TestableCommand { + time.Sleep(3 * time.Second) + return helpers.Command("inspect", data.Identifier()) + } + + testCase.Expected = func(data test.Data, helpers test.Helpers) *test.Expected { + return &test.Expected{ + ExitCode: expect.ExitCodeSuccess, + Output: expect.JSON([]dockercompat.Container{}, func(dc []dockercompat.Container, t tig.T) { + assert.Equal(t, 1, len(dc)) + assert.Assert(t, dc[0].State != nil && dc[0].State.Status == "exited") + if !nerdtest.IsDocker() { + assert.Equal(t, "stopped", dc[0].Config.Labels[restart.StatusLabel]) + } + }), + } + } + + testCase.Run(t) +} + +func TestRunRestartAlwaysKill(t *testing.T) { + testCase := nerdtest.Setup() + if !nerdtest.IsDocker() { + testCase.Require = nerdtest.ContainerdPlugin("io.containerd.internal.v1", "restart", []string{"always"}) + } + + testCase.Setup = func(data test.Data, helpers test.Helpers) { + helpers.Ensure("run", "-d", "--restart=always", "--name", data.Identifier(), testutil.CommonImage, "sleep", "infinity") + helpers.Ensure("kill", data.Identifier()) + } + + testCase.Cleanup = func(data test.Data, helpers test.Helpers) { + helpers.Anyhow("rm", "-f", data.Identifier()) + } + + testCase.Command = func(data test.Data, helpers test.Helpers) test.TestableCommand { + time.Sleep(3 * time.Second) + return helpers.Command("inspect", data.Identifier()) + } + + testCase.Expected = func(data test.Data, helpers test.Helpers) *test.Expected { + return &test.Expected{ + ExitCode: expect.ExitCodeSuccess, + Output: expect.JSON([]dockercompat.Container{}, func(dc []dockercompat.Container, t tig.T) { + assert.Equal(t, 1, len(dc)) + assert.Assert(t, dc[0].State != nil && dc[0].State.Status == "exited") + if !nerdtest.IsDocker() { + assert.Equal(t, "stopped", dc[0].Config.Labels[restart.StatusLabel]) + } + }), + } + } + + testCase.Run(t) +} diff --git a/pkg/cmd/container/kill.go b/pkg/cmd/container/kill.go index d42a7cd8c82..8c17821ce92 100644 --- a/pkg/cmd/container/kill.go +++ b/pkg/cmd/container/kill.go @@ -27,6 +27,7 @@ import ( "github.com/moby/sys/signal" containerd "github.com/containerd/containerd/v2/client" + "github.com/containerd/containerd/v2/core/runtime/restart" "github.com/containerd/containerd/v2/pkg/cio" "github.com/containerd/errdefs" "github.com/containerd/go-cni" @@ -88,6 +89,13 @@ func killContainer(ctx context.Context, container containerd.Container, signal s if err := containerutil.UpdateExplicitlyStoppedLabel(ctx, container, true); err != nil { return err } + if l, err := container.Labels(ctx); err == nil { + if _, ok := l[restart.PolicyLabel]; ok { + if err := containerutil.UpdateStatusLabel(ctx, container, containerd.Stopped); err != nil { + return err + } + } + } task, err := container.Task(ctx, cio.Load) if err != nil { return err diff --git a/pkg/containerutil/containerutil.go b/pkg/containerutil/containerutil.go index fa27533f080..c991ec552da 100644 --- a/pkg/containerutil/containerutil.go +++ b/pkg/containerutil/containerutil.go @@ -363,6 +363,12 @@ func Stop(ctx context.Context, container containerd.Container, timeout *time.Dur if err != nil { return err } + + if _, ok := l[restart.PolicyLabel]; ok { + if err := UpdateStatusLabel(ctx, container, containerd.Stopped); err != nil { + return err + } + } ipc, err := ipcutil.DecodeIPCLabel(l[labels.IPC]) if err != nil { return err