summaryrefslogtreecommitdiffstats
path: root/nfvparser
diff options
context:
space:
mode:
Diffstat (limited to 'nfvparser')
-rw-r--r--nfvparser/toscaparser/__init__.py2
-rw-r--r--nfvparser/toscaparser/capabilities.py6
-rw-r--r--nfvparser/toscaparser/common/exception.py9
-rw-r--r--nfvparser/toscaparser/elements/TOSCA_definition_1_0.yaml25
-rw-r--r--nfvparser/toscaparser/elements/capabilitytype.py2
-rw-r--r--nfvparser/toscaparser/elements/nodetype.py2
-rw-r--r--nfvparser/toscaparser/elements/policytype.py2
-rw-r--r--nfvparser/toscaparser/elements/statefulentitytype.py3
-rw-r--r--nfvparser/toscaparser/elements/tosca_type_validation.py7
-rw-r--r--nfvparser/toscaparser/entity_template.py2
-rw-r--r--nfvparser/toscaparser/functions.py57
-rw-r--r--nfvparser/toscaparser/parameters.py8
-rw-r--r--nfvparser/toscaparser/shell.py54
-rw-r--r--nfvparser/toscaparser/tests/data/custom_types/container_cap_child.yaml33
-rw-r--r--nfvparser/toscaparser/tests/data/custom_types/custom_cap.yaml22
-rw-r--r--nfvparser/toscaparser/tests/data/custom_types/nested_test_kibana.yaml3
-rw-r--r--nfvparser/toscaparser/tests/data/custom_types/node_with_cap.yaml7
-rw-r--r--nfvparser/toscaparser/tests/data/custom_types/wordpress.yml19
-rw-r--r--nfvparser/toscaparser/tests/data/functions/test_container_cap_child.yaml28
-rw-r--r--nfvparser/toscaparser/tests/data/functions/test_get_prop_cap_bool.yaml37
-rw-r--r--nfvparser/toscaparser/tests/data/functions/test_get_prop_cap_host.yaml25
-rw-r--r--nfvparser/toscaparser/tests/data/policies/tosca_policy_template.yaml26
-rw-r--r--nfvparser/toscaparser/tests/data/test_custom_capabilty.yaml23
-rw-r--r--nfvparser/toscaparser/tests/data/test_instance_nested_imports.yaml4
-rw-r--r--nfvparser/toscaparser/tests/data/topology_template/definitions.yaml2
-rw-r--r--nfvparser/toscaparser/tests/data/tosca_helloworld_with_version_1_1.yaml23
-rw-r--r--nfvparser/toscaparser/tests/test_functions.py24
-rw-r--r--nfvparser/toscaparser/tests/test_topology_template.py2
-rw-r--r--nfvparser/toscaparser/tests/test_toscatpl.py18
-rw-r--r--nfvparser/toscaparser/tests/test_toscatplvalidation.py66
-rw-r--r--nfvparser/toscaparser/topology_template.py2
-rw-r--r--nfvparser/toscaparser/tosca_template.py76
-rw-r--r--nfvparser/toscaparser/triggers.py26
33 files changed, 579 insertions, 66 deletions
diff --git a/nfvparser/toscaparser/__init__.py b/nfvparser/toscaparser/__init__.py
index d9745ed..63ddcd4 100644
--- a/nfvparser/toscaparser/__init__.py
+++ b/nfvparser/toscaparser/__init__.py
@@ -14,4 +14,4 @@ import pbr.version
__version__ = pbr.version.VersionInfo(
- 'tosca-parser').version_string()
+ 'nfv-toscaparser').version_string()
diff --git a/nfvparser/toscaparser/capabilities.py b/nfvparser/toscaparser/capabilities.py
index c23ef72..1708fd8 100644
--- a/nfvparser/toscaparser/capabilities.py
+++ b/nfvparser/toscaparser/capabilities.py
@@ -16,10 +16,11 @@ from toscaparser.properties import Property
class Capability(object):
'''TOSCA built-in capabilities type.'''
- def __init__(self, name, properties, definition):
+ def __init__(self, name, properties, definition, custom_def):
self.name = name
self._properties = properties
self.definition = definition
+ self.custom_def = custom_def
def get_properties_objects(self):
'''Return a list of property objects.'''
@@ -30,7 +31,8 @@ class Capability(object):
props_def = self.definition.get_properties_def()
if props_def and name in props_def:
properties.append(Property(name, value,
- props_def[name].schema))
+ props_def[name].schema,
+ self.custom_def))
return properties
def get_properties(self):
diff --git a/nfvparser/toscaparser/common/exception.py b/nfvparser/toscaparser/common/exception.py
index 13ccabd..67a9f7f 100644
--- a/nfvparser/toscaparser/common/exception.py
+++ b/nfvparser/toscaparser/common/exception.py
@@ -20,7 +20,7 @@ import traceback
from toscaparser.utils.gettextutils import _
-log = logging.getLogger(__name__)
+log = logging.getLogger('tosca')
class TOSCAException(Exception):
@@ -206,6 +206,13 @@ class ExceptionCollector(object):
raise exception
@staticmethod
+ def removeException(exception_type):
+ if ExceptionCollector.collecting and ExceptionCollector.exceptions:
+ for i, e in enumerate(ExceptionCollector.exceptions):
+ if isinstance(e, exception_type):
+ del ExceptionCollector.exceptions[i]
+
+ @staticmethod
def exceptionsCaught():
return len(ExceptionCollector.exceptions) > 0
diff --git a/nfvparser/toscaparser/elements/TOSCA_definition_1_0.yaml b/nfvparser/toscaparser/elements/TOSCA_definition_1_0.yaml
index 9f3369e..57c9bf9 100644
--- a/nfvparser/toscaparser/elements/TOSCA_definition_1_0.yaml
+++ b/nfvparser/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/nfvparser/toscaparser/elements/capabilitytype.py b/nfvparser/toscaparser/elements/capabilitytype.py
index 5fa9661..23c5afc 100644
--- a/nfvparser/toscaparser/elements/capabilitytype.py
+++ b/nfvparser/toscaparser/elements/capabilitytype.py
@@ -25,7 +25,7 @@ class CapabilityTypeDef(StatefulEntityType):
self.nodetype = ntype
self.properties = None
self.custom_def = custom_def
- if self.PROPERTIES in self.defs:
+ if self.defs and self.PROPERTIES in self.defs:
self.properties = self.defs[self.PROPERTIES]
self.parent_capabilities = self._get_parent_capabilities(custom_def)
diff --git a/nfvparser/toscaparser/elements/nodetype.py b/nfvparser/toscaparser/elements/nodetype.py
index 7f3da2d..4889ed8 100644
--- a/nfvparser/toscaparser/elements/nodetype.py
+++ b/nfvparser/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/nfvparser/toscaparser/elements/policytype.py b/nfvparser/toscaparser/elements/policytype.py
index a922d26..82aed0a 100644
--- a/nfvparser/toscaparser/elements/policytype.py
+++ b/nfvparser/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/nfvparser/toscaparser/elements/statefulentitytype.py b/nfvparser/toscaparser/elements/statefulentitytype.py
index 2f221b3..28ee697 100644
--- a/nfvparser/toscaparser/elements/statefulentitytype.py
+++ b/nfvparser/toscaparser/elements/statefulentitytype.py
@@ -46,7 +46,8 @@ class StatefulEntityType(EntityType):
elif custom_def and entitytype in list(custom_def.keys()):
self.defs = custom_def[entitytype]
else:
- self.defs = None
+ # avoid errors if self.defs = none
+ self.defs = {}
ExceptionCollector.appendException(
InvalidTypeError(what=entitytype))
self.type = entitytype
diff --git a/nfvparser/toscaparser/elements/tosca_type_validation.py b/nfvparser/toscaparser/elements/tosca_type_validation.py
index 82b0b46..89a6a03 100644
--- a/nfvparser/toscaparser/elements/tosca_type_validation.py
+++ b/nfvparser/toscaparser/elements/tosca_type_validation.py
@@ -23,13 +23,14 @@ class TypeValidation(object):
DATA_TYPES, ARTIFACT_TYPES, GROUP_TYPES,
RELATIONSHIP_TYPES, CAPABILITY_TYPES,
INTERFACE_TYPES, POLICY_TYPES,
- TOPOLOGY_TEMPLATE) = \
+ TOPOLOGY_TEMPLATE, METADATA) = \
('tosca_definitions_version', 'description', 'imports',
'dsl_definitions', 'node_types', 'repositories',
'data_types', 'artifact_types', 'group_types',
'relationship_types', 'capability_types',
- 'interface_types', 'policy_types', 'topology_template')
- VALID_TEMPLATE_VERSIONS = ['tosca_simple_yaml_1_0']
+ 'interface_types', 'policy_types', 'topology_template', 'metadata')
+ VALID_TEMPLATE_VERSIONS = ['tosca_simple_yaml_1_0',
+ 'tosca_simple_yaml_1_1']
exttools = ExtTools()
VALID_TEMPLATE_VERSIONS.extend(exttools.get_versions())
diff --git a/nfvparser/toscaparser/entity_template.py b/nfvparser/toscaparser/entity_template.py
index cc3d620..d454ac0 100644
--- a/nfvparser/toscaparser/entity_template.py
+++ b/nfvparser/toscaparser/entity_template.py
@@ -164,7 +164,7 @@ class EntityTemplate(object):
if 'properties' in props and props['properties']:
properties.update(props['properties'])
- cap = Capability(name, properties, c)
+ cap = Capability(name, properties, c, self.custom_def)
capability.append(cap)
return capability
diff --git a/nfvparser/toscaparser/functions.py b/nfvparser/toscaparser/functions.py
index d498229..b64f1bc 100644
--- a/nfvparser/toscaparser/functions.py
+++ b/nfvparser/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/nfvparser/toscaparser/parameters.py b/nfvparser/toscaparser/parameters.py
index 787db00..d2d2eb3 100644
--- a/nfvparser/toscaparser/parameters.py
+++ b/nfvparser/toscaparser/parameters.py
@@ -32,9 +32,10 @@ class Input(object):
'constraints', 'required', 'status',
'entry_schema')
- def __init__(self, name, schema_dict):
+ def __init__(self, name, schema_dict, custom_defs=None):
self.name = name
self.schema = Schema(name, schema_dict)
+ self.custom_defs = custom_defs or {}
self._validate_field()
self.validate_type(self.type)
@@ -75,7 +76,8 @@ class Input(object):
field=name))
def validate_type(self, input_type):
- if input_type not in Schema.PROPERTY_TYPES:
+ if input_type not in Schema.PROPERTY_TYPES and \
+ input_type not in self.custom_defs:
ExceptionCollector.appendException(
ValueError(_('Invalid type "%s".') % type))
@@ -89,6 +91,8 @@ class Input(object):
datatype = tosca[self.type]
elif EntityType.DATATYPE_NETWORK_PREFIX + self.type in tosca:
datatype = tosca[EntityType.DATATYPE_NETWORK_PREFIX + self.type]
+ elif self.type in self.custom_defs:
+ datatype = self.custom_defs
DataEntity.validate_datatype(self.type, value, None, datatype)
diff --git a/nfvparser/toscaparser/shell.py b/nfvparser/toscaparser/shell.py
index 1d98f1a..88c7473 100644
--- a/nfvparser/toscaparser/shell.py
+++ b/nfvparser/toscaparser/shell.py
@@ -12,9 +12,11 @@
import argparse
+import logging
import os
import sys
+from toscaparser.common.exception import ValidationError
from toscaparser.tosca_template import ToscaTemplate
from toscaparser.utils.gettextutils import _
import toscaparser.utils.urlutils
@@ -38,6 +40,8 @@ e.g.
--template-file=toscaparser/tests/data/CSAR/csar_hello_world.zip
"""
+log = logging.getLogger("tosca.model")
+
class ParserShell(object):
@@ -49,41 +53,67 @@ class ParserShell(object):
required=True,
help=_('YAML template or CSAR file to parse.'))
+ parser.add_argument('-nrpv', dest='no_required_paras_check',
+ action='store_true', default=False,
+ help=_('Ignore input parameter validation '
+ 'when parse template.'))
+
+ parser.add_argument('--debug', dest='debug_mode',
+ action='store_true', default=False,
+ help=_('debug mode for print more details '
+ 'other than raise exceptions when '
+ 'errors happen as possible'))
+
return parser
def main(self, argv):
parser = self.get_parser(argv)
(args, extra_args) = parser.parse_known_args(argv)
path = args.template_file
+ nrpv = args.no_required_paras_check
+ debug = args.debug_mode
+
if os.path.isfile(path):
- self.parse(path)
+ self.parse(path, no_required_paras_check=nrpv, debug_mode=debug)
elif toscaparser.utils.urlutils.UrlUtils.validate_url(path):
- self.parse(path, False)
+ self.parse(path, False,
+ no_required_paras_check=nrpv,
+ debug_mode=debug)
else:
raise ValueError(_('"%(path)s" is not a valid file.')
% {'path': path})
- def parse(self, path, a_file=True):
- output = None
- tosca = ToscaTemplate(path, None, a_file)
-
- version = tosca.version
- if tosca.version:
+ def parse(self, path, a_file=True, no_required_paras_check=False,
+ debug_mode=False):
+ nrpv = no_required_paras_check
+ try:
+ tosca = ToscaTemplate(path, None, a_file,
+ no_required_paras_check=nrpv,
+ debug_mode=debug_mode)
+ except ValidationError as e:
+ log.error(e.message)
+ if debug_mode:
+ print(e.message)
+ else:
+ raise e
+
+ version = tosca.version if tosca else "unknown"
+ if tosca and tosca.version:
print("\nversion: " + version)
- if hasattr(tosca, 'description'):
+ if tosca and hasattr(tosca, 'description'):
description = tosca.description
if description:
print("\ndescription: " + description)
- if hasattr(tosca, 'inputs'):
+ if tosca and hasattr(tosca, 'inputs'):
inputs = tosca.inputs
if inputs:
print("\ninputs:")
for input in inputs:
print("\t" + input.name)
- if hasattr(tosca, 'nodetemplates'):
+ if tosca and hasattr(tosca, 'nodetemplates'):
nodetemplates = tosca.nodetemplates
if nodetemplates:
print("\nnodetemplates:")
@@ -102,7 +132,7 @@ class ParserShell(object):
for trigger in policy.triggers:
print("\ttrigger name:" + trigger.name)'''
- if hasattr(tosca, 'outputs'):
+ if tosca and hasattr(tosca, 'outputs'):
outputs = tosca.outputs
if outputs:
print("\noutputs:")
diff --git a/nfvparser/toscaparser/tests/data/custom_types/container_cap_child.yaml b/nfvparser/toscaparser/tests/data/custom_types/container_cap_child.yaml
new file mode 100644
index 0000000..1df09dd
--- /dev/null
+++ b/nfvparser/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/nfvparser/toscaparser/tests/data/custom_types/custom_cap.yaml b/nfvparser/toscaparser/tests/data/custom_types/custom_cap.yaml
new file mode 100644
index 0000000..018bcf6
--- /dev/null
+++ b/nfvparser/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/nfvparser/toscaparser/tests/data/custom_types/nested_test_kibana.yaml b/nfvparser/toscaparser/tests/data/custom_types/nested_test_kibana.yaml
new file mode 100644
index 0000000..c8675c6
--- /dev/null
+++ b/nfvparser/toscaparser/tests/data/custom_types/nested_test_kibana.yaml
@@ -0,0 +1,3 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+imports:
+ - custom_types/kibana.yaml
diff --git a/nfvparser/toscaparser/tests/data/custom_types/node_with_cap.yaml b/nfvparser/toscaparser/tests/data/custom_types/node_with_cap.yaml
index b17513f..332f830 100644
--- a/nfvparser/toscaparser/tests/data/custom_types/node_with_cap.yaml
+++ b/nfvparser/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/nfvparser/toscaparser/tests/data/custom_types/wordpress.yml b/nfvparser/toscaparser/tests/data/custom_types/wordpress.yml
new file mode 100644
index 0000000..5899ed9
--- /dev/null
+++ b/nfvparser/toscaparser/tests/data/custom_types/wordpress.yml
@@ -0,0 +1,19 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+node_types:
+ tosca.nodes.WebApplication.WordPress:
+ derived_from: tosca.nodes.WebApplication
+ requirements:
+ - database_endpoint:
+ capability: tosca.capabilities.Endpoint.Database
+ node: tosca.nodes.Database
+ relationship: tosca.relationships.ConnectsTo
+ interfaces:
+ Standard:
+ inputs:
+ wp_db_name:
+ type: string
+ wp_db_user:
+ type: string
+ wp_db_password:
+ type: string
diff --git a/nfvparser/toscaparser/tests/data/functions/test_container_cap_child.yaml b/nfvparser/toscaparser/tests/data/functions/test_container_cap_child.yaml
new file mode 100644
index 0000000..84118c8
--- /dev/null
+++ b/nfvparser/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/nfvparser/toscaparser/tests/data/functions/test_get_prop_cap_bool.yaml b/nfvparser/toscaparser/tests/data/functions/test_get_prop_cap_bool.yaml
new file mode 100644
index 0000000..d9c4c1c
--- /dev/null
+++ b/nfvparser/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/nfvparser/toscaparser/tests/data/functions/test_get_prop_cap_host.yaml b/nfvparser/toscaparser/tests/data/functions/test_get_prop_cap_host.yaml
new file mode 100644
index 0000000..7fcb4a7
--- /dev/null
+++ b/nfvparser/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/nfvparser/toscaparser/tests/data/policies/tosca_policy_template.yaml b/nfvparser/toscaparser/tests/data/policies/tosca_policy_template.yaml
index 47f7870..4c18d9d 100644
--- a/nfvparser/toscaparser/tests/data/policies/tosca_policy_template.yaml
+++ b/nfvparser/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/nfvparser/toscaparser/tests/data/test_custom_capabilty.yaml b/nfvparser/toscaparser/tests/data/test_custom_capabilty.yaml
new file mode 100644
index 0000000..03a8a07
--- /dev/null
+++ b/nfvparser/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/nfvparser/toscaparser/tests/data/test_instance_nested_imports.yaml b/nfvparser/toscaparser/tests/data/test_instance_nested_imports.yaml
index 6aa9307..a130e49 100644
--- a/nfvparser/toscaparser/tests/data/test_instance_nested_imports.yaml
+++ b/nfvparser/toscaparser/tests/data/test_instance_nested_imports.yaml
@@ -5,6 +5,7 @@ description: >
imports:
- wordpress: custom_types/nested_test_wordpress.yaml
+ - custom_types/nested_test_kibana.yaml
topology_template:
@@ -20,3 +21,6 @@ topology_template:
logstash:
type: tosca.nodes.SoftwareComponent.Logstash
+
+ kibana:
+ type: tosca.nodes.SoftwareComponent.Kibana
diff --git a/nfvparser/toscaparser/tests/data/topology_template/definitions.yaml b/nfvparser/toscaparser/tests/data/topology_template/definitions.yaml
index ba5eac1..300bb8a 100644
--- a/nfvparser/toscaparser/tests/data/topology_template/definitions.yaml
+++ b/nfvparser/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/nfvparser/toscaparser/tests/data/tosca_helloworld_with_version_1_1.yaml b/nfvparser/toscaparser/tests/data/tosca_helloworld_with_version_1_1.yaml
new file mode 100644
index 0000000..eeb5f7b
--- /dev/null
+++ b/nfvparser/toscaparser/tests/data/tosca_helloworld_with_version_1_1.yaml
@@ -0,0 +1,23 @@
+tosca_definitions_version: tosca_simple_yaml_1_1
+
+description: Template for deploying a single server with predefined properties.
+
+topology_template:
+ node_templates:
+ my_server:
+ type: tosca.nodes.Compute
+ capabilities:
+ # Host container properties
+ host:
+ properties:
+ num_cpus: 2
+ disk_size: 10 GB
+ mem_size: 512 MB
+ # Guest Operating System properties
+ os:
+ properties:
+ # host Operating System image properties
+ architecture: x86_64
+ type: Linux
+ distribution: RHEL
+ version: 6.5
diff --git a/nfvparser/toscaparser/tests/test_functions.py b/nfvparser/toscaparser/tests/test_functions.py
index fa60140..2e1d71e 100644
--- a/nfvparser/toscaparser/tests/test_functions.py
+++ b/nfvparser/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/nfvparser/toscaparser/tests/test_topology_template.py b/nfvparser/toscaparser/tests/test_topology_template.py
index 3aabc9b..a0d6dc3 100644
--- a/nfvparser/toscaparser/tests/test_topology_template.py
+++ b/nfvparser/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/nfvparser/toscaparser/tests/test_toscatpl.py b/nfvparser/toscaparser/tests/test_toscatpl.py
index fac8687..fd8ee90 100644
--- a/nfvparser/toscaparser/tests/test_toscatpl.py
+++ b/nfvparser/toscaparser/tests/test_toscatpl.py
@@ -216,6 +216,10 @@ class ToscaTemplateTest(TestCase):
tosca_tpl = self._load_template('test_no_outputs_in_template.yaml')
self.assertEqual(0, len(tosca_tpl.outputs))
+ def test_template_file_with_suffix_yml(self):
+ tosca_tpl = self._load_template('custom_types/wordpress.yml')
+ self.assertIsNotNone(tosca_tpl)
+
def test_relationship_interface(self):
template = ToscaTemplate(self.tosca_elk_tpl)
for node_tpl in template.nodetemplates:
@@ -510,7 +514,8 @@ class ToscaTemplateTest(TestCase):
os.path.dirname(os.path.abspath(__file__)),
"data/test_instance_nested_imports.yaml")
tosca = ToscaTemplate(tosca_tpl)
- expected_custom_types = ['tosca.nodes.WebApplication.WordPress',
+ expected_custom_types = ['tosca.nodes.SoftwareComponent.Kibana',
+ 'tosca.nodes.WebApplication.WordPress',
'test_namespace_prefix.Rsyslog',
'Test2ndRsyslogType',
'test_2nd_namespace_prefix.Rsyslog',
@@ -661,6 +666,17 @@ class ToscaTemplateTest(TestCase):
self.assertEqual(tosca.version, "tosca_simple_yaml_1_0")
+ def test_yaml_dict_tpl_with_version_1_1(self):
+ test_tpl = os.path.join(
+ os.path.dirname(os.path.abspath(__file__)),
+ "data/tosca_helloworld_with_version_1_1.yaml")
+
+ yaml_dict_tpl = toscaparser.utils.yamlparser.load_yaml(test_tpl)
+
+ tosca = ToscaTemplate(yaml_dict_tpl=yaml_dict_tpl)
+
+ self.assertEqual(tosca.version, "tosca_simple_yaml_1_1")
+
def test_yaml_dict_tpl_with_params_and_url_import(self):
test_tpl = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
diff --git a/nfvparser/toscaparser/tests/test_toscatplvalidation.py b/nfvparser/toscaparser/tests/test_toscatplvalidation.py
index 911867f..a8b1590 100644
--- a/nfvparser/toscaparser/tests/test_toscatplvalidation.py
+++ b/nfvparser/toscaparser/tests/test_toscatplvalidation.py
@@ -101,6 +101,7 @@ class ToscaTemplateValidationTest(TestCase):
_('The template version "tosca_simple_yaml_1_10 in '
'custom_types/imported_sample.yaml" is invalid. '
'Valid versions are "tosca_simple_yaml_1_0, '
+ 'tosca_simple_yaml_1_1, '
'tosca_simple_profile_for_nfv_1_0_0".'))
exception.ExceptionCollector.assertExceptionMessage(
exception.UnknownFieldError,
@@ -446,6 +447,18 @@ heat-translator/master/translator/tests/data/custom_types/wordpress.yaml
self.assertTrue(custom_defs.get("mycompany.tosca.nodes."
"WebApplication.WordPress"))
+ def test_imports_file_with_suffix_yml(self):
+ tpl_snippet = '''
+ imports:
+ - custom_types/wordpress.yml
+ '''
+ path = 'toscaparser/tests/data/tosca_elk.yaml'
+ custom_defs = self._imports_content_test(tpl_snippet,
+ path,
+ "node_types")
+ self.assertTrue(custom_defs.get("tosca.nodes."
+ "WebApplication.WordPress"))
+
def test_import_error_file_uri(self):
tpl_snippet = '''
imports:
@@ -1581,7 +1594,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 +1623,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 +1680,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/nfvparser/toscaparser/topology_template.py b/nfvparser/toscaparser/topology_template.py
index 4571fe7..080108e 100644
--- a/nfvparser/toscaparser/topology_template.py
+++ b/nfvparser/toscaparser/topology_template.py
@@ -66,7 +66,7 @@ class TopologyTemplate(object):
def _inputs(self):
inputs = []
for name, attrs in self._tpl_inputs().items():
- input = Input(name, attrs)
+ input = Input(name, attrs, self.custom_defs)
if self.parsed_params and name in self.parsed_params:
input.validate(self.parsed_params[name])
else:
diff --git a/nfvparser/toscaparser/tosca_template.py b/nfvparser/toscaparser/tosca_template.py
index f48078f..b0df424 100644
--- a/nfvparser/toscaparser/tosca_template.py
+++ b/nfvparser/toscaparser/tosca_template.py
@@ -18,6 +18,9 @@ from copy import deepcopy
from toscaparser.common.exception import ExceptionCollector
from toscaparser.common.exception import InvalidTemplateVersion
from toscaparser.common.exception import MissingRequiredFieldError
+from toscaparser.common.exception import MissingRequiredInputError
+from toscaparser.common.exception import MissingRequiredOutputError
+from toscaparser.common.exception import MissingRequiredParameterError
from toscaparser.common.exception import UnknownFieldError
from toscaparser.common.exception import ValidationError
from toscaparser.elements.entity_type import update_definitions
@@ -55,17 +58,21 @@ YAML_LOADER = toscaparser.utils.yamlparser.load_yaml
class ToscaTemplate(object):
exttools = ExtTools()
- VALID_TEMPLATE_VERSIONS = ['tosca_simple_yaml_1_0']
+ VALID_TEMPLATE_VERSIONS = ['tosca_simple_yaml_1_0',
+ 'tosca_simple_yaml_1_1']
VALID_TEMPLATE_VERSIONS.extend(exttools.get_versions())
- ADDITIONAL_SECTIONS = {'tosca_simple_yaml_1_0': SPECIAL_SECTIONS}
+ ADDITIONAL_SECTIONS = {'tosca_simple_yaml_1_0': SPECIAL_SECTIONS,
+ 'tosca_simple_yaml_1_1': SPECIAL_SECTIONS}
ADDITIONAL_SECTIONS.update(exttools.get_sections())
'''Load the template data.'''
def __init__(self, path=None, parsed_params=None, a_file=True,
- yaml_dict_tpl=None, sub_mapped_node_template=None):
+ yaml_dict_tpl=None, sub_mapped_node_template=None,
+ no_required_paras_check=False,
+ debug_mode=False):
if sub_mapped_node_template is None:
ExceptionCollector.start()
self.a_file = a_file
@@ -75,6 +82,9 @@ class ToscaTemplate(object):
self.sub_mapped_node_template = sub_mapped_node_template
self.nested_tosca_tpls_with_topology = {}
self.nested_tosca_templates_with_topology = []
+ self.no_required_paras_check = no_required_paras_check
+ self.debug_mode = debug_mode
+
if path:
self.input_path = path
self.path = self._get_path(path)
@@ -233,16 +243,36 @@ class ToscaTemplate(object):
if self._is_sub_mapped_node(nodetemplate, tosca_tpl):
parsed_params = self._get_params_for_nested_template(
nodetemplate)
- nested_template = ToscaTemplate(
- path=fname, parsed_params=parsed_params,
- yaml_dict_tpl=tosca_tpl,
- sub_mapped_node_template=nodetemplate)
- if nested_template._has_substitution_mappings():
+
+ cache_exeptions = deepcopy(ExceptionCollector.exceptions)
+ cache_exeptions_state = \
+ deepcopy(ExceptionCollector.collecting)
+ nested_template = None
+ try:
+ nrpv = self.no_required_paras_check
+ nested_template = ToscaTemplate(
+ path=fname, parsed_params=parsed_params,
+ sub_mapped_node_template=nodetemplate,
+ no_required_paras_check=nrpv,
+ debug_mode=self.debug_mode)
+ except ValidationError as e:
+ log.error(e.message)
+ if self.debug_mode:
+ print(e.message)
+ else:
+ raise e
+
+ ExceptionCollector.exceptions = deepcopy(cache_exeptions)
+ ExceptionCollector.collecting = \
+ deepcopy(cache_exeptions_state)
+
+ if nested_template and \
+ nested_template._has_substitution_mappings():
# Record the nested templates in top level template
self.nested_tosca_templates_with_topology.\
append(nested_template)
# Set the substitution toscatemplate for mapped node
- nodetemplate.sub_mapping_tosca_template = \
+ nodetemplate.substitution_mapped = \
nested_template
def _validate_field(self):
@@ -268,11 +298,12 @@ class ToscaTemplate(object):
what=version,
valid_versions=', '. join(self.VALID_TEMPLATE_VERSIONS)))
else:
- if version != 'tosca_simple_yaml_1_0':
+ if (version != 'tosca_simple_yaml_1_0' and
+ version != 'tosca_simple_yaml_1_1'):
update_definitions(version)
def _get_path(self, path):
- if path.lower().endswith('.yaml'):
+ if path.lower().endswith('.yaml') or path.lower().endswith('.yml'):
return path
elif path.lower().endswith(('.zip', '.csar')):
# a CSAR archive
@@ -287,18 +318,37 @@ class ToscaTemplate(object):
% {'path': path}))
def verify_template(self):
+ if self.no_required_paras_check:
+ ExceptionCollector.removeException(
+ MissingRequiredParameterError)
+ ExceptionCollector.removeException(
+ MissingRequiredInputError)
+ ExceptionCollector.removeException(
+ MissingRequiredOutputError)
if ExceptionCollector.exceptionsCaught():
if self.input_path:
- raise ValidationError(
+ exceptions = ValidationError(
message=(_('\nThe input "%(path)s" failed validation with '
'the following error(s): \n\n\t')
% {'path': self.input_path}) +
'\n\t'.join(ExceptionCollector.getExceptionsReport()))
else:
- raise ValidationError(
+ exceptions = ValidationError(
message=_('\nThe pre-parsed input failed validation with '
'the following error(s): \n\n\t') +
'\n\t'.join(ExceptionCollector.getExceptionsReport()))
+ if not self.debug_mode:
+ raise exceptions
+ else:
+ if self.sub_mapped_node_template:
+ msg = _('======== nested service template ======== ')
+
+ else:
+ msg = _('======== main service template ======== ')
+ print(msg)
+ print(exceptions.message)
+ log.error(msg)
+ log.error(exceptions.message)
else:
if self.input_path:
msg = (_('The input "%(path)s" successfully passed '
diff --git a/nfvparser/toscaparser/triggers.py b/nfvparser/toscaparser/triggers.py
index 9edeef4..8e47eee 100644
--- a/nfvparser/toscaparser/triggers.py
+++ b/nfvparser/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)