mirror of
https://github.com/opencontainers/runc.git
synced 2026-07-11 06:03:57 +08:00
Add runc features command
Fix issue 3274 See `types/features/features.go`. Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
This commit is contained in:
+74
@@ -0,0 +1,74 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/opencontainers/runc/libcontainer/capabilities"
|
||||||
|
"github.com/opencontainers/runc/libcontainer/configs"
|
||||||
|
"github.com/opencontainers/runc/libcontainer/seccomp"
|
||||||
|
"github.com/opencontainers/runc/libcontainer/specconv"
|
||||||
|
"github.com/opencontainers/runc/types/features"
|
||||||
|
"github.com/opencontainers/runtime-spec/specs-go"
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
var featuresCommand = cli.Command{
|
||||||
|
Name: "features",
|
||||||
|
Usage: "show the enabled features",
|
||||||
|
ArgsUsage: "",
|
||||||
|
Description: `Show the enabled features.
|
||||||
|
The result is parsable as a JSON.
|
||||||
|
See https://pkg.go.dev/github.com/opencontainers/runc/types/features for the type definition.
|
||||||
|
`,
|
||||||
|
Action: func(context *cli.Context) error {
|
||||||
|
if err := checkArgs(context, 0, exactArgs); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tru := true
|
||||||
|
|
||||||
|
feat := features.Features{
|
||||||
|
OCIVersionMin: "1.0.0",
|
||||||
|
OCIVersionMax: specs.Version,
|
||||||
|
Annotations: map[string]string{
|
||||||
|
features.AnnotationRuncVersion: version,
|
||||||
|
features.AnnotationRuncCommit: gitCommit,
|
||||||
|
features.AnnotationRuncCheckpointEnabled: "true",
|
||||||
|
},
|
||||||
|
Hooks: configs.KnownHookNames(),
|
||||||
|
MountOptions: specconv.KnownMountOptions(),
|
||||||
|
Linux: &features.Linux{
|
||||||
|
Namespaces: specconv.KnownNamespaces(),
|
||||||
|
Capabilities: capabilities.KnownCapabilities(),
|
||||||
|
Cgroup: &features.Cgroup{
|
||||||
|
V1: &tru,
|
||||||
|
V2: &tru,
|
||||||
|
Systemd: &tru,
|
||||||
|
SystemdUser: &tru,
|
||||||
|
},
|
||||||
|
Apparmor: &features.Apparmor{
|
||||||
|
Enabled: &tru,
|
||||||
|
},
|
||||||
|
Selinux: &features.Selinux{
|
||||||
|
Enabled: &tru,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if seccomp.Enabled {
|
||||||
|
feat.Linux.Seccomp = &features.Seccomp{
|
||||||
|
Enabled: &tru,
|
||||||
|
Actions: seccomp.KnownActions(),
|
||||||
|
Operators: seccomp.KnownOperators(),
|
||||||
|
Archs: seccomp.KnownArchs(),
|
||||||
|
}
|
||||||
|
major, minor, patch := seccomp.Version()
|
||||||
|
feat.Annotations[features.AnnotationLibseccompVersion] = fmt.Sprintf("%d.%d.%d", major, minor, patch)
|
||||||
|
}
|
||||||
|
|
||||||
|
enc := json.NewEncoder(context.App.Writer)
|
||||||
|
enc.SetIndent("", " ")
|
||||||
|
return enc.Encode(feat)
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -35,6 +35,17 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// KnownCapabilities returns the list of the known capabilities.
|
||||||
|
// Used by `runc features`.
|
||||||
|
func KnownCapabilities() []string {
|
||||||
|
list := capability.List()
|
||||||
|
res := make([]string, len(list))
|
||||||
|
for i, c := range list {
|
||||||
|
res[i] = "CAP_" + strings.ToUpper(c.String())
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
// New creates a new Caps from the given Capabilities config. Unknown Capabilities
|
// New creates a new Caps from the given Capabilities config. Unknown Capabilities
|
||||||
// or Capabilities that are unavailable in the current environment are ignored,
|
// or Capabilities that are unavailable in the current environment are ignored,
|
||||||
// printing a warning instead.
|
// printing a warning instead.
|
||||||
|
|||||||
@@ -251,6 +251,19 @@ const (
|
|||||||
Poststop HookName = "poststop"
|
Poststop HookName = "poststop"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// KnownHookNames returns the known hook names.
|
||||||
|
// Used by `runc features`.
|
||||||
|
func KnownHookNames() []string {
|
||||||
|
return []string{
|
||||||
|
string(Prestart), // deprecated
|
||||||
|
string(CreateRuntime),
|
||||||
|
string(CreateContainer),
|
||||||
|
string(StartContainer),
|
||||||
|
string(Poststart),
|
||||||
|
string(Poststop),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type Capabilities struct {
|
type Capabilities struct {
|
||||||
// Bounding is the set of capabilities checked by the kernel.
|
// Bounding is the set of capabilities checked by the kernel.
|
||||||
Bounding []string
|
Bounding []string
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package seccomp
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
|
||||||
"github.com/opencontainers/runc/libcontainer/configs"
|
"github.com/opencontainers/runc/libcontainer/configs"
|
||||||
)
|
)
|
||||||
@@ -16,6 +17,17 @@ var operators = map[string]configs.Operator{
|
|||||||
"SCMP_CMP_MASKED_EQ": configs.MaskEqualTo,
|
"SCMP_CMP_MASKED_EQ": configs.MaskEqualTo,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// KnownOperators returns the list of the known operations.
|
||||||
|
// Used by `runc features`.
|
||||||
|
func KnownOperators() []string {
|
||||||
|
var res []string
|
||||||
|
for k := range operators {
|
||||||
|
res = append(res, k)
|
||||||
|
}
|
||||||
|
sort.Strings(res)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
var actions = map[string]configs.Action{
|
var actions = map[string]configs.Action{
|
||||||
"SCMP_ACT_KILL": configs.Kill,
|
"SCMP_ACT_KILL": configs.Kill,
|
||||||
"SCMP_ACT_ERRNO": configs.Errno,
|
"SCMP_ACT_ERRNO": configs.Errno,
|
||||||
@@ -26,6 +38,17 @@ var actions = map[string]configs.Action{
|
|||||||
"SCMP_ACT_NOTIFY": configs.Notify,
|
"SCMP_ACT_NOTIFY": configs.Notify,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// KnownActions returns the list of the known actions.
|
||||||
|
// Used by `runc features`.
|
||||||
|
func KnownActions() []string {
|
||||||
|
var res []string
|
||||||
|
for k := range actions {
|
||||||
|
res = append(res, k)
|
||||||
|
}
|
||||||
|
sort.Strings(res)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
var archs = map[string]string{
|
var archs = map[string]string{
|
||||||
"SCMP_ARCH_X86": "x86",
|
"SCMP_ARCH_X86": "x86",
|
||||||
"SCMP_ARCH_X86_64": "amd64",
|
"SCMP_ARCH_X86_64": "amd64",
|
||||||
@@ -45,6 +68,17 @@ var archs = map[string]string{
|
|||||||
"SCMP_ARCH_S390X": "s390x",
|
"SCMP_ARCH_S390X": "s390x",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// KnownArchs returns the list of the known archs.
|
||||||
|
// Used by `runc features`.
|
||||||
|
func KnownArchs() []string {
|
||||||
|
var res []string
|
||||||
|
for k := range archs {
|
||||||
|
res = append(res, k)
|
||||||
|
}
|
||||||
|
sort.Strings(res)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
// ConvertStringToOperator converts a string into a Seccomp comparison operator.
|
// ConvertStringToOperator converts a string into a Seccomp comparison operator.
|
||||||
// Comparison operators use the names they are assigned by Libseccomp's header.
|
// Comparison operators use the names they are assigned by Libseccomp's header.
|
||||||
// Attempting to convert a string that is not a valid operator results in an
|
// Attempting to convert a string that is not a valid operator results in an
|
||||||
|
|||||||
@@ -265,3 +265,6 @@ func matchCall(filter *libseccomp.ScmpFilter, call *configs.Syscall, defAct libs
|
|||||||
func Version() (uint, uint, uint) {
|
func Version() (uint, uint, uint) {
|
||||||
return libseccomp.GetLibraryVersion()
|
return libseccomp.GetLibraryVersion()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enabled is true if seccomp support is compiled in.
|
||||||
|
const Enabled = true
|
||||||
|
|||||||
@@ -23,3 +23,6 @@ func InitSeccomp(config *configs.Seccomp) (int, error) {
|
|||||||
func Version() (uint, uint, uint) {
|
func Version() (uint, uint, uint) {
|
||||||
return 0, 0, 0
|
return 0, 0, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enabled is true if seccomp support is compiled in.
|
||||||
|
const Enabled = false
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@@ -105,6 +106,38 @@ func initMaps() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// KnownNamespaces returns the list of the known namespaces.
|
||||||
|
// Used by `runc features`.
|
||||||
|
func KnownNamespaces() []string {
|
||||||
|
initMaps()
|
||||||
|
var res []string
|
||||||
|
for k := range namespaceMapping {
|
||||||
|
res = append(res, string(k))
|
||||||
|
}
|
||||||
|
sort.Strings(res)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// KnownMountOptions returns the list of the known mount options.
|
||||||
|
// Used by `runc features`.
|
||||||
|
func KnownMountOptions() []string {
|
||||||
|
initMaps()
|
||||||
|
var res []string
|
||||||
|
for k := range mountFlags {
|
||||||
|
res = append(res, k)
|
||||||
|
}
|
||||||
|
for k := range mountPropagationMapping {
|
||||||
|
if k != "" {
|
||||||
|
res = append(res, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for k := range extensionFlags {
|
||||||
|
res = append(res, k)
|
||||||
|
}
|
||||||
|
sort.Strings(res)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
// AllowedDevices is the set of devices which are automatically included for
|
// AllowedDevices is the set of devices which are automatically included for
|
||||||
// all containers.
|
// all containers.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -132,6 +132,7 @@ func main() {
|
|||||||
startCommand,
|
startCommand,
|
||||||
stateCommand,
|
stateCommand,
|
||||||
updateCommand,
|
updateCommand,
|
||||||
|
featuresCommand,
|
||||||
}
|
}
|
||||||
app.Before = func(context *cli.Context) error {
|
app.Before = func(context *cli.Context) error {
|
||||||
if !context.IsSet("root") && xdgRuntimeDir != "" {
|
if !context.IsSet("root") && xdgRuntimeDir != "" {
|
||||||
|
|||||||
@@ -0,0 +1,129 @@
|
|||||||
|
// Package features provides the JSON structure that is printed by `runc features` (since runc v1.1.0).
|
||||||
|
package features
|
||||||
|
|
||||||
|
// Features represents the supported features of the runtime.
|
||||||
|
type Features struct {
|
||||||
|
// OCIVersionMin is the minimum OCI Runtime Spec version recognized by the runtime, e.g., "1.0.0".
|
||||||
|
OCIVersionMin string `json:"ociVersionMin,omitempty"`
|
||||||
|
|
||||||
|
// OCIVersionMax is the maximum OCI Runtime Spec version recognized by the runtime, e.g., "1.0.2-dev".
|
||||||
|
OCIVersionMax string `json:"ociVersionMax,omitempty"`
|
||||||
|
|
||||||
|
// Hooks is the list of the recognized hook names, e.g., "createRuntime".
|
||||||
|
// Nil value means "unknown", not "no support for any hook".
|
||||||
|
Hooks []string `json:"hooks,omitempty"`
|
||||||
|
|
||||||
|
// MountOptions is the list of the recognized mount options, e.g., "ro".
|
||||||
|
// Nil value means "unknown", not "no support for any mount option".
|
||||||
|
MountOptions []string `json:"mountOptions,omitempty"`
|
||||||
|
|
||||||
|
// Linux is specific to Linux.
|
||||||
|
Linux *Linux `json:"linux,omitempty"`
|
||||||
|
|
||||||
|
// Annotations contains implementation-specific annotation strings,
|
||||||
|
// such as the implementation version, and third-party extensions.
|
||||||
|
Annotations map[string]string `json:"annotations,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Linux is specific to Linux.
|
||||||
|
type Linux struct {
|
||||||
|
// Namespaces is the list of the recognized namespaces, e.g., "mount".
|
||||||
|
// Nil value means "unknown", not "no support for any namespace".
|
||||||
|
Namespaces []string `json:"namespaces,omitempty"`
|
||||||
|
|
||||||
|
// Capabilities is the list of the recognized capabilities , e.g., "CAP_SYS_ADMIN".
|
||||||
|
// Nil value means "unknown", not "no support for any capability".
|
||||||
|
Capabilities []string `json:"capabilities,omitempty"`
|
||||||
|
|
||||||
|
Cgroup *Cgroup `json:"cgroup,omitempty"`
|
||||||
|
Seccomp *Seccomp `json:"seccomp,omitempty"`
|
||||||
|
Apparmor *Apparmor `json:"apparmor,omitempty"`
|
||||||
|
Selinux *Selinux `json:"selinux,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Seccomp represents the "seccomp" field.
|
||||||
|
type Seccomp struct {
|
||||||
|
// Enabled is true if seccomp support is compiled in.
|
||||||
|
// Nil value means "unknown", not "false".
|
||||||
|
Enabled *bool `json:"enabled,omitempty"`
|
||||||
|
|
||||||
|
// Actions is the list of the recognized actions, e.g., "SCMP_ACT_NOTIFY".
|
||||||
|
// Nil value means "unknown", not "no support for any action".
|
||||||
|
Actions []string `json:"actions,omitempty"`
|
||||||
|
|
||||||
|
// Operators is the list of the recognized actions, e.g., "SCMP_CMP_NE".
|
||||||
|
// Nil value means "unknown", not "no support for any operator".
|
||||||
|
Operators []string `json:"operators,omitempty"`
|
||||||
|
|
||||||
|
// Operators is the list of the recognized archs, e.g., "SCMP_ARCH_X86_64".
|
||||||
|
// Nil value means "unknown", not "no support for any arch".
|
||||||
|
Archs []string `json:"archs,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apparmor represents the "apparmor" field.
|
||||||
|
type Apparmor struct {
|
||||||
|
// Enabled is true if AppArmor support is compiled in.
|
||||||
|
// Unrelated to whether the host supports AppArmor or not.
|
||||||
|
// Nil value means "unknown", not "false".
|
||||||
|
// Always true in the current version of runc.
|
||||||
|
Enabled *bool `json:"enabled,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Selinux represents the "selinux" field.
|
||||||
|
type Selinux struct {
|
||||||
|
// Enabled is true if SELinux support is compiled in.
|
||||||
|
// Unrelated to whether the host supports SELinux or not.
|
||||||
|
// Nil value means "unknown", not "false".
|
||||||
|
// Always true in the current version of runc.
|
||||||
|
Enabled *bool `json:"enabled,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cgroup represents the "cgroup" field.
|
||||||
|
type Cgroup struct {
|
||||||
|
// V1 represents whether Cgroup v1 support is compiled in.
|
||||||
|
// Unrelated to whether the host uses cgroup v1 or not.
|
||||||
|
// Nil value means "unknown", not "false".
|
||||||
|
// Always true in the current version of runc.
|
||||||
|
V1 *bool `json:"v1,omitempty"`
|
||||||
|
|
||||||
|
// V2 represents whether Cgroup v2 support is compiled in.
|
||||||
|
// Unrelated to whether the host uses cgroup v2 or not.
|
||||||
|
// Nil value means "unknown", not "false".
|
||||||
|
// Always true in the current version of runc.
|
||||||
|
V2 *bool `json:"v2,omitempty"`
|
||||||
|
|
||||||
|
// Systemd represents whether systemd-cgroup support is compiled in.
|
||||||
|
// Unrelated to whether the host uses systemd or not.
|
||||||
|
// Nil value means "unknown", not "false".
|
||||||
|
// Always true in the current version of runc.
|
||||||
|
Systemd *bool `json:"systemd,omitempty"`
|
||||||
|
|
||||||
|
// SystemdUser represents whether user-scoped systemd-cgroup support is compiled in.
|
||||||
|
// Unrelated to whether the host uses systemd or not.
|
||||||
|
// Nil value means "unknown", not "false".
|
||||||
|
// Always true in the current version of runc.
|
||||||
|
SystemdUser *bool `json:"systemdUser,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// AnnotationRuncVersion represents the version of runc, e.g., "1.2.3", "1.2.3+dev", "1.2.3-rc.4.", "1.2.3-rc.4+dev".
|
||||||
|
// Third party implementations such as crun and runsc MAY use this annotation to report the most compatible runc version,
|
||||||
|
// however, parsing this annotation value is discouraged.
|
||||||
|
AnnotationRuncVersion = "org.opencontainers.runc.version"
|
||||||
|
|
||||||
|
// AnnotationRuncCommit corresponds to the output of `git describe --dirty --long --always` in the runc repo.
|
||||||
|
// Third party implementations such as crun and runsc SHOULD NOT use this annotation, as their repo is different from the runc repo.
|
||||||
|
// Parsing this annotation value is discouraged.
|
||||||
|
AnnotationRuncCommit = "org.opencontainers.runc.commit"
|
||||||
|
|
||||||
|
// AnnotationRuncCheckpointEnabled is set to "true" if CRIU-based checkpointing is supported.
|
||||||
|
// Unrelated to whether the host supports CRIU or not.
|
||||||
|
// Always set to "true" in the current version of runc.
|
||||||
|
// This is defined as an annotation because checkpointing is a runc-specific feature that is not defined in the OCI Runtime Spec.
|
||||||
|
// Third party implementations such as crun and runsc MAY use this annotation.
|
||||||
|
AnnotationRuncCheckpointEnabled = "org.opencontainers.runc.checkpoint.enabled"
|
||||||
|
|
||||||
|
// AnnotationLibseccompVersion is the version of libseccomp, e.g., "2.5.1".
|
||||||
|
// Note that the runtime MAY support seccomp even when this annotation is not present.
|
||||||
|
AnnotationLibseccompVersion = "io.github.seccomp.libseccomp.version"
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user