blob: 3b1948a3a33e246e480d2ca27148a4c641e25aba [file] [log] [blame]
# 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(u'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(
u'invalid scaling parameters for node template "{0}": min={min_instances}, max='
u'{max_instances}, default={default_instances}'.format(node_template.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(u'Artifact type: {0}'.format(out_stream.type_style(
self._model.type.name)))
out_stream.write(u'Source path: {0}'.format(out_stream.literal_style(
self._model.source_path)))
if self._model.target_path is not None:
out_stream.write(u'Target path: {0}'.format(out_stream.literal_style(
self._model.target_path)))
if self._model.repository_url is not None:
out_stream.write(u'Repository URL: {0}'.format(
out_stream.literal_style(self._model.repository_url)))
if self._model.repository_credential:
out_stream.write(u'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(u'Type: {0}'.format(out_stream.type_style(self._model.type.name)))
out_stream.write(
u'Occurrences: {0:d}{1}'.format(
self._model.min_occurrences or 0,
u' 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(u'Valid source node types: {0}'.format(
u', '.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(u'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(u'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(u'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(u'Target capability name: {0}'.format(
out_stream.node_style(self._model.target_capability_name)))
if self._model.target_node_template_constraints:
out_stream.write(u'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(u'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(u'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(u'Member node templates: {0}'.format(u', '.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(u'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(u'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(u'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(u'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(u'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(u'Target node templates: {0}'.format(u', '.join(
(str(out_stream.node_style(v.name)) for v in self._model.node_templates))))
if self._model.group_templates:
out_stream.write(u'Target group templates: {0}'.format(u', '.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(u'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(u'{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(
u'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(
u'mapping "{0}" refers to neither capability nor a requirement '
u'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(u'Relationship type: {0}'.format(out_stream.type_style(
self._model.type.name)))
else:
out_stream.write(u'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(u'Implementation: {0}'.format(
out_stream.literal_style(self._model.implementation)))
if self._model.dependencies:
out_stream.write(u'Dependencies: {0}'.format(u', '.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(u'Executor: {0}'.format(
out_stream.literal_style(self._model.executor)))
if self._model.max_attempts is not None:
out_stream.write(u'Max attempts: {0}'.format(out_stream.literal_style(
self._model.max_attempts)))
if self._model.retry_interval is not None:
out_stream.write(u'Retry interval: {0}'.format(
out_stream.literal_style(self._model.retry_interval)))
if self._model.plugin_specification is not None:
out_stream.write(u'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(u'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