schema: JSON Schema and validator for `config.json`

Conforming to https://tools.ietf.org/html/draft-zyp-json-schema-03
and http://json-schema.org/latest/json-schema-core.html

* Utilizes a number of JSON schema features, including 'pattern'
* Defined primitives, like integers, that we'll use
* Split out definitions for primitives and platform-specific
* Provide a Makefile for:
 - "fmt" target for *.json
 - "validate" target for building the validation tool

Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
This commit is contained in:
Vincent Batts 2016-01-19 11:27:47 -05:00
parent dae09c6a7d
commit cdcabdeb6b
6 changed files with 960 additions and 0 deletions

15
schema/Makefile Normal file
View File

@ -0,0 +1,15 @@
default: help
help:
@echo "Usage: make <target>"
@echo
@echo " * 'fmt' - format the json with indentation"
@echo " * 'validate' - build the validation tool"
fmt:
for i in *.json ; do jq --indent 4 -M . "$${i}" > xx && cat xx > "$${i}" && rm xx ; done
validate: validate.go
go build ./validate.go

239
schema/defs-linux.json Normal file
View File

@ -0,0 +1,239 @@
{
"definitions": {
"SeccompArch": {
"type": "string",
"enum": [
"SCMP_ARCH_X86",
"SCMP_ARCH_X86_64",
"SCMP_ARCH_X32",
"SCMP_ARCH_ARM",
"SCMP_ARCH_AARCH64",
"SCMP_ARCH_MIPS",
"SCMP_ARCH_MIPS64",
"SCMP_ARCH_MIPS64N32",
"SCMP_ARCH_MIPSEL",
"SCMP_ARCH_MIPSEL64",
"SCMP_ARCH_MIPSEL64N32"
]
},
"SeccompAction": {
"type": "string",
"enum": [
"SCMP_ACT_KILL",
"SCMP_ACT_TRAP",
"SCMP_ACT_ERRNO",
"SCMP_ACT_TRACE",
"SCMP_ACT_ALLOW"
]
},
"SeccompOperators": {
"type": "string",
"enum": [
"SCMP_CMP_NE",
"SCMP_CMP_LT",
"SCMP_CMP_LE",
"SCMP_CMP_EQ",
"SCMP_CMP_GE",
"SCMP_CMP_GT",
"SCMP_CMP_MASKED_EQ"
]
},
"SyscallArg": {
"properties": {
"index": {
"$ref": "defs.json#/definitions/uint32"
},
"value": {
"$ref": "defs.json#/definitions/uint64"
},
"valueTwo": {
"$ref": "defs.json#/definitions/uint64"
},
"op": {
"$ref": "#/definitions/SeccompOperators"
}
}
},
"Syscall": {
"properties": {
"name": {
"type": "string"
},
"action": {
"$ref": "#/definitions/SeccompAction"
},
"args": {
"type": "array",
"items": {
"$ref": "#/definitions/SyscallArg"
}
}
}
},
"Capability": {
"description": "Linux process permissions",
"type": "string",
"pattern": "^CAP_([A-Z]|_)+$"
},
"Major": {
"description": "major device number",
"$ref": "defs.json#/definitions/uint16"
},
"Minor": {
"description": "minor device number",
"$ref": "defs.json#/definitions/uint16"
},
"FileMode": {
"description": "File permissions mode (typically an octal value)",
"type": "integer",
"minimum": 0,
"maximum": 512
},
"FilePermissions": {
"type": "string"
},
"FileType": {
"type": "integer"
},
"Device": {
"properties": {
"type": {
"$ref": "#/definitions/FileType"
},
"permissions": {
"$ref": "#/definitions/FilePermissions"
},
"path": {
"$ref": "defs.json#/definitions/FilePath"
},
"fileMode": {
"$ref": "#/definitions/FileMode"
},
"major": {
"$ref": "#/definitions/Major"
},
"minor": {
"$ref": "#/definitions/Minor"
},
"uid": {
"$ref": "defs.json#/definitions/UID"
},
"gid": {
"$ref": "defs.json#/definitions/GID"
}
}
},
"blkioWeight": {
"type": "integer",
"minimum": 10,
"maximum": 1000
},
"blkioWeightPointer": {
"oneOf": [
{
"$ref": "#/definitions/blkioWeight"
},
{
"type": "null"
}
]
},
"blockIODevice": {
"properties": {
"major": {
"$ref": "#/definitions/Major"
},
"minor": {
"$ref": "#/definitions/Minor"
}
},
"required": [
"major",
"minor"
]
},
"blockIODeviceWeight": {
"type": "object",
"allOf": [
{
"$ref": "#/definitions/blockIODevice"
},
{
"properties": {
"weight": {
"$ref": "#/definitions/blkioWeightPointer"
},
"leafWeight": {
"$ref": "#/definitions/blkioWeightPointer"
}
}
}
]
},
"blockIODeviceWeightPointer": {
"oneOf": [
{
"$ref": "#/definitions/blockIODeviceWeight"
},
{
"type": "null"
}
]
},
"blockIODeviceThrottle": {
"allOf": [
{
"$ref": "#/definitions/blockIODevice"
},
{
"properties": {
"rate": {
"$ref": "defs.json#/definitions/uint64Pointer"
}
}
}
]
},
"blockIODeviceThrottlePointer": {
"oneOf": [
{
"$ref": "#/definitions/blockIODeviceThrottle"
},
{
"type": "null"
}
]
},
"NetworkInterfacePriority": {
"properties": {
"name": {
"type": "string"
},
"priority": {
"$ref": "defs.json#/definitions/uint32"
}
}
},
"NamespaceType": {
"type": "string",
"enum": [
"mount",
"pid",
"network",
"uts",
"ipc",
"user"
]
},
"NamespaceReference": {
"properties": {
"type": {
"$ref": "#/definitions/NamespaceType"
},
"path": {
"$ref": "defs.json#/definitions/FilePath"
}
}
}
}
}

