[PDF] [SPEC] Add 'version: 1.0' 61/50661/3
authorAlexandru Avadanii <Alexandru.Avadanii@enea.com>
Mon, 15 Jan 2018 03:32:31 +0000 (04:32 +0100)
committerAlexandru Avadanii <Alexandru.Avadanii@enea.com>
Mon, 22 Jan 2018 17:37:09 +0000 (18:37 +0100)
- add 'version: 1.0' to PDF spec;
- add 'version: 1.0' to all existing lab PDFs;
- extend schema with new property;
- add workaround for value-based decision-making in schema version
  selection via `validate-template.py`;
- add support for multiple schema versions;
- add versions for all schema blocks defined so far;
- fix PDF schema pattern for disk size decimals (e.g. '1.8T');

Change-Id: Ie8f768803ec19f1f9a7982fe5ca59df80764fc4a
Signed-off-by: Alexandru Avadanii <Alexandru.Avadanii@enea.com>
18 files changed:
config/pdf/pod1.encrypted.yaml
config/pdf/pod1.schema.yaml
config/pdf/pod1.yaml
config/utils/check-schema.sh
config/utils/validate_schema.py
labs/arm/pod5.yaml
labs/arm/pod6.yaml
labs/bii/pod1.yaml
labs/ericsson/pod1.yaml
labs/ericsson/pod2.yaml
labs/huawei/pod1.yaml
labs/intel/pod18.yaml
labs/lf/pod2.yaml
labs/lf/pod5.yaml
labs/zte/pod1.yaml
labs/zte/pod2.yaml
labs/zte/pod3.yaml
labs/zte/pod9.yaml

index c1e8f78..b5c78b5 100644 (file)
@@ -8,6 +8,8 @@
 ---
 ### POD descriptor file ###
 
+version: 1.0
+
 details:
   pod_owner: Lab Owner
   contact: email@address.com
index a602b56..2a96d0b 100644 (file)
@@ -10,173 +10,216 @@ $schema: 'http://json-schema.org/schema#'
 $id: 'https://github.com/opnfv/pharos/blob/master/config/pdf/pod1.yaml'
 
 definitions:
+  ############################################################################
+  # Low-level, general purpose definitions, unversioned
   ip_address:
     type: 'string'  # NOTE: we don't validate this is a valid addr (yet)
   mac_address:
     type: 'string'
     pattern: '^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$'
-  # Common node schema for jumpserver, cluster nodes
+  ############################################################################
+  # Mid-level definitions, common schema for jumpserver & cluster nodes
   node:
-    type: 'object'
-    properties:
-      type:
-        type: 'string'
-        enum: ['baremetal', 'virtual']
-      vendor:
-        type: 'string'
-      model:
-        type: 'string'
-      arch:
-        type: 'string'
-        enum: ['aarch64', 'x86_64']
-      cpus:
-        type: 'number'
-      cpu_cflags:
-        type: 'string'
-      cores:
-        type: 'number'
-      memory:
-        type: 'string'
-        pattern: '^[0-9]+[GT]B?$'
-    required: ['type', 'vendor', 'model', 'arch', 'cpus', 'cpu_cflags', 'cores', 'memory']
-    additionalProperties: false
-  disks:
-    type: 'array'
-    items:
+    v1.0:
       type: 'object'
       properties:
-        name:
+        type:
+          type: 'string'
+          enum: ['baremetal', 'virtual']
+        vendor:
           type: 'string'
-          pattern: '^disk[0-9]+$'
-        disk_capacity:
+        model:
           type: 'string'
-          pattern: '^[0-9]+[MGT]B?$'
-        disk_type:
+        arch:
           type: 'string'
-          enum: ['hdd', 'ssd', 'cdrom', 'tape']
-        disk_interface:
+          enum: ['aarch64', 'x86_64']
+        cpus:
+          type: 'number'
+        cpu_cflags:
           type: 'string'
-          enum: ['sata', 'sas', 'ssd', 'nvme', 'scsi', 'iscsi']
-        disk_rotation:
+        cores:
           type: 'number'
-          enum: [0, 5400, 7200, 10000, 15000]
-      required: ['name', 'disk_capacity', 'disk_type', 'disk_interface', 'disk_rotation']
+        memory:
+          type: 'string'
+          pattern: '^[1-9]\d*[MGT]B?$'
+      required: ['type', 'vendor', 'model', 'arch', 'cpus', 'cpu_cflags', 'cores', 'memory']
       additionalProperties: false
