Skip to content

Commit

Permalink
complete spec errors of config.md
Browse files Browse the repository at this point in the history
Signed-off-by: Liang Chenye <liangchenye@huawei.com>
  • Loading branch information
liangchenye committed Sep 5, 2017
1 parent 06bd267 commit 27503c5
Show file tree
Hide file tree
Showing 4 changed files with 209 additions and 58 deletions.
2 changes: 1 addition & 1 deletion cmd/runtimetest/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,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)
}
}

Expand Down
237 changes: 194 additions & 43 deletions specerror/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,90 @@ const (
// 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
// 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 Runtime Specification with which the bundle complies."
SpecVersionInSemVer
// RootOnWindowsRequired represents "On Windows, for Windows Server Containers, this field is REQUIRED."
RootOnWindowsRequired
// RootOnHyperVNotSet represents "For [Hyper-V Containers](config-windows.md#hyperv), this field MUST NOT be set."
RootOnHyperVNotSet
// RootOnNonHyperVRequired represents "On all other platforms, this field is REQUIRED."
RootOnNonHyperVRequired
// RootPathOnWindowsGUID represents "* On Windows, `path` MUST be a [volume GUID path][naming-a-volume]."
RootPathOnWindowsGUID
// RootPathOnPosixConvention represents "The value SHOULD be the conventional `rootfs`."
RootPathOnPosixConvention
// RootPathExist represents "A directory MUST exist at the path declared by the field."
RootPathExist
// RootReadonlyImplement represents "* **`readonly`** (bool, OPTIONAL) If true then the root filesystem MUST be read-only inside the container, defaults to false."
RootReadonlyImplement
// RootReadonlyOnWindowsFalse represents "* On Windows, this field MUST be omitted or false."
RootReadonlyOnWindowsFalse
// MountsInOrder represents "The runtime MUST mount entries in the listed order."
MountsInOrder
// MountsDestAbs represents "This value MUST be an absolute path."
MountsDestAbs
// MountsDestOnWindowsNotNested represents "* Windows: one mount destination MUST NOT be nested within another mount (e.g., c:\\foo and c:\\foo\\bar)."
MountsDestOnWindowsNotNested
// MountsOptionsOnWindowsROSupport represents "* Windows: runtimes MUST support `ro`, mounting the filesystem read-only when `ro` is given."
MountsOptionsOnWindowsROSupport
// ProcRequiredAtStart represents "This property is REQUIRED when [`start`](runtime.md#start) is called."
ProcRequiredAtStart
// ProcConsoleSizeIgnore represents "Runtimes MUST ignore `consoleSize` if `terminal` is `false` or unset."
ProcConsoleSizeIgnore
// ProcCwdAbs represents "This value MUST be an absolute path."
ProcCwdAbs
// 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
// PosixProcRlimitsTypeError represents "The runtime MUST [generate an error](runtime.md#errors) for any values which cannot be mapped to a relevant kernel interface"
PosixProcRlimitsTypeError
// PosixProcRlimitsTypeGet represents "For each entry in `rlimits`, a [`getrlimit(3)`][getrlimit.3] on `type` MUST succeed."
PosixProcRlimitsTypeGet
// PosixProcRlimitsSoftMatchCur represents "`rlim.rlim_cur` MUST match the configured value."
PosixProcRlimitsSoftMatchCur
// PosixProcRlimitsHardMatchMax represents "`rlim.rlim_max` MUST match the configured value."
PosixProcRlimitsHardMatchMax
// PosixProcRlimitsErrorOnDup represents "If `rlimits` contains duplicated entries with same `type`, the runtime MUST [generate an error](runtime.md#errors)."
PosixProcRlimitsErrorOnDup
// LinuxProcCapError represents "Any value which cannot be mapped to a relevant kernel interface MUST cause an error."
LinuxProcCapError
// LinuxProcOomScoreAdjSet represents "If `oomScoreAdj` is set, the runtime MUST set `oom_score_adj` to the given value."
LinuxProcOomScoreAdjSet
// LinuxProcOomScoreAdjNotSet represents "If `oomScoreAdj` is not set, the runtime MUST NOT change the value of `oom_score_adj`."
LinuxProcOomScoreAdjNotSet
// PlatformSpecConfOnWindowsSet represents "This MUST be set if the target platform of this spec is `windows`."
PlatformSpecConfOnWindowsSet
// PosixHooksPathAbs represents "This specification extends the IEEE standard in that **`path`** MUST be absolute."
PosixHooksPathAbs
// PosixHooksTimeoutPositive represents "If set, `timeout` MUST be greater than zero."
PosixHooksTimeoutPositive
// PosixHooksCalledInOrder represents "Hooks MUST be called in the listed order."
PosixHooksCalledInOrder
// 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
// 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
// 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
// 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
// AnnotationsKeyValueMap represents "Annotations MUST be a key-value map."
AnnotationsKeyValueMap
// AnnotationsKeyString represents "Keys MUST be strings."
AnnotationsKeyString
// AnnotationsKeyRequired represents "Keys MUST NOT be an empty string."
AnnotationsKeyRequired
// AnnotationsKeyReversedDomain represents "Keys SHOULD be named using a reverse domain notation - e.g. `com.example.myKey`."
AnnotationsKeyReversedDomain
// AnnotationsKeyReservedNS represents "Keys using the `org.opencontainers` namespace are reserved and MUST NOT be used by subsequent specifications."
AnnotationsKeyReservedNS
// AnnotationsKeyIgnoreUnknown represents "Implementations that are reading/processing this configuration file MUST NOT generate an error if they encounter an unknown annotation key."
AnnotationsKeyIgnoreUnknown
// AnnotationsValueString represents "Values MUST be strings."
AnnotationsValueString
// ExtensibilityIgnoreUnknownProp represents "Runtimes that are reading or processing this configuration file MUST NOT generate an error if they encounter an unknown property."
ExtensibilityIgnoreUnknownProp
// ValidValuesError represents "Runtimes that are reading or processing this configuration file MUST generate an error when invalid or unsupported values are encountered."
ValidValuesError

// DefaultFilesystems represents the error code of default filesystems test
DefaultFilesystems
Expand All @@ -55,56 +122,140 @@ const (
CreateNewContainer
)

type errorTemplate struct {
Level rfc2119.Level
Reference func(version string) (reference string, err error)
}

// Error represents a runtime-spec violation.
type Error struct {
// Err holds the RFC 2119 violation.
Err rfc2119.Error

// Code is a matchable holds a Code
Code Code
}

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) {

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
}
posixProcRef = func(version string) (reference string, err error) {
return fmt.Sprintf(referenceTemplate, version, "config.md#posix-process"), nil
}
linuxProcRef = 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
}

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
}
)

