daemon: allow shimv2 runtimes to be configured
Kubernetes only permits RuntimeClass values which are valid lowercase RFC 1123 labels, which disallows the period character. This prevents cri-dockerd from being able to support configuring alternative shimv2 runtimes for a pod as shimv2 runtime names must contain at least one period character. Add support for configuring named shimv2 runtimes in daemon.json so that runtime names can be aliased to Kubernetes-compatible names. Allow options to be set on shimv2 runtimes in daemon.json. The names of the new daemon runtime config fields have been selected to correspond with the equivalent field names in cri-containerd's configuration so that users can more easily follow documentation from the runtime vendor written for cri-containerd and apply it to daemon.json. Signed-off-by: Cory Snider <csnider@mirantis.com>
This commit is contained in:
parent
c030f7f40d
commit
b0eed5ade6
14 changed files with 713 additions and 76 deletions
|
@ -653,12 +653,18 @@ type Checkpoint struct {
|
|||
|
||||
// Runtime describes an OCI runtime
|
||||
type Runtime struct {
|
||||
Path string `json:"path"`
|
||||
// "Legacy" runtime configuration for runc-compatible runtimes.
|
||||
|
||||
Path string `json:"path,omitempty"`
|
||||
Args []string `json:"runtimeArgs,omitempty"`
|
||||
|
||||
// Shimv2 runtime configuration. Mutually exclusive with the legacy config above.
|
||||
|
||||
Type string `json:"runtimeType,omitempty"`
|
||||
Options map[string]interface{} `json:"options,omitempty"`
|
||||
|
||||
// This is exposed here only for internal use
|
||||
// It is not currently supported to specify custom shim configs
|
||||
Shim *ShimConfig `json:"-"`
|
||||
ShimConfig *ShimConfig `json:"-"`
|
||||
}
|
||||
|
||||
// ShimConfig is used by runtime to configure containerd shims
|
||||
|
|
|
@ -6,7 +6,6 @@ package daemon
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/daemon/config"
|
||||
"github.com/docker/go-connections/nat"
|
||||
|
@ -33,9 +32,8 @@ func TestContainerWarningHostAndPublishPorts(t *testing.T) {
|
|||
NetworkMode: "host",
|
||||
PortBindings: tc.ports,
|
||||
}
|
||||
cs := &config.Config{
|
||||
Runtimes: map[string]types.Runtime{"runc": {}},
|
||||
}
|
||||
cs := &config.Config{}
|
||||
configureRuntimes(cs)
|
||||
d := &Daemon{configStore: cs}
|
||||
wrns, err := d.verifyContainerSettings(hostConfig, &containertypes.Config{}, false)
|
||||
assert.NilError(t, err)
|
||||
|
|
|
@ -908,15 +908,17 @@ func NewDaemon(ctx context.Context, config *config.Config, pluginStore *plugin.S
|
|||
}
|
||||
}
|
||||
|
||||
var rt types.Runtime
|
||||
var (
|
||||
shim string
|
||||
shimOpts interface{}
|
||||
)
|
||||
if runtime.GOOS != "windows" {
|
||||
rtPtr, err := d.getRuntime(config.GetDefaultRuntimeName())
|
||||
shim, shimOpts, err = d.getRuntime(config.GetDefaultRuntimeName())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rt = *rtPtr
|
||||
}
|
||||
return pluginexec.New(ctx, getPluginExecRoot(config), pluginCli, config.ContainerdPluginNamespace, m, rt)
|
||||
return pluginexec.New(ctx, getPluginExecRoot(config), pluginCli, config.ContainerdPluginNamespace, m, shim, shimOpts)
|
||||
}
|
||||
|
||||
// Plugin system initialization should happen before restore. Do not change order.
|
||||
|
|
|
@ -705,7 +705,7 @@ func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.
|
|||
hostConfig.Runtime = daemon.configStore.GetDefaultRuntimeName()
|
||||
}
|
||||
|
||||
if _, err := daemon.getRuntime(hostConfig.Runtime); err != nil {
|
||||
if _, _, err := daemon.getRuntime(hostConfig.Runtime); err != nil {
|
||||
return warnings, err
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/daemon/config"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/libcontainerd/shimopts"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
@ -31,7 +32,7 @@ func configureRuntimes(conf *config.Config) {
|
|||
if conf.Runtimes == nil {
|
||||
conf.Runtimes = make(map[string]types.Runtime)
|
||||
}
|
||||
conf.Runtimes[config.LinuxV2RuntimeName] = types.Runtime{Path: defaultRuntimeName, Shim: defaultV2ShimConfig(conf, defaultRuntimeName)}
|
||||
conf.Runtimes[config.LinuxV2RuntimeName] = types.Runtime{Path: defaultRuntimeName, ShimConfig: defaultV2ShimConfig(conf, defaultRuntimeName)}
|
||||
conf.Runtimes[config.StockRuntimeName] = conf.Runtimes[config.LinuxV2RuntimeName]
|
||||
}
|
||||
|
||||
|
@ -88,17 +89,42 @@ func (daemon *Daemon) initRuntimes(runtimes map[string]types.Runtime) (err error
|
|||
}
|
||||
}()
|
||||
|
||||
for name, rt := range runtimes {
|
||||
if len(rt.Args) > 0 {
|
||||
script := filepath.Join(tmpDir, name)
|
||||
content := fmt.Sprintf("#!/bin/sh\n%s %s $@\n", rt.Path, strings.Join(rt.Args, " "))
|
||||
if err := os.WriteFile(script, []byte(content), 0700); err != nil {
|
||||
return err
|
||||
for name := range runtimes {
|
||||
rt := runtimes[name]
|
||||
if rt.Path == "" && rt.Type == "" {
|
||||
return errors.Errorf("runtime %s: either a runtimeType or a path must be configured", name)
|
||||
}
|
||||
if rt.Path != "" {
|
||||
if rt.Type != "" {
|
||||
return errors.Errorf("runtime %s: cannot configure both path and runtimeType for the same runtime", name)
|
||||
}
|
||||
if len(rt.Options) > 0 {
|
||||
return errors.Errorf("runtime %s: options cannot be used with a path runtime", name)
|
||||
}
|
||||
|
||||
if len(rt.Args) > 0 {
|
||||
script := filepath.Join(tmpDir, name)
|
||||
content := fmt.Sprintf("#!/bin/sh\n%s %s $@\n", rt.Path, strings.Join(rt.Args, " "))
|
||||
if err := os.WriteFile(script, []byte(content), 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
rt.ShimConfig = defaultV2ShimConfig(daemon.configStore, daemon.rewriteRuntimePath(name, rt.Path, rt.Args))
|
||||
} else {
|
||||
if len(rt.Args) > 0 {
|
||||
return errors.Errorf("runtime %s: args cannot be used with a runtimeType runtime", name)
|
||||
}
|
||||
// Unlike implicit runtimes, there is no restriction on configuring a shim by path.
|
||||
rt.ShimConfig = &types.ShimConfig{Binary: rt.Type}
|
||||
if len(rt.Options) > 0 {
|
||||
// It has to be a pointer type or there'll be a panic in containerd/typeurl when we try to start the container.
|
||||
rt.ShimConfig.Opts, err = shimopts.Generate(rt.Type, rt.Options)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "runtime %v", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
if rt.Shim == nil {
|
||||
rt.Shim = defaultV2ShimConfig(daemon.configStore, rt.Path)
|
||||
}
|
||||
runtimes[name] = rt
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -106,40 +132,39 @@ func (daemon *Daemon) initRuntimes(runtimes map[string]types.Runtime) (err error
|
|||
// rewriteRuntimePath is used for runtimes which have custom arguments supplied.
|
||||
// This is needed because the containerd API only calls the OCI runtime binary, there is no options for extra arguments.
|
||||
// To support this case, the daemon wraps the specified runtime in a script that passes through those arguments.
|
||||
func (daemon *Daemon) rewriteRuntimePath(name, p string, args []string) (string, error) {
|
||||
func (daemon *Daemon) rewriteRuntimePath(name, p string, args []string) string {
|
||||
if len(args) == 0 {
|
||||
return p, nil
|
||||
return p
|
||||
}
|
||||
|
||||
// Check that the runtime path actually exists here so that we can return a well known error.
|
||||
if _, err := exec.LookPath(p); err != nil {
|
||||
return "", errors.Wrap(err, "error while looking up the specified runtime path")
|
||||
}
|
||||
|
||||
return filepath.Join(daemon.configStore.Root, "runtimes", name), nil
|
||||
return filepath.Join(daemon.configStore.Root, "runtimes", name)
|
||||
}
|
||||
|
||||
func (daemon *Daemon) getRuntime(name string) (*types.Runtime, error) {
|
||||
func (daemon *Daemon) getRuntime(name string) (shim string, opts interface{}, err error) {
|
||||
rt := daemon.configStore.GetRuntime(name)
|
||||
if rt == nil {
|
||||
if !config.IsPermissibleC8dRuntimeName(name) {
|
||||
return nil, errdefs.InvalidParameter(errors.Errorf("unknown or invalid runtime name: %s", name))
|
||||
return "", nil, errdefs.InvalidParameter(errors.Errorf("unknown or invalid runtime name: %s", name))
|
||||
}
|
||||
return &types.Runtime{Shim: &types.ShimConfig{Binary: name}}, nil
|
||||
return name, nil, nil
|
||||
}
|
||||
|
||||
if len(rt.Args) > 0 {
|
||||
p, err := daemon.rewriteRuntimePath(name, rt.Path, rt.Args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// Check that the path of the runtime which the script wraps actually exists so
|
||||
// that we can return a well known error which references the configured path
|
||||
// instead of the wrapper script's.
|
||||
if _, err := exec.LookPath(rt.Path); err != nil {
|
||||
return "", nil, errors.Wrap(err, "error while looking up the specified runtime path")
|
||||
}
|
||||
rt.Path = p
|
||||
rt.Args = nil
|
||||
}
|
||||
|
||||
if rt.Shim == nil {
|
||||
rt.Shim = defaultV2ShimConfig(daemon.configStore, rt.Path)
|
||||
if rt.ShimConfig == nil {
|
||||
// Should never happen as daemon.initRuntimes always sets
|
||||
// ShimConfig and config reloading is synchronized.
|
||||
err := errdefs.System(errors.Errorf("BUG: runtime %s: rt.ShimConfig == nil", name))
|
||||
logrus.Error(err)
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
return rt, nil
|
||||
return rt.ShimConfig.Binary, rt.ShimConfig.Opts, nil
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/containerd/containerd/plugin"
|
||||
v2runcoptions "github.com/containerd/containerd/runtime/v2/runc/options"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
|
@ -17,13 +18,110 @@ import (
|
|||
"github.com/docker/docker/errdefs"
|
||||
)
|
||||
|
||||
func TestInitRuntimes_InvalidConfigs(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
runtime types.Runtime
|
||||
expectErr string
|
||||
}{
|
||||
{
|
||||
name: "Empty",
|
||||
expectErr: "either a runtimeType or a path must be configured",
|
||||
},
|
||||
{
|
||||
name: "ArgsOnly",
|
||||
runtime: types.Runtime{Args: []string{"foo", "bar"}},
|
||||
expectErr: "either a runtimeType or a path must be configured",
|
||||
},
|
||||
{
|
||||
name: "OptionsOnly",
|
||||
runtime: types.Runtime{Options: map[string]interface{}{"hello": "world"}},
|
||||
expectErr: "either a runtimeType or a path must be configured",
|
||||
},
|
||||
{
|
||||
name: "PathAndType",
|
||||
runtime: types.Runtime{Path: "/bin/true", Type: "io.containerd.runsc.v1"},
|
||||
expectErr: "cannot configure both",
|
||||
},
|
||||
{
|
||||
name: "PathAndOptions",
|
||||
runtime: types.Runtime{Path: "/bin/true", Options: map[string]interface{}{"a": "b"}},
|
||||
expectErr: "options cannot be used with a path runtime",
|
||||
},
|
||||
{
|
||||
name: "TypeAndArgs",
|
||||
runtime: types.Runtime{Type: "io.containerd.runsc.v1", Args: []string{"--version"}},
|
||||
expectErr: "args cannot be used with a runtimeType runtime",
|
||||
},
|
||||
{
|
||||
name: "PathArgsOptions",
|
||||
runtime: types.Runtime{
|
||||
Path: "/bin/true",
|
||||
Args: []string{"--version"},
|
||||
Options: map[string]interface{}{"hmm": 3},
|
||||
},
|
||||
expectErr: "options cannot be used with a path runtime",
|
||||
},
|
||||
{
|
||||
name: "TypeOptionsArgs",
|
||||
runtime: types.Runtime{
|
||||
Type: "io.containerd.kata.v2",
|
||||
Options: map[string]interface{}{"a": "b"},
|
||||
Args: []string{"--help"},
|
||||
},
|
||||
expectErr: "args cannot be used with a runtimeType runtime",
|
||||
},
|
||||
{
|
||||
name: "PathArgsTypeOptions",
|
||||
runtime: types.Runtime{
|
||||
Path: "/bin/true",
|
||||
Args: []string{"foo"},
|
||||
Type: "io.containerd.runsc.v1",
|
||||
Options: map[string]interface{}{"a": "b"},
|
||||
},
|
||||
expectErr: "cannot configure both",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range cases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cfg, err := config.New()
|
||||
assert.NilError(t, err)
|
||||
d := &Daemon{configStore: cfg}
|
||||
d.configStore.Root = t.TempDir()
|
||||
assert.Assert(t, os.Mkdir(filepath.Join(d.configStore.Root, "runtimes"), 0700))
|
||||
|
||||
err = d.initRuntimes(map[string]types.Runtime{"myruntime": tt.runtime})
|
||||
assert.Check(t, is.ErrorContains(err, tt.expectErr))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRuntime(t *testing.T) {
|
||||
// Configured runtimes can have any arbitrary name, including names
|
||||
// which would not be allowed as implicit runtime names. Explicit takes
|
||||
// precedence over implicit.
|
||||
const configuredRtName = "my/custom.shim.v1"
|
||||
const configuredRtName = "my/custom.runtime.v1"
|
||||
configuredRuntime := types.Runtime{Path: "/bin/true"}
|
||||
|
||||
const rtWithArgsName = "withargs"
|
||||
rtWithArgs := types.Runtime{
|
||||
Path: "/bin/false",
|
||||
Args: []string{"--version"},
|
||||
}
|
||||
|
||||
const shimWithOptsName = "shimwithopts"
|
||||
shimWithOpts := types.Runtime{
|
||||
Type: plugin.RuntimeRuncV2,
|
||||
Options: map[string]interface{}{"IoUid": 42},
|
||||
}
|
||||
|
||||
const shimAliasName = "wasmedge"
|
||||
shimAlias := types.Runtime{Type: "io.containerd.wasmedge.v1"}
|
||||
|
||||
const configuredShimByPathName = "shimwithpath"
|
||||
configuredShimByPath := types.Runtime{Type: "/path/to/my/shim"}
|
||||
|
||||
cfg, err := config.New()
|
||||
assert.NilError(t, err)
|
||||
|
||||
|
@ -31,7 +129,11 @@ func TestGetRuntime(t *testing.T) {
|
|||
d.configStore.Root = t.TempDir()
|
||||
assert.Assert(t, os.Mkdir(filepath.Join(d.configStore.Root, "runtimes"), 0700))
|
||||
d.configStore.Runtimes = map[string]types.Runtime{
|
||||
configuredRtName: configuredRuntime,
|
||||
configuredRtName: configuredRuntime,
|
||||
rtWithArgsName: rtWithArgs,
|
||||
shimWithOptsName: shimWithOpts,
|
||||
shimAliasName: shimAlias,
|
||||
configuredShimByPathName: configuredShimByPath,
|
||||
}
|
||||
configureRuntimes(d.configStore)
|
||||
assert.Assert(t, d.loadRuntimes())
|
||||
|
@ -39,36 +141,33 @@ func TestGetRuntime(t *testing.T) {
|
|||
stockRuntime, ok := d.configStore.Runtimes[config.StockRuntimeName]
|
||||
assert.Assert(t, ok, "stock runtime could not be found (test needs to be updated)")
|
||||
|
||||
configdOpts := *stockRuntime.Shim.Opts.(*v2runcoptions.Options)
|
||||
configdOpts := *stockRuntime.ShimConfig.Opts.(*v2runcoptions.Options)
|
||||
configdOpts.BinaryName = configuredRuntime.Path
|
||||
wantConfigdRuntime := configuredRuntime
|
||||
wantConfigdRuntime.Shim = &types.ShimConfig{
|
||||
Binary: stockRuntime.Shim.Binary,
|
||||
Opts: &configdOpts,
|
||||
}
|
||||
|
||||
for _, tt := range []struct {
|
||||
name, runtime string
|
||||
want *types.Runtime
|
||||
wantShim string
|
||||
wantOpts interface{}
|
||||
}{
|
||||
{
|
||||
name: "StockRuntime",
|
||||
runtime: config.StockRuntimeName,
|
||||
want: &stockRuntime,
|
||||
name: "StockRuntime",
|
||||
runtime: config.StockRuntimeName,
|
||||
wantShim: stockRuntime.ShimConfig.Binary,
|
||||
wantOpts: stockRuntime.ShimConfig.Opts,
|
||||
},
|
||||
{
|
||||
name: "ShimName",
|
||||
runtime: "io.containerd.my-shim.v42",
|
||||
want: &types.Runtime{Shim: &types.ShimConfig{Binary: "io.containerd.my-shim.v42"}},
|
||||
name: "ShimName",
|
||||
runtime: "io.containerd.my-shim.v42",
|
||||
wantShim: "io.containerd.my-shim.v42",
|
||||
},
|
||||
{
|
||||
// containerd is pretty loose about the format of runtime names. Perhaps too
|
||||
// loose. The only requirements are that the name contain a dot and (depending
|
||||
// on the containerd version) not start with a dot. It does not enforce any
|
||||
// particular format of the dot-delimited components of the name.
|
||||
name: "VersionlessShimName",
|
||||
runtime: "io.containerd.my-shim",
|
||||
want: &types.Runtime{Shim: &types.ShimConfig{Binary: "io.containerd.my-shim"}},
|
||||
name: "VersionlessShimName",
|
||||
runtime: "io.containerd.my-shim",
|
||||
wantShim: "io.containerd.my-shim",
|
||||
},
|
||||
{
|
||||
name: "IllformedShimName",
|
||||
|
@ -91,16 +190,45 @@ func TestGetRuntime(t *testing.T) {
|
|||
runtime: "my/io.containerd.runc.v2",
|
||||
},
|
||||
{
|
||||
name: "ConfiguredRuntime",
|
||||
runtime: configuredRtName,
|
||||
want: &wantConfigdRuntime,
|
||||
name: "ConfiguredRuntime",
|
||||
runtime: configuredRtName,
|
||||
wantShim: stockRuntime.ShimConfig.Binary,
|
||||
wantOpts: &configdOpts,
|
||||
},
|
||||
{
|
||||
name: "RuntimeWithArgs",
|
||||
runtime: rtWithArgsName,
|
||||
wantShim: stockRuntime.ShimConfig.Binary,
|
||||
wantOpts: defaultV2ShimConfig(
|
||||
d.configStore,
|
||||
d.rewriteRuntimePath(
|
||||
rtWithArgsName,
|
||||
rtWithArgs.Path,
|
||||
rtWithArgs.Args)).Opts,
|
||||
},
|
||||
{
|
||||
name: "ShimWithOpts",
|
||||
runtime: shimWithOptsName,
|
||||
wantShim: shimWithOpts.Type,
|
||||
wantOpts: &v2runcoptions.Options{IoUid: 42},
|
||||
},
|
||||
{
|
||||
name: "ShimAlias",
|
||||
runtime: shimAliasName,
|
||||
wantShim: shimAlias.Type,
|
||||
},
|
||||
{
|
||||
name: "ConfiguredShimByPath",
|
||||
runtime: configuredShimByPathName,
|
||||
wantShim: configuredShimByPath.Type,
|
||||
},
|
||||
} {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := d.getRuntime(tt.runtime)
|
||||
assert.Check(t, is.DeepEqual(got, tt.want))
|
||||
if tt.want != nil {
|
||||
gotShim, gotOpts, err := d.getRuntime(tt.runtime)
|
||||
assert.Check(t, is.Equal(gotShim, tt.wantShim))
|
||||
assert.Check(t, is.DeepEqual(gotOpts, tt.wantOpts))
|
||||
if tt.wantShim != "" {
|
||||
assert.Check(t, err)
|
||||
} else {
|
||||
assert.Check(t, errdefs.IsInvalidParameter(err))
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
package daemon
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/pkg/errors"
|
||||
"errors"
|
||||
)
|
||||
|
||||
func (daemon *Daemon) getRuntime(name string) (*types.Runtime, error) {
|
||||
return nil, errors.New("not implemented")
|
||||
func (daemon *Daemon) getRuntime(name string) (shim string, opts interface{}, err error) {
|
||||
return "", nil, errors.New("not implemented")
|
||||
}
|
||||
|
|
|
@ -15,10 +15,10 @@ func (daemon *Daemon) getLibcontainerdCreateOptions(container *container.Contain
|
|||
container.CheckpointTo(daemon.containersReplica)
|
||||
}
|
||||
|
||||
rt, err := daemon.getRuntime(container.HostConfig.Runtime)
|
||||
binary, opts, err := daemon.getRuntime(container.HostConfig.Runtime)
|
||||
if err != nil {
|
||||
return "", nil, setExitCodeFromError(container.SetExitCode, err)
|
||||
}
|
||||
|
||||
return rt.Shim.Binary, rt.Shim.Opts, nil
|
||||
return binary, opts, nil
|
||||
}
|
||||
|
|
38
libcontainerd/shimopts/convert.go
Normal file
38
libcontainerd/shimopts/convert.go
Normal file
|
@ -0,0 +1,38 @@
|
|||
package shimopts
|
||||
|
||||
import (
|
||||
runhcsoptions "github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/options"
|
||||
runtimeoptions "github.com/containerd/containerd/pkg/runtimeoptions/v1"
|
||||
"github.com/containerd/containerd/plugin"
|
||||
runcoptions "github.com/containerd/containerd/runtime/v2/runc/options"
|
||||
"github.com/pelletier/go-toml"
|
||||
)
|
||||
|
||||
// Generate converts opts into a runtime options value for the runtimeType which
|
||||
// can be passed into containerd.
|
||||
func Generate(runtimeType string, opts map[string]interface{}) (interface{}, error) {
|
||||
// This is horrible, but we have no other choice. The containerd client
|
||||
// can only handle options values which can be marshaled into a
|
||||
// typeurl.Any. And we're in good company: cri-containerd handles shim
|
||||
// options in the same way.
|
||||
var out interface{}
|
||||
switch runtimeType {
|
||||
case plugin.RuntimeRuncV1, plugin.RuntimeRuncV2:
|
||||
out = &runcoptions.Options{}
|
||||
case "io.containerd.runhcs.v1":
|
||||
out = &runhcsoptions.Options{}
|
||||
default:
|
||||
out = &runtimeoptions.Options{}
|
||||
}
|
||||
|
||||
// We can't use mergo.Map as it is too strict about type-assignability
|
||||
// with numeric types.
|
||||
tree, err := toml.TreeFromMap(opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := tree.Unmarshal(out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
|
@ -9,7 +9,6 @@ import (
|
|||
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/cio"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/libcontainerd"
|
||||
libcontainerdtypes "github.com/docker/docker/libcontainerd/types"
|
||||
|
@ -24,11 +23,12 @@ type ExitHandler interface {
|
|||
}
|
||||
|
||||
// New creates a new containerd plugin executor
|
||||
func New(ctx context.Context, rootDir string, cli *containerd.Client, ns string, exitHandler ExitHandler, runtime types.Runtime) (*Executor, error) {
|
||||
func New(ctx context.Context, rootDir string, cli *containerd.Client, ns string, exitHandler ExitHandler, shim string, shimOpts interface{}) (*Executor, error) {
|
||||
e := &Executor{
|
||||
rootDir: rootDir,
|
||||
exitHandler: exitHandler,
|
||||
runtime: runtime,
|
||||
shim: shim,
|
||||
shimOpts: shimOpts,
|
||||
plugins: make(map[string]*c8dPlugin),
|
||||
}
|
||||
|
||||
|
@ -45,7 +45,8 @@ type Executor struct {
|
|||
rootDir string
|
||||
client libcontainerdtypes.Client
|
||||
exitHandler ExitHandler
|
||||
runtime types.Runtime
|
||||
shim string
|
||||
shimOpts interface{}
|
||||
|
||||
mu sync.Mutex // Guards plugins map
|
||||
plugins map[string]*c8dPlugin
|
||||
|
@ -75,7 +76,7 @@ func (p c8dPlugin) deleteTaskAndContainer(ctx context.Context) {
|
|||
func (e *Executor) Create(id string, spec specs.Spec, stdout, stderr io.WriteCloser) error {
|
||||
ctx := context.Background()
|
||||
log := logrus.WithField("plugin", id)
|
||||
ctr, err := libcontainerd.ReplaceContainer(ctx, e.client, id, &spec, e.runtime.Shim.Binary, e.runtime.Shim.Opts)
|
||||
ctr, err := libcontainerd.ReplaceContainer(ctx, e.client, id, &spec, e.shim, e.shimOpts)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error creating containerd container for plugin")
|
||||
}
|
||||
|
|
397
vendor/github.com/containerd/containerd/pkg/runtimeoptions/v1/api.pb.go
generated
vendored
Normal file
397
vendor/github.com/containerd/containerd/pkg/runtimeoptions/v1/api.pb.go
generated
vendored
Normal file
|
@ -0,0 +1,397 @@
|
|||
// Code generated by protoc-gen-gogo. DO NOT EDIT.
|
||||
// source: github.com/containerd/containerd/pkg/runtimeoptions/v1/api.proto
|
||||
|
||||
package runtimeoptions_v1
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
_ "github.com/gogo/protobuf/gogoproto"
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
io "io"
|
||||
math "math"
|
||||
math_bits "math/bits"
|
||||
reflect "reflect"
|
||||
strings "strings"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
type Options struct {
|
||||
// TypeUrl specifies the type of the content inside the config file.
|
||||
TypeUrl string `protobuf:"bytes,1,opt,name=type_url,json=typeUrl,proto3" json:"type_url,omitempty"`
|
||||
// ConfigPath specifies the filesystem location of the config file
|
||||
// used by the runtime.
|
||||
ConfigPath string `protobuf:"bytes,2,opt,name=config_path,json=configPath,proto3" json:"config_path,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Options) Reset() { *m = Options{} }
|
||||
func (*Options) ProtoMessage() {}
|
||||
func (*Options) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_7700dd27e3487aa6, []int{0}
|
||||
}
|
||||
func (m *Options) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *Options) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
if deterministic {
|
||||
return xxx_messageInfo_Options.Marshal(b, m, deterministic)
|
||||
} else {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalToSizedBuffer(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b[:n], nil
|
||||
}
|
||||
}
|
||||
func (m *Options) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Options.Merge(m, src)
|
||||
}
|
||||
func (m *Options) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *Options) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Options.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Options proto.InternalMessageInfo
|
||||
|
||||
func (m *Options) GetTypeUrl() string {
|
||||
if m != nil {
|
||||
return m.TypeUrl
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Options) GetConfigPath() string {
|
||||
if m != nil {
|
||||
return m.ConfigPath
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*Options)(nil), "runtimeoptions.v1.Options")
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterFile("github.com/containerd/containerd/pkg/runtimeoptions/v1/api.proto", fileDescriptor_7700dd27e3487aa6)
|
||||
}
|
||||
|
||||
var fileDescriptor_7700dd27e3487aa6 = []byte{
|
||||
// 214 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x72, 0x48, 0xcf, 0x2c, 0xc9,
|
||||
0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0xcf, 0x2b, 0x49, 0xcc, 0xcc, 0x4b, 0x2d,
|
||||
0x4a, 0x41, 0x66, 0x16, 0x64, 0xa7, 0xeb, 0x17, 0x95, 0xe6, 0x95, 0x64, 0xe6, 0xa6, 0xe6, 0x17,
|
||||
0x94, 0x64, 0xe6, 0xe7, 0x15, 0xeb, 0x97, 0x19, 0xea, 0x27, 0x16, 0x64, 0xea, 0x15, 0x14, 0xe5,
|
||||
0x97, 0xe4, 0x0b, 0x09, 0xa2, 0x4a, 0xea, 0x95, 0x19, 0x4a, 0xe9, 0x22, 0x19, 0x9a, 0x9e, 0x9f,
|
||||
0x9e, 0xaf, 0x0f, 0x56, 0x99, 0x54, 0x9a, 0x06, 0xe6, 0x81, 0x39, 0x60, 0x16, 0xc4, 0x04, 0x25,
|
||||
0x57, 0x2e, 0x76, 0x7f, 0x88, 0x66, 0x21, 0x49, 0x2e, 0x8e, 0x92, 0xca, 0x82, 0xd4, 0xf8, 0xd2,
|
||||
0xa2, 0x1c, 0x09, 0x46, 0x05, 0x46, 0x0d, 0xce, 0x20, 0x76, 0x10, 0x3f, 0xb4, 0x28, 0x47, 0x48,
|
||||
0x9e, 0x8b, 0x3b, 0x39, 0x3f, 0x2f, 0x2d, 0x33, 0x3d, 0xbe, 0x20, 0xb1, 0x24, 0x43, 0x82, 0x09,
|
||||
0x2c, 0xcb, 0x05, 0x11, 0x0a, 0x48, 0x2c, 0xc9, 0x70, 0x4a, 0x3b, 0xf1, 0x50, 0x8e, 0xf1, 0xc6,
|
||||
0x43, 0x39, 0x86, 0x86, 0x47, 0x72, 0x8c, 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24, 0xc7, 0xf8,
|
||||
0xe0, 0x91, 0x1c, 0xe3, 0x84, 0xc7, 0x72, 0x0c, 0x51, 0x1e, 0xe4, 0x79, 0xd4, 0x1a, 0x55, 0x24,
|
||||
0xbe, 0xcc, 0x30, 0x89, 0x0d, 0xec, 0x6a, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x91, 0x3c,
|
||||
0x3e, 0x79, 0x3b, 0x01, 0x00, 0x00,
|
||||
}
|
||||
|
||||
func (m *Options) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *Options) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *Options) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if len(m.ConfigPath) > 0 {
|
||||
i -= len(m.ConfigPath)
|
||||
copy(dAtA[i:], m.ConfigPath)
|
||||
i = encodeVarintApi(dAtA, i, uint64(len(m.ConfigPath)))
|
||||
i--
|
||||
dAtA[i] = 0x12
|
||||
}
|
||||
if len(m.TypeUrl) > 0 {
|
||||
i -= len(m.TypeUrl)
|
||||
copy(dAtA[i:], m.TypeUrl)
|
||||
i = encodeVarintApi(dAtA, i, uint64(len(m.TypeUrl)))
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func encodeVarintApi(dAtA []byte, offset int, v uint64) int {
|
||||
offset -= sovApi(v)
|
||||
base := offset
|
||||
for v >= 1<<7 {
|
||||
dAtA[offset] = uint8(v&0x7f | 0x80)
|
||||
v >>= 7
|
||||
offset++
|
||||
}
|
||||
dAtA[offset] = uint8(v)
|
||||
return base
|
||||
}
|
||||
func (m *Options) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
l = len(m.TypeUrl)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovApi(uint64(l))
|
||||
}
|
||||
l = len(m.ConfigPath)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovApi(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func sovApi(x uint64) (n int) {
|
||||
return (math_bits.Len64(x|1) + 6) / 7
|
||||
}
|
||||
func sozApi(x uint64) (n int) {
|
||||
return sovApi(uint64((x << 1) ^ uint64((int64(x) >> 63))))
|
||||
}
|
||||
func (this *Options) String() string {
|
||||
if this == nil {
|
||||
return "nil"
|
||||
}
|
||||
s := strings.Join([]string{`&Options{`,
|
||||
`TypeUrl:` + fmt.Sprintf("%v", this.TypeUrl) + `,`,
|
||||
`ConfigPath:` + fmt.Sprintf("%v", this.ConfigPath) + `,`,
|
||||
`}`,
|
||||
}, "")
|
||||
return s
|
||||
}
|
||||
func valueToStringApi(v interface{}) string {
|
||||
rv := reflect.ValueOf(v)
|
||||
if rv.IsNil() {
|
||||
return "nil"
|
||||
}
|
||||
pv := reflect.Indirect(rv).Interface()
|
||||
return fmt.Sprintf("*%v", pv)
|
||||
}
|
||||
func (m *Options) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowApi
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: Options: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: Options: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field TypeUrl", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowApi
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthApi
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthApi
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.TypeUrl = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 2:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field ConfigPath", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowApi
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthApi
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthApi
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.ConfigPath = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipApi(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLengthApi
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func skipApi(dAtA []byte) (n int, err error) {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
depth := 0
|
||||
for iNdEx < l {
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowApi
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
wireType := int(wire & 0x7)
|
||||
switch wireType {
|
||||
case 0:
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowApi
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx++
|
||||
if dAtA[iNdEx-1] < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 1:
|
||||
iNdEx += 8
|
||||
case 2:
|
||||
var length int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowApi
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
length |= (int(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if length < 0 {
|
||||
return 0, ErrInvalidLengthApi
|
||||
}
|
||||
iNdEx += length
|
||||
case 3:
|
||||
depth++
|
||||
case 4:
|
||||
if depth == 0 {
|
||||
return 0, ErrUnexpectedEndOfGroupApi
|
||||
}
|
||||
depth--
|
||||
case 5:
|
||||
iNdEx += 4
|
||||
default:
|
||||
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
|
||||
}
|
||||
if iNdEx < 0 {
|
||||
return 0, ErrInvalidLengthApi
|
||||
}
|
||||
if depth == 0 {
|
||||
return iNdEx, nil
|
||||
}
|
||||
}
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
|
||||
var (
|
||||
ErrInvalidLengthApi = fmt.Errorf("proto: negative length found during unmarshaling")
|
||||
ErrIntOverflowApi = fmt.Errorf("proto: integer overflow")
|
||||
ErrUnexpectedEndOfGroupApi = fmt.Errorf("proto: unexpected end of group")
|
||||
)
|
25
vendor/github.com/containerd/containerd/pkg/runtimeoptions/v1/api.proto
generated
vendored
Normal file
25
vendor/github.com/containerd/containerd/pkg/runtimeoptions/v1/api.proto
generated
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
// To regenerate api.pb.go run `make protos`
|
||||
syntax = "proto3";
|
||||
|
||||
package runtimeoptions.v1;
|
||||
|
||||
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
|
||||
|
||||
option (gogoproto.goproto_stringer_all) = false;
|
||||
option (gogoproto.stringer_all) = true;
|
||||
option (gogoproto.goproto_getters_all) = true;
|
||||
option (gogoproto.marshaler_all) = true;
|
||||
option (gogoproto.sizer_all) = true;
|
||||
option (gogoproto.unmarshaler_all) = true;
|
||||
option (gogoproto.goproto_unrecognized_all) = false;
|
||||
|
||||
|
||||
option go_package = "github.com/containerd/containerd/pkg/runtimeoptions/v1;runtimeoptions_v1";
|
||||
|
||||
message Options {
|
||||
// TypeUrl specifies the type of the content inside the config file.
|
||||
string type_url = 1;
|
||||
// ConfigPath specifies the filesystem location of the config file
|
||||
// used by the runtime.
|
||||
string config_path = 2;
|
||||
}
|
17
vendor/github.com/containerd/containerd/pkg/runtimeoptions/v1/doc.go
generated
vendored
Normal file
17
vendor/github.com/containerd/containerd/pkg/runtimeoptions/v1/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
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 runtimeoptions_v1 //nolint
|
1
vendor/modules.txt
vendored
1
vendor/modules.txt
vendored
|
@ -259,6 +259,7 @@ github.com/containerd/containerd/pkg/apparmor
|
|||
github.com/containerd/containerd/pkg/cap
|
||||
github.com/containerd/containerd/pkg/dialer
|
||||
github.com/containerd/containerd/pkg/kmutex
|
||||
github.com/containerd/containerd/pkg/runtimeoptions/v1
|
||||
github.com/containerd/containerd/pkg/seccomp
|
||||
github.com/containerd/containerd/pkg/shutdown
|
||||
github.com/containerd/containerd/pkg/ttrpcutil
|
||||
|
|
Loading…
Reference in a new issue