Update runtime spec to 1.0.0.rc5

Signed-off-by: Mrunal Patel <mrunalp@gmail.com>
This commit is contained in:
Mrunal Patel
2017-03-14 09:36:38 -07:00
parent 31980a53ae
commit 4f9cb13b64
21 changed files with 436 additions and 217 deletions

View File

@@ -176,7 +176,13 @@ func getProcess(context *cli.Context, bundle string) (*specs.Process, error) {
p.SelinuxLabel = l p.SelinuxLabel = l
} }
if caps := context.StringSlice("cap"); len(caps) > 0 { if caps := context.StringSlice("cap"); len(caps) > 0 {
p.Capabilities = caps for _, c := range caps {
p.Capabilities.Bounding = append(p.Capabilities.Bounding, c)
p.Capabilities.Inheritable = append(p.Capabilities.Inheritable, c)
p.Capabilities.Effective = append(p.Capabilities.Effective, c)
p.Capabilities.Permitted = append(p.Capabilities.Permitted, c)
p.Capabilities.Ambient = append(p.Capabilities.Ambient, c)
}
} }
// append the passed env variables // append the passed env variables
p.Env = append(p.Env, context.StringSlice("env")...) p.Env = append(p.Env, context.StringSlice("env")...)

View File

@@ -7,6 +7,7 @@ import (
"os" "os"
"strings" "strings"
"github.com/opencontainers/runc/libcontainer/configs"
"github.com/syndtr/gocapability/capability" "github.com/syndtr/gocapability/capability"
) )
@@ -28,40 +29,84 @@ func init() {
} }
} }
func newCapWhitelist(caps []string) (*whitelist, error) { func newContainerCapList(capConfig *configs.Capabilities) (*containerCapabilities, error) {
l := []capability.Cap{} bounding := []capability.Cap{}
for _, c := range caps { for _, c := range capConfig.Bounding {
v, ok := capabilityMap[c] v, ok := capabilityMap[c]
if !ok { if !ok {
return nil, fmt.Errorf("unknown capability %q", c) return nil, fmt.Errorf("unknown capability %q", c)
} }
l = append(l, v) bounding = append(bounding, v)
}
effective := []capability.Cap{}
for _, c := range capConfig.Effective {
v, ok := capabilityMap[c]
if !ok {
return nil, fmt.Errorf("unknown capability %q", c)
}
effective = append(effective, v)
}
inheritable := []capability.Cap{}
for _, c := range capConfig.Inheritable {
v, ok := capabilityMap[c]
if !ok {
return nil, fmt.Errorf("unknown capability %q", c)
}
inheritable = append(inheritable, v)
}
permitted := []capability.Cap{}
for _, c := range capConfig.Permitted {
v, ok := capabilityMap[c]
if !ok {
return nil, fmt.Errorf("unknown capability %q", c)
}
permitted = append(permitted, v)
}
ambient := []capability.Cap{}
for _, c := range capConfig.Ambient {
v, ok := capabilityMap[c]
if !ok {
return nil, fmt.Errorf("unknown capability %q", c)
}
ambient = append(ambient, v)
} }
pid, err := capability.NewPid(os.Getpid()) pid, err := capability.NewPid(os.Getpid())
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &whitelist{ return &containerCapabilities{
keep: l, bounding: bounding,
effective: effective,
inheritable: inheritable,
permitted: permitted,
ambient: ambient,
pid: pid, pid: pid,
}, nil }, nil
} }
type whitelist struct { type containerCapabilities struct {
pid capability.Capabilities pid capability.Capabilities
keep []capability.Cap bounding []capability.Cap
effective []capability.Cap
inheritable []capability.Cap
permitted []capability.Cap
ambient []capability.Cap
} }
// dropBoundingSet drops the capability bounding set to those specified in the whitelist. // ApplyBoundingSet sets the capability bounding set to those specified in the whitelist.
func (w *whitelist) dropBoundingSet() error { func (c *containerCapabilities) ApplyBoundingSet() error {
w.pid.Clear(capability.BOUNDS) c.pid.Clear(capability.BOUNDS)
w.pid.Set(capability.BOUNDS, w.keep...) c.pid.Set(capability.BOUNDS, c.bounding...)
return w.pid.Apply(capability.BOUNDS) return c.pid.Apply(capability.BOUNDS)
} }
// drop drops all capabilities for the current process except those specified in the whitelist. // Apply sets all the capabilities for the current process in the config.
func (w *whitelist) drop() error { func (c *containerCapabilities) ApplyCaps() error {
w.pid.Clear(allCapabilityTypes) c.pid.Clear(allCapabilityTypes)
w.pid.Set(allCapabilityTypes, w.keep...) c.pid.Set(capability.BOUNDS, c.bounding...)
return w.pid.Apply(allCapabilityTypes) c.pid.Set(capability.PERMITTED, c.permitted...)
c.pid.Set(capability.INHERITABLE, c.inheritable...)
c.pid.Set(capability.EFFECTIVE, c.effective...)
c.pid.Set(capability.AMBIENT, c.ambient...)
return c.pid.Apply(allCapabilityTypes)
} }

View File

