aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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