diff --git a/cmd/runtimetest/main.go b/cmd/runtimetest/main.go index ec6481b21..33f505ff8 100644 --- a/cmd/runtimetest/main.go +++ b/cmd/runtimetest/main.go @@ -328,7 +328,7 @@ func validateRootFS(spec *rspec.Spec) error { if spec.Root.Readonly { err := testWriteAccess("/") if err == nil { - return specerror.NewError(specerror.ReadonlyFilesystem, fmt.Errorf("rootfs must be readonly"), rspec.Version) + return specerror.NewError(specerror.RootReadonlyImplement, fmt.Errorf("rootfs must be readonly"), rspec.Version) } } diff --git a/specerror/bundle.go b/specerror/bundle.go new file mode 100644 index 000000000..865306cf7 --- /dev/null +++ b/specerror/bundle.go @@ -0,0 +1,31 @@ +// Package specerror implements runtime-spec-specific tooling for +// tracking RFC 2119 violations. +package specerror + +import ( + "fmt" + + rfc2119 "github.com/opencontainers/runtime-tools/error" +) + +// define error codes +const ( + // ConfigInRootBundleDir represents "This REQUIRED file MUST reside in the root of the bundle directory" + ConfigInRootBundleDir = "This REQUIRED file MUST reside in the root of the bundle directory." + // ConfigConstName represents "This REQUIRED file MUST be named `config.json`." + ConfigConstName = "This REQUIRED file MUST be named `config.json`." + // ArtifactsInSingleDir represents "When supplied, while these artifacts MUST all be present in a single directory on the local filesystem, that directory itself is not part of the bundle." + ArtifactsInSingleDir = "When supplied, while these artifacts MUST all be present in a single directory on the local filesystem, that directory itself is not part of the bundle." +) + +var ( + containerFormatRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "bundle.md#container-format"), nil + } +) + +func init() { + register(ConfigInRootBundleDir, rfc2119.Must, containerFormatRef) + register(ConfigConstName, rfc2119.Must, containerFormatRef) + register(ArtifactsInSingleDir, rfc2119.Must, containerFormatRef) +} diff --git a/specerror/config-linux.go b/specerror/config-linux.go new file mode 100644 index 000000000..cafccea0b --- /dev/null +++ b/specerror/config-linux.go @@ -0,0 +1,25 @@ +// Package specerror implements runtime-spec-specific tooling for +// tracking RFC 2119 violations. +package specerror + +import ( + "fmt" + + rfc2119 "github.com/opencontainers/runtime-tools/error" +) + +// define error codes +const ( + // DefaultFilesystems represents "The following filesystems SHOULD be made available in each container's filesystem:" + DefaultFilesystems = "The following filesystems SHOULD be made available in each container's filesystem:" +) + +var ( + defaultFilesystemsRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config-linux.md#default-filesystems"), nil + } +) + +func init() { + register(DefaultFilesystems, rfc2119.Should, defaultFilesystemsRef) +} diff --git a/specerror/config.go b/specerror/config.go new file mode 100644 index 000000000..ba03c68b5 --- /dev/null +++ b/specerror/config.go @@ -0,0 +1,187 @@ +// Package specerror implements runtime-spec-specific tooling for +// tracking RFC 2119 violations. +package specerror + +import ( + "fmt" + + rfc2119 "github.com/opencontainers/runtime-tools/error" +) + +// define error codes +const ( + // SpecVersionInSemVer represents "**`ociVersion`** (string, Required) MUST be in [SemVer v2.0.0][semver-v2.0.0] format and specifies the version of the Open Container Initiative Runtime Specification with which the bundle complies." + SpecVersionInSemVer = "**`ociVersion`** (string, Required) MUST be in [SemVer v2.0.0][semver-v2.0.0] format and specifies the version of the Open Container Initiative Runtime Specification with which the bundle complies." + // RootOnWindowsRequired represents "On Windows, for Windows Server Containers, this field is REQUIRED." + RootOnWindowsRequired = "On Windows, for Windows Server Containers, this field is REQUIRED." + // RootOnHyperVNotSet represents "For [Hyper-V Containers](config-windows.md#hyperv), this field MUST NOT be set." + RootOnHyperVNotSet = "For [Hyper-V Containers](config-windows.md#hyperv), this field MUST NOT be set." + // RootOnNonHyperVRequired represents "On all other platforms, this field is REQUIRED." + RootOnNonHyperVRequired = "On all other platforms, this field is REQUIRED." + // RootPathOnWindowsGUID represents "On Windows, `path` MUST be a [volume GUID path][naming-a-volume]." + RootPathOnWindowsGUID = "On Windows, `path` MUST be a [volume GUID path][naming-a-volume]." + // RootPathOnPosixConvention represents "The value SHOULD be the conventional `rootfs`." + RootPathOnPosixConvention = "The value SHOULD be the conventional `rootfs`." + // RootPathExist represents "A directory MUST exist at the path declared by the field." + RootPathExist = "A directory MUST exist at the path declared by the field." + // RootReadonlyImplement represents "**`readonly`** (bool, OPTIONAL) If true then the root filesystem MUST be read-only inside the container, defaults to false." + RootReadonlyImplement = "**`readonly`** (bool, OPTIONAL) If true then the root filesystem MUST be read-only inside the container, defaults to false." + // RootReadonlyOnWindowsFalse represents "* On Windows, this field MUST be omitted or false." + RootReadonlyOnWindowsFalse = "On Windows, this field MUST be omitted or false." + // MountsInOrder represents "The runtime MUST mount entries in the listed order." + MountsInOrder = "The runtime MUST mount entries in the listed order." + // MountsDestAbs represents "Destination of mount point: path inside container. This value MUST be an absolute path." + MountsDestAbs = "Destination of mount point: path inside container. This value MUST be an absolute path." + // MountsDestOnWindowsNotNested represents "Windows: one mount destination MUST NOT be nested within another mount (e.g., c:\\foo and c:\\foo\\bar)." + MountsDestOnWindowsNotNested = "Windows: one mount destination MUST NOT be nested within another mount (e.g., c:\\foo and c:\\foo\\bar)." + // MountsOptionsOnWindowsROSupport represents "Windows: runtimes MUST support `ro`, mounting the filesystem read-only when `ro` is given." + MountsOptionsOnWindowsROSupport = "Windows: runtimes MUST support `ro`, mounting the filesystem read-only when `ro` is given." + // ProcRequiredAtStart represents "This property is REQUIRED when [`start`](runtime.md#start) is called." + ProcRequiredAtStart = "This property is REQUIRED when [`start`](runtime.md#start) is called." + // ProcessConsoleSizeIgnore represents "Runtimes MUST ignore `consoleSize` if `terminal` is `false` or unset." + ProcessConsoleSizeIgnore = "Runtimes MUST ignore `consoleSize` if `terminal` is `false` or unset." + // ProcCwdAbs represents "** cwd ** (string, REQUIRED) is the working directory that will be set for the executable. This value MUST be an absolute path." + ProcCwdAbs = "** cwd ** (string, REQUIRED) is the working directory that will be set for the executable. This value MUST be an absolute path." + // ProcArgsOneEntryRequired represents "This specification extends the IEEE standard in that at least one entry is REQUIRED, and that entry is used with the same semantics as `execvp`'s *file*." + ProcArgsOneEntryRequired = "This specification extends the IEEE standard in that at least one entry is REQUIRED, and that entry is used with the same semantics as `execvp`'s *file*." + // PosixProcRlimitsTypeGeneError represents "The runtime MUST [generate an error](runtime.md#errors) for any values which cannot be mapped to a relevant kernel interface." + PosixProcRlimitsTypeGeneError = "The runtime MUST [generate an error](runtime.md#errors) for any values which cannot be mapped to a relevant kernel interface." + // PosixProcRlimitsTypeGet represents "For each entry in `rlimits`, a [`getrlimit(3)`][getrlimit.3] on `type` MUST succeed." + PosixProcRlimitsTypeGet = "For each entry in `rlimits`, a [`getrlimit(3)`][getrlimit.3] on `type` MUST succeed." + // PosixProcRlimitsSoftMatchCur represents "`rlim.rlim_cur` MUST match the configured value." + PosixProcRlimitsSoftMatchCur = "`rlim.rlim_cur` MUST match the configured value." + // PosixProcRlimitsHardMatchMax represents "`rlim.rlim_max` MUST match the configured value." + PosixProcRlimitsHardMatchMax = "`rlim.rlim_max` MUST match the configured value." + // PosixProcRlimitsErrorOnDup represents "If `rlimits` contains duplicated entries with same `type`, the runtime MUST [generate an error](runtime.md#errors)." + PosixProcRlimitsErrorOnDup = "If `rlimits` contains duplicated entries with same `type`, the runtime MUST [generate an error](runtime.md#errors)." + // LinuxProcCapError represents "Any value which cannot be mapped to a relevant kernel interface MUST cause an error." + LinuxProcCapError = "Any value which cannot be mapped to a relevant kernel interface MUST cause an error." + // LinuxProcOomScoreAdjSet represents "If `oomScoreAdj` is set, the runtime MUST set `oom_score_adj` to the given value." + LinuxProcOomScoreAdjSet = "If `oomScoreAdj` is set, the runtime MUST set `oom_score_adj` to the given value." + // LinuxProcOomScoreAdjNotSet represents "If `oomScoreAdj` is not set, the runtime MUST NOT change the value of `oom_score_adj`." + LinuxProcOomScoreAdjNotSet = "If `oomScoreAdj` is not set, the runtime MUST NOT change the value of `oom_score_adj`." + // PlatformSpecConfOnWindowsSet represents "This MUST be set if the target platform of this spec is `windows`." + PlatformSpecConfOnWindowsSet = "This MUST be set if the target platform of this spec is `windows`." + // PosixHooksPathAbs represents "This specification extends the IEEE standard in that **`path`** MUST be absolute." + PosixHooksPathAbs = "This specification extends the IEEE standard in that **`path`** MUST be absolute." + // PosixHooksTimeoutPositive represents "If set, `timeout` MUST be greater than zero." + PosixHooksTimeoutPositive = "If set, `timeout` MUST be greater than zero." + // PosixHooksCalledInOrder represents "Hooks MUST be called in the listed order." + PosixHooksCalledInOrder = "Hooks MUST be called in the listed order." + // PosixHooksStateToStdin represents "The [state](runtime.md#state) of the container MUST be passed to hooks over stdin so that they may do work appropriate to the current state of the container." + PosixHooksStateToStdin = "The [state](runtime.md#state) of the container MUST be passed to hooks over stdin so that they may do work appropriate to the current state of the container." + // PrestartTiming represents "The pre-start hooks MUST be called after the [`start`](runtime.md#start) operation is called but [before the user-specified program command is executed](runtime.md#lifecycle)." + PrestartTiming = "The pre-start hooks MUST be called after the [`start`](runtime.md#start) operation is called but [before the user-specified program command is executed](runtime.md#lifecycle)." + // PoststartTiming represents "The post-start hooks MUST be called [after the user-specified process is executed](runtime.md#lifecycle) but before the [`start`](runtime.md#start) operation returns." + PoststartTiming = "The post-start hooks MUST be called [after the user-specified process is executed](runtime.md#lifecycle) but before the [`start`](runtime.md#start) operation returns." + // PoststopTiming represents "The post-stop hooks MUST be called [after the container is deleted](runtime.md#lifecycle) but before the [`delete`](runtime.md#delete) operation returns." + PoststopTiming = "The post-stop hooks MUST be called [after the container is deleted](runtime.md#lifecycle) but before the [`delete`](runtime.md#delete) operation returns." + // AnnotationsKeyValueMap represents "Annotations MUST be a key-value map." + AnnotationsKeyValueMap = "Annotations MUST be a key-value map." + // AnnotationsKeyString represents "Keys MUST be strings." + AnnotationsKeyString = "Keys MUST be strings." + // AnnotationsKeyRequired represents "Keys MUST NOT be an empty string." + AnnotationsKeyRequired = "Keys MUST NOT be an empty string." + // AnnotationsKeyReversedDomain represents "Keys SHOULD be named using a reverse domain notation - e.g. `com.example.myKey`." + AnnotationsKeyReversedDomain = "Keys SHOULD be named using a reverse domain notation - e.g. `com.example.myKey`." + // AnnotationsKeyReservedNS represents "Keys using the `org.opencontainers` namespace are reserved and MUST NOT be used by subsequent specifications." + AnnotationsKeyReservedNS = "Keys using the `org.opencontainers` namespace are reserved and MUST NOT be used by subsequent specifications." + // AnnotationsKeyIgnoreUnknown represents "Implementations that are reading/processing this configuration file MUST NOT generate an error if they encounter an unknown annotation key." + AnnotationsKeyIgnoreUnknown = "Implementations that are reading/processing this configuration file MUST NOT generate an error if they encounter an unknown annotation key." + // AnnotationsValueString represents "Values MUST be strings." + AnnotationsValueString = "Values MUST be strings." + // ExtensibilityIgnoreUnknownProp represents "Runtimes that are reading or processing this configuration file MUST NOT generate an error if they encounter an unknown property." + ExtensibilityIgnoreUnknownProp = "Runtimes that are reading or processing this configuration file MUST NOT generate an error if they encounter an unknown property.\nInstead they MUST ignore unknown properties." + // ValidValues represents "Runtimes that are reading or processing this configuration file MUST generate an error when invalid or unsupported values are encountered." + ValidValues = "Runtimes that are reading or processing this configuration file MUST generate an error when invalid or unsupported values are encountered." +) + +var ( + specificationVersionRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config.md#specification-version"), nil + } + rootRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config.md#root"), nil + } + mountsRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config.md#mounts"), nil + } + processRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config.md#process"), nil + } + posixProcessRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config.md#posix-process"), nil + } + linuxProcessRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config.md#linux-process"), nil + } + platformSpecificConfigurationRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config.md#platform-specific-configuration"), nil + } + posixPlatformHooksRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config.md#posix-platform-hooks"), nil + } + prestartRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config.md#prestart"), nil + } + poststartRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config.md#poststart"), nil + } + poststopRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config.md#poststop"), nil + } + annotationsRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config.md#annotations"), nil + } + extensibilityRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config.md#extensibility"), nil + } + validValuesRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config.md#valid-values"), nil + } +) + +func init() { + register(SpecVersionInSemVer, rfc2119.Must, specificationVersionRef) + register(RootOnWindowsRequired, rfc2119.Required, rootRef) + register(RootOnHyperVNotSet, rfc2119.Must, rootRef) + register(RootOnNonHyperVRequired, rfc2119.Required, rootRef) + register(RootPathOnWindowsGUID, rfc2119.Must, rootRef) + register(RootPathOnPosixConvention, rfc2119.Should, rootRef) + register(RootPathExist, rfc2119.Must, rootRef) + register(RootReadonlyImplement, rfc2119.Must, rootRef) + register(RootReadonlyOnWindowsFalse, rfc2119.Must, rootRef) + register(MountsInOrder, rfc2119.Must, mountsRef) + register(MountsDestAbs, rfc2119.Must, mountsRef) + register(MountsDestOnWindowsNotNested, rfc2119.Must, mountsRef) + register(MountsOptionsOnWindowsROSupport, rfc2119.Must, mountsRef) + register(ProcRequiredAtStart, rfc2119.Required, processRef) + register(ProcessConsoleSizeIgnore, rfc2119.Must, processRef) + register(ProcCwdAbs, rfc2119.Must, processRef) + register(ProcArgsOneEntryRequired, rfc2119.Required, processRef) + register(PosixProcRlimitsTypeGeneError, rfc2119.Must, posixProcessRef) + register(PosixProcRlimitsTypeGet, rfc2119.Must, posixProcessRef) + register(PosixProcRlimitsSoftMatchCur, rfc2119.Must, posixProcessRef) + register(PosixProcRlimitsHardMatchMax, rfc2119.Must, posixProcessRef) + register(PosixProcRlimitsErrorOnDup, rfc2119.Must, posixProcessRef) + register(LinuxProcCapError, rfc2119.Must, linuxProcessRef) + register(LinuxProcOomScoreAdjSet, rfc2119.Must, linuxProcessRef) + register(LinuxProcOomScoreAdjNotSet, rfc2119.Must, linuxProcessRef) + register(PlatformSpecConfOnWindowsSet, rfc2119.Must, platformSpecificConfigurationRef) + register(PosixHooksPathAbs, rfc2119.Must, posixPlatformHooksRef) + register(PosixHooksTimeoutPositive, rfc2119.Must, posixPlatformHooksRef) + register(PosixHooksCalledInOrder, rfc2119.Must, posixPlatformHooksRef) + register(PosixHooksStateToStdin, rfc2119.Must, posixPlatformHooksRef) + register(PrestartTiming, rfc2119.Must, prestartRef) + register(PoststartTiming, rfc2119.Must, poststartRef) + register(PoststopTiming, rfc2119.Must, poststopRef) + register(AnnotationsKeyValueMap, rfc2119.Must, annotationsRef) + register(AnnotationsKeyString, rfc2119.Must, annotationsRef) + register(AnnotationsKeyRequired, rfc2119.Must, annotationsRef) + register(AnnotationsKeyReversedDomain, rfc2119.Should, annotationsRef) + register(AnnotationsKeyReservedNS, rfc2119.Must, annotationsRef) + register(AnnotationsKeyIgnoreUnknown, rfc2119.Must, annotationsRef) + register(AnnotationsValueString, rfc2119.Must, annotationsRef) + register(ExtensibilityIgnoreUnknownProp, rfc2119.Must, extensibilityRef) + register(ValidValues, rfc2119.Must, validValuesRef) +} diff --git a/specerror/error.go b/specerror/error.go index 069cbc1e6..1cfe054c2 100644 --- a/specerror/error.go +++ b/specerror/error.go @@ -13,46 +13,13 @@ const referenceTemplate = "https://github.com/opencontainers/runtime-spec/blob/v // Code represents the spec violation, enumerating both // configuration violations and runtime violations. -type Code int +type Code string const ( // NonError represents that an input is not an error - NonError Code = iota + NonError = "the input is not an error" // NonRFCError represents that an error is not a rfc2119 error - NonRFCError - - // ConfigFileExistence represents the error code of 'config.json' existence test - ConfigFileExistence - // ArtifactsInSingleDir represents the error code of artifacts place test - ArtifactsInSingleDir - - // SpecVersion represents the error code of specfication version test - SpecVersion - - // RootOnNonHyperV represents the error code of root setting test on non hyper-v containers - RootOnNonHyperV - // RootOnHyperV represents the error code of root setting test on hyper-v containers - RootOnHyperV - // PathFormatOnWindows represents the error code of the path format test on Window - PathFormatOnWindows - // PathName represents the error code of the path name test - PathName - // PathExistence represents the error code of the path existence test - PathExistence - // ReadonlyFilesystem represents the error code of readonly test - ReadonlyFilesystem - // ReadonlyOnWindows represents the error code of readonly setting test on Windows - ReadonlyOnWindows - - // DefaultFilesystems represents the error code of default filesystems test - DefaultFilesystems - - // CreateWithID represents the error code of 'create' lifecyle test with 'id' provided - CreateWithID - // CreateWithUniqueID represents the error code of 'create' lifecyle test with unique 'id' provided - CreateWithUniqueID - // CreateNewContainer represents the error code 'create' lifecyle test that creates new container - CreateNewContainer + NonRFCError = "the error is not a rfc2119 error" ) type errorTemplate struct { @@ -79,52 +46,14 @@ type LevelErrors struct { Error *multierror.Error } -var ( - containerFormatRef = func(version string) (reference string, err error) { - return fmt.Sprintf(referenceTemplate, version, "bundle.md#container-format"), nil - } - specVersionRef = func(version string) (reference string, err error) { - return fmt.Sprintf(referenceTemplate, version, "config.md#specification-version"), nil - } - rootRef = func(version string) (reference string, err error) { - return fmt.Sprintf(referenceTemplate, version, "config.md#root"), nil - } - defaultFSRef = func(version string) (reference string, err error) { - return fmt.Sprintf(referenceTemplate, version, "config-linux.md#default-filesystems"), nil - } - runtimeCreateRef = func(version string) (reference string, err error) { - return fmt.Sprintf(referenceTemplate, version, "runtime.md#create"), nil +var ociErrors = map[Code]errorTemplate{} + +func register(code Code, level rfc2119.Level, ref func(versiong string) (string, error)) { + if _, ok := ociErrors[code]; ok { + panic(fmt.Sprintf("should not regist a same code twice: %s", code)) } -) -var ociErrors = map[Code]errorTemplate{ - // Bundle.md - // Container Format - ConfigFileExistence: {Level: rfc2119.Must, Reference: containerFormatRef}, - ArtifactsInSingleDir: {Level: rfc2119.Must, Reference: containerFormatRef}, - - // Config.md - // Specification Version - SpecVersion: {Level: rfc2119.Must, Reference: specVersionRef}, - // Root - RootOnNonHyperV: {Level: rfc2119.Required, Reference: rootRef}, - RootOnHyperV: {Level: rfc2119.Must, Reference: rootRef}, - // TODO: add tests for 'PathFormatOnWindows' - PathFormatOnWindows: {Level: rfc2119.Must, Reference: rootRef}, - PathName: {Level: rfc2119.Should, Reference: rootRef}, - PathExistence: {Level: rfc2119.Must, Reference: rootRef}, - ReadonlyFilesystem: {Level: rfc2119.Must, Reference: rootRef}, - ReadonlyOnWindows: {Level: rfc2119.Must, Reference: rootRef}, - - // Config-Linux.md - // Default Filesystems - DefaultFilesystems: {Level: rfc2119.Should, Reference: defaultFSRef}, - - // Runtime.md - // Create - CreateWithID: {Level: rfc2119.Must, Reference: runtimeCreateRef}, - CreateWithUniqueID: {Level: rfc2119.Must, Reference: runtimeCreateRef}, - CreateNewContainer: {Level: rfc2119.Must, Reference: runtimeCreateRef}, + ociErrors[code] = errorTemplate{Level: level, Reference: ref} } // Error returns the error message with specification reference. diff --git a/specerror/runtime.go b/specerror/runtime.go new file mode 100644 index 000000000..5bf3593e2 --- /dev/null +++ b/specerror/runtime.go @@ -0,0 +1,31 @@ +// Package specerror implements runtime-spec-specific tooling for +// tracking RFC 2119 violations. +package specerror + +import ( + "fmt" + + rfc2119 "github.com/opencontainers/runtime-tools/error" +) + +// define error codes +const ( + // CreateWithBundlePathAndID represents "This operation MUST [generate an error](#errors) if it is not provided a path to the bundle and the container ID to associate with the container." + CreateWithBundlePathAndID = "This operation MUST [generate an error](#errors) if it is not provided a path to the bundle and the container ID to associate with the container." + // CreateWithUniqueID represents "If the ID provided is not unique across all containers within the scope of the runtime, or is not valid in any other way, the implementation MUST [generate an error](#errors) and a new container MUST NOT be created." + CreateWithUniqueID = "If the ID provided is not unique across all containers within the scope of the runtime, or is not valid in any other way, the implementation MUST [generate an error](#errors) and a new container MUST NOT be created." + // CreateNewContainer represents "This operation MUST create a new container." + CreateNewContainer = "This operation MUST create a new container." +) + +var ( + createRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "runtime.md#create"), nil + } +) + +func init() { + register(CreateWithBundlePathAndID, rfc2119.Must, createRef) + register(CreateWithUniqueID, rfc2119.Must, createRef) + register(CreateNewContainer, rfc2119.Must, createRef) +} diff --git a/validate/validate.go b/validate/validate.go index 418ac07b3..82a18d70a 100644 --- a/validate/validate.go +++ b/validate/validate.go @@ -94,7 +94,7 @@ func NewValidatorFromPath(bundlePath string, hostSpecific bool, platform string) configPath := filepath.Join(bundlePath, specConfig) content, err := ioutil.ReadFile(configPath) if err != nil { - return Validator{}, specerror.NewError(specerror.ConfigFileExistence, err, rspec.Version) + return Validator{}, specerror.NewError(specerror.ConfigInRootBundleDir, err, rspec.Version) } if !utf8.Valid(content) { return Validator{}, fmt.Errorf("%q is not encoded in UTF-8", configPath) @@ -173,13 +173,13 @@ func (v *Validator) CheckRoot() (errs error) { if v.platform == "windows" && v.spec.Windows != nil && v.spec.Windows.HyperV != nil { if v.spec.Root != nil { errs = multierror.Append(errs, - specerror.NewError(specerror.RootOnHyperV, fmt.Errorf("for Hyper-V containers, Root must not be set"), rspec.Version)) + specerror.NewError(specerror.RootOnHyperVNotSet, fmt.Errorf("for Hyper-V containers, Root must not be set"), rspec.Version)) return } return } else if v.spec.Root == nil { errs = multierror.Append(errs, - specerror.NewError(specerror.RootOnNonHyperV, fmt.Errorf("for non-Hyper-V containers, Root must be set"), rspec.Version)) + specerror.NewError(specerror.RootOnNonHyperVRequired, fmt.Errorf("for non-Hyper-V containers, Root must be set"), rspec.Version)) return } @@ -189,12 +189,12 @@ func (v *Validator) CheckRoot() (errs error) { errs = multierror.Append(errs, err) } else if !matched { errs = multierror.Append(errs, - specerror.NewError(specerror.PathFormatOnWindows, fmt.Errorf("root.path is %q, but it MUST be a volume GUID path when target platform is windows", v.spec.Root.Path), rspec.Version)) + specerror.NewError(specerror.RootPathOnWindowsGUID, fmt.Errorf("root.path is %q, but it MUST be a volume GUID path when target platform is windows", v.spec.Root.Path), rspec.Version)) } if v.spec.Root.Readonly { errs = multierror.Append(errs, - specerror.NewError(specerror.ReadonlyOnWindows, fmt.Errorf("root.readonly field MUST be omitted or false when target platform is windows"), rspec.Version)) + specerror.NewError(specerror.RootReadonlyOnWindowsFalse, fmt.Errorf("root.readonly field MUST be omitted or false when target platform is windows"), rspec.Version)) } return @@ -208,7 +208,7 @@ func (v *Validator) CheckRoot() (errs error) { if filepath.Base(v.spec.Root.Path) != "rootfs" { errs = multierror.Append(errs, - specerror.NewError(specerror.PathName, fmt.Errorf("path name should be the conventional 'rootfs'"), rspec.Version)) + specerror.NewError(specerror.RootPathOnPosixConvention, fmt.Errorf("path name should be the conventional 'rootfs'"), rspec.Version)) } var rootfsPath string @@ -228,10 +228,10 @@ func (v *Validator) CheckRoot() (errs error) { if fi, err := os.Stat(rootfsPath); err != nil { errs = multierror.Append(errs, - specerror.NewError(specerror.PathExistence, fmt.Errorf("cannot find the root path %q", rootfsPath), rspec.Version)) + specerror.NewError(specerror.RootPathExist, fmt.Errorf("cannot find the root path %q", rootfsPath), rspec.Version)) } else if !fi.IsDir() { errs = multierror.Append(errs, - specerror.NewError(specerror.PathExistence, fmt.Errorf("root.path %q is not a directory", rootfsPath), rspec.Version)) + specerror.NewError(specerror.RootPathExist, fmt.Errorf("root.path %q is not a directory", rootfsPath), rspec.Version)) } rootParent := filepath.Dir(absRootPath) @@ -251,7 +251,7 @@ func (v *Validator) CheckSemVer() (errs error) { _, err := semver.Parse(version) if err != nil { errs = multierror.Append(errs, - specerror.NewError(specerror.SpecVersion, fmt.Errorf("%q is not valid SemVer: %s", version, err.Error()), rspec.Version)) + specerror.NewError(specerror.SpecVersionInSemVer, fmt.Errorf("%q is not valid SemVer: %s", version, err.Error()), rspec.Version)) } if version != rspec.Version { errs = multierror.Append(errs, fmt.Errorf("validate currently only handles version %s, but the supplied configuration targets %s", rspec.Version, version)) diff --git a/validate/validate_test.go b/validate/validate_test.go index 2497bad63..82f7b7b6d 100644 --- a/validate/validate_test.go +++ b/validate/validate_test.go @@ -151,18 +151,18 @@ func TestCheckRoot(t *testing.T) { platform string expected specerror.Code }{ - {rspec.Spec{Windows: &rspec.Windows{HyperV: &rspec.WindowsHyperV{}}, Root: &rspec.Root{}}, "windows", specerror.RootOnHyperV}, + {rspec.Spec{Windows: &rspec.Windows{HyperV: &rspec.WindowsHyperV{}}, Root: &rspec.Root{}}, "windows", specerror.RootOnHyperVNotSet}, {rspec.Spec{Windows: &rspec.Windows{HyperV: &rspec.WindowsHyperV{}}, Root: nil}, "windows", specerror.NonError}, - {rspec.Spec{Windows: &rspec.Windows{}, Root: &rspec.Root{Path: filepath.Join(tmpBundle, "rootfs")}}, "windows", specerror.PathFormatOnWindows}, + {rspec.Spec{Windows: &rspec.Windows{}, Root: &rspec.Root{Path: filepath.Join(tmpBundle, "rootfs")}}, "windows", specerror.RootPathOnWindowsGUID}, {rspec.Spec{Windows: &rspec.Windows{}, Root: &rspec.Root{Path: "\\\\?\\Volume{ec84d99e-3f02-11e7-ac6c-00155d7682cf}\\"}}, "windows", specerror.NonError}, - {rspec.Spec{Root: nil}, "linux", specerror.RootOnNonHyperV}, - {rspec.Spec{Root: &rspec.Root{Path: "maverick-rootfs"}}, "linux", specerror.PathName}, + {rspec.Spec{Root: nil}, "linux", specerror.RootOnNonHyperVRequired}, + {rspec.Spec{Root: &rspec.Root{Path: "maverick-rootfs"}}, "linux", specerror.RootPathOnPosixConvention}, {rspec.Spec{Root: &rspec.Root{Path: "rootfs"}}, "linux", specerror.NonError}, - {rspec.Spec{Root: &rspec.Root{Path: filepath.Join(tmpBundle, rootfsNonExists)}}, "linux", specerror.PathExistence}, - {rspec.Spec{Root: &rspec.Root{Path: filepath.Join(tmpBundle, rootfsNonDir)}}, "linux", specerror.PathExistence}, + {rspec.Spec{Root: &rspec.Root{Path: filepath.Join(tmpBundle, rootfsNonExists)}}, "linux", specerror.RootPathExist}, + {rspec.Spec{Root: &rspec.Root{Path: filepath.Join(tmpBundle, rootfsNonDir)}}, "linux", specerror.RootPathExist}, {rspec.Spec{Root: &rspec.Root{Path: filepath.Join(tmpBundle, "rootfs")}}, "linux", specerror.NonError}, {rspec.Spec{Root: &rspec.Root{Path: "rootfs/rootfs"}}, "linux", specerror.ArtifactsInSingleDir}, - {rspec.Spec{Root: &rspec.Root{Readonly: true}}, "windows", specerror.ReadonlyOnWindows}, + {rspec.Spec{Root: &rspec.Root{Readonly: true}}, "windows", specerror.RootReadonlyOnWindowsFalse}, } for _, c := range cases { v := NewValidator(&c.val, tmpBundle, false, c.platform) @@ -179,7 +179,7 @@ func TestCheckSemVer(t *testing.T) { {rspec.Version, specerror.NonError}, //FIXME: validate currently only handles rpsec.Version {"0.0.1", specerror.NonRFCError}, - {"invalid", specerror.SpecVersion}, + {"invalid", specerror.SpecVersionInSemVer}, } for _, c := range cases { diff --git a/validation/validation_test.go b/validation/validation_test.go index 775190da7..6661c6d62 100644 --- a/validation/validation_test.go +++ b/validation/validation_test.go @@ -116,7 +116,7 @@ func TestValidateCreate(t *testing.T) { errExpected bool err error }{ - {"", false, specerror.NewError(specerror.CreateWithID, fmt.Errorf("create MUST generate an error if the ID is not provided"), rspecs.Version)}, + {"", false, specerror.NewError(specerror.CreateWithBundlePathAndID, fmt.Errorf("create MUST generate an error if the ID is not provided"), rspecs.Version)}, {containerID, true, specerror.NewError(specerror.CreateNewContainer, fmt.Errorf("create MUST create a new container"), rspecs.Version)}, {containerID, false, specerror.NewError(specerror.CreateWithUniqueID, fmt.Errorf("create MUST generate an error if the ID provided is not unique"), rspecs.Version)}, }