diff options
Diffstat (limited to 'tosca2heat/tosca-parser')
25 files changed, 405 insertions, 40 deletions
diff --git a/tosca2heat/tosca-parser/CONTRIBUTING.rst b/tosca2heat/tosca-parser/CONTRIBUTING.rst new file mode 100644 index 0000000..7366825 --- /dev/null +++ b/tosca2heat/tosca-parser/CONTRIBUTING.rst @@ -0,0 +1,16 @@ +If you would like to contribute to the development of OpenStack, +you must follow the steps in this page: + + http://docs.openstack.org/infra/manual/developers.html + +Once those steps have been completed, changes to OpenStack +should be submitted for review via the Gerrit tool, following +the workflow documented at: + + http://docs.openstack.org/infra/manual/developers.html#development-workflow + +Pull requests submitted through GitHub will be ignored. + +Bugs should be filed on Launchpad, not GitHub: + + https://bugs.launchpad.net/tosca-parser
\ No newline at end of file diff --git a/tosca2heat/tosca-parser/HACKING.rst b/tosca2heat/tosca-parser/HACKING.rst new file mode 100644 index 0000000..60505f1 --- /dev/null +++ b/tosca2heat/tosca-parser/HACKING.rst @@ -0,0 +1,4 @@ +tosca-parser Style Commandments +=============================================== + +Read the OpenStack Style Commandments http://docs.openstack.org/developer/hacking/
\ No newline at end of file diff --git a/tosca2heat/tosca-parser/README.md b/tosca2heat/tosca-parser/README.rst index 0f94072..0f94072 100644 --- a/tosca2heat/tosca-parser/README.md +++ b/tosca2heat/tosca-parser/README.rst diff --git a/tosca2heat/tosca-parser/requirements.txt b/tosca2heat/tosca-parser/requirements.txt index 45a19f0..807d749 100644 --- a/tosca2heat/tosca-parser/requirements.txt +++ b/tosca2heat/tosca-parser/requirements.txt @@ -1,10 +1,10 @@ # The order of packages is significant, because pip processes them in the order # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. -pbr>=1.8 # Apache-2.0 -Babel>=2.3.4 # BSD -cliff>=2.3.0 # Apache-2.0 +pbr!=2.1.0,>=2.0.0 # Apache-2.0 +Babel!=2.4.0,>=2.3.4 # BSD +cliff>=2.6.0 # Apache-2.0 PyYAML>=3.10.0 # MIT python-dateutil>=2.4.2 # BSD six>=1.9.0 # MIT -requests!=2.12.2,!=2.13.0,>=2.10.0 # Apache-2.0 +requests>=2.14.2 # Apache-2.0 diff --git a/tosca2heat/tosca-parser/setup.cfg b/tosca2heat/tosca-parser/setup.cfg index 45a5ae7..77e1b2e 100644 --- a/tosca2heat/tosca-parser/setup.cfg +++ b/tosca2heat/tosca-parser/setup.cfg @@ -3,7 +3,7 @@ name = tosca-parser url = https://launchpad.net/tosca-parser summary = Parser for TOSCA Simple Profile in YAML. description-file = - README.md + README.rst author = OpenStack author-email = openstack-dev@lists.openstack.org home-page = http://docs.openstack.org/developer/tosca-parser/ @@ -28,6 +28,14 @@ packages = console_scripts = tosca-parser = toscaparser.shell:main +[build_sphinx] +source-dir = doc/source +build-dir = doc/build +all_files = 1 + +[upload_sphinx] +upload-dir = doc/build/html + [compile_catalog] directory = toscaparser/locale domain = toscaparser diff --git a/tosca2heat/tosca-parser/setup.py b/tosca2heat/tosca-parser/setup.py index 782bb21..566d844 100644 --- a/tosca2heat/tosca-parser/setup.py +++ b/tosca2heat/tosca-parser/setup.py @@ -25,5 +25,5 @@ except ImportError: pass setuptools.setup( - setup_requires=['pbr>=1.8'], + setup_requires=['pbr>=2.0.0'], pbr=True) diff --git a/tosca2heat/tosca-parser/test-requirements.txt b/tosca2heat/tosca-parser/test-requirements.txt index d4b59c3..da69d4f 100644 --- a/tosca2heat/tosca-parser/test-requirements.txt +++ b/tosca2heat/tosca-parser/test-requirements.txt @@ -1,13 +1,13 @@ # The order of packages is significant, because pip processes them in the order # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. -hacking<0.11,>=0.10.0 -coverage>=4.0 # Apache-2.0 +hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0 +coverage!=4.4,>=4.0 # Apache-2.0 fixtures>=3.0.0 # Apache-2.0/BSD oslotest>=1.10.0 # Apache-2.0 oslosphinx>=4.7.0 # Apache-2.0 python-subunit>=0.0.18 # Apache-2.0/BSD -sphinx>=1.5.1 # BSD +sphinx>=1.6.2 # BSD testrepository>=0.0.18 # Apache-2.0/BSD testscenarios>=0.4 # Apache-2.0/BSD testtools>=1.4.0 # MIT diff --git a/tosca2heat/tosca-parser/toscaparser/elements/TOSCA_definition_1_0.yaml b/tosca2heat/tosca-parser/toscaparser/elements/TOSCA_definition_1_0.yaml index 9f3369e..57c9bf9 100644 --- a/tosca2heat/tosca-parser/toscaparser/elements/TOSCA_definition_1_0.yaml +++ b/tosca2heat/tosca-parser/toscaparser/elements/TOSCA_definition_1_0.yaml @@ -339,6 +339,26 @@ node_types: relationship: tosca.relationships.network.LinksTo node: tosca.nodes.network.Network + tosca.nodes.network.FloatingIP: + derived_from: tosca.nodes.Root + description: > + The TOSCA FloatingIP node represents a floating IP that can associate to a Port. + properties: + floating_network: + type: string + required: true + floating_ip_address: + type: string + required: false + port_id: + type: string + required: false + requirements: + - link: + capability: tosca.capabilities.network.Linkable + relationship: tosca.relationships.network.LinksTo + node: tosca.nodes.network.Port + tosca.nodes.ObjectStorage: derived_from: tosca.nodes.Root description: > @@ -928,6 +948,11 @@ policy_types: description: The TOSCA Policy Type definition that is used to govern scaling of TOSCA nodes or groups of nodes. + tosca.policies.Monitoring: + derived_from: tosca.policies.Root + description: The TOSCA Policy Type definition that is used to govern + monitoring of TOSCA nodes or groups of nodes. + tosca.policies.Update: derived_from: tosca.policies.Root description: The TOSCA Policy Type definition that is used to govern diff --git a/tosca2heat/tosca-parser/toscaparser/elements/nodetype.py b/tosca2heat/tosca-parser/toscaparser/elements/nodetype.py index 7f3da2d..4889ed8 100644 --- a/tosca2heat/tosca-parser/toscaparser/elements/nodetype.py +++ b/tosca2heat/tosca-parser/toscaparser/elements/nodetype.py @@ -83,8 +83,6 @@ class NodeType(StatefulEntityType): captype = value['capability'] value = (self. _get_node_type_by_cap(captype)) - # _get_node_type_by_cap(key, captype)) - # relation = self._get_relation(key, value) keyword = key node_type = value rtype = RelationshipType(relation, keyword, self.custom_def) diff --git a/tosca2heat/tosca-parser/toscaparser/elements/policytype.py b/tosca2heat/tosca-parser/toscaparser/elements/policytype.py index a922d26..82aed0a 100644 --- a/tosca2heat/tosca-parser/toscaparser/elements/policytype.py +++ b/tosca2heat/tosca-parser/toscaparser/elements/policytype.py @@ -113,7 +113,7 @@ class PolicyType(StatefulEntityType): for entry_schema, entry_schema_type in meta_data.items(): if isinstance(entry_schema_type, dict) and not \ - entry_schema_type.get('type') == 'string': + entry_schema_type.get('type') == 'string': ExceptionCollector.appendException( InvalidTypeError(what='"%s" defined in policy for ' 'metadata "%s"' diff --git a/tosca2heat/tosca-parser/toscaparser/functions.py b/tosca2heat/tosca-parser/toscaparser/functions.py index d498229..b64f1bc 100644 --- a/tosca2heat/tosca-parser/toscaparser/functions.py +++ b/tosca2heat/tosca-parser/toscaparser/functions.py @@ -158,6 +158,8 @@ class GetAttribute(Function): # then check the req or caps attr = self._find_req_or_cap_attribute(self.args[1], self.args[2]) + if not attr: + return value_type = attr.schema['type'] if len(self.args) > index: @@ -236,8 +238,8 @@ class GetAttribute(Function): target_node = self._find_node_template(target_name) target_type = target_node.type_definition for capability in target_type.get_capabilities_objects(): - if capability.type in \ - hosted_on_rel['valid_target_types']: + if capability.inherits_from( + hosted_on_rel['valid_target_types']): if self._attribute_exists_in_type(target_type): return target_node return self._find_host_containing_attribute( @@ -412,6 +414,8 @@ class GetProperty(Function): def _find_req_or_cap_property(self, req_or_cap, property_name): node_tpl = self._find_node_template(self.args[0]) + if node_tpl is None: + return None # Find property in node template's requirements for r in node_tpl.requirements: for req, node_name in r.items(): @@ -429,7 +433,8 @@ class GetProperty(Function): def _get_capability_property(self, node_template, capability_name, - property_name): + property_name, + throw_errors=True): """Gets a node template capability property.""" caps = node_template.get_capabilities() if caps and capability_name in caps.keys(): @@ -438,7 +443,7 @@ class GetProperty(Function): props = cap.get_properties() if props and property_name in props.keys(): property = props[property_name].value - if not property: + if property is None and throw_errors: ExceptionCollector.appendException( KeyError(_('Property "%(prop)s" was not found in ' 'capability "%(cap)s" of node template ' @@ -448,12 +453,15 @@ class GetProperty(Function): 'ntpl1': node_template.name, 'ntpl2': self.context.name})) return property - msg = _('Requirement/Capability "{0}" referenced from node template ' - '"{1}" was not found in node template "{2}".').format( - capability_name, - self.context.name, - node_template.name) - ExceptionCollector.appendException(KeyError(msg)) + if throw_errors: + msg = _('Requirement/Capability "{0}" referenced from ' + 'node template "{1}" was not found in node template' + ' "{2}".').format(capability_name, + self.context.name, + node_template.name) + ExceptionCollector.appendException(KeyError(msg)) + else: + return None def _find_property(self, property_name): node_tpl = self._find_node_template(self.args[0]) @@ -475,7 +483,18 @@ class GetProperty(Function): return self.context # enable the HOST value in the function if node_template_name == HOST: - return self._find_host_containing_property() + node = self._find_host_containing_property() + if node is None: + ExceptionCollector.appendException( + KeyError(_( + "Property '{0}' not found in capability/requirement" + " '{1}' referenced from node template {2}"). + format(self.args[2], + self.args[1], + self.context.name))) + return None + else: + return node if node_template_name == TARGET: if not isinstance(self.context.type_definition, RelationshipType): ExceptionCollector.appendException( @@ -498,7 +517,9 @@ class GetProperty(Function): ExceptionCollector.appendException( KeyError(_( 'Node template "{0}" was not found.' - ).format(node_template_name))) + ' referenced from node template {1}' + ).format(node_template_name, + self.context.name))) def _get_index_value(self, value, index): if isinstance(value, list): @@ -555,9 +576,19 @@ class GetProperty(Function): target_node = self._find_node_template(target_name) target_type = target_node.type_definition for capability in target_type.get_capabilities_objects(): - if capability.type in hosted_on_rel['valid_target_types']: + if capability.inherits_from( + hosted_on_rel['valid_target_types']): if self._property_exists_in_type(target_type): return target_node + # If requirement was not found, look in node + # template's capabilities + if (len(self.args) > 2 and + self._get_capability_property(target_node, + self.args[1], + self.args[2], + False) + is not None): + return target_node return self._find_host_containing_property( target_name) return None diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/container_cap_child.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/container_cap_child.yaml new file mode 100644 index 0000000..1df09dd --- /dev/null +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/container_cap_child.yaml @@ -0,0 +1,33 @@ +tosca_definitions_version: tosca_simple_yaml_1_0 + +description: > + Define a capability class that inherits from tosca.capabilities.Container + +capability_types: + + tosca.capabilities.ContainerChild: + derived_from: tosca.capabilities.Container + +node_types: + + tosca.nodes.SomeNode: + derived_from: tosca.nodes.Root + properties: + some_prop: + type: string + requirements: + - host_child: + capability: tosca.capabilities.ContainerChild + node: tosca.nodes.SomeNode2 + relationship: tosca.relationships.HostedOn + + tosca.nodes.SomeNode2: + derived_from: tosca.nodes.Root + capabilities: + host_child: + type: tosca.capabilities.ContainerChild + requirements: + - host: + capability: tosca.capabilities.Container + node: tosca.nodes.Compute + relationship: tosca.relationships.HostedOn diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/custom_cap.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/custom_cap.yaml new file mode 100644 index 0000000..018bcf6 --- /dev/null +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/custom_cap.yaml @@ -0,0 +1,22 @@ +tosca_definitions_version: tosca_simple_yaml_1_0 + +capability_types: + + tosca.capabilities.SomeCap: + derived_from: tosca.capabilities.Container + +node_types: + + tosca.nodes.NodeWithReq: + derived_from: tosca.nodes.SoftwareComponent + requirements: + - host: + capability: tosca.capabilities.SomeCap + relationship: tosca.relationships.HostedOn + occurrences: [1, 1] + + tosca.nodes.NodeWithCap: + derived_from: tosca.nodes.SoftwareComponent + capabilities: + host: + type: tosca.capabilities.SomeCap diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/node_with_cap.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/node_with_cap.yaml index b17513f..332f830 100644 --- a/tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/node_with_cap.yaml +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/node_with_cap.yaml @@ -6,7 +6,7 @@ description: > capability_types: tosca.capabilities.SomeCap: - derived_from: tosca.capabilities.Root + derived_from: tosca.capabilities.Container properties: type: type: string @@ -19,6 +19,11 @@ node_types: tosca.nodes.SomeNode: derived_from: tosca.nodes.Root + properties: + some_prop: + type: string + required: false + default: some requirements: - some_req: capability: tosca.capabilities.SomeCap diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_container_cap_child.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_container_cap_child.yaml new file mode 100644 index 0000000..84118c8 --- /dev/null +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_container_cap_child.yaml @@ -0,0 +1,28 @@ +tosca_definitions_version: tosca_simple_yaml_1_0 + +description: > + TOSCA simple profile to test the get attribute function with HOST parameter + using a node that has as capability a child class of Container + +imports: + - ../custom_types/container_cap_child.yaml + +topology_template: + + node_templates: + + test_node: + type: tosca.nodes.SomeNode + properties: + some_prop: { get_attribute: [ HOST, public_address ] } + requirements: + - host_child: test_node2 + + test_node2: + type: tosca.nodes.SomeNode2 + requirements: + - host: server + + server: + type: tosca.nodes.Compute + diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_get_prop_cap_bool.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_get_prop_cap_bool.yaml new file mode 100644 index 0000000..d9c4c1c --- /dev/null +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_get_prop_cap_bool.yaml @@ -0,0 +1,37 @@ +tosca_definitions_version: tosca_simple_yaml_1_0 + +description: TOSCA test for boolean properties + +node_types: + + tosca.nodes.SoftwareComponentTest: + derived_from: tosca.nodes.SoftwareComponent + properties: + some_prop: + type: boolean + + tosca.nodes.ComputeTest: + derived_from: tosca.nodes.Compute + capabilities: + endpoint: + type: tosca.capabilities.Endpoint + +topology_template: + + node_templates: + + software: + type: tosca.nodes.SoftwareComponentTest + properties: + some_prop: { get_property: [ HOST, endpoint, secure ] } + requirements: + - host: server + + server: + type: tosca.nodes.ComputeTest + capabilities: + endpoint: + properties: + network_name: PUBLIC + secure: false + diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_get_prop_cap_host.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_get_prop_cap_host.yaml new file mode 100644 index 0000000..7fcb4a7 --- /dev/null +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_get_prop_cap_host.yaml @@ -0,0 +1,25 @@ +tosca_definitions_version: tosca_simple_yaml_1_0 + +description: TOSCA test for the IM + +imports: + - test: ../custom_types/node_with_cap.yaml + +topology_template: + + node_templates: + + some_node: + type: tosca.nodes.SomeNode + properties: + some_prop: { get_property: [ HOST, some_req, type ] } + requirements: + - some_req: server + + server: + type: tosca.nodes.NodeWithCap + capabilities: + some_req: + properties: + type: someval + diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/policies/tosca_policy_template.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/policies/tosca_policy_template.yaml index 47f7870..4c18d9d 100644 --- a/tosca2heat/tosca-parser/toscaparser/tests/data/policies/tosca_policy_template.yaml +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/policies/tosca_policy_template.yaml @@ -75,6 +75,32 @@ topology_template: inputs: strategy: LEAST_USED implementation: Senlin.webhook() + high_cpu_usage: + description: trigger + meter_name: cpu_util + condition: + constraint: utilization greater_than 60% + threshold: 60 + period: 600 + evaluations: 1 + method: average + comparison_operator: gt + metadata: SG1 + action: [SP1] + + low_cpu_usage: + description: trigger + meter_name: cpu_util + condition: + constraint: utilization less_than 20% + threshold: 20 + period: 600 + evaluations: 1 + method: average + comparison_operator: gt + metadata: SG1 + action: [SP1] + - my_groups_placement: type: mycompany.mytypes.myScalingPolicy targets: [ webserver_group ] diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/test_custom_capabilty.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/test_custom_capabilty.yaml new file mode 100644 index 0000000..03a8a07 --- /dev/null +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/test_custom_capabilty.yaml @@ -0,0 +1,23 @@ +tosca_definitions_version: tosca_simple_yaml_1_0 + +description: TOSCA simple profile to test a custom defined capability + +imports: + - custom_types/custom_cap.yaml + +topology_template: + + node_templates: + + node_req: + type: tosca.nodes.NodeWithReq + requirements: + - host: node_cap + + node_cap: + type: tosca.nodes.NodeWithCap + requirements: + - host: server + + server: + type: tosca.nodes.Compute diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/definitions.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/definitions.yaml index ba5eac1..300bb8a 100644 --- a/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/definitions.yaml +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/definitions.yaml @@ -49,7 +49,7 @@ node_types: derived_from: tosca.nodes.Database example.SomeApp: - derived_from: tosca.nodes.SoftwareComponent + derived_from: tosca.nodes.WebApplication properties: admin_user: type: string diff --git a/tosca2heat/tosca-parser/toscaparser/tests/test_functions.py b/tosca2heat/tosca-parser/toscaparser/tests/test_functions.py index fa60140..2e1d71e 100644 --- a/tosca2heat/tosca-parser/toscaparser/tests/test_functions.py +++ b/tosca2heat/tosca-parser/toscaparser/tests/test_functions.py @@ -188,6 +188,26 @@ class IntrinsicFunctionsTest(TestCase): self.assertIsInstance(source_port, functions.GetProperty) self.assertEqual(3306, source_port.result()) + def test_get_prop_cap_host(self): + tosca_tpl = os.path.join( + os.path.dirname(os.path.abspath(__file__)), + "data/functions/test_get_prop_cap_host.yaml") + some_node = self._get_node('some_node', + ToscaTemplate(tosca_tpl)) + some_prop = some_node.get_properties()['some_prop'] + self.assertIsInstance(some_prop.value, functions.GetProperty) + self.assertEqual('someval', some_prop.value.result()) + + def test_get_prop_cap_bool(self): + tosca_tpl = os.path.join( + os.path.dirname(os.path.abspath(__file__)), + "data/functions/test_get_prop_cap_bool.yaml") + some_node = self._get_node('software', + ToscaTemplate(tosca_tpl)) + some_prop = some_node.get_properties()['some_prop'] + self.assertIsInstance(some_prop.value, functions.GetProperty) + self.assertEqual(False, some_prop.value.result()) + class GetAttributeTest(TestCase): @@ -318,6 +338,10 @@ class GetAttributeTest(TestCase): self.assertIsNotNone(self._load_template( 'functions/test_get_implicit_attribute.yaml')) + def test_get_attribute_capability_inheritance(self): + self.assertIsNotNone(self._load_template( + 'functions/test_container_cap_child.yaml')) + class ConcatTest(TestCase): diff --git a/tosca2heat/tosca-parser/toscaparser/tests/test_topology_template.py b/tosca2heat/tosca-parser/toscaparser/tests/test_topology_template.py index 3aabc9b..a0d6dc3 100644 --- a/tosca2heat/tosca-parser/toscaparser/tests/test_topology_template.py +++ b/tosca2heat/tosca-parser/toscaparser/tests/test_topology_template.py @@ -91,7 +91,7 @@ class TopologyTemplateTest(TestCase): tpl_name = "app" expected_type = "example.SomeApp" expected_properties = ['admin_user', 'pool_size'] - expected_capabilities = ['feature', 'message_receiver'] + expected_capabilities = ['app_endpoint', 'feature', 'message_receiver'] expected_requirements = [{'host': {'node': 'websrv'}}] expected_relationshp = ['tosca.relationships.HostedOn'] expected_host = ['websrv'] diff --git a/tosca2heat/tosca-parser/toscaparser/tests/test_toscatplvalidation.py b/tosca2heat/tosca-parser/toscaparser/tests/test_toscatplvalidation.py index 911867f..f7c22ab 100644 --- a/tosca2heat/tosca-parser/toscaparser/tests/test_toscatplvalidation.py +++ b/tosca2heat/tosca-parser/toscaparser/tests/test_toscatplvalidation.py @@ -1581,7 +1581,7 @@ heat-translator/master/translator/tests/data/custom_types/wordpress.yaml lambda: Policy(name, policies[name], None, None)) self.assertEqual(expectedmessage, err.__str__()) - def test_policy_trigger_valid_keyname(self): + def test_policy_trigger_valid_keyname_senlin_resources(self): tpl_snippet = ''' triggers: - resize_compute: @@ -1610,7 +1610,28 @@ heat-translator/master/translator/tests/data/custom_types/wordpress.yaml name = list(triggers.keys())[0] Triggers(name, triggers[name]) - def test_policy_trigger_invalid_keyname(self): + def test_policy_trigger_valid_keyname_heat_resources(self): + tpl_snippet = ''' + triggers: + - high_cpu_usage: + description: trigger + meter_name: cpu_util + condition: + constraint: utilization greater_than 60% + threshold: 60 + period: 600 + evaluations: 1 + method: average + comparison_operator: gt + metadata: SG1 + action: [SP1] + ''' + triggers = (toscaparser.utils.yamlparser. + simple_parse(tpl_snippet))['triggers'][0] + name = list(triggers.keys())[0] + Triggers(name, triggers[name]) + + def test_policy_trigger_invalid_keyname_senlin_resources(self): tpl_snippet = ''' triggers: - resize_compute: @@ -1646,6 +1667,34 @@ heat-translator/master/translator/tests/data/custom_types/wordpress.yaml lambda: Triggers(name, triggers[name])) self.assertEqual(expectedmessage, err.__str__()) + def test_policy_trigger_invalid_keyname_heat_resources(self): + tpl_snippet = ''' + triggers: + - high_cpu_usage: + description: trigger + meter_name: cpu_util + condition: + constraint: utilization greater_than 60% + threshold: 60 + period: 600 + evaluations: 1 + method: average + comparison_operator: gt + metadata1: SG1 + action: [SP1] + ''' + triggers = (toscaparser.utils.yamlparser. + simple_parse(tpl_snippet))['triggers'][0] + name = list(triggers.keys())[0] + expectedmessage = _( + 'Triggers "high_cpu_usage" contains unknown field ' + '"metadata1". Refer to the definition ' + 'to verify valid values.') + err = self.assertRaises( + exception.UnknownFieldError, + lambda: Triggers(name, triggers[name])) + self.assertEqual(expectedmessage, err.__str__()) + def test_policy_missing_required_keyname(self): tpl_snippet = ''' policies: diff --git a/tosca2heat/tosca-parser/toscaparser/triggers.py b/tosca2heat/tosca-parser/toscaparser/triggers.py index 9edeef4..8e47eee 100644 --- a/tosca2heat/tosca-parser/toscaparser/triggers.py +++ b/tosca2heat/tosca-parser/toscaparser/triggers.py @@ -16,12 +16,16 @@ import logging from toscaparser.common.exception import ExceptionCollector from toscaparser.common.exception import UnknownFieldError from toscaparser.entity_template import EntityTemplate - -SECTIONS = (DESCRIPTION, EVENT, SCHEDULE, TARGET_FILTER, CONDITION, ACTION) = \ - ('description', 'event_type', 'schedule', - 'target_filter', 'condition', 'action') -CONDITION_KEYNAMES = (CONTRAINT, PERIOD, EVALUATIONS, METHOD) = \ - ('constraint', 'period', 'evaluations', 'method') +from toscaparser.utils import validateutils + +SECTIONS = (DESCRIPTION, EVENT, SCHEDULE, METER_NAME, METADATA, + TARGET_FILTER, CONDITION, ACTION) = \ + ('description', 'event_type', 'schedule', 'meter_name', + 'metadata', 'target_filter', 'condition', 'action') +CONDITION_KEYNAMES = (CONSTRAINT, PERIOD, EVALUATIONS, METHOD, + THRESHOLD, COMPARISON_OPERATOR) = \ + ('constraint', 'period', 'evaluations', + 'method', 'threshold', 'comparison_operator') log = logging.getLogger('tosca') @@ -34,6 +38,7 @@ class Triggers(EntityTemplate): self.trigger_tpl = trigger_tpl self._validate_keys() self._validate_condition() + self._validate_input() def get_description(self): return self.trigger_tpl['description'] @@ -66,3 +71,12 @@ class Triggers(EntityTemplate): ExceptionCollector.appendException( UnknownFieldError(what='Triggers "%s"' % self.name, field=key)) + + def _validate_input(self): + for key, value in self.get_condition().items(): + if key in [PERIOD, EVALUATIONS]: + validateutils.validate_integer(value) + elif key == THRESHOLD: + validateutils.validate_numeric(value) + elif key in [METER_NAME, METHOD]: + validateutils.validate_string(value) diff --git a/tosca2heat/tosca-parser/tox.ini b/tosca2heat/tosca-parser/tox.ini index 8fc2a88..3603a18 100644 --- a/tosca2heat/tosca-parser/tox.ini +++ b/tosca2heat/tosca-parser/tox.ini @@ -1,5 +1,5 @@ [tox] -minversion = 1.6 +minversion = 2.0 envlist = py27,pep8 skipsdist = True @@ -28,9 +28,6 @@ commands = python setup.py build_sphinx commands = oslo_debug_helper -t toscaparser/tests {posargs} [flake8] -# H803 skipped on purpose per list discussion. -# E123, E125 skipped as they are invalid PEP-8. - show-source = True ignore = E123,E125,H803 builtins = _ |