X-Git-Url: https://gerrit.onap.org/r/gitweb?a=blobdiff_plain;f=azure%2Faria%2Faria-extension-cloudify%2Fsrc%2Faria%2Faria%2Forchestrator%2Ftopology%2Ftemplate_handler.py;fp=azure%2Faria%2Faria-extension-cloudify%2Fsrc%2Faria%2Faria%2Forchestrator%2Ftopology%2Ftemplate_handler.py;h=dda541883a82ce968911248e3282e26eaa873bf4;hb=7409dfb144cf2a06210400134d822a1393462b1f;hp=0000000000000000000000000000000000000000;hpb=9e65649dfff8f00dc0a0ef6b10d020ae0e2255ba;p=multicloud%2Fazure.git diff --git a/azure/aria/aria-extension-cloudify/src/aria/aria/orchestrator/topology/template_handler.py b/azure/aria/aria-extension-cloudify/src/aria/aria/orchestrator/topology/template_handler.py new file mode 100644 index 0000000..dda5418 --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/aria/orchestrator/topology/template_handler.py @@ -0,0 +1,609 @@ +# 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. + +from datetime import datetime + +from ...utils import ( + formatting, + versions +) +from ...modeling import utils as modeling_utils +from . import utils, common + + +class ServiceTemplate(common.TemplateHandlerBase): + def dump(self, out_stream): + if self._model.description is not None: + out_stream.write(out_stream.meta_style(self._model.description)) + self._topology.dump(self._model.meta_data, out_stream, title='Metadata') + self._topology.dump(self._model.node_templates, out_stream) + self._topology.dump(self._model.group_templates, out_stream) + self._topology.dump(self._model.policy_templates, out_stream) + self._topology.dump(self._model.substitution_template, out_stream) + self._topology.dump(self._model.inputs, out_stream, title='Inputs') + self._topology.dump(self._model.outputs, out_stream, title='Outputs') + self._topology.dump(self._model.workflow_templates, out_stream, title='Workflow templates') + + def coerce(self, **kwargs): + self._coerce(self._model.meta_data, + self._model.node_templates, + self._model.group_templates, + self._model.policy_templates, + self._model.substitution_template, + self._model.inputs, + self._model.outputs, + self._model.workflow_templates, + **kwargs) + + def instantiate(self, instance_cls, inputs=None, plugins=None): # pylint: disable=arguments-differ + now = datetime.now() + + # modeling_utils.validate_no_undeclared_inputs( + # declared_inputs=self._model.inputs, supplied_inputs=inputs or {}) + modeling_utils.validate_required_inputs_are_supplied( + declared_inputs=self._model.inputs, supplied_inputs=inputs or {}) + + service = instance_cls( + created_at=now, + updated_at=now, + description=utils.deepcopy_with_locators(self._model.description), + service_template=self._model, + inputs=modeling_utils.merge_parameter_values(inputs, self._model.inputs) + ) + + for plugin_specification in self._model.plugin_specifications.itervalues(): + if plugin_specification.enabled and plugins: + if self._resolve_plugin_specification(plugin_specification, plugins): + plugin = plugin_specification.plugin + service.plugins[plugin.name] = plugin + else: + self._topology.report('specified plugin not found: {0}'.format( + plugin_specification.name), level=self._topology.Issue.EXTERNAL) + service.meta_data = self._topology.instantiate(self._model.meta_data) + + for node_template in self._model.node_templates.itervalues(): + for _ in range(self._scaling(node_template)['default_instances']): + node = self._topology.instantiate(node_template) + service.nodes[node.name] = node + + service.groups = self._topology.instantiate(self._model.group_templates) + service.policies = self._topology.instantiate(self._model.policy_templates) + service.workflows = self._topology.instantiate(self._model.workflow_templates) + service.substitution = self._topology.instantiate(self._model.substitution_template) + service.outputs = self._topology.instantiate(self._model.outputs) + + return service + + @staticmethod + def _resolve_plugin_specification(plugin_specification, plugins): + matching_plugins = [] + if plugins: + for plugin in plugins: + if (plugin.name == plugin_specification.name and + (plugin_specification.version is None or + versions.VersionString(plugin.package_version) >= + plugin_specification.version) + ): + matching_plugins.append(plugin) + plugin_specification.plugin = None + if matching_plugins: + # Return highest version of plugin + plugin_specification.plugin = \ + max(matching_plugins, + key=lambda plugin: versions.VersionString(plugin.package_version).key) + return plugin_specification.plugin is not None + + def _scaling(self, node_template): + scaling = node_template.scaling + + if any([scaling['min_instances'] < 0, + scaling['max_instances'] < scaling['min_instances'], + scaling['max_instances'] < 0, + + scaling['default_instances'] < 0, + scaling['default_instances'] < scaling['min_instances'], + scaling['default_instances'] > scaling['max_instances'] + ]): + self._topology.report( + 'invalid scaling parameters for node template "{0}": min={min_instances}, max=' + '{max_instances}, default={default_instances}'.format(self._model.name, **scaling), + level=self._topology.Issue.BETWEEN_TYPES) + + return scaling + + def validate(self, **kwargs): + self._validate( + self._model.meta_data, + self._model.node_templates, + self._model.group_templates, + self._model.policy_templates, + self._model.substitution_template, + self._model.inputs, + self._model.outputs, + self._model.workflow_templates, + self._model.node_types, + self._model.group_types, + self._model.policy_types, + self._model.relationship_types, + self._model.capability_types, + self._model.interface_types, + self._model.artifact_types, + **kwargs + ) + + +class ArtifactTemplate(common.TemplateHandlerBase): + def dump(self, out_stream): + out_stream.write(out_stream.node_style(self._model.name)) + if self._model.description: + out_stream.write(out_stream.meta_style(self._model.description)) + with out_stream.indent(): + out_stream.write('Artifact type: {0}'.format(out_stream.type_style( + self._model.type.name))) + out_stream.write('Source path: {0}'.format(out_stream.literal_style( + self._model.source_path))) + if self._model.target_path is not None: + out_stream.write('Target path: {0}'.format(out_stream.literal_style( + self._model.target_path))) + if self._model.repository_url is not None: + out_stream.write('Repository URL: {0}'.format( + out_stream.literal_style(self._model.repository_url))) + if self._model.repository_credential: + out_stream.write('Repository credential: {0}'.format( + out_stream.literal_style(self._model.repository_credential))) + self._topology.dump(self._model.properties, out_stream, title='Properties') + + def coerce(self, **kwargs): + self._topology.coerce(self._model.properties, **kwargs) + + def instantiate(self, instance_cls, **_): + return instance_cls( + name=self._model.name, + type=self._model.type, + description=utils.deepcopy_with_locators(self._model.description), + source_path=self._model.source_path, + target_path=self._model.target_path, + repository_url=self._model.repository_url, + repository_credential=self._model.repository_credential, + artifact_template=self._model) + + def validate(self, **kwargs): + self._topology.validate(self._model.properties, **kwargs) + + +class CapabilityTemplate(common.TemplateHandlerBase): + def dump(self, out_stream): + out_stream.write(out_stream.node_style(self._model.name)) + if self._model.description: + out_stream.write(out_stream.meta_style(self._model.description)) + with out_stream.indent(): + out_stream.write('Type: {0}'.format(out_stream.type_style(self._model.type.name))) + out_stream.write( + 'Occurrences: {0:d}{1}'.format( + self._model.min_occurrences or 0, + ' to {0:d}'.format(self._model.max_occurrences) + if self._model.max_occurrences is not None + else ' or more')) + if self._model.valid_source_node_types: + out_stream.write('Valid source node types: {0}'.format( + ', '.join((str(out_stream.type_style(v.name)) + for v in self._model.valid_source_node_types)))) + self._topology.dump(self._model.properties, out_stream, title='Properties') + + def coerce(self, **kwargs): + self._topology.coerce(self._model.properties, **kwargs) + + def instantiate(self, instance_cls, **_): + capability = instance_cls( + name=self._model.name, + type=self._model.type, + min_occurrences=self._model.min_occurrences, + max_occurrences=self._model.max_occurrences, + occurrences=0, + capability_template=self._model) + capability.properties = self._topology.instantiate(self._model.properties) + return capability + + def validate(self, **kwargs): + self._topology.validate(self._model.properties, **kwargs) + + +class RequirementTemplate(common.TemplateHandlerBase): + def dump(self, out_stream): + if self._model.name: + out_stream.write(out_stream.node_style(self._model.name)) + else: + out_stream.write('Requirement:') + with out_stream.indent(): + if self._model.target_node_type is not None: + out_stream.write('Target node type: {0}'.format( + out_stream.type_style(self._model.target_node_type.name))) + elif self._model.target_node_template is not None: + out_stream.write('Target node template: {0}'.format( + out_stream.node_style(self._model.target_node_template.name))) + if self._model.target_capability_type is not None: + out_stream.write('Target capability type: {0}'.format( + out_stream.type_style(self._model.target_capability_type.name))) + elif self._model.target_capability_name is not None: + out_stream.write('Target capability name: {0}'.format( + out_stream.node_style(self._model.target_capability_name))) + if self._model.target_node_template_constraints: + out_stream.write('Target node template constraints:') + with out_stream.indent(): + for constraint in self._model.target_node_template_constraints: + out_stream.write(out_stream.literal_style(constraint)) + if self._model.relationship_template: + out_stream.write('Relationship:') + with out_stream.indent(): + self._topology.dump(self._model.relationship_template, out_stream) + + def coerce(self, **kwargs): + self._topology.coerce(self._model.relationship_template, **kwargs) + + def instantiate(self, instance_cls, **_): + pass + + def validate(self, **kwargs): + self._topology.validate(self._model.relationship_template, **kwargs) + + +class GroupTemplate(common.TemplateHandlerBase): + def dump(self, out_stream): + out_stream.write('Group template: {0}'.format(out_stream.node_style(self._model.name))) + if self._model.description: + out_stream.write(out_stream.meta_style(self._model.description)) + with out_stream.indent(): + out_stream.write('Type: {0}'.format(out_stream.type_style(self._model.type.name))) + self._topology.dump(self._model.properties, out_stream, title='Properties') + self._topology.dump(self._model.interface_templates, out_stream, + title='Interface Templates') + if self._model.node_templates: + out_stream.write('Member node templates: {0}'.format(', '.join( + (str(out_stream.node_style(v.name)) for v in self._model.node_templates)))) + + def coerce(self, **kwargs): + self._coerce(self._model.properties, + self._model.interface_templates, + **kwargs) + + def instantiate(self, instance_cls, **_): + group = instance_cls( + name=self._model.name, + type=self._model.type, + description=utils.deepcopy_with_locators(self._model.description), + group_template=self._model) + group.properties = self._topology.instantiate(self._model.properties) + group.interfaces = self._topology.instantiate(self._model.interface_templates) + if self._model.node_templates: + for node_template in self._model.node_templates: + group.nodes += node_template.nodes + return group + + def validate(self, **kwargs): + self._validate(self._model.properties, + self._model.interface_templates, + **kwargs) + + +class InterfaceTemplate(common.TemplateHandlerBase): + def dump(self, out_stream): + out_stream.write(out_stream.node_style(self._model.name)) + if self._model.description: + out_stream.write(out_stream.meta_style(self._model.description)) + with out_stream.indent(): + out_stream.write('Interface type: {0}'.format(out_stream.type_style( + self._model.type.name))) + self._topology.dump(self._model.inputs, out_stream, title='Inputs') + self._topology.dump(self._model.operation_templates, out_stream, + title='Operation templates') + + def coerce(self, **kwargs): + self._coerce(self._model.inputs, + self._model.operation_templates, + **kwargs) + + def instantiate(self, instance_cls, **_): + interface = instance_cls( + name=self._model.name, + type=self._model.type, + description=utils.deepcopy_with_locators(self._model.description), + interface_template=self._model) + interface.inputs = self._topology.instantiate(self._model.inputs) + interface.operations = self._topology.instantiate(self._model.operation_templates) + return interface + + def validate(self, **kwargs): + self._validate(self._model.inputs, + self._model.operation_templates, + **kwargs) + + +class NodeTemplate(common.TemplateHandlerBase): + def dump(self, out_stream): + out_stream.write('Node template: {0}'.format(out_stream.node_style(self._model.name))) + with out_stream.indent(): + if self._model.description: + out_stream.write(out_stream.meta_style(self._model.description)) + out_stream.write('Type: {0}'.format(out_stream.type_style(self._model.type.name))) + self._topology.dump(self._model.properties, out_stream, title='Properties') + self._topology.dump(self._model.attributes, out_stream, title='Attributes') + self._topology.dump( + self._model.interface_templates, out_stream, title='Interface Templates') + self._topology.dump( + self._model.artifact_templates, out_stream, title='Artifact Templates') + self._topology.dump( + self._model.capability_templates, out_stream, title='Capability Templates') + self._topology.dump( + self._model.requirement_templates, out_stream, title='Requirement Templates') + + def coerce(self, **kwargs): + self._coerce(self._model.properties, + self._model.attributes, + self._model.interface_templates, + self._model.artifact_templates, + self._model.capability_templates, + self._model.requirement_templates, + **kwargs) + + def instantiate(self, instance_cls, **_): + node = instance_cls( + name=self._model._next_name, + type=self._model.type, + description=utils.deepcopy_with_locators(self._model.description), + node_template=self._model + ) + + node.properties = self._topology.instantiate(self._model.properties) + node.attributes = self._topology.instantiate(self._model.attributes) + node.interfaces = self._topology.instantiate(self._model.interface_templates) + node.artifacts = self._topology.instantiate(self._model.artifact_templates) + node.capabilities = self._topology.instantiate(self._model.capability_templates) + + # Default attributes + if 'tosca_name' in node.attributes and node.attributes['tosca_name'].type_name == 'string': + node.attributes['tosca_name'].value = self._model.name + if 'tosca_id' in node.attributes and node.attributes['tosca_id'].type_name == 'string': + node.attributes['tosca_id'].value = node.name + + return node + + def validate(self, **kwargs): + self._validate(self._model.properties, + self._model.attributes, + self._model.interface_templates, + self._model.artifact_templates, + self._model.capability_templates, + self._model.requirement_templates, + **kwargs) + + +class PolicyTemplate(common.TemplateHandlerBase): + def dump(self, out_stream): + out_stream.write('Policy template: {0}'.format(out_stream.node_style(self._model.name))) + if self._model.description: + out_stream.write(out_stream.meta_style(self._model.description)) + with out_stream.indent(): + out_stream.write('Type: {0}'.format(out_stream.type_style(self._model.type.name))) + self._topology.dump(self._model.properties, out_stream, title='Properties') + if self._model.node_templates: + out_stream.write('Target node templates: {0}'.format(', '.join( + (str(out_stream.node_style(v.name)) for v in self._model.node_templates)))) + if self._model.group_templates: + out_stream.write('Target group templates: {0}'.format(', '.join( + (str(out_stream.node_style(v.name)) for v in self._model.group_templates)))) + + def coerce(self, **kwargs): + self._topology.coerce(self._model.properties, **kwargs) + + def instantiate(self, instance_cls, **_): + policy = instance_cls( + name=self._model.name, + type=self._model.type, + description=utils.deepcopy_with_locators(self._model.description), + policy_template=self._model) + + policy.properties = self._topology.instantiate(self._model.properties) + if self._model.node_templates: + for node_template in self._model.node_templates: + policy.nodes += node_template.nodes + if self._model.group_templates: + for group_template in self._model.group_templates: + policy.groups += group_template.groups + return policy + + def validate(self, **kwargs): + self._topology.validate(self._model.properties, **kwargs) + + +class SubstitutionTemplate(common.TemplateHandlerBase): + + def dump(self, out_stream): + out_stream.write('Substitution template:') + with out_stream.indent(): + out_stream.write('Node type: {0}'.format(out_stream.type_style( + self._model.node_type.name))) + self._topology.dump(self._model.mappings, out_stream, title='Mappings') + + def coerce(self, **kwargs): + self._topology.coerce(self._model.mappings, **kwargs) + + def instantiate(self, instance_cls, **_): + return instance_cls(node_type=self._model.node_type, substitution_template=self._model) + + def validate(self, **kwargs): + self._topology.validate(self._model.mappings, **kwargs) + + +class SubstitutionTemplateMapping(common.TemplateHandlerBase): + + def dump(self, out_stream): + if self._model.capability_template is not None: + node_template = self._model.capability_template.node_template + else: + node_template = self._model.requirement_template.node_template + out_stream.write('{0} -> {1}.{2}'.format( + out_stream.node_style(self._model.name), + out_stream.node_style(node_template.name), + out_stream.node_style(self._model.capability_template.name + if self._model.capability_template + else self._model.requirement_template.name))) + + def coerce(self, **_): + pass + + def instantiate(self, instance_cls, **_): + substitution_mapping = instance_cls( + name=self._model.name, + requirement_template=self._model.requirement_template) + + if self._model.capability_template is not None: + node_template = self._model.capability_template.node_template + else: + node_template = self._model.requirement_template.node_template + nodes = node_template.nodes + if len(nodes) == 0: + self._topology.report( + 'mapping "{0}" refers to node template "{1}" but there are no node instances'. + format(self._model.mapped_name, self._model.node_template.name), + level=self._topology.Issue.BETWEEN_INSTANCES) + return None + # The TOSCA spec does not provide a way to choose the node, + # so we will just pick the first one + substitution_mapping.node_style = nodes[0] + if self._model.capability_template: + for a_capability in substitution_mapping.node_style.capabilities.itervalues(): + if a_capability.capability_template.name == \ + self._model.capability_template.name: + substitution_mapping.capability = a_capability + + return substitution_mapping + + def validate(self, **_): + if self._model.capability_template is None and self._model.requirement_template is None: + self._topology.report( + 'mapping "{0}" refers to neither capability nor a requirement ' + 'in node template: {1}'.format( + self._model.name, formatting.safe_repr(self._model.node_template.name)), + level=self._topology.Issue.BETWEEN_TYPES) + + +class RelationshipTemplate(common.TemplateHandlerBase): + def dump(self, out_stream): + if self._model.type is not None: + out_stream.write('Relationship type: {0}'.format(out_stream.type_style( + self._model.type.name))) + else: + out_stream.write('Relationship template: {0}'.format( + out_stream.node_style(self._model.name))) + if self._model.description: + out_stream.write(out_stream.meta_style(self._model.description)) + with out_stream.indent(): + self._topology.dump(self._model.properties, out_stream, title='Properties') + self._topology.dump(self._model.interface_templates, out_stream, + title='Interface Templates') + + def coerce(self, **kwargs): + self._coerce(self._model.properties, self._model.interface_templates, **kwargs) + + def instantiate(self, instance_cls, **_): + relationship = instance_cls( + name=self._model.name, + type=self._model.type, + relationship_template=self._model) + + relationship.properties = self._topology.instantiate(self._model.properties) + relationship.interfaces = self._topology.instantiate(self._model.interface_templates) + return relationship + + def validate(self, **kwargs): + self._validate(self._model.properties, self._model.interface_templates, **kwargs) + + +class OperationTemplate(common.TemplateHandlerBase): + + def dump(self, out_stream): + out_stream.write(out_stream.node_style(self._model.name)) + if self._model.description: + out_stream.write(out_stream.meta_style(self._model.description)) + with out_stream.indent(): + if self._model.implementation is not None: + out_stream.write('Implementation: {0}'.format( + out_stream.literal_style(self._model.implementation))) + if self._model.dependencies: + out_stream.write('Dependencies: {0}'.format(', '.join( + (str(out_stream.literal_style(v)) for v in self._model.dependencies)))) + self._topology.dump(self._model.inputs, out_stream, title='Inputs') + if self._model.executor is not None: + out_stream.write('Executor: {0}'.format( + out_stream.literal_style(self._model.executor))) + if self._model.max_attempts is not None: + out_stream.write('Max attempts: {0}'.format(out_stream.literal_style( + self._model.max_attempts))) + if self._model.retry_interval is not None: + out_stream.write('Retry interval: {0}'.format( + out_stream.literal_style(self._model.retry_interval))) + if self._model.plugin_specification is not None: + out_stream.write('Plugin specification: {0}'.format( + out_stream.literal_style(self._model.plugin_specification.name))) + self._topology.dump(self._model.configurations, out_stream, title='Configuration') + if self._model.function is not None: + out_stream.write('Function: {0}'.format(out_stream.literal_style( + self._model.function))) + + def coerce(self, **kwargs): + self._coerce(self._model.inputs, + self._model.configurations, + **kwargs) + + def instantiate(self, instance_cls, **_): + operation = instance_cls( + name=self._model.name, + description=utils.deepcopy_with_locators(self._model.description), + relationship_edge=self._model.relationship_edge, + implementation=self._model.implementation, + dependencies=self._model.dependencies, + executor=self._model.executor, + function=self._model.function, + max_attempts=self._model.max_attempts, + retry_interval=self._model.retry_interval, + operation_template=self._model) + + if (self._model.plugin_specification is not None and + self._model.plugin_specification.enabled): + operation.plugin = self._model.plugin_specification.plugin + + operation.inputs = self._topology.instantiate(self._model.inputs) + operation.configurations = self._topology.instantiate(self._model.configurations) + + return operation + + def validate(self, **kwargs): + self._validate(self._model.inputs, + self._model.configurations, + **kwargs) + + +class PluginSpecification(common.HandlerBase): + def validate(self, **kwargs): + pass + + def coerce(self, **kwargs): + pass + + def instantiate(self, **_): + pass + + def dump(self, out_stream): + pass