You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ariatosca.apache.org by mx...@apache.org on 2017/07/27 14:15:31 UTC
[1/2] incubator-ariatosca git commit: removed the old style class
from consumption, removed any unnecessary and local imports [Forced Update!]
Repository: incubator-ariatosca
Updated Branches:
refs/heads/ARIA-174-Refactor-instantiation-phase d1db39926 -> ec7b9c970 (forced update)
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/ec7b9c97/aria/orchestrator/topology/template.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/topology/template.py b/aria/orchestrator/topology/template.py
deleted file mode 100644
index 51be788..0000000
--- a/aria/orchestrator/topology/template.py
+++ /dev/null
@@ -1,583 +0,0 @@
-# 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
-from ...modeling import utils as modeling_utils
-from . import utils, common
-
-
-class ServiceTemplate(common._TemplateHandlerMixin):
- def dump(self, console):
- if self._model.description is not None:
- console.write(console.meta(self._model.description))
- self._topology.dump(self._model.meta_data, console, 'Metadata')
- self._topology.dump(self._model.node_templates, console)
- self._topology.dump(self._model.group_templates, console)
- self._topology.dump(self._model.policy_templates, console)
- self._topology.dump(self._model.substitution_template, console)
- self._topology.dump(self._model.inputs, console, 'Inputs')
- self._topology.dump(self._model.outputs, console, 'Outputs')
- self._topology.dump(self._model.workflow_templates, console, '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): # pylint: disable=arguments-differ
- now = datetime.now()
- 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 self._topology._model_storage:
- if utils.resolve_plugin_specification(plugin_specification,
- self._topology.model_storage.plugin.list()):
- 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
-
- def _scaling(self, node_template):
- scaling = {}
-
- def extract_property(properties, name):
- if name in scaling:
- return
- prop = properties.get(name)
- if (prop is not None) and (prop.type_name == 'integer') and (prop.value is not None):
- scaling[name] = prop.value
-
- def extract_properties(properties):
- extract_property(properties, 'min_instances')
- extract_property(properties, 'max_instances')
- extract_property(properties, 'default_instances')
-
- # From our scaling capabilities
- for capability_template in node_template.capability_templates.itervalues():
- if capability_template.type.role == 'scaling':
- extract_properties(capability_template.properties)
-
- # From service scaling policies
- for policy_template in node_template.service_template.policy_templates.itervalues():
- if policy_template.type.role == 'scaling':
- if policy_template.is_for_node_template(node_template.name):
- extract_properties(policy_template.properties)
-
- # Defaults
- scaling.setdefault('min_instances', 0)
- scaling.setdefault('max_instances', 1)
- scaling.setdefault('default_instances', 1)
-
- # Validate
- # pylint: disable=too-many-boolean-expressions
- if (scaling['min_instances'] < 0 or
- scaling['max_instances'] < 0 or
- scaling['default_instances'] < 0 or
- scaling['max_instances'] < scaling['min_instances'] or
- scaling['default_instances'] < scaling['min_instances'] or
- 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):
- self._topology.validate(self._model.meta_data)
- self._topology.validate(self._model.node_templates)
- self._topology.validate(self._model.group_templates)
- self._topology.validate(self._model.policy_templates)
- self._topology.validate(self._model.substitution_template)
- self._topology.validate(self._model.inputs)
- self._topology.validate(self._model.outputs)
- self._topology.validate(self._model.workflow_templates)
- self._topology.validate(self._model.node_types)
- self._topology.validate(self._model.group_types)
- self._topology.validate(self._model.policy_types)
- self._topology.validate(self._model.relationship_types)
- self._topology.validate(self._model.capability_types)
- self._topology.validate(self._model.interface_types)
- self._topology.validate(self._model.artifact_types)
-
-
-class ArtifactTemplate(common._TemplateHandlerMixin):
- def dump(self, console):
- console.write(console.node(self._model.name))
- if self._model.description:
- console.write(console.meta(self._model.description))
- with console.indent:
- console.write('Artifact type: {0}'.format(console.type(self._model.type.name)))
- console.write('Source path: {0}'.format(console.literal(self._model.source_path)))
- if self._model.target_path is not None:
- console.write('Target path: {0}'.format(console.literal(self._model.target_path)))
- if self._model.repository_url is not None:
- console.write('Repository URL: {0}'.format(
- console.literal(self._model.repository_url)))
- if self._model.repository_credential:
- console.write('Repository credential: {0}'.format(
- console.literal(self._model.repository_credential)))
- self._topology.dump(self._model.properties, console, '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):
- self._topology.validate(self._model.properties)
-
-
-class CapabilityTemplate(common._TemplateHandlerMixin):
- def dump(self, console):
- console.write(console.node(self._model.name))
- if self._model.description:
- console.write(console.meta(self._model.description))
- with console.indent:
- console.write('Type: {0}'.format(console.type(self._model.type.name)))
- console.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:
- console.write('Valid source node types: {0}'.format(
- ', '.join((str(console.type(v.name))
- for v in self._model.valid_source_node_types))))
- self._topology.dump(self._model.properties, console, 'Properties')
-
- def coerce(self):
- self._topology.coerce(self._model.properties)
-
- def instantiate(self, instance_cls):
- return 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)
-
- def validate(self):
- self._topology.validate(self._model.properties)
-
-
-class RequirementTemplate(common._TemplateHandlerMixin):
- def dump(self, console):
- if self._model.name:
- console.write(console.node(self._model.name))
- else:
- console.write('Requirement:')
- with console.indent:
- if self._model.target_node_type is not None:
- console.write('Target node type: {0}'.format(
- console.type(self._model.target_node_type.name)))
- elif self._model.target_node_template is not None:
- console.write('Target node template: {0}'.format(
- console.node(self._model.target_node_template.name)))
- if self._model.target_capability_type is not None:
- console.write('Target capability type: {0}'.format(
- console.type(self._model.target_capability_type.name)))
- elif self._model.target_capability_name is not None:
- console.write('Target capability name: {0}'.format(
- console.node(self._model.target_capability_name)))
- if self._model.target_node_template_constraints:
- console.write('Target node template constraints:')
- with console.indent:
- for constraint in self._model.target_node_template_constraints:
- console.write(console.literal(constraint))
- if self._model.relationship_template:
- console.write('Relationship:')
- with console.indent:
- self._topology.dump(self._model.relationship_template, console)
-
- def coerce(self, **kwargs):
- self._topology.coerce(self._model.relationship_template, **kwargs)
-
- def instantiate(self, instance_cls):
- return 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)
-
- def validate(self):
- self._topology.validate(self._model.relationship_template)
-
-
-class GroupTemplate(common._TemplateHandlerMixin):
- def dump(self, console):
- console.write('Group template: {0}'.format(console.node(self._model.name)))
- if self._model.description:
- console.write(console.meta(self._model.description))
- with console.indent:
- console.write('Type: {0}'.format(console.type(self._model.type.name)))
- self._topology.dump(self._model.properties, console, 'Properties')
- self._topology.dump(self._model.interface_templates, console, 'Interface Templates')
- if self._model.node_templates:
- console.write('Member node templates: {0}'.format(', '.join(
- (str(console.node(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):
- self._validate(self._model.properties,
- self._model.interface_templates)
-
-
-class InterfaceTemplate(common._TemplateHandlerMixin):
- def dump(self, console):
- console.write(console.node(self._model.name))
- if self._model.description:
- console.write(console.meta(self._model.description))
- with console.indent:
- console.write('Interface type: {0}'.format(console.type(self._model.type.name)))
- self._topology.dump(self._model.inputs, console, 'Inputs')
- self._topology.dump(self._model.operation_templates, console, '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):
- self._validate(self._model.inputs,
- self._model.operation_templates)
-
-
-class NodeTemplate(common._TemplateHandlerMixin):
- def dump(self, console):
- console.write('Node template: {0}'.format(console.node(self._model.name)))
- if self._model.description:
- console.write(console.meta(self._model.description))
- console.write('Type: {0}'.format(console.type(self._model.type.name)))
- self._topology.dump(self._model.properties, console, 'Properties')
- self._topology.dump(self._model.attributes, console, 'Attributes')
- self._topology.dump(self._model.interface_templates, console, 'Interface Templates')
- self._topology.dump(self._model.artifact_templates, console, 'Artifact Templates')
- self._topology.dump(self._model.capability_templates, console, 'Capability Templates')
- self._topology.dump(self._model.requirement_templates, console, '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):
- self._validate(self._model.properties,
- self._model.attributes,
- self._model.interface_templates,
- self._model.artifact_templates,
- self._model.capability_templates,
- self._model.requirement_templates)
-
-
-class PolicyTemplate(common._TemplateHandlerMixin):
- def dump(self, console):
- console.write('Policy template: {0}'.format(console.node(self._model.name)))
- if self._model.description:
- console.write(console.meta(self._model.description))
- with console.indent:
- console.write('Type: {0}'.format(console.type(self._model.type.name)))
- self._topology.dump(self._model.properties, console, 'Properties')
- if self._model.node_templates:
- console.write('Target node templates: {0}'.format(', '.join(
- (str(console.node(v.name)) for v in self._model.node_templates))))
- if self._model.group_templates:
- console.write('Target group templates: {0}'.format(', '.join(
- (str(console.node(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):
- self._topology.validate(self._model.properties)
-
-
-class SubstitutionTemplate(common._TemplateHandlerMixin):
-
- def dump(self, console):
- console.write('Substitution template:')
- with console.indent:
- console.write('Node type: {0}'.format(console.type(self._model.node_type.name)))
- self._topology.dump(self._model.mappings, console, '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):
- self._topology.validate(self._model.mappings)
-
-
-class SubstitutionTemplateMapping(common._TemplateHandlerMixin):
-
- def dump(self, console):
- if self._topology.capability_template is not None:
- node_template = self._topology.capability_template.node_template
- else:
- node_template = self._topology.requirement_template.node_template
- console.write('{0} -> {1}.{2}'.format(
- console.node(self._topology.name),
- console.node(node_template.name),
- console.node(self._topology.capability_template.name
- if self._topology.capability_template
- else self._topology.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 = nodes[0]
- if self._model.capability_template:
- for a_capability in substitution_mapping.node.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._TemplateHandlerMixin):
- def dump(self, console):
- if self._model.type is not None:
- console.write('Relationship type: {0}'.format(console.type(self._model.type.name)))
- else:
- console.write('Relationship template: {0}'.format(
- console.node(self._model.name)))
- if self._model.description:
- console.write(console.meta(self._model.description))
- with console.indent:
- self._topology.dump(self._model.properties, console, 'Properties')
- self._topology.dump(self._model.interface_templates, console, '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):
- self._validate(self._model.properties, self._model.interface_templates)
-
-
-class OperationTemplate(common._TemplateHandlerMixin):
-
- def dump(self, console):
- console.write(console.node(self._model.name))
- if self._model.description:
- console.write(console.meta(self._model.description))
- with console.indent:
- if self._model.implementation is not None:
- console.write('Implementation: {0}'.format(
- console.literal(self._model.implementation)))
- if self._model.dependencies:
- console.write('Dependencies: {0}'.format(
- ', '.join((str(console.literal(v)) for v in self._model.dependencies))))
- self._topology.dump(self._model.inputs, console, 'Inputs')
- if self._model.executor is not None:
- console.write('Executor: {0}'.format(console.literal(self._model.executor)))
- if self._model.max_attempts is not None:
- console.write('Max attempts: {0}'.format(console.literal(self._model.max_attempts)))
- if self._model.retry_interval is not None:
- console.write('Retry interval: {0}'.format(
- console.literal(self._model.retry_interval)))
- if self._model.plugin_specification is not None:
- console.write('Plugin specification: {0}'.format(
- console.literal(self._model.plugin_specification.name)))
- self._topology.dump(self._model.configurations, console, 'Configuration')
- if self._model.function is not None:
- console.write('Function: {0}'.format(console.literal(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):
- self._validate(self._model.inputs,
- self._model.configurations)
-
-
-class PluginSpecification(common._TemplateHandlerMixin):
- def instantiate(self, **kwargs):
- pass
-
- def dump(self, console):
- pass
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/ec7b9c97/aria/orchestrator/topology/template_handler.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/topology/template_handler.py b/aria/orchestrator/topology/template_handler.py
new file mode 100644
index 0000000..51be788
--- /dev/null
+++ b/aria/orchestrator/topology/template_handler.py
@@ -0,0 +1,583 @@
+# 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
+from ...modeling import utils as modeling_utils
+from . import utils, common
+
+
+class ServiceTemplate(common._TemplateHandlerMixin):
+ def dump(self, console):
+ if self._model.description is not None:
+ console.write(console.meta(self._model.description))
+ self._topology.dump(self._model.meta_data, console, 'Metadata')
+ self._topology.dump(self._model.node_templates, console)
+ self._topology.dump(self._model.group_templates, console)
+ self._topology.dump(self._model.policy_templates, console)
+ self._topology.dump(self._model.substitution_template, console)
+ self._topology.dump(self._model.inputs, console, 'Inputs')
+ self._topology.dump(self._model.outputs, console, 'Outputs')
+ self._topology.dump(self._model.workflow_templates, console, '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): # pylint: disable=arguments-differ
+ now = datetime.now()
+ 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 self._topology._model_storage:
+ if utils.resolve_plugin_specification(plugin_specification,
+ self._topology.model_storage.plugin.list()):
+ 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
+
+ def _scaling(self, node_template):
+ scaling = {}
+
+ def extract_property(properties, name):
+ if name in scaling:
+ return
+ prop = properties.get(name)
+ if (prop is not None) and (prop.type_name == 'integer') and (prop.value is not None):
+ scaling[name] = prop.value
+
+ def extract_properties(properties):
+ extract_property(properties, 'min_instances')
+ extract_property(properties, 'max_instances')
+ extract_property(properties, 'default_instances')
+
+ # From our scaling capabilities
+ for capability_template in node_template.capability_templates.itervalues():
+ if capability_template.type.role == 'scaling':
+ extract_properties(capability_template.properties)
+
+ # From service scaling policies
+ for policy_template in node_template.service_template.policy_templates.itervalues():
+ if policy_template.type.role == 'scaling':
+ if policy_template.is_for_node_template(node_template.name):
+ extract_properties(policy_template.properties)
+
+ # Defaults
+ scaling.setdefault('min_instances', 0)
+ scaling.setdefault('max_instances', 1)
+ scaling.setdefault('default_instances', 1)
+
+ # Validate
+ # pylint: disable=too-many-boolean-expressions
+ if (scaling['min_instances'] < 0 or
+ scaling['max_instances'] < 0 or
+ scaling['default_instances'] < 0 or
+ scaling['max_instances'] < scaling['min_instances'] or
+ scaling['default_instances'] < scaling['min_instances'] or
+ 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):
+ self._topology.validate(self._model.meta_data)
+ self._topology.validate(self._model.node_templates)
+ self._topology.validate(self._model.group_templates)
+ self._topology.validate(self._model.policy_templates)
+ self._topology.validate(self._model.substitution_template)
+ self._topology.validate(self._model.inputs)
+ self._topology.validate(self._model.outputs)
+ self._topology.validate(self._model.workflow_templates)
+ self._topology.validate(self._model.node_types)
+ self._topology.validate(self._model.group_types)
+ self._topology.validate(self._model.policy_types)
+ self._topology.validate(self._model.relationship_types)
+ self._topology.validate(self._model.capability_types)
+ self._topology.validate(self._model.interface_types)
+ self._topology.validate(self._model.artifact_types)
+
+
+class ArtifactTemplate(common._TemplateHandlerMixin):
+ def dump(self, console):
+ console.write(console.node(self._model.name))
+ if self._model.description:
+ console.write(console.meta(self._model.description))
+ with console.indent:
+ console.write('Artifact type: {0}'.format(console.type(self._model.type.name)))
+ console.write('Source path: {0}'.format(console.literal(self._model.source_path)))
+ if self._model.target_path is not None:
+ console.write('Target path: {0}'.format(console.literal(self._model.target_path)))
+ if self._model.repository_url is not None:
+ console.write('Repository URL: {0}'.format(
+ console.literal(self._model.repository_url)))
+ if self._model.repository_credential:
+ console.write('Repository credential: {0}'.format(
+ console.literal(self._model.repository_credential)))
+ self._topology.dump(self._model.properties, console, '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):
+ self._topology.validate(self._model.properties)
+
+
+class CapabilityTemplate(common._TemplateHandlerMixin):
+ def dump(self, console):
+ console.write(console.node(self._model.name))
+ if self._model.description:
+ console.write(console.meta(self._model.description))
+ with console.indent:
+ console.write('Type: {0}'.format(console.type(self._model.type.name)))
+ console.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:
+ console.write('Valid source node types: {0}'.format(
+ ', '.join((str(console.type(v.name))
+ for v in self._model.valid_source_node_types))))
+ self._topology.dump(self._model.properties, console, 'Properties')
+
+ def coerce(self):
+ self._topology.coerce(self._model.properties)
+
+ def instantiate(self, instance_cls):
+ return 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)
+
+ def validate(self):
+ self._topology.validate(self._model.properties)
+
+
+class RequirementTemplate(common._TemplateHandlerMixin):
+ def dump(self, console):
+ if self._model.name:
+ console.write(console.node(self._model.name))
+ else:
+ console.write('Requirement:')
+ with console.indent:
+ if self._model.target_node_type is not None:
+ console.write('Target node type: {0}'.format(
+ console.type(self._model.target_node_type.name)))
+ elif self._model.target_node_template is not None:
+ console.write('Target node template: {0}'.format(
+ console.node(self._model.target_node_template.name)))
+ if self._model.target_capability_type is not None:
+ console.write('Target capability type: {0}'.format(
+ console.type(self._model.target_capability_type.name)))
+ elif self._model.target_capability_name is not None:
+ console.write('Target capability name: {0}'.format(
+ console.node(self._model.target_capability_name)))
+ if self._model.target_node_template_constraints:
+ console.write('Target node template constraints:')
+ with console.indent:
+ for constraint in self._model.target_node_template_constraints:
+ console.write(console.literal(constraint))
+ if self._model.relationship_template:
+ console.write('Relationship:')
+ with console.indent:
+ self._topology.dump(self._model.relationship_template, console)
+
+ def coerce(self, **kwargs):
+ self._topology.coerce(self._model.relationship_template, **kwargs)
+
+ def instantiate(self, instance_cls):
+ return 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)
+
+ def validate(self):
+ self._topology.validate(self._model.relationship_template)
+
+
+class GroupTemplate(common._TemplateHandlerMixin):
+ def dump(self, console):
+ console.write('Group template: {0}'.format(console.node(self._model.name)))
+ if self._model.description:
+ console.write(console.meta(self._model.description))
+ with console.indent:
+ console.write('Type: {0}'.format(console.type(self._model.type.name)))
+ self._topology.dump(self._model.properties, console, 'Properties')
+ self._topology.dump(self._model.interface_templates, console, 'Interface Templates')
+ if self._model.node_templates:
+ console.write('Member node templates: {0}'.format(', '.join(
+ (str(console.node(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):
+ self._validate(self._model.properties,
+ self._model.interface_templates)
+
+
+class InterfaceTemplate(common._TemplateHandlerMixin):
+ def dump(self, console):
+ console.write(console.node(self._model.name))
+ if self._model.description:
+ console.write(console.meta(self._model.description))
+ with console.indent:
+ console.write('Interface type: {0}'.format(console.type(self._model.type.name)))
+ self._topology.dump(self._model.inputs, console, 'Inputs')
+ self._topology.dump(self._model.operation_templates, console, '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):
+ self._validate(self._model.inputs,
+ self._model.operation_templates)
+
+
+class NodeTemplate(common._TemplateHandlerMixin):
+ def dump(self, console):
+ console.write('Node template: {0}'.format(console.node(self._model.name)))
+ if self._model.description:
+ console.write(console.meta(self._model.description))
+ console.write('Type: {0}'.format(console.type(self._model.type.name)))
+ self._topology.dump(self._model.properties, console, 'Properties')
+ self._topology.dump(self._model.attributes, console, 'Attributes')
+ self._topology.dump(self._model.interface_templates, console, 'Interface Templates')
+ self._topology.dump(self._model.artifact_templates, console, 'Artifact Templates')
+ self._topology.dump(self._model.capability_templates, console, 'Capability Templates')
+ self._topology.dump(self._model.requirement_templates, console, '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):
+ self._validate(self._model.properties,
+ self._model.attributes,
+ self._model.interface_templates,
+ self._model.artifact_templates,
+ self._model.capability_templates,
+ self._model.requirement_templates)
+
+
+class PolicyTemplate(common._TemplateHandlerMixin):
+ def dump(self, console):
+ console.write('Policy template: {0}'.format(console.node(self._model.name)))
+ if self._model.description:
+ console.write(console.meta(self._model.description))
+ with console.indent:
+ console.write('Type: {0}'.format(console.type(self._model.type.name)))
+ self._topology.dump(self._model.properties, console, 'Properties')
+ if self._model.node_templates:
+ console.write('Target node templates: {0}'.format(', '.join(
+ (str(console.node(v.name)) for v in self._model.node_templates))))
+ if self._model.group_templates:
+ console.write('Target group templates: {0}'.format(', '.join(
+ (str(console.node(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):
+ self._topology.validate(self._model.properties)
+
+
+class SubstitutionTemplate(common._TemplateHandlerMixin):
+
+ def dump(self, console):
+ console.write('Substitution template:')
+ with console.indent:
+ console.write('Node type: {0}'.format(console.type(self._model.node_type.name)))
+ self._topology.dump(self._model.mappings, console, '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):
+ self._topology.validate(self._model.mappings)
+
+
+class SubstitutionTemplateMapping(common._TemplateHandlerMixin):
+
+ def dump(self, console):
+ if self._topology.capability_template is not None:
+ node_template = self._topology.capability_template.node_template
+ else:
+ node_template = self._topology.requirement_template.node_template
+ console.write('{0} -> {1}.{2}'.format(
+ console.node(self._topology.name),
+ console.node(node_template.name),
+ console.node(self._topology.capability_template.name
+ if self._topology.capability_template
+ else self._topology.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 = nodes[0]
+ if self._model.capability_template:
+ for a_capability in substitution_mapping.node.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._TemplateHandlerMixin):
+ def dump(self, console):
+ if self._model.type is not None:
+ console.write('Relationship type: {0}'.format(console.type(self._model.type.name)))
+ else:
+ console.write('Relationship template: {0}'.format(
+ console.node(self._model.name)))
+ if self._model.description:
+ console.write(console.meta(self._model.description))
+ with console.indent:
+ self._topology.dump(self._model.properties, console, 'Properties')
+ self._topology.dump(self._model.interface_templates, console, '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):
+ self._validate(self._model.properties, self._model.interface_templates)
+
+
+class OperationTemplate(common._TemplateHandlerMixin):
+
+ def dump(self, console):
+ console.write(console.node(self._model.name))
+ if self._model.description:
+ console.write(console.meta(self._model.description))
+ with console.indent:
+ if self._model.implementation is not None:
+ console.write('Implementation: {0}'.format(
+ console.literal(self._model.implementation)))
+ if self._model.dependencies:
+ console.write('Dependencies: {0}'.format(
+ ', '.join((str(console.literal(v)) for v in self._model.dependencies))))
+ self._topology.dump(self._model.inputs, console, 'Inputs')
+ if self._model.executor is not None:
+ console.write('Executor: {0}'.format(console.literal(self._model.executor)))
+ if self._model.max_attempts is not None:
+ console.write('Max attempts: {0}'.format(console.literal(self._model.max_attempts)))
+ if self._model.retry_interval is not None:
+ console.write('Retry interval: {0}'.format(
+ console.literal(self._model.retry_interval)))
+ if self._model.plugin_specification is not None:
+ console.write('Plugin specification: {0}'.format(
+ console.literal(self._model.plugin_specification.name)))
+ self._topology.dump(self._model.configurations, console, 'Configuration')
+ if self._model.function is not None:
+ console.write('Function: {0}'.format(console.literal(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):
+ self._validate(self._model.inputs,
+ self._model.configurations)
+
+
+class PluginSpecification(common._TemplateHandlerMixin):
+ def instantiate(self, **kwargs):
+ pass
+
+ def dump(self, console):
+ pass
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/ec7b9c97/aria/orchestrator/topology/topology.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/topology/topology.py b/aria/orchestrator/topology/topology.py
new file mode 100644
index 0000000..c66749d
--- /dev/null
+++ b/aria/orchestrator/topology/topology.py
@@ -0,0 +1,256 @@
+# 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 StringIO import StringIO
+
+from ...parser.validation import issue
+from ...modeling import models
+from ...utils import (
+ console as console_utils,
+ formatting
+)
+from . import (
+ template_handler,
+ instance_handler,
+ common
+)
+
+
+class Topology(issue.Reporter):
+
+ _init_map = {
+ models.ServiceTemplate: models.Service,
+ models.ArtifactTemplate: models.Artifact,
+ models.CapabilityTemplate: models.Capability,
+ models.GroupTemplate: models.Group,
+ models.InterfaceTemplate: models.Interface,
+ models.NodeTemplate: models.Node,
+ models.PolicyTemplate: models.Policy,
+ models.SubstitutionTemplate: models.Substitution,
+ models.RelationshipTemplate: models.Relationship,
+ models.OperationTemplate: models.Operation,
+ models.RequirementTemplate: None,
+ models.SubstitutionTemplateMapping: models.SubstitutionMapping,
+
+ # Common
+ models.Metadata: models.Metadata,
+ models.Attribute: models.Attribute,
+ models.Property: models.Property,
+ models.Input: models.Input,
+ models.Output: models.Output,
+ models.Configuration: models.Configuration,
+ models.Argument: models.Argument,
+ models.Type: models.Type
+ }
+
+ class Stylizer(object):
+
+ def __init__(self, indentation=2):
+ self._str = StringIO()
+ self.indentation = indentation
+
+ def write(self, str_):
+ console_utils.puts(str_, stream=self._str)
+
+ @property
+ def indent(self):
+ return console_utils.indent(self.indentation)
+
+ @staticmethod
+ def section(value):
+ return console_utils.Colored.cyan(value, bold=True)
+
+ @staticmethod
+ def type(value):
+ return console_utils.Colored.blue(value, bold=True)
+
+ @staticmethod
+ def node(value):
+ return console_utils.Colored.red(value, bold=True)
+
+ @staticmethod
+ def property(value):
+ return console_utils.Colored.magenta(value, bold=True)
+
+ @staticmethod
+ def literal(value):
+ return console_utils.Colored.magenta(formatting.safe_repr(value))
+
+ @staticmethod
+ def meta(value):
+ return console_utils.Colored.green(value)
+
+ def __repr__(self):
+ return self._str.getvalue()
+
+ def __str__(self):
+ return repr(self)
+
+ def __init__(self, model_storage=None, *args, **kwargs):
+ # TODO: model storage is required only for the list of plugins, can we get it
+ # somewhere else?
+ super(Topology, self).__init__(*args, **kwargs)
+ self._model_storage = model_storage
+ self._handlers = dict(self._init_handlers(instance_handler),
+ **self._init_handlers(template_handler))
+
+ @staticmethod
+ def _init_handlers(module_):
+ handlers = {}
+ for attribute_name in dir(module_):
+ if attribute_name.startswith('_'):
+ continue
+ attribute = getattr(module_, attribute_name)
+ if isinstance(attribute, type) and issubclass(attribute, common._Handler):
+ handlers[getattr(models, attribute_name)] = attribute
+ return handlers
+
+ def instantiate(self, model, **kwargs):
+ """
+ all handlers used by instantiate should hold a tuple as value (handler, instnace_cls)
+ :param model:
+ :param kwargs:
+ :return:
+ """
+ if isinstance(model, dict):
+ return dict((name, self.instantiate(value, **kwargs))
+ for name, value in model.iteritems())
+ elif isinstance(model, list):
+ return list(self.instantiate(value, **kwargs) for value in model)
+ elif model is not None:
+ _handler = self._handlers.get(model.__class__)
+ instance_cls = self._init_map.get(model.__class__)
+ return _handler(self, model).instantiate(instance_cls, **kwargs)
+
+ def validate(self, model, **kwargs):
+ if isinstance(model, dict):
+ return self.validate(model.values())
+ elif isinstance(model, list):
+ return all(self.validate(value) for value in model)
+ elif model is not None:
+ _handler = self._handlers.get(model.__class__)
+ return _handler(self, model).validate(**kwargs)
+
+ def dump(self, model, console=None, section_name=None, **kwargs):
+ console = console or self.Stylizer()
+
+ # if model is empty, no need to print out the section name
+ if model and section_name:
+ console.write('{0}:'.format(section_name))
+
+ if isinstance(model, dict):
+ return self.dump(model.values(), console=console, **kwargs)
+ elif isinstance(model, list):
+ with console.indent:
+ for value in model:
+ self.dump(value, console=console, **kwargs)
+ elif model is not None:
+ _handler = self._handlers.get(model.__class__)
+ _handler(self, model).dump(console=console, **kwargs)
+ return str(console)
+
+ def dump_graph(self, service, **kwargs):
+ console = self.Stylizer()
+ for node in service.nodes.itervalues():
+ if not node.inbound_relationships:
+ self._dump_graph_node(console, node)
+
+ def _dump_graph_node(self, console, node, capability=None):
+ console.write(console.style.node(node.name))
+ if capability is not None:
+ console.write('{0} ({1})'.format(console.style.property(capability.name),
+ console.style.type(capability.type.name)))
+ if node.outbound_relationships:
+ with console.style.indent:
+ for relationship_model in node.outbound_relationships:
+ relationship_name = console.style.property(relationship_model.name)
+ if relationship_model.type is not None:
+ console.write('-> {0} ({1})'.format(
+ relationship_name, console.style.type(relationship_model.type.name)))
+ else:
+ console.write('-> {0}'.format(relationship_name))
+ with console.indent(3):
+ self._dump_graph_node(relationship_model.target_node,
+ relationship_model.target_capability)
+
+ def coerce(self, model, **kwargs):
+ if isinstance(model, dict):
+ return self.validate(model.values())
+ elif isinstance(model, list):
+ return all(self.validate(value) for value in model)
+ elif model is not None:
+ _handler = self._handlers.get(model.__class__)
+ return _handler(self, model).coerce(**kwargs)
+
+ def dump_types(self, service_template, console=None):
+ console = console or self.Stylizer()
+ console.write(self.dump(service_template.node_types, console))
+ console.write(self.dump(service_template.group_types, console))
+ console.write(self.dump(service_template.capability_types, console))
+ console.write(self.dump(service_template.relationship_types, console))
+ console.write(self.dump(service_template.policy_types, console))
+ console.write(self.dump(service_template.artifact_types, console))
+ console.write(self.dump(service_template.interface_types, console))
+
+ return str(console)
+
+ def satisfy_requirements(self, model, **kwargs):
+ if isinstance(model, dict):
+ return self.satisfy_requirements(model.values())
+ elif isinstance(model, list):
+ return all(self.satisfy_requirements(value) for value in model)
+ elif model is not None:
+ _handler = self._handlers.get(model.__class__)
+ return _handler(self, model).satisfy_requirements(**kwargs)
+
+ def validate_capabilities(self, model, **kwargs):
+ if isinstance(model, dict):
+ return self.validate_capabilities(model.values())
+ elif isinstance(model, list):
+ return all(self.validate_capabilities(value) for value in model)
+ elif model is not None:
+ _handler = self._handlers.get(model.__class__)
+ return _handler(self, model).validate_capabilities(**kwargs)
+
+ def _find_host(self, node):
+ if node.type.role == 'host':
+ return node
+
+ has_role = lambda rel, role: \
+ rel.target_capability is not None and rel.target_capability.type.role == role
+
+ for relationship in node.outbound_relationships:
+ if has_role(relationship, 'host'):
+ host = self._find_host(relationship.target_node)
+ if host is not None:
+ return host
+ for relationship in node.inbound_relationships:
+ if has_role(relationship, 'feature'):
+ host = self._find_host(relationship.source_node)
+ if host is not None:
+ return host
+ return None
+
+ def find_hosts(self, service):
+ for node in service.nodes.values():
+ node.host = self._find_host(node)
+
+ def configure_operations(self, model, **kwargs):
+ if isinstance(model, dict):
+ return self.configure_operations(model.values())
+ elif isinstance(model, list):
+ return all(self.configure_operations(value) for value in model)
+ elif model is not None:
+ _handler = self._handlers.get(model.__class__)
+ return _handler(self, model).configure_operations(**kwargs)
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/ec7b9c97/aria/parser/consumption/__init__.py
----------------------------------------------------------------------
diff --git a/aria/parser/consumption/__init__.py b/aria/parser/consumption/__init__.py
index bd4b29c..f9caf5f 100644
--- a/aria/parser/consumption/__init__.py
+++ b/aria/parser/consumption/__init__.py
@@ -20,7 +20,6 @@ Consumption package.
:nosignatures:
aria.parser.consumption.ConsumptionContext
- aria.parser.consumption.Style
Consumers
---------
@@ -47,7 +46,6 @@ Consumers
from .exceptions import ConsumerException
from .context import ConsumptionContext
-from .style import Style
from .consumer import (
Consumer,
ConsumerChain
@@ -70,7 +68,6 @@ from .inputs import Inputs
__all__ = (
'ConsumerException',
'ConsumptionContext',
- 'Style',
'Consumer',
'ConsumerChain',
'Read',
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/ec7b9c97/aria/parser/consumption/consumer.py
----------------------------------------------------------------------
diff --git a/aria/parser/consumption/consumer.py b/aria/parser/consumption/consumer.py
index ea63643..fb60d66 100644
--- a/aria/parser/consumption/consumer.py
+++ b/aria/parser/consumption/consumer.py
@@ -14,6 +14,7 @@
# limitations under the License.
+from ...orchestrator import topology
from ...exceptions import AriaException
from ...utils.exceptions import print_exception
from ..validation import Issue
@@ -27,9 +28,7 @@ class Consumer(object):
"""
def __init__(self, context):
- from aria.orchestrator import topology
-
- self.handler = topology.Handler()
+ self.topology = topology.Topology()
self.context = context
def consume(self):
@@ -77,8 +76,8 @@ class ConsumerChain(Consumer):
else:
raise e
- if consumer.handler.has_issues:
- self.context.validation.extend_issues(consumer.handler.issues)
+ if consumer.topology.has_issues:
+ self.context.validation.extend_issues(consumer.topology.issues)
if self.context.validation.has_issues:
break
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/ec7b9c97/aria/parser/consumption/context.py
----------------------------------------------------------------------
diff --git a/aria/parser/consumption/context.py b/aria/parser/consumption/context.py
index 6fa61f4..5b2f31b 100644
--- a/aria/parser/consumption/context.py
+++ b/aria/parser/consumption/context.py
@@ -21,7 +21,6 @@ from ..loading import LoadingContext
from ..reading import ReadingContext
from ..presentation import PresentationContext
from ..modeling import ModelingContext
-from .style import Style
_thread_locals = threading.local()
@@ -58,7 +57,6 @@ class ConsumptionContext(object):
def __init__(self, set_thread_local=True):
self.args = []
self.out = sys.stdout
- self.style = Style()
self.validation = ValidationContext()
self.loading = LoadingContext()
self.reading = ReadingContext()
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/ec7b9c97/aria/parser/consumption/modeling.py
----------------------------------------------------------------------
diff --git a/aria/parser/consumption/modeling.py b/aria/parser/consumption/modeling.py
index 1338c03..0afd555 100644
--- a/aria/parser/consumption/modeling.py
+++ b/aria/parser/consumption/modeling.py
@@ -43,7 +43,7 @@ class CoerceServiceTemplateValues(Consumer):
"""
def consume(self):
- self.handler.coerce(self.context.modeling.template, report_issues=True)
+ self.topology.coerce(self.context.modeling.template, report_issues=True)
class ValidateServiceTemplate(Consumer):
@@ -52,7 +52,7 @@ class ValidateServiceTemplate(Consumer):
"""
def consume(self):
- self.handler.validate(self.context.modeling.template)
+ self.topology.validate(self.context.modeling.template)
class ServiceTemplate(ConsumerChain):
@@ -75,7 +75,7 @@ class ServiceTemplate(ConsumerChain):
raw = self.context.modeling.template_as_raw
self.context.write(json_dumps(raw, indent=indent))
else:
- self.handler.dump(self.context.modeling.template)
+ self.topology.dump(self.context.modeling.template)
class Types(Consumer):
@@ -93,7 +93,7 @@ class Types(Consumer):
raw = self.context.modeling.types_as_raw
self.context.write(json_dumps(raw, indent=indent))
else:
- self.handler.dump_types(self.context, self.context.modeling.template)
+ self.topology.dump_types(self.context, self.context.modeling.template)
class InstantiateServiceInstance(Consumer):
@@ -106,7 +106,7 @@ class InstantiateServiceInstance(Consumer):
self.context.validation.report('InstantiateServiceInstance consumer: missing service '
'template')
return
- self.context.modeling.instance = self.handler.instantiate(
+ self.context.modeling.instance = self.topology.instantiate(
self.context.modeling.template,
inputs=dict(self.context.modeling.inputs)
)
@@ -134,7 +134,7 @@ class CoerceServiceInstanceValues(Consumer):
"""
def consume(self):
- self.handler.coerce(self.context.modeling.instance, report_issues=True)
+ self.topology.coerce(self.context.modeling.instance, report_issues=True)
class ValidateServiceInstance(Consumer):
@@ -143,7 +143,7 @@ class ValidateServiceInstance(Consumer):
"""
def consume(self):
- self.handler.validate(self.context.modeling.instance)
+ self.topology.validate(self.context.modeling.instance)
class SatisfyRequirements(Consumer):
@@ -152,7 +152,7 @@ class SatisfyRequirements(Consumer):
"""
def consume(self):
- self.handler.satisfy_requirements(self.context.modeling.instance)
+ self.topology.satisfy_requirements(self.context.modeling.instance)
class ValidateCapabilities(Consumer):
@@ -161,7 +161,7 @@ class ValidateCapabilities(Consumer):
"""
def consume(self):
- self.handler.validate_capabilities(self.context.modeling.instance)
+ self.topology.validate_capabilities(self.context.modeling.instance)
class FindHosts(Consumer):
@@ -170,7 +170,7 @@ class FindHosts(Consumer):
"""
def consume(self):
- self.handler.find_hosts(self.context.modeling.instance)
+ self.topology.find_hosts(self.context.modeling.instance)
class ConfigureOperations(Consumer):
@@ -179,7 +179,7 @@ class ConfigureOperations(Consumer):
"""
def consume(self):
- self.handler.configure_operations(self.context.modeling.instance)
+ self.topology.configure_operations(self.context.modeling.instance)
class ServiceInstance(ConsumerChain):
@@ -211,5 +211,5 @@ class ServiceInstance(ConsumerChain):
raw = self.context.modeling.instance_as_raw
self.context.write(json_dumps(raw, indent=indent))
else:
- str_rep = self.handler.dump(self.context.modeling.instance)
+ str_rep = self.topology.dump(self.context.modeling.instance)
self.context.write(str_rep)
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/ec7b9c97/aria/parser/consumption/style.py
----------------------------------------------------------------------
diff --git a/aria/parser/consumption/style.py b/aria/parser/consumption/style.py
deleted file mode 100644
index 72892b9..0000000
--- a/aria/parser/consumption/style.py
+++ /dev/null
@@ -1,50 +0,0 @@
-# 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 ...utils.console import Colored, indent
-from ...utils.formatting import safe_repr
-
-
-class Style(object):
- def __init__(self, indentation=2):
- self.indentation = indentation
-
- @property
- def indent(self):
- return indent(self.indentation)
-
- @staticmethod
- def section(value):
- return Colored.cyan(value, bold=True)
-
- @staticmethod
- def type(value):
- return Colored.blue(value, bold=True)
-
- @staticmethod
- def node(value):
- return Colored.red(value, bold=True)
-
- @staticmethod
- def property(value):
- return Colored.magenta(value, bold=True)
-
- @staticmethod
- def literal(value):
- return Colored.magenta(safe_repr(value))
-
- @staticmethod
- def meta(value):
- return Colored.green(value)
[2/2] incubator-ariatosca git commit: removed the old style class
from consumption, removed any unnecessary and local imports
Posted by mx...@apache.org.
removed the old style class from consumption, removed any unnecessary and local imports
Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/ec7b9c97
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/ec7b9c97
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/ec7b9c97
Branch: refs/heads/ARIA-174-Refactor-instantiation-phase
Commit: ec7b9c9702509f6619d4ae20508d06134ee10f26
Parents: bb67dbb
Author: max-orlov <ma...@gigaspaces.com>
Authored: Thu Jul 27 16:45:03 2017 +0300
Committer: max-orlov <ma...@gigaspaces.com>
Committed: Thu Jul 27 17:15:25 2017 +0300
----------------------------------------------------------------------
aria/cli/commands/service_templates.py | 6 +-
aria/cli/commands/services.py | 6 +-
aria/core.py | 24 +-
aria/orchestrator/topology/__init__.py | 216 +------
aria/orchestrator/topology/instance.py | 633 --------------------
aria/orchestrator/topology/instance_handler.py | 633 ++++++++++++++++++++
aria/orchestrator/topology/template.py | 583 ------------------
aria/orchestrator/topology/template_handler.py | 583 ++++++++++++++++++
aria/orchestrator/topology/topology.py | 256 ++++++++
aria/parser/consumption/__init__.py | 3 -
aria/parser/consumption/consumer.py | 9 +-
aria/parser/consumption/context.py | 2 -
aria/parser/consumption/modeling.py | 24 +-
aria/parser/consumption/style.py | 50 --
14 files changed, 1507 insertions(+), 1521 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/ec7b9c97/aria/cli/commands/service_templates.py
----------------------------------------------------------------------
diff --git a/aria/cli/commands/service_templates.py b/aria/cli/commands/service_templates.py
index 6eef97a..482170b 100644
--- a/aria/cli/commands/service_templates.py
+++ b/aria/cli/commands/service_templates.py
@@ -28,7 +28,7 @@ from ...core import Core
from ...storage import exceptions as storage_exceptions
from ...parser import consumption
from ...utils import (formatting, collections, console)
-from ... orchestrator import topology
+from ... orchestrator.topology import Topology
DESCRIPTION_FIELD_LENGTH_LIMIT = 20
SERVICE_TEMPLATE_COLUMNS = \
@@ -73,9 +73,9 @@ def show(service_template_name, model_storage, mode_full, mode_types, format_jso
elif format_yaml:
console.puts(formatting.yaml_dumps(collections.prune(service_template.as_raw)))
else:
- logger.info(topology.Handler().dump(service_template))
+ logger.info(Topology().dump(service_template))
elif mode_types:
- logger.info(topology.Handler().dump_types(service_template=service_template))
+ logger.info(Topology().dump_types(service_template=service_template))
else:
logger.info('Showing service template {0}...'.format(service_template_name))
service_template_dict = service_template.to_dict()
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/ec7b9c97/aria/cli/commands/services.py
----------------------------------------------------------------------
diff --git a/aria/cli/commands/services.py b/aria/cli/commands/services.py
index 93bea7f..3b07866 100644
--- a/aria/cli/commands/services.py
+++ b/aria/cli/commands/services.py
@@ -20,7 +20,7 @@ CLI ``services`` sub-commands.
import os
from StringIO import StringIO
-from aria.orchestrator import topology
+from aria.orchestrator.topology import Topology
from . import service_templates
from .. import helptexts
from .. import table
@@ -74,9 +74,9 @@ def show(service_name, model_storage, mode_full, mode_graph, format_json, format
elif format_yaml:
console.puts(formatting.yaml_dumps(collections.prune(service.as_raw)))
else:
- logger.info(topology.Handler().dump(service))
+ logger.info(Topology().dump(service))
elif mode_graph:
- logger.info(topology.Handler().dump_graph(service))
+ logger.info(Topology().dump_graph(service))
else:
logger.info('Showing service {0}...'.format(service_name))
service_dict = service.to_dict()
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/ec7b9c97/aria/core.py
----------------------------------------------------------------------
diff --git a/aria/core.py b/aria/core.py
index 444bcb9..e726be7 100644
--- a/aria/core.py
+++ b/aria/core.py
@@ -17,10 +17,10 @@
ARIA core module.
"""
-from aria.orchestrator import topology
from . import exceptions
from .parser import consumption
from .parser.loading.location import UriLocation
+from .orchestrator.topology import Topology
class Core(object):
@@ -74,20 +74,20 @@ class Core(object):
# setting no autoflush for the duration of instantiation - this helps avoid dependency
# constraints as they're being set up
with storage_session.no_autoflush:
- handler = topology.Handler(self.model_storage)
- service = handler.instantiate(service_template, inputs=inputs)
- handler.coerce(service)
+ topology = Topology(self.model_storage)
+ service = topology.instantiate(service_template, inputs=inputs)
+ topology.coerce(service)
- handler.validate(service)
- handler.satisfy_requirements(service)
- handler.coerce(service)
+ topology.validate(service)
+ topology.satisfy_requirements(service)
+ topology.coerce(service)
- handler.validate_capabilities(service)
- handler.find_hosts(service)
- handler.configure_operations(service)
- handler.coerce(service)
+ topology.validate_capabilities(service)
+ topology.find_hosts(service)
+ topology.configure_operations(service)
+ topology.coerce(service)
- if handler.dump_issues():
+ if topology.dump_issues():
raise exceptions.InstantiationError('Failed to instantiate service template `{0}`'
.format(service_template.name))
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/ec7b9c97/aria/orchestrator/topology/__init__.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/topology/__init__.py b/aria/orchestrator/topology/__init__.py
index 1ba12aa..099a950 100644
--- a/aria/orchestrator/topology/__init__.py
+++ b/aria/orchestrator/topology/__init__.py
@@ -12,219 +12,5 @@
# 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 StringIO import StringIO
-from ...parser.validation import issue
-from ...parser.consumption.style import Style
-from ...modeling import models
-from ...utils import console as console_utils
-from . import (
- template,
- instance,
- common
-)
-
-
-class Handler(issue.Reporter):
-
- _init_map = {
- models.ServiceTemplate: models.Service,
- models.ArtifactTemplate: models.Artifact,
- models.CapabilityTemplate: models.Capability,
- models.GroupTemplate: models.Group,
- models.InterfaceTemplate: models.Interface,
- models.NodeTemplate: models.Node,
- models.PolicyTemplate: models.Policy,
- models.SubstitutionTemplate: models.Substitution,
- models.RelationshipTemplate: models.Relationship,
- models.OperationTemplate: models.Operation,
- models.RequirementTemplate: None,
- models.SubstitutionTemplateMapping: models.SubstitutionMapping,
-
- # Common
- models.Metadata: models.Metadata,
- models.Attribute: models.Attribute,
- models.Property: models.Property,
- models.Input: models.Input,
- models.Output: models.Output,
- models.Configuration: models.Configuration,
- models.Argument: models.Argument,
- models.Type: models.Type
- }
-
- class TopologyStylizer(object):
- def __init__(self):
- self._style = Style()
- self._str = StringIO()
-
- def write(self, str_):
- console_utils.puts(str_, stream=self._str)
-
- def __repr__(self):
- return self._str.getvalue()
-
- def __str__(self):
- return repr(self)
-
- def __getattr__(self, item):
- try:
- return getattr(self._style, item)
- except AttributeError:
- return super(Handler.TopologyStylizer, self).__getattribute__(item)
-
- def __init__(self, model_storage=None, *args, **kwargs):
- # TODO: model storage is required only for the list of plugins, can we get it
- # somewhere else?
- super(Handler, self).__init__(*args, **kwargs)
- self._model_storage = model_storage
- self._handlers = dict(self._init_handlers(instance), **self._init_handlers(template))
-
- @staticmethod
- def _init_handlers(module_):
- handlers = {}
- for attribute_name in dir(module_):
- if attribute_name.startswith('_'):
- continue
- attribute = getattr(module_, attribute_name)
- if isinstance(attribute, type) and issubclass(attribute, common._Handler):
- handlers[getattr(models, attribute_name)] = attribute
- return handlers
-
- def instantiate(self, model, **kwargs):
- """
- all handlers used by instantiate should hold a tuple as value (handler, instnace_cls)
- :param model:
- :param kwargs:
- :return:
- """
- if isinstance(model, dict):
- return dict((name, self.instantiate(value, **kwargs))
- for name, value in model.iteritems())
- elif isinstance(model, list):
- return list(self.instantiate(value, **kwargs) for value in model)
- elif model is not None:
- _handler = self._handlers.get(model.__class__)
- instance_cls = self._init_map.get(model.__class__)
- return _handler(self, model).instantiate(instance_cls, **kwargs)
-
- def validate(self, model, **kwargs):
- if isinstance(model, dict):
- return self.validate(model.values())
- elif isinstance(model, list):
- return all(self.validate(value) for value in model)
- elif model is not None:
- _handler = self._handlers.get(model.__class__)
- return _handler(self, model).validate(**kwargs)
-
- def dump(self, model, console=None, section_name=None, **kwargs):
- console = console or self.TopologyStylizer()
-
- # if model is empty, no need to print out the section name
- if model and section_name:
- console.write('{0}:'.format(section_name))
-
- if isinstance(model, dict):
- return self.dump(model.values(), console=console, **kwargs)
- elif isinstance(model, list):
- with console.indent:
- for value in model:
- self.dump(value, console=console, **kwargs)
- elif model is not None:
- _handler = self._handlers.get(model.__class__)
- _handler(self, model).dump(console=console, **kwargs)
- return str(console)
-
- def dump_graph(self, service, **kwargs):
- console = self.TopologyStylizer()
- for node in service.nodes.itervalues():
- if not node.inbound_relationships:
- self._dump_graph_node(console, node)
-
- def _dump_graph_node(self, console, node, capability=None):
- console.write(console.style.node(node.name))
- if capability is not None:
- console.write('{0} ({1})'.format(console.style.property(capability.name),
- console.style.type(capability.type.name)))
- if node.outbound_relationships:
- with console.style.indent:
- for relationship_model in node.outbound_relationships:
- relationship_name = console.style.property(relationship_model.name)
- if relationship_model.type is not None:
- console.write('-> {0} ({1})'.format(
- relationship_name, console.style.type(relationship_model.type.name)))
- else:
- console.write('-> {0}'.format(relationship_name))
- with console.indent(3):
- self._dump_graph_node(relationship_model.target_node,
- relationship_model.target_capability)
-
- def coerce(self, model, **kwargs):
- if isinstance(model, dict):
- return self.validate(model.values())
- elif isinstance(model, list):
- return all(self.validate(value) for value in model)
- elif model is not None:
- _handler = self._handlers.get(model.__class__)
- return _handler(self, model).coerce(**kwargs)
-
- def dump_types(self, service_template, console=None):
- console = console or self.TopologyStylizer()
- console.write(self.dump(service_template.node_types, console))
- console.write(self.dump(service_template.group_types, console))
- console.write(self.dump(service_template.capability_types, console))
- console.write(self.dump(service_template.relationship_types, console))
- console.write(self.dump(service_template.policy_types, console))
- console.write(self.dump(service_template.artifact_types, console))
- console.write(self.dump(service_template.interface_types, console))
-
- return str(console)
-
- def satisfy_requirements(self, model, **kwargs):
- if isinstance(model, dict):
- return self.satisfy_requirements(model.values())
- elif isinstance(model, list):
- return all(self.satisfy_requirements(value) for value in model)
- elif model is not None:
- _handler = self._handlers.get(model.__class__)
- return _handler(self, model).satisfy_requirements(**kwargs)
-
- def validate_capabilities(self, model, **kwargs):
- if isinstance(model, dict):
- return self.validate_capabilities(model.values())
- elif isinstance(model, list):
- return all(self.validate_capabilities(value) for value in model)
- elif model is not None:
- _handler = self._handlers.get(model.__class__)
- return _handler(self, model).validate_capabilities(**kwargs)
-
- def _find_host(self, node):
- if node.type.role == 'host':
- return node
-
- has_role = lambda rel, role: \
- rel.target_capability is not None and rel.target_capability.type.role == role
-
- for relationship in node.outbound_relationships:
- if has_role(relationship, 'host'):
- host = self._find_host(relationship.target_node)
- if host is not None:
- return host
- for relationship in node.inbound_relationships:
- if has_role(relationship, 'feature'):
- host = self._find_host(relationship.source_node)
- if host is not None:
- return host
- return None
-
- def find_hosts(self, service):
- for node in service.nodes.values():
- node.host = self._find_host(node)
-
- def configure_operations(self, model, **kwargs):
- if isinstance(model, dict):
- return self.configure_operations(model.values())
- elif isinstance(model, list):
- return all(self.configure_operations(value) for value in model)
- elif model is not None:
- _handler = self._handlers.get(model.__class__)
- return _handler(self, model).configure_operations(**kwargs)
+from .topology import Topology
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/ec7b9c97/aria/orchestrator/topology/instance.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/topology/instance.py b/aria/orchestrator/topology/instance.py
deleted file mode 100644
index dc204fe..0000000
--- a/aria/orchestrator/topology/instance.py
+++ /dev/null
@@ -1,633 +0,0 @@
-# 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 ... parser.modeling import context
-from ... modeling import models
-from ... utils import formatting
-from .. import execution_plugin
-from .. import decorators
-from . import common
-
-
-class Artifact(common._InstanceHandlerMixin):
-
- def coerce(self, **kwargs):
- self._topology.coerce(self._model.properties, **kwargs)
-
- def validate(self, **kwargs):
- self._topology.validate(self._model.properties)
-
- def dump(self, console):
- console.write(console.node(self._model.name))
- if self._model.description:
- console.write(console.meta(self._model.description))
- with console.indent:
- console.write('Artifact type: {0}'.format(console.type(self._model.type.name)))
- console.write('Source path: {0}'.format(
- console.literal(self._model.source_path)))
- if self._model.target_path is not None:
- console.write('Target path: {0}'.format(
- console.literal(self._model.target_path)))
- if self._model.repository_url is not None:
- console.write('Repository URL: {0}'.format(
- console.literal(self._model.repository_url)))
- if self._model.repository_credential:
- console.write('Repository credential: {0}'.format(
- console.literal(self._model.repository_credential)))
- self._topology.dump(self._model.properties, console, 'Properties')
-
-
-class Capability(common._InstanceHandlerMixin):
- def coerce(self, **kwargs):
- self._topology.coerce(self._model.properties, **kwargs)
-
- def validate(self, **kwargs):
- self._topology.validate(self._model.properties)
-
- def dump(self, console):
- console.write(console.node(self._model.name))
- with console.indent:
- console.write('Type: {0}'.format(console.type(self._model.type.name)))
- console.write('Occurrences: {0:d} ({1:d}{2})'.format(
- self._model.occurrences,
- 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'))
- self._topology.dump(self._model.properties, console, 'Properties')
-
-
-class Group(common._OperatorHolderHandlerMixin):
-
- def coerce(self, **kwargs):
- self._coerce(self._model.properties, self._model.interfaces, **kwargs)
-
- def validate(self, **kwargs):
- self._validate(self._model.properties,
- self._model.interfaces)
-
- def dump(self, console):
- console.write('Group: {0}'.format(console.node(self._model.name)))
- with console.indent:
- console.write('Type: {0}'.format(console.type(self._model.type.name)))
- self._topology.dump(self._model.properties, console, 'Properties')
- self._topology.dump(self._model.interfaces, console, 'Interfaces')
- if self._model.nodes:
- console.write('Member nodes:')
- with console.indent:
- for node in self._model.nodes:
- console.write(console.node(node.name))
-
- def configure_operations(self):
- for interface in self._model.interfaces.values():
- self._topology.configure_operations(interface)
-
-
-class Interface(common._OperatorHolderHandlerMixin):
- def coerce(self, **kwargs):
- self._coerce(self._model.inputs, self._model.operations, **kwargs)
-
- def validate(self, **kwargs):
- self._validate(self._model.inputs,
- self._model.operations)
-
- def dump(self, console):
- console.write(console.node(self._model.name))
- if self._model.description:
- console.write(console.meta(self._model.description))
- with console.indent:
- console.write('Interface type: {0}'.format(console.type(self._model.type.name)))
- self._topology.dump(self._model.inputs, console, 'Inputs')
- self._topology.dump(self._model.operations, console, 'Operations')
-
- def configure_operations(self):
- for operation in self._model.operations.values():
- self._topology.configure_operations(operation)
-
-
-class Node(common._OperatorHolderHandlerMixin):
- def coerce(self, **kwargs):
- self._coerce(self._model.properties,
- self._model.attributes,
- self._model.interfaces,
- self._model.artifacts,
- self._model.capabilities,
- self._model.outbound_relationships,
- **kwargs)
-
- def validate(self, **kwargs):
- if len(self._model.name) > context.ID_MAX_LENGTH:
- self._topology.report(
- '"{0}" has an ID longer than the limit of {1:d} characters: {2:d}'.format(
- self._model.name, context.ID_MAX_LENGTH, len(self._model.name)),
- level=self._topology.Issue.BETWEEN_INSTANCES)
-
- self._validate(self._model.properties,
- self._model.attributes,
- self._model.interfaces,
- self._model.artifacts,
- self._model.capabilities,
- self._model.outbound_relationships)
-
- def dump(self, console):
- console.write('Node: {0}'.format(console.node(self._model.name)))
- with console.indent:
- console.write('Type: {0}'.format(console.type(self._model.type.name)))
- console.write('Template: {0}'.format(console.node(self._model.node_template.name)))
- self._topology.dump(self._model.properties, console, 'Properties')
- self._topology.dump(self._model.attributes, console, 'Attributes')
- self._topology.dump(self._model.interfaces, console, 'Interfaces')
- self._topology.dump(self._model.artifacts, console, 'Artifacts')
- self._topology.dump(self._model.capabilities, console, 'Capabilities')
- self._topology.dump(self._model.outbound_relationships, console, 'Relationships')
-
- def configure_operations(self):
- for interface in self._model.interfaces.values():
- self._topology.configure_operations(interface)
- for relationship in self._model.outbound_relationships:
- self._topology.configure_operations(relationship)
-
- def validate_capabilities(self):
- satisfied = False
- for capability in self._model.capabilities.itervalues():
- if not capability.has_enough_relationships:
- self._topology.report(
- 'capability "{0}" of node "{1}" requires at least {2:d} '
- 'relationships but has {3:d}'.format(capability.name,
- self._model.name,
- capability.min_occurrences,
- capability.occurrences),
- level=self._topology.Issue.BETWEEN_INSTANCES)
- satisfied = False
- return satisfied
-
- def satisfy_requirements(self):
- satisfied = True
- for requirement_template in self._model.node_template.requirement_templates:
-
- # Since we try and satisfy requirements, which are node template bound, and use that
- # information in the creation of the relationship, Some requirements may have been
- # satisfied by a previous run on that node template.
- # The entire mechanism of satisfying requirements needs to be refactored.
- if any(r.requirement_template == requirement_template
- for r in self._model.outbound_relationships):
- return satisfied
-
- # Find target template
- target_node_template, target_node_capability = self._find_target(requirement_template)
- if target_node_template is not None:
- satisfied = self._satisfy_capability(
- target_node_capability, target_node_template, requirement_template)
- else:
- self._topology.report('requirement "{0}" of node "{1}" has no target node template'.
- format(requirement_template.name, self._model.name),
- level=self._topology.Issue.BETWEEN_INSTANCES)
- satisfied = False
- return satisfied
-
- def _satisfy_capability(self, target_node_capability, target_node_template,
- requirement_template):
- # Find target nodes
- target_nodes = target_node_template.nodes
- if target_nodes:
- target_node = None
- target_capability = None
-
- if target_node_capability is not None:
- # Relate to the first target node that has capacity
- for node in target_nodes:
- a_target_capability = node.capabilities.get(target_node_capability.name)
- if a_target_capability.relate():
- target_node = node
- target_capability = a_target_capability
- break
- else:
- # Use first target node
- target_node = target_nodes[0]
-
- if target_node is not None:
- if requirement_template.relationship_template is not None:
- relationship_model = self._topology.instantiate(
- requirement_template.relationship_template)
- else:
- relationship_model = models.Relationship()
- relationship_model.name = requirement_template.name
- relationship_model.requirement_template = requirement_template
- relationship_model.target_node = target_node
- relationship_model.target_capability = target_capability
- self._model.outbound_relationships.append(relationship_model)
- return True
- else:
- self._topology.report(
- 'requirement "{0}" of node "{1}" targets node '
- 'template "{2}" but its instantiated nodes do not '
- 'have enough capacity'.format(
- requirement_template.name, self._model.name, target_node_template.name),
- level=self._topology.Issue.BETWEEN_INSTANCES)
- return False
- else:
- self._topology.report(
- 'requirement "{0}" of node "{1}" targets node template '
- '"{2}" but it has no instantiated nodes'.format(
- requirement_template.name, self._model.name, target_node_template.name),
- level=self._topology.Issue.BETWEEN_INSTANCES)
- return False
-
- def _find_target(self, requirement_template):
- # We might already have a specific node template, so we'll just verify it
- if requirement_template.target_node_template is not None:
- if not self._model.node_template.is_target_node_template_valid(
- requirement_template.target_node_template):
- self._topology.report(
- 'requirement "{0}" of node template "{1}" is for node '
- 'template "{2}" but it does not match constraints'.format(
- requirement_template.name,
- requirement_template.target_node_template.name,
- self._model.node_template.name),
- level=self._topology.Issue.BETWEEN_TYPES)
- if (requirement_template.target_capability_type is not None or
- requirement_template.target_capability_name is not None):
- target_node_capability = self._get_capability(requirement_template)
- if target_node_capability is None:
- return None, None
- else:
- target_node_capability = None
-
- return requirement_template.target_node_template, target_node_capability
-
- # Find first node that matches the type
- elif requirement_template.target_node_type is not None:
- for target_node_template in \
- self._model.node_template.service_template.node_templates.itervalues():
- if requirement_template.target_node_type.get_descendant(
- target_node_template.type.name) is None:
- continue
-
- if not self._model.node_template.is_target_node_template_valid(
- target_node_template):
- continue
-
- target_node_capability = self._get_capability(requirement_template,
- target_node_template)
-
- if target_node_capability is None:
- continue
-
- return target_node_template, target_node_capability
-
- return None, None
-
- def _get_capability(self, requirement_template, target_node_template=None):
- target_node_template = target_node_template or requirement_template.target_node_template
-
- for capability_template in target_node_template.capability_templates.values():
- if self._satisfies_requirement(
- capability_template, requirement_template, target_node_template):
- return capability_template
-
- return None
-
- def _satisfies_requirement(
- self, capability_template, requirement_template, target_node_template):
- # Do we match the required capability type?
- if (requirement_template.target_capability_type and
- requirement_template.target_capability_type.get_descendant(
- capability_template.type.name) is None):
- return False
-
- # Are we in valid_source_node_types?
- if capability_template.valid_source_node_types:
- for valid_source_node_type in capability_template.valid_source_node_types:
- if valid_source_node_type.get_descendant(
- self._model.node_template.type.name) is None:
- return False
-
- # Apply requirement constraints
- if requirement_template.target_node_template_constraints:
- for node_template_constraint in requirement_template.target_node_template_constraints:
- if not node_template_constraint.matches(
- self._model.node_template, target_node_template):
- return False
-
- return True
-
-
-class Operation(common._OperatorHolderHandlerMixin):
- def coerce(self, **kwargs):
- self._coerce(self._model.inputs,
- self._model.configurations,
- self._model.arguments,
- **kwargs)
-
- def validate(self, **kwargs):
- self._validate(self._model.inputs,
- self._model.configurations,
- self._model.arguments)
-
- def dump(self, console):
- console.write(console.node(self._model.name))
- if self._model.description:
- console.write(console.meta(self._model.description))
- with console.indent:
- if self._model.implementation is not None:
- console.write('Implementation: {0}'.format(
- console.literal(self._model.implementation)))
- if self._model.dependencies:
- console.write(
- 'Dependencies: {0}'.format(
- ', '.join((str(console.literal(v)) for v in self._model.dependencies))))
- self._topology.dump(self._model.inputs, console, 'Inputs')
- if self._model.executor is not None:
- console.write('Executor: {0}'.format(console.literal(self._model.executor)))
- if self._model.max_attempts is not None:
- console.write('Max attempts: {0}'.format(console.literal(self._model.max_attempts)))
- if self._model.retry_interval is not None:
- console.write('Retry interval: {0}'.format(
- console.literal(self._model.retry_interval)))
- if self._model.plugin is not None:
- console.write('Plugin: {0}'.format(
- console.literal(self._model.plugin.name)))
- self._topology.dump(self._model.configurations, console, 'Configuration')
- if self._model.function is not None:
- console.write('Function: {0}'.format(console.literal(self._model.function)))
- self._topology.dump(self._model.arguments, console, 'Arguments')
-
- def configure_operations(self):
- if self._model.implementation is None and self._model.function is None:
- return
-
- if (self._model.interface is not None and
- self._model.plugin is None and
- self._model.function is None):
- # ("interface" is None for workflow operations, which do not currently use "plugin")
- # The default (None) plugin is the execution plugin
- execution_plugin.instantiation.configure_operation(self._model)
- else:
- # In the future plugins may be able to add their own "configure_operation" hook that
- # can validate the configuration and otherwise create specially derived arguments. For
- # now, we just send all configuration parameters as arguments without validation.
- for key, conf in self._model.configurations.items():
- self._model.arguments[key] = self._topology.instantiate(conf.as_argument())
-
- if self._model.interface is not None:
- # Send all interface inputs as extra arguments
- # ("interface" is None for workflow operations)
- # Note that they will override existing arguments of the same names
- for key, input in self._model.interface.inputs.items():
- self._model.arguments[key] = self._topology.instantiate(input.as_argument())
-
- # Send all inputs as extra arguments
- # Note that they will override existing arguments of the same names
- for key, input in self._model.inputs.items():
- self._model.arguments[key] = self._topology.instantiate(input.as_argument())
-
- # Check for reserved arguments
- used_reserved_names = set(decorators.OPERATION_DECORATOR_RESERVED_ARGUMENTS).intersection(
- self._model.arguments.keys())
- if used_reserved_names:
- self._topology.report(
- 'using reserved arguments in operation "{0}": {1}'.format(
- self._model.name, formatting.string_list_as_string(used_reserved_names)),
- level=self._topology.Issue.EXTERNAL)
-
-
-class Policy(common._InstanceHandlerMixin):
- def coerce(self, **kwargs):
- self._topology.coerce(self._model.properties, **kwargs)
-
- def validate(self, **kwargs):
- self._topology.validate(self._model.properties)
-
- def dump(self, console):
- console.write('Policy: {0}'.format(console.node(self._model.name)))
- with console.indent:
- console.write('Type: {0}'.format(console.type(self._model.type.name)))
- self._topology.dump(self._model.properties, console, 'Properties')
- if self._model.nodes:
- console.write('Target nodes:')
- with console.indent:
- for node in self._model.nodes:
- console.write(console.node(node.name))
- if self._model.groups:
- console.write('Target groups:')
- with console.indent:
- for group in self._model.groups:
- console.write(console.node(group.name))
-
-
-class Relationship(common._OperatorHolderHandlerMixin):
- def coerce(self, **kwargs):
- self._coerce(self._model.properties,
- self._model.interfaces,
- **kwargs)
-
- def validate(self, **kwargs):
- self._validate(self._model.properties,
- self._model.interfaces)
-
- def dump(self, console):
- if self._model.name:
- console.write('{0} ->'.format(console.node(self._model.name)))
- else:
- console.write('->')
- with console.indent:
- console.write('Node: {0}'.format(console.node(self._model.target_node.name)))
- if self._model.target_capability:
- console.write('Capability: {0}'.format(console.node(
- self._model.target_capability.name)))
- if self._model.type is not None:
- console.write('Relationship type: {0}'.format(
- console.type(self._model.type.name)))
- if (self._model.relationship_template is not None and
- self._model.relationship_template.name):
- console.write('Relationship template: {0}'.format(
- console.node(self._model.relationship_template.name)))
- self._topology.dump(self._model.properties, console, 'Properties')
- self._topology.dump(self._model.interfaces, console, 'Interfaces')
-
- def configure_operations(self):
- for interface in self._model.interfaces.values():
- self._topology.configure_operations(interface)
-
-
-class Service(common._OperatorHolderHandlerMixin):
- def coerce(self, **kwargs):
- self._coerce(self._model.meta_data,
- self._model.nodes,
- self._model.groups,
- self._model.policies,
- self._model.substitution,
- self._model.inputs,
- self._model.outputs,
- self._model.workflows,
- **kwargs)
-
- def validate(self, **kwargs):
- self._validate(self._model.meta_data,
- self._model.nodes,
- self._model.groups,
- self._model.policies,
- self._model.substitution,
- self._model.inputs,
- self._model.outputs,
- self._model.workflows)
-
- def dump(self, console):
- if self._model.description is not None:
- console.write(console.meta(self._model.description))
- self._topology.dump(self._model.meta_data, console, 'Metadata')
- self._topology.dump(self._model.nodes, console)
- self._topology.dump(self._model.groups, console)
- self._topology.dump(self._model.policies, console)
- self._topology.dump(self._model.substitution, console)
- self._topology.dump(self._model.inputs, console, 'Inputs')
- self._topology.dump(self._model.outputs, console, 'Outputs')
- self._topology.dump(self._model.workflows, console, 'Workflows')
-
- def configure_operations(self):
- for node in self._model.nodes.itervalues():
- self._topology.configure_operations(node)
- for group in self._model.groups.itervalues():
- self._topology.configure_operations(group)
- for operation in self._model.workflows.itervalues():
- self._topology.configure_operations(operation)
-
- def validate_capabilities(self):
- satisfied = True
- for node in self._model.nodes.values():
- if not self._topology.validate_capabilities(node):
- satisfied = False
- return satisfied
-
- def satisfy_requirements(self):
- return all(self._topology.satisfy_requirements(node)
- for node in self._model.nodes.values())
-
-
-class Substitution(common._InstanceHandlerMixin):
- def coerce(self, **kwargs):
- self._topology.coerce(self._model.mappings, **kwargs)
-
- def validate(self, **kwargs):
- self._topology.validate(self._model.mappings)
-
- def dump(self, console):
- console.write('Substitution:')
- with console.indent:
- console.write('Node type: {0}'.format(console.type(self._model.node_type.name)))
- self._topology.dump(self._model.mappings, console, 'Mappings')
-
-
-class SubstitutionMapping(common._InstanceHandlerMixin):
-
- def validate(self, **kwargs):
- if (self._model.capability is None) and (self._model.requirement_template is None):
- self._topology.report(
- 'mapping "{0}" refers to neither capability nor a requirement'
- ' in node: {1}'.format(
- self._model.name, formatting.safe_repr(self._model.node.name)),
- level=self._topology.Issue.BETWEEN_TYPES)
-
- def dump(self, console):
- if self._model.capability is not None:
- console.write('{0} -> {1}.{2}'.format(
- console.node(self._model.name),
- console.node(self._model.capability.node.name),
- console.node(self._model.capability.name)))
- else:
- console.write('{0} -> {1}.{2}'.format(
- console.node(self._model.name),
- console.node(self._model.node.name),
- console.node(self._model.requirement_template.name)))
-
-
-class Metadata(common._InstanceHandlerMixin):
-
- def dump(self, console):
- console.write('{0}: {1}'.format(
- console.property(self._topology.name),
- console.literal(self._topology.value)))
-
- def coerce(self):
- pass
-
- def instantiate(self, instance_cls, **kwargs):
- return instance_cls(name=self._model.name, value=self._model.value)
-
- def validate(self):
- pass
-
-
-class _Parameter(common._InstanceHandlerMixin):
-
- def dump(self, console):
- if self._model.type_name is not None:
- console.write('{0}: {1} ({2})'.format(
- console.property(self._model.name),
- console.literal(formatting.as_raw(self._model.value)),
- console.type(self._model.type_name)))
- else:
- console.write('{0}: {1}'.format(
- console.property(self._model.name),
- console.literal(formatting.as_raw(self._model.value))))
- if self._model.description:
- console.write(console.meta(self._model.description))
-
- def instantiate(self, instance_cls, **kwargs):
- return instance_cls(
- name=self._model.name, # pylint: disable=unexpected-keyword-arg
- type_name=self._model.type_name,
- _value=self._model._value,
- description=self._model.description
- )
-
- def validate(self):
- pass
-
-
-class Attribute(_Parameter):
- pass
-
-
-class Input(_Parameter):
- pass
-
-
-class Output(_Parameter):
- pass
-
-
-class Argument(_Parameter):
- pass
-
-
-class Property(_Parameter):
- pass
-
-
-class Configuration(_Parameter):
- pass
-
-
-class Type(common._InstanceHandlerMixin):
- def coerce(self):
- pass
-
- def dump(self, console):
- if self._model.name:
- console.write(console.type(self._model.name))
- with console.indent:
- for child in self._model.children:
- self._topology.dump(child, console)
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/ec7b9c97/aria/orchestrator/topology/instance_handler.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/topology/instance_handler.py b/aria/orchestrator/topology/instance_handler.py
new file mode 100644
index 0000000..dc204fe
--- /dev/null
+++ b/aria/orchestrator/topology/instance_handler.py
@@ -0,0 +1,633 @@
+# 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 ... parser.modeling import context
+from ... modeling import models
+from ... utils import formatting
+from .. import execution_plugin
+from .. import decorators
+from . import common
+
+
+class Artifact(common._InstanceHandlerMixin):
+
+ def coerce(self, **kwargs):
+ self._topology.coerce(self._model.properties, **kwargs)
+
+ def validate(self, **kwargs):
+ self._topology.validate(self._model.properties)
+
+ def dump(self, console):
+ console.write(console.node(self._model.name))
+ if self._model.description:
+ console.write(console.meta(self._model.description))
+ with console.indent:
+ console.write('Artifact type: {0}'.format(console.type(self._model.type.name)))
+ console.write('Source path: {0}'.format(
+ console.literal(self._model.source_path)))
+ if self._model.target_path is not None:
+ console.write('Target path: {0}'.format(
+ console.literal(self._model.target_path)))
+ if self._model.repository_url is not None:
+ console.write('Repository URL: {0}'.format(
+ console.literal(self._model.repository_url)))
+ if self._model.repository_credential:
+ console.write('Repository credential: {0}'.format(
+ console.literal(self._model.repository_credential)))
+ self._topology.dump(self._model.properties, console, 'Properties')
+
+
+class Capability(common._InstanceHandlerMixin):
+ def coerce(self, **kwargs):
+ self._topology.coerce(self._model.properties, **kwargs)
+
+ def validate(self, **kwargs):
+ self._topology.validate(self._model.properties)
+
+ def dump(self, console):
+ console.write(console.node(self._model.name))
+ with console.indent:
+ console.write('Type: {0}'.format(console.type(self._model.type.name)))
+ console.write('Occurrences: {0:d} ({1:d}{2})'.format(
+ self._model.occurrences,
+ 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'))
+ self._topology.dump(self._model.properties, console, 'Properties')
+
+
+class Group(common._OperatorHolderHandlerMixin):
+
+ def coerce(self, **kwargs):
+ self._coerce(self._model.properties, self._model.interfaces, **kwargs)
+
+ def validate(self, **kwargs):
+ self._validate(self._model.properties,
+ self._model.interfaces)
+
+ def dump(self, console):
+ console.write('Group: {0}'.format(console.node(self._model.name)))
+ with console.indent:
+ console.write('Type: {0}'.format(console.type(self._model.type.name)))
+ self._topology.dump(self._model.properties, console, 'Properties')
+ self._topology.dump(self._model.interfaces, console, 'Interfaces')
+ if self._model.nodes:
+ console.write('Member nodes:')
+ with console.indent:
+ for node in self._model.nodes:
+ console.write(console.node(node.name))
+
+ def configure_operations(self):
+ for interface in self._model.interfaces.values():
+ self._topology.configure_operations(interface)
+
+
+class Interface(common._OperatorHolderHandlerMixin):
+ def coerce(self, **kwargs):
+ self._coerce(self._model.inputs, self._model.operations, **kwargs)
+
+ def validate(self, **kwargs):
+ self._validate(self._model.inputs,
+ self._model.operations)
+
+ def dump(self, console):
+ console.write(console.node(self._model.name))
+ if self._model.description:
+ console.write(console.meta(self._model.description))
+ with console.indent:
+ console.write('Interface type: {0}'.format(console.type(self._model.type.name)))
+ self._topology.dump(self._model.inputs, console, 'Inputs')
+ self._topology.dump(self._model.operations, console, 'Operations')
+
+ def configure_operations(self):
+ for operation in self._model.operations.values():
+ self._topology.configure_operations(operation)
+
+
+class Node(common._OperatorHolderHandlerMixin):
+ def coerce(self, **kwargs):
+ self._coerce(self._model.properties,
+ self._model.attributes,
+ self._model.interfaces,
+ self._model.artifacts,
+ self._model.capabilities,
+ self._model.outbound_relationships,
+ **kwargs)
+
+ def validate(self, **kwargs):
+ if len(self._model.name) > context.ID_MAX_LENGTH:
+ self._topology.report(
+ '"{0}" has an ID longer than the limit of {1:d} characters: {2:d}'.format(
+ self._model.name, context.ID_MAX_LENGTH, len(self._model.name)),
+ level=self._topology.Issue.BETWEEN_INSTANCES)
+
+ self._validate(self._model.properties,
+ self._model.attributes,
+ self._model.interfaces,
+ self._model.artifacts,
+ self._model.capabilities,
+ self._model.outbound_relationships)
+
+ def dump(self, console):
+ console.write('Node: {0}'.format(console.node(self._model.name)))
+ with console.indent:
+ console.write('Type: {0}'.format(console.type(self._model.type.name)))
+ console.write('Template: {0}'.format(console.node(self._model.node_template.name)))
+ self._topology.dump(self._model.properties, console, 'Properties')
+ self._topology.dump(self._model.attributes, console, 'Attributes')
+ self._topology.dump(self._model.interfaces, console, 'Interfaces')
+ self._topology.dump(self._model.artifacts, console, 'Artifacts')
+ self._topology.dump(self._model.capabilities, console, 'Capabilities')
+ self._topology.dump(self._model.outbound_relationships, console, 'Relationships')
+
+ def configure_operations(self):
+ for interface in self._model.interfaces.values():
+ self._topology.configure_operations(interface)
+ for relationship in self._model.outbound_relationships:
+ self._topology.configure_operations(relationship)
+
+ def validate_capabilities(self):
+ satisfied = False
+ for capability in self._model.capabilities.itervalues():
+ if not capability.has_enough_relationships:
+ self._topology.report(
+ 'capability "{0}" of node "{1}" requires at least {2:d} '
+ 'relationships but has {3:d}'.format(capability.name,
+ self._model.name,
+ capability.min_occurrences,
+ capability.occurrences),
+ level=self._topology.Issue.BETWEEN_INSTANCES)
+ satisfied = False
+ return satisfied
+
+ def satisfy_requirements(self):
+ satisfied = True
+ for requirement_template in self._model.node_template.requirement_templates:
+
+ # Since we try and satisfy requirements, which are node template bound, and use that
+ # information in the creation of the relationship, Some requirements may have been
+ # satisfied by a previous run on that node template.
+ # The entire mechanism of satisfying requirements needs to be refactored.
+ if any(r.requirement_template == requirement_template
+ for r in self._model.outbound_relationships):
+ return satisfied
+
+ # Find target template
+ target_node_template, target_node_capability = self._find_target(requirement_template)
+ if target_node_template is not None:
+ satisfied = self._satisfy_capability(
+ target_node_capability, target_node_template, requirement_template)
+ else:
+ self._topology.report('requirement "{0}" of node "{1}" has no target node template'.
+ format(requirement_template.name, self._model.name),
+ level=self._topology.Issue.BETWEEN_INSTANCES)
+ satisfied = False
+ return satisfied
+
+ def _satisfy_capability(self, target_node_capability, target_node_template,
+ requirement_template):
+ # Find target nodes
+ target_nodes = target_node_template.nodes
+ if target_nodes:
+ target_node = None
+ target_capability = None
+
+ if target_node_capability is not None:
+ # Relate to the first target node that has capacity
+ for node in target_nodes:
+ a_target_capability = node.capabilities.get(target_node_capability.name)
+ if a_target_capability.relate():
+ target_node = node
+ target_capability = a_target_capability
+ break
+ else:
+ # Use first target node
+ target_node = target_nodes[0]
+
+ if target_node is not None:
+ if requirement_template.relationship_template is not None:
+ relationship_model = self._topology.instantiate(
+ requirement_template.relationship_template)
+ else:
+ relationship_model = models.Relationship()
+ relationship_model.name = requirement_template.name
+ relationship_model.requirement_template = requirement_template
+ relationship_model.target_node = target_node
+ relationship_model.target_capability = target_capability
+ self._model.outbound_relationships.append(relationship_model)
+ return True
+ else:
+ self._topology.report(
+ 'requirement "{0}" of node "{1}" targets node '
+ 'template "{2}" but its instantiated nodes do not '
+ 'have enough capacity'.format(
+ requirement_template.name, self._model.name, target_node_template.name),
+ level=self._topology.Issue.BETWEEN_INSTANCES)
+ return False
+ else:
+ self._topology.report(
+ 'requirement "{0}" of node "{1}" targets node template '
+ '"{2}" but it has no instantiated nodes'.format(
+ requirement_template.name, self._model.name, target_node_template.name),
+ level=self._topology.Issue.BETWEEN_INSTANCES)
+ return False
+
+ def _find_target(self, requirement_template):
+ # We might already have a specific node template, so we'll just verify it
+ if requirement_template.target_node_template is not None:
+ if not self._model.node_template.is_target_node_template_valid(
+ requirement_template.target_node_template):
+ self._topology.report(
+ 'requirement "{0}" of node template "{1}" is for node '
+ 'template "{2}" but it does not match constraints'.format(
+ requirement_template.name,
+ requirement_template.target_node_template.name,
+ self._model.node_template.name),
+ level=self._topology.Issue.BETWEEN_TYPES)
+ if (requirement_template.target_capability_type is not None or
+ requirement_template.target_capability_name is not None):
+ target_node_capability = self._get_capability(requirement_template)
+ if target_node_capability is None:
+ return None, None
+ else:
+ target_node_capability = None
+
+ return requirement_template.target_node_template, target_node_capability
+
+ # Find first node that matches the type
+ elif requirement_template.target_node_type is not None:
+ for target_node_template in \
+ self._model.node_template.service_template.node_templates.itervalues():
+ if requirement_template.target_node_type.get_descendant(
+ target_node_template.type.name) is None:
+ continue
+
+ if not self._model.node_template.is_target_node_template_valid(
+ target_node_template):
+ continue
+
+ target_node_capability = self._get_capability(requirement_template,
+ target_node_template)
+
+ if target_node_capability is None:
+ continue
+
+ return target_node_template, target_node_capability
+
+ return None, None
+
+ def _get_capability(self, requirement_template, target_node_template=None):
+ target_node_template = target_node_template or requirement_template.target_node_template
+
+ for capability_template in target_node_template.capability_templates.values():
+ if self._satisfies_requirement(
+ capability_template, requirement_template, target_node_template):
+ return capability_template
+
+ return None
+
+ def _satisfies_requirement(
+ self, capability_template, requirement_template, target_node_template):
+ # Do we match the required capability type?
+ if (requirement_template.target_capability_type and
+ requirement_template.target_capability_type.get_descendant(
+ capability_template.type.name) is None):
+ return False
+
+ # Are we in valid_source_node_types?
+ if capability_template.valid_source_node_types:
+ for valid_source_node_type in capability_template.valid_source_node_types:
+ if valid_source_node_type.get_descendant(
+ self._model.node_template.type.name) is None:
+ return False
+
+ # Apply requirement constraints
+ if requirement_template.target_node_template_constraints:
+ for node_template_constraint in requirement_template.target_node_template_constraints:
+ if not node_template_constraint.matches(
+ self._model.node_template, target_node_template):
+ return False
+
+ return True
+
+
+class Operation(common._OperatorHolderHandlerMixin):
+ def coerce(self, **kwargs):
+ self._coerce(self._model.inputs,
+ self._model.configurations,
+ self._model.arguments,
+ **kwargs)
+
+ def validate(self, **kwargs):
+ self._validate(self._model.inputs,
+ self._model.configurations,
+ self._model.arguments)
+
+ def dump(self, console):
+ console.write(console.node(self._model.name))
+ if self._model.description:
+ console.write(console.meta(self._model.description))
+ with console.indent:
+ if self._model.implementation is not None:
+ console.write('Implementation: {0}'.format(
+ console.literal(self._model.implementation)))
+ if self._model.dependencies:
+ console.write(
+ 'Dependencies: {0}'.format(
+ ', '.join((str(console.literal(v)) for v in self._model.dependencies))))
+ self._topology.dump(self._model.inputs, console, 'Inputs')
+ if self._model.executor is not None:
+ console.write('Executor: {0}'.format(console.literal(self._model.executor)))
+ if self._model.max_attempts is not None:
+ console.write('Max attempts: {0}'.format(console.literal(self._model.max_attempts)))
+ if self._model.retry_interval is not None:
+ console.write('Retry interval: {0}'.format(
+ console.literal(self._model.retry_interval)))
+ if self._model.plugin is not None:
+ console.write('Plugin: {0}'.format(
+ console.literal(self._model.plugin.name)))
+ self._topology.dump(self._model.configurations, console, 'Configuration')
+ if self._model.function is not None:
+ console.write('Function: {0}'.format(console.literal(self._model.function)))
+ self._topology.dump(self._model.arguments, console, 'Arguments')
+
+ def configure_operations(self):
+ if self._model.implementation is None and self._model.function is None:
+ return
+
+ if (self._model.interface is not None and
+ self._model.plugin is None and
+ self._model.function is None):
+ # ("interface" is None for workflow operations, which do not currently use "plugin")
+ # The default (None) plugin is the execution plugin
+ execution_plugin.instantiation.configure_operation(self._model)
+ else:
+ # In the future plugins may be able to add their own "configure_operation" hook that
+ # can validate the configuration and otherwise create specially derived arguments. For
+ # now, we just send all configuration parameters as arguments without validation.
+ for key, conf in self._model.configurations.items():
+ self._model.arguments[key] = self._topology.instantiate(conf.as_argument())
+
+ if self._model.interface is not None:
+ # Send all interface inputs as extra arguments
+ # ("interface" is None for workflow operations)
+ # Note that they will override existing arguments of the same names
+ for key, input in self._model.interface.inputs.items():
+ self._model.arguments[key] = self._topology.instantiate(input.as_argument())
+
+ # Send all inputs as extra arguments
+ # Note that they will override existing arguments of the same names
+ for key, input in self._model.inputs.items():
+ self._model.arguments[key] = self._topology.instantiate(input.as_argument())
+
+ # Check for reserved arguments
+ used_reserved_names = set(decorators.OPERATION_DECORATOR_RESERVED_ARGUMENTS).intersection(
+ self._model.arguments.keys())
+ if used_reserved_names:
+ self._topology.report(
+ 'using reserved arguments in operation "{0}": {1}'.format(
+ self._model.name, formatting.string_list_as_string(used_reserved_names)),
+ level=self._topology.Issue.EXTERNAL)
+
+
+class Policy(common._InstanceHandlerMixin):
+ def coerce(self, **kwargs):
+ self._topology.coerce(self._model.properties, **kwargs)
+
+ def validate(self, **kwargs):
+ self._topology.validate(self._model.properties)
+
+ def dump(self, console):
+ console.write('Policy: {0}'.format(console.node(self._model.name)))
+ with console.indent:
+ console.write('Type: {0}'.format(console.type(self._model.type.name)))
+ self._topology.dump(self._model.properties, console, 'Properties')
+ if self._model.nodes:
+ console.write('Target nodes:')
+ with console.indent:
+ for node in self._model.nodes:
+ console.write(console.node(node.name))
+ if self._model.groups:
+ console.write('Target groups:')
+ with console.indent:
+ for group in self._model.groups:
+ console.write(console.node(group.name))
+
+
+class Relationship(common._OperatorHolderHandlerMixin):
+ def coerce(self, **kwargs):
+ self._coerce(self._model.properties,
+ self._model.interfaces,
+ **kwargs)
+
+ def validate(self, **kwargs):
+ self._validate(self._model.properties,
+ self._model.interfaces)
+
+ def dump(self, console):
+ if self._model.name:
+ console.write('{0} ->'.format(console.node(self._model.name)))
+ else:
+ console.write('->')
+ with console.indent:
+ console.write('Node: {0}'.format(console.node(self._model.target_node.name)))
+ if self._model.target_capability:
+ console.write('Capability: {0}'.format(console.node(
+ self._model.target_capability.name)))
+ if self._model.type is not None:
+ console.write('Relationship type: {0}'.format(
+ console.type(self._model.type.name)))
+ if (self._model.relationship_template is not None and
+ self._model.relationship_template.name):
+ console.write('Relationship template: {0}'.format(
+ console.node(self._model.relationship_template.name)))
+ self._topology.dump(self._model.properties, console, 'Properties')
+ self._topology.dump(self._model.interfaces, console, 'Interfaces')
+
+ def configure_operations(self):
+ for interface in self._model.interfaces.values():
+ self._topology.configure_operations(interface)
+
+
+class Service(common._OperatorHolderHandlerMixin):
+ def coerce(self, **kwargs):
+ self._coerce(self._model.meta_data,
+ self._model.nodes,
+ self._model.groups,
+ self._model.policies,
+ self._model.substitution,
+ self._model.inputs,
+ self._model.outputs,
+ self._model.workflows,
+ **kwargs)
+
+ def validate(self, **kwargs):
+ self._validate(self._model.meta_data,
+ self._model.nodes,
+ self._model.groups,
+ self._model.policies,
+ self._model.substitution,
+ self._model.inputs,
+ self._model.outputs,
+ self._model.workflows)
+
+ def dump(self, console):
+ if self._model.description is not None:
+ console.write(console.meta(self._model.description))
+ self._topology.dump(self._model.meta_data, console, 'Metadata')
+ self._topology.dump(self._model.nodes, console)
+ self._topology.dump(self._model.groups, console)
+ self._topology.dump(self._model.policies, console)
+ self._topology.dump(self._model.substitution, console)
+ self._topology.dump(self._model.inputs, console, 'Inputs')
+ self._topology.dump(self._model.outputs, console, 'Outputs')
+ self._topology.dump(self._model.workflows, console, 'Workflows')
+
+ def configure_operations(self):
+ for node in self._model.nodes.itervalues():
+ self._topology.configure_operations(node)
+ for group in self._model.groups.itervalues():
+ self._topology.configure_operations(group)
+ for operation in self._model.workflows.itervalues():
+ self._topology.configure_operations(operation)
+
+ def validate_capabilities(self):
+ satisfied = True
+ for node in self._model.nodes.values():
+ if not self._topology.validate_capabilities(node):
+ satisfied = False
+ return satisfied
+
+ def satisfy_requirements(self):
+ return all(self._topology.satisfy_requirements(node)
+ for node in self._model.nodes.values())
+
+
+class Substitution(common._InstanceHandlerMixin):
+ def coerce(self, **kwargs):
+ self._topology.coerce(self._model.mappings, **kwargs)
+
+ def validate(self, **kwargs):
+ self._topology.validate(self._model.mappings)
+
+ def dump(self, console):
+ console.write('Substitution:')
+ with console.indent:
+ console.write('Node type: {0}'.format(console.type(self._model.node_type.name)))
+ self._topology.dump(self._model.mappings, console, 'Mappings')
+
+
+class SubstitutionMapping(common._InstanceHandlerMixin):
+
+ def validate(self, **kwargs):
+ if (self._model.capability is None) and (self._model.requirement_template is None):
+ self._topology.report(
+ 'mapping "{0}" refers to neither capability nor a requirement'
+ ' in node: {1}'.format(
+ self._model.name, formatting.safe_repr(self._model.node.name)),
+ level=self._topology.Issue.BETWEEN_TYPES)
+
+ def dump(self, console):
+ if self._model.capability is not None:
+ console.write('{0} -> {1}.{2}'.format(
+ console.node(self._model.name),
+ console.node(self._model.capability.node.name),
+ console.node(self._model.capability.name)))
+ else:
+ console.write('{0} -> {1}.{2}'.format(
+ console.node(self._model.name),
+ console.node(self._model.node.name),
+ console.node(self._model.requirement_template.name)))
+
+
+class Metadata(common._InstanceHandlerMixin):
+
+ def dump(self, console):
+ console.write('{0}: {1}'.format(
+ console.property(self._topology.name),
+ console.literal(self._topology.value)))
+
+ def coerce(self):
+ pass
+
+ def instantiate(self, instance_cls, **kwargs):
+ return instance_cls(name=self._model.name, value=self._model.value)
+
+ def validate(self):
+ pass
+
+
+class _Parameter(common._InstanceHandlerMixin):
+
+ def dump(self, console):
+ if self._model.type_name is not None:
+ console.write('{0}: {1} ({2})'.format(
+ console.property(self._model.name),
+ console.literal(formatting.as_raw(self._model.value)),
+ console.type(self._model.type_name)))
+ else:
+ console.write('{0}: {1}'.format(
+ console.property(self._model.name),
+ console.literal(formatting.as_raw(self._model.value))))
+ if self._model.description:
+ console.write(console.meta(self._model.description))
+
+ def instantiate(self, instance_cls, **kwargs):
+ return instance_cls(
+ name=self._model.name, # pylint: disable=unexpected-keyword-arg
+ type_name=self._model.type_name,
+ _value=self._model._value,
+ description=self._model.description
+ )
+
+ def validate(self):
+ pass
+
+
+class Attribute(_Parameter):
+ pass
+
+
+class Input(_Parameter):
+ pass
+
+
+class Output(_Parameter):
+ pass
+
+
+class Argument(_Parameter):
+ pass
+
+
+class Property(_Parameter):
+ pass
+
+
+class Configuration(_Parameter):
+ pass
+
+
+class Type(common._InstanceHandlerMixin):
+ def coerce(self):
+ pass
+
+ def dump(self, console):
+ if self._model.name:
+ console.write(console.type(self._model.name))
+ with console.indent:
+ for child in self._model.children:
+ self._topology.dump(child, console)