diff --git a/.github/validate.py b/.github/validate.py index 981b965..24c33bf 100644 --- a/.github/validate.py +++ b/.github/validate.py @@ -9,16 +9,20 @@ here = os.path.abspath(__file__) root = os.path.dirname(os.path.dirname(here)) -schema_file = os.path.join(root, "definition-schema.json") +# Validation for the compspec.json files, a compatibility group schema, +# is done with an existing standard, json graph format +schema_file = os.path.join(root, "json-graph-schema_v2.json") +example_schema_file = os.path.join(root, "schema.json") -def recursive_find(base, pattern="compspec.json"): + +def recursive_find(base, basename="compspec.json"): """ Find all compspec.json below a root """ for root, _, filenames in os.walk(base): for filename in filenames: fullpath = os.path.join(root, filename) - if re.search(pattern, fullpath): + if filename == basename: yield fullpath @@ -38,11 +42,20 @@ def main(root): specs = recursive_find(root) schema = read_json(schema_file) + example_schema = read_json(example_schema_file) + for spec_file in specs: print(f"⭐️ Validating spec {spec_file}") spec = read_json(spec_file) jsonschema.validate(spec, schema=schema) + # Validate examples + for example in os.listdir(os.path.join(root, "example")): + fullpath = os.path.join(root, "example", example) + print(f"⭐️ Validating example {example}") + spec = read_json(fullpath) + jsonschema.validate(spec, schema=example_schema) + if __name__ == "__main__": if len(sys.argv) > 1: diff --git a/README.md b/README.md index 66f4f56..e129c96 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,22 @@ # Compspec -This is a prototype repository for compatibility specifications that are being worked on by the [OCI compatibility working group](https://github.com/opencontainers/wg-image-compatibility). While that work is underway (and the structure and format of these metadata to be determined. For the time being we have defined: +This is a prototype repository for compatibility specifications that are being worked on by the [OCI compatibility working group](https://github.com/opencontainers/wg-image-compatibility). While that work is underway (and the structure and format of these metadata to be determined. For the time being we have defined two things: + +- A **compatibility schema** is a graph (nodes and edges) that defines a space of metadata and relationships for compatibility attributes +- A **compatibility spec** is a specific extraction of these metadata attributes for a given application or container image ## JSON Schema Specifications - - [schema.json](schema.json) is used to validate the format of a json defining compatibiilty. - - [definition-schema.json](definition-schema.json) is to validate the format of the keys for each namespace (in the subdirectories here) + - The [JGF schema](https://github.com/jsongraph/json-graph-specification) version 2.0 is used to validate the compatibility schemas (compspec.json) files, which are essentially graphs with nodes and edges. Every node is required to be present in the graph. + - The [schema.json](schema.json) is used to validate a compatibility spec using one or more compatibility schemas -Both of the above are based on [Proposal C](https://github.com/opencontainers/wg-image-compatibility/pull/8) of the Image Compatibility working group, and everything is subject to change. This repository is for prototyping only. +Both of the above are based on proposals [C](https://github.com/opencontainers/wg-image-compatibility/pull/8) and [D](https://github.com/opencontainers/wg-image-compatibility/pull/9) of the Image Compatibility working group, with a stronger orientation toward D to honor the graph. This, however, means that everything is subject to change. This repository is for prototyping only! ## Organization The different subdirectories of compatibility families (sets of metadata owned by different groups). -Likely these metadata can be moved to be owned properly by the group. They are all kept here for the time being for ease of access. Also for the time being, we have represented the entire set of labels (and smaller namespaces) for one compatibilty family (e.g., supercontainers) in one JSON file, and of course this is subject to change. I am also keeping things simple - for now each compatibility family has different groups that can define one or more key value pairs, and those pairs must be strings. This means that numbers will need to be parsed from strings by any respective tool. +Likely these metadata can be moved to be owned properly by the group. They are all kept here for the time being for ease of access. Also for the time being, we have represented the entire set of labels (and smaller namespaces) for one compatibilty family (e.g., supercontainers) in one JSON file, and of course this is subject to change. ## History diff --git a/archspec/compspec.json b/archspec/compspec.json index 76f2988..c52104f 100644 --- a/archspec/compspec.json +++ b/archspec/compspec.json @@ -1,14 +1,50 @@ { - "compatibilities": { - "io.archspec.cpu": { - "version": "0.0.0", - "annotations": [ - "family", - "model", - "target", - "vendor" - ] - } + "graph": { + "id": "io.archspec", + "type": "compspec", + "label": "compatibilities", + "nodes": { + "cpu": { + "label": "central processing unit (cpu)" + }, + "cpu.family": { + "label": "cpu family" + }, + "cpu.model": { + "label": "cpu model" + }, + "cpu.target": { + "label": "cpu target" + }, + "cpu.vendor": { + "label": "cpu vendor" + } + }, + "edges": [ + { + "source": "cpu", + "target": "cpu.family", + "relation": "contains" + }, + { + "source": "cpu", + "target": "cpu.model", + "relation": "contains" + }, + { + "source": "cpu", + "target": "cpu.target", + "relation": "contains" + }, + { + "source": "cpu", + "target": "cpu.vendor", + "relation": "contains" + } + ], + "metadata": { + "version": "0.0.0", + "source": "https://github.com/supercontainers/compspec" } + } } - diff --git a/definition-schema.json b/definition-schema.json deleted file mode 100644 index be69517..0000000 --- a/definition-schema.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "Schema for the definitions of the known labels", - "type": "object", - "additionalProperties": false, - "properties": { - "compatibilities": { - "type": "object", - "patternProperties": { - "([\\w]*)": { - "properties": { - "version": { - "$comment": "Version of the metadata namespace", - "type": "string" - }, - "annotations": { - "$comment": "Acceptable keys for a given namespace.", - "type": "array", - "items": { - "type": "string" - } - } - } - } - } - } - } -} diff --git a/example/compatibility-spec.json b/example/compatibility-spec.json new file mode 100644 index 0000000..b75eda2 --- /dev/null +++ b/example/compatibility-spec.json @@ -0,0 +1,33 @@ +{ + "version": "0.0.0", + "kind": "CompatibilitySpec", + "metadata": { + "name": "lammps-prototype" + }, + "compatibilities": [ + { + "name": "io.archspec", + "version": "0.0.0", + "schema": "https://raw.githubusercontent.com/supercontainers/compspec/main/archspec/compspec.json", + "attributes": { + "cpu.model": "13th Gen Intel(R) Core(TM) i5-1335U", + "cpu.target": "amd64", + "cpu.vendor": "GenuineIntel" + } + }, + { + "name": "org.supercontainers", + "version": "0.0.0", + "schema": "https://raw.githubusercontent.com/supercontainers/compspec/main/supercontainers/compspec.json", + "attributes": { + "mpi.implementation": "mpich", + "mpi.version": "4.1.1", + "os.name": "Ubuntu 22.04.3 LTS", + "os.release": "22.04.3", + "os.vendor": "ubuntu", + "os.version": "22.04", + "hardware.gpu.available": "yes" + } + } + ] +} diff --git a/json-graph-schema_v2.json b/json-graph-schema_v2.json new file mode 100644 index 0000000..9ce7399 --- /dev/null +++ b/json-graph-schema_v2.json @@ -0,0 +1,138 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "http://jsongraphformat.info/v2.1/json-graph-schema.json", + "title": "JSON Graph Schema", + "oneOf": [ + { + "type": "object", + "properties": { + "graph": { "$ref": "#/definitions/graph" } + }, + "additionalProperties": false, + "required": [ + "graph" + ] + }, + { + "type": "object", + "properties": { + "graphs": { + "type": "array", + "items": { "$ref": "#/definitions/graph" } + } + }, + "additionalProperties": false + } + ], + "definitions": { + "graph": { + "oneOf": [ + { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { "type": "string" }, + "label": { "type": "string" }, + "directed": { "type": [ "boolean" ], "default": true }, + "type": { "type": "string" }, + "metadata": { "type": [ "object" ] }, + "nodes": { + "type": "object", + "additionalProperties": { "$ref": "#/definitions/node" } + }, + "edges": { + "type": [ "array" ], + "items": { "$ref": "#/definitions/edge" } + } + } + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { "type": "string" }, + "label": { "type": "string" }, + "directed": { "type": [ "boolean" ], "default": true }, + "type": { "type": "string" }, + "metadata": { "type": [ "object" ] }, + "nodes": { + "type": "object", + "additionalProperties": { "$ref": "#/definitions/node" } + }, + "hyperedges": { + "type": [ "array" ], + "items": { "$ref": "#/definitions/directedhyperedge" } + } + } + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { "type": "string" }, + "label": { "type": "string" }, + "directed": { "type": [ "boolean" ], "enum": [false] }, + "type": { "type": "string" }, + "metadata": { "type": [ "object" ] }, + "nodes": { + "type": "object", + "additionalProperties": { "$ref": "#/definitions/node" } + }, + "hyperedges": { + "type": [ "array" ], + "items": { "$ref": "#/definitions/undirectedhyperedge" } + } + }, + "required": [ "directed" ] + } + ] + }, + "node": { + "type": "object", + "properties": { + "label": { "type": "string" }, + "metadata": { "type": "object" }, + "additionalProperties": false + } + }, + "edge": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { "type": "string" }, + "source": { "type": "string" }, + "target": { "type": "string" }, + "relation": { "type": "string" }, + "directed": { "type": [ "boolean" ], "default": true }, + "label": { "type": "string" }, + "metadata": { "type": [ "object" ] } + }, + "required": [ "source", "target" ] + }, + "directedhyperedge": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { "type": "string" }, + "source": { "type": "array", "items": { "type": "string" } }, + "target": { "type": "array", "items": { "type": "string" } }, + "relation": { "type": "string" }, + "label": { "type": "string" }, + "metadata": { "type": [ "object" ] } + }, + "required": [ "source", "target" ] + }, + "undirectedhyperedge": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { "type": "string" }, + "nodes": { "type": "array", "items": { "type": "string" } }, + "relation": { "type": "string" }, + "label": { "type": "string" }, + "metadata": { "type": [ "object" ] } + }, + "required": [ "nodes" ] + } + } +} diff --git a/schema.json b/schema.json index 7fe587a..3e8683b 100644 --- a/schema.json +++ b/schema.json @@ -4,24 +4,53 @@ "type": "object", "additionalProperties": false, "properties": { - "compatibilities": { + "version": { + "$comment": "Version of the compatibility spec", + "type": "string" + }, + "kind": { + "$comment": "kind of compatibility spec", + "type": "string" + }, + "metadata": { + "$comment": "metadata for the compatiblity spec", "type": "object", - "patternProperties": { - "([\\w]*)": { - "properties": { - "version": { - "$comment": "Version of the metadata namespace", - "type": "string" - }, - "annotations": { - "$comment": "Key value pairs for a given namespace.", - "type": "array", - "items": { - "type": "object", - "patternProperties": { - "\\w[\\w-]*": { - "type": "string" - } + "additionalProperties": true, + "properties": { + "name": { + "type": "string" + } + }, + "required": [ + "name" + ] + }, + "compatibilities": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": ["name", "version", "schema", "attributes"], + "properties": { + "name": { + "$comment": "Name of the compatibility schema", + "type": "string" + }, + "version": { + "$comment": "Version of the compatibility schema", + "type": "string" + }, + "schema": { + "$comment": "web accessible public URL of the compatibility schema compspec.json", + "type": "string" + }, + "attributes": { + "$comment": "Key value pairs for a given namespace.", + "type": "object", + "properties": { + "patternProperties": { + "\\w[\\w-]*": { + "type": "string" } } } diff --git a/supercontainers/compspec.json b/supercontainers/compspec.json index cd4dc59..0474b6c 100644 --- a/supercontainers/compspec.json +++ b/supercontainers/compspec.json @@ -1,43 +1,168 @@ { - "compatibilities": { - "org.supercontainers.mpi": { - "version": "0.0.0", - "annotations": [ - "implementation", - "version", - "portability.optimization", - "porability.mode" - ] - }, - "org.supercontainers.os": { - "version": "0.0.0", - "annotations": [ - "name", - "release", - "vendor", - "version" - ] - }, - "org.supercontainers.hardware.gpu": { - "version": "0.0.0", - "annotations": [ - "enabled", - "driver.version", - "cuda.version", - "architecture" - ] - }, - "org.supercontainers.communication": { - "version": "0.0.0", - "annotations": [ - "framework" - ] - }, - "org.supercontainers.libfabric": { - "version": "0.0.0", - "annotations": [ - "abi.version" - ] - } + "graph": { + "id": "org.supercontainers", + "type": "compspec", + "label": "compatibilities", + "nodes": { + "mpi": { + "label": "message passing interface (mpi)" + }, + "mpi.implementation": { + "label": "mpi implementation" + }, + "mpi.version": { + "label": "mpi version" + }, + "mpi.portability": { + "label": "mpi portability attributes" + }, + "mpi.portability.optimization": { + "label": "mpi portability optimization" + }, + "mpi.portability.mode": { + "label": "mpi portability mode" + }, + "os": { + "label": "operating system" + }, + "os.name": { + "label": "operating system name" + }, + "os.release": { + "label": "operating system release" + }, + "os.vendor": { + "label": "operating system vendor" + }, + "os.version": { + "label": "operating system version" + }, + "hardware": { + "label": "hardware" + }, + "hardware.gpu": { + "label": "gpu hardware" + }, + "hardware.gpu.enabled": { + "label": "true if gpu is enabled" + }, + "hardware.gpu.driver": { + "label": "gpu driver" + }, + "hardware.gpu.architecture": { + "label": "gpu architecture" + }, + "hardware.gpu.driver.version": { + "label": "gpu driver version" + }, + "hardware.gpu.cuda": { + "label": "gpu cuda" + }, + "hardware.gpu.cuda.version": { + "label": "cuda version" + }, + "communication": { + "label": "communication" + }, + "communication.framework": { + "label": "communication framework" + } + }, + "edges": [ + { + "source": "mpi", + "target": "mpi.version", + "relation": "contains" + }, + { + "source": "mpi", + "target": "mpi.implementation", + "relation": "contains" + }, + { + "source": "mpi", + "target": "mpi.portability", + "relation": "contains" + }, + { + "source": "mpi.portability", + "target": "mpi.portability.optimization", + "relation": "contains" + }, + { + "source": "mpi.portability", + "target": "mpi.portability.mode", + "relation": "contains" + }, + { + "source": "os", + "target": "os.name", + "relation": "contains" + }, + { + "source": "os", + "target": "os.release", + "relation": "contains" + }, + { + "source": "os", + "target": "os.vendor", + "relation": "contains" + }, + { + "source": "os", + "target": "os.version", + "relation": "contains" + }, + { + "source": "hardware", + "target": "hardware.gpu", + "relation": "contains" + }, + { + "source": "hardware.gpu", + "target": "hardware.gpu.enabled", + "relation": "contains" + }, + { + "source": "hardware.gpu", + "target": "hardware.gpu.driver", + "relation": "contains" + }, + { + "source": "hardware.gpu.driver", + "target": "hardware.gpu.driver.version", + "relation": "contains" + }, + { + "source": "hardware.gpu", + "target": "hardware.gpu.architecture", + "relation": "contains" + }, + { + "source": "hardware.gpu", + "target": "hardware.gpu.version", + "relation": "contains" + }, + { + "source": "hardware.gpu", + "target": "hardware.gpu.cuda", + "relation": "contains" + }, + { + "source": "hardware.gpu.cuda", + "target": "hardware.gpu.cuda.version", + "relation": "contains" + }, + { + "source": "communication", + "target": "communication.framework", + "relation": "contains" + } + ], + "metadata": { + "version": "0.0.0", + "source": "https://github.com/supercontainers/compspec" } + } }