+  disks:
+    v1.0:
+      type: 'array'
+      items:
+        type: 'object'
+        properties:
+          name:
+            type: 'string'
+            pattern: '^disk[0-9]+$'
+          disk_capacity:
+            type: 'string'
+            pattern: '^[1-9][\d\.]*[MGT]B?$'
+          disk_type:
+            type: 'string'
+            enum: ['hdd', 'ssd', 'cdrom', 'tape']
+          disk_interface:
+            type: 'string'
+            enum: ['sata', 'sas', 'ssd', 'nvme', 'scsi', 'iscsi']
+          disk_rotation:
+            type: 'number'
+            enum: [0, 5400, 7200, 10000, 15000]
+        required: ['name', 'disk_capacity', 'disk_type', 'disk_interface', 'disk_rotation']
+        additionalProperties: false
   remote_management:
-    type: 'object'
-    properties:
-      type:
-        type: 'string'
-        enum: ['ipmi', 'amt']
-      versions:
-        type: 'array'
-        items:
-          type: 'number'
-          enum: [1.0, 2.0]
-      user:
-        type: 'string'
-      pass:
-        type: 'string'
-      address:
-        $ref: '#/definitions/ip_address'
-      mac_address:
-        $ref: '#/definitions/mac_address'
-    required: ['type', 'versions', 'user', 'pass', 'address', 'mac_address']
-    additionalProperties: false
-  interfaces:
-    type: 'array'
-    items:
+    v1.0:
       type: 'object'
       properties:
-        name:
+        type:
+          type: 'string'
+          enum: ['ipmi', 'amt']
+        versions:
+          type: 'array'
+          items:
+            type: 'number'
+            enum: [1.0, 2.0]
+        user:
+          type: 'string'
+        pass:
           type: 'string'
-          pattern: '^nic[0-9]+$'
-        mac_address:
-          $ref: '#/definitions/mac_address'
-        # Optional
         address:
           $ref: '#/definitions/ip_address'
-        # Optional
-        vlan:
-          oneOf:
-            - type: 'string'
-              pattern: '^(native|[1-9][0-9]{0,3})(\|(native|[1-9][0-9]{0,3}))*$'
-            - type: 'integer'
-              mininum: 1
-              maximum: 4095
-        # Optional
-        speed:
-          type: 'string'
-          enum: ['1gb', '10gb', '25gb', '40gb']
-          # FIXME: mandatory for nodes?
-        # Optional
-        features:
-          type: ['string', 'null']
-          pattern: '^((dpdk|sriov)\|?)*$'
-          # FIXME: mandatory for nodes?
-      required: ['name', 'mac_address']
+        mac_address:
+          $ref: '#/definitions/mac_address'
+      required: ['type', 'versions', 'user', 'pass', 'address', 'mac_address']
       additionalProperties: false
-
-# Do not allow any properties not defined here. This lets us catch typos.
-additionalProperties: false
-
-properties:
+  interfaces:
+    v1.0:
+      type: 'array'
+      items:
+        type: 'object'
+        properties:
+          name:
+            type: 'string'
+            pattern: '^nic[0-9]+$'
+          mac_address:
+            $ref: '#/definitions/mac_address'
+          # Optional
+          address:
+            $ref: '#/definitions/ip_address'
+          # Optional
+          vlan:
+            oneOf:
+              - type: 'string'
+                pattern: '^(native|[1-9][0-9]{0,3})(\|(native|[1-9][0-9]{0,3}))*$'
+              - type: 'integer'
+                mininum: 1
+                maximum: 4095
+          # Optional
+          speed:
+            type: 'string'
+            enum: ['1gb', '10gb', '25gb', '40gb']
+            # FIXME: mandatory for nodes?
+          # Optional
+          features:
+            type: ['string', 'null']
+            pattern: '^((dpdk|sriov)\|?)*$'
+            # FIXME: mandatory for nodes?
+        required: ['name', 'mac_address']
+        additionalProperties: false
+  ############################################################################
+  # Top-level PDF blocks, versioned
   details:
-    type: 'object'
-    properties:
-      type:
-        type: 'string'
-        enum: ['production', 'development']
-      pod_owner:
-        type: 'string'
-      contact:
-        type: 'string'
-        pattern: '^([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+[,; ]*)+$'
-      lab:
-        type: 'string'
-      location:
-        type: 'string'
-      link:
-        type: 'string'
-    required: ['type', 'pod_owner', 'contact', 'lab', 'location', 'link']
-    additionalProperties: false
+    v1.0:
+      type: 'object'
+      properties:
+        type:
+          type: 'string'
+          enum: ['production', 'development']
+        pod_owner:
+          type: 'string'
+        contact:
+          type: 'string'
+          pattern: '^([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+[,; ]*)+$'
+        lab:
+          type: 'string'
+        location:
+          type: 'string'
+        link:
+          type: 'string'
+      required: ['type', 'pod_owner', 'contact', 'lab', 'location', 'link']
+      additionalProperties: false
   jumphost:
-    type: 'object'
-    properties:
-      name:
-        type: 'string'
-      node:
-        $ref: '#/definitions/node'
-      disks:
-        $ref: '#/definitions/disks'
-      os:
-        type: 'string'
-      remote_params:  # Optional YAML anchor, contents will be validated below
-        type: 'object'
-      remote_management:
-        $ref: '#/definitions/remote_management'
-      interfaces:
-        $ref: '#/definitions/interfaces'
-    required: ['name', 'node', 'disks', 'os', 'remote_management', 'interfaces']
-    additionalProperties: false
-  nodes:
-    type: 'array'
-    items:
+    v1.0:
       type: 'object'
       properties:
         name:
           type: 'string'
         node:
-          $ref: '#/definitions/node'
+          $ref: '#/definitions/node/v1.0'
         disks:
-          $ref: '#/definitions/disks'
+          $ref: '#/definitions/disks/v1.0'
         os:
           type: 'string'
-        remote_params:  # Optional YAML anchor, contents will be validated after inject
+        remote_params:  # Optional YAML anchor, contents will be validated below
           type: 'object'
         remote_management:
-          $ref: '#/definitions/remote_management'
+          $ref: '#/definitions/remote_management/v1.0'
         interfaces:
-          $ref: '#/definitions/interfaces'
-      required: ['name', 'node', 'disks', 'remote_management', 'interfaces']
+          $ref: '#/definitions/interfaces/v1.0'
+      required: ['name', 'node', 'disks', 'os', 'remote_management', 'interfaces']
       additionalProperties: false
+  nodes:
+    v1.0:
+      type: 'array'
+      items:
+        type: 'object'
+        properties:
+          name:
+            type: 'string'
+          node:
+            $ref: '#/definitions/node/v1.0'
+          disks:
+            $ref: '#/definitions/disks/v1.0'
+          os:
+            type: 'string'
+          remote_params:  # Optional YAML anchor, contents will be validated after inject
+            type: 'object'
+          remote_management:
+            $ref: '#/definitions/remote_management/v1.0'
+          interfaces:
+            $ref: '#/definitions/interfaces/v1.0'
+        required: ['name', 'node', 'disks', 'remote_management', 'interfaces']
+        additionalProperties: false
+
+##############################################################################
+# Top-level structure:
+# - define all possible top-level keys, without enforcing a schema for them,
+#   just so we can disallow additional properties;
+# - require 'version' and allow dynamically generated 'version_x.y' key;
+properties:
+  # version_x.y keys are auto-added by `validate_schema.py` based on 'version'
+  version_1.0:
+    type: 'boolean'
+  version:
+    type: 'number'
+    enum: [1.0]
+  details:
+    type: 'object'
+  jumphost:
+    type: 'object'
+  nodes:
+    type: 'array'
+required: ['version']
+additionalProperties: false
+
+##############################################################################
+# Schema versioning
+# - based on dynamically added 'version_x.y', require additional PDF blocks
+#   and validate them against the proper schema version;
+dependencies:
+  version_1.0:
+    properties:
+      details:
+        $ref: '#/definitions/details/v1.0'
+      jumphost:
+        $ref: '#/definitions/jumphost/v1.0'
+      nodes:
+        $ref: '#/definitions/nodes/v1.0'
+    required: ['details', 'jumphost', 'nodes']
index c2d0734..d0cd793 100644 (file)
@@ -8,6 +8,8 @@
 ---
 ### POD descriptor file ###
 
+version: 1.0
+
 details:
   pod_owner: Lab Owner
   contact: email@address.com
index 321c5ce..61bdec2 100755 (executable)
@@ -16,7 +16,7 @@ RC=0
 while IFS= read -r lab_config; do
     pdf_cmd="${VALIDATE_SCHEMA} -s ${PDF_SCHEMA} -y ${lab_config}"
     echo "###################### ${lab_config} ######################"
-    pdf_out=$(${pdf_cmd} |& sed 's|ENC\[PKCS.*\]|opnfv|g')
+    pdf_out=$(${pdf_cmd} |& sed 's|ENC\[PKCS.*\][\\n]*|opnfv|g')
     if [ -z "${pdf_out}" ]; then
         SUMMARY+=";${lab_config#labs/};OK;\n"
         echo "[PDF] [OK] ${pdf_cmd}"
index cb40455..6bdc3bd 100755 (executable)
@@ -22,6 +22,19 @@ with open(ARGS.yaml) as _:
 with open(ARGS.schema) as _:
     _SCHEMA = yaml.safe_load(_)
 