160
schema/defs.json Normal file
View File

@ -0,0 +1,160 @@
{
"description": "Definitions used throughout the OpenContainer Specification",
"definitions": {
"int8": {
"type": "integer",
"minimum": -128,
"maximum": 127
},
"int16": {
"type": "integer",
"minimum": -32768,
"maximum": 32767
},
"int32": {
"type": "integer",
"minimum": -2147483648,
"maximum": 2147483647
},
"int64": {
"type": "integer",
"minimum": -9223372036854776000,
"maximum": 9223372036854776000
},
"uint8": {
"type": "integer",
"minimum": 0,
"maximum": 255
},
"uint16": {
"type": "integer",
"minimum": 0,
"maximum": 65535
},
"uint32": {
"type": "integer",
"minimum": 0,
"maximum": 4294967295
},
"uint64": {
"type": "integer",
"minimum": 0,
"maximum": 18446744073709552000
},
"uint16Pointer": {
"oneOf": [
{
"$ref": "#/definitions/uint16"
},
{
"type": "null"
}
]
},
"uint64Pointer": {
"oneOf": [
{
"$ref": "#/definitions/uint64"
},
{
"type": "null"
}
]
},
"stringPointer": {
"oneOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"mapStringString": {
"type": "object",
"patternProperties": {
".{1,}": {
"type": "string"
}
}
},
"UID": {
"$ref": "#/definitions/uint32"
},
"GID": {
"$ref": "#/definitions/uint32"
},
"ArrayOfGIDs": {
"type": "array",
"items": {
"$ref": "#/definitions/GID"
}
},
"ArrayOfStrings": {
"type": "array",
"items": {
"type": "string"
}
},
"FilePath": {
"type": "string"
},
"Env": {
"$ref": "#/definitions/ArrayOfStrings"
},
"Hook": {
"properties": {
"path": {
"$ref": "#/definitions/FilePath"
},
"args": {
"$ref": "#/definitions/ArrayOfStrings"
},
"env": {
"$ref": "#/definitions/Env"
}
}
},
"ArrayOfHooks": {
"type": "array",
"items": {
"$ref": "#/definitions/Hook"
}
},
"IDMapping": {
"properties": {
"hostID": {
"$ref": "#/definitions/uint32"
},
"containerID": {
"$ref": "#/definitions/uint32"
},
"size": {
"$ref": "#/definitions/uint32"
}
}
},
"Mount": {
"properties": {
"source": {
"$ref": "#/definitions/FilePath"
},
"destination": {
"$ref": "#/definitions/FilePath"
},
"options": {
"$ref": "#/definitions/ArrayOfStrings"
},
"type": {
"type": "string"
}
},
"required": [
"destination",
"source",
"type"
]
}
}
}

343
schema/schema-linux.json Normal file
View File

