vFW and vDNS support added to azure-plugin
[multicloud/azure.git] / azure / aria / aria-extension-cloudify / src / aria / aria / orchestrator / topology / template_handler.py
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 (file)
index 0000000..dda5418
--- /dev/null
@@ -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