Skip to content

Commit

Permalink
validate: Check configuration against JSON Schema
Browse files Browse the repository at this point in the history
runtime-spec publishes a JSON Schema covering the configuration format
(and other JSON related to runtime-spec) [1].  Reduce duplication of
effort by validating configurations against that schema.  For example
this gives us lots of range checking:

  $ ocitools validate
  ...
  1. linux.resources.oomScoreAdj: Must be greater than or equal to -1000
  ...

without us having to duplicate all the range-input work that the
runtime-spec folks have already done for us.

Only validating the JSON Schema is not sufficient, because
--host-specific (e.g. you're running on a Linux box) and
cross-property constraits (e.g. must create a new UTS namespace if you
set hostname) are difficult/impossible to express in JSON Schema.

[1]: https://github.com/opencontainers/runtime-spec/tree/v1.0.0-rc1/schema

Signed-off-by: W. Trevor King <wking@tremily.us>
  • Loading branch information
wking committed Aug 18, 2016
1 parent ea1d5dd commit d4b604c
Showing 1 changed file with 42 additions and 0 deletions.
42 changes: 42 additions & 0 deletions cmd/ocitools/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/blang/semver"
rspec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/urfave/cli"
"github.com/xeipuuv/gojsonschema"
)

type configCheck func(rspec.Spec, string, bool) []string
Expand Down Expand Up @@ -61,6 +62,8 @@ var (
"CAP_KILL",
"CAP_AUDIT_WRITE",
}

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

var bundleValidateCommand = cli.Command{
Expand Down Expand Up @@ -103,6 +106,7 @@ var bundleValidateCommand = cli.Command{
checks := []configCheck{
checkMandatoryFields,
checkSemVer,
checkJSONSchema,
checkMounts,
checkPlatform,
checkProcess,
Expand Down Expand Up @@ -144,6 +148,44 @@ func checkSemVer(spec rspec.Spec, rootfs string, hostCheck bool) (msgs []string)
return
}

// 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) {
if version != rspec.Version {
return "", fmt.Errorf("unrecognized version %s", version)
}
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 checkJSONSchema(spec rspec.Spec, rootfs string, hostCheck bool) (msgs []string) {
url, err := JSONSchemaURL(spec.Version)
if err != nil {
msgs = append(msgs, err.Error())
return msgs
}

schemaLoader := gojsonschema.NewReferenceLoader(url)
documentLoader := gojsonschema.NewGoLoader(spec)
result, err := gojsonschema.Validate(schemaLoader, documentLoader)
if err != nil {
msgs = append(msgs, fmt.Sprintf("internal error: %s", err.Error()))
return msgs
}

if !result.Valid() {
for _, resultError := range result.Errors() {
msgs = append(msgs, fmt.Sprintf("%s", resultError))
}
}

return msgs
}

func checkPlatform(spec rspec.Spec, rootfs string, hostCheck bool) (msgs []string) {
logrus.Debugf("check platform")

Expand Down

0 comments on commit d4b604c

Please sign in to comment.