diff --git a/cmd/ocitools/generate.go b/cmd/ocitools/generate.go index 2efac6114..6dd4ec7f6 100644 --- a/cmd/ocitools/generate.go +++ b/cmd/ocitools/generate.go @@ -36,7 +36,7 @@ var generateFlags = []cli.Flag{ cli.StringFlag{Name: "mount-label", Usage: "selinux mount context label"}, cli.StringSliceFlag{Name: "tmpfs", Usage: "mount tmpfs"}, cli.StringSliceFlag{Name: "args", Usage: "command to run in the container"}, - cli.StringSliceFlag{Name: "env", Usage: "add environment variable"}, + cli.StringSliceFlag{Name: "env", Usage: "add environment variable e.g. key=value"}, cli.StringFlag{Name: "cgroups-path", Usage: "specify the path to the cgroups"}, cli.StringFlag{Name: "mount-cgroups", Value: "no", Usage: "mount cgroups (rw,ro,no)"}, cli.StringSliceFlag{Name: "bind", Usage: "bind mount directories src:dest:(rw,ro)"}, @@ -58,6 +58,7 @@ var generateFlags = []cli.Flag{ cli.StringSliceFlag{Name: "seccomp-errno", Usage: "specifies syscalls to be added to list that returns an error"}, cli.StringFlag{Name: "template", Usage: "base template to use for creating the configuration"}, cli.StringSliceFlag{Name: "label", Usage: "add annotations to the configuration e.g. key=value"}, + cli.IntFlag{Name: "oom-score-adj", Usage: "oom_score_adj for the container"}, } var generateCommand = cli.Command{ @@ -319,6 +320,10 @@ func setupSpec(g *generate.Generator, context *cli.Context) error { g.AddLinuxGIDMapping(hid, cid, size) } + if context.IsSet("oom-score-adj") { + g.SetLinuxResourcesOOMScoreAdj(context.Int("oom-score-adj")) + } + var sd string var sa, ss []string diff --git a/cmd/ocitools/validate.go b/cmd/ocitools/validate.go index 0fab50202..6c37147a5 100644 --- a/cmd/ocitools/validate.go +++ b/cmd/ocitools/validate.go @@ -316,13 +316,7 @@ func checkLinux(spec rspec.Spec, rootfs string, hostCheck bool) (msgs []string) ipcExists := false mountExists := false netExists := false - - if len(spec.Linux.UIDMappings) > 5 { - msgs = append(msgs, "Only 5 UID mappings are allowed (linux kernel restriction).") - } - if len(spec.Linux.GIDMappings) > 5 { - msgs = append(msgs, "Only 5 GID mappings are allowed (linux kernel restriction).") - } + userExists := false for index := 0; index < len(spec.Linux.Namespaces); index++ { if !namespaceValid(spec.Linux.Namespaces[index]) { @@ -336,10 +330,20 @@ func checkLinux(spec rspec.Spec, rootfs string, hostCheck bool) (msgs []string) netExists = true } else if spec.Linux.Namespaces[index].Type == rspec.MountNamespace { mountExists = true + } else if spec.Linux.Namespaces[index].Type == rspec.UserNamespace { + userExists = true } } } + if (len(spec.Linux.UIDMappings) > 0 || len(spec.Linux.GIDMappings) > 0) && !userExists { + msgs = append(msgs, "UID/GID mappings requires a new User namespace to be specified as well") + } else if len(spec.Linux.UIDMappings) > 5 { + msgs = append(msgs, "Only 5 UID mappings are allowed (linux kernel restriction).") + } else if len(spec.Linux.GIDMappings) > 5 { + msgs = append(msgs, "Only 5 GID mappings are allowed (linux kernel restriction).") + } + for k := range spec.Linux.Sysctl { if strings.HasPrefix(k, "net.") && !netExists { msgs = append(msgs, fmt.Sprintf("Sysctl %v requires a new Network namespace to be specified as well", k)) @@ -361,6 +365,11 @@ func checkLinux(spec rspec.Spec, rootfs string, hostCheck bool) (msgs []string) } } + if spec.Linux.Resources != nil { + ms := checkLinuxResources(*spec.Linux.Resources, hostCheck) + msgs = append(msgs, ms...) + } + if spec.Linux.Seccomp != nil { ms := checkSeccomp(*spec.Linux.Seccomp) msgs = append(msgs, ms...) @@ -381,6 +390,21 @@ func checkLinux(spec rspec.Spec, rootfs string, hostCheck bool) (msgs []string) return } +func checkLinuxResources(r rspec.Resources, hostCheck bool) (msgs []string) { + logrus.Debugf("check linux resources") + + if r.Memory != nil { + if r.Memory.Limit != nil && r.Memory.Swap != nil && uint64(*r.Memory.Limit) > uint64(*r.Memory.Swap) { + msgs = append(msgs, fmt.Sprintf("Minimum memoryswap should be larger than memory limit")) + } + if r.Memory.Limit != nil && r.Memory.Reservation != nil && uint64(*r.Memory.Reservation) > uint64(*r.Memory.Limit) { + msgs = append(msgs, fmt.Sprintf("Minimum memory limit should be larger than memory reservation")) + } + } + + return +} + func checkSeccomp(s rspec.Seccomp) (msgs []string) { logrus.Debugf("check seccomp") diff --git a/completions/bash/ocitools b/completions/bash/ocitools index 3328792d7..50233c71a 100644 --- a/completions/bash/ocitools +++ b/completions/bash/ocitools @@ -275,6 +275,7 @@ _ocitools_generate() { --cap-add --cap-drop --cgroup + --cgroup-path --cwd --env --gid @@ -283,25 +284,31 @@ _ocitools_generate() { --hostname --help --ipc + --label --mount --mount-cgroups + --mount-label --network --os + --output --pid --poststart --poststop --prestart --root-propagation --rootfs - --seccomp-default + --seccomp-allow --seccomp-arch + --seccomp-default + --seccomp-errno --seccomp-syscalls --selinux-label - --mount-label --sysctl + --tmplate --tmpfs --uid --uidmappings + --user --uts " @@ -330,11 +337,6 @@ _ocitools_generate() { return ;; - --seccomp-default) - __ocitools_complete_seccomp_actions - return - ;; - --root-propagation) __ocitools_complete_propagations return diff --git a/generate/generate.go b/generate/generate.go index bb3f880dc..a3d978572 100644 --- a/generate/generate.go +++ b/generate/generate.go @@ -194,11 +194,7 @@ func (g *Generator) Save(w io.Writer) error { } _, err = w.Write(data) - if err != nil { - return err - } - - return nil + return err } // SaveToFile writes the spec into a file. @@ -362,6 +358,12 @@ func (g *Generator) SetLinuxMountLabel(label string) { g.spec.Linux.MountLabel = label } +// SetLinuxResourcesOOMScoreAdj sets g.spec.Linux.Resources.OOMScoreAdj. +func (g *Generator) SetLinuxResourcesOOMScoreAdj(adj int) { + g.initSpecLinuxResources() + g.spec.Linux.Resources.OOMScoreAdj = &adj +} + // SetLinuxResourcesCPUShares sets g.spec.Linux.Resources.CPU.Shares. func (g *Generator) SetLinuxResourcesCPUShares(shares uint64) { g.initSpecLinuxResourcesCPU() @@ -855,6 +857,7 @@ func (g *Generator) AddCgroupsMount(mountCgroupOption string) error { switch mountCgroupOption { case "ro": case "rw": + break case "no": return nil default: diff --git a/man/ocitools-generate.1.md b/man/ocitools-generate.1.md index 72bc764aa..a530a8e1a 100644 --- a/man/ocitools-generate.1.md +++ b/man/ocitools-generate.1.md @@ -58,10 +58,10 @@ read the configuration from `config.json`. Current working directory for the process **--env**=[] - Set environment variables - This option allows you to specify arbitrary -environment variables that are available for the process that will be launched -inside of the container. + Set environment variables e.g. key=value. + This option allows you to specify arbitrary environment variables + that are available for the process that will be launched inside of + the container. **--gid**=GID Gid for the process inside of container @@ -84,6 +84,9 @@ inside of the container. The special *PATH* `host` removes any existing IPC namespace from the configuration. +**--label**=[] + Add annotations to the configuration e.g. key=value. + **--mount**=*PATH* Use a mount namespace where *PATH* is an existing mount namespace file to join. The special *PATH* empty-string creates a new namespace. @@ -117,6 +120,9 @@ inside of the container. using tools like setuid apps. It is a good idea to run unprivileged containers with this flag. +**--oom-score-adj**=adj + Specifies oom_score_adj for the container. + **--output**=PATH Instead of writing the configuration JSON to stdout, write it to a file at *PATH* (overwriting the existing content if a file already diff --git a/man/ocitools.1.md b/man/ocitools.1.md index a698fff4e..dbc790cd0 100644 --- a/man/ocitools.1.md +++ b/man/ocitools.1.md @@ -38,11 +38,11 @@ ocitools is a collection of tools for working with the [OCI runtime specificatio # COMMANDS **validate** Validating OCI bundle - See **ocitools-validate(1)** for full documentation on the **validate** command. + See **ocitools-validate**(1) for full documentation on the **validate** command. **generate** Generating OCI runtime spec configuration files - See **ocitools-generate(1)** for full documentation on the **generate** command. + See **ocitools-generate**(1) for full documentation on the **generate** command. # SEE ALSO **ocitools-validate**(1), **ocitools-generate**(1)