@ -0,0 +1,343 @@
{
"linux": {
"description": "Linux platform-specific configurations",
"id": "https://opencontainers.org/schema/bundle/linux",
"type": "object",
"properties": {
"devices": {
"id": "https://opencontainers.org/schema/bundle/linux/devices",
"oneOf": [
{
"type": "array",
"items": {
"$ref": "defs-linux.json#/definitions/Device"
}
},
{
"type": "null"
}
]
},
"uidMappings": {
"id": "https://opencontainers.org/schema/bundle/linux/uidMappings",
"oneOf": [
{
"type": "array",
"items": {
"$ref": "defs.json#/definitions/IDMapping"
}
},
{
"type": "null"
}
]
},
"gidMappings": {
"id": "https://opencontainers.org/schema/bundle/linux/gidMappings",
"oneOf": [
{
"type": "array",
"items": {
"$ref": "defs.json#/definitions/IDMapping"
}
},
{
"type": "null"
}
]
},
"namespaces": {
"id": "https://opencontainers.org/schema/bundle/linux/namespaces",
"type": "array",
"items": {
"anyOf": [
{
"$ref": "defs-linux.json#/definitions/NamespaceReference"
}
]
}
},
"resources": {
"id": "https://opencontainers.org/schema/bundle/linux/resources",
"type": "object",
"properties": {
"blockIO": {
"id": "https://opencontainers.org/schema/bundle/linux/resources/blockIO",
"type": "object",
"properties": {
"blkioWeight": {
"id": "https://opencontainers.org/schema/bundle/linux/resources/blockIO/blkioWeight",
"$ref": "defs-linux.json#/definitions/blkioWeightPointer"
},
"blkioLeafWeight": {
"id": "https://opencontainers.org/schema/bundle/linux/resources/blockIO/blkioLeafWeight",
"$ref": "defs-linux.json#/definitions/blkioWeightPointer"
},
"blkioThrottleReadBpsDevice": {
"id": "https://opencontainers.org/schema/bundle/linux/resources/blockIO/blkioThrottleReadBpsDevice",
"oneOf": [
{
"type": "array",
"items": [
{
"$ref": "defs-linux.json#/definitions/blockIODeviceThrottlePointer"
}
]
},
{
"type": "null"
}
]
},
"blkioThrottleWriteBpsDevice": {
"id": "https://opencontainers.org/schema/bundle/linux/resources/blockIO/blkioThrottleWriteBpsDevice",
"oneOf": [
{
"type": "array",
"items": [
{
"$ref": "defs-linux.json#/definitions/blockIODeviceThrottlePointer"
}
]
},
{
"type": "null"
}
]
},
"blkioThrottleReadIopsDevice": {
"id": "https://opencontainers.org/schema/bundle/linux/resources/blockIO/blkioThrottleReadIopsDevice",
"oneOf": [
{
"type": "array",
"items": [
{
"$ref": "defs-linux.json#/definitions/blockIODeviceThrottlePointer"
}
]
},
{
"type": "null"
}
]
},
"blkioThrottleWriteIopsDevice": {
"id": "https://opencontainers.org/schema/bundle/linux/resources/blockIO/blkioThrottleWriteIopsDevice",
"oneOf": [
{
"type": "array",
"items": [
{
"$ref": "defs-linux.json#/definitions/blockIODeviceThrottlePointer"
}
]
},
{
"type": "null"
}
]
},
"blkioWeightDevice": {
"id": "https://opencontainers.org/schema/bundle/linux/resources/blockIO/blkioWeightDevice",
"type": "array",
"items": [
{
"$ref": "defs-linux.json#/definitions/blockIODeviceWeightPointer"
}
]
}
}
},
"cpu": {
"id": "https://opencontainers.org/schema/bundle/linux/resources/cpu",
"properties": {
"cpus": {
"id": "https://opencontainers.org/schema/bundle/linux/resources/cpu/cpus",
"$ref": "defs.json#/definitions/stringPointer"
},
"mems": {
"id": "https://opencontainers.org/schema/bundle/linux/resources/cpu/mems",
"$ref": "defs.json#/definitions/stringPointer"
},
"period": {
"id": "https://opencontainers.org/schema/bundle/linux/resources/cpu/period",
"$ref": "defs.json#/definitions/uint64Pointer"
},
"quota": {
"id": "https://opencontainers.org/schema/bundle/linux/resources/cpu/quota",
"$ref": "defs.json#/definitions/uint64Pointer"
},
"realtimePeriod": {
"id": "https://opencontainers.org/schema/bundle/linux/resources/cpu/realtimePeriod",
"$ref": "defs.json#/definitions/uint64Pointer"
},
"realtimeRuntime": {
"id": "https://opencontainers.org/schema/bundle/linux/resources/cpu/realtimeRuntime",
"$ref": "defs.json#/definitions/uint64Pointer"
},
"shares": {
"id": "https://opencontainers.org/schema/bundle/linux/resources/cpu/shares",
"$ref": "defs.json#/definitions/uint64Pointer"
}
},
"type": "object"
},
"disableOOMKiller": {
"id": "https://opencontainers.org/schema/bundle/linux/resources/disableOOMKiller",
"type": "boolean"
},
"hugepageLimits": {
"id": "https://opencontainers.org/schema/bundle/linux/resources/hugepageLimits",
"oneOf": [
{
"type": "object",
"properties": {
"pageSize": {
"type": "string"
},
"limit": {
"$ref": "defs.json#/definitions/uint64"
}
}
},
{
"type": "null"
}
]
},
"memory": {
"id": "https://opencontainers.org/schema/bundle/linux/resources/memory",
"type": "object",
"properties": {
"kernel": {
"id": "https://opencontainers.org/schema/bundle/linux/resources/memory/kernel",
"$ref": "defs.json#/definitions/uint64Pointer"
},
"limit": {
"id": "https://opencontainers.org/schema/bundle/linux/resources/memory/limit",
"$ref": "defs.json#/definitions/uint64Pointer"
},
"reservation": {
"id": "https://opencontainers.org/schema/bundle/linux/resources/memory/reservation",
"$ref": "defs.json#/definitions/uint64Pointer"
},
"swap": {
"id": "https://opencontainers.org/schema/bundle/linux/resources/memory/swap",
"$ref": "defs.json#/definitions/uint64Pointer"
},
"swappiness": {
"id": "https://opencontainers.org/schema/bundle/linux/resources/memory/swappiness",
"$ref": "defs.json#/definitions/uint64Pointer"
}
}
},
"network": {
"id": "https://opencontainers.org/schema/bundle/linux/resources/network",
"type": "object",
"properties": {
"classId": {
"id": "https://opencontainers.org/schema/bundle/linux/resources/network/classId",
"type": "string"
},
"priorities": {
"id": "https://opencontainers.org/schema/bundle/linux/resources/network/priorities",
"oneOf": [
{
"type": "array",
"items": {
"$ref": "defs-linux.json#/definitions/NetworkInterfacePriority"
}
},
{
"type": "null"
}
]
}
}
}
}
},
"rlimits": {
"id": "https://opencontainers.org/schema/bundle/linux/rlimits",
"items": [
{
"id": "https://opencontainers.org/schema/bundle/linux/rlimits/0",
"properties": {
"hard": {
"id": "https://opencontainers.org/schema/bundle/linux/rlimits/0/hard",
"type": "integer"
},
"soft": {
"id": "https://opencontainers.org/schema/bundle/linux/rlimits/0/soft",
"type": "integer"
},
"type": {
"id": "https://opencontainers.org/schema/bundle/linux/rlimits/0/type",
"type": "string",
"pattern": "^RLIMIT_[A-Z]+$"
}
},
"type": "object"
}
],
"type": "array"
},
"cgroupsPath": {
"oneOf": [
{
"type": "null"
},
{
"type": "string"
}
]
},
"rootfsPropagation": {
"id": "https://opencontainers.org/schema/bundle/linux/rootfsPropagation",
"type": "string"
},
"seccomp": {
"id": "https://opencontainers.org/schema/bundle/linux/seccomp",
"properties": {
"defaultAction": {
"id": "https://opencontainers.org/schema/bundle/linux/seccomp/defaultAction",
"type": "string"
},
"architectures": {
"id": "https://opencontainers.org/schema/bundle/linux/seccomp/architectures",
"oneOf": [
{
"type": "array",
"items": {
"$ref": "defs-linux.json#/definitions/SeccompArch"
}
},
{
"type": "null"
}
]
},
"syscalls": {
"id": "https://opencontainers.org/schema/bundle/linux/seccomp/syscalls",
"type": "array",
"items": {
"$ref": "defs-linux.json#/definitions/Syscall"
}
}
},
"type": "object"
},
"sysctl": {
"id": "https://opencontainers.org/schema/bundle/linux/sysctl",
"oneOf": [
{
"$ref": "defs.json#/definitions/mapStringString"
},
{
"type": "null"
}
]
}
}
}
}

