summaryrefslogtreecommitdiffstats
path: root/azure/aria/aria-extension-cloudify/src/aria/aria/orchestrator/topology/template_handler.py
diff options
context:
space:
mode:
Diffstat (limited to 'azure/aria/aria-extension-cloudify/src/aria/aria/orchestrator/topology/template_handler.py')
-rw-r--r--azure/aria/aria-extension-cloudify/src/aria/aria/orchestrator/topology/template_handler.py609
1 files changed, 609 insertions, 0 deletions
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