diff --git a/client/container.go b/client/container.go index b9cf25e93..5763ae6d7 100644 --- a/client/container.go +++ b/client/container.go @@ -279,7 +279,8 @@ func (c *container) NewTask(ctx context.Context, ioCreate cio.Creator, opts ...N } } info := TaskInfo{ - runtime: r.Runtime.Name, + runtime: r.Runtime.Name, + runtimeOptions: r.Runtime.Options, } for _, o := range opts { if err := o(ctx, c.client, &info); err != nil { diff --git a/client/task.go b/client/task.go index 20312a922..1e3c3f631 100644 --- a/client/task.go +++ b/client/task.go @@ -146,6 +146,11 @@ type TaskInfo struct { // runtime is the runtime name for the container, and cannot be changed. runtime string + + // runtimeOptions is the runtime options for the container, and when task options are set, + // they will be based on the runtimeOptions. + // https://github.com/containerd/containerd/issues/11568 + runtimeOptions typeurl.Any } // Runtime name for the container @@ -153,6 +158,29 @@ func (i *TaskInfo) Runtime() string { return i.runtime } +// getRuncOptions returns a reference to the runtime options for use by the task. +// If the set of options is not set by the opts passed into the NewTask creation +// this function first attempts to initialize the runtime options with a copy of the runtimeOptions, +// otherwise an empty set of options is assigned and returned +func (i *TaskInfo) getRuncOptions() (*options.Options, error) { + if i.Options != nil { + opts, ok := i.Options.(*options.Options) + if !ok { + return nil, errors.New("invalid runtime v2 options format") + } + return opts, nil + } + + opts := &options.Options{} + if i.runtimeOptions != nil && i.runtimeOptions.GetValue() != nil { + if err := typeurl.UnmarshalTo(i.runtimeOptions, opts); err != nil { + return nil, fmt.Errorf("failed to get runtime v2 options: %w", err) + } + } + i.Options = opts + return opts, nil +} + // Task is the executable object within containerd type Task interface { Process diff --git a/client/task_opts.go b/client/task_opts.go index 8e94d4c59..27bde3506 100644 --- a/client/task_opts.go +++ b/client/task_opts.go @@ -54,12 +54,9 @@ func WithRuntimePath(absRuntimePath string) NewTaskOpts { // usually it is served inside a sandbox, and we can get it from sandbox status. func WithTaskAPIEndpoint(address string, version uint32) NewTaskOpts { return func(ctx context.Context, client *Client, info *TaskInfo) error { - if info.Options == nil { - info.Options = &options.Options{} - } - opts, ok := info.Options.(*options.Options) - if !ok { - return errors.New("invalid runtime v2 options format") + opts, err := info.getRuncOptions() + if err != nil { + return err } opts.TaskApiAddress = address opts.TaskApiVersion = version @@ -119,12 +116,9 @@ func WithCheckpointImagePath(path string) CheckpointTaskOpts { // WithRestoreImagePath sets image path for create option func WithRestoreImagePath(path string) NewTaskOpts { return func(ctx context.Context, c *Client, ti *TaskInfo) error { - if ti.Options == nil { - ti.Options = &options.Options{} - } - opts, ok := ti.Options.(*options.Options) - if !ok { - return errors.New("invalid runtime v2 options format") + opts, err := ti.getRuncOptions() + if err != nil { + return err } opts.CriuImagePath = path return nil @@ -134,12 +128,9 @@ func WithRestoreImagePath(path string) NewTaskOpts { // WithRestoreWorkPath sets criu work path for create option func WithRestoreWorkPath(path string) NewTaskOpts { return func(ctx context.Context, c *Client, ti *TaskInfo) error { - if ti.Options == nil { - ti.Options = &options.Options{} - } - opts, ok := ti.Options.(*options.Options) - if !ok { - return errors.New("invalid runtime v2 options format") + opts, err := ti.getRuncOptions() + if err != nil { + return err } opts.CriuWorkPath = path return nil diff --git a/client/task_opts_unix.go b/client/task_opts_unix.go index d33e30284..26b5c17be 100644 --- a/client/task_opts_unix.go +++ b/client/task_opts_unix.go @@ -20,20 +20,14 @@ package client import ( "context" - "errors" - - "github.com/containerd/containerd/api/types/runc/options" ) // WithNoNewKeyring causes tasks not to be created with a new keyring for secret storage. // There is an upper limit on the number of keyrings in a linux system func WithNoNewKeyring(ctx context.Context, c *Client, ti *TaskInfo) error { - if ti.Options == nil { - ti.Options = &options.Options{} - } - opts, ok := ti.Options.(*options.Options) - if !ok { - return errors.New("invalid v2 shim create options format") + opts, err := ti.getRuncOptions() + if err != nil { + return err } opts.NoNewKeyring = true return nil @@ -41,12 +35,9 @@ func WithNoNewKeyring(ctx context.Context, c *Client, ti *TaskInfo) error { // WithNoPivotRoot instructs the runtime not to you pivot_root func WithNoPivotRoot(_ context.Context, _ *Client, ti *TaskInfo) error { - if ti.Options == nil { - ti.Options = &options.Options{} - } - opts, ok := ti.Options.(*options.Options) - if !ok { - return errors.New("invalid v2 shim create options format") + opts, err := ti.getRuncOptions() + if err != nil { + return err } opts.NoPivotRoot = true return nil @@ -55,12 +46,9 @@ func WithNoPivotRoot(_ context.Context, _ *Client, ti *TaskInfo) error { // WithShimCgroup sets the existing cgroup for the shim func WithShimCgroup(path string) NewTaskOpts { return func(ctx context.Context, c *Client, ti *TaskInfo) error { - if ti.Options == nil { - ti.Options = &options.Options{} - } - opts, ok := ti.Options.(*options.Options) - if !ok { - return errors.New("invalid v2 shim create options format") + opts, err := ti.getRuncOptions() + if err != nil { + return err } opts.ShimCgroup = path return nil @@ -70,12 +58,9 @@ func WithShimCgroup(path string) NewTaskOpts { // WithUIDOwner allows console I/O to work with the remapped UID in user namespace func WithUIDOwner(uid uint32) NewTaskOpts { return func(ctx context.Context, c *Client, ti *TaskInfo) error { - if ti.Options == nil { - ti.Options = &options.Options{} - } - opts, ok := ti.Options.(*options.Options) - if !ok { - return errors.New("invalid v2 shim create options format") + opts, err := ti.getRuncOptions() + if err != nil { + return err } opts.IoUid = uid return nil @@ -85,12 +70,9 @@ func WithUIDOwner(uid uint32) NewTaskOpts { // WithGIDOwner allows console I/O to work with the remapped GID in user namespace func WithGIDOwner(gid uint32) NewTaskOpts { return func(ctx context.Context, c *Client, ti *TaskInfo) error { - if ti.Options == nil { - ti.Options = &options.Options{} - } - opts, ok := ti.Options.(*options.Options) - if !ok { - return errors.New("invalid v2 shim create options format") + opts, err := ti.getRuncOptions() + if err != nil { + return err } opts.IoGid = gid return nil