# 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