Merge pull request #9442 from AkihiroSuda/runtime-info2
api/services/instrospection: add PluginInfo
This commit is contained in:
@@ -17,9 +17,12 @@
|
||||
package manager
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@@ -30,16 +33,21 @@ import (
|
||||
"github.com/containerd/cgroups/v3"
|
||||
"github.com/containerd/cgroups/v3/cgroup1"
|
||||
cgroupsv2 "github.com/containerd/cgroups/v3/cgroup2"
|
||||
"github.com/containerd/containerd/v2/api/types"
|
||||
"github.com/containerd/containerd/v2/cmd/containerd-shim-runc-v2/process"
|
||||
"github.com/containerd/containerd/v2/cmd/containerd-shim-runc-v2/runc"
|
||||
"github.com/containerd/containerd/v2/core/mount"
|
||||
"github.com/containerd/containerd/v2/core/runtime/v2/runc/options"
|
||||
"github.com/containerd/containerd/v2/core/runtime/v2/shim"
|
||||
"github.com/containerd/containerd/v2/pkg/errdefs"
|
||||
"github.com/containerd/containerd/v2/pkg/namespaces"
|
||||
"github.com/containerd/containerd/v2/pkg/oci"
|
||||
"github.com/containerd/containerd/v2/pkg/schedcore"
|
||||
"github.com/containerd/containerd/v2/protobuf"
|
||||
"github.com/containerd/containerd/v2/version"
|
||||
runcC "github.com/containerd/go-runc"
|
||||
"github.com/containerd/log"
|
||||
"github.com/opencontainers/runtime-spec/specs-go/features"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
@@ -272,3 +280,63 @@ func (manager) Stop(ctx context.Context, id string) (shim.StopStatus, error) {
|
||||
Pid: pid,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m manager) Info(ctx context.Context, optionsR io.Reader) (*types.RuntimeInfo, error) {
|
||||
info := &types.RuntimeInfo{
|
||||
Name: m.name,
|
||||
Version: &types.RuntimeVersion{
|
||||
Version: version.Version,
|
||||
Revision: version.Version,
|
||||
},
|
||||
Annotations: nil,
|
||||
}
|
||||
binaryName := runcC.DefaultCommand
|
||||
opts, err := shim.ReadRuntimeOptions[*options.Options](optionsR)
|
||||
if err != nil {
|
||||
if !errors.Is(err, errdefs.ErrNotFound) {
|
||||
return nil, fmt.Errorf("failed to read runtime options (*options.Options): %w", err)
|
||||
}
|
||||
}
|
||||
if opts != nil {
|
||||
info.Options, err = protobuf.MarshalAnyToProto(opts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal %T: %w", opts, err)
|
||||
}
|
||||
if opts.BinaryName != "" {
|
||||
binaryName = opts.BinaryName
|
||||
}
|
||||
|
||||
}
|
||||
absBinary, err := exec.LookPath(binaryName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to look up the path of %q: %w", binaryName, err)
|
||||
}
|
||||
features, err := m.features(ctx, absBinary, opts)
|
||||
if err != nil {
|
||||
// youki does not implement `runc features` yet, at the time of writing this (Sep 2023)
|
||||
// https://github.com/containers/youki/issues/815
|
||||
log.G(ctx).WithError(err).Debug("Failed to get the runtime features. The runc binary does not implement `runc features` command?")
|
||||
}
|
||||
if features != nil {
|
||||
info.Features, err = protobuf.MarshalAnyToProto(features)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal %T: %w", features, err)
|
||||
}
|
||||
}
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func (m manager) features(ctx context.Context, absBinary string, opts *options.Options) (*features.Features, error) {
|
||||
var stderr bytes.Buffer
|
||||
cmd := exec.CommandContext(ctx, absBinary, "features")
|
||||
cmd.Stderr = &stderr
|
||||
stdout, err := cmd.Output()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute %v: %w (stderr: %q)", cmd.Args, err, stderr.String())
|
||||
}
|
||||
var feat features.Features
|
||||
if err := json.Unmarshal(stdout, &feat); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &feat, nil
|
||||
}
|
||||
|
||||
@@ -96,6 +96,19 @@ var (
|
||||
},
|
||||
}
|
||||
|
||||
// RuntimeFlags are cli flags specifying runtime
|
||||
RuntimeFlags = []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "runtime",
|
||||
Usage: "Runtime name or absolute path to runtime binary",
|
||||
Value: defaults.DefaultRuntime,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "runtime-config-path",
|
||||
Usage: "Optional runtime config path",
|
||||
},
|
||||
}
|
||||
|
||||
// ContainerFlags are cli flags specifying container options
|
||||
ContainerFlags = []cli.Flag{
|
||||
cli.StringFlag{
|
||||
@@ -138,19 +151,10 @@ var (
|
||||
Name: "read-only",
|
||||
Usage: "Set the containers filesystem as readonly",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "runtime",
|
||||
Usage: "Runtime name or absolute path to runtime binary",
|
||||
Value: defaults.DefaultRuntime,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "sandbox",
|
||||
Usage: "Create the container in the given sandbox",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "runtime-config-path",
|
||||
Usage: "Optional runtime config path",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "tty,t",
|
||||
Usage: "Allocate a TTY for the container",
|
||||
|
||||
@@ -19,10 +19,24 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/containerd/containerd/v2/core/runtime/v2/runc/options"
|
||||
runtimeoptions "github.com/containerd/containerd/v2/pkg/runtimeoptions/v1"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
func init() {
|
||||
RuntimeFlags = append(RuntimeFlags, cli.StringFlag{
|
||||
Name: "runc-binary",
|
||||
Usage: "Specify runc-compatible binary",
|
||||
}, cli.StringFlag{
|
||||
Name: "runc-root",
|
||||
Usage: "Specify runc-compatible root",
|
||||
}, cli.BoolFlag{
|
||||
Name: "runc-systemd-cgroup",
|
||||
Usage: "Start runc with systemd cgroup manager",
|
||||
})
|
||||
ContainerFlags = append(ContainerFlags, cli.BoolFlag{
|
||||
Name: "rootfs",
|
||||
Usage: "Use custom rootfs that is not managed by containerd snapshotter",
|
||||
@@ -44,3 +58,42 @@ func init() {
|
||||
Usage: "File path to a device to add to the container; or a path to a directory tree of devices to add to the container",
|
||||
})
|
||||
}
|
||||
|
||||
func getRuncOptions(context *cli.Context) (*options.Options, error) {
|
||||
runtimeOpts := &options.Options{}
|
||||
if runcBinary := context.String("runc-binary"); runcBinary != "" {
|
||||
runtimeOpts.BinaryName = runcBinary
|
||||
}
|
||||
if context.Bool("runc-systemd-cgroup") {
|
||||
if context.String("cgroup") == "" {
|
||||
// runc maps "machine.slice:foo:deadbeef" to "/machine.slice/foo-deadbeef.scope"
|
||||
return nil, errors.New("option --runc-systemd-cgroup requires --cgroup to be set, e.g. \"machine.slice:foo:deadbeef\"")
|
||||
}
|
||||
runtimeOpts.SystemdCgroup = true
|
||||
}
|
||||
if root := context.String("runc-root"); root != "" {
|
||||
runtimeOpts.Root = root
|
||||
}
|
||||
|
||||
return runtimeOpts, nil
|
||||
}
|
||||
|
||||
func RuntimeOptions(context *cli.Context) (interface{}, error) {
|
||||
// validate first
|
||||
if (context.String("runc-binary") != "" || context.Bool("runc-systemd-cgroup")) &&
|
||||
context.String("runtime") != "io.containerd.runc.v2" {
|
||||
return nil, errors.New("specifying runc-binary and runc-systemd-cgroup is only supported for \"io.containerd.runc.v2\" runtime")
|
||||
}
|
||||
|
||||
if context.String("runtime") == "io.containerd.runc.v2" {
|
||||
return getRuncOptions(context)
|
||||
}
|
||||
|
||||
if configPath := context.String("runtime-config-path"); configPath != "" {
|
||||
return &runtimeoptions.Options{
|
||||
ConfigPath: configPath,
|
||||
}, nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -38,3 +38,7 @@ func init() {
|
||||
Usage: "Identifier of a device to add to the container (e.g. class://5B45201D-F2F2-4F3B-85BB-30FF1F953599)",
|
||||
})
|
||||
}
|
||||
|
||||
func RuntimeOptions(context *cli.Context) (interface{}, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ var createCommand = cli.Command{
|
||||
Usage: "Create container",
|
||||
ArgsUsage: "[flags] Image|RootFS CONTAINER [COMMAND] [ARG...]",
|
||||
SkipArgReorder: true,
|
||||
Flags: append(append(commands.SnapshotterFlags, []cli.Flag{commands.SnapshotterLabels}...), commands.ContainerFlags...),
|
||||
Flags: append(commands.RuntimeFlags, append(append(commands.SnapshotterFlags, []cli.Flag{commands.SnapshotterLabels}...), commands.ContainerFlags...)...),
|
||||
Action: func(context *cli.Context) error {
|
||||
var (
|
||||
id string
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package plugins
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
@@ -39,6 +40,7 @@ var Command = cli.Command{
|
||||
Usage: "Provides information about containerd plugins",
|
||||
Subcommands: []cli.Command{
|
||||
listCommand,
|
||||
inspectRuntimeCommand,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -162,3 +164,32 @@ func prettyPlatforms(pspb []*types.Platform) string {
|
||||
sort.Stable(sort.StringSlice(ps))
|
||||
return strings.Join(ps, ",")
|
||||
}
|
||||
|
||||
var inspectRuntimeCommand = cli.Command{
|
||||
Name: "inspect-runtime",
|
||||
Usage: "Display runtime info",
|
||||
ArgsUsage: "[flags]",
|
||||
Flags: commands.RuntimeFlags,
|
||||
Action: func(context *cli.Context) error {
|
||||
rt := context.String("runtime")
|
||||
rtOptions, err := commands.RuntimeOptions(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client, ctx, cancel, err := commands.NewClient(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
rtInfo, err := client.RuntimeInfo(ctx, rt, rtOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
j, err := json.MarshalIndent(rtInfo, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = fmt.Fprintln(context.App.Writer, string(j))
|
||||
return err
|
||||
},
|
||||
}
|
||||
|
||||
@@ -128,8 +128,9 @@ var Command = cli.Command{
|
||||
Usage: "Enable cni networking for the container",
|
||||
},
|
||||
}, append(platformRunFlags,
|
||||
append(append(commands.SnapshotterFlags, []cli.Flag{commands.SnapshotterLabels}...),
|
||||
commands.ContainerFlags...)...)...),
|
||||
append(commands.RuntimeFlags,
|
||||
append(append(commands.SnapshotterFlags, []cli.Flag{commands.SnapshotterLabels}...),
|
||||
commands.ContainerFlags...)...)...)...),
|
||||
Action: func(context *cli.Context) error {
|
||||
var (
|
||||
err error
|
||||
|
||||
@@ -34,10 +34,8 @@ import (
|
||||
"github.com/containerd/containerd/v2/contrib/nvidia"
|
||||
"github.com/containerd/containerd/v2/contrib/seccomp"
|
||||
"github.com/containerd/containerd/v2/core/containers"
|
||||
"github.com/containerd/containerd/v2/core/runtime/v2/runc/options"
|
||||
"github.com/containerd/containerd/v2/core/snapshots"
|
||||
"github.com/containerd/containerd/v2/pkg/oci"
|
||||
runtimeoptions "github.com/containerd/containerd/v2/pkg/runtimeoptions/v1"
|
||||
"github.com/containerd/log"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/intel/goresctrl/pkg/blockio"
|
||||
@@ -48,18 +46,6 @@ import (
|
||||
)
|
||||
|
||||
var platformRunFlags = []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "runc-binary",
|
||||
Usage: "Specify runc-compatible binary",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "runc-root",
|
||||
Usage: "Specify runc-compatible root",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "runc-systemd-cgroup",
|
||||
Usage: "Start runc with systemd cgroup manager",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "uidmap",
|
||||
Usage: "Run inside a user namespace with the specified UID mapping range; specified with the format `container-uid:host-uid:length`",
|
||||
@@ -413,7 +399,7 @@ func NewContainer(ctx gocontext.Context, client *containerd.Client, context *cli
|
||||
cOpts = append(cOpts, containerd.WithContainerExtension(commands.CtrCniMetadataExtension, cniMeta))
|
||||
}
|
||||
|
||||
runtimeOpts, err := getRuntimeOptions(context)
|
||||
runtimeOpts, err := commands.RuntimeOptions(context)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -430,45 +416,6 @@ func NewContainer(ctx gocontext.Context, client *containerd.Client, context *cli
|
||||
return client.NewContainer(ctx, id, cOpts...)
|
||||
}
|
||||
|
||||
func getRuncOptions(context *cli.Context) (*options.Options, error) {
|
||||
runtimeOpts := &options.Options{}
|
||||
if runcBinary := context.String("runc-binary"); runcBinary != "" {
|
||||
runtimeOpts.BinaryName = runcBinary
|
||||
}
|
||||
if context.Bool("runc-systemd-cgroup") {
|
||||
if context.String("cgroup") == "" {
|
||||
// runc maps "machine.slice:foo:deadbeef" to "/machine.slice/foo-deadbeef.scope"
|
||||
return nil, errors.New("option --runc-systemd-cgroup requires --cgroup to be set, e.g. \"machine.slice:foo:deadbeef\"")
|
||||
}
|
||||
runtimeOpts.SystemdCgroup = true
|
||||
}
|
||||
if root := context.String("runc-root"); root != "" {
|
||||
runtimeOpts.Root = root
|
||||
}
|
||||
|
||||
return runtimeOpts, nil
|
||||
}
|
||||
|
||||
func getRuntimeOptions(context *cli.Context) (interface{}, error) {
|
||||
// validate first
|
||||
if (context.String("runc-binary") != "" || context.Bool("runc-systemd-cgroup")) &&
|
||||
context.String("runtime") != "io.containerd.runc.v2" {
|
||||
return nil, errors.New("specifying runc-binary and runc-systemd-cgroup is only supported for \"io.containerd.runc.v2\" runtime")
|
||||
}
|
||||
|
||||
if context.String("runtime") == "io.containerd.runc.v2" {
|
||||
return getRuncOptions(context)
|
||||
}
|
||||
|
||||
if configPath := context.String("runtime-config-path"); configPath != "" {
|
||||
return &runtimeoptions.Options{
|
||||
ConfigPath: configPath,
|
||||
}, nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func parseIDMapping(mapping string) (specs.LinuxIDMapping, error) {
|
||||
// We expect 3 parts, but limit to 4 to allow detection of invalid values.
|
||||
parts := strings.SplitN(mapping, ":", 4)
|
||||
|
||||
Reference in New Issue
Block a user