+# Draft 4 (latest supported by py-jsonschema) does not support value-based
+# decisions properly, see related github issue:
+# https://github.com/json-schema-org/json-schema-spec/issues/64
+# Workaround: build 'version_x.y: true' on the fly based on 'version: x.y'
+def schema_version_workaround(node):
+    """Traverse nested dictionaries and handle 'version' key where found."""
+    if 'version' in node:
+        node['version_{0}'.format(node['version'])] = True
+    for item in node.items():
+        if type(item) is dict:
+            schema_version_workaround(item)
+schema_version_workaround(_DICT)
+
 _VALIDATOR = jsonschema.Draft4Validator(_SCHEMA)
 for error in _VALIDATOR.iter_errors(_DICT):
     raise RuntimeError(str(error))
index 3708b7f..3a55678 100644 (file)
@@ -8,6 +8,7 @@
 ---
 ### Enea ARM POD 5 descriptor file ###
 
+version: 1.0
 details:
   pod_owner: ENEA AB
   contact: dan.lilliehorn@enea.com
index dc53888..3b55816 100644 (file)
@@ -8,6 +8,7 @@
 ---
 ### Enea ARM POD 6 descriptor file ###
 
+version: 1.0
 details:
   pod_owner: ENEA AB
   contact: dan.lilliehorn@enea.com
index 44eedc3..40ac58d 100644 (file)
@@ -8,6 +8,7 @@
 ---
 ### This is a BII POD1 descriptor file ###
 
+version: 1.0
 details:
   pod_owner: ylong
   contact: ylong@biigroup.cn, zjtang@biigroup.cn
index ae04b30..1c2f5ae 100644 (file)
@@ -8,6 +8,7 @@
 ---
 ### POD descriptor file ###
 
+version: 1.0
 details:
   pod_owner: Jose Lausuch
   contact: jose.lausuch@ericsson.com
index 8814c42..4d25af4 100644 (file)
@@ -1,6 +1,7 @@
 ---
 ### POD descriptor file ###
 
+version: 1.0
 details:
   pod_owner: Jose Lausuch
   contact: jose.lausuch@ericsson.com
index f48d823..807c6f3 100644 (file)
@@ -9,6 +9,7 @@
 ---
 ### POD descriptor file ###
 
+version: 1.0
 details:
   pod_owner: Tianwei Wu
   contact: wutianwei1@hauwei.com
index b1123b7..2273891 100644 (file)
@@ -2,6 +2,7 @@
 
 ### POD descriptor file ###
 
+version: 1.0
 details:
   pod_owner: Jack Morgan
   contact: jack.morgan@intel.com
index ab60bdb..219b2a6 100644 (file)
@@ -8,6 +8,7 @@
 ---
 ### LF POD 2 descriptor file ###
 
+version: 1.0
 details:
   pod_owner: Trevor Bramwell
   contact: tbramwell@linuxfoundation.org
index 60ab402..61ca3eb 100644 (file)
@@ -8,6 +8,7 @@
 ---
 ### LF POD 5 descriptor file ###
 
+version: 1.0
 details:
   pod_owner: Trevor Bramwell
   contact: tbramwell@linuxfoundation.org
index 1b4d1ad..9a4a8a0 100644 (file)
@@ -9,6 +9,7 @@
 ### ZTE POD 1 descriptor file ###
 # refering to https://gerrit.opnfv.org/gerrit/#/c/23727/9/config/pod1.yaml
 
+version: 1.0
 details:
   pod_owner: Alex Yang
   contact: yangyang1@zte.com.cn
index f51d7f7..e5dd5e6 100644 (file)
@@ -9,6 +9,7 @@
 ### ZTE POD 2 descriptor file ###
 # refering to https://gerrit.opnfv.org/gerrit/#/c/23727/9/config/pod1.yaml
 
+version: 1.0
 details:
   pod_owner: Alex Yang
   contact: yangyang1@zte.com.cn
index 063b7df..b676839 100644 (file)
@@ -9,6 +9,7 @@
 ### ZTE POD 3 descriptor file ###
 # refering to https://gerrit.opnfv.org/gerrit/#/c/23727/9/config/pod1.yaml
 
+version: 1.0
 details:
   pod_owner: Alex Yang
   contact: yangyang1@zte.com.cn
index 76d4aa9..c18d244 100644 (file)
@@ -8,6 +8,7 @@
 ---
 ### ZTE POD 9 descriptor file ###
 
+version: 1.0
 details:
   pod_owner: Zhiijang Hu
   contact: huzhijiang@zte.com.cn