github.com/rawahars/moby@v24.0.4+incompatible/daemon/runtime_unix_test.go (about) 1 //go:build !windows 2 // +build !windows 3 4 package daemon 5 6 import ( 7 "os" 8 "path/filepath" 9 "testing" 10 11 "github.com/containerd/containerd/plugin" 12 v2runcoptions "github.com/containerd/containerd/runtime/v2/runc/options" 13 "gotest.tools/v3/assert" 14 is "gotest.tools/v3/assert/cmp" 15 16 "github.com/docker/docker/api/types" 17 "github.com/docker/docker/daemon/config" 18 "github.com/docker/docker/errdefs" 19 ) 20 21 func TestInitRuntimes_InvalidConfigs(t *testing.T) { 22 cases := []struct { 23 name string 24 runtime types.Runtime 25 expectErr string 26 }{ 27 { 28 name: "Empty", 29 expectErr: "either a runtimeType or a path must be configured", 30 }, 31 { 32 name: "ArgsOnly", 33 runtime: types.Runtime{Args: []string{"foo", "bar"}}, 34 expectErr: "either a runtimeType or a path must be configured", 35 }, 36 { 37 name: "OptionsOnly", 38 runtime: types.Runtime{Options: map[string]interface{}{"hello": "world"}}, 39 expectErr: "either a runtimeType or a path must be configured", 40 }, 41 { 42 name: "PathAndType", 43 runtime: types.Runtime{Path: "/bin/true", Type: "io.containerd.runsc.v1"}, 44 expectErr: "cannot configure both", 45 }, 46 { 47 name: "PathAndOptions", 48 runtime: types.Runtime{Path: "/bin/true", Options: map[string]interface{}{"a": "b"}}, 49 expectErr: "options cannot be used with a path runtime", 50 }, 51 { 52 name: "TypeAndArgs", 53 runtime: types.Runtime{Type: "io.containerd.runsc.v1", Args: []string{"--version"}}, 54 expectErr: "args cannot be used with a runtimeType runtime", 55 }, 56 { 57 name: "PathArgsOptions", 58 runtime: types.Runtime{ 59 Path: "/bin/true", 60 Args: []string{"--version"}, 61 Options: map[string]interface{}{"hmm": 3}, 62 }, 63 expectErr: "options cannot be used with a path runtime", 64 }, 65 { 66 name: "TypeOptionsArgs", 67 runtime: types.Runtime{ 68 Type: "io.containerd.kata.v2", 69 Options: map[string]interface{}{"a": "b"}, 70 Args: []string{"--help"}, 71 }, 72 expectErr: "args cannot be used with a runtimeType runtime", 73 }, 74 { 75 name: "PathArgsTypeOptions", 76 runtime: types.Runtime{ 77 Path: "/bin/true", 78 Args: []string{"foo"}, 79 Type: "io.containerd.runsc.v1", 80 Options: map[string]interface{}{"a": "b"}, 81 }, 82 expectErr: "cannot configure both", 83 }, 84 } 85 86 for _, tt := range cases { 87 t.Run(tt.name, func(t *testing.T) { 88 cfg, err := config.New() 89 assert.NilError(t, err) 90 d := &Daemon{configStore: cfg} 91 d.configStore.Root = t.TempDir() 92 assert.Assert(t, os.Mkdir(filepath.Join(d.configStore.Root, "runtimes"), 0700)) 93 94 err = d.initRuntimes(map[string]types.Runtime{"myruntime": tt.runtime}) 95 assert.Check(t, is.ErrorContains(err, tt.expectErr)) 96 }) 97 } 98 } 99 100 func TestGetRuntime(t *testing.T) { 101 // Configured runtimes can have any arbitrary name, including names 102 // which would not be allowed as implicit runtime names. Explicit takes 103 // precedence over implicit. 104 const configuredRtName = "my/custom.runtime.v1" 105 configuredRuntime := types.Runtime{Path: "/bin/true"} 106 107 const rtWithArgsName = "withargs" 108 rtWithArgs := types.Runtime{ 109 Path: "/bin/false", 110 Args: []string{"--version"}, 111 } 112 113 const shimWithOptsName = "shimwithopts" 114 shimWithOpts := types.Runtime{ 115 Type: plugin.RuntimeRuncV2, 116 Options: map[string]interface{}{"IoUid": 42}, 117 } 118 119 const shimAliasName = "wasmedge" 120 shimAlias := types.Runtime{Type: "io.containerd.wasmedge.v1"} 121 122 const configuredShimByPathName = "shimwithpath" 123 configuredShimByPath := types.Runtime{Type: "/path/to/my/shim"} 124 125 cfg, err := config.New() 126 assert.NilError(t, err) 127 128 d := &Daemon{configStore: cfg} 129 d.configStore.Root = t.TempDir() 130 assert.Assert(t, os.Mkdir(filepath.Join(d.configStore.Root, "runtimes"), 0700)) 131 d.configStore.Runtimes = map[string]types.Runtime{ 132 configuredRtName: configuredRuntime, 133 rtWithArgsName: rtWithArgs, 134 shimWithOptsName: shimWithOpts, 135 shimAliasName: shimAlias, 136 configuredShimByPathName: configuredShimByPath, 137 } 138 configureRuntimes(d.configStore) 139 assert.Assert(t, d.loadRuntimes()) 140 141 stockRuntime, ok := d.configStore.Runtimes[config.StockRuntimeName] 142 assert.Assert(t, ok, "stock runtime could not be found (test needs to be updated)") 143 144 configdOpts := *stockRuntime.ShimConfig.Opts.(*v2runcoptions.Options) 145 configdOpts.BinaryName = configuredRuntime.Path 146 147 for _, tt := range []struct { 148 name, runtime string 149 wantShim string 150 wantOpts interface{} 151 }{ 152 { 153 name: "StockRuntime", 154 runtime: config.StockRuntimeName, 155 wantShim: stockRuntime.ShimConfig.Binary, 156 wantOpts: stockRuntime.ShimConfig.Opts, 157 }, 158 { 159 name: "ShimName", 160 runtime: "io.containerd.my-shim.v42", 161 wantShim: "io.containerd.my-shim.v42", 162 }, 163 { 164 // containerd is pretty loose about the format of runtime names. Perhaps too 165 // loose. The only requirements are that the name contain a dot and (depending 166 // on the containerd version) not start with a dot. It does not enforce any 167 // particular format of the dot-delimited components of the name. 168 name: "VersionlessShimName", 169 runtime: "io.containerd.my-shim", 170 wantShim: "io.containerd.my-shim", 171 }, 172 { 173 name: "IllformedShimName", 174 runtime: "myshim", 175 }, 176 { 177 name: "EmptyString", 178 runtime: "", 179 }, 180 { 181 name: "PathToShim", 182 runtime: "/path/to/runc", 183 }, 184 { 185 name: "PathToShimName", 186 runtime: "/path/to/io.containerd.runc.v2", 187 }, 188 { 189 name: "RelPathToShim", 190 runtime: "my/io.containerd.runc.v2", 191 }, 192 { 193 name: "ConfiguredRuntime", 194 runtime: configuredRtName, 195 wantShim: stockRuntime.ShimConfig.Binary, 196 wantOpts: &configdOpts, 197 }, 198 { 199 name: "RuntimeWithArgs", 200 runtime: rtWithArgsName, 201 wantShim: stockRuntime.ShimConfig.Binary, 202 wantOpts: defaultV2ShimConfig( 203 d.configStore, 204 d.rewriteRuntimePath( 205 rtWithArgsName, 206 rtWithArgs.Path, 207 rtWithArgs.Args)).Opts, 208 }, 209 { 210 name: "ShimWithOpts", 211 runtime: shimWithOptsName, 212 wantShim: shimWithOpts.Type, 213 wantOpts: &v2runcoptions.Options{IoUid: 42}, 214 }, 215 { 216 name: "ShimAlias", 217 runtime: shimAliasName, 218 wantShim: shimAlias.Type, 219 }, 220 { 221 name: "ConfiguredShimByPath", 222 runtime: configuredShimByPathName, 223 wantShim: configuredShimByPath.Type, 224 }, 225 } { 226 tt := tt 227 t.Run(tt.name, func(t *testing.T) { 228 gotShim, gotOpts, err := d.getRuntime(tt.runtime) 229 assert.Check(t, is.Equal(gotShim, tt.wantShim)) 230 assert.Check(t, is.DeepEqual(gotOpts, tt.wantOpts)) 231 if tt.wantShim != "" { 232 assert.Check(t, err) 233 } else { 234 assert.Check(t, errdefs.IsInvalidParameter(err)) 235 } 236 }) 237 } 238 }