158
schema/schema.json Normal file
View File

@ -0,0 +1,158 @@
{
"description": "Schema for OpenContainer bundle configuration file",
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "https://opencontainers.org/schema/bundle",
"type": "object",
"properties": {
"ociVersion": {
"description": "The version of OpenContainer specification configuration complies with",
"id": "https://opencontainers.org/schema/bundle/ociVersion",
"type": "string"
},
"hooks": {
"id": "https://opencontainers.org/schema/bundle/hooks",
"type": "object",
"properties": {
"prestart": {
"$ref": "defs.json#/definitions/ArrayOfHooks"
},
"poststart": {
"$ref": "defs.json#/definitions/ArrayOfHooks"
},
"poststop": {
"$ref": "defs.json#/definitions/ArrayOfHooks"
}
}
},
"annotations": {
"id": "https://opencontainers.org/schema/bundle/linux/sysctl",
"oneOf": [
{
"$ref": "defs.json#/definitions/mapStringString"
},
{
"type": "null"
}
]
},
"hostname": {
"id": "https://opencontainers.org/schema/bundle/hostname",
"type": "string"
},
"mounts": {
"id": "https://opencontainers.org/schema/bundle/mounts",
"type": "array",
"items": {
"$ref": "defs.json#/definitions/Mount"
}
},
"platform": {
"id": "https://opencontainers.org/schema/bundle/platform",
"type": "object",
"required": [
"arch",
"os"
],
"properties": {
"arch": {
"id": "https://opencontainers.org/schema/bundle/platform/arch",
"type": "string"
},
"os": {
"id": "https://opencontainers.org/schema/bundle/platform/os",
"type": "string"
}
}
},
"root": {
"description": "the root filesystem the container's bundle",
"id": "https://opencontainers.org/schema/bundle/root",
"type": "object",
"properties": {
"path": {
"id": "https://opencontainers.org/schema/bundle/root/path",
"$ref": "defs.json#/definitions/FilePath"
},
"readonly": {
"id": "https://opencontainers.org/schema/bundle/root/readonly",
"type": "boolean"
}
}
},
"process": {
"id": "https://opencontainers.org/schema/bundle/process",
"type": "object",
"required": [
"cwd",
"args"
],
"properties": {
"args": {
"id": "https://opencontainers.org/schema/bundle/process/args",
"$ref": "defs.json#/definitions/ArrayOfStrings"
},
"cwd": {
"id": "https://opencontainers.org/schema/bundle/process/cwd",
"type": "string"
},
"env": {
"id": "https://opencontainers.org/schema/bundle/process/env",
"$ref": "defs.json#/definitions/Env"
},
"terminal": {
"id": "https://opencontainers.org/schema/bundle/process/terminal",
"type": "boolean"
},
"user": {
"id": "https://opencontainers.org/schema/bundle/process/user",
"type": "object",
"properties": {
"uid": {
"id": "https://opencontainers.org/schema/bundle/process/user/uid",
"$ref": "defs.json#/definitions/UID"
},
"gid": {
"id": "https://opencontainers.org/schema/bundle/process/user/gid",
"$ref": "defs.json#/definitions/GID"
},
"additionalGids": {
"id": "https://opencontainers.org/schema/bundle/process/user/additionalGids",
"$ref": "defs.json#/definitions/ArrayOfGIDs"
}
}
},
"capabilities": {
"id": "https://opencontainers.org/schema/bundle/process/linux/capabilities",
"type": "array",
"items": {
"$ref": "defs-linux.json#/definitions/Capability"
}
},
"apparmorProfile": {
"id": "https://opencontainers.org/schema/bundle/process/linux/apparmorProfile",
"type": "string"
},
"selinuxProcessLabel": {
"id": "https://opencontainers.org/schema/bundle/process/linux/selinuxProcessLabel",
"type": "string"
},
"noNewPrivileges": {
"id": "https://opencontainers.org/schema/bundle/process/linux/noNewPrivileges",
"type": "boolean"
}
}
},
"linux": {
"$ref": "schema-linux.json#/linux"
}
},
"required": [
"ociVersion",
"platform",
"process",
"root",
"hostname",
"mounts",
"hooks"
]
}

45
schema/validate.go Normal file
View File

@ -0,0 +1,45 @@
package main
import (
"fmt"
"os"
"path/filepath"
"github.com/xeipuuv/gojsonschema"
)
func main() {
if len(os.Args[1:]) != 2 {
fmt.Printf("ERROR: usage is: %s <schema.json> <config.json>", os.Args[0])
os.Exit(1)
}
schemaPath, err := filepath.Abs(os.Args[1])
if err != nil {
fmt.Println(err)
os.Exit(1)
}
documentPath, err := filepath.Abs(os.Args[2])
if err != nil {
fmt.Println(err)
os.Exit(1)
}
schemaLoader := gojsonschema.NewReferenceLoader("file://" + schemaPath)
documentLoader := gojsonschema.NewReferenceLoader("file://" + documentPath)
result, err := gojsonschema.Validate(schemaLoader, documentLoader)
if err != nil {
panic(err.Error())
}
if result.Valid() {
fmt.Printf("The document is valid\n")
} else {
fmt.Printf("The document is not valid. see errors :\n")
for _, desc := range result.Errors() {
fmt.Printf("- %s\n", desc)
}
os.Exit(1)
}
}