diff options
author | Sudhakar Reddy <Sudhakar.Reddy@amdocs.com> | 2018-10-10 04:39:35 +0000 |
---|---|---|
committer | Gerrit Code Review <gerrit@onap.org> | 2018-10-10 04:39:35 +0000 |
commit | 9abc9c644a96e74612a995b7194c69167317a6ae (patch) | |
tree | 188151d737a8ea38dffe651d9ed21396cebb4c29 /azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py | |
parent | 5c37beb20ca804afc810074463275d87436a65df (diff) | |
parent | 7409dfb144cf2a06210400134d822a1393462b1f (diff) |
Merge "vFW and vDNS support added to azure-plugin"1.2.0
Diffstat (limited to 'azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py')
-rw-r--r-- | azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py | 750 |
1 files changed, 750 insertions, 0 deletions
diff --git a/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py new file mode 100644 index 0000000..d960e05 --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py @@ -0,0 +1,750 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Creates ARIA service template models based on the TOSCA presentation. + +Relies on many helper methods in the presentation classes. +""" + +#pylint: disable=unsubscriptable-object + +import os +import re +from types import FunctionType +from datetime import datetime + +from ruamel import yaml + +from aria.parser.validation import Issue +from aria.utils.formatting import string_list_as_string +from aria.utils.collections import (StrictDict, OrderedDict) +from aria.orchestrator import WORKFLOW_DECORATOR_RESERVED_ARGUMENTS +from aria.modeling.models import (Type, ServiceTemplate, NodeTemplate, + RequirementTemplate, RelationshipTemplate, CapabilityTemplate, + GroupTemplate, PolicyTemplate, SubstitutionTemplate, + SubstitutionTemplateMapping, InterfaceTemplate, OperationTemplate, + ArtifactTemplate, Metadata, Input, Output, Property, + Attribute, Configuration, PluginSpecification) + +from .parameters import coerce_parameter_value +from .constraints import (Equal, GreaterThan, GreaterOrEqual, LessThan, LessOrEqual, InRange, + ValidValues, Length, MinLength, MaxLength, Pattern) +from ..data_types import coerce_value + + +# These match the first un-escaped ">" +# See: http://stackoverflow.com/a/11819111/849021 +IMPLEMENTATION_PREFIX_REGEX = re.compile(r'(?<!\\)(?:\\\\)*>') + + +def create_service_template_model(context): # pylint: disable=too-many-locals,too-many-branches + model = ServiceTemplate(created_at=datetime.now(), + main_file_name=os.path.basename(str(context.presentation.location))) + + model.description = context.presentation.get('service_template', 'description', 'value') + + # Metadata + metadata = context.presentation.get('service_template', 'metadata') + if metadata is not None: + create_metadata_models(context, model, metadata) + + # Types + model.node_types = Type(variant='node') + create_types(context, + model.node_types, + context.presentation.get('service_template', 'node_types')) + model.group_types = Type(variant='group') + create_types(context, + model.group_types, + context.presentation.get('service_template', 'group_types')) + model.policy_types = Type(variant='policy') + create_types(context, + model.policy_types, + context.presentation.get('service_template', 'policy_types')) + model.relationship_types = Type(variant='relationship') + create_types(context, + model.relationship_types, + context.presentation.get('service_template', 'relationship_types')) + model.capability_types = Type(variant='capability') + create_types(context, + model.capability_types, + context.presentation.get('service_template', 'capability_types')) + model.interface_types = Type(variant='interface') + create_types(context, + model.interface_types, + context.presentation.get('service_template', 'interface_types')) + model.artifact_types = Type(variant='artifact') + create_types(context, + model.artifact_types, + context.presentation.get('service_template', 'artifact_types')) + + # Topology template + topology_template = context.presentation.get('service_template', 'topology_template') + if topology_template is not None: + model.inputs.update( + create_input_models_from_values(topology_template._get_input_values(context))) + model.outputs.update( + create_output_models_from_values(topology_template._get_output_values(context))) + + # Plugin specifications + policies = context.presentation.get('service_template', 'topology_template', 'policies') + if policies: + for policy in policies.itervalues(): + role = model.policy_types.get_descendant(policy.type).role + if role == 'plugin': + plugin_specification = create_plugin_specification_model(context, policy) + model.plugin_specifications[plugin_specification.name] = plugin_specification + elif role == 'workflow': + operation_template = create_workflow_operation_template_model(context, + model, policy) + model.workflow_templates[operation_template.name] = operation_template + + # Node templates + node_templates = context.presentation.get('service_template', 'topology_template', + 'node_templates') + if node_templates: + for node_template in node_templates.itervalues(): + node_template_model = create_node_template_model(context, model, node_template) + model.node_templates[node_template_model.name] = node_template_model + for node_template in node_templates.itervalues(): + fix_node_template_model(context, model, node_template) + + # Group templates + groups = context.presentation.get('service_template', 'topology_template', 'groups') + if groups: + for group in groups.itervalues(): + group_template_model = create_group_template_model(context, model, group) + model.group_templates[group_template_model.name] = group_template_model + + # Policy templates + policies = context.presentation.get('service_template', 'topology_template', 'policies') + if policies: + for policy in policies.itervalues(): + policy_template_model = create_policy_template_model(context, model, policy) + model.policy_templates[policy_template_model.name] = policy_template_model + + # Substitution template + substitution_mappings = context.presentation.get('service_template', 'topology_template', + 'substitution_mappings') + if substitution_mappings: + model.substitution_template = create_substitution_template_model(context, model, + substitution_mappings) + + return model + + +def create_metadata_models(context, service_template, metadata): + service_template.meta_data['template_name'] = Metadata(name='template_name', + value=metadata.template_name) + service_template.meta_data['template_author'] = Metadata(name='template_author', + value=metadata.template_author) + service_template.meta_data['template_version'] = Metadata(name='template_version', + value=metadata.template_version) + custom = metadata.custom + if custom: + for name, value in custom.iteritems(): + service_template.meta_data[name] = Metadata(name=name, + value=value) + + +def create_node_template_model(context, service_template, node_template): + node_type = node_template._get_type(context) + node_type = service_template.node_types.get_descendant(node_type._name) + model = NodeTemplate(name=node_template._name, type=node_type) + + if node_template.description: + model.description = node_template.description.value + + if node_template.directives: + model.directives = node_template.directives + + model.properties.update(create_property_models_from_values( + template_properties=node_template._get_property_values(context))) + model.attributes.update(create_attribute_models_from_values( + template_attributes=node_template._get_attribute_default_values(context))) + + create_interface_template_models(context, service_template, model.interface_templates, + node_template._get_interfaces(context)) + + artifacts = node_template._get_artifacts(context) + if artifacts: + for artifact_name, artifact in artifacts.iteritems(): + model.artifact_templates[artifact_name] = \ + create_artifact_template_model(context, service_template, artifact) + + capabilities = node_template._get_capabilities(context) + if capabilities: + for capability_name, capability in capabilities.iteritems(): + model.capability_templates[capability_name] = \ + create_capability_template_model(context, service_template, capability) + + if node_template.node_filter: + model.target_node_template_constraints = [] + create_node_filter_constraints(context, node_template.node_filter, + model.target_node_template_constraints) + + return model + + +def fix_node_template_model(context, service_template, node_template): + # Requirements have to be created after all node templates have been created, because + # requirements might reference another node template + model = service_template.node_templates[node_template._name] + requirements = node_template._get_requirements(context) + if requirements: + for _, requirement in requirements: + model.requirement_templates.append(create_requirement_template_model(context, + service_template, + requirement)) + + +def create_group_template_model(context, service_template, group): + group_type = group._get_type(context) + group_type = service_template.group_types.get_descendant(group_type._name) + model = GroupTemplate(name=group._name, + type=group_type) + + if group.description: + model.description = group.description.value + + model.properties.update(create_property_models_from_values(group._get_property_values(context))) + + create_interface_template_models(context, service_template, model.interface_templates, + group._get_interfaces(context)) + members = group.members + if members: + for member in members: + node_template = service_template.node_templates[member] + assert node_template + model.node_templates.append(node_template) + + return model + + +def create_policy_template_model(context, service_template, policy): + policy_type = policy._get_type(context) + policy_type = service_template.policy_types.get_descendant(policy_type._name) + model = PolicyTemplate(name=policy._name, + type=policy_type) + + if policy.description: + model.description = policy.description.value + + model.properties.update( + create_property_models_from_values(policy._get_property_values(context))) + + node_templates, groups = policy._get_targets(context) + if node_templates: + for target in node_templates: + node_template = service_template.node_templates[target._name] + assert node_template + model.node_templates.append(node_template) + if groups: + for target in groups: + group_template = service_template.group_templates[target._name] + assert group_template + model.group_templates.append(group_template) + + return model + + +def create_requirement_template_model(context, service_template, requirement): + model = {'name': requirement._name} + + node, node_variant = requirement._get_node(context) + if node is not None: + if node_variant == 'node_type': + node_type = service_template.node_types.get_descendant(node._name) + model['target_node_type'] = node_type + else: + node_template = service_template.node_templates[node._name] + model['target_node_template'] = node_template + + capability, capability_variant = requirement._get_capability(context) + if capability is not None: + if capability_variant == 'capability_type': + capability_type = \ + service_template.capability_types.get_descendant(capability._name) + model['target_capability_type'] = capability_type + else: + model['target_capability_name'] = capability._name + + model = RequirementTemplate(**model) + + if requirement.node_filter: + model.target_node_template_constraints = [] + create_node_filter_constraints(context, requirement.node_filter, + model.target_node_template_constraints) + + relationship = requirement.relationship + if relationship is not None: + model.relationship_template = \ + create_relationship_template_model(context, service_template, relationship) + model.relationship_template.name = requirement._name + + return model + + +def create_relationship_template_model(context, service_template, relationship): + relationship_type, relationship_type_variant = relationship._get_type(context) + if relationship_type_variant == 'relationship_type': + relationship_type = service_template.relationship_types.get_descendant( + relationship_type._name) + model = RelationshipTemplate(type=relationship_type) + else: + relationship_template = relationship_type + relationship_type = relationship_template._get_type(context) + relationship_type = service_template.relationship_types.get_descendant( + relationship_type._name) + model = RelationshipTemplate(type=relationship_type) + if relationship_template.description: + model.description = relationship_template.description.value + + create_parameter_models_from_assignments(model.properties, + relationship.properties, + model_cls=Property) + create_interface_template_models(context, service_template, model.interface_templates, + relationship.interfaces) + + return model + + +def create_capability_template_model(context, service_template, capability): + capability_type = capability._get_type(context) + capability_type = service_template.capability_types.get_descendant(capability_type._name) + model = CapabilityTemplate(name=capability._name, + type=capability_type) + + capability_definition = capability._get_definition(context) + if capability_definition.description: + model.description = capability_definition.description.value + occurrences = capability_definition.occurrences + if occurrences is not None: + model.min_occurrences = occurrences.value[0] + if occurrences.value[1] != 'UNBOUNDED': + model.max_occurrences = occurrences.value[1] + + valid_source_types = capability_definition.valid_source_types + if valid_source_types: + for valid_source_type in valid_source_types: + # TODO: handle shortcut type names + node_type = service_template.node_types.get_descendant(valid_source_type) + model.valid_source_node_types.append(node_type) + + create_parameter_models_from_assignments(model.properties, + capability.properties, + model_cls=Property) + + return model + + +def create_interface_template_model(context, service_template, interface): + interface_type = interface._get_type(context) + interface_type = service_template.interface_types.get_descendant(interface_type._name) + model = InterfaceTemplate(name=interface._name, type=interface_type) + + if interface_type.description: + model.description = interface_type.description + + create_parameter_models_from_assignments(model.inputs, interface.inputs, model_cls=Input) + + operations = interface.operations + if operations: + for operation_name, operation in operations.iteritems(): + model.operation_templates[operation_name] = \ + create_operation_template_model(context, service_template, operation) + + return model if model.operation_templates else None + + +def create_operation_template_model(context, service_template, operation): + model = OperationTemplate(name=operation._name) + + if operation.description: + model.description = operation.description.value + + implementation = operation.implementation + if implementation is not None: + primary = implementation.primary + extract_implementation_primary(context, service_template, operation, model, primary) + relationship_edge = operation._get_extensions(context).get('relationship_edge') + if relationship_edge is not None: + if relationship_edge == 'source': + model.relationship_edge = False + elif relationship_edge == 'target': + model.relationship_edge = True + + dependencies = implementation.dependencies + configuration = OrderedDict() + if dependencies: + for dependency in dependencies: + key, value = split_prefix(dependency) + if key is not None: + # Special ARIA prefix: signifies configuration parameters + + # Parse as YAML + try: + value = yaml.load(value) + except yaml.parser.MarkedYAMLError as e: + context.validation.report( + 'YAML parser {0} in operation configuration: {1}' + .format(e.problem, value), + locator=implementation._locator, + level=Issue.FIELD) + continue + + # Coerce to intrinsic functions, if there are any + value = coerce_parameter_value(context, implementation, None, value).value + + # Support dot-notation nesting + set_nested(configuration, key.split('.'), value) + else: + if model.dependencies is None: + model.dependencies = [] + model.dependencies.append(dependency) + + # Convert configuration to Configuration models + for key, value in configuration.iteritems(): + model.configurations[key] = Configuration.wrap(key, value, + description='Operation configuration.') + + create_parameter_models_from_assignments(model.inputs, operation.inputs, model_cls=Input) + return model + + +def create_artifact_template_model(context, service_template, artifact): + artifact_type = artifact._get_type(context) + artifact_type = service_template.artifact_types.get_descendant(artifact_type._name) + model = ArtifactTemplate(name=artifact._name, + type=artifact_type, + source_path=artifact.file) + + if artifact.description: + model.description = artifact.description.value + + model.target_path = artifact.deploy_path + + repository = artifact._get_repository(context) + if repository is not None: + model.repository_url = repository.url + credential = repository._get_credential(context) + if credential: + model.repository_credential = {} + for k, v in credential.iteritems(): + model.repository_credential[k] = v + + model.properties.update( + create_property_models_from_values(artifact._get_property_values(context))) + + return model + + +def create_substitution_template_model(context, service_template, substitution_mappings): + node_type = service_template.node_types.get_descendant(substitution_mappings.node_type) + model = SubstitutionTemplate(node_type=node_type) + + capabilities = substitution_mappings.capabilities + if capabilities: + for mapped_capability_name, capability in capabilities.iteritems(): + name = 'capability.' + mapped_capability_name + node_template_model = service_template.node_templates[capability.node_template] + capability_template_model = \ + node_template_model.capability_templates[capability.capability] + model.mappings[name] = \ + SubstitutionTemplateMapping(name=name, + capability_template=capability_template_model) + + requirements = substitution_mappings.requirements + if requirements: + for mapped_requirement_name, requirement in requirements.iteritems(): + name = 'requirement.' + mapped_requirement_name + node_template_model = service_template.node_templates[requirement.node_template] + requirement_template_model = None + for a_model in node_template_model.requirement_templates: + if a_model.name == requirement.requirement: + requirement_template_model = a_model + break + model.mappings[name] = \ + SubstitutionTemplateMapping(name=name, + requirement_template=requirement_template_model) + + return model + + +def create_plugin_specification_model(context, policy): + properties = policy.properties + + def get(name, default=None): + prop = properties.get(name) + return prop.value if prop is not None else default + + model = PluginSpecification(name=policy._name, + version=get('version'), + enabled=get('enabled', True)) + + return model + + +def create_workflow_operation_template_model(context, service_template, policy): + model = OperationTemplate(name=policy._name) + # since we use backpopulates, these fields are populated upon commit, we get a weird(temporary) + # behavior where in previous code service_template.workflow_templates is a dict which has None + # as key for the value of model. + service_template.workflow_templates[model.name] = model + + if policy.description: + model.description = policy.description.value + + properties = policy._get_property_values(context) + for prop_name, prop in properties.iteritems(): + if prop_name == 'implementation': + model.function = prop.value + else: + input_model = create_parameter_model_from_value(prop, prop_name, model_cls=Input) + input_model.required = prop.required + model.inputs[prop_name] = input_model + + used_reserved_names = WORKFLOW_DECORATOR_RESERVED_ARGUMENTS.intersection(model.inputs.keys()) + if used_reserved_names: + context.validation.report('using reserved arguments in workflow policy "{0}": {1}' + .format( + policy._name, + string_list_as_string(used_reserved_names)), + locator=policy._locator, + level=Issue.EXTERNAL) + return model + + +# +# Utils +# + +def create_types(context, root, types): + if types is None: + return + + def added_all(): + for name in types: + if root.get_descendant(name) is None: + return False + return True + + while not added_all(): + for name, the_type in types.iteritems(): + if root.get_descendant(name) is None: + parent_type = the_type._get_parent(context) + model = Type(name=the_type._name, + role=the_type._get_extension('role')) + if the_type.description: + model.description = the_type.description.value + if parent_type is None: + model.parent = root + model.variant = root.variant + root.children.append(model) + else: + container = root.get_descendant(parent_type._name) + if container is not None: + model.parent = container + model.variant = container.variant + container.children.append(model) + + +def create_input_models_from_values(template_inputs): + model_inputs = {} + if template_inputs: + for template_input_name, template_input in template_inputs.iteritems(): + model_input = create_parameter_model_from_value(template_input, template_input_name, + model_cls=Input) + model_input.required = template_input.required + model_inputs[model_input.name] = model_input + return model_inputs + +def create_output_models_from_values(template_outputs): + model_outputs = {} + for template_output_name, template_output in template_outputs.iteritems(): + model_outputs[template_output_name] = \ + create_parameter_model_from_value(template_output, + template_output_name, + model_cls=Output) + return model_outputs + + +def create_property_models_from_values(template_properties): + model_properties = {} + for template_property_name, template_property in template_properties.iteritems(): + model_properties[template_property_name] = \ + create_parameter_model_from_value(template_property, + template_property_name, + model_cls=Property) + return model_properties + +def create_attribute_models_from_values(template_attributes): + model_attributes = {} + for template_attribute_name, template_attribute in template_attributes.iteritems(): + model_attributes[template_attribute_name] = \ + create_parameter_model_from_value(template_attribute, + template_attribute_name, + model_cls=Attribute) + return model_attributes + + +def create_parameter_model_from_value(template_parameter, template_parameter_name, model_cls): + return model_cls(name=template_parameter_name, + type_name=template_parameter.type, + value=template_parameter.value, + description=template_parameter.description) + + +def create_parameter_models_from_assignments(properties, source_properties, model_cls): + if source_properties: + for property_name, prop in source_properties.iteritems(): + properties[property_name] = model_cls(name=property_name, # pylint: disable=unexpected-keyword-arg + type_name=prop.value.type, + value=prop.value.value, + description=prop.value.description) + + +def create_interface_template_models(context, service_template, interfaces, source_interfaces): + if source_interfaces: + for interface_name, interface in source_interfaces.iteritems(): + interface = create_interface_template_model(context, service_template, interface) + if interface is not None: + interfaces[interface_name] = interface + + +def create_node_filter_constraints(context, node_filter, target_node_template_constraints): + properties = node_filter.properties + if properties is not None: + for property_name, constraint_clause in properties: + constraint = create_constraint(context, node_filter, constraint_clause, property_name, + None) + target_node_template_constraints.append(constraint) + + capabilities = node_filter.capabilities + if capabilities is not None: + for capability_name, capability in capabilities: + properties = capability.properties + if properties is not None: + for property_name, constraint_clause in properties: + constraint = create_constraint(context, node_filter, constraint_clause, + property_name, capability_name) + target_node_template_constraints.append(constraint) + + +def create_constraint(context, node_filter, constraint_clause, property_name, capability_name): # pylint: disable=too-many-return-statements + constraint_key = constraint_clause._raw.keys()[0] + + the_type = constraint_clause._get_type(context) + + def coerce_constraint(constraint): + if the_type is not None: + return coerce_value(context, node_filter, the_type, None, None, constraint, + constraint_key) + else: + return constraint + + def coerce_constraints(constraints): + if the_type is not None: + return tuple(coerce_constraint(constraint) for constraint in constraints) + else: + return constraints + + if constraint_key == 'equal': + return Equal(property_name, capability_name, + coerce_constraint(constraint_clause.equal)) + elif constraint_key == 'greater_than': + return GreaterThan(property_name, capability_name, + coerce_constraint(constraint_clause.greater_than)) + elif constraint_key == 'greater_or_equal': + return GreaterOrEqual(property_name, capability_name, + coerce_constraint(constraint_clause.greater_or_equal)) + elif constraint_key == 'less_than': + return LessThan(property_name, capability_name, + coerce_constraint(constraint_clause.less_than)) + elif constraint_key == 'less_or_equal': + return LessOrEqual(property_name, capability_name, + coerce_constraint(constraint_clause.less_or_equal)) + elif constraint_key == 'in_range': + return InRange(property_name, capability_name, + coerce_constraints(constraint_clause.in_range)) + elif constraint_key == 'valid_values': + return ValidValues(property_name, capability_name, + coerce_constraints(constraint_clause.valid_values)) + elif constraint_key == 'length': + return Length(property_name, capability_name, + coerce_constraint(constraint_clause.length)) + elif constraint_key == 'min_length': + return MinLength(property_name, capability_name, + coerce_constraint(constraint_clause.min_length)) + elif constraint_key == 'max_length': + return MaxLength(property_name, capability_name, + coerce_constraint(constraint_clause.max_length)) + elif constraint_key == 'pattern': + return Pattern(property_name, capability_name, + coerce_constraint(constraint_clause.pattern)) + else: + raise ValueError('malformed node_filter: {0}'.format(constraint_key)) + + +def split_prefix(string): + """ + Splits the prefix on the first non-escaped ">". + """ + + split = IMPLEMENTATION_PREFIX_REGEX.split(string, 1) + if len(split) < 2: + return None, None + return split[0].strip(), split[1].strip() + + +def set_nested(the_dict, keys, value): + """ + If the ``keys`` list has just one item, puts the value in the the dict. If there are more items, + puts the value in a sub-dict, creating sub-dicts as necessary for each key. + + For example, if ``the_dict`` is an empty dict, keys is ``['first', 'second', 'third']`` and + value is ``'value'``, then the_dict will be: ``{'first':{'second':{'third':'value'}}}``. + + :param the_dict: Dict to change + :type the_dict: {} + :param keys: Keys + :type keys: [basestring] + :param value: Value + """ + key = keys.pop(0) + if len(keys) == 0: + the_dict[key] = value + else: + if key not in the_dict: + the_dict[key] = StrictDict(key_class=basestring) + set_nested(the_dict[key], keys, value) + + +def extract_implementation_primary(context, service_template, presentation, model, primary): + prefix, postfix = split_prefix(primary) + if prefix: + # Special ARIA prefix + model.plugin_specification = service_template.plugin_specifications.get(prefix) + model.function = postfix + if model.plugin_specification is None: + context.validation.report( + 'no policy for plugin "{0}" specified in operation implementation: {1}' + .format(prefix, primary), + locator=presentation._get_child_locator('properties', 'implementation'), + level=Issue.BETWEEN_TYPES) + else: + # Standard TOSCA artifact with default plugin + model.implementation = primary |