1 # Licensed to the Apache Software Foundation (ASF) under one or more
2 # contributor license agreements. See the NOTICE file distributed with
3 # this work for additional information regarding copyright ownership.
4 # The ASF licenses this file to You under the Apache License, Version 2.0
5 # (the "License"); you may not use this file except in compliance with
6 # the License. You may obtain a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
16 from ...parser.validation import issue
17 from ...modeling import models
18 from ...utils import console
26 class Topology(issue.ReporterMixin):
29 models.ServiceTemplate: models.Service,
30 models.ArtifactTemplate: models.Artifact,
31 models.CapabilityTemplate: models.Capability,
32 models.GroupTemplate: models.Group,
33 models.InterfaceTemplate: models.Interface,
34 models.NodeTemplate: models.Node,
35 models.PolicyTemplate: models.Policy,
36 models.SubstitutionTemplate: models.Substitution,
37 models.RelationshipTemplate: models.Relationship,
38 models.OperationTemplate: models.Operation,
39 models.SubstitutionTemplateMapping: models.SubstitutionMapping,
42 models.Metadata: models.Metadata,
43 models.Attribute: models.Attribute,
44 models.Property: models.Property,
45 models.Input: models.Input,
46 models.Output: models.Output,
47 models.Configuration: models.Configuration,
48 models.Argument: models.Argument,
49 models.Type: models.Type
52 def __init__(self, *args, **kwargs):
53 super(Topology, self).__init__(*args, **kwargs)
54 self._model_cls_to_handler = dict(self._init_handlers(instance_handler),
55 **self._init_handlers(template_handler))
58 def _init_handlers(module_):
60 Register handlers from a handler module to the models.
62 :param module_: the module to look for handlers
63 :returns: dict where the key is the models class, and the value is the handler class
64 associated with it from the provided module
67 for attribute_name in dir(module_):
68 if attribute_name.startswith('_'):
70 attribute = getattr(module_, attribute_name)
71 if isinstance(attribute, type) and issubclass(attribute, common.HandlerBase):
72 handlers[getattr(models, attribute_name)] = attribute
75 def instantiate(self, model, **kwargs):
77 Instantiate the provided model.
83 if isinstance(model, dict):
84 return dict((name, self.instantiate(value, **kwargs))
85 for name, value in model.iteritems())
86 elif isinstance(model, list):
87 return list(self.instantiate(value, **kwargs) for value in model)
88 elif model is not None:
89 _handler = self._model_cls_to_handler[model.__class__]
90 model_instance_cls = self._init_map[model.__class__]
91 return _handler(self, model).instantiate(model_instance_cls, **kwargs)
93 def validate(self, model, **kwargs):
94 if isinstance(model, dict):
95 return self.validate(model.values(), **kwargs)
96 elif isinstance(model, list):
97 return all(self.validate(value, **kwargs) for value in model)
98 elif model is not None:
99 _handler = self._model_cls_to_handler[model.__class__]
100 return _handler(self, model).validate(**kwargs)
102 def dump(self, model, out_stream=None, title=None, **kwargs):
103 out_stream = out_stream or console.TopologyStylizer()
105 # if model is empty, no need to print out the section name
107 out_stream.write('{0}:'.format(title))
109 if isinstance(model, dict):
111 with out_stream.indent():
112 return self.dump(model.values(), out_stream=out_stream, **kwargs)
114 return self.dump(model.values(), out_stream=out_stream, **kwargs)
116 elif isinstance(model, list):
118 self.dump(value, out_stream=out_stream, **kwargs)
120 elif model is not None:
121 _handler = self._model_cls_to_handler[model.__class__]
122 _handler(self, model).dump(out_stream=out_stream, **kwargs)
126 def dump_graph(self, service):
127 out_stream = console.TopologyStylizer()
128 for node in service.nodes.itervalues():
129 if not node.inbound_relationships:
130 self._dump_graph_node(out_stream, node)
133 def _dump_graph_node(self, out_stream, node, capability=None):
134 out_stream.write(out_stream.node_style(node.name))
135 if capability is not None:
136 out_stream.write('{0} ({1})'.format(out_stream.property_style(capability.name),
137 out_stream.type_style(capability.type.name)))
138 if node.outbound_relationships:
139 with out_stream.indent():
140 for relationship_model in node.outbound_relationships:
141 styled_relationship_name = out_stream.property_style(relationship_model.name)
142 if relationship_model.type is not None:
143 out_stream.write('-> {0} ({1})'.format(
144 styled_relationship_name,
145 out_stream.type_style(relationship_model.type.name)))
147 out_stream.write('-> {0}'.format(styled_relationship_name))
148 with out_stream.indent(3):
149 self._dump_graph_node(out_stream,
150 relationship_model.target_node,
151 relationship_model.target_capability)
153 def coerce(self, model, **kwargs):
154 if isinstance(model, dict):
155 return self.coerce(model.values(), **kwargs)
156 elif isinstance(model, list):
157 return all(self.coerce(value, **kwargs) for value in model)
158 elif model is not None:
159 _handler = self._model_cls_to_handler[model.__class__]
160 return _handler(self, model).coerce(**kwargs)
162 def dump_types(self, service_template, out_stream=None):
163 out_stream = out_stream or console.TopologyStylizer()
164 self.dump(service_template.node_types, out_stream, 'Node types')
165 self.dump(service_template.group_types, out_stream, 'Group types')
166 self.dump(service_template.capability_types, out_stream, 'Capability types')
167 self.dump(service_template.relationship_types, out_stream, 'Relationship types')
168 self.dump(service_template.policy_types, out_stream, 'Policy types')
169 self.dump(service_template.artifact_types, out_stream, 'Artifact types')
170 self.dump(service_template.interface_types, out_stream, 'Interface types')
174 def satisfy_requirements(self, model, **kwargs):
175 if isinstance(model, dict):
176 return self.satisfy_requirements(model.values(), **kwargs)
177 elif isinstance(model, list):
178 return all(self.satisfy_requirements(value, **kwargs) for value in model)
179 elif model is not None:
180 _handler = self._model_cls_to_handler[model.__class__]
181 return _handler(self, model).satisfy_requirements(**kwargs)
183 def validate_capabilities(self, model, **kwargs):
184 if isinstance(model, dict):
185 return self.validate_capabilities(model.values(), **kwargs)
186 elif isinstance(model, list):
187 return all(self.validate_capabilities(value, **kwargs) for value in model)
188 elif model is not None:
189 _handler = self._model_cls_to_handler[model.__class__]
190 return _handler(self, model).validate_capabilities(**kwargs)
192 def _find_host(self, node):
193 if node.type.role == 'host':
196 def target_has_role(rel, role):
197 return (rel.target_capability is not None and
198 rel.target_capability.type.role == role)
200 for outbound_relationship in node.outbound_relationships:
201 if target_has_role(outbound_relationship, 'host'):
202 host = self._find_host(outbound_relationship.target_node)
205 for inbound_relationship in node.inbound_relationships:
206 if target_has_role(inbound_relationship, 'feature'):
207 host = self._find_host(inbound_relationship.source_node)
212 def assign_hosts(self, service):
213 for node in service.nodes.values():
214 node.host = self._find_host(node)
216 def configure_operations(self, model, **kwargs):
217 if isinstance(model, dict):
218 return self.configure_operations(model.values(), **kwargs)
219 elif isinstance(model, list):
220 return all(self.configure_operations(value, **kwargs) for value in model)
221 elif model is not None:
222 _handler = self._model_cls_to_handler[model.__class__]
223 return _handler(self, model).configure_operations(**kwargs)