type errorTemplate struct {
Level rfc2119.Level
Reference func(version string) (reference string, err error)
}

// Error represents a runtime-spec violation.
type Error struct {
// Err holds the RFC 2119 violation.
Err rfc2119.Error

// Code is a matchable holds a Code
Code 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},
// config.md
// Specification version
SpecVersionInSemVer: {Level: rfc2119.Must, Reference: specificationVersionRef},
// 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},
RootOnWindowsRequired: {Level: rfc2119.Required, Reference: rootRef},
RootOnHyperVNotSet: {Level: rfc2119.Must, Reference: rootRef},
RootOnNonHyperVRequired: {Level: rfc2119.Required, Reference: rootRef},
RootPathOnWindowsGUID: {Level: rfc2119.Must, Reference: rootRef},
RootPathOnPosixConvention: {Level: rfc2119.Should, Reference: rootRef},
RootPathExist: {Level: rfc2119.Must, Reference: rootRef},
RootReadonlyImplement: {Level: rfc2119.Must, Reference: rootRef},
RootReadonlyOnWindowsFalse: {Level: rfc2119.Must, Reference: rootRef},
// Mounts
MountsInOrder: {Level: rfc2119.Must, Reference: mountsRef},
MountsDestAbs: {Level: rfc2119.Must, Reference: mountsRef},
MountsDestOnWindowsNotNested: {Level: rfc2119.Must, Reference: mountsRef},
MountsOptionsOnWindowsROSupport: {Level: rfc2119.Must, Reference: mountsRef},
// Proc
ProcRequiredAtStart: {Level: rfc2119.Required, Reference: processRef},
ProcConsoleSizeIgnore: {Level: rfc2119.Must, Reference: processRef},
ProcCwdAbs: {Level: rfc2119.Must, Reference: processRef},
ProcArgsOneEntryRequired: {Level: rfc2119.Required, Reference: processRef},
// POSIX process
PosixProcRlimitsTypeError: {Level: rfc2119.Must, Reference: posixProcRef},
PosixProcRlimitsTypeGet: {Level: rfc2119.Must, Reference: posixProcRef},
PosixProcRlimitsSoftMatchCur: {Level: rfc2119.Must, Reference: posixProcRef},
PosixProcRlimitsHardMatchMax: {Level: rfc2119.Must, Reference: posixProcRef},
PosixProcRlimitsErrorOnDup: {Level: rfc2119.Must, Reference: posixProcRef},
// Linux Proc
LinuxProcCapError: {Level: rfc2119.Must, Reference: linuxProcRef},
LinuxProcOomScoreAdjSet: {Level: rfc2119.Must, Reference: linuxProcRef},
LinuxProcOomScoreAdjNotSet: {Level: rfc2119.Must, Reference: linuxProcRef},
// Platform-specific configuration
PlatformSpecConfOnWindowsSet: {Level: rfc2119.Must, Reference: platformSpecificConfigurationRef},
// POSIX-platform Hooks
PosixHooksPathAbs: {Level: rfc2119.Must, Reference: posixPlatformHooksRef},
PosixHooksTimeoutPositive: {Level: rfc2119.Must, Reference: posixPlatformHooksRef},
PosixHooksCalledInOrder: {Level: rfc2119.Must, Reference: posixPlatformHooksRef},
PosixHooksStateToStdin: {Level: rfc2119.Must, Reference: posixPlatformHooksRef},
// Prestart
PrestartTiming: {Level: rfc2119.Must, Reference: prestartRef},
// Poststart
PoststartTiming: {Level: rfc2119.Must, Reference: poststartRef},
// Poststop
PoststopTiming: {Level: rfc2119.Must, Reference: poststopRef},
// Annotations
AnnotationsKeyValueMap: {Level: rfc2119.Must, Reference: annotationsRef},
AnnotationsKeyString: {Level: rfc2119.Must, Reference: annotationsRef},
AnnotationsKeyRequired: {Level: rfc2119.Must, Reference: annotationsRef},
AnnotationsKeyReversedDomain: {Level: rfc2119.Should, Reference: annotationsRef},
AnnotationsKeyReservedNS: {Level: rfc2119.Must, Reference: annotationsRef},
AnnotationsKeyIgnoreUnknown: {Level: rfc2119.Must, Reference: annotationsRef},
AnnotationsValueString: {Level: rfc2119.Must, Reference: annotationsRef},
// Extensibility
ExtensibilityIgnoreUnknownProp: {Level: rfc2119.Must, Reference: extensibilityRef},
// Valid values
ValidValuesError: {Level: rfc2119.Must, Reference: validValuesRef},

// Config-Linux.md
// Default Filesystems
Expand Down
14 changes: 7 additions & 7 deletions validate/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,13 +120,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
}

Expand All @@ -138,7 +138,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
Expand All @@ -158,10 +158,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)
Expand All @@ -173,7 +173,7 @@ func (v *Validator) CheckRoot() (errs error) {
if v.platform == "windows" {
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))
}
}

Expand All @@ -188,7 +188,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))
Expand Down
Loading

0 comments on commit 27503c5

Please sign in to comment.