summaryrefslogtreecommitdiff
path: root/vendor/github.com/opencontainers/runtime-tools/validate/validate.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/opencontainers/runtime-tools/validate/validate.go')
-rw-r--r--vendor/github.com/opencontainers/runtime-tools/validate/validate.go278
1 files changed, 61 insertions, 217 deletions
diff --git a/vendor/github.com/opencontainers/runtime-tools/validate/validate.go b/vendor/github.com/opencontainers/runtime-tools/validate/validate.go
index 1030099df..e2e820979 100644
--- a/vendor/github.com/opencontainers/runtime-tools/validate/validate.go
+++ b/vendor/github.com/opencontainers/runtime-tools/validate/validate.go
@@ -13,7 +13,6 @@ import (
"regexp"
"runtime"
"strings"
- "syscall"
"unicode"
"unicode/utf8"
@@ -115,6 +114,7 @@ func (v *Validator) CheckAll() error {
errs = multierror.Append(errs, v.CheckMounts())
errs = multierror.Append(errs, v.CheckProcess())
errs = multierror.Append(errs, v.CheckLinux())
+ errs = multierror.Append(errs, v.CheckAnnotations())
if v.platform == "linux" || v.platform == "solaris" {
errs = multierror.Append(errs, v.CheckHooks())
}
@@ -142,6 +142,8 @@ func JSONSchemaURL(version string) (url string, err error) {
// runtime-spec JSON Schema, using the version of the schema that
// matches the configuration's declared version.
func (v *Validator) CheckJSONSchema() (errs error) {
+ logrus.Debugf("check JSON schema")
+
url, err := JSONSchemaURL(v.spec.Version)
if err != nil {
errs = multierror.Append(errs, err)
@@ -169,16 +171,21 @@ func (v *Validator) CheckJSONSchema() (errs error) {
func (v *Validator) CheckRoot() (errs error) {
logrus.Debugf("check root")
- if v.platform == "windows" && v.spec.Windows != nil && v.spec.Windows.HyperV != nil {
- if v.spec.Root != nil {
+ if v.platform == "windows" && v.spec.Windows != nil {
+ if v.spec.Windows.HyperV != nil {
+ if v.spec.Root != nil {
+ errs = multierror.Append(errs,
+ specerror.NewError(specerror.RootOnHyperVNotSet, fmt.Errorf("for Hyper-V containers, Root must not be set"), rspec.Version))
+ }
+ return
+ } else if v.spec.Root == nil {
errs = multierror.Append(errs,
- specerror.NewError(specerror.RootOnHyperVNotSet, fmt.Errorf("for Hyper-V containers, Root must not be set"), rspec.Version))
+ specerror.NewError(specerror.RootOnWindowsRequired, fmt.Errorf("on Windows, for Windows Server Containers, this field is REQUIRED"), rspec.Version))
return
}
- return
- } else if v.spec.Root == nil {
+ } else if v.platform != "windows" && v.spec.Root == nil {
errs = multierror.Append(errs,
- specerror.NewError(specerror.RootOnNonHyperVRequired, fmt.Errorf("for non-Hyper-V containers, Root must be set"), rspec.Version))
+ specerror.NewError(specerror.RootOnNonWindowsRequired, fmt.Errorf("on all other platforms, this field is REQUIRED"), rspec.Version))
return
}
@@ -570,6 +577,11 @@ func (v *Validator) CheckPlatform() (errs error) {
return
}
+ if v.HostSpecific && v.platform != runtime.GOOS {
+ errs = multierror.Append(errs, fmt.Errorf("platform %q differs from the host %q, skipping host-specific checks", v.platform, runtime.GOOS))
+ v.HostSpecific = false
+ }
+
if v.platform == "windows" {
if v.spec.Windows == nil {
errs = multierror.Append(errs,
@@ -583,189 +595,6 @@ func (v *Validator) CheckPlatform() (errs error) {
return
}
-// CheckLinux checks v.spec.Linux
-func (v *Validator) CheckLinux() (errs error) {
- logrus.Debugf("check linux")
-
- if v.spec.Linux == nil {
- return
- }
-
- var nsTypeList = map[rspec.LinuxNamespaceType]struct {
- num int
- newExist bool
- }{
- rspec.PIDNamespace: {0, false},
- rspec.NetworkNamespace: {0, false},
- rspec.MountNamespace: {0, false},
- rspec.IPCNamespace: {0, false},
- rspec.UTSNamespace: {0, false},
- rspec.UserNamespace: {0, false},
- rspec.CgroupNamespace: {0, false},
- }
-
- for index := 0; index < len(v.spec.Linux.Namespaces); index++ {
- ns := v.spec.Linux.Namespaces[index]
- if ns.Path != "" && !osFilepath.IsAbs(v.platform, ns.Path) {
- errs = multierror.Append(errs, specerror.NewError(specerror.NSPathAbs, fmt.Errorf("namespace.path %q is not an absolute path", ns.Path), rspec.Version))
- }
-
- tmpItem := nsTypeList[ns.Type]
- tmpItem.num = tmpItem.num + 1
- if tmpItem.num > 1 {
- errs = multierror.Append(errs, specerror.NewError(specerror.NSErrorOnDup, fmt.Errorf("duplicated namespace %q", ns.Type), rspec.Version))
- }
-
- if len(ns.Path) == 0 {
- tmpItem.newExist = true
- }
- nsTypeList[ns.Type] = tmpItem
- }
-
- if (len(v.spec.Linux.UIDMappings) > 0 || len(v.spec.Linux.GIDMappings) > 0) && !nsTypeList[rspec.UserNamespace].newExist {
- errs = multierror.Append(errs, errors.New("the UID/GID mappings requires a new User namespace to be specified as well"))
- }
-
- for k := range v.spec.Linux.Sysctl {
- if strings.HasPrefix(k, "net.") && !nsTypeList[rspec.NetworkNamespace].newExist {
- errs = multierror.Append(errs, fmt.Errorf("sysctl %v requires a new Network namespace to be specified as well", k))
- }
- if strings.HasPrefix(k, "fs.mqueue.") {
- if !nsTypeList[rspec.MountNamespace].newExist || !nsTypeList[rspec.IPCNamespace].newExist {
- errs = multierror.Append(errs, fmt.Errorf("sysctl %v requires a new IPC namespace and Mount namespace to be specified as well", k))
- }
- }
- }
-
- if v.platform == "linux" && !nsTypeList[rspec.UTSNamespace].newExist && v.spec.Hostname != "" {
- errs = multierror.Append(errs, fmt.Errorf("on Linux, hostname requires a new UTS namespace to be specified as well"))
- }
-
- // Linux devices validation
- devList := make(map[string]bool)
- devTypeList := make(map[string]bool)
- for index := 0; index < len(v.spec.Linux.Devices); index++ {
- device := v.spec.Linux.Devices[index]
- if !deviceValid(device) {
- errs = multierror.Append(errs, fmt.Errorf("device %v is invalid", device))
- }
-
- if _, exists := devList[device.Path]; exists {
- errs = multierror.Append(errs, fmt.Errorf("device %s is duplicated", device.Path))
- } else {
- var rootfsPath string
- if filepath.IsAbs(v.spec.Root.Path) {
- rootfsPath = v.spec.Root.Path
- } else {
- rootfsPath = filepath.Join(v.bundlePath, v.spec.Root.Path)
- }
- absPath := filepath.Join(rootfsPath, device.Path)
- fi, err := os.Stat(absPath)
- if os.IsNotExist(err) {
- devList[device.Path] = true
- } else if err != nil {
- errs = multierror.Append(errs, err)
- } else {
- fStat, ok := fi.Sys().(*syscall.Stat_t)
- if !ok {
- errs = multierror.Append(errs, specerror.NewError(specerror.DevicesAvailable,
- fmt.Errorf("cannot determine state for device %s", device.Path), rspec.Version))
- continue
- }
- var devType string
- switch fStat.Mode & syscall.S_IFMT {
- case syscall.S_IFCHR:
- devType = "c"
- case syscall.S_IFBLK:
- devType = "b"
- case syscall.S_IFIFO:
- devType = "p"
- default:
- devType = "unmatched"
- }
- if devType != device.Type || (devType == "c" && device.Type == "u") {
- errs = multierror.Append(errs, specerror.NewError(specerror.DevicesFileNotMatch,
- fmt.Errorf("unmatched %s already exists in filesystem", device.Path), rspec.Version))
- continue
- }
- if devType != "p" {
- dev := fStat.Rdev
- major := (dev >> 8) & 0xfff
- minor := (dev & 0xff) | ((dev >> 12) & 0xfff00)
- if int64(major) != device.Major || int64(minor) != device.Minor {
- errs = multierror.Append(errs, specerror.NewError(specerror.DevicesFileNotMatch,
- fmt.Errorf("unmatched %s already exists in filesystem", device.Path), rspec.Version))
- continue
- }
- }
- if device.FileMode != nil {
- expectedPerm := *device.FileMode & os.ModePerm
- actualPerm := fi.Mode() & os.ModePerm
- if expectedPerm != actualPerm {
- errs = multierror.Append(errs, specerror.NewError(specerror.DevicesFileNotMatch,
- fmt.Errorf("unmatched %s already exists in filesystem", device.Path), rspec.Version))
- continue
- }
- }
- if device.UID != nil {
- if *device.UID != fStat.Uid {
- errs = multierror.Append(errs, specerror.NewError(specerror.DevicesFileNotMatch,
- fmt.Errorf("unmatched %s already exists in filesystem", device.Path), rspec.Version))
- continue
- }
- }
- if device.GID != nil {
- if *device.GID != fStat.Gid {
- errs = multierror.Append(errs, specerror.NewError(specerror.DevicesFileNotMatch,
- fmt.Errorf("unmatched %s already exists in filesystem", device.Path), rspec.Version))
- continue
- }
- }
- }
- }
-
- // unify u->c when comparing, they are synonyms
- var devID string
- if device.Type == "u" {
- devID = fmt.Sprintf("%s:%d:%d", "c", device.Major, device.Minor)
- } else {
- devID = fmt.Sprintf("%s:%d:%d", device.Type, device.Major, device.Minor)
- }
-
- if _, exists := devTypeList[devID]; exists {
- logrus.Warnf("type:%s, major:%d and minor:%d for linux devices is duplicated", device.Type, device.Major, device.Minor)
- } else {
- devTypeList[devID] = true
- }
- }
-
- if v.spec.Linux.Resources != nil {
- errs = multierror.Append(errs, v.CheckLinuxResources())
- }
-
- for _, maskedPath := range v.spec.Linux.MaskedPaths {
- if !strings.HasPrefix(maskedPath, "/") {
- errs = multierror.Append(errs,
- specerror.NewError(
- specerror.MaskedPathsAbs,
- fmt.Errorf("maskedPath %v is not an absolute path", maskedPath),
- rspec.Version))
- }
- }
-
- for _, readonlyPath := range v.spec.Linux.ReadonlyPaths {
- if !strings.HasPrefix(readonlyPath, "/") {
- errs = multierror.Append(errs,
- specerror.NewError(
- specerror.ReadonlyPathsAbs,
- fmt.Errorf("readonlyPath %v is not an absolute path", readonlyPath),
- rspec.Version))
- }
- }
-
- return
-}
-
// CheckLinuxResources checks v.spec.Linux.Resources
func (v *Validator) CheckLinuxResources() (errs error) {
logrus.Debugf("check linux resources")
@@ -817,6 +646,44 @@ func (v *Validator) CheckLinuxResources() (errs error) {
}
}
+ if r.BlockIO != nil && r.BlockIO.WeightDevice != nil {
+ for i, weightDevice := range r.BlockIO.WeightDevice {
+ if weightDevice.Weight == nil && weightDevice.LeafWeight == nil {
+ errs = multierror.Append(errs,
+ specerror.NewError(
+ specerror.BlkIOWeightOrLeafWeightExist,
+ fmt.Errorf("linux.resources.blockIO.weightDevice[%d] specifies neither weight nor leafWeight", i),
+ rspec.Version))
+ }
+ }
+ }
+
+ return
+}
+
+// CheckAnnotations checks v.spec.Annotations
+func (v *Validator) CheckAnnotations() (errs error) {
+ logrus.Debugf("check annotations")
+
+ reversedDomain := regexp.MustCompile(`^[A-Za-z]{2,6}(\.[A-Za-z0-9-]{1,63})+$`)
+ for key := range v.spec.Annotations {
+ if strings.HasPrefix(key, "org.opencontainers") {
+ errs = multierror.Append(errs,
+ specerror.NewError(
+ specerror.AnnotationsKeyReservedNS,
+ fmt.Errorf("key %q is reserved", key),
+ rspec.Version))
+ }
+
+ if !reversedDomain.MatchString(key) {
+ errs = multierror.Append(errs,
+ specerror.NewError(
+ specerror.AnnotationsKeyReversedDomain,
+ fmt.Errorf("key %q SHOULD be named using a reverse domain notation", key),
+ rspec.Version))
+ }
+ }
+
return
}
@@ -843,17 +710,6 @@ func CapValid(c string, hostSpecific bool) error {
return nil
}
-// LastCap return last cap of system
-func LastCap() capability.Cap {
- last := capability.CAP_LAST_CAP
- // hack for RHEL6 which has no /proc/sys/kernel/cap_last_cap
- if last == capability.Cap(63) {
- last = capability.CAP_BLOCK_SUSPEND
- }
-
- return last
-}
-
func envValid(env string) bool {
items := strings.Split(env, "=")
if len(items) < 2 {
@@ -896,22 +752,6 @@ func (v *Validator) rlimitValid(rlimit rspec.POSIXRlimit) (errs error) {
return
}
-func deviceValid(d rspec.LinuxDevice) bool {
- switch d.Type {
- case "b", "c", "u":
- if d.Major <= 0 || d.Minor <= 0 {
- return false
- }
- case "p":
- if d.Major != 0 || d.Minor != 0 {
- return false
- }
- default:
- return false
- }
- return true
-}
-
func isStruct(t reflect.Type) bool {
return t.Kind() == reflect.Struct
}
@@ -990,5 +830,9 @@ func checkMandatory(obj interface{}) (errs error) {
func (v *Validator) CheckMandatoryFields() error {
logrus.Debugf("check mandatory fields")
+ if v.spec == nil {
+ return fmt.Errorf("Spec can't be nil")
+ }
+
return checkMandatory(v.spec)
}