Skip to content

Commit 68ec7ee

Browse files
author
Zhou Hao
authored
Merge pull request #451 from liangchenye/runtimeenv
use rfc code in bundle validate
2 parents 3767027 + 2520212 commit 68ec7ee

File tree

24 files changed

+4728
-200
lines changed

24 files changed

+4728
-200
lines changed

cmd/oci-runtime-tool/validate.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package main
22

33
import (
44
"fmt"
5-
"strings"
65

76
"github.com/opencontainers/runtime-tools/validate"
87
"github.com/urfave/cli"
@@ -27,9 +26,8 @@ var bundleValidateCommand = cli.Command{
2726
return err
2827
}
2928

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

3432
}
3533
fmt.Println("Bundle validation succeeded.")

cmd/runtimetest/main.go

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ import (
2222
"github.com/urfave/cli"
2323

2424
"github.com/opencontainers/runtime-tools/cmd/runtimetest/mount"
25-
rfc2119 "github.com/opencontainers/runtime-tools/error"
26-
"github.com/opencontainers/runtime-tools/validate"
25+
rerr "github.com/opencontainers/runtime-tools/error"
2726
)
2827

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

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

327326
mountInfos, err := mount.GetMounts()
328327
if err != nil {
329-
validate.NewError(validate.DefaultFilesystems, err.Error(), spec.Version)
328+
rerr.NewError(rerr.DefaultFilesystems, err.Error(), spec.Version)
330329
}
331330

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

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

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

