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
6 changes: 2 additions & 4 deletions cmd/oci-runtime-tool/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package main

import (
"fmt"
"strings"

"github.com/opencontainers/runtime-tools/validate"
"github.com/urfave/cli"
Expand All @@ -27,9 +26,8 @@ var bundleValidateCommand = cli.Command{
return err
}

errMsgs := v.CheckAll()
if len(errMsgs) > 0 {
return fmt.Errorf("%d Errors detected:\n%s", len(errMsgs), strings.Join(errMsgs, "\n"))
if err := v.CheckAll(); err != nil {
return err

}
fmt.Println("Bundle validation succeeded.")
Expand Down
17 changes: 8 additions & 9 deletions cmd/runtimetest/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ import (
"github.com/urfave/cli"

"github.com/opencontainers/runtime-tools/cmd/runtimetest/mount"
rfc2119 "github.com/opencontainers/runtime-tools/error"
"github.com/opencontainers/runtime-tools/validate"
rerr "github.com/opencontainers/runtime-tools/error"
)

// PrGetNoNewPrivs isn't exposed in Golang so we define it ourselves copying the value from
Expand Down Expand Up @@ -314,7 +313,7 @@ func validateRootFS(spec *rspec.Spec) error {
if spec.Root.Readonly {
err := testWriteAccess("/")
if err == nil {
return fmt.Errorf("Rootfs should be readonly")
return rerr.NewError(rerr.ReadonlyFilesystem, "Rootfs should be readonly", rspec.Version)
}
}

Expand All @@ -326,7 +325,7 @@ func validateDefaultFS(spec *rspec.Spec) error {

mountInfos, err := mount.GetMounts()
if err != nil {
validate.NewError(validate.DefaultFilesystems, err.Error(), spec.Version)
rerr.NewError(rerr.DefaultFilesystems, err.Error(), spec.Version)
}

mountsMap := make(map[string]string)
Expand All @@ -336,7 +335,7 @@ func validateDefaultFS(spec *rspec.Spec) error {

for fs, fstype := range defaultFS {
if !(mountsMap[fs] == fstype) {
return validate.NewError(validate.DefaultFilesystems, fmt.Sprintf("%v SHOULD exist and expected type is %v", fs, fstype), spec.Version)
return rerr.NewError(rerr.DefaultFilesystems, fmt.Sprintf("%v SHOULD exist and expected type is %v", fs, fstype), rspec.Version)
}
}

Expand Down Expand Up @@ -720,17 +719,17 @@ func run(context *cli.Context) error {
t.Header(0)

complianceLevelString := context.String("compliance-level")
complianceLevel, err := rfc2119.ParseLevel(complianceLevelString)
complianceLevel, err := rerr.ParseLevel(complianceLevelString)
if err != nil {
complianceLevel = rfc2119.Must
complianceLevel = rerr.Must
logrus.Warningf("%s, using 'MUST' by default.", err.Error())
}
var validationErrors error
for _, v := range defaultValidations {
err := v.test(spec)
t.Ok(err == nil, v.description)
if err != nil {
if e, ok := err.(*rfc2119.Error); ok && e.Level < complianceLevel {
if e, ok := err.(*rerr.Error); ok && e.Level < complianceLevel {
continue
}
validationErrors = multierror.Append(validationErrors, err)
Expand All @@ -742,7 +741,7 @@ func run(context *cli.Context) error {
err := v.test(spec)
t.Ok(err == nil, v.description)
if err != nil {
if e, ok := err.(*rfc2119.Error); ok && e.Level < complianceLevel {
if e, ok := err.(*rerr.Error); ok && e.Level < complianceLevel {
continue
}
validationErrors = multierror.Append(validationErrors, err)
Expand Down
1 change: 1 addition & 0 deletions error/error.go → error/rfc2199.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ type Error struct {
Level Level
Reference string
Err error
ErrCode int
}

// ParseLevel takes a string level and returns the OCI compliance level constant.
Expand Down
135 changes: 135 additions & 0 deletions error/runtime_spec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package error

import (
"errors"
"fmt"

"github.com/hashicorp/go-multierror"
)

const referenceTemplate = "https://github.com/opencontainers/runtime-spec/blob/v%s/%s"

// SpecErrorCode represents the compliance content.
type SpecErrorCode int

const (
// NonError represents that an input is not an error
NonError SpecErrorCode = iota
// 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
)

type errorTemplate struct {
Level Level
Reference func(version string) (reference string, err 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
}
)

var ociErrors = map[SpecErrorCode]errorTemplate{
// Bundle.md
// Container Format
ConfigFileExistence: errorTemplate{Level: Must, Reference: containerFormatRef},
ArtifactsInSingleDir: errorTemplate{Level: Must, Reference: containerFormatRef},

// Config.md
// Specification Version
SpecVersion: errorTemplate{Level: Must, Reference: specVersionRef},
// Root
RootOnNonHyperV: errorTemplate{Level: Required, Reference: rootRef},
RootOnHyperV: errorTemplate{Level: Must, Reference: rootRef},
// TODO: add tests for 'PathFormatOnWindows'
PathFormatOnWindows: errorTemplate{Level: Must, Reference: rootRef},
PathName: errorTemplate{Level: Should, Reference: rootRef},
PathExistence: errorTemplate{Level: Must, Reference: rootRef},
ReadonlyFilesystem: errorTemplate{Level: Must, Reference: rootRef},
ReadonlyOnWindows: errorTemplate{Level: Must, Reference: rootRef},

// Config-Linux.md
// Default Filesystems
DefaultFilesystems: errorTemplate{Level: Should, Reference: defaultFSRef},
}

// NewError creates an Error referencing a spec violation. The error
// can be cast to a *runtime-tools.error.Error for extracting
// structured information about the level of the violation and a
// reference to the violated spec condition.
//
// A version string (for the version of the spec that was violated)
// must be set to get a working URL.
func NewError(code SpecErrorCode, msg string, version string) (err error) {
template := ociErrors[code]
reference, err := template.Reference(version)
if err != nil {
return err
}
return &Error{
Level: template.Level,
Reference: reference,
Err: errors.New(msg),
ErrCode: int(code),
}
}

// FindError finds an error from a source error (mulitple error) and
// returns the error code if founded.
// If the source error is nil or empty, return NonError.
// If the source error is not a multiple error, return NonRFCError.
func FindError(err error, code SpecErrorCode) SpecErrorCode {
if err == nil {
return NonError
}

if merr, ok := err.(*multierror.Error); ok {
if merr.ErrorOrNil() == nil {
return NonError
}
for _, e := range merr.Errors {
if rfcErr, ok := e.(*Error); ok {
if rfcErr.ErrCode == int(code) {
return code
}
}
}
}
return NonRFCError
}
52 changes: 0 additions & 52 deletions validate/error.go

This file was deleted.

Loading