diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2b921dfa2..33e5c9ba6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -330,8 +330,9 @@ jobs: env: GOPROXY: direct TEST_RUNTIME: io.containerd.runc.${{ matrix.runtime }} + RUNC_FLAVOR: ${{ matrix.runc }} run: | - sudo GOPATH=$GOPATH GOPROXY=$GOPROXY TEST_RUNTIME=$TEST_RUNTIME make integration EXTRA_TESTFLAGS=-no-criu TESTFLAGS_RACE=-race + sudo GOPATH=$GOPATH GOPROXY=$GOPROXY TEST_RUNTIME=$TEST_RUNTIME RUNC_FLAVOR=$RUNC_FLAVOR make integration EXTRA_TESTFLAGS=-no-criu TESTFLAGS_RACE=-race working-directory: src/github.com/containerd/containerd # Run the integration suite a second time. See discussion in github.com/containerd/containerd/pull/1759 @@ -339,8 +340,9 @@ jobs: env: GOPROXY: direct TEST_RUNTIME: io.containerd.runc.${{ matrix.runtime }} + RUNC_FLAVOR: ${{ matrix.runc }} run: | - sudo GOPATH=$GOPATH GOPROXY=$GOPROXY TEST_RUNTIME=$TEST_RUNTIME TESTFLAGS_PARALLEL=1 make integration EXTRA_TESTFLAGS=-no-criu + sudo GOPATH=$GOPATH GOPROXY=$GOPROXY TEST_RUNTIME=$TEST_RUNTIME RUNC_FLAVOR=$RUNC_FLAVOR TESTFLAGS_PARALLEL=1 make integration EXTRA_TESTFLAGS=-no-criu working-directory: src/github.com/containerd/containerd - name: CRI test diff --git a/container_test.go b/container_test.go index 2ae9d096a..2ebfc3a99 100644 --- a/container_test.go +++ b/container_test.go @@ -23,6 +23,7 @@ import ( "io/ioutil" "os" "os/exec" + "path" "runtime" "strings" "syscall" @@ -36,10 +37,12 @@ import ( "github.com/containerd/containerd/oci" "github.com/containerd/containerd/platforms" _ "github.com/containerd/containerd/runtime" + "github.com/containerd/containerd/runtime/v2/runc/options" "github.com/containerd/typeurl" specs "github.com/opencontainers/runtime-spec/specs-go" "github.com/containerd/containerd/errdefs" + "github.com/containerd/go-runc" gogotypes "github.com/gogo/protobuf/types" ) @@ -629,6 +632,78 @@ func TestContainerKill(t *testing.T) { } } +func TestKillContainerDeletedByRunc(t *testing.T) { + t.Parallel() + + // We skip this case when runtime is crun. + // More information in https://github.com/containerd/containerd/pull/4214#discussion_r422769497 + if os.Getenv("RUNC_FLAVOR") == "crun" { + t.Skip("skip it when using crun") + } + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + runcRoot = "/tmp/runc-test" + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Fatal(err) + } + container, err := client.NewContainer(ctx, id, + WithNewSnapshot(id, image), + WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "10")), + WithRuntime(client.runtime, &options.Options{Root: runcRoot})) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx) + + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + defer task.Delete(ctx) + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if err := task.Start(ctx); err != nil { + t.Fatal(err) + } + + rcmd := &runc.Runc{ + Root: path.Join(runcRoot, testNamespace), + } + + if err := rcmd.Delete(ctx, id, &runc.DeleteOpts{Force: true}); err != nil { + t.Fatal(err) + } + err = task.Kill(ctx, syscall.SIGKILL) + if err == nil { + t.Fatal("kill should return NotFound error") + } else if !errdefs.IsNotFound(err) { + t.Errorf("expected error %q but received %q", errdefs.ErrNotFound, err) + } + + select { + case <-statusC: + case <-time.After(2 * time.Second): + t.Errorf("unexpected timeout when try to get exited container's status") + } +} + func TestContainerNoBinaryExists(t *testing.T) { t.Parallel() diff --git a/pkg/process/utils.go b/pkg/process/utils.go index 3c4661770..444dbb657 100644 --- a/pkg/process/utils.go +++ b/pkg/process/utils.go @@ -137,6 +137,8 @@ func checkKillError(err error) error { strings.Contains(strings.ToLower(err.Error()), "no such process") || err == unix.ESRCH { return errors.Wrapf(errdefs.ErrNotFound, "process already finished") + } else if strings.Contains(err.Error(), "does not exist") { + return errors.Wrapf(errdefs.ErrNotFound, "no such container") } return errors.Wrapf(err, "unknown error after kill") }