diff --git a/integration/client/container_test.go b/integration/client/container_test.go index 45b937ee4..81928ce49 100644 --- a/integration/client/container_test.go +++ b/integration/client/container_test.go @@ -23,6 +23,7 @@ import ( "io" "os" "path" + "path/filepath" "runtime" "strings" "syscall" @@ -39,9 +40,11 @@ import ( "github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/oci" "github.com/containerd/containerd/platforms" + "github.com/containerd/containerd/plugin" gogotypes "github.com/containerd/containerd/protobuf/types" _ "github.com/containerd/containerd/runtime" "github.com/containerd/containerd/runtime/v2/runc/options" + "github.com/containerd/continuity/fs" "github.com/containerd/go-runc" "github.com/containerd/typeurl/v2" specs "github.com/opencontainers/runtime-spec/specs-go" @@ -173,6 +176,130 @@ func TestContainerStart(t *testing.T) { } } +func readShimPath(taskID string) (string, error) { + runtime := fmt.Sprintf("%s.%s", plugin.RuntimePluginV2, "task") + shimBinaryNamePath := filepath.Join(defaultState, runtime, testNamespace, taskID, "shim-binary-path") + + shimPath, err := os.ReadFile(shimBinaryNamePath) + if err != nil { + return "", err + } + return string(shimPath), nil +} + +func copyShim(shimPath string) (string, error) { + tempPath := filepath.Join(os.TempDir(), filepath.Base(shimPath)) + if err := fs.CopyFile(tempPath, shimPath); err != nil { + return "", err + } + + fi, err := os.Stat(shimPath) + if err != nil { + return "", err + } + if err := os.Chmod(tempPath, fi.Mode().Perm()); err != nil { + return "", err + } + + return tempPath, nil +} + +func TestContainerStartWithAbsRuntimePath(t *testing.T) { + t.Parallel() + + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext(t) + id = t.Name() + ) + 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), withExitStatus(7))) + if err != nil { + t.Fatal(err) + } + defer container.Delete(ctx, WithSnapshotCleanup) + + // create a temp task to read the default shim path + task, err := container.NewTask(ctx, empty()) + if err != nil { + t.Fatal(err) + } + + defaultShimPath, err := readShimPath(task.ID()) + if err != nil { + t.Fatal(err) + } + + // remove the temp task + if _, err := task.Delete(ctx, WithProcessKill); err != nil { + t.Fatal(err) + } + + tempShimPath, err := copyShim(defaultShimPath) + if err != nil { + t.Fatal(err) + } + defer os.Remove(tempShimPath) + + task, err = container.NewTask(ctx, empty(), WithRuntimePath(tempShimPath)) + if err != nil { + t.Fatal(err) + } + + shimPath, err := readShimPath(task.ID()) + if err != nil { + t.Fatal(err) + } + if shimPath != tempShimPath { + t.Fatalf("The task's shim path is %s, does not used the specified runtime path: %s", shimPath, tempShimPath) + } + + statusC, err := task.Wait(ctx) + if err != nil { + t.Fatal(err) + } + + if runtime.GOOS != "windows" { + // task.Pid not implemented on Windows + if pid := task.Pid(); pid < 1 { + t.Errorf("invalid task pid %d", pid) + } + } + + if err := task.Start(ctx); err != nil { + t.Error(err) + task.Delete(ctx) + return + } + status := <-statusC + code, _, err := status.Result() + if err != nil { + t.Fatal(err) + } + if code != 7 { + t.Errorf("expected status 7 from wait but received %d", code) + } + + deleteStatus, err := task.Delete(ctx) + if err != nil { + t.Fatal(err) + } + if ec := deleteStatus.ExitCode(); ec != 7 { + t.Errorf("expected status 7 from delete but received %d", ec) + } +} + func TestContainerOutput(t *testing.T) { t.Parallel() diff --git a/integration/client/go.mod b/integration/client/go.mod index e55ddf42c..84c2896ea 100644 --- a/integration/client/go.mod +++ b/integration/client/go.mod @@ -8,6 +8,7 @@ require ( github.com/Microsoft/hcsshim/test v0.0.0-20210408205431-da33ecd607e1 github.com/containerd/cgroups/v3 v3.0.1 github.com/containerd/containerd v1.7.0-beta.0 // see replace; the actual version of containerd is replaced with the code at the root of this repository + github.com/containerd/continuity v0.3.0 github.com/containerd/go-runc v1.0.0 github.com/containerd/ttrpc v1.2.1 github.com/containerd/typeurl/v2 v2.1.0 @@ -27,7 +28,6 @@ require ( github.com/cilium/ebpf v0.9.1 // indirect github.com/containerd/cgroups v1.1.0 // indirect github.com/containerd/console v1.0.3 // indirect - github.com/containerd/continuity v0.3.0 // indirect github.com/containerd/fifo v1.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cyphar/filepath-securejoin v0.2.3 // indirect