Merge pull request #9853 from abel-von/make-shim-independent

sandbox: make an independent shim plugin
This commit is contained in:
Maksym Pavlenko 2024-04-29 21:07:21 +00:00 committed by GitHub
commit 7feb1f327d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 388 additions and 301 deletions

View File

@ -19,19 +19,23 @@ package v2
import (
"context"
"errors"
"fmt"
"os"
"path/filepath"
"github.com/containerd/errdefs"
"github.com/containerd/log"
"github.com/containerd/containerd/v2/core/mount"
"github.com/containerd/containerd/v2/internal/cleanup"
"github.com/containerd/containerd/v2/pkg/namespaces"
"github.com/containerd/containerd/v2/pkg/timeout"
"github.com/containerd/errdefs"
"github.com/containerd/log"
)
func (m *ShimManager) loadExistingTasks(ctx context.Context) error {
nsDirs, err := os.ReadDir(m.state)
// LoadExistingShims loads existing shims from the path specified by stateDir
// rootDir is for cleaning up the unused paths of removed shims.
func (m *ShimManager) LoadExistingShims(ctx context.Context, stateDir string, rootDir string) error {
nsDirs, err := os.ReadDir(stateDir)
if err != nil {
return err
}
@ -45,11 +49,11 @@ func (m *ShimManager) loadExistingTasks(ctx context.Context) error {
continue
}
log.G(ctx).WithField("namespace", ns).Debug("loading tasks in namespace")
if err := m.loadShims(namespaces.WithNamespace(ctx, ns)); err != nil {
if err := m.loadShims(namespaces.WithNamespace(ctx, ns), stateDir); err != nil {
log.G(ctx).WithField("namespace", ns).WithError(err).Error("loading tasks in namespace")
continue
}
if err := m.cleanupWorkDirs(namespaces.WithNamespace(ctx, ns)); err != nil {
if err := m.cleanupWorkDirs(namespaces.WithNamespace(ctx, ns), rootDir); err != nil {
log.G(ctx).WithField("namespace", ns).WithError(err).Error("cleanup working directory in namespace")
continue
}
@ -57,14 +61,14 @@ func (m *ShimManager) loadExistingTasks(ctx context.Context) error {
return nil
}
func (m *ShimManager) loadShims(ctx context.Context) error {
func (m *ShimManager) loadShims(ctx context.Context, stateDir string) error {
ns, err := namespaces.NamespaceRequired(ctx)
if err != nil {
return err
}
ctx = log.WithLogger(ctx, log.G(ctx).WithField("namespace", ns))
shimDirs, err := os.ReadDir(filepath.Join(m.state, ns))
shimDirs, err := os.ReadDir(filepath.Join(stateDir, ns))
if err != nil {
return err
}
@ -77,7 +81,7 @@ func (m *ShimManager) loadShims(ctx context.Context) error {
if len(id) > 0 && id[0] == '.' {
continue
}
bundle, err := LoadBundle(ctx, m.state, id)
bundle, err := LoadBundle(ctx, stateDir, id)
if err != nil {
// fine to return error here, it is a programmer error if the context
// does not have a namespace
@ -102,9 +106,20 @@ func (m *ShimManager) loadShims(ctx context.Context) error {
bundle.Delete()
continue
}
if err := m.loadShim(ctx, bundle); err != nil {
log.G(ctx).WithError(err).Errorf("failed to load shim %s", bundle.Path)
bundle.Delete()
continue
}
}
return nil
}
func (m *ShimManager) loadShim(ctx context.Context, bundle *Bundle) error {
var (
runtime string
id = bundle.ID
)
// If we're on 1.6+ and specified custom path to the runtime binary, path will be saved in 'shim-binary-path' file.
@ -122,17 +137,16 @@ func (m *ShimManager) loadShims(ctx context.Context) error {
if err := mount.UnmountRecursive(filepath.Join(bundle.Path, "rootfs"), 0); err != nil {
log.G(ctx).WithError(err).Errorf("failed to unmount of rootfs %s", id)
}
bundle.Delete()
continue
return err
}
runtime = container.Runtime.Name
}
runtime, err = m.resolveRuntimePath(runtime)
runtime, err := m.resolveRuntimePath(runtime)
if err != nil {
bundle.Delete()
log.G(ctx).WithError(err).Error("failed to resolve runtime path")
continue
return fmt.Errorf("failed to resolve runtime path: %w", err)
}
binaryCall := shimBinary(bundle,
@ -142,6 +156,7 @@ func (m *ShimManager) loadShims(ctx context.Context) error {
ttrpcAddress: m.containerdTTRPCAddress,
schedCore: m.schedCore,
})
// TODO: It seems we can only call loadShim here if it is a sandbox shim?
shim, err := loadShimTask(ctx, bundle, func() {
log.G(ctx).WithField("id", id).Info("shim disconnected")
@ -150,9 +165,8 @@ func (m *ShimManager) loadShims(ctx context.Context) error {
m.shims.Delete(ctx, id)
})
if err != nil {
log.G(ctx).WithError(err).Errorf("unable to load shim %q", id)
cleanupAfterDeadShim(ctx, id, m.shims, m.events, binaryCall)
continue
return fmt.Errorf("unable to load shim %q: %w", id, err)
}
// There are 3 possibilities for the loaded shim here:
@ -174,7 +188,6 @@ func (m *ShimManager) loadShims(ctx context.Context) error {
} else {
m.shims.Add(ctx, shim.ShimInstance)
}
}
return nil
}
@ -198,13 +211,13 @@ func loadShimTask(ctx context.Context, bundle *Bundle, onClose func()) (_ *shimT
return s, nil
}
func (m *ShimManager) cleanupWorkDirs(ctx context.Context) error {
func (m *ShimManager) cleanupWorkDirs(ctx context.Context, rootDir string) error {
ns, err := namespaces.NamespaceRequired(ctx)
if err != nil {
return err
}
f, err := os.Open(filepath.Join(m.root, ns))
f, err := os.Open(filepath.Join(rootDir, ns))
if err != nil {
return err
}
@ -220,7 +233,7 @@ func (m *ShimManager) cleanupWorkDirs(ctx context.Context) error {
// this can happen on a reboot where /run for the bundle state is cleaned up
// but that persistent working dir is left
if _, err := m.shims.Get(ctx, dir); err != nil {
path := filepath.Join(m.root, ns, dir)
path := filepath.Join(rootDir, ns, dir)
if err := os.RemoveAll(path); err != nil {
log.G(ctx).WithError(err).Errorf("cleanup working dir %s", path)
}

View File

@ -17,7 +17,6 @@
package v2
import (
"bytes"
"context"
"errors"
"fmt"
@ -27,7 +26,11 @@ import (
"strings"
"sync"
apitypes "github.com/containerd/containerd/v2/api/types"
"github.com/containerd/log"
"github.com/containerd/platforms"
"github.com/containerd/plugin"
"github.com/containerd/plugin/registry"
"github.com/containerd/containerd/v2/core/containers"
"github.com/containerd/containerd/v2/core/events/exchange"
"github.com/containerd/containerd/v2/core/metadata"
@ -39,15 +42,10 @@ import (
"github.com/containerd/containerd/v2/pkg/timeout"
"github.com/containerd/containerd/v2/plugins"
"github.com/containerd/containerd/v2/protobuf"
"github.com/containerd/containerd/v2/protobuf/proto"
"github.com/containerd/errdefs"
"github.com/containerd/log"
"github.com/containerd/platforms"
"github.com/containerd/plugin"
"github.com/containerd/plugin/registry"
"github.com/containerd/containerd/v2/version"
)
// Config for the v2 runtime
// Config for the shim
type Config struct {
// Supported platforms
Platforms []string `toml:"platforms"`
@ -56,9 +54,12 @@ type Config struct {
}
func init() {
// ShimManager is not only for TaskManager,
// the "shim" sandbox controller also use it to manage shims,
// so we make it an independent plugin
registry.Register(&plugin.Registration{
Type: plugins.RuntimePluginV2,
ID: "task",
Type: plugins.ShimPlugin,
ID: "shim",
Requires: []plugin.Type{
plugins.EventPlugin,
plugins.MetadataPlugin,
@ -72,7 +73,6 @@ func init() {
if err != nil {
return nil, err
}
ic.Meta.Platforms = supportedPlatforms
m, err := ic.GetSingle(plugins.MetadataPlugin)
@ -83,13 +83,10 @@ func init() {
if err != nil {
return nil, err
}
events := ep.(*exchange.Exchange)
cs := metadata.NewContainerStore(m.(*metadata.DB))
ss := metadata.NewSandboxStore(m.(*metadata.DB))
events := ep.(*exchange.Exchange)
shimManager, err := NewShimManager(ic.Context, &ManagerConfig{
Root: ic.Properties[plugins.PropertyRootDir],
State: ic.Properties[plugins.PropertyStateDir],
return NewShimManager(&ManagerConfig{
Address: ic.Properties[plugins.PropertyGRPCAddress],
TTRPCAddress: ic.Properties[plugins.PropertyTTRPCAddress],
Events: events,
@ -97,36 +94,27 @@ func init() {
SchedCore: config.SchedCore,
SandboxStore: ss,
})
if err != nil {
return nil, err
}
return NewTaskManager(shimManager), nil
},
})
// Task manager uses shim manager as a dependency to manage shim instances.
// However, due to time limits and to avoid migration steps in 1.6 release,
// use the following workaround.
// This expected to be removed in 1.7.
registry.Register(&plugin.Registration{
Type: plugins.RuntimePluginV2,
ID: "shim",
InitFn: func(ic *plugin.InitContext) (interface{}, error) {
taskManagerI, err := ic.GetByID(plugins.RuntimePluginV2, "task")
if err != nil {
return nil, err
ConfigMigration: func(ctx context.Context, configVersion int, pluginConfigs map[string]interface{}) error {
// Migrate configurations from io.containerd.runtime.v2.task
// if the configVersion >= 3 please make sure the config is under io.containerd.shim.v1.shim.
if configVersion >= version.ConfigVersion {
return nil
}
taskManager := taskManagerI.(*TaskManager)
return taskManager.manager, nil
const originalPluginName = string(plugins.RuntimePluginV2) + ".task"
original, ok := pluginConfigs[originalPluginName]
if !ok {
return nil
}
const newPluginName = string(plugins.ShimPlugin) + ".shim"
pluginConfigs[originalPluginName] = nil
pluginConfigs[newPluginName] = original
return nil
},
})
}
type ManagerConfig struct {
Root string
State string
Store containers.Store
Events *exchange.Exchange
Address string
@ -136,16 +124,8 @@ type ManagerConfig struct {
}
// NewShimManager creates a manager for v2 shims
func NewShimManager(ctx context.Context, config *ManagerConfig) (*ShimManager, error) {
for _, d := range []string{config.Root, config.State} {
if err := os.MkdirAll(d, 0711); err != nil {
return nil, err
}
}
func NewShimManager(config *ManagerConfig) (*ShimManager, error) {
m := &ShimManager{
root: config.Root,
state: config.State,
containerdAddress: config.Address,
containerdTTRPCAddress: config.TTRPCAddress,
shims: runtime.NewNSMap[ShimInstance](),
@ -155,10 +135,6 @@ func NewShimManager(ctx context.Context, config *ManagerConfig) (*ShimManager, e
sandboxStore: config.SandboxStore,
}
if err := m.loadExistingTasks(ctx); err != nil {
return nil, err
}
return m, nil
}
@ -167,8 +143,6 @@ func NewShimManager(ctx context.Context, config *ManagerConfig) (*ShimManager, e
// The manager is unaware of the underlying services shim provides and lets higher level services consume them,
// but don't care about lifecycle management.
type ShimManager struct {
root string
state string
containerdAddress string
containerdTTRPCAddress string
schedCore bool
@ -182,21 +156,11 @@ type ShimManager struct {
// ID of the shim manager
func (m *ShimManager) ID() string {
return plugins.RuntimePluginV2.String() + ".shim"
return plugins.ShimPlugin.String() + ".shim"
}
// Start launches a new shim instance
func (m *ShimManager) Start(ctx context.Context, id string, opts runtime.CreateOpts) (_ ShimInstance, retErr error) {
bundle, err := NewBundle(ctx, m.root, m.state, id, opts.Spec)
if err != nil {
return nil, err
}
defer func() {
if retErr != nil {
bundle.Delete()
}
}()
func (m *ShimManager) Start(ctx context.Context, id string, bundle *Bundle, opts runtime.CreateOpts) (_ ShimInstance, retErr error) {
// This container belongs to sandbox which supposed to be already started via sandbox API.
if opts.SandboxID != "" {
process, err := m.Get(ctx, opts.SandboxID)
@ -209,7 +173,7 @@ func (m *ShimManager) Start(ctx context.Context, id string, opts runtime.CreateO
return nil, err
}
params, err := restoreBootstrapParams(filepath.Join(m.state, process.Namespace(), opts.SandboxID))
params, err := restoreBootstrapParams(process.Bundle())
if err != nil {
return nil, err
}
@ -423,148 +387,3 @@ func (m *ShimManager) Delete(ctx context.Context, id string) error {
return err
}
// TaskManager wraps task service client on top of shim manager.
type TaskManager struct {
manager *ShimManager
}
// NewTaskManager creates a new task manager instance.
func NewTaskManager(shims *ShimManager) *TaskManager {
return &TaskManager{
manager: shims,
}
}
// ID of the task manager
func (m *TaskManager) ID() string {
return plugins.RuntimePluginV2.String() + ".task"
}
// Create launches new shim instance and creates new task
func (m *TaskManager) Create(ctx context.Context, taskID string, opts runtime.CreateOpts) (runtime.Task, error) {
shim, err := m.manager.Start(ctx, taskID, opts)
if err != nil {
return nil, fmt.Errorf("failed to start shim: %w", err)
}
// Cast to shim task and call task service to create a new container task instance.
// This will not be required once shim service / client implemented.
shimTask, err := newShimTask(shim)
if err != nil {
return nil, err
}
t, err := shimTask.Create(ctx, opts)
if err != nil {
// NOTE: ctx contains required namespace information.
m.manager.shims.Delete(ctx, taskID)
dctx, cancel := timeout.WithContext(cleanup.Background(ctx), cleanupTimeout)
defer cancel()
sandboxed := opts.SandboxID != ""
_, errShim := shimTask.delete(dctx, sandboxed, func(context.Context, string) {})
if errShim != nil {
if errdefs.IsDeadlineExceeded(errShim) {
dctx, cancel = timeout.WithContext(cleanup.Background(ctx), cleanupTimeout)
defer cancel()
}
shimTask.Shutdown(dctx)
shimTask.Close()
}
return nil, fmt.Errorf("failed to create shim task: %w", err)
}
return t, nil
}
// Get a specific task
func (m *TaskManager) Get(ctx context.Context, id string) (runtime.Task, error) {
shim, err := m.manager.shims.Get(ctx, id)
if err != nil {
return nil, err
}
return newShimTask(shim)
}
// Tasks lists all tasks
func (m *TaskManager) Tasks(ctx context.Context, all bool) ([]runtime.Task, error) {
shims, err := m.manager.shims.GetAll(ctx, all)
if err != nil {
return nil, err
}
out := make([]runtime.Task, len(shims))
for i := range shims {
newClient, err := newShimTask(shims[i])
if err != nil {
return nil, err
}
out[i] = newClient
}
return out, nil
}
// Delete deletes the task and shim instance
func (m *TaskManager) Delete(ctx context.Context, taskID string) (*runtime.Exit, error) {
shim, err := m.manager.shims.Get(ctx, taskID)
if err != nil {
return nil, err
}
container, err := m.manager.containers.Get(ctx, taskID)
if err != nil {
return nil, err
}
shimTask, err := newShimTask(shim)
if err != nil {
return nil, err
}
sandboxed := container.SandboxID != ""
exit, err := shimTask.delete(ctx, sandboxed, func(ctx context.Context, id string) {
m.manager.shims.Delete(ctx, id)
})
if err != nil {
return nil, fmt.Errorf("failed to delete task: %w", err)
}
return exit, nil
}
func (m *TaskManager) PluginInfo(ctx context.Context, request interface{}) (interface{}, error) {
req, ok := request.(*apitypes.RuntimeRequest)
if !ok {
return nil, fmt.Errorf("unknown request type %T: %w", request, errdefs.ErrNotImplemented)
}
runtimePath, err := m.manager.resolveRuntimePath(req.RuntimePath)
if err != nil {
return nil, fmt.Errorf("failed to resolve runtime path: %w", err)
}
var optsB []byte
if req.Options != nil {
optsB, err = proto.Marshal(req.Options)
if err != nil {
return nil, fmt.Errorf("failed to marshal %s: %w", req.Options.TypeUrl, err)
}
}
var stderr bytes.Buffer
cmd := exec.CommandContext(ctx, runtimePath, "-info")
cmd.Stdin = bytes.NewReader(optsB)
cmd.Stderr = &stderr
stdout, err := cmd.Output()
if err != nil {
return nil, fmt.Errorf("failed to run %v: %w (stderr: %q)", cmd.Args, err, stderr.String())
}
var info apitypes.RuntimeInfo
if err = proto.Unmarshal(stdout, &info); err != nil {
return nil, fmt.Errorf("failed to unmarshal stdout from %v into %T: %w", cmd.Args, &info, err)
}
return &info, nil
}

View File

@ -0,0 +1,226 @@
/*
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 v2
import (
"bytes"
"context"
"fmt"
"os"
"os/exec"
"github.com/containerd/errdefs"
"github.com/containerd/plugin"
"github.com/containerd/plugin/registry"
apitypes "github.com/containerd/containerd/v2/api/types"
"github.com/containerd/containerd/v2/core/runtime"
"github.com/containerd/containerd/v2/internal/cleanup"
"github.com/containerd/containerd/v2/pkg/timeout"
"github.com/containerd/containerd/v2/plugins"
"github.com/containerd/containerd/v2/protobuf/proto"
)
func init() {
registry.Register(&plugin.Registration{
Type: plugins.RuntimePluginV2,
ID: "task",
Requires: []plugin.Type{
plugins.ShimPlugin,
},
InitFn: func(ic *plugin.InitContext) (interface{}, error) {
shimManagerI, err := ic.GetByID(plugins.ShimPlugin, "shim")
if err != nil {
return nil, err
}
shimManager := shimManagerI.(*ShimManager)
root, state := ic.Properties[plugins.PropertyRootDir], ic.Properties[plugins.PropertyStateDir]
for _, d := range []string{root, state} {
if err := os.MkdirAll(d, 0711); err != nil {
return nil, err
}
}
return NewTaskManager(ic.Context, root, state, shimManager)
},
})
}
// TaskManager wraps task service client on top of shim manager.
type TaskManager struct {
root string
state string
manager *ShimManager
}
// NewTaskManager creates a new task manager instance.
// root is the rootDir of TaskManager plugin to store persistent data
// state is the stateDir of TaskManager plugin to store transient data
// shims is ShimManager for TaskManager to create/delete shims
func NewTaskManager(ctx context.Context, root, state string, shims *ShimManager) (*TaskManager, error) {
if err := shims.LoadExistingShims(ctx, state, root); err != nil {
return nil, fmt.Errorf("failed to load existing shims for task manager")
}
m := &TaskManager{
root: root,
state: state,
manager: shims,
}
return m, nil
}
// ID of the task manager
func (m *TaskManager) ID() string {
return plugins.RuntimePluginV2.String() + ".task"
}
// Create launches new shim instance and creates new task
func (m *TaskManager) Create(ctx context.Context, taskID string, opts runtime.CreateOpts) (_ runtime.Task, retErr error) {
bundle, err := NewBundle(ctx, m.root, m.state, taskID, opts.Spec)
if err != nil {
return nil, err
}
defer func() {
if retErr != nil {
bundle.Delete()
}
}()
shim, err := m.manager.Start(ctx, taskID, bundle, opts)
if err != nil {
return nil, fmt.Errorf("failed to start shim: %w", err)
}
// Cast to shim task and call task service to create a new container task instance.
// This will not be required once shim service / client implemented.
shimTask, err := newShimTask(shim)
if err != nil {
return nil, err
}
t, err := shimTask.Create(ctx, opts)
if err != nil {
// NOTE: ctx contains required namespace information.
m.manager.shims.Delete(ctx, taskID)
dctx, cancel := timeout.WithContext(cleanup.Background(ctx), cleanupTimeout)
defer cancel()
sandboxed := opts.SandboxID != ""
_, errShim := shimTask.delete(dctx, sandboxed, func(context.Context, string) {})
if errShim != nil {
if errdefs.IsDeadlineExceeded(errShim) {
dctx, cancel = timeout.WithContext(cleanup.Background(ctx), cleanupTimeout)
defer cancel()
}
shimTask.Shutdown(dctx)
shimTask.Close()
}
return nil, fmt.Errorf("failed to create shim task: %w", err)
}
return t, nil
}
// Get a specific task
func (m *TaskManager) Get(ctx context.Context, id string) (runtime.Task, error) {
shim, err := m.manager.shims.Get(ctx, id)
if err != nil {
return nil, err
}
return newShimTask(shim)
}
// Tasks lists all tasks
func (m *TaskManager) Tasks(ctx context.Context, all bool) ([]runtime.Task, error) {
shims, err := m.manager.shims.GetAll(ctx, all)
if err != nil {
return nil, err
}
out := make([]runtime.Task, len(shims))
for i := range shims {
newClient, err := newShimTask(shims[i])
if err != nil {
return nil, err
}
out[i] = newClient
}
return out, nil
}
// Delete deletes the task and shim instance
func (m *TaskManager) Delete(ctx context.Context, taskID string) (*runtime.Exit, error) {
shim, err := m.manager.shims.Get(ctx, taskID)
if err != nil {
return nil, err
}
container, err := m.manager.containers.Get(ctx, taskID)
if err != nil {
return nil, err
}
shimTask, err := newShimTask(shim)
if err != nil {
return nil, err
}
sandboxed := container.SandboxID != ""
exit, err := shimTask.delete(ctx, sandboxed, func(ctx context.Context, id string) {
m.manager.shims.Delete(ctx, id)
})
if err != nil {
return nil, fmt.Errorf("failed to delete task: %w", err)
}
return exit, nil
}
func (m *TaskManager) PluginInfo(ctx context.Context, request interface{}) (interface{}, error) {
req, ok := request.(*apitypes.RuntimeRequest)
if !ok {
return nil, fmt.Errorf("unknown request type %T: %w", request, errdefs.ErrNotImplemented)
}
runtimePath, err := m.manager.resolveRuntimePath(req.RuntimePath)
if err != nil {
return nil, fmt.Errorf("failed to resolve runtime path: %w", err)
}
var optsB []byte
if req.Options != nil {
optsB, err = proto.Marshal(req.Options)
if err != nil {
return nil, fmt.Errorf("failed to marshal %s: %w", req.Options.TypeUrl, err)
}
}
var stderr bytes.Buffer
cmd := exec.CommandContext(ctx, runtimePath, "-info")
cmd.Stdin = bytes.NewReader(optsB)
cmd.Stderr = &stderr
stdout, err := cmd.Output()
if err != nil {
return nil, fmt.Errorf("failed to run %v: %w (stderr: %q)", cmd.Args, err, stderr.String())
}
var info apitypes.RuntimeInfo
if err = proto.Unmarshal(stdout, &info); err != nil {
return nil, fmt.Errorf("failed to unmarshal stdout from %v into %T: %w", cmd.Args, &info, err)
}
return &info, nil
}

View File

@ -19,8 +19,16 @@ package sandbox
import (
"context"
"fmt"
"os"
"time"
"github.com/containerd/errdefs"
"github.com/containerd/log"
"github.com/containerd/platforms"
"github.com/containerd/plugin"
"github.com/containerd/plugin/registry"
"google.golang.org/protobuf/types/known/anypb"
runtimeAPI "github.com/containerd/containerd/v2/api/runtime/sandbox/v1"
"github.com/containerd/containerd/v2/api/types"
"github.com/containerd/containerd/v2/core/events"
@ -30,13 +38,6 @@ import (
v2 "github.com/containerd/containerd/v2/core/runtime/v2"
"github.com/containerd/containerd/v2/core/sandbox"
"github.com/containerd/containerd/v2/plugins"
"github.com/containerd/errdefs"
"github.com/containerd/log"
"github.com/containerd/platforms"
"github.com/containerd/plugin"
"github.com/containerd/plugin/registry"
"google.golang.org/protobuf/types/known/anypb"
)
func init() {
@ -44,11 +45,11 @@ func init() {
Type: plugins.SandboxControllerPlugin,
ID: "shim",
Requires: []plugin.Type{
plugins.RuntimePluginV2,
plugins.ShimPlugin,
plugins.EventPlugin,
},
InitFn: func(ic *plugin.InitContext) (interface{}, error) {
shimPlugin, err := ic.GetByID(plugins.RuntimePluginV2, "shim")
shimPlugin, err := ic.GetByID(plugins.ShimPlugin, "shim")
if err != nil {
return nil, err
}
@ -62,16 +63,32 @@ func init() {
shims = shimPlugin.(*v2.ShimManager)
publisher = exchangePlugin.(*exchange.Exchange)
)
state := ic.Properties[plugins.PropertyStateDir]
root := ic.Properties[plugins.PropertyRootDir]
for _, d := range []string{root, state} {
if err := os.MkdirAll(d, 0711); err != nil {
return nil, err
}
}
return &controllerLocal{
if err := shims.LoadExistingShims(ic.Context, root, state); err != nil {
return nil, fmt.Errorf("failed to load existing shim sandboxes, %v", err)
}
c := &controllerLocal{
root: root,
state: state,
shims: shims,
publisher: publisher,
}, nil
}
return c, nil
},
})
}
type controllerLocal struct {
root string
state string
shims *v2.ShimManager
publisher events.Publisher
}
@ -97,7 +114,7 @@ func (c *controllerLocal) cleanupShim(ctx context.Context, sandboxID string, svc
}
}
func (c *controllerLocal) Create(ctx context.Context, info sandbox.Sandbox, opts ...sandbox.CreateOpt) error {
func (c *controllerLocal) Create(ctx context.Context, info sandbox.Sandbox, opts ...sandbox.CreateOpt) (retErr error) {
var coptions sandbox.CreateOptions
sandboxID := info.ID
for _, opt := range opts {
@ -108,7 +125,17 @@ func (c *controllerLocal) Create(ctx context.Context, info sandbox.Sandbox, opts
return fmt.Errorf("sandbox %s already running: %w", sandboxID, errdefs.ErrAlreadyExists)
}
shim, err := c.shims.Start(ctx, sandboxID, runtime.CreateOpts{
bundle, err := v2.NewBundle(ctx, c.root, c.state, sandboxID, info.Spec)
if err != nil {
return err
}
defer func() {
if retErr != nil {
bundle.Delete()
}
}()
shim, err := c.shims.Start(ctx, sandboxID, bundle, runtime.CreateOpts{
Spec: info.Spec,
RuntimeOptions: info.Runtime.Options,
Runtime: info.Runtime.Name,

View File

@ -71,6 +71,8 @@ const (
WarningPlugin plugin.Type = "io.containerd.warning.v1"
// CRIServicePlugin implements a cri service
CRIServicePlugin plugin.Type = "io.containerd.cri.v1"
// ShimPlugin implements a shim service
ShimPlugin plugin.Type = "io.containerd.shim.v1"
)
const (