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 allowed value/type checking:

  $ cat config.json
  {
    "ociVersion": "1.0.0-rc6",
    "process": {
      "cwd": "/",
      "args": [
        "sh"
      ],
      "user": {
        "uid": 1,
        "gid": 1
      },
      "rlimits": [{}]
    },
    "root": {
      "path": "rootfs"
    }
  }
  $ ./oci-runtime-tool validate
  3 Errors detected:
  process.rlimits.0.type: Does not match pattern '^RLIMIT_[A-Z]+$'
  'POSIXRlimit.Type' should not be empty.
  rlimit type "" is invalid

without us having to duplicate all the 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-rc2/schema

Signed-off-by: W. Trevor King <wking@tremily.us>
  • Loading branch information
wking committed Jul 19, 2017
1 parent 6210a30 commit c596ee5
Showing 1 changed file with 47 additions and 0 deletions.
47 changes: 47 additions & 0 deletions validate/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/syndtr/gocapability/capability"
"github.com/xeipuuv/gojsonschema"
)

const specConfig = "config.json"
Expand All @@ -41,6 +42,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 @@ -95,6 +98,7 @@ func NewValidatorFromPath(bundlePath string, hostSpecific bool, platform string)

// CheckAll checks all parts of runtime bundle
func (v *Validator) CheckAll() (msgs []string) {
msgs = append(msgs, v.CheckJSONSchema()...)
msgs = append(msgs, v.CheckPlatform()...)
msgs = append(msgs, v.CheckRootfsPath()...)
msgs = append(msgs, v.CheckMandatoryFields()...)
Expand All @@ -109,6 +113,49 @@ func (v *Validator) CheckAll() (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) {
ver, err := semver.Parse(version)
if err != nil {
return "", err
}
configSchemaVersion, err := semver.Parse("1.0.0-rc2") // config.json became config-schema.json in 1.0.0-rc2
if ver.Compare(configSchemaVersion) == -1 {
return "", fmt.Errorf("unsupported configuration version (older than %s)", configSchemaVersion)
}
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() (msgs []string) {
url, err := JSONSchemaURL(v.spec.Version)
if err != nil {
msgs = append(msgs, err.Error())
return msgs
}

schemaLoader := gojsonschema.NewReferenceLoader(url)
documentLoader := gojsonschema.NewGoLoader(v.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
}

// CheckRootfsPath checks status of v.spec.Root.Path
func (v *Validator) CheckRootfsPath() (msgs []string) {
logrus.Debugf("check rootfs path")
Expand Down

0 comments on commit c596ee5

Please sign in to comment.