722721
complianceLevelString := context.String("compliance-level")
723-
complianceLevel, err := rfc2119.ParseLevel(complianceLevelString)
722+
complianceLevel, err := rerr.ParseLevel(complianceLevelString)
724723
if err != nil {
725-
complianceLevel = rfc2119.Must
724+
complianceLevel = rerr.Must
726725
logrus.Warningf("%s, using 'MUST' by default.", err.Error())
727726
}
728727
var validationErrors error
729728
for _, v := range defaultValidations {
730729
err := v.test(spec)
731730
t.Ok(err == nil, v.description)
732731
if err != nil {
733-
if e, ok := err.(*rfc2119.Error); ok && e.Level < complianceLevel {
732+
if e, ok := err.(*rerr.Error); ok && e.Level < complianceLevel {
734733
continue
735734
}
736735
validationErrors = multierror.Append(validationErrors, err)
@@ -742,7 +741,7 @@ func run(context *cli.Context) error {
742741
err := v.test(spec)
743742
t.Ok(err == nil, v.description)
744743
if err != nil {
745-
if e, ok := err.(*rfc2119.Error); ok && e.Level < complianceLevel {
744+
if e, ok := err.(*rerr.Error); ok && e.Level < complianceLevel {
746745
continue
747746
}
748747
validationErrors = multierror.Append(validationErrors, err)

error/error.go renamed to error/rfc2199.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ type Error struct {
4848
Level Level
4949
Reference string
5050
Err error
51+
ErrCode int
5152
}
5253

5354
// ParseLevel takes a string level and returns the OCI compliance level constant.

error/runtime_spec.go

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
package error
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
7+
"github.com/hashicorp/go-multierror"
8+
)
9+
10+
const referenceTemplate = "https://github.com/opencontainers/runtime-spec/blob/v%s/%s"
11+
12+
// SpecErrorCode represents the compliance content.
13+
type SpecErrorCode int
14+
15+
const (
16+
// NonError represents that an input is not an error
17+
NonError SpecErrorCode = iota
18+
// NonRFCError represents that an error is not a rfc2119 error
19+
NonRFCError
20+
21+
// ConfigFileExistence represents the error code of 'config.json' existence test
22+
ConfigFileExistence
23+
// ArtifactsInSingleDir represents the error code of artifacts place test
24+
ArtifactsInSingleDir
25+
26+
// SpecVersion represents the error code of specfication version test
27+
SpecVersion
28+
29+
// RootOnNonHyperV represents the error code of root setting test on non hyper-v containers
30+
RootOnNonHyperV
31+
// RootOnHyperV represents the error code of root setting test on hyper-v containers
32+
RootOnHyperV
33+
// PathFormatOnWindows represents the error code of the path format test on Window
34+
PathFormatOnWindows
35+
// PathName represents the error code of the path name test
36+
PathName
37+
// PathExistence represents the error code of the path existence test
38+
PathExistence
39+
// ReadonlyFilesystem represents the error code of readonly test
40+
ReadonlyFilesystem
41+
// ReadonlyOnWindows represents the error code of readonly setting test on Windows
42+
ReadonlyOnWindows
43+
44+
// DefaultFilesystems represents the error code of default filesystems test
45+
DefaultFilesystems
46+
)
47+
48+
type errorTemplate struct {
49+
Level Level
50+
Reference func(version string) (reference string, err error)
51+
}
52+
53+
var (
54+
containerFormatRef = func(version string) (reference string, err error) {
55+
return fmt.Sprintf(referenceTemplate, version, "bundle.md#container-format"), nil
56+
}
57+
specVersionRef = func(version string) (reference string, err error) {
58+
return fmt.Sprintf(referenceTemplate, version, "config.md#specification-version"), nil
59+
}
60+
rootRef = func(version string) (reference string, err error) {
61+
return fmt.Sprintf(referenceTemplate, version, "config.md#root"), nil
62+
}
63+
defaultFSRef = func(version string) (reference string, err error) {
64+
return fmt.Sprintf(referenceTemplate, version, "config-linux.md#default-filesystems"), nil
65+
}
66+
)
67+
68+
var ociErrors = map[SpecErrorCode]errorTemplate{
69+
// Bundle.md
70+
// Container Format
71+
ConfigFileExistence: errorTemplate{Level: Must, Reference: containerFormatRef},
72+
ArtifactsInSingleDir: errorTemplate{Level: Must, Reference: containerFormatRef},
73+
74+
// Config.md
75+
// Specification Version
76+
SpecVersion: errorTemplate{Level: Must, Reference: specVersionRef},
77+
// Root
78+
RootOnNonHyperV: errorTemplate{Level: Required, Reference: rootRef},
79+
RootOnHyperV: errorTemplate{Level: Must, Reference: rootRef},
80+
// TODO: add tests for 'PathFormatOnWindows'
81+
PathFormatOnWindows: errorTemplate{Level: Must, Reference: rootRef},
82+
PathName: errorTemplate{Level: Should, Reference: rootRef},
83+
PathExistence: errorTemplate{Level: Must, Reference: rootRef},
84+
ReadonlyFilesystem: errorTemplate{Level: Must, Reference: rootRef},
85+
ReadonlyOnWindows: errorTemplate{Level: Must, Reference: rootRef},
86+
87+
// Config-Linux.md
88+
// Default Filesystems
89+
DefaultFilesystems: errorTemplate{Level: Should, Reference: defaultFSRef},
90+
}
91+
92+
// NewError creates an Error referencing a spec violation. The error
93+
// can be cast to a *runtime-tools.error.Error for extracting
94+
// structured information about the level of the violation and a
95+
// reference to the violated spec condition.
96+
//
97+
// A version string (for the version of the spec that was violated)
98+
// must be set to get a working URL.
99+
func NewError(code SpecErrorCode, msg string, version string) (err error) {
100+
template := ociErrors[code]
101+
reference, err := template.Reference(version)
102+
if err != nil {
103+
return err
104+
}
105+
return &Error{
106+
Level: template.Level,
107+
Reference: reference,
108+
Err: errors.New(msg),
109+
ErrCode: int(code),
110+
}
111+
}
112+
113+
// FindError finds an error from a source error (mulitple error) and
114+
// returns the error code if founded.
115+
// If the source error is nil or empty, return NonError.
116+
// If the source error is not a multiple error, return NonRFCError.
117+
func FindError(err error, code SpecErrorCode) SpecErrorCode {
118+
if err == nil {
119+
return NonError
120+
}
121+
122+
if merr, ok := err.(*multierror.Error); ok {
123+
if merr.ErrorOrNil() == nil {
124+
return NonError
125+
}
126+
for _, e := range merr.Errors {
127+
if rfcErr, ok := e.(*Error); ok {
128+
if rfcErr.ErrCode == int(code) {
129+
return code
130+
}
131+
}
132+
}
133+
}
134+
return NonRFCError
135+
}

validate/error.go

Lines changed: 0 additions & 52 deletions
This file was deleted.

0 commit comments

Comments
 (0)