@@ -113,8 +113,8 @@ type Config struct {
Namespaces Namespaces `json:"namespaces"` Namespaces Namespaces `json:"namespaces"`
// Capabilities specify the capabilities to keep when executing the process inside the container // Capabilities specify the capabilities to keep when executing the process inside the container
// All capbilities not specified will be dropped from the processes capability mask // All capabilities not specified will be dropped from the processes capability mask
Capabilities []string `json:"capabilities"` Capabilities *Capabilities `json:"capabilities"`
// Networks specifies the container's network setup to be created // Networks specifies the container's network setup to be created
Networks []*Network `json:"networks"` Networks []*Network `json:"networks"`
@@ -197,6 +197,19 @@ type Hooks struct {
Poststop []Hook Poststop []Hook
} }
type Capabilities struct {
// Bounding is the set of capabilities checked by the kernel.
Bounding []string
// Effective is the set of capabilities checked by the kernel.
Effective []string
// Inheritable is the capabilities preserved across execve.
Inheritable []string
// Permitted is the limiting superset for effective capabilities.
Permitted []string
// Ambient is the ambient set of capabilities that are kept.
Ambient []string
}
func (hooks *Hooks) UnmarshalJSON(b []byte) error { func (hooks *Hooks) UnmarshalJSON(b []byte) error {
var state struct { var state struct {
Prestart []CommandHook Prestart []CommandHook

View File

@@ -123,7 +123,7 @@ func TestFuncHookRun(t *testing.T) {
Version: "1", Version: "1",
ID: "1", ID: "1",
Pid: 1, Pid: 1,
BundlePath: "/bundle", Bundle: "/bundle",
} }
fHook := configs.NewFunctionHook(func(s configs.HookState) error { fHook := configs.NewFunctionHook(func(s configs.HookState) error {
@@ -141,7 +141,7 @@ func TestCommandHookRun(t *testing.T) {
Version: "1", Version: "1",
ID: "1", ID: "1",
Pid: 1, Pid: 1,
BundlePath: "/bundle", Bundle: "/bundle",
} }
timeout := time.Second timeout := time.Second
@@ -164,7 +164,7 @@ func TestCommandHookRunTimeout(t *testing.T) {
Version: "1", Version: "1",
ID: "1", ID: "1",
Pid: 1, Pid: 1,
BundlePath: "/bundle", Bundle: "/bundle",
} }
timeout := (10 * time.Millisecond) timeout := (10 * time.Millisecond)

View File

@@ -278,7 +278,7 @@ func (c *linuxContainer) start(process *Process, isInit bool) error {
Version: c.config.Version, Version: c.config.Version,
ID: c.id, ID: c.id,
Pid: parent.pid(), Pid: parent.pid(),
BundlePath: utils.SearchLabels(c.config.Labels, "bundle"), Bundle: utils.SearchLabels(c.config.Labels, "bundle"),
} }
for i, hook := range c.config.Hooks.Poststart { for i, hook := range c.config.Hooks.Poststart {
if err := hook.Run(s); err != nil { if err := hook.Run(s); err != nil {
@@ -1160,7 +1160,7 @@ func (c *linuxContainer) criuNotifications(resp *criurpc.CriuResp, process *Proc
Version: c.config.Version, Version: c.config.Version,
ID: c.id, ID: c.id,
Pid: int(notify.GetPid()), Pid: int(notify.GetPid()),
BundlePath: utils.SearchLabels(c.config.Labels, "bundle"), Bundle: utils.SearchLabels(c.config.Labels, "bundle"),
} }
for i, hook := range c.config.Hooks.Prestart { for i, hook := range c.config.Hooks.Prestart {
if err := hook.Run(s); err != nil { if err := hook.Run(s); err != nil {

View File

@@ -48,7 +48,7 @@ type initConfig struct {
Args []string `json:"args"` Args []string `json:"args"`
Env []string `json:"env"` Env []string `json:"env"`
Cwd string `json:"cwd"` Cwd string `json:"cwd"`
Capabilities []string `json:"capabilities"` Capabilities *configs.Capabilities `json:"capabilities"`
ProcessLabel string `json:"process_label"` ProcessLabel string `json:"process_label"`
AppArmorProfile string `json:"apparmor_profile"` AppArmorProfile string `json:"apparmor_profile"`
NoNewPrivileges bool `json:"no_new_privileges"` NoNewPrivileges bool `json:"no_new_privileges"`
@@ -121,12 +121,12 @@ func finalizeNamespace(config *initConfig) error {
if config.Capabilities != nil { if config.Capabilities != nil {
capabilities = config.Capabilities capabilities = config.Capabilities
} }
w, err := newCapWhitelist(capabilities) w, err := newContainerCapList(capabilities)
if err != nil { if err != nil {
return err return err
} }
// drop capabilities in bounding set before changing user // drop capabilities in bounding set before changing user
if err := w.dropBoundingSet(); err != nil { if err := w.ApplyBoundingSet(); err != nil {
return err return err
} }
// preserve existing capabilities while we change users // preserve existing capabilities while we change users
@@ -139,8 +139,7 @@ func finalizeNamespace(config *initConfig) error {
if err := system.ClearKeepCaps(); err != nil { if err := system.ClearKeepCaps(); err != nil {
return err return err
} }
// drop all other capabilities if err := w.ApplyCaps(); err != nil {
if err := w.drop(); err != nil {
return err return err
} }
if config.Cwd != "" { if config.Cwd != "" {

View File

@@ -357,17 +357,19 @@ func TestProcessCaps(t *testing.T) {
ok(t, err) ok(t, err)
defer container.Destroy() defer container.Destroy()
processCaps := append(config.Capabilities, "CAP_NET_ADMIN")
var stdout bytes.Buffer var stdout bytes.Buffer
pconfig := libcontainer.Process{ pconfig := libcontainer.Process{
Cwd: "/", Cwd: "/",
Args: []string{"sh", "-c", "cat /proc/self/status"}, Args: []string{"sh", "-c", "cat /proc/self/status"},
Env: standardEnvironment, Env: standardEnvironment,
Capabilities: processCaps,
Stdin: nil, Stdin: nil,
Stdout: &stdout, Stdout: &stdout,
Capabilities: &configs.Capabilities{},
} }
pconfig.Capabilities.Bounding = append(config.Capabilities.Bounding, "CAP_NET_ADMIN")
pconfig.Capabilities.Permitted = append(config.Capabilities.Permitted, "CAP_NET_ADMIN")
pconfig.Capabilities.Effective = append(config.Capabilities.Effective, "CAP_NET_ADMIN")
pconfig.Capabilities.Inheritable = append(config.Capabilities.Inheritable, "CAP_NET_ADMIN")
err = container.Run(&pconfig) err = container.Run(&pconfig)
ok(t, err) ok(t, err)
@@ -1059,8 +1061,8 @@ func TestHook(t *testing.T) {
defer remove(rootfs) defer remove(rootfs)
config := newTemplateConfig(rootfs) config := newTemplateConfig(rootfs)
expectedBundlePath := bundle expectedBundle := bundle
config.Labels = append(config.Labels, fmt.Sprintf("bundle=%s", expectedBundlePath)) config.Labels = append(config.Labels, fmt.Sprintf("bundle=%s", expectedBundle))
getRootfsFromBundle := func(bundle string) (string, error) { getRootfsFromBundle := func(bundle string) (string, error) {
f, err := os.Open(filepath.Join(bundle, "config.json")) f, err := os.Open(filepath.Join(bundle, "config.json"))
@@ -1078,11 +1080,11 @@ func TestHook(t *testing.T) {
config.Hooks = &configs.Hooks{ config.Hooks = &configs.Hooks{
Prestart: []configs.Hook{ Prestart: []configs.Hook{
configs.NewFunctionHook(func(s configs.HookState) error { configs.NewFunctionHook(func(s configs.HookState) error {
if s.BundlePath != expectedBundlePath { if s.Bundle != expectedBundle {
t.Fatalf("Expected prestart hook bundlePath '%s'; got '%s'", expectedBundlePath, s.BundlePath) t.Fatalf("Expected prestart hook bundlePath '%s'; got '%s'", expectedBundle, s.Bundle)
} }
root, err := getRootfsFromBundle(s.BundlePath) root, err := getRootfsFromBundle(s.Bundle)
if err != nil { if err != nil {
return err return err
} }
@@ -1095,11 +1097,11 @@ func TestHook(t *testing.T) {
}, },
Poststart: []configs.Hook{ Poststart: []configs.Hook{
configs.NewFunctionHook(func(s configs.HookState) error { configs.NewFunctionHook(func(s configs.HookState) error {
if s.BundlePath != expectedBundlePath { if s.Bundle != expectedBundle {
t.Fatalf("Expected poststart hook bundlePath '%s'; got '%s'", expectedBundlePath, s.BundlePath) t.Fatalf("Expected poststart hook bundlePath '%s'; got '%s'", expectedBundle, s.Bundle)
} }
root, err := getRootfsFromBundle(s.BundlePath) root, err := getRootfsFromBundle(s.Bundle)
if err != nil { if err != nil {
return err return err
} }
@@ -1108,11 +1110,11 @@ func TestHook(t *testing.T) {
}, },
Poststop: []configs.Hook{ Poststop: []configs.Hook{
configs.NewFunctionHook(func(s configs.HookState) error { configs.NewFunctionHook(func(s configs.HookState) error {
if s.BundlePath != expectedBundlePath { if s.Bundle != expectedBundle {
t.Fatalf("Expected poststop hook bundlePath '%s'; got '%s'", expectedBundlePath, s.BundlePath) t.Fatalf("Expected poststop hook bundlePath '%s'; got '%s'", expectedBundle, s.Bundle)
} }
root, err := getRootfsFromBundle(s.BundlePath) root, err := getRootfsFromBundle(s.Bundle)
if err != nil { if err != nil {
return err return err
} }
@@ -1391,18 +1393,21 @@ func TestRootfsPropagationSharedMount(t *testing.T) {
stdinR2, stdinW2, err := os.Pipe() stdinR2, stdinW2, err := os.Pipe()
ok(t, err) ok(t, err)
// Provide CAP_SYS_ADMIN
processCaps := append(config.Capabilities, "CAP_SYS_ADMIN")
pconfig2 := &libcontainer.Process{ pconfig2 := &libcontainer.Process{
Cwd: "/", Cwd: "/",
Args: []string{"mount", "--bind", dir2cont, dir2cont}, Args: []string{"mount", "--bind", dir2cont, dir2cont},
Env: standardEnvironment, Env: standardEnvironment,
Stdin: stdinR2, Stdin: stdinR2,
Stdout: &stdout2, Stdout: &stdout2,
Capabilities: processCaps, Capabilities: &configs.Capabilities{},
} }
// Provide CAP_SYS_ADMIN
pconfig2.Capabilities.Bounding = append(config.Capabilities.Bounding, "CAP_SYS_ADMIN")
pconfig2.Capabilities.Permitted = append(config.Capabilities.Permitted, "CAP_SYS_ADMIN")
pconfig2.Capabilities.Effective = append(config.Capabilities.Effective, "CAP_SYS_ADMIN")
pconfig2.Capabilities.Inheritable = append(config.Capabilities.Inheritable, "CAP_SYS_ADMIN")
err = container.Run(pconfig2) err = container.Run(pconfig2)
stdinR2.Close() stdinR2.Close()
defer stdinW2.Close() defer stdinW2.Close()

View File

@@ -23,7 +23,8 @@ func newTemplateConfig(rootfs string) *configs.Config {
allowAllDevices := false allowAllDevices := false
return &configs.Config{ return &configs.Config{
Rootfs: rootfs, Rootfs: rootfs,
Capabilities: []string{ Capabilities: &configs.Capabilities{
Bounding: []string{
"CAP_CHOWN", "CAP_CHOWN",
"CAP_DAC_OVERRIDE", "CAP_DAC_OVERRIDE",
"CAP_FSETID", "CAP_FSETID",
@@ -39,6 +40,71 @@ func newTemplateConfig(rootfs string) *configs.Config {
"CAP_KILL", "CAP_KILL",
"CAP_AUDIT_WRITE", "CAP_AUDIT_WRITE",
}, },
Permitted: []string{
"CAP_CHOWN",
"CAP_DAC_OVERRIDE",
"CAP_FSETID",
"CAP_FOWNER",
"CAP_MKNOD",
"CAP_NET_RAW",
"CAP_SETGID",
"CAP_SETUID",
"CAP_SETFCAP",
"CAP_SETPCAP",
"CAP_NET_BIND_SERVICE",
"CAP_SYS_CHROOT",
"CAP_KILL",
"CAP_AUDIT_WRITE",
},
Inheritable: []string{
"CAP_CHOWN",
"CAP_DAC_OVERRIDE",
"CAP_FSETID",
"CAP_FOWNER",
"CAP_MKNOD",
"CAP_NET_RAW",
"CAP_SETGID",
"CAP_SETUID",
"CAP_SETFCAP",
"CAP_SETPCAP",
"CAP_NET_BIND_SERVICE",
"CAP_SYS_CHROOT",
"CAP_KILL",
"CAP_AUDIT_WRITE",
},
Ambient: []string{
"CAP_CHOWN",
"CAP_DAC_OVERRIDE",
"CAP_FSETID",
"CAP_FOWNER",
"CAP_MKNOD",
"CAP_NET_RAW",
"CAP_SETGID",
"CAP_SETUID",
"CAP_SETFCAP",
"CAP_SETPCAP",
"CAP_NET_BIND_SERVICE",
"CAP_SYS_CHROOT",
"CAP_KILL",
"CAP_AUDIT_WRITE",
},
Effective: []string{
"CAP_CHOWN",
"CAP_DAC_OVERRIDE",
"CAP_FSETID",
"CAP_FOWNER",
"CAP_MKNOD",
"CAP_NET_RAW",
"CAP_SETGID",
"CAP_SETUID",
"CAP_SETFCAP",
"CAP_SETPCAP",
"CAP_NET_BIND_SERVICE",
"CAP_SYS_CHROOT",
"CAP_KILL",
"CAP_AUDIT_WRITE",
},
},
Namespaces: configs.Namespaces([]configs.Namespace{ Namespaces: configs.Namespaces([]configs.Namespace{
{Type: configs.NEWNS}, {Type: configs.NEWNS},
{Type: configs.NEWUTS}, {Type: configs.NEWUTS},

View File

@@ -53,7 +53,7 @@ type Process struct {
// Capabilities specify the capabilities to keep when executing the process inside the container // Capabilities specify the capabilities to keep when executing the process inside the container
// All capabilities not specified will be dropped from the processes capability mask // All capabilities not specified will be dropped from the processes capability mask
Capabilities []string Capabilities *configs.Capabilities
// AppArmorProfile specifies the profile to apply to the process and is // AppArmorProfile specifies the profile to apply to the process and is
// changed at the time the process is execed // changed at the time the process is execed

View File

@@ -340,7 +340,7 @@ func (p *initProcess) start() error {
Version: p.container.config.Version, Version: p.container.config.Version,
ID: p.container.id, ID: p.container.id,
Pid: p.pid(), Pid: p.pid(),
BundlePath: utils.SearchLabels(p.config.Config.Labels, "bundle"), Bundle: utils.SearchLabels(p.config.Config.Labels, "bundle"),
} }
for i, hook := range p.config.Config.Hooks.Prestart { for i, hook := range p.config.Config.Hooks.Prestart {
if err := hook.Run(s); err != nil { if err := hook.Run(s); err != nil {
@@ -360,7 +360,7 @@ func (p *initProcess) start() error {
Version: p.container.config.Version, Version: p.container.config.Version,
ID: p.container.id, ID: p.container.id,
Pid: p.pid(), Pid: p.pid(),
BundlePath: utils.SearchLabels(p.config.Config.Labels, "bundle"), Bundle: utils.SearchLabels(p.config.Config.Labels, "bundle"),
} }
for i, hook := range p.config.Config.Hooks.Prestart { for i, hook := range p.config.Config.Hooks.Prestart {
if err := hook.Run(s); err != nil { if err := hook.Run(s); err != nil {

View File

@@ -230,6 +230,15 @@ func CreateLibcontainerConfig(opts *CreateOpts) (*configs.Config, error) {
if spec.Linux.Resources != nil && spec.Linux.Resources.OOMScoreAdj != nil { if spec.Linux.Resources != nil && spec.Linux.Resources.OOMScoreAdj != nil {
config.OomScoreAdj = *spec.Linux.Resources.OOMScoreAdj config.OomScoreAdj = *spec.Linux.Resources.OOMScoreAdj
} }
if spec.Process.Capabilities != nil {
config.Capabilities = &configs.Capabilities{
Bounding: spec.Process.Capabilities.Bounding,
Effective: spec.Process.Capabilities.Effective,
Permitted: spec.Process.Capabilities.Permitted,
Inheritable: spec.Process.Capabilities.Inheritable,
Ambient: spec.Process.Capabilities.Ambient,
}
}
createHooks(spec, config) createHooks(spec, config)
config.MountLabel = spec.Linux.MountLabel config.MountLabel = spec.Linux.MountLabel
config.Version = specs.Version config.Version = specs.Version
@@ -262,10 +271,10 @@ func createCgroupConfig(name string, useSystemdCgroup bool, spec *specs.Spec) (*
Resources: &configs.Resources{}, Resources: &configs.Resources{},
} }
if spec.Linux != nil && spec.Linux.CgroupsPath != nil { if spec.Linux != nil && spec.Linux.CgroupsPath != "" {
myCgroupPath = libcontainerUtils.CleanPath(*spec.Linux.CgroupsPath) myCgroupPath = libcontainerUtils.CleanPath(spec.Linux.CgroupsPath)
if useSystemdCgroup { if useSystemdCgroup {
myCgroupPath = *spec.Linux.CgroupsPath myCgroupPath = spec.Linux.CgroupsPath
} }
} }
@@ -306,8 +315,8 @@ func createCgroupConfig(name string, useSystemdCgroup bool, spec *specs.Spec) (*
major = int64(-1) major = int64(-1)
minor = int64(-1) minor = int64(-1)
) )
if d.Type != nil { if d.Type != "" {
t = *d.Type t = d.Type
} }
if d.Major != nil { if d.Major != nil {
major = *d.Major major = *d.Major
@@ -315,7 +324,7 @@ func createCgroupConfig(name string, useSystemdCgroup bool, spec *specs.Spec) (*
if d.Minor != nil { if d.Minor != nil {
minor = *d.Minor minor = *d.Minor
} }
if d.Access == nil || *d.Access == "" { if d.Access == "" {
return nil, fmt.Errorf("device access at %d field cannot be empty", i) return nil, fmt.Errorf("device access at %d field cannot be empty", i)
} }
dt, err := stringToCgroupDeviceRune(t) dt, err := stringToCgroupDeviceRune(t)
@@ -326,7 +335,7 @@ func createCgroupConfig(name string, useSystemdCgroup bool, spec *specs.Spec) (*
Type: dt, Type: dt,
Major: major, Major: major,
Minor: minor, Minor: minor,
Permissions: *d.Access, Permissions: d.Access,
Allow: d.Allow, Allow: d.Allow,
} }
c.Resources.Devices = append(c.Resources.Devices, dd) c.Resources.Devices = append(c.Resources.Devices, dd)
@@ -370,11 +379,11 @@ func createCgroupConfig(name string, useSystemdCgroup bool, spec *specs.Spec) (*
if r.CPU.RealtimePeriod != nil { if r.CPU.RealtimePeriod != nil {
c.Resources.CpuRtPeriod = int64(*r.CPU.RealtimePeriod) c.Resources.CpuRtPeriod = int64(*r.CPU.RealtimePeriod)
} }
if r.CPU.Cpus != nil { if r.CPU.Cpus != "" {
c.Resources.CpusetCpus = *r.CPU.Cpus c.Resources.CpusetCpus = r.CPU.Cpus
} }
if r.CPU.Mems != nil { if r.CPU.Mems != "" {
c.Resources.CpusetMems = *r.CPU.Mems c.Resources.CpusetMems = r.CPU.Mems
} }
} }
if r.Pids != nil { if r.Pids != nil {
@@ -720,12 +729,12 @@ func setupSeccomp(config *specs.LinuxSeccomp) (*configs.Seccomp, error) {
return nil, err return nil, err
} }
for _, name := range call.Names {
newCall := configs.Syscall{ newCall := configs.Syscall{
Name: call.Name, Name: name,
Action: newAction, Action: newAction,
Args: []*configs.Arg{}, Args: []*configs.Arg{},
} }
// Loop through all the arguments of the syscall and convert them // Loop through all the arguments of the syscall and convert them
for _, arg := range call.Args { for _, arg := range call.Args {
newOp, err := seccomp.ConvertStringToOperator(string(arg.Op)) newOp, err := seccomp.ConvertStringToOperator(string(arg.Op))
@@ -742,15 +751,17 @@ func setupSeccomp(config *specs.LinuxSeccomp) (*configs.Seccomp, error) {
newCall.Args = append(newCall.Args, &newArg) newCall.Args = append(newCall.Args, &newArg)
} }
newConfig.Syscalls = append(newConfig.Syscalls, &newCall) newConfig.Syscalls = append(newConfig.Syscalls, &newCall)
} }
}
return newConfig, nil return newConfig, nil
} }
func createHooks(rspec *specs.Spec, config *configs.Config) { func createHooks(rspec *specs.Spec, config *configs.Config) {
config.Hooks = &configs.Hooks{} config.Hooks = &configs.Hooks{}
if rspec.Hooks != nil {
for _, h := range rspec.Hooks.Prestart { for _, h := range rspec.Hooks.Prestart {
cmd := createCommandHook(h) cmd := createCommandHook(h)
config.Hooks.Prestart = append(config.Hooks.Prestart, configs.NewCommandHook(cmd)) config.Hooks.Prestart = append(config.Hooks.Prestart, configs.NewCommandHook(cmd))
@@ -763,6 +774,7 @@ func createHooks(rspec *specs.Spec, config *configs.Config) {
cmd := createCommandHook(h) cmd := createCommandHook(h)
config.Hooks.Poststop = append(config.Hooks.Poststop, configs.NewCommandHook(cmd)) config.Hooks.Poststop = append(config.Hooks.Poststop, configs.NewCommandHook(cmd))
} }
}
} }
func createCommandHook(h specs.Hook) configs.Command { func createCommandHook(h specs.Hook) configs.Command {

View File

@@ -13,7 +13,7 @@ func TestLinuxCgroupsPathSpecified(t *testing.T) {
spec := &specs.Spec{} spec := &specs.Spec{}
spec.Linux = &specs.Linux{ spec.Linux = &specs.Linux{
CgroupsPath: &cgroupsPath, CgroupsPath: cgroupsPath,
} }
cgroup, err := createCgroupConfig("ContainerID", false, spec) cgroup, err := createCgroupConfig("ContainerID", false, spec)

View File

@@ -60,7 +60,7 @@ func runPoststopHooks(c *linuxContainer) error {
s := configs.HookState{ s := configs.HookState{
Version: c.config.Version, Version: c.config.Version,
ID: c.id, ID: c.id,
BundlePath: utils.SearchLabels(c.config.Labels, "bundle"), Bundle: utils.SearchLabels(c.config.Labels, "bundle"),
} }
for _, hook := range c.config.Hooks.Poststop { for _, hook := range c.config.Hooks.Poststop {
if err := hook.Run(s); err != nil { if err := hook.Run(s); err != nil {

26
spec.go
View File

@@ -90,11 +90,33 @@ container on your host.`,
}, },
Cwd: "/", Cwd: "/",
NoNewPrivileges: true, NoNewPrivileges: true,
Capabilities: []string{ Capabilities: &specs.LinuxCapabilities{
Bounding: []string{
"CAP_AUDIT_WRITE", "CAP_AUDIT_WRITE",
"CAP_KILL", "CAP_KILL",
"CAP_NET_BIND_SERVICE", "CAP_NET_BIND_SERVICE",
}, },
Permitted: []string{
"CAP_AUDIT_WRITE",
"CAP_KILL",
"CAP_NET_BIND_SERVICE",
},
Inheritable: []string{
"CAP_AUDIT_WRITE",
"CAP_KILL",
"CAP_NET_BIND_SERVICE",
},
Ambient: []string{
"CAP_AUDIT_WRITE",
"CAP_KILL",
"CAP_NET_BIND_SERVICE",
},
Effective: []string{
"CAP_AUDIT_WRITE",
"CAP_KILL",
"CAP_NET_BIND_SERVICE",
},
},
Rlimits: []specs.LinuxRlimit{ Rlimits: []specs.LinuxRlimit{
{ {
Type: "RLIMIT_NOFILE", Type: "RLIMIT_NOFILE",
@@ -169,7 +191,7 @@ container on your host.`,
Devices: []specs.LinuxDeviceCgroup{ Devices: []specs.LinuxDeviceCgroup{
{ {
Allow: false, Allow: false,
Access: sPtr("rwm"), Access: "rwm",
}, },
}, },
}, },

View File

@@ -13,6 +13,7 @@ import (
"github.com/urfave/cli" "github.com/urfave/cli"
) )
func i64Ptr(i int64) *int64 { return &i }
func u64Ptr(i uint64) *uint64 { return &i } func u64Ptr(i uint64) *uint64 { return &i }
func u16Ptr(i uint16) *uint16 { return &i } func u16Ptr(i uint16) *uint16 { return &i }
@@ -127,12 +128,12 @@ other options are ignored.
}, },
CPU: &specs.LinuxCPU{ CPU: &specs.LinuxCPU{
Shares: u64Ptr(0), Shares: u64Ptr(0),
Quota: u64Ptr(0), Quota: i64Ptr(0),
Period: u64Ptr(0), Period: u64Ptr(0),
RealtimeRuntime: u64Ptr(0), RealtimeRuntime: i64Ptr(0),
RealtimePeriod: u64Ptr(0), RealtimePeriod: u64Ptr(0),
Cpus: sPtr(""), Cpus: "",
Mems: sPtr(""), Mems: "",
}, },
BlockIO: &specs.LinuxBlockIO{ BlockIO: &specs.LinuxBlockIO{
Weight: u16Ptr(0), Weight: u16Ptr(0),
@@ -164,10 +165,10 @@ other options are ignored.
r.BlockIO.Weight = u16Ptr(uint16(val)) r.BlockIO.Weight = u16Ptr(uint16(val))
} }
if val := context.String("cpuset-cpus"); val != "" { if val := context.String("cpuset-cpus"); val != "" {
r.CPU.Cpus = &val r.CPU.Cpus = val
} }
if val := context.String("cpuset-mems"); val != "" { if val := context.String("cpuset-mems"); val != "" {
r.CPU.Mems = &val r.CPU.Mems = val
} }
for _, pair := range []struct { for _, pair := range []struct {
@@ -176,9 +177,7 @@ other options are ignored.
}{ }{
{"cpu-period", r.CPU.Period}, {"cpu-period", r.CPU.Period},
{"cpu-quota", r.CPU.Quota},
{"cpu-rt-period", r.CPU.RealtimePeriod}, {"cpu-rt-period", r.CPU.RealtimePeriod},
{"cpu-rt-runtime", r.CPU.RealtimeRuntime},
{"cpu-share", r.CPU.Shares}, {"cpu-share", r.CPU.Shares},
} { } {
if val := context.String(pair.opt); val != "" { if val := context.String(pair.opt); val != "" {
@@ -189,6 +188,22 @@ other options are ignored.
} }
} }
} }
for _, pair := range []struct {
opt string
dest *int64
}{
{"cpu-quota", r.CPU.Quota},
{"cpu-rt-runtime", r.CPU.RealtimeRuntime},
} {
if val := context.String(pair.opt); val != "" {
var err error
*pair.dest, err = strconv.ParseInt(val, 10, 64)
if err != nil {
return fmt.Errorf("invalid value for %s: %s", pair.opt, err)
}
}
}
for _, pair := range []struct { for _, pair := range []struct {
opt string opt string
dest *uint64 dest *uint64
@@ -222,8 +237,8 @@ other options are ignored.
config.Cgroups.Resources.CpuShares = int64(*r.CPU.Shares) config.Cgroups.Resources.CpuShares = int64(*r.CPU.Shares)
config.Cgroups.Resources.CpuRtPeriod = int64(*r.CPU.RealtimePeriod) config.Cgroups.Resources.CpuRtPeriod = int64(*r.CPU.RealtimePeriod)
config.Cgroups.Resources.CpuRtRuntime = int64(*r.CPU.RealtimeRuntime) config.Cgroups.Resources.CpuRtRuntime = int64(*r.CPU.RealtimeRuntime)
config.Cgroups.Resources.CpusetCpus = *r.CPU.Cpus config.Cgroups.Resources.CpusetCpus = r.CPU.Cpus
config.Cgroups.Resources.CpusetMems = *r.CPU.Mems config.Cgroups.Resources.CpusetMems = r.CPU.Mems
config.Cgroups.Resources.KernelMemory = int64(*r.Memory.Kernel) config.Cgroups.Resources.KernelMemory = int64(*r.Memory.Kernel)
config.Cgroups.Resources.KernelMemoryTCP = int64(*r.Memory.KernelTCP) config.Cgroups.Resources.KernelMemoryTCP = int64(*r.Memory.KernelTCP)
config.Cgroups.Resources.Memory = int64(*r.Memory.Limit) config.Cgroups.Resources.Memory = int64(*r.Memory.Limit)

View File

@@ -15,6 +15,7 @@ import (
"github.com/coreos/go-systemd/activation" "github.com/coreos/go-systemd/activation"
"github.com/opencontainers/runc/libcontainer" "github.com/opencontainers/runc/libcontainer"
"github.com/opencontainers/runc/libcontainer/cgroups/systemd" "github.com/opencontainers/runc/libcontainer/cgroups/systemd"
"github.com/opencontainers/runc/libcontainer/configs"
"github.com/opencontainers/runc/libcontainer/specconv" "github.com/opencontainers/runc/libcontainer/specconv"
"github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/runtime-spec/specs-go"
"github.com/urfave/cli" "github.com/urfave/cli"
@@ -77,11 +78,18 @@ func newProcess(p specs.Process) (*libcontainer.Process, error) {
// TODO: fix libcontainer's API to better support uid/gid in a typesafe way. // TODO: fix libcontainer's API to better support uid/gid in a typesafe way.
User: fmt.Sprintf("%d:%d", p.User.UID, p.User.GID), User: fmt.Sprintf("%d:%d", p.User.UID, p.User.GID),
Cwd: p.Cwd, Cwd: p.Cwd,
Capabilities: p.Capabilities,
Label: p.SelinuxLabel, Label: p.SelinuxLabel,
NoNewPrivileges: &p.NoNewPrivileges, NoNewPrivileges: &p.NoNewPrivileges,
AppArmorProfile: p.ApparmorProfile, AppArmorProfile: p.ApparmorProfile,
} }
if p.Capabilities != nil {
lp.Capabilities = &configs.Capabilities{}
lp.Capabilities.Bounding = p.Capabilities.Bounding
lp.Capabilities.Effective = p.Capabilities.Effective
lp.Capabilities.Inheritable = p.Capabilities.Inheritable
lp.Capabilities.Permitted = p.Capabilities.Permitted
lp.Capabilities.Ambient = p.Capabilities.Ambient
}
for _, gid := range p.User.AdditionalGids { for _, gid := range p.User.AdditionalGids {
lp.AdditionalGroups = append(lp.AdditionalGroups, strconv.FormatUint(uint64(gid), 10)) lp.AdditionalGroups = append(lp.AdditionalGroups, strconv.FormatUint(uint64(gid), 10))
} }

View File

@@ -6,7 +6,7 @@ github.com/docker/go-units 9b001659dd36225e356b4467c465d732e745f53d
github.com/godbus/dbus c7fdd8b5cd55e87b4e1f4e372cdb1db61dd6c66f github.com/godbus/dbus c7fdd8b5cd55e87b4e1f4e372cdb1db61dd6c66f
github.com/golang/protobuf/proto f7137ae6b19afbfd61a94b746fda3b3fe0491874 github.com/golang/protobuf/proto f7137ae6b19afbfd61a94b746fda3b3fe0491874
github.com/mrunalp/fileutils ed869b029674c0e9ce4c0dfa781405c2d9946d08 github.com/mrunalp/fileutils ed869b029674c0e9ce4c0dfa781405c2d9946d08
github.com/opencontainers/runtime-spec/specs-go 794ca7ac88234607f9d2c76da8a6e9bbbade8cb9 github.com/opencontainers/runtime-spec/specs-go 035da1dca3dfbb00d752eb58b0b158d6129f3776
github.com/seccomp/libseccomp-golang 32f571b70023028bd57d9288c20efbcb237f3ce0 github.com/seccomp/libseccomp-golang 32f571b70023028bd57d9288c20efbcb237f3ce0
github.com/syndtr/gocapability/capability e7cb7fa329f456b3855136a2642b197bad7366ba github.com/syndtr/gocapability/capability e7cb7fa329f456b3855136a2642b197bad7366ba
github.com/urfave/cli d53eb991652b1d438abdd34ce4bfa3ef1539108e github.com/urfave/cli d53eb991652b1d438abdd34ce4bfa3ef1539108e

View File

@@ -1,12 +1,14 @@
# Open Container Initiative Runtime Specification # Open Container Initiative Runtime Specification
The [Open Container Initiative](http://www.opencontainers.org/) develops specifications for standards on Operating System process and application containers. The [Open Container Initiative][oci] develops specifications for standards on Operating System process and application containers.
The specification can be found [here](spec.md). The specification can be found [here](spec.md).
## Table of Contents
Additional documentation about how this group operates: Additional documentation about how this group operates:
- [Code of Conduct](https://github.com/opencontainers/tob/blob/d2f9d68c1332870e40693fe077d311e0742bc73d/code-of-conduct.md) - [Code of Conduct][code-of-conduct]
- [Style and Conventions](style.md) - [Style and Conventions](style.md)
- [Roadmap](ROADMAP.md) - [Roadmap](ROADMAP.md)
- [Implementations](implementations.md) - [Implementations](implementations.md)
@@ -14,38 +16,38 @@ Additional documentation about how this group operates:
- [project](project.md) - [project](project.md)
- [charter][charter] - [charter][charter]
# Use Cases ## Use Cases
To provide context for users the following section gives example use cases for each part of the spec. To provide context for users the following section gives example use cases for each part of the spec.
#### Application Bundle Builders ### Application Bundle Builders
Application bundle builders can create a [bundle](bundle.md) directory that includes all of the files required for launching an application as a container. Application bundle builders can create a [bundle](bundle.md) directory that includes all of the files required for launching an application as a container.
The bundle contains an OCI [configuration file](config.md) where the builder can specify host-independent details such as [which executable to launch](config.md#process) and host-specific settings such as [mount](config.md#mounts) locations, [hook](config.md#hooks) paths, Linux [namespaces](config-linux.md#namespaces) and [cgroups](config-linux.md#control-groups). The bundle contains an OCI [configuration file](config.md) where the builder can specify host-independent details such as [which executable to launch](config.md#process) and host-specific settings such as [mount](config.md#mounts) locations, [hook](config.md#hooks) paths, Linux [namespaces](config-linux.md#namespaces) and [cgroups](config-linux.md#control-groups).
Because the configuration includes host-specific settings, application bundle directories copied between two hosts may require configuration adjustments. Because the configuration includes host-specific settings, application bundle directories copied between two hosts may require configuration adjustments.
#### Hook Developers ### Hook Developers
[Hook](config.md#hooks) developers can extend the functionality of an OCI-compliant runtime by hooking into a container's lifecycle with an external application. [Hook](config.md#hooks) developers can extend the functionality of an OCI-compliant runtime by hooking into a container's lifecycle with an external application.
Example use cases include sophisticated network configuration, volume garbage collection, etc. Example use cases include sophisticated network configuration, volume garbage collection, etc.
#### Runtime Developers ### Runtime Developers
Runtime developers can build runtime implementations that run OCI-compliant bundles and container configuration, containing low-level OS and host specific details, on a particular platform. Runtime developers can build runtime implementations that run OCI-compliant bundles and container configuration, containing low-level OS and host specific details, on a particular platform.
# Releases ## Releases
There is a loose [Road Map](./ROADMAP.md). There is a loose [Road Map](./ROADMAP.md).
During the `0.x` series of OCI releases we make no backwards compatibility guarantees and intend to break the schema during this series. During the `0.x` series of OCI releases we make no backwards compatibility guarantees and intend to break the schema during this series.
# Contributing ## Contributing
Development happens on GitHub for the spec. Development happens on GitHub for the spec.
Issues are used for bugs and actionable items and longer discussions can happen on the [mailing list](#mailing-list). Issues are used for bugs and actionable items and longer discussions can happen on the [mailing list](#mailing-list).
The specification and code is licensed under the Apache 2.0 license found in the [LICENSE](./LICENSE) file. The specification and code is licensed under the Apache 2.0 license found in the [LICENSE](./LICENSE) file.
## Discuss your design ### Discuss your design
The project welcomes submissions, but please let everyone know what you are working on. The project welcomes submissions, but please let everyone know what you are working on.
@@ -56,27 +58,27 @@ It also guarantees that the design is sound before code is written; a GitHub pul
Typos and grammatical errors can go straight to a pull-request. Typos and grammatical errors can go straight to a pull-request.
When in doubt, start on the [mailing-list](#mailing-list). When in doubt, start on the [mailing-list](#mailing-list).
## Weekly Call ### Weekly Call
The contributors and maintainers of all OCI projects have a weekly meeting Wednesdays at 2:00 PM (USA Pacific). The contributors and maintainers of all OCI projects have a weekly meeting Wednesdays at 2:00 PM (USA Pacific).
Everyone is welcome to participate via [UberConference web][UberConference] or audio-only: 415-968-0849 (no PIN needed.) Everyone is welcome to participate via [UberConference web][uberconference] or audio-only: 415-968-0849 (no PIN needed.)
An initial agenda will be posted to the [mailing list](#mailing-list) earlier in the week, and everyone is welcome to propose additional topics or suggest other agenda alterations there. An initial agenda will be posted to the [mailing list](#mailing-list) earlier in the week, and everyone is welcome to propose additional topics or suggest other agenda alterations there.
Minutes are posted to the [mailing list](#mailing-list) and minutes from past calls are archived to the [wiki](https://github.com/opencontainers/runtime-spec/wiki) for those who are unable to join the call. Minutes are posted to the [mailing list](#mailing-list) and minutes from past calls are archived to the [wiki][runtime-wiki].
## Mailing List ### Mailing List
You can subscribe and join the mailing list on [Google Groups](https://groups.google.com/a/opencontainers.org/forum/#!forum/dev). You can subscribe and join the mailing list on [Google Groups][dev-list].
## IRC ### IRC
OCI discussion happens on #opencontainers on Freenode ([logs][irc-logs]). OCI discussion happens on #opencontainers on Freenode ([logs][irc-logs]).
## Git commit ### Git commit
### Sign your work #### Sign your work
The sign-off is a simple line at the end of the explanation for the patch, which certifies that you wrote it or otherwise have the right to pass it on as an open-source patch. The sign-off is a simple line at the end of the explanation for the patch, which certifies that you wrote it or otherwise have the right to pass it on as an open-source patch.
The rules are pretty simple: if you can certify the below (from [developercertificate.org](http://developercertificate.org/)): The rules are pretty simple: if you can certify the below (from http://developercertificate.org):
``` ```
Developer Certificate of Origin Developer Certificate of Origin
@@ -125,10 +127,10 @@ using your real name (sorry, no pseudonyms or anonymous contributions.)
You can add the sign off when creating the git commit via `git commit -s`. You can add the sign off when creating the git commit via `git commit -s`.
### Commit Style #### Commit Style
Simple house-keeping for clean git history. Simple house-keeping for clean git history.
Read more on [How to Write a Git Commit Message](http://chris.beams.io/posts/git-commit/) or the Discussion section of [`git-commit(1)`](http://git-scm.com/docs/git-commit). Read more on [How to Write a Git Commit Message][how-to-git-commit] or the Discussion section of [git-commit(1)][git-commit.1].
1. Separate the subject from body with a blank line 1. Separate the subject from body with a blank line
2. Limit the subject line to 50 characters 2. Limit the subject line to 50 characters
@@ -140,6 +142,14 @@ Read more on [How to Write a Git Commit Message](http://chris.beams.io/posts/git
* If there was important/useful/essential conversation or information, copy or include a reference * If there was important/useful/essential conversation or information, copy or include a reference
8. When possible, one keyword to scope the change in the subject (i.e. "README: ...", "runtime: ...") 8. When possible, one keyword to scope the change in the subject (i.e. "README: ...", "runtime: ...")
[UberConference]: https://www.uberconference.com/opencontainers
[irc-logs]: http://ircbot.wl.linuxfoundation.org/eavesdrop/%23opencontainers/
[charter]: https://www.opencontainers.org/about/governance [charter]: https://www.opencontainers.org/about/governance
[code-of-conduct]: https://github.com/opencontainers/tob/blob/master/code-of-conduct.md
[dev-list]: https://groups.google.com/a/opencontainers.org/forum/#!forum/dev
[how-to-git-commit]: http://chris.beams.io/posts/git-commit
[irc-logs]: http://ircbot.wl.linuxfoundation.org/eavesdrop/%23opencontainers/
[oci]: https://www.opencontainers.org
[runtime-wiki]: https://github.com/opencontainers/runtime-spec/wiki
[uberconference]: https://www.uberconference.com/opencontainers
[git-commit.1]: http://git-scm.com/docs/git-commit

View File

@@ -17,7 +17,7 @@ type Spec struct {
// Mounts configures additional mounts (on top of Root). // Mounts configures additional mounts (on top of Root).
Mounts []Mount `json:"mounts,omitempty"` Mounts []Mount `json:"mounts,omitempty"`
// Hooks configures callbacks for container lifecycle events. // Hooks configures callbacks for container lifecycle events.
Hooks Hooks `json:"hooks"` Hooks *Hooks `json:"hooks,omitempty"`
// Annotations contains arbitrary metadata for the container. // Annotations contains arbitrary metadata for the container.
Annotations map[string]string `json:"annotations,omitempty"` Annotations map[string]string `json:"annotations,omitempty"`
@@ -44,8 +44,8 @@ type Process struct {
// Cwd is the current working directory for the process and must be // Cwd is the current working directory for the process and must be
// relative to the container's root. // relative to the container's root.
Cwd string `json:"cwd"` Cwd string `json:"cwd"`
// Capabilities are Linux capabilities that are kept for the container. // Capabilities are Linux capabilities that are kept for the process.
Capabilities []string `json:"capabilities,omitempty" platform:"linux"` Capabilities *LinuxCapabilities `json:"capabilities,omitempty" platform:"linux"`
// Rlimits specifies rlimit options to apply to the process. // Rlimits specifies rlimit options to apply to the process.
Rlimits []LinuxRlimit `json:"rlimits,omitempty" platform:"linux"` Rlimits []LinuxRlimit `json:"rlimits,omitempty" platform:"linux"`
// NoNewPrivileges controls whether additional privileges could be gained by processes in the container. // NoNewPrivileges controls whether additional privileges could be gained by processes in the container.
@@ -56,6 +56,21 @@ type Process struct {
SelinuxLabel string `json:"selinuxLabel,omitempty" platform:"linux"` SelinuxLabel string `json:"selinuxLabel,omitempty" platform:"linux"`
} }
// LinuxCapabilities specifies the whitelist of capabilities that are kept for a process.
// http://man7.org/linux/man-pages/man7/capabilities.7.html
type LinuxCapabilities struct {
// Bounding is the set of capabilities checked by the kernel.
Bounding []string `json:"bounding,omitempty" platform:"linux"`
// Effective is the set of capabilities checked by the kernel.
Effective []string `json:"effective,omitempty" platform:"linux"`
// Inheritable is the capabilities preserved across execve.
Inheritable []string `json:"inheritable,omitempty" platform:"linux"`
// Permitted is the limiting superset for effective capabilities.
Permitted []string `json:"permitted,omitempty" platform:"linux"`
// Ambient is the ambient set of capabilities that are kept.
Ambient []string `json:"ambient,omitempty" platform:"linux"`
}
// Box specifies dimensions of a rectangle. Used for specifying the size of a console. // Box specifies dimensions of a rectangle. Used for specifying the size of a console.
type Box struct { type Box struct {
// Height is the vertical dimension of a box. // Height is the vertical dimension of a box.
@@ -98,10 +113,10 @@ type Mount struct {
// Destination is the path where the mount will be placed relative to the container's root. The path and child directories MUST exist, a runtime MUST NOT create directories automatically to a mount point. // Destination is the path where the mount will be placed relative to the container's root. The path and child directories MUST exist, a runtime MUST NOT create directories automatically to a mount point.
Destination string `json:"destination"` Destination string `json:"destination"`
// Type specifies the mount kind. // Type specifies the mount kind.
Type string `json:"type"` Type string `json:"type,omitempty"`
// Source specifies the source path of the mount. In the case of bind mounts on // Source specifies the source path of the mount. In the case of bind mounts on
// Linux based systems this would be the file on the host. // Linux based systems this would be the file on the host.
Source string `json:"source"` Source string `json:"source,omitempty"`
// Options are fstab style mount options. // Options are fstab style mount options.
Options []string `json:"options,omitempty"` Options []string `json:"options,omitempty"`
} }
@@ -139,7 +154,7 @@ type Linux struct {
// CgroupsPath specifies the path to cgroups that are created and/or joined by the container. // CgroupsPath specifies the path to cgroups that are created and/or joined by the container.
// The path is expected to be relative to the cgroups mountpoint. // The path is expected to be relative to the cgroups mountpoint.
// If resources are specified, the cgroups at CgroupsPath will be updated based on resources. // If resources are specified, the cgroups at CgroupsPath will be updated based on resources.
CgroupsPath *string `json:"cgroupsPath,omitempty"` CgroupsPath string `json:"cgroupsPath,omitempty"`
// Namespaces contains the namespaces that are created and/or joined by the container // Namespaces contains the namespaces that are created and/or joined by the container
Namespaces []LinuxNamespace `json:"namespaces,omitempty"` Namespaces []LinuxNamespace `json:"namespaces,omitempty"`
// Devices are a list of device nodes that are created for the container // Devices are a list of device nodes that are created for the container
@@ -284,17 +299,17 @@ type LinuxCPU struct {
// CPU shares (relative weight (ratio) vs. other cgroups with cpu shares). // CPU shares (relative weight (ratio) vs. other cgroups with cpu shares).
Shares *uint64 `json:"shares,omitempty"` Shares *uint64 `json:"shares,omitempty"`
// CPU hardcap limit (in usecs). Allowed cpu time in a given period. // CPU hardcap limit (in usecs). Allowed cpu time in a given period.
Quota *uint64 `json:"quota,omitempty"` Quota *int64 `json:"quota,omitempty"`
// CPU period to be used for hardcapping (in usecs). // CPU period to be used for hardcapping (in usecs).
Period *uint64 `json:"period,omitempty"` Period *uint64 `json:"period,omitempty"`
// How much time realtime scheduling may use (in usecs). // How much time realtime scheduling may use (in usecs).
RealtimeRuntime *uint64 `json:"realtimeRuntime,omitempty"` RealtimeRuntime *int64 `json:"realtimeRuntime,omitempty"`
// CPU period to be used for realtime scheduling (in usecs). // CPU period to be used for realtime scheduling (in usecs).
RealtimePeriod *uint64 `json:"realtimePeriod,omitempty"` RealtimePeriod *uint64 `json:"realtimePeriod,omitempty"`
// CPUs to use within the cpuset. Default is to use any CPU available. // CPUs to use within the cpuset. Default is to use any CPU available.
Cpus *string `json:"cpus,omitempty"` Cpus string `json:"cpus,omitempty"`
// List of memory nodes in the cpuset. Default is to use any available memory node. // List of memory nodes in the cpuset. Default is to use any available memory node.
Mems *string `json:"mems,omitempty"` Mems string `json:"mems,omitempty"`
} }
// LinuxPids for Linux cgroup 'pids' resource management (Linux 4.3) // LinuxPids for Linux cgroup 'pids' resource management (Linux 4.3)
@@ -356,20 +371,13 @@ type LinuxDeviceCgroup struct {
// Allow or deny // Allow or deny
Allow bool `json:"allow"` Allow bool `json:"allow"`
// Device type, block, char, etc. // Device type, block, char, etc.
Type *string `json:"type,omitempty"` Type string `json:"type,omitempty"`
// Major is the device's major number. // Major is the device's major number.
Major *int64 `json:"major,omitempty"` Major *int64 `json:"major,omitempty"`
// Minor is the device's minor number. // Minor is the device's minor number.
Minor *int64 `json:"minor,omitempty"` Minor *int64 `json:"minor,omitempty"`
// Cgroup access permissions format, rwm. // Cgroup access permissions format, rwm.
Access *string `json:"access,omitempty"` Access string `json:"access,omitempty"`
}
// LinuxSeccomp represents syscall restrictions
type LinuxSeccomp struct {
DefaultAction LinuxSeccompAction `json:"defaultAction"`
Architectures []Arch `json:"architectures"`
Syscalls []LinuxSyscall `json:"syscalls,omitempty"`
} }
// Solaris contains platform specific configuration for Solaris application containers. // Solaris contains platform specific configuration for Solaris application containers.
@@ -469,6 +477,13 @@ type WindowsNetworkResources struct {
EgressBandwidth *uint64 `json:"egressBandwidth,omitempty"` EgressBandwidth *uint64 `json:"egressBandwidth,omitempty"`
} }
// LinuxSeccomp represents syscall restrictions
type LinuxSeccomp struct {
DefaultAction LinuxSeccompAction `json:"defaultAction"`
Architectures []Arch `json:"architectures,omitempty"`
Syscalls []LinuxSyscall `json:"syscalls"`
}
// Arch used for additional architectures // Arch used for additional architectures
type Arch string type Arch string
@@ -491,6 +506,8 @@ const (
ArchPPC64LE Arch = "SCMP_ARCH_PPC64LE" ArchPPC64LE Arch = "SCMP_ARCH_PPC64LE"
ArchS390 Arch = "SCMP_ARCH_S390" ArchS390 Arch = "SCMP_ARCH_S390"
ArchS390X Arch = "SCMP_ARCH_S390X" ArchS390X Arch = "SCMP_ARCH_S390X"
ArchPARISC Arch = "SCMP_ARCH_PARISC"
ArchPARISC64 Arch = "SCMP_ARCH_PARISC64"
) )
// LinuxSeccompAction taken upon Seccomp rule match // LinuxSeccompAction taken upon Seccomp rule match
@@ -529,7 +546,8 @@ type LinuxSeccompArg struct {
// LinuxSyscall is used to match a syscall in Seccomp // LinuxSyscall is used to match a syscall in Seccomp
type LinuxSyscall struct { type LinuxSyscall struct {
Name string `json:"name"` Names []string `json:"names"`
Action LinuxSeccompAction `json:"action"` Action LinuxSeccompAction `json:"action"`
Args []LinuxSeccompArg `json:"args,omitempty"` Args []LinuxSeccompArg `json:"args"`
Comment string `json:"comment"`
} }

View File

@@ -6,12 +6,12 @@ type State struct {
Version string `json:"ociVersion"` Version string `json:"ociVersion"`
// ID is the container ID // ID is the container ID
ID string `json:"id"` ID string `json:"id"`
// Status is the runtime state of the container. // Status is the runtime status of the container.
Status string `json:"status"` Status string `json:"status"`
// Pid is the process ID for the container process. // Pid is the process ID for the container process.
Pid int `json:"pid"` Pid int `json:"pid"`
// BundlePath is the path to the container's bundle directory. // Bundle is the path to the container's bundle directory.
BundlePath string `json:"bundlePath"` Bundle string `json:"bundle"`
// Annotations are the annotations associated with the container. // Annotations are key values associated with the container.
Annotations map[string]string `json:"annotations"` Annotations map[string]string `json:"annotations,omitempty"`
} }

View File

@@ -11,7 +11,7 @@ const (
VersionPatch = 0 VersionPatch = 0
// VersionDev indicates development branch. Releases will be empty string. // VersionDev indicates development branch. Releases will be empty string.
VersionDev = "-rc3" VersionDev = "-rc5"
) )
// Version is the specification version that the package types support. // Version is the specification version that the package types support.