Merge pull request #45032 from corhere/shim-opts
daemon: allow shimv2 runtimes to be configured
This commit is contained in:
commit
11261594d8
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)
|
||||
|
|
|
@ -909,15 +909,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/snapshotters
|
||||
|
|
Loading…
Reference in a new issue