diff options
Diffstat (limited to 'vendor/github.com/opencontainers/runtime-tools/validate/validate.go')
-rw-r--r-- | vendor/github.com/opencontainers/runtime-tools/validate/validate.go | 278 |
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) } |