Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ BINDIR ?= $(DESTDIR)/usr/bin

BUILDTAGS=
RUNTIME ?= runc
PLATFORM ?= linux

all: tool runtimetest

Expand Down Expand Up @@ -39,7 +40,7 @@ clean:
rm -f oci-runtime-tool runtimetest *.1

localvalidation: runtimetest
RUNTIME=$(RUNTIME) go test -tags "$(BUILDTAGS)" ${TESTFLAGS} -v github.com/opencontainers/runtime-tools/validation
RUNTIME=$(RUNTIME) PLATFORM=$(PLATFORM) go test -tags "$(BUILDTAGS)" ${TESTFLAGS} -v github.com/opencontainers/runtime-tools/validation

.PHONY: test .gofmt .govet .golint

Expand Down
6 changes: 0 additions & 6 deletions cmd/oci-runtime-tool/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"bytes"
"fmt"
"os"
"runtime"
"strconv"
"strings"
"unicode"
Expand All @@ -19,7 +18,6 @@ import (

var generateFlags = []cli.Flag{
cli.StringFlag{Name: "apparmor", Usage: "specifies the the apparmor profile for the container"},
cli.StringFlag{Name: "arch", Value: runtime.GOARCH, Usage: "architecture the container is created for"},
cli.StringSliceFlag{Name: "args", Usage: "command to run in the container"},
cli.StringSliceFlag{Name: "bind", Usage: "bind mount directories src:dest[:options...]"},
cli.StringSliceFlag{Name: "cap-add", Usage: "add Linux capabilities"},
Expand Down Expand Up @@ -62,7 +60,6 @@ var generateFlags = []cli.Flag{
cli.StringFlag{Name: "mount-label", Usage: "selinux mount context label"},
cli.BoolFlag{Name: "no-new-privileges", Usage: "set no new privileges bit for the container process"},
cli.IntFlag{Name: "oom-score-adj", Usage: "oom_score_adj for the container"},
cli.StringFlag{Name: "os", Value: runtime.GOOS, Usage: "operating system the container is created for"},
cli.StringFlag{Name: "output", Usage: "output file (defaults to stdout)"},
cli.StringSliceFlag{Name: "poststart", Usage: "set command to run in poststart hooks"},
cli.StringSliceFlag{Name: "poststop", Usage: "set command to run in poststop hooks"},
Expand Down Expand Up @@ -151,9 +148,6 @@ func setupSpec(g *generate.Generator, context *cli.Context) error {
g.SetHostname(context.String("hostname"))
}

g.SetPlatformOS(context.String("os"))
g.SetPlatformArch(context.String("arch"))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you also need to remove options os and arch from cli.Flag and manpage


if context.IsSet("label") {
annotations := context.StringSlice("label")
for _, s := range annotations {
Expand Down
5 changes: 5 additions & 0 deletions cmd/oci-runtime-tool/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ func main() {
Value: "error",
Usage: "Log level (panic, fatal, error, warn, info, or debug)",
},
cli.StringFlag{
Name: "platform",
Value: "linux",
Usage: "Platform the tool targets",
},
}

app.Commands = []cli.Command{
Expand Down
3 changes: 2 additions & 1 deletion cmd/oci-runtime-tool/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ var bundleValidateCommand = cli.Command{
Action: func(context *cli.Context) error {
inputPath := context.String("path")
hostSpecific := context.GlobalBool("host-specific")
v, err := validate.NewValidatorFromPath(inputPath, hostSpecific)
platform := context.GlobalString("platform")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add 'platform' to man page as well.

v, err := validate.NewValidatorFromPath(inputPath, hostSpecific, platform)
if err != nil {
return err
}
Expand Down
11 changes: 9 additions & 2 deletions cmd/runtimetest/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,8 @@ func validate(context *cli.Context) error {
return err
}

platform := context.String("platform")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also need to pass this to validation_test.go#getDefaultGenerator and change the Makefile (by adding a PLATFORM for example).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, but I don't think we use it in generator.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean we should change:

g.SetProcessArgs([]string{"/runtimetest"})

to

g.SetProcessArgs([]string{"/runtimetest", "platform", platform})

since you add a platform option to runtimetest command.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we don't use it anymore in generator.

Copy link
Contributor Author

@hqhq hqhq Jul 5, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But platform is not a process arg. It should be a generator arg as it's a validate arg.

I know what you mean, here the process is runtimetest.


defaultValidations := []validation{
{
test: validateRootFS,
Expand Down Expand Up @@ -666,7 +668,7 @@ func validate(context *cli.Context) error {
}
}

if spec.Platform.OS == "linux" {
if platform == "linux" {
for _, v := range linuxValidations {
err := v.test(spec)
t.Ok(err == nil, v.description)
Expand Down Expand Up @@ -695,7 +697,12 @@ func main() {
cli.StringFlag{
Name: "path",
Value: ".",
Usage: "path to the configuration",
Usage: "Path to the configuration",
},
cli.StringFlag{
Name: "platform",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the runtimetest automatically get which platform it is running on? I think it seems there is no need to specify it manunally. What do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hqhq how does runc do?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Mashimiao We can, but can we do that in a follow up PR, what we did in this PR looks consistent and we have the default value.

@liangchenye runc doesn't check platform at all, the spec author should be responsible to give runc the right config.

Value: "linux",
Usage: "Platform the runtime runs on",
},
}

Expand Down
17 changes: 0 additions & 17 deletions generate/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"fmt"
"io"
"os"
"runtime"
"strings"

rspec "github.com/opencontainers/runtime-spec/specs-go"
Expand Down Expand Up @@ -35,10 +34,6 @@ type ExportOptions struct {
func New() Generator {
spec := rspec.Spec{
Version: rspec.Version,
Platform: rspec.Platform{
OS: runtime.GOOS,
Arch: runtime.GOARCH,
},
Root: rspec.Root{
Path: "",
Readonly: false,
Expand Down Expand Up @@ -346,18 +341,6 @@ func (g *Generator) RemoveAnnotation(key string) {
delete(g.spec.Annotations, key)
}

// SetPlatformOS sets g.spec.Process.OS.
func (g *Generator) SetPlatformOS(os string) {
g.initSpec()
g.spec.Platform.OS = os
}

// SetPlatformArch sets g.spec.Platform.Arch.
func (g *Generator) SetPlatformArch(arch string) {
g.initSpec()
g.spec.Platform.Arch = arch
}

// SetProcessUID sets g.spec.Process.User.UID.
func (g *Generator) SetProcessUID(uid uint32) {
g.initSpec()
Expand Down
7 changes: 0 additions & 7 deletions man/oci-runtime-tool-generate.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@ read the configuration from `config.json`.
**--apparmor**=PROFILE
Specifies the apparmor profile for the container

**--arch**=ARCH
Architecture used within the container.
"amd64"

**--args**=OPTION
Arguments to run within the container. Can be specified multiple times.
If you were going to run a command with multiple options, you would need
Expand Down Expand Up @@ -200,9 +196,6 @@ read the configuration from `config.json`.
**--oom-score-adj**=adj
Specifies oom_score_adj for the container.

**--os**=OS
Operating system used within 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
Expand Down
3 changes: 3 additions & 0 deletions man/oci-runtime-tool.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ oci-runtime-tool is a collection of tools for working with the [OCI runtime spec
**--log-level**=LEVEL
Log level (panic, fatal, error, warn, info, or debug) (default: "error").

**--platform**
Platform the tool targets.

**-v**, **--version**
Print version information.

Expand Down
90 changes: 34 additions & 56 deletions validate/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,21 @@ type Validator struct {
spec *rspec.Spec
bundlePath string
HostSpecific bool
platform string
}

// NewValidator creates a Validator
func NewValidator(spec *rspec.Spec, bundlePath string, hostSpecific bool) Validator {
return Validator{spec: spec, bundlePath: bundlePath, HostSpecific: hostSpecific}
func NewValidator(spec *rspec.Spec, bundlePath string, hostSpecific bool, platform string) Validator {
return Validator{
spec: spec,
bundlePath: bundlePath,
HostSpecific: hostSpecific,
platform: platform,
}
}

// NewValidatorFromPath creates a Validator with specified bundle path
func NewValidatorFromPath(bundlePath string, hostSpecific bool) (Validator, error) {
func NewValidatorFromPath(bundlePath string, hostSpecific bool, platform string) (Validator, error) {
if bundlePath == "" {
return Validator{}, fmt.Errorf("Bundle path shouldn't be empty")
}
Expand All @@ -77,18 +83,17 @@ func NewValidatorFromPath(bundlePath string, hostSpecific bool) (Validator, erro
return Validator{}, err
}

return NewValidator(&spec, bundlePath, hostSpecific), nil
return NewValidator(&spec, bundlePath, hostSpecific, platform), nil
}

// CheckAll checks all parts of runtime bundle
func (v *Validator) CheckAll() (msgs []string) {
msgs = append(msgs, v.CheckPlatform()...)
msgs = append(msgs, v.CheckRootfsPath()...)
msgs = append(msgs, v.CheckMandatoryFields()...)
msgs = append(msgs, v.CheckSemVer()...)
msgs = append(msgs, v.CheckMounts()...)
msgs = append(msgs, v.CheckPlatform()...)
msgs = append(msgs, v.CheckProcess()...)
msgs = append(msgs, v.CheckOS()...)
msgs = append(msgs, v.CheckHooks()...)
if v.spec.Linux != nil {
msgs = append(msgs, v.CheckLinux()...)
Expand Down Expand Up @@ -131,9 +136,9 @@ func (v *Validator) CheckRootfsPath() (msgs []string) {
msgs = append(msgs, fmt.Sprintf("root.path is %q, but it MUST be a child of %q", v.spec.Root.Path, absBundlePath))
}

if v.spec.Platform.OS == "windows" {
if v.platform == "windows" {
if v.spec.Root.Readonly {
msgs = append(msgs, "root.readonly field MUST be omitted or false when platform.os is windows")
msgs = append(msgs, "root.readonly field MUST be omitted or false when target platform is windows")
}
}

Expand All @@ -156,37 +161,6 @@ func (v *Validator) CheckSemVer() (msgs []string) {
return
}

// CheckPlatform checks v.spec.Platform
func (v *Validator) CheckPlatform() (msgs []string) {
logrus.Debugf("check platform")

validCombins := map[string][]string{
"android": {"arm"},
"darwin": {"386", "amd64", "arm", "arm64"},
"dragonfly": {"amd64"},
"freebsd": {"386", "amd64", "arm"},
"linux": {"386", "amd64", "arm", "arm64", "mips", "mips64", "mips64le", "mipsle", "ppc64", "ppc64le", "s390x"},
"netbsd": {"386", "amd64", "arm"},
"openbsd": {"386", "amd64", "arm"},
"plan9": {"386", "amd64"},
"solaris": {"amd64"},
"windows": {"386", "amd64"}}
platform := v.spec.Platform
for os, archs := range validCombins {
if os == platform.OS {
for _, arch := range archs {
if arch == platform.Arch {
return nil
}
}
msgs = append(msgs, fmt.Sprintf("Combination of %q and %q is invalid.", platform.OS, platform.Arch))
}
}
msgs = append(msgs, fmt.Sprintf("Operation system %q of the bundle is not supported yet.", platform.OS))

return
}

// CheckHooks check v.spec.Hooks
func (v *Validator) CheckHooks() (msgs []string) {
logrus.Debugf("check hooks")
Expand Down Expand Up @@ -271,8 +245,7 @@ func (v *Validator) CheckProcess() (msgs []string) {
}
msgs = append(msgs, v.CheckRlimits()...)

if v.spec.Platform.OS == "linux" {

if v.platform == "linux" {
if len(process.ApparmorProfile) > 0 {
profilePath := filepath.Join(v.bundlePath, v.spec.Root.Path, "/etc/apparmor.d", process.ApparmorProfile)
_, err := os.Stat(profilePath)
Expand All @@ -288,7 +261,7 @@ func (v *Validator) CheckProcess() (msgs []string) {
// CheckCapabilities checks v.spec.Process.Capabilities
func (v *Validator) CheckCapabilities() (msgs []string) {
process := v.spec.Process
if v.spec.Platform.OS == "linux" {
if v.platform == "linux" {
var effective, permitted, inheritable, ambient bool
caps := make(map[string][]string)

Expand Down Expand Up @@ -336,7 +309,7 @@ func (v *Validator) CheckCapabilities() (msgs []string) {
}
}
} else {
logrus.Warnf("process.capabilities validation not yet implemented for OS %q", v.spec.Platform.OS)
logrus.Warnf("process.capabilities validation not yet implemented for OS %q", v.platform)
}

return
Expand Down Expand Up @@ -402,7 +375,7 @@ func supportedMountTypes(OS string, hostSpecific bool) (map[string]bool, error)
func (v *Validator) CheckMounts() (msgs []string) {
logrus.Debugf("check mounts")

supportedTypes, err := supportedMountTypes(v.spec.Platform.OS, v.HostSpecific)
supportedTypes, err := supportedMountTypes(v.platform, v.HostSpecific)
if err != nil {
msgs = append(msgs, err.Error())
return
Expand All @@ -423,25 +396,30 @@ func (v *Validator) CheckMounts() (msgs []string) {
return
}

// CheckOS checks v.spec.Platform.OS
func (v *Validator) CheckOS() (msgs []string) {
logrus.Debugf("check os")
// CheckPlatform checks v.platform
func (v *Validator) CheckPlatform() (msgs []string) {
logrus.Debugf("check platform")

if v.platform != "linux" && v.platform != "solaris" && v.platform != "windows" {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, spec just supports linux, solaris and windows, all other platforms are invalid?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should check

if v.platform != "linux" && v.platform != "solaris" && v.platform != "windows" {

right after

	platform := context.GlobalString("platform")

Copy link
Contributor Author

@hqhq hqhq Jul 5, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine with either, if check platform right after got it from context, it would be like a runtime-tools limitation, while it's actually can be an OCI validation, so check it in Validator methods seems reasonable to me.

Plus I moved CheckPlatform to the top in the second commit, so we don't do much unnecessary check it platform is wrong.

msgs = append(msgs, fmt.Sprintf("platform %q is not supported", v.platform))
return
}

if v.spec.Platform.OS != "linux" {
if v.platform != "linux" {
if v.spec.Linux != nil {
msgs = append(msgs, fmt.Sprintf("'linux' MUST NOT be set when platform.os is %q", v.spec.Platform.OS))
msgs = append(msgs, fmt.Sprintf("'linux' MUST NOT be set when target platform is %q", v.platform))
}
}

if v.spec.Platform.OS != "solaris" {
if v.platform != "solaris" {
if v.spec.Solaris != nil {
msgs = append(msgs, fmt.Sprintf("'solaris' MUST NOT be set when platform.os is %q", v.spec.Platform.OS))
msgs = append(msgs, fmt.Sprintf("'solaris' MUST NOT be set when target platform is %q", v.platform))
}
}

if v.spec.Platform.OS != "windows" {
if v.platform != "windows" {
if v.spec.Windows != nil {
msgs = append(msgs, fmt.Sprintf("'windows' MUST NOT be set when platform.os is %q", v.spec.Platform.OS))
msgs = append(msgs, fmt.Sprintf("'windows' MUST NOT be set when target platform is %q", v.platform))
}
}

Expand Down Expand Up @@ -502,7 +480,7 @@ func (v *Validator) CheckLinux() (msgs []string) {
}
}

if v.spec.Platform.OS == "linux" && !typeList[rspec.UTSNamespace].newExist && v.spec.Hostname != "" {
if v.platform == "linux" && !typeList[rspec.UTSNamespace].newExist && v.spec.Hostname != "" {
msgs = append(msgs, fmt.Sprintf("On Linux, hostname requires a new UTS namespace to be specified as well"))
}

Expand Down Expand Up @@ -684,15 +662,15 @@ func (v *Validator) rlimitValid(rlimit rspec.LinuxRlimit) (msgs []string) {
msgs = append(msgs, fmt.Sprintf("hard limit of rlimit %s should not be less than soft limit", rlimit.Type))
}

if v.spec.Platform.OS == "linux" {
if v.platform == "linux" {
for _, val := range defaultRlimits {
if val == rlimit.Type {
return
}
}
msgs = append(msgs, fmt.Sprintf("rlimit type %q is invalid", rlimit.Type))
} else {
logrus.Warnf("process.rlimits validation not yet implemented for OS %q", v.spec.Platform.OS)
logrus.Warnf("process.rlimits validation not yet implemented for platform %q", v.platform)
}

return
Expand Down
4 changes: 2 additions & 2 deletions validate/validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func TestCheckRootfsPath(t *testing.T) {
{filepath.Join(tmpBundle, rootfsNonExists), false},
}
for _, c := range cases {
v := NewValidator(&rspec.Spec{Root: rspec.Root{Path: c.val}}, tmpBundle, false)
v := NewValidator(&rspec.Spec{Root: rspec.Root{Path: c.val}}, tmpBundle, false, "linux")
checkErrors(t, "CheckRootfsPath "+c.val, v.CheckRootfsPath(), c.expected)
}
}
Expand All @@ -64,7 +64,7 @@ func TestCheckSemVer(t *testing.T) {
}

for _, c := range cases {
v := NewValidator(&rspec.Spec{Version: c.val}, "", false)
v := NewValidator(&rspec.Spec{Version: c.val}, "", false, "linux")
checkErrors(t, "CheckSemVer "+c.val, v.CheckSemVer(), c.expected)
}
}
Loading