Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

validate: Check configuration against JSON Schema #197

Merged
merged 2 commits into from
Sep 14, 2017
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
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