[PDF] Add schema validation 75/50575/2
authorAlexandru Avadanii <Alexandru.Avadanii@enea.com>
Sat, 13 Jan 2018 17:35:04 +0000 (18:35 +0100)
committerAlexandru Avadanii <Alexandru.Avadanii@enea.com>
Sun, 14 Jan 2018 20:58:05 +0000 (21:58 +0100)
- create new YAML schema for PDF validation;
- add basic python script for checking a PDF against the schema;
- add bash wrapper for checking all PDFs in Pharos, to be leveraged
  later via a new verify CI job;

Change-Id: I47e02642756b7a231138dec3d5258b100b4db72b
Signed-off-by: Alexandru Avadanii <Alexandru.Avadanii@enea.com>
config/pdf/pod1.schema.yaml [new file with mode: 0644]
config/utils/check-schema.sh [new file with mode: 0755]
config/utils/validate_schema.py [new file with mode: 0755]

diff --git a/config/pdf/pod1.schema.yaml b/config/pdf/pod1.schema.yaml
new file mode 100644 (file)
index 0000000..12ce38d
--- /dev/null
@@ -0,0 +1,182 @@
+##############################################################################
+# Copyright (c) 2018 Enea AB and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+---
+$schema: 'http://json-schema.org/schema#'
+$id: 'https://github.com/opnfv/pharos/blob/master/config/pdf/pod1.yaml'
+
+definitions:
+  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
+  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:
+      type: 'object'
+      properties:
+        name:
+          type: 'string'
+          pattern: '^disk[0-9]+$'
+        disk_capacity:
+          type: 'string'
+          pattern: '^[0-9]+[MGT]B?$'
+        disk_type:
+          type: 'string'
+          enum: ['hdd', 'ssd', 'cdrom', 'tape']
+        disk_interface:
+          type: 'string'
+          enum: ['sata', 'sas', 'ssd', 'nvme']
+        disk_rotation:
+          type: 'number'
+          enum: [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:
+      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
+
+# Do not allow any properties not defined here. This lets us catch typos.
+additionalProperties: false
+
+properties:
+  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
+  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:
+      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 after inject
+          type: 'object'
+        remote_management:
+          $ref: '#/definitions/remote_management'
+        interfaces:
+          $ref: '#/definitions/interfaces'
+      required: ['name', 'node', 'disks', 'remote_management', 'interfaces']
+      additionalProperties: false
diff --git a/config/utils/check-schema.sh b/config/utils/check-schema.sh
new file mode 100755 (executable)
index 0000000..321c5ce
--- /dev/null
@@ -0,0 +1,37 @@
+#!/bin/bash -e
+##############################################################################
+# Copyright (c) 2018 Enea AB and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+export PATH=$PATH:/usr/local/bin/
+
+VALIDATE_SCHEMA='./config/utils/validate_schema.py'
+PDF_SCHEMA='./config/pdf/pod1.schema.yaml'
+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')
+    if [ -z "${pdf_out}" ]; then
+        SUMMARY+=";${lab_config#labs/};OK;\n"
+        echo "[PDF] [OK] ${pdf_cmd}"
+    else
+        SUMMARY+=";${lab_config#labs/};ERROR;\n"
+        RC=1
+        echo "${pdf_out}"
+        echo "[PDF] [ERROR] ${pdf_cmd}"
+    fi
+    echo ''
+done < <(find 'labs' -name 'pod*.yaml')
+
+cat <<EOF
+###################### Schema Validation Matrix ######################
+
+$(echo -e "${SUMMARY}" | sed -e 's/;/;| /g' | column -t -s ';')
+EOF
+exit "${RC}"
diff --git a/config/utils/validate_schema.py b/config/utils/validate_schema.py
new file mode 100755 (executable)
index 0000000..cb40455
--- /dev/null
@@ -0,0 +1,27 @@
+#!/usr/bin/python
+##############################################################################
+# Copyright (c) 2018 Enea AB and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+"""This module validates a PDF file against the schema."""
+import argparse
+import jsonschema
+import yaml
+
+PARSER = argparse.ArgumentParser()
+PARSER.add_argument("--yaml", "-y", type=str, required=True)
+PARSER.add_argument("--schema", "-s", type=str, required=True)
+ARGS = PARSER.parse_args()
+
+with open(ARGS.yaml) as _:
+    _DICT = yaml.safe_load(_)
+
+with open(ARGS.schema) as _:
+    _SCHEMA = yaml.safe_load(_)
+
+_VALIDATOR = jsonschema.Draft4Validator(_SCHEMA)
+for error in _VALIDATOR.iter_errors(_DICT):
+    raise RuntimeError(str(error))