Skip to content

Commit

Permalink
Merge pull request #197 from wking/json-schema
Browse files Browse the repository at this point in the history
validate: Check configuration against JSON Schema
  • Loading branch information
Ma Shimiao authored Sep 14, 2017
2 parents 6073aff + 3935592 commit 4882fc1
Show file tree
Hide file tree
Showing 47 changed files with 6,880 additions and 494 deletions.
37 changes: 32 additions & 5 deletions Godeps/Godeps.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

47 changes: 47 additions & 0 deletions validate/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/syndtr/gocapability/capability"

"github.com/opencontainers/runtime-tools/specerror"
"github.com/xeipuuv/gojsonschema"
)

const specConfig = "config.json"
Expand All @@ -47,6 +48,8 @@ var (
"RLIMIT_SIGPENDING",
"RLIMIT_STACK",
}

configSchemaTemplate = "https://raw.githubusercontent.com/opencontainers/runtime-spec/v%s/schema/config-schema.json"
)

// Validator represents a validator for runtime bundle
Expand Down Expand Up @@ -102,6 +105,7 @@ func NewValidatorFromPath(bundlePath string, hostSpecific bool, platform string)
// CheckAll checks all parts of runtime bundle
func (v *Validator) CheckAll() error {
var errs *multierror.Error
errs = multierror.Append(errs, v.CheckJSONSchema())
errs = multierror.Append(errs, v.CheckPlatform())
errs = multierror.Append(errs, v.CheckRoot())
errs = multierror.Append(errs, v.CheckMandatoryFields())
Expand All @@ -114,6 +118,49 @@ func (v *Validator) CheckAll() error {
return errs.ErrorOrNil()
}

// JSONSchemaURL returns the URL for the JSON Schema specifying the
// configuration format. It consumes configSchemaTemplate, but we
// provide it as a function to isolate consumers from inconsistent
// naming as runtime-spec evolves.
func JSONSchemaURL(version string) (url string, err error) {
ver, err := semver.Parse(version)
if err != nil {
return "", err
}
configRenamedToConfigSchemaVersion, err := semver.Parse("1.0.0-rc2") // config.json became config-schema.json in 1.0.0-rc2
if ver.Compare(configRenamedToConfigSchemaVersion) == -1 {
return "", fmt.Errorf("unsupported configuration version (older than %s)", configRenamedToConfigSchemaVersion)
}
return fmt.Sprintf(configSchemaTemplate, version), nil
}

// CheckJSONSchema validates the configuration against the
// runtime-spec JSON Schema, using the version of the schema that
// matches the configuration's declared version.
func (v *Validator) CheckJSONSchema() (errs error) {
url, err := JSONSchemaURL(v.spec.Version)
if err != nil {
errs = multierror.Append(errs, err)
return errs
}

schemaLoader := gojsonschema.NewReferenceLoader(url)
documentLoader := gojsonschema.NewGoLoader(v.spec)
result, err := gojsonschema.Validate(schemaLoader, documentLoader)
if err != nil {
errs = multierror.Append(errs, err)
return errs
}

if !result.Valid() {
for _, resultError := range result.Errors() {
errs = multierror.Append(errs, errors.New(resultError.String()))
}
}

return errs
}

// CheckRoot checks status of v.spec.Root
func (v *Validator) CheckRoot() (errs error) {
logrus.Debugf("check root")
Expand Down
57 changes: 57 additions & 0 deletions validate/validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"runtime"
"testing"

"github.com/hashicorp/go-multierror"
rspec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/stretchr/testify/assert"

Expand All @@ -32,6 +33,62 @@ func TestNewValidator(t *testing.T) {
}
}

func TestJSONSchema(t *testing.T) {
for _, tt := range []struct {
config *rspec.Spec
error string
}{
{
config: &rspec.Spec{},
error: "Version string empty",
},
{
config: &rspec.Spec{
Version: "1.0.1-rc1",
},
error: "Could not read schema from HTTP, response status is 404 Not Found",
},
{
config: &rspec.Spec{
Version: "1.0.0",
},
error: "",
},
{
config: &rspec.Spec{
Version: "1.0.0",
Process: &rspec.Process{},
},
error: "process.args: Invalid type. Expected: array, given: null",
},
{
config: &rspec.Spec{
Version: "1.0.0-rc5",
},
error: "process: process is required",
},
} {
t.Run(tt.error, func(t *testing.T) {
v := &Validator{spec: tt.config}
errs := v.CheckJSONSchema()
if tt.error == "" {
assert.Equal(t, nil, errs)
return
}
merr, ok := errs.(*multierror.Error)
if !ok {
t.Fatalf("non-multierror returned by CheckJSONSchema: %s", errs.Error())
}
for _, err := range merr.Errors {
if err.Error() == tt.error {
return
}
}
assert.Equal(t, tt.error, errs.Error())
})
}
}

func TestCheckRoot(t *testing.T) {
tmpBundle, err := ioutil.TempDir("", "oci-check-rootfspath")
if err != nil {
Expand Down
6 changes: 4 additions & 2 deletions vendor/github.com/davecgh/go-spew/LICENSE

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 8 additions & 7 deletions vendor/github.com/davecgh/go-spew/spew/bypass.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 5 additions & 4 deletions vendor/github.com/davecgh/go-spew/spew/bypasssafe.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions vendor/github.com/davecgh/go-spew/spew/common.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 11 additions & 2 deletions vendor/github.com/davecgh/go-spew/spew/config.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 10 additions & 1 deletion vendor/github.com/davecgh/go-spew/spew/doc.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 4882fc1

Please sign in to comment.