From ba5fcf13fc2f94ca5bbcd03bd86612f1fae6425d Mon Sep 17 00:00:00 2001 From: Flavio Castelli Date: Mon, 13 Nov 2023 23:43:41 +0100 Subject: [PATCH] Wasm shims and runtimes detection Create a generic helper function that finds extra containerd runtimes. The code was originally inside of the nvidia container discovery file. Signed-off-by: Flavio Castelli Discover the containerd shims based on runwasi that are already available on the node. The runtimes could have been installed either by a package manager or by the kwasm operator. Signed-off-by: Flavio Castelli The containerd configuration on a Linux system now handles the nvidia and the WebAssembly runtimes. Signed-off-by: Flavio Castelli --------- Signed-off-by: Flavio Castelli --- pkg/agent/containerd/config_linux.go | 6 +- pkg/agent/containerd/nvidia.go | 36 +---- pkg/agent/containerd/nvidia_test.go | 86 ++++++++--- pkg/agent/containerd/runtimes.go | 56 +++++++ pkg/agent/containerd/runtimes_test.go | 214 ++++++++++++++++++++++++++ pkg/agent/containerd/runwasi.go | 60 ++++++++ pkg/agent/containerd/runwasi_test.go | 199 ++++++++++++++++++++++++ 7 files changed, 604 insertions(+), 53 deletions(-) create mode 100644 pkg/agent/containerd/runtimes.go create mode 100644 pkg/agent/containerd/runtimes_test.go create mode 100644 pkg/agent/containerd/runwasi.go create mode 100644 pkg/agent/containerd/runwasi_test.go diff --git a/pkg/agent/containerd/config_linux.go b/pkg/agent/containerd/config_linux.go index 559d966dec..354576a685 100644 --- a/pkg/agent/containerd/config_linux.go +++ b/pkg/agent/containerd/config_linux.go @@ -60,6 +60,10 @@ func setupContainerdConfig(ctx context.Context, cfg *config.Node) error { cfg.AgentConfig.Systemd = !isRunningInUserNS && controllers["cpuset"] && os.Getenv("INVOCATION_ID") != "" } + extraRuntimes := runtimeConfigs{} + findNvidiaContainerRuntimes(os.DirFS(string(os.PathSeparator)), extraRuntimes) + findWasiRuntimes(os.DirFS(string(os.PathSeparator)), extraRuntimes) + var containerdTemplate string containerdConfig := templates.ContainerdConfig{ NodeConfig: cfg, @@ -68,7 +72,7 @@ func setupContainerdConfig(ctx context.Context, cfg *config.Node) error { IsRunningInUserNS: isRunningInUserNS, EnableUnprivileged: kernel.CheckKernelVersion(4, 11, 0), PrivateRegistryConfig: privRegistries.Registry, - ExtraRuntimes: findNvidiaContainerRuntimes(os.DirFS(string(os.PathSeparator))), + ExtraRuntimes: extraRuntimes, Program: version.Program, } diff --git a/pkg/agent/containerd/nvidia.go b/pkg/agent/containerd/nvidia.go index 96aae90a09..372ebdf4f6 100644 --- a/pkg/agent/containerd/nvidia.go +++ b/pkg/agent/containerd/nvidia.go @@ -4,12 +4,7 @@ package containerd import ( - "errors" "io/fs" - "path/filepath" - - "github.com/k3s-io/k3s/pkg/agent/templates" - "github.com/sirupsen/logrus" ) // findNvidiaContainerRuntimes returns a list of nvidia container runtimes that @@ -17,7 +12,7 @@ import ( // gpu operator and by system package managers. The gpu operator installation // takes precedence over the system package manager installation. // The given fs.FS should represent the filesystem root directory to search in. -func findNvidiaContainerRuntimes(root fs.FS) map[string]templates.ContainerdRuntimeConfig { +func findNvidiaContainerRuntimes(root fs.FS, foundRuntimes runtimeConfigs) { // Check these locations in order. The GPU operator's installation should // take precedence over the package manager's installation. locationsToCheck := []string{ @@ -28,7 +23,7 @@ func findNvidiaContainerRuntimes(root fs.FS) map[string]templates.ContainerdRunt // Fill in the binary location with just the name of the binary, // and check against each of the possible locations. If a match is found, // set the location to the full path. - potentialRuntimes := map[string]templates.ContainerdRuntimeConfig{ + potentialRuntimes := runtimeConfigs{ "nvidia": { RuntimeType: "io.containerd.runc.v2", BinaryName: "nvidia-container-runtime", @@ -38,30 +33,5 @@ func findNvidiaContainerRuntimes(root fs.FS) map[string]templates.ContainerdRunt BinaryName: "nvidia-container-runtime-experimental", }, } - foundRuntimes := map[string]templates.ContainerdRuntimeConfig{} -RUNTIME: - for runtimeName, runtimeConfig := range potentialRuntimes { - for _, location := range locationsToCheck { - binaryPath := filepath.Join(location, runtimeConfig.BinaryName) - logrus.Debugf("Searching for %s container runtime at /%s", runtimeName, binaryPath) - if info, err := fs.Stat(root, binaryPath); err == nil { - if info.IsDir() { - logrus.Debugf("Found %s container runtime at /%s, but it is a directory. Skipping.", runtimeName, binaryPath) - continue - } - runtimeConfig.BinaryName = filepath.Join("/", binaryPath) - logrus.Infof("Found %s container runtime at %s", runtimeName, runtimeConfig.BinaryName) - foundRuntimes[runtimeName] = runtimeConfig - // Skip to the next runtime to enforce precedence. - continue RUNTIME - } else { - if errors.Is(err, fs.ErrNotExist) { - logrus.Debugf("%s container runtime not found at /%s", runtimeName, binaryPath) - } else { - logrus.Errorf("Error searching for %s container runtime at /%s: %v", runtimeName, binaryPath, err) - } - } - } - } - return foundRuntimes + findContainerRuntimes(root, potentialRuntimes, locationsToCheck, foundRuntimes) } diff --git a/pkg/agent/containerd/nvidia_test.go b/pkg/agent/containerd/nvidia_test.go index 2f6f2fc0b0..ebbe08c76b 100644 --- a/pkg/agent/containerd/nvidia_test.go +++ b/pkg/agent/containerd/nvidia_test.go @@ -8,26 +8,26 @@ import ( "reflect" "testing" "testing/fstest" - - "github.com/k3s-io/k3s/pkg/agent/templates" ) func Test_UnitFindNvidiaContainerRuntimes(t *testing.T) { executable := &fstest.MapFile{Mode: 0755} type args struct { - root fs.FS + root fs.FS + alreadyFoundRuntimes runtimeConfigs } tests := []struct { name string args args - want map[string]templates.ContainerdRuntimeConfig + want runtimeConfigs }{ { name: "No runtimes", args: args{ - root: fstest.MapFS{}, + root: fstest.MapFS{}, + alreadyFoundRuntimes: runtimeConfigs{}, }, - want: map[string]templates.ContainerdRuntimeConfig{}, + want: runtimeConfigs{}, }, { name: "Nvidia runtime in /usr/bin", @@ -35,8 +35,9 @@ func Test_UnitFindNvidiaContainerRuntimes(t *testing.T) { root: fstest.MapFS{ "usr/bin/nvidia-container-runtime": executable, }, + alreadyFoundRuntimes: runtimeConfigs{}, }, - want: map[string]templates.ContainerdRuntimeConfig{ + want: runtimeConfigs{ "nvidia": { RuntimeType: "io.containerd.runc.v2", BinaryName: "/usr/bin/nvidia-container-runtime", @@ -49,8 +50,9 @@ func Test_UnitFindNvidiaContainerRuntimes(t *testing.T) { root: fstest.MapFS{ "usr/local/nvidia/toolkit/nvidia-container-runtime": executable, }, + alreadyFoundRuntimes: runtimeConfigs{}, }, - want: map[string]templates.ContainerdRuntimeConfig{ + want: runtimeConfigs{ "nvidia": { RuntimeType: "io.containerd.runc.v2", BinaryName: "/usr/local/nvidia/toolkit/nvidia-container-runtime", @@ -64,8 +66,9 @@ func Test_UnitFindNvidiaContainerRuntimes(t *testing.T) { "usr/bin/nvidia-container-runtime": executable, "usr/local/nvidia/toolkit/nvidia-container-runtime": executable, }, + alreadyFoundRuntimes: runtimeConfigs{}, }, - want: map[string]templates.ContainerdRuntimeConfig{ + want: runtimeConfigs{ "nvidia": { RuntimeType: "io.containerd.runc.v2", BinaryName: "/usr/local/nvidia/toolkit/nvidia-container-runtime", @@ -78,8 +81,9 @@ func Test_UnitFindNvidiaContainerRuntimes(t *testing.T) { root: fstest.MapFS{ "usr/bin/nvidia-container-runtime-experimental": executable, }, + alreadyFoundRuntimes: runtimeConfigs{}, }, - want: map[string]templates.ContainerdRuntimeConfig{ + want: runtimeConfigs{ "nvidia-experimental": { RuntimeType: "io.containerd.runc.v2", BinaryName: "/usr/bin/nvidia-container-runtime-experimental", @@ -93,8 +97,9 @@ func Test_UnitFindNvidiaContainerRuntimes(t *testing.T) { "usr/bin/nvidia-container-runtime-experimental": executable, "usr/local/nvidia/toolkit/nvidia-container-runtime-experimental": executable, }, + alreadyFoundRuntimes: runtimeConfigs{}, }, - want: map[string]templates.ContainerdRuntimeConfig{ + want: runtimeConfigs{ "nvidia-experimental": { RuntimeType: "io.containerd.runc.v2", BinaryName: "/usr/local/nvidia/toolkit/nvidia-container-runtime-experimental", @@ -108,8 +113,9 @@ func Test_UnitFindNvidiaContainerRuntimes(t *testing.T) { "usr/bin/nvidia-container-runtime-experimental": executable, "usr/bin/nvidia-container-runtime": executable, }, + alreadyFoundRuntimes: runtimeConfigs{}, }, - want: map[string]templates.ContainerdRuntimeConfig{ + want: runtimeConfigs{ "nvidia": { RuntimeType: "io.containerd.runc.v2", BinaryName: "/usr/bin/nvidia-container-runtime", @@ -129,8 +135,9 @@ func Test_UnitFindNvidiaContainerRuntimes(t *testing.T) { "usr/bin/nvidia-container-runtime": executable, "usr/bin/nvidia-container-runtime-experimental": executable, }, + alreadyFoundRuntimes: runtimeConfigs{}, }, - want: map[string]templates.ContainerdRuntimeConfig{ + want: runtimeConfigs{ "nvidia": { RuntimeType: "io.containerd.runc.v2", BinaryName: "/usr/local/nvidia/toolkit/nvidia-container-runtime", @@ -148,8 +155,9 @@ func Test_UnitFindNvidiaContainerRuntimes(t *testing.T) { "usr/local/nvidia/toolkit/nvidia-container-runtime": executable, "usr/local/nvidia/toolkit/nvidia-container-runtime-experimental": executable, }, + alreadyFoundRuntimes: runtimeConfigs{}, }, - want: map[string]templates.ContainerdRuntimeConfig{ + want: runtimeConfigs{ "nvidia": { RuntimeType: "io.containerd.runc.v2", BinaryName: "/usr/local/nvidia/toolkit/nvidia-container-runtime", @@ -168,8 +176,9 @@ func Test_UnitFindNvidiaContainerRuntimes(t *testing.T) { "usr/bin/nvidia-container-runtime-experimental": executable, "usr/local/nvidia/toolkit/nvidia-container-runtime-experimental": executable, }, + alreadyFoundRuntimes: runtimeConfigs{}, }, - want: map[string]templates.ContainerdRuntimeConfig{ + want: runtimeConfigs{ "nvidia": { RuntimeType: "io.containerd.runc.v2", BinaryName: "/usr/bin/nvidia-container-runtime", @@ -188,8 +197,9 @@ func Test_UnitFindNvidiaContainerRuntimes(t *testing.T) { Mode: fs.ModeDir, }, }, + alreadyFoundRuntimes: runtimeConfigs{}, }, - want: map[string]templates.ContainerdRuntimeConfig{}, + want: runtimeConfigs{}, }, { name: "Runtime in both directories, but one is a directory", @@ -200,8 +210,44 @@ func Test_UnitFindNvidiaContainerRuntimes(t *testing.T) { Mode: fs.ModeDir, }, }, + alreadyFoundRuntimes: runtimeConfigs{}, + }, + want: runtimeConfigs{ + "nvidia": { + RuntimeType: "io.containerd.runc.v2", + BinaryName: "/usr/bin/nvidia-container-runtime", + }, }, - want: map[string]templates.ContainerdRuntimeConfig{ + }, + { + name: "Preserve already found runtimes", + args: args{ + root: fstest.MapFS{ + "usr/bin/nvidia-container-runtime": executable, + "usr/local/nvidia/toolkit/nvidia-container-runtime": &fstest.MapFile{ + Mode: fs.ModeDir, + }, + }, + alreadyFoundRuntimes: runtimeConfigs{ + "slight": { + RuntimeType: "io.containerd.slight.v2", + BinaryName: "/opt/kwasm/bin/containerd-shim-slight-v1", + }, + "wasmtime": { + RuntimeType: "io.containerd.wasmtime.v2", + BinaryName: "/opt/kwasm/bin/containerd-shim-wasmtime-v1", + }, + }, + }, + want: runtimeConfigs{ + "slight": { + RuntimeType: "io.containerd.slight.v2", + BinaryName: "/opt/kwasm/bin/containerd-shim-slight-v1", + }, + "wasmtime": { + RuntimeType: "io.containerd.wasmtime.v2", + BinaryName: "/opt/kwasm/bin/containerd-shim-wasmtime-v1", + }, "nvidia": { RuntimeType: "io.containerd.runc.v2", BinaryName: "/usr/bin/nvidia-container-runtime", @@ -211,8 +257,10 @@ func Test_UnitFindNvidiaContainerRuntimes(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := findNvidiaContainerRuntimes(tt.args.root); !reflect.DeepEqual(got, tt.want) { - t.Errorf("findNvidiaContainerRuntimes() = %+v\nWant = %+v", got, tt.want) + foundRuntimes := tt.args.alreadyFoundRuntimes + findNvidiaContainerRuntimes(tt.args.root, foundRuntimes) + if !reflect.DeepEqual(foundRuntimes, tt.want) { + t.Errorf("findNvidiaContainerRuntimes() = %+v\nWant = %+v", foundRuntimes, tt.want) } }) } diff --git a/pkg/agent/containerd/runtimes.go b/pkg/agent/containerd/runtimes.go new file mode 100644 index 0000000000..a4a09efb34 --- /dev/null +++ b/pkg/agent/containerd/runtimes.go @@ -0,0 +1,56 @@ +//go:build linux +// +build linux + +package containerd + +import ( + "errors" + "io/fs" + "path/filepath" + + "github.com/k3s-io/k3s/pkg/agent/templates" + "github.com/sirupsen/logrus" +) + +// A map with string as value and `templates.ContainerdRuntimeConfig` as values. +// The key holds the name of the runtime +type runtimeConfigs map[string]templates.ContainerdRuntimeConfig + +// findContainerRuntimes returns a list of container runtimes that +// are available on the system. It checks install locations provided via +// the potentialRuntimes variable. +// The binaries are searched at the locations specivied by locationsToCheck. +// Note: check the given locations in order. +// The given fs.FS should represent the filesystem root directory to search in. +func findContainerRuntimes(root fs.FS, potentialRuntimes runtimeConfigs, locationsToCheck []string, foundRuntimes runtimeConfigs) { + // Check these locations in order. The GPU operator's installation should + // take precedence over the package manager's installation. + + // Fill in the binary location with just the name of the binary, + // and check against each of the possible locations. If a match is found, + // set the location to the full path. +RUNTIME: + for runtimeName, runtimeConfig := range potentialRuntimes { + for _, location := range locationsToCheck { + binaryPath := filepath.Join(location, runtimeConfig.BinaryName) + logrus.Debugf("Searching for %s container runtime at /%s", runtimeName, binaryPath) + if info, err := fs.Stat(root, binaryPath); err == nil { + if info.IsDir() { + logrus.Debugf("Found %s container runtime at /%s, but it is a directory. Skipping.", runtimeName, binaryPath) + continue + } + runtimeConfig.BinaryName = filepath.Join("/", binaryPath) + logrus.Infof("Found %s container runtime at %s", runtimeName, runtimeConfig.BinaryName) + foundRuntimes[runtimeName] = runtimeConfig + // Skip to the next runtime to enforce precedence. + continue RUNTIME + } else { + if errors.Is(err, fs.ErrNotExist) { + logrus.Debugf("%s container runtime not found at /%s", runtimeName, binaryPath) + } else { + logrus.Errorf("Error searching for %s container runtime at /%s: %v", runtimeName, binaryPath, err) + } + } + } + } +} diff --git a/pkg/agent/containerd/runtimes_test.go b/pkg/agent/containerd/runtimes_test.go new file mode 100644 index 0000000000..c5c63af2a6 --- /dev/null +++ b/pkg/agent/containerd/runtimes_test.go @@ -0,0 +1,214 @@ +//go:build linux +// +build linux + +package containerd + +import ( + "io/fs" + "reflect" + "testing" + "testing/fstest" +) + +func Test_UnitFindContainerRuntimes(t *testing.T) { + executable := &fstest.MapFile{Mode: 0755} + locationsToCheck := []string{ + "usr/local/nvidia/toolkit", // Path for nvidia shim when installing via GPU Operator + "opt/kwasm/bin", // Path for wasm shim when installing via the kwasm operator + "usr/bin", // Path when installing via package manager + "usr/sbin", // Path when installing via package manager + } + + potentialRuntimes := runtimeConfigs{ + "nvidia": { + RuntimeType: "io.containerd.runc.v2", + BinaryName: "nvidia-container-runtime", + }, + "spin": { + RuntimeType: "io.containerd.spin.v2", + BinaryName: "containerd-shim-spin-v1", + }, + } + + type args struct { + root fs.FS + potentialRuntimes runtimeConfigs + locationsToCheck []string + } + tests := []struct { + name string + args args + want runtimeConfigs + }{ + { + name: "No runtimes", + args: args{ + root: fstest.MapFS{}, + locationsToCheck: locationsToCheck, + potentialRuntimes: potentialRuntimes, + }, + want: runtimeConfigs{}, + }, + { + name: "Nvidia runtime in /usr/bin", + args: args{ + root: fstest.MapFS{ + "usr/bin/nvidia-container-runtime": executable, + }, + locationsToCheck: locationsToCheck, + potentialRuntimes: potentialRuntimes, + }, + want: runtimeConfigs{ + "nvidia": { + RuntimeType: "io.containerd.runc.v2", + BinaryName: "/usr/bin/nvidia-container-runtime", + }, + }, + }, + { + name: "Two runtimes in separate directories", + args: args{ + root: fstest.MapFS{ + "usr/bin/nvidia-container-runtime": executable, + "opt/kwasm/bin/containerd-shim-spin-v1": executable, + }, + locationsToCheck: locationsToCheck, + potentialRuntimes: potentialRuntimes, + }, + want: runtimeConfigs{ + "nvidia": { + RuntimeType: "io.containerd.runc.v2", + BinaryName: "/usr/bin/nvidia-container-runtime", + }, + "spin": { + RuntimeType: "io.containerd.spin.v2", + BinaryName: "/opt/kwasm/bin/containerd-shim-spin-v1", + }, + }, + }, + { + name: "Same runtime in two directories", + args: args{ + root: fstest.MapFS{ + "usr/bin/containerd-shim-spin-v1": executable, + "opt/kwasm/bin/containerd-shim-spin-v1": executable, + }, + locationsToCheck: locationsToCheck, + potentialRuntimes: potentialRuntimes, + }, + want: runtimeConfigs{ + "spin": { + RuntimeType: "io.containerd.spin.v2", + BinaryName: "/opt/kwasm/bin/containerd-shim-spin-v1", + }, + }, + }, + { + name: "Both runtimes in /usr/bin", + args: args{ + root: fstest.MapFS{ + "usr/bin/containerd-shim-spin-v1": executable, + "usr/bin/nvidia-container-runtime": executable, + }, + locationsToCheck: locationsToCheck, + potentialRuntimes: potentialRuntimes, + }, + want: runtimeConfigs{ + "nvidia": { + RuntimeType: "io.containerd.runc.v2", + BinaryName: "/usr/bin/nvidia-container-runtime", + }, + "spin": { + RuntimeType: "io.containerd.spin.v2", + BinaryName: "/usr/bin/containerd-shim-spin-v1", + }, + }, + }, + { + name: "Both runtimes in both directories", + args: args{ + root: fstest.MapFS{ + "usr/local/nvidia/toolkit/nvidia-container-runtime": executable, + "usr/bin/nvidia-container-runtime": executable, + "usr/bin/containerd-shim-spin-v1": executable, + "opt/kwasm/bin/containerd-shim-spin-v1": executable, + }, + locationsToCheck: locationsToCheck, + potentialRuntimes: potentialRuntimes, + }, + want: runtimeConfigs{ + "nvidia": { + RuntimeType: "io.containerd.runc.v2", + BinaryName: "/usr/local/nvidia/toolkit/nvidia-container-runtime", + }, + "spin": { + RuntimeType: "io.containerd.spin.v2", + BinaryName: "/opt/kwasm/bin/containerd-shim-spin-v1", + }, + }, + }, + { + name: "Both runtimes in /usr/bin and one duplicate in /usr/local/nvidia/toolkit", + args: args{ + root: fstest.MapFS{ + "usr/bin/nvidia-container-runtime": executable, + "usr/bin/containerd-shim-spin-v1": executable, + "usr/local/nvidia/toolkit/nvidia-container-runtime": executable, + }, + locationsToCheck: locationsToCheck, + potentialRuntimes: potentialRuntimes, + }, + want: runtimeConfigs{ + "spin": { + RuntimeType: "io.containerd.spin.v2", + BinaryName: "/usr/bin/containerd-shim-spin-v1", + }, + "nvidia": { + RuntimeType: "io.containerd.runc.v2", + BinaryName: "/usr/local/nvidia/toolkit/nvidia-container-runtime", + }, + }, + }, + { + name: "Runtime is a directory", + args: args{ + root: fstest.MapFS{ + "usr/bin/nvidia-container-runtime": &fstest.MapFile{ + Mode: fs.ModeDir, + }, + }, + locationsToCheck: locationsToCheck, + potentialRuntimes: potentialRuntimes, + }, + want: runtimeConfigs{}, + }, + { + name: "Runtime in both directories, but one is a directory", + args: args{ + root: fstest.MapFS{ + "usr/bin/nvidia-container-runtime": executable, + "usr/local/nvidia/toolkit/nvidia-container-runtime": &fstest.MapFile{ + Mode: fs.ModeDir, + }, + }, + locationsToCheck: locationsToCheck, + potentialRuntimes: potentialRuntimes, + }, + want: runtimeConfigs{ + "nvidia": { + RuntimeType: "io.containerd.runc.v2", + BinaryName: "/usr/bin/nvidia-container-runtime", + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + foundRuntimes := runtimeConfigs{} + findContainerRuntimes(tt.args.root, tt.args.potentialRuntimes, tt.args.locationsToCheck, foundRuntimes) + if !reflect.DeepEqual(foundRuntimes, tt.want) { + t.Errorf("findContainerRuntimes() = %+v\nWant = %+v", foundRuntimes, tt.want) + } + }) + } +} diff --git a/pkg/agent/containerd/runwasi.go b/pkg/agent/containerd/runwasi.go new file mode 100644 index 0000000000..e64d35c732 --- /dev/null +++ b/pkg/agent/containerd/runwasi.go @@ -0,0 +1,60 @@ +//go:build linux +// +build linux + +package containerd + +import ( + "io/fs" +) + +// findWasiRuntimes returns a list of WebAssembly (WASI) container runtimes that +// are available on the system. It checks install locations used by the kwasm +// operator and by system package managers. The kwasm operator installation +// takes precedence over the system package manager installation. +// The given fs.FS should represent the filesystem root directory to search in. +func findWasiRuntimes(root fs.FS, + foundRuntimes runtimeConfigs, +) { + // Check these locations in order. The GPU operator's installation should + // take precedence over the package manager's installation. + locationsToCheck := []string{ + "opt/kwasm/bin", // Path when installing via kwasm Operator + "usr/bin", // Path when installing via package manager + "usr/sbin", // Path when installing via package manager + } + + // Fill in the binary location with just the name of the binary, + // and check against each of the possible locations. If a match is found, + // set the location to the full path. + potentialRuntimes := runtimeConfigs{ + "lunatic": { + RuntimeType: "io.containerd.lunatic.v2", + BinaryName: "containerd-shim-lunatic-v1", + }, + "slight": { + RuntimeType: "io.containerd.slight.v2", + BinaryName: "containerd-shim-slight-v1", + }, + "spin": { + RuntimeType: "io.containerd.spin.v2", + BinaryName: "containerd-shim-spin-v1", + }, + "wws": { + RuntimeType: "io.containerd.wws.v2", + BinaryName: "containerd-shim-wws-v1", + }, + "wasmedge": { + RuntimeType: "io.containerd.wasmedge.v2", + BinaryName: "containerd-shim-wasmedge-v1", + }, + "wasmer": { + RuntimeType: "io.containerd.wasmer.v2", + BinaryName: "containerd-shim-wasmer-v1", + }, + "wasmtime": { + RuntimeType: "io.containerd.wasmtime.v2", + BinaryName: "containerd-shim-wasmtime-v1", + }, + } + findContainerRuntimes(root, potentialRuntimes, locationsToCheck, foundRuntimes) +} diff --git a/pkg/agent/containerd/runwasi_test.go b/pkg/agent/containerd/runwasi_test.go new file mode 100644 index 0000000000..d5d5a7a344 --- /dev/null +++ b/pkg/agent/containerd/runwasi_test.go @@ -0,0 +1,199 @@ +//go:build linux +// +build linux + +package containerd + +import ( + "io/fs" + "reflect" + "testing" + "testing/fstest" +) + +func Test_UnitFindWasiRuntimes(t *testing.T) { + executable := &fstest.MapFile{Mode: 0755} + type args struct { + root fs.FS + alreadyFoundRuntimes runtimeConfigs + } + tests := []struct { + name string + args args + want runtimeConfigs + }{ + { + name: "No runtimes", + args: args{ + root: fstest.MapFS{}, + alreadyFoundRuntimes: runtimeConfigs{}, + }, + want: runtimeConfigs{}, + }, + { + name: "wasmtime runtime in /usr/sbin", + args: args{ + root: fstest.MapFS{ + "usr/sbin/containerd-shim-wasmtime-v1": executable, + }, + alreadyFoundRuntimes: runtimeConfigs{}, + }, + want: runtimeConfigs{ + "wasmtime": { + RuntimeType: "io.containerd.wasmtime.v2", + BinaryName: "/usr/sbin/containerd-shim-wasmtime-v1", + }, + }, + }, + { + name: "lunatic runtime in /opt/kwasm/bin/", + args: args{ + root: fstest.MapFS{ + "opt/kwasm/bin/containerd-shim-lunatic-v1": executable, + }, + alreadyFoundRuntimes: runtimeConfigs{}, + }, + want: runtimeConfigs{ + "lunatic": { + RuntimeType: "io.containerd.lunatic.v2", + BinaryName: "/opt/kwasm/bin/containerd-shim-lunatic-v1", + }, + }, + }, + { + name: "Two runtimes in separate directories", + args: args{ + root: fstest.MapFS{ + "usr/bin/containerd-shim-wasmer-v1": executable, + "opt/kwasm/bin/containerd-shim-slight-v1": executable, + }, + alreadyFoundRuntimes: runtimeConfigs{}, + }, + want: runtimeConfigs{ + "slight": { + RuntimeType: "io.containerd.slight.v2", + BinaryName: "/opt/kwasm/bin/containerd-shim-slight-v1", + }, + "wasmer": { + RuntimeType: "io.containerd.wasmer.v2", + BinaryName: "/usr/bin/containerd-shim-wasmer-v1", + }, + }, + }, + { + name: "Same runtime in two directories", + args: args{ + root: fstest.MapFS{ + "usr/bin/containerd-shim-wasmedge-v1": executable, + "opt/kwasm/bin/containerd-shim-wasmedge-v1": executable, + }, + alreadyFoundRuntimes: runtimeConfigs{}, + }, + want: runtimeConfigs{ + "wasmedge": { + RuntimeType: "io.containerd.wasmedge.v2", + BinaryName: "/opt/kwasm/bin/containerd-shim-wasmedge-v1", + }, + }, + }, + { + name: "All runtimes in /usr/bin", + args: args{ + root: fstest.MapFS{ + "usr/bin/containerd-shim-lunatic-v1": executable, + "usr/bin/containerd-shim-slight-v1": executable, + "usr/bin/containerd-shim-spin-v1": executable, + "usr/bin/containerd-shim-wws-v1": executable, + "usr/bin/containerd-shim-wasmedge-v1": executable, + "usr/bin/containerd-shim-wasmer-v1": executable, + "usr/bin/containerd-shim-wasmtime-v1": executable, + }, + alreadyFoundRuntimes: runtimeConfigs{}, + }, + want: runtimeConfigs{ + "lunatic": { + RuntimeType: "io.containerd.lunatic.v2", + BinaryName: "/usr/bin/containerd-shim-lunatic-v1", + }, + "slight": { + RuntimeType: "io.containerd.slight.v2", + BinaryName: "/usr/bin/containerd-shim-slight-v1", + }, + "spin": { + RuntimeType: "io.containerd.spin.v2", + BinaryName: "/usr/bin/containerd-shim-spin-v1", + }, + "wws": { + RuntimeType: "io.containerd.wws.v2", + BinaryName: "/usr/bin/containerd-shim-wws-v1", + }, + "wasmedge": { + RuntimeType: "io.containerd.wasmedge.v2", + BinaryName: "/usr/bin/containerd-shim-wasmedge-v1", + }, + "wasmer": { + RuntimeType: "io.containerd.wasmer.v2", + BinaryName: "/usr/bin/containerd-shim-wasmer-v1", + }, + "wasmtime": { + RuntimeType: "io.containerd.wasmtime.v2", + BinaryName: "/usr/bin/containerd-shim-wasmtime-v1", + }, + }, + }, + { + name: "Both runtimes in both directories", + args: args{ + root: fstest.MapFS{ + "opt/kwasm/bin/containerd-shim-slight-v1": executable, + "opt/kwasm/bin/containerd-shim-wasmtime-v1": executable, + "usr/bin/containerd-shim-slight-v1": executable, + "usr/bin/containerd-shim-wasmtime-v1": executable, + }, + alreadyFoundRuntimes: runtimeConfigs{}, + }, + want: runtimeConfigs{ + "slight": { + RuntimeType: "io.containerd.slight.v2", + BinaryName: "/opt/kwasm/bin/containerd-shim-slight-v1", + }, + "wasmtime": { + RuntimeType: "io.containerd.wasmtime.v2", + BinaryName: "/opt/kwasm/bin/containerd-shim-wasmtime-v1", + }, + }, + }, + { + name: "Preserve already found runtimes", + args: args{ + root: fstest.MapFS{ + "opt/kwasm/bin/containerd-shim-wasmtime-v1": executable, + }, + alreadyFoundRuntimes: runtimeConfigs{ + "nvidia": { + RuntimeType: "io.containerd.runc.v2", + BinaryName: "/usr/bin/nvidia-container-runtime", + }, + }, + }, + want: runtimeConfigs{ + "nvidia": { + RuntimeType: "io.containerd.runc.v2", + BinaryName: "/usr/bin/nvidia-container-runtime", + }, + "wasmtime": { + RuntimeType: "io.containerd.wasmtime.v2", + BinaryName: "/opt/kwasm/bin/containerd-shim-wasmtime-v1", + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + foundRuntimes := tt.args.alreadyFoundRuntimes + findWasiRuntimes(tt.args.root, foundRuntimes) + if !reflect.DeepEqual(foundRuntimes, tt.want) { + t.Errorf("findWasiRuntimes() = %+v\nWant = %+v", foundRuntimes, tt.want) + } + }) + } +}