blob: ef5322ea036b9c3af6f62b7afaec0de036cb1130 [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from ...parser.validation import issue
from ...modeling import models
from ...utils import console
from . import (
template_handler,
instance_handler,
common
)
class Topology(issue.ReporterMixin):
_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.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
}
def __init__(self, *args, **kwargs):
super(Topology, self).__init__(*args, **kwargs)
self._model_cls_to_handler = dict(self._init_handlers(instance_handler),
**self._init_handlers(template_handler))
@staticmethod
def _init_handlers(module_):
"""
Register handlers from a handler module to the models.
:param module_: the module to look for handlers
:returns: dict where the key is the models class, and the value is the handler class
associated with it from the provided 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.HandlerBase):
handlers[getattr(models, attribute_name)] = attribute
return handlers
def instantiate(self, model, **kwargs):
"""
Instantiate the provided model.
:param model:
:param kwargs:
:returns:
"""
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._model_cls_to_handler[model.__class__]
model_instance_cls = self._init_map[model.__class__]
return _handler(self, model).instantiate(model_instance_cls, **kwargs)
def validate(self, model, **kwargs):
if isinstance(model, dict):
return self.validate(model.values(), **kwargs)
elif isinstance(model, list):
return all(self.validate(value, **kwargs) for value in model)
elif model is not None:
_handler = self._model_cls_to_handler[model.__class__]
return _handler(self, model).validate(**kwargs)
def dump(self, model, out_stream=None, title=None, **kwargs):
out_stream = out_stream or console.TopologyStylizer()
# if model is empty, no need to print out the section name
if model and title:
out_stream.write(u'{0}:'.format(title))
if isinstance(model, dict):
if str(out_stream):
with out_stream.indent():
return self.dump(model.values(), out_stream=out_stream, **kwargs)
else:
return self.dump(model.values(), out_stream=out_stream, **kwargs)
elif isinstance(model, list):
for value in model:
self.dump(value, out_stream=out_stream, **kwargs)
elif model is not None:
_handler = self._model_cls_to_handler[model.__class__]
_handler(self, model).dump(out_stream=out_stream, **kwargs)
return out_stream
def dump_graph(self, service):
out_stream = console.TopologyStylizer()
for node in service.nodes.itervalues():
if not node.inbound_relationships:
self._dump_graph_node(out_stream, node)
return out_stream
def _dump_graph_node(self, out_stream, node, capability=None):
out_stream.write(out_stream.node_style(node.name))
if capability is not None:
out_stream.write(u'{0} ({1})'.format(out_stream.property_style(capability.name),
out_stream.type_style(capability.type.name)))
if node.outbound_relationships:
with out_stream.indent():
for relationship_model in node.outbound_relationships:
styled_relationship_name = out_stream.property_style(relationship_model.name)
if relationship_model.type is not None:
out_stream.write(u'-> {0} ({1})'.format(
styled_relationship_name,
out_stream.type_style(relationship_model.type.name)))
else:
out_stream.write(u'-> {0}'.format(styled_relationship_name))
with out_stream.indent(3):
self._dump_graph_node(out_stream,
relationship_model.target_node,
relationship_model.target_capability)
def coerce(self, model, **kwargs):
if isinstance(model, dict):
return self.coerce(model.values(), **kwargs)
elif isinstance(model, list):
return all(self.coerce(value, **kwargs) for value in model)
elif model is not None:
_handler = self._model_cls_to_handler[model.__class__]
return _handler(self, model).coerce(**kwargs)
def dump_types(self, service_template, out_stream=None):
out_stream = out_stream or console.TopologyStylizer()
self.dump(service_template.node_types, out_stream, 'Node types')
self.dump(service_template.group_types, out_stream, 'Group types')
self.dump(service_template.capability_types, out_stream, 'Capability types')
self.dump(service_template.relationship_types, out_stream, 'Relationship types')
self.dump(service_template.policy_types, out_stream, 'Policy types')
self.dump(service_template.artifact_types, out_stream, 'Artifact types')
self.dump(service_template.interface_types, out_stream, 'Interface types')
return out_stream
def satisfy_requirements(self, model, **kwargs):
if isinstance(model, dict):
return self.satisfy_requirements(model.values(), **kwargs)
elif isinstance(model, list):
return all(self.satisfy_requirements(value, **kwargs) for value in model)
elif model is not None:
_handler = self._model_cls_to_handler[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(), **kwargs)
elif isinstance(model, list):
return all(self.validate_capabilities(value, **kwargs) for value in model)
elif model is not None:
_handler = self._model_cls_to_handler[model.__class__]
return _handler(self, model).validate_capabilities(**kwargs)
def _find_host(self, node):
if node.type.role == 'host':
return node
def target_has_role(rel, role):
return (rel.target_capability is not None and
rel.target_capability.type.role == role)
for outbound_relationship in node.outbound_relationships:
if target_has_role(outbound_relationship, 'host'):
host = self._find_host(outbound_relationship.target_node)
if host is not None:
return host
for inbound_relationship in node.inbound_relationships:
if target_has_role(inbound_relationship, 'feature'):
host = self._find_host(inbound_relationship.source_node)
if host is not None:
return host
return None
def assign_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(), **kwargs)
elif isinstance(model, list):
return all(self.configure_operations(value, **kwargs) for value in model)
elif model is not None:
_handler = self._model_cls_to_handler[model.__class__]
return _handler(self, model).configure_operations(**kwargs)