diff --git a/tools/container/runtime/containerd/config_v3_test.go b/tools/container/runtime/containerd/config_v3_test.go new file mode 100644 index 00000000..10482bad --- /dev/null +++ b/tools/container/runtime/containerd/config_v3_test.go @@ -0,0 +1,476 @@ +/** +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +*/ + +package containerd + +import ( + "fmt" + "testing" + + testlog "github.com/sirupsen/logrus/hooks/test" + "github.com/stretchr/testify/require" + + "github.com/NVIDIA/nvidia-container-toolkit/pkg/config/engine/containerd" + "github.com/NVIDIA/nvidia-container-toolkit/pkg/config/toml" + "github.com/NVIDIA/nvidia-container-toolkit/tools/container" +) + +const ( + runtimeType = "runtime_type" +) + +func TestUpdateV3ConfigDefaultRuntime(t *testing.T) { + logger, _ := testlog.NewNullLogger() + const runtimeDir = "/test/runtime/dir" + + testCases := []struct { + setAsDefault bool + runtimeName string + expectedDefaultRuntimeName interface{} + }{ + {}, + { + setAsDefault: false, + runtimeName: "nvidia", + expectedDefaultRuntimeName: nil, + }, + { + setAsDefault: false, + runtimeName: "NAME", + expectedDefaultRuntimeName: nil, + }, + { + setAsDefault: true, + runtimeName: "nvidia", + expectedDefaultRuntimeName: "nvidia", + }, + { + setAsDefault: true, + runtimeName: "NAME", + expectedDefaultRuntimeName: "NAME", + }, + } + + for i, tc := range testCases { + t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { + o := &container.Options{ + RuntimeName: tc.runtimeName, + RuntimeDir: runtimeDir, + SetAsDefault: tc.setAsDefault, + } + + cfg, err := toml.LoadMap(map[string]interface{}{}) + require.NoError(t, err) + + v3 := &containerd.ConfigV3{ + Logger: logger, + Tree: cfg, + RuntimeType: runtimeType, + } + + err = o.UpdateConfig(v3) + require.NoError(t, err) + + defaultRuntimeName := cfg.GetPath([]string{"plugins", "io.containerd.grpc.v1.cri", "containerd", "default_runtime_name"}) + require.EqualValues(t, tc.expectedDefaultRuntimeName, defaultRuntimeName) + }) + } +} + +func TestUpdateV3Config(t *testing.T) { + logger, _ := testlog.NewNullLogger() + const runtimeDir = "/test/runtime/dir" + + testCases := []struct { + runtimeName string + expectedConfig map[string]interface{} + }{ + { + runtimeName: "nvidia", + expectedConfig: map[string]interface{}{ + "version": int64(3), + "plugins": map[string]interface{}{ + "io.containerd.grpc.v1.cri": map[string]interface{}{ + "containerd": map[string]interface{}{ + "runtimes": map[string]interface{}{ + "nvidia": map[string]interface{}{ + "runtime_type": "runtime_type", + "runtime_root": "", + "runtime_engine": "", + "privileged_without_host_devices": false, + "container_annotations": []string{"cdi.k8s.io/*"}, + "options": map[string]interface{}{ + "BinaryName": "/test/runtime/dir/nvidia-container-runtime", + }, + }, + "nvidia-cdi": map[string]interface{}{ + "runtime_type": "runtime_type", + "runtime_root": "", + "runtime_engine": "", + "privileged_without_host_devices": false, + "container_annotations": []string{"cdi.k8s.io/*"}, + "options": map[string]interface{}{ + "BinaryName": "/test/runtime/dir/nvidia-container-runtime.cdi", + }, + }, + "nvidia-legacy": map[string]interface{}{ + "runtime_type": "runtime_type", + "runtime_root": "", + "runtime_engine": "", + "privileged_without_host_devices": false, + "container_annotations": []string{"cdi.k8s.io/*"}, + "options": map[string]interface{}{ + "BinaryName": "/test/runtime/dir/nvidia-container-runtime.legacy", + }, + }, + }, + }, + }, + }, + }, + }, + { + runtimeName: "NAME", + expectedConfig: map[string]interface{}{ + "version": int64(3), + "plugins": map[string]interface{}{ + "io.containerd.grpc.v1.cri": map[string]interface{}{ + "containerd": map[string]interface{}{ + "runtimes": map[string]interface{}{ + "NAME": map[string]interface{}{ + "runtime_type": "runtime_type", + "runtime_root": "", + "runtime_engine": "", + "privileged_without_host_devices": false, + "container_annotations": []string{"cdi.k8s.io/*"}, + "options": map[string]interface{}{ + "BinaryName": "/test/runtime/dir/nvidia-container-runtime", + }, + }, + "nvidia-cdi": map[string]interface{}{ + "runtime_type": "runtime_type", + "runtime_root": "", + "runtime_engine": "", + "privileged_without_host_devices": false, + "container_annotations": []string{"cdi.k8s.io/*"}, + "options": map[string]interface{}{ + "BinaryName": "/test/runtime/dir/nvidia-container-runtime.cdi", + }, + }, + "nvidia-legacy": map[string]interface{}{ + "runtime_type": "runtime_type", + "runtime_root": "", + "runtime_engine": "", + "privileged_without_host_devices": false, + "container_annotations": []string{"cdi.k8s.io/*"}, + "options": map[string]interface{}{ + "BinaryName": "/test/runtime/dir/nvidia-container-runtime.legacy", + }, + }, + }, + }, + }, + }, + }, + }, + } + + for i, tc := range testCases { + t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { + o := &container.Options{ + RuntimeName: tc.runtimeName, + RuntimeDir: runtimeDir, + } + + cfg, err := toml.LoadMap(map[string]interface{}{}) + require.NoError(t, err) + + v3 := &containerd.ConfigV3{ + Logger: logger, + Tree: cfg, + RuntimeType: runtimeType, + ContainerAnnotations: []string{"cdi.k8s.io/*"}, + } + + err = o.UpdateConfig(v3) + require.NoError(t, err) + + expected, err := toml.TreeFromMap(tc.expectedConfig) + require.NoError(t, err) + + require.Equal(t, expected.String(), cfg.String()) + }) + } + +} + +func TestUpdateV3ConfigWithRuncPresent(t *testing.T) { + logger, _ := testlog.NewNullLogger() + const runtimeDir = "/test/runtime/dir" + + testCases := []struct { + runtimeName string + expectedConfig map[string]interface{} + }{ + { + runtimeName: "nvidia", + expectedConfig: map[string]interface{}{ + "version": int64(3), + "plugins": map[string]interface{}{ + "io.containerd.grpc.v1.cri": map[string]interface{}{ + "containerd": map[string]interface{}{ + "runtimes": map[string]interface{}{ + "runc": map[string]interface{}{ + "runtime_type": "runc_runtime_type", + "runtime_root": "runc_runtime_root", + "runtime_engine": "runc_runtime_engine", + "privileged_without_host_devices": true, + "options": map[string]interface{}{ + "runc-option": "value", + "BinaryName": "/runc-binary", + }, + }, + "nvidia": map[string]interface{}{ + "runtime_type": "runc_runtime_type", + "runtime_root": "runc_runtime_root", + "runtime_engine": "runc_runtime_engine", + "privileged_without_host_devices": true, + "container_annotations": []string{"cdi.k8s.io/*"}, + "options": map[string]interface{}{ + "runc-option": "value", + "BinaryName": "/test/runtime/dir/nvidia-container-runtime", + }, + }, + "nvidia-cdi": map[string]interface{}{ + "runtime_type": "runc_runtime_type", + "runtime_root": "runc_runtime_root", + "runtime_engine": "runc_runtime_engine", + "privileged_without_host_devices": true, + "container_annotations": []string{"cdi.k8s.io/*"}, + "options": map[string]interface{}{ + "runc-option": "value", + "BinaryName": "/test/runtime/dir/nvidia-container-runtime.cdi", + }, + }, + "nvidia-legacy": map[string]interface{}{ + "runtime_type": "runc_runtime_type", + "runtime_root": "runc_runtime_root", + "runtime_engine": "runc_runtime_engine", + "privileged_without_host_devices": true, + "container_annotations": []string{"cdi.k8s.io/*"}, + "options": map[string]interface{}{ + "runc-option": "value", + "BinaryName": "/test/runtime/dir/nvidia-container-runtime.legacy", + }, + }, + }, + }, + }, + }, + }, + }, + { + runtimeName: "NAME", + expectedConfig: map[string]interface{}{ + "version": int64(3), + "plugins": map[string]interface{}{ + "io.containerd.grpc.v1.cri": map[string]interface{}{ + "containerd": map[string]interface{}{ + "runtimes": map[string]interface{}{ + "runc": map[string]interface{}{ + "runtime_type": "runc_runtime_type", + "runtime_root": "runc_runtime_root", + "runtime_engine": "runc_runtime_engine", + "privileged_without_host_devices": true, + "options": map[string]interface{}{ + "runc-option": "value", + "BinaryName": "/runc-binary", + }, + }, + "NAME": map[string]interface{}{ + "runtime_type": "runc_runtime_type", + "runtime_root": "runc_runtime_root", + "runtime_engine": "runc_runtime_engine", + "privileged_without_host_devices": true, + "container_annotations": []string{"cdi.k8s.io/*"}, + "options": map[string]interface{}{ + "runc-option": "value", + "BinaryName": "/test/runtime/dir/nvidia-container-runtime", + }, + }, + "nvidia-cdi": map[string]interface{}{ + "runtime_type": "runc_runtime_type", + "runtime_root": "runc_runtime_root", + "runtime_engine": "runc_runtime_engine", + "privileged_without_host_devices": true, + "container_annotations": []string{"cdi.k8s.io/*"}, + "options": map[string]interface{}{ + "runc-option": "value", + "BinaryName": "/test/runtime/dir/nvidia-container-runtime.cdi", + }, + }, + "nvidia-legacy": map[string]interface{}{ + "runtime_type": "runc_runtime_type", + "runtime_root": "runc_runtime_root", + "runtime_engine": "runc_runtime_engine", + "privileged_without_host_devices": true, + "container_annotations": []string{"cdi.k8s.io/*"}, + "options": map[string]interface{}{ + "runc-option": "value", + "BinaryName": "/test/runtime/dir/nvidia-container-runtime.legacy", + }, + }, + }, + }, + }, + }, + }, + }, + } + + for i, tc := range testCases { + t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { + o := &container.Options{ + RuntimeName: tc.runtimeName, + RuntimeDir: runtimeDir, + } + + cfg, err := toml.LoadMap(runcConfigMapV2("/runc-binary")) + require.NoError(t, err) + + v3 := &containerd.ConfigV3{ + Logger: logger, + Tree: cfg, + RuntimeType: runtimeType, + ContainerAnnotations: []string{"cdi.k8s.io/*"}, + } + + err = o.UpdateConfig(v3) + require.NoError(t, err) + + expected, err := toml.TreeFromMap(tc.expectedConfig) + require.NoError(t, err) + + require.Equal(t, expected.String(), cfg.String()) + }) + } +} + +func TestRevertV3Config(t *testing.T) { + testCases := []struct { + config map[string]interface { + } + expected map[string]interface{} + }{ + {}, + { + config: map[string]interface{}{ + "version": int64(3), + }, + }, + { + config: map[string]interface{}{ + "version": int64(3), + "plugins": map[string]interface{}{ + "io.containerd.grpc.v1.cri": map[string]interface{}{ + "containerd": map[string]interface{}{ + "runtimes": map[string]interface{}{ + "nvidia": runtimeMapV2("/test/runtime/dir/nvidia-container-runtime"), + }, + }, + }, + }, + }, + }, + { + config: map[string]interface{}{ + "version": int64(3), + "plugins": map[string]interface{}{ + "io.containerd.grpc.v1.cri": map[string]interface{}{ + "containerd": map[string]interface{}{ + "runtimes": map[string]interface{}{ + "nvidia": runtimeMapV2("/test/runtime/dir/nvidia-container-runtime"), + }, + "default_runtime_name": "nvidia", + }, + }, + }, + }, + }, + } + + for i, tc := range testCases { + t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { + o := &container.Options{ + RuntimeName: "nvidia", + } + + cfg, err := toml.LoadMap(tc.config) + require.NoError(t, err) + + expected, err := toml.TreeFromMap(tc.expected) + require.NoError(t, err) + + v3 := &containerd.ConfigV3{ + Tree: cfg, + RuntimeType: runtimeType, + } + + err = o.RevertConfig(v3) + require.NoError(t, err) + + configContents, _ := toml.Marshal(cfg) + expectedContents, _ := toml.Marshal(expected) + + require.Equal(t, string(expectedContents), string(configContents)) + }) + } +} + +func runtimeMapV3(binary string) map[string]interface{} { + return map[string]interface{}{ + "runtime_type": runtimeType, + "runtime_root": "", + "runtime_engine": "", + "privileged_without_host_devices": false, + "options": map[string]interface{}{ + "BinaryName": binary, + }, + } +} + +func runcConfigMapV3(binary string) map[string]interface{} { + return map[string]interface{}{ + "plugins": map[string]interface{}{ + "io.containerd.grpc.v1.cri": map[string]interface{}{ + "containerd": map[string]interface{}{ + "runtimes": map[string]interface{}{ + "runc": map[string]interface{}{ + "runtime_type": "runc_runtime_type", + "runtime_root": "runc_runtime_root", + "runtime_engine": "runc_runtime_engine", + "privileged_without_host_devices": true, + "options": map[string]interface{}{ + "runc-option": "value", + "BinaryName": binary, + }, + }, + }, + }, + }, + }, + } +}