Merge pull request #9442 from AkihiroSuda/runtime-info2
api/services/instrospection: add PluginInfo
This commit is contained in:
@@ -21,6 +21,7 @@ import (
|
||||
|
||||
"github.com/containerd/typeurl/v2"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/opencontainers/runtime-spec/specs-go/features"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -31,4 +32,5 @@ func init() {
|
||||
typeurl.Register(&specs.Process{}, prefix, "opencontainers/runtime-spec", major, "Process")
|
||||
typeurl.Register(&specs.LinuxResources{}, prefix, "opencontainers/runtime-spec", major, "LinuxResources")
|
||||
typeurl.Register(&specs.WindowsResources{}, prefix, "opencontainers/runtime-spec", major, "WindowsResources")
|
||||
typeurl.Register(&features.Features{}, prefix, "opencontainers/runtime-spec", major, "features", "Features")
|
||||
}
|
||||
|
||||
@@ -243,6 +243,29 @@ The delete command MUST accept the following flags:
|
||||
|
||||
The delete command will be executed in the container's bundle as its `cwd` except for on Windows and FreeBSD platforms.
|
||||
|
||||
### Command-like flags
|
||||
#### `-v`
|
||||
Each shim SHOULD implement a `-v` flag.
|
||||
This command-like flag prints the shim implementation version and exits.
|
||||
The output is not machine-parsable.
|
||||
|
||||
#### `-info`
|
||||
Each shim SHOULD implement a `-info` flag.
|
||||
This command-like flag gets the option protobuf from stdin, prints the shim info protobuf (see below) to stdout, and exits.
|
||||
|
||||
```proto
|
||||
message RuntimeInfo {
|
||||
string name = 1;
|
||||
RuntimeVersion version = 2;
|
||||
// Options from stdin
|
||||
google.protobuf.Any options = 3;
|
||||
// OCI-compatible runtimes should use https://github.com/opencontainers/runtime-spec/blob/main/features.md
|
||||
google.protobuf.Any features = 4;
|
||||
// Annotations of the shim. Irrelevant to features.Annotations.
|
||||
map<string, string> annotations = 5;
|
||||
}
|
||||
```
|
||||
|
||||
### Host Level Shim Configuration
|
||||
|
||||
containerd does not provide any host level configuration for shims via the API.
|
||||
|
||||
@@ -18,9 +18,11 @@ package example
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
taskAPI "github.com/containerd/containerd/v2/api/runtime/task/v2"
|
||||
apitypes "github.com/containerd/containerd/v2/api/types"
|
||||
"github.com/containerd/containerd/v2/core/runtime/v2/shim"
|
||||
"github.com/containerd/containerd/v2/pkg/errdefs"
|
||||
"github.com/containerd/containerd/v2/pkg/shutdown"
|
||||
@@ -73,6 +75,16 @@ func (m manager) Stop(ctx context.Context, id string) (shim.StopStatus, error) {
|
||||
return shim.StopStatus{}, errdefs.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (m manager) Info(ctx context.Context, optionsR io.Reader) (*apitypes.RuntimeInfo, error) {
|
||||
info := &apitypes.RuntimeInfo{
|
||||
Name: "io.containerd.example.v1",
|
||||
Version: &apitypes.RuntimeVersion{
|
||||
Version: "v1.0.0",
|
||||
},
|
||||
}
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func newTaskService(ctx context.Context, publisher shim.Publisher, sd shutdown.Service) (taskAPI.TaskService, error) {
|
||||
// The shim.Publisher and shutdown.Service are usually useful for your task service,
|
||||
// but we don't need them in the exampleTaskService.
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package v2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -26,6 +27,7 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
apitypes "github.com/containerd/containerd/v2/api/types"
|
||||
"github.com/containerd/containerd/v2/core/containers"
|
||||
"github.com/containerd/containerd/v2/core/metadata"
|
||||
"github.com/containerd/containerd/v2/core/runtime"
|
||||
@@ -38,6 +40,7 @@ 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/log"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/containerd/plugin"
|
||||
@@ -533,3 +536,35 @@ func (m *TaskManager) Delete(ctx context.Context, taskID string) (*runtime.Exit,
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import (
|
||||
"time"
|
||||
|
||||
shimapi "github.com/containerd/containerd/v2/api/runtime/task/v3"
|
||||
"github.com/containerd/containerd/v2/api/types"
|
||||
"github.com/containerd/containerd/v2/pkg/events"
|
||||
"github.com/containerd/containerd/v2/pkg/namespaces"
|
||||
"github.com/containerd/containerd/v2/pkg/shutdown"
|
||||
@@ -79,6 +80,7 @@ type Manager interface {
|
||||
Name() string
|
||||
Start(ctx context.Context, id string, opts StartOpts) (BootstrapParams, error)
|
||||
Stop(ctx context.Context, id string) (StopStatus, error)
|
||||
Info(ctx context.Context, optionsR io.Reader) (*types.RuntimeInfo, error)
|
||||
}
|
||||
|
||||
// OptsKey is the context key for the Opts value.
|
||||
@@ -116,6 +118,7 @@ type TTRPCServerOptioner interface {
|
||||
var (
|
||||
debugFlag bool
|
||||
versionFlag bool
|
||||
infoFlag bool
|
||||
id string
|
||||
namespaceFlag string
|
||||
socketFlag string
|
||||
@@ -135,6 +138,9 @@ const (
|
||||
func parseFlags() {
|
||||
flag.BoolVar(&debugFlag, "debug", false, "enable debug output in logs")
|
||||
flag.BoolVar(&versionFlag, "v", false, "show the shim version and exit")
|
||||
// "info" is not a subcommand, because old shims produce very confusing errors for unknown subcommands
|
||||
// https://github.com/containerd/containerd/pull/8509#discussion_r1210021403
|
||||
flag.BoolVar(&infoFlag, "info", false, "get the option protobuf from stdin, print the shim info protobuf to stdout, and exit")
|
||||
flag.StringVar(&namespaceFlag, "namespace", "", "namespace that owns the shim")
|
||||
flag.StringVar(&id, "id", "", "id of the task")
|
||||
flag.StringVar(&socketFlag, "socket", "", "socket path to serve")
|
||||
@@ -195,6 +201,19 @@ func Run(ctx context.Context, manager Manager, opts ...BinaryOpts) {
|
||||
}
|
||||
}
|
||||
|
||||
func runInfo(ctx context.Context, manager Manager) error {
|
||||
info, err := manager.Info(ctx, os.Stdin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
infoB, err := proto.Marshal(info)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = os.Stdout.Write(infoB)
|
||||
return err
|
||||
}
|
||||
|
||||
func run(ctx context.Context, manager Manager, config Config) error {
|
||||
parseFlags()
|
||||
if versionFlag {
|
||||
@@ -206,6 +225,10 @@ func run(ctx context.Context, manager Manager, config Config) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if infoFlag {
|
||||
return runInfo(ctx, manager)
|
||||
}
|
||||
|
||||
if namespaceFlag == "" {
|
||||
return fmt.Errorf("shim namespace cannot be empty")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user