aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLianhao Lu <lianhao.lu@intel.com>2018-08-10 17:04:14 +0800
committerLianhao Lu <lianhao.lu@intel.com>2018-08-15 06:07:53 +0000
commit9f629ff62c270fd3771c381f78aa36f473e65bb5 (patch)
tree7feba7a32eaf6f808761502f4c1ab4b949169561
parent4e3368b279970e4244addbafbf650b316255d69c (diff)
Added the logic to validate HPA
Added the code logic to validate HPA for opnfv tosca parser. Also corrected some hpa validation schema errors introduced by the previous patch. Change-Id: Icd61d34d7915aa965ec32adfc3c0f1a117dd6f3e Issue-ID: VNFSDK-194 Signed-off-by: Lianhao Lu <lianhao.lu@intel.com>
-rw-r--r--tests/resources/hpa.csarbin0 -> 7984 bytes
-rw-r--r--tests/resources/hpa_bad.csarbin0 -> 7984 bytes
-rw-r--r--tests/validator/test_toscaparser_validator.py16
-rw-r--r--vnfsdk_pkgtools/validator/hpa.yaml55
-rw-r--r--vnfsdk_pkgtools/validator/toscaparser_validator.py99
5 files changed, 141 insertions, 29 deletions
diff --git a/tests/resources/hpa.csar b/tests/resources/hpa.csar
new file mode 100644
index 0000000..a9558ae
--- /dev/null
+++ b/tests/resources/hpa.csar
Binary files differ
diff --git a/tests/resources/hpa_bad.csar b/tests/resources/hpa_bad.csar
new file mode 100644
index 0000000..4431d61
--- /dev/null
+++ b/tests/resources/hpa_bad.csar
Binary files differ
diff --git a/tests/validator/test_toscaparser_validator.py b/tests/validator/test_toscaparser_validator.py
index c35d1ed..3348d60 100644
--- a/tests/validator/test_toscaparser_validator.py
+++ b/tests/validator/test_toscaparser_validator.py
@@ -15,13 +15,29 @@
import os
+import pytest
+
from vnfsdk_pkgtools.packager import csar
from vnfsdk_pkgtools.validator import toscaparser_validator
CSAR_PATH = 'tests/resources/test_import.csar'
+HPA_PATH = 'tests/resources/hpa.csar'
+BAD_HPA_PATH = 'tests/resources/hpa_bad.csar'
def test_validate(tmpdir):
reader = csar._CSARReader(CSAR_PATH, str(tmpdir.mkdir('validate')))
validator = toscaparser_validator.ToscaparserValidator()
validator.validate(reader)
assert hasattr(validator, 'tosca')
+
+def test_validate_hpa(tmpdir):
+ reader = csar._CSARReader(HPA_PATH, str(tmpdir.mkdir('validate')))
+ validator = toscaparser_validator.ToscaparserValidator()
+ validator.validate(reader)
+ assert hasattr(validator, 'tosca')
+
+def test_validate_hpa_bad(tmpdir):
+ reader = csar._CSARReader(BAD_HPA_PATH, str(tmpdir.mkdir('validate')))
+ validator = toscaparser_validator.ToscaparserValidator()
+ with pytest.raises(toscaparser_validator.HpaValueError):
+ validator.validate(reader)
diff --git a/vnfsdk_pkgtools/validator/hpa.yaml b/vnfsdk_pkgtools/validator/hpa.yaml
index bc551c6..98ac42b 100644
--- a/vnfsdk_pkgtools/validator/hpa.yaml
+++ b/vnfsdk_pkgtools/validator/hpa.yaml
@@ -7,11 +7,11 @@ schemas:
# hpa key name
cpuModelSpecificationBinding:
# json encoded key name: reg expression for the valid value
- schema-version: &any r'.*'
+ schema-version: &any '.*'
schema-location: *any
- platform-id: &generic r'generic'
- mandatory: &bool r'true|false|TRUE|FALSE|True|False'
- configuration-value: r'strictBinding|equalOrBetterBinding'
+ platform-id: &generic 'generic'
+ mandatory: &bool 'true|false|TRUE|FALSE|True|False'
+ configuration-value: 'strictBinding|equalOrBetterBinding'
instructionSetRequirements:
schema-version: *any
schema-location: *any
@@ -23,7 +23,7 @@ schemas:
schema-location: *any
platform-id: *generic
mandatory: *bool
- configuration-value: r'enabled|disabled'
+ configuration-value: 'enabled|disabled'
hypervisorConfiguration:
schema-version: *any
schema-location: *any
@@ -35,7 +35,7 @@ schemas:
schema-location: *any
platform-id: *generic
mandatory: *bool
- configuration-value: r'pciDetectedAndCorrectedErrors|pciDetectedAndUncorrectedErrors'
+ configuration-value: 'pciDetectedAndCorrectedErrors|pciDetectedAndUncorrectedErrors'
cpuModel:
schema-version: *any
schema-location: *any
@@ -71,44 +71,44 @@ schemas:
schema-location: *any
platform-id: *generic
mandatory: *bool
- configuration-value: r'\d+'
+ configuration-value: '\d+'
virtualCpuClock:
schema-version: *any
schema-location: *any
platform-id: *generic
mandatory: *bool
- configuration-value: r'\d+\w*(Hz|kHz|MHz|GHz)'
+ configuration-value: '\d+\s*(Hz|kHz|MHz|GHz)'
logicalCpuPinningPolicy:
schema-version: *any
schema-location: *any
platform-id: *generic
mandatory: *bool
- configuration-value: r'dedicated|shared'
+ configuration-value: 'dedicated|shared'
logicalCpuThreadPinningPolicy:
schema-version: *any
schema-location: *any
platform-id: *generic
mandatory: *bool
- configuration-value: r'require|isolate|prefer'
+ configuration-value: 'require|isolate|prefer'
vduMemRequirements:
memoryPageSize:
schema-version: *any
schema-location: *any
platform-id: *generic
mandatory: *bool
- configuration-value: r'\d+\w*(B|kB|KB|KiB|MB|MiB|GB|GiB|TB|TiB)'
+ configuration-value: '\d+\s*(B|kB|KB|KiB|MB|MiB|GB|GiB|TB|TiB)'
numberOfPages:
schema-version: *any
schema-location: *any
platform-id: *generic
mandatory: *bool
- configuration-value: r'\d+'
+ configuration-value: '\d+'
memoryAllocationPolicy:
schema-version: *any
schema-location: *any
platform-id: *generic
mandatory: *bool
- configuration-value: r'strictLocalAffinity|preferredLocalAffinity'
+ configuration-value: 'strictLocalAffinity|preferredLocalAffinity'
memoryType:
schema-version: *any
schema-location: *any
@@ -132,7 +132,7 @@ schemas:
schema-location: *any
platform-id: *generic
mandatory: *bool
- configuration-value: r'\d+'
+ configuration-value: '\d+'
processorCacheAllocationType:
schema-version: *any
schema-location: *any
@@ -151,13 +151,13 @@ schemas:
schema-location: *any
platform-id: *generic
mandatory: *bool
- configuration-value: r'\d+'
+ configuration-value: '\d+'
storageResilencyMechanism:
schema-version: *any
schema-location: *any
platform-id: *generic
mandatory: *bool
- configuration-value: r'erasure|tripleReplication'
+ configuration-value: 'erasure|tripleReplication'
processorCacheAllocationSize:
schema-version: *any
schema-location: *any
@@ -176,13 +176,13 @@ schemas:
schema-location: *any
platform-id: *generic
mandatory: *bool
- configuration-value: r'\d+'
+ configuration-value: '\d+'
localNumaMemorySize:
schema-version: *any
schema-location: *any
platform-id: *generic
mandatory: *bool
- configuration-value: r'\d+\w*(B|kB|KB|KiB|MB|MiB|GB|GiB|TB|TiB)'
+ configuration-value: '\d+\s*(B|kB|KB|KiB|MB|MiB|GB|GiB|TB|TiB)'
logicalNodeIoRequirements:
pciVendorId:
schema-version: *any
@@ -201,7 +201,7 @@ schemas:
schema-location: *any
platform-id: *generic
mandatory: *bool
- configuration-value: r'\d+'
+ configuration-value: '\d+'
pciAddress:
schema-version: *any
schema-location: *any
@@ -213,7 +213,7 @@ schemas:
schema-location: *any
platform-id: *generic
mandatory: *bool
- configuration-value: r'required|notRequired'
+ configuration-value: 'required|notRequired'
networkInterfaceRequirements:
nicFeature:
schema-version: *any
@@ -221,13 +221,13 @@ schemas:
platform-id: *generic
mandatory: *bool
configuration-value: *any
- dataProcessingAccelerationLibray:
+ dataProcessingAccelerationLibrary:
schema-version: *any
schema-location: *any
platform-id: *generic
mandatory: *bool
- configuration-value: r'DPDK'
- dataProcessingAccelerationLibrayVersion:
+ configuration-value: 'DPDK|dpdk'
+ dataProcessingAccelerationLibraryVersion:
schema-version: *any
schema-location: *any
platform-id: *generic
@@ -238,14 +238,13 @@ schemas:
schema-location: *any
platform-id: *generic
mandatory: *bool
- configuration-value: r'virtio|PCI-Passthrough|SR-IOV|E1000|RTL8139|PCNET'
+ configuration-value: 'virtio|PCI-Passthrough|SR-IOV|E1000|RTL8139|PCNET'
mappings:
# mapping between property value of a tosca node type and the valid hpa schema
# type: tosca node type
# key: prop1##prop2##...##propN
# Property hierachy within that node type. Prefix of '(capability:)'
# in propI means the value is from capability instead of property.
-# Suffix '[] in propI means the value is a list of propI+1.
# schema: schema defined in the above schemas section
- type: tosca.nodes.nfv.Vdu.Compute
key: capability:virtual_compute##logical_node##logical_node_requirements
@@ -255,13 +254,13 @@ mappings:
schema: vduCpuRequirements
- type: tosca.nodes.nfv.Vdu.Compute
key: capability:virtual_compute##virtual_memory##vdu_memory_requirements
- schema: vduCpuRequirements
+ schema: vduMemRequirements
- type: tosca.nodes.nfv.Vdu.VirtualStorage
key: vdu_storage_requirements
schema: vduStorageRequirements
- type: tosca.nodes.nfv.VduCp
- key: virtual_network_interface_requirements[]##network_interface_requirements##logical_node_requirements
+ key: virtual_network_interface_requirements##network_interface_requirements
schema: networkInterfaceRequirements
- type: tosca.nodes.nfv.VduCp
- key: virtual_network_interface_requirements[]##nic_io_requirements##logical_node_requirements
+ key: virtual_network_interface_requirements##nic_io_requirements##logical_node_requirements
schema: logicalNodeIoRequirements
diff --git a/vnfsdk_pkgtools/validator/toscaparser_validator.py b/vnfsdk_pkgtools/validator/toscaparser_validator.py
index d1aad30..dfe44b8 100644
--- a/vnfsdk_pkgtools/validator/toscaparser_validator.py
+++ b/vnfsdk_pkgtools/validator/toscaparser_validator.py
@@ -13,9 +13,12 @@
# under the License.
#
+import functools
+import json
import logging
import os
import pkg_resources
+import re
from toscaparser.common.exception import ValidationError
from toscaparser.tosca_template import ToscaTemplate
@@ -30,6 +33,10 @@ class HpaSchemaDefError(ValueError):
pass
+class HpaValueError(ValueError):
+ pass
+
+
class ToscaparserValidator(validator.ValidatorBase):
def __init__(self):
super(ToscaparserValidator, self).__init__()
@@ -66,5 +73,95 @@ class ToscaparserValidator(validator.ValidatorBase):
except ValidationError as e:
LOG.error(e.message)
raise e
+ self.validate_hpa()
+
+ def is_type(self, node, tosca_type):
+ if node is None:
+ return False
+ elif node.type == tosca_type:
+ return True
+ else:
+ return self.is_type(node.parent_type, tosca_type)
+
+ def extract_value(self, node, key):
+ if node is None:
+ return None
+
+ (cur_key, _, pending) = key.partition('##')
+
+ prefix = None
+ prop = cur_key
+ if ':' in cur_key:
+ (prefix, prop) = cur_key.split(':', 1)
+ if prefix == 'capability':
+ getter = getattr(node, 'get_capability', None)
+ if not getter:
+ raise HpaSchemaDefError("not find capability %s" % prop)
+ elif prefix == 'property' or prefix is None:
+ getter = getattr(node, 'get_property_value', None)
+ if not getter and isinstance(node, dict):
+ getter = getattr(node, 'get')
+ else:
+ raise HpaSchemaDefError("unknown prefix in mapping "
+ "key %s" % cur_key)
+ value = getter(prop)
+
+ if not pending:
+ return value
+ elif isinstance(value, list):
+ return list(map(functools.partial(self.extract_value,
+ key=pending),
+ value))
+ else:
+ return self.extract_value(value, pending)
+
+ @staticmethod
+ def validate_value(refkey, hpa_schema, value):
+ if value is None:
+ return
+ if not isinstance(value, dict):
+ msg = "node %s: value %s is not a map of string"
+ raise HpaValueError(msg % (refkey, value))
+ for (key, hpa_value) in value.iteritems():
+ if key not in hpa_schema:
+ msg = "node %s: %s is NOT a valid HPA key"
+ raise HpaValueError(msg % (refkey, key))
+ try:
+ hpa_dict = json.loads(hpa_value)
+ except:
+ msg = "node %s, HPA key %s: %s is NOT a valid json encoded string"
+ raise HpaValueError(msg % (refkey, key, hpa_value.encode('ascii', 'replace')))
+ if not isinstance(hpa_dict, dict):
+ msg = "node %s, HPA key %s: %s is NOT a valid json encoded string of dict"
+ raise HpaValueError(msg % (refkey, key, hpa_value.encode('ascii', 'replace')))
+ for (attr, val) in hpa_dict.iteritems():
+ if attr not in hpa_schema[key]:
+ msg = "node %s, HPA key %s: %s is NOT valid HPA attribute"
+ raise HpaValueError(msg % (refkey, key, attr))
+ attr_schema = hpa_schema[key][attr]
+ if not re.match(attr_schema, str(val)):
+ msg = ("node %s, HPA key %s, attr %s: %s is not a valid HPA "
+ "attr value, expected re pattern is %s")
+ raise HpaValueError(msg % (refkey, key, attr, val.encode('ascii','replace'), attr_schema))
+
+ def validate_hpa_value(self, refkey, hpa_schema, values):
+ if isinstance(values, list):
+ for value in values:
+ self.validate_value(refkey, hpa_schema, value)
+ elif isinstance(values, dict):
+ self.validate_value(refkey, hpa_schema, values)
+
+ def validate_hpa(self):
+ for node in getattr(self.tosca, 'nodetemplates', []):
+ for mapping in self.hpa_mappings:
+ if self.is_type(node, mapping['type']):
+ value = self.extract_value(node, mapping['key'])
+ if value:
+ refkey = node.name + '->' + mapping['key']
+ LOG.debug("Checking HPA values %s of node %s "
+ "against schema %s", value, refkey, mapping['schema'])
+ self.validate_hpa_value(refkey,
+ self.hpa_schemas[mapping['schema']],
+ value)
+
- print self.tosca