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 datetime import datetime
18 from ...utils import (
22 from ...modeling import utils as modeling_utils
23 from . import utils, common
26 class ServiceTemplate(common.TemplateHandlerBase):
27 def dump(self, out_stream):
28 if self._model.description is not None:
29 out_stream.write(out_stream.meta_style(self._model.description))
30 self._topology.dump(self._model.meta_data, out_stream, title='Metadata')
31 self._topology.dump(self._model.node_templates, out_stream)
32 self._topology.dump(self._model.group_templates, out_stream)
33 self._topology.dump(self._model.policy_templates, out_stream)
34 self._topology.dump(self._model.substitution_template, out_stream)
35 self._topology.dump(self._model.inputs, out_stream, title='Inputs')
36 self._topology.dump(self._model.outputs, out_stream, title='Outputs')
37 self._topology.dump(self._model.workflow_templates, out_stream, title='Workflow templates')
39 def coerce(self, **kwargs):
40 self._coerce(self._model.meta_data,
41 self._model.node_templates,
42 self._model.group_templates,
43 self._model.policy_templates,
44 self._model.substitution_template,
47 self._model.workflow_templates,
50 def instantiate(self, instance_cls, inputs=None, plugins=None): # pylint: disable=arguments-differ
53 # modeling_utils.validate_no_undeclared_inputs(
54 # declared_inputs=self._model.inputs, supplied_inputs=inputs or {})
55 modeling_utils.validate_required_inputs_are_supplied(
56 declared_inputs=self._model.inputs, supplied_inputs=inputs or {})
58 service = instance_cls(
61 description=utils.deepcopy_with_locators(self._model.description),
62 service_template=self._model,
63 inputs=modeling_utils.merge_parameter_values(inputs, self._model.inputs)
66 for plugin_specification in self._model.plugin_specifications.itervalues():
67 if plugin_specification.enabled and plugins:
68 if self._resolve_plugin_specification(plugin_specification, plugins):
69 plugin = plugin_specification.plugin
70 service.plugins[plugin.name] = plugin
72 self._topology.report('specified plugin not found: {0}'.format(
73 plugin_specification.name), level=self._topology.Issue.EXTERNAL)
74 service.meta_data = self._topology.instantiate(self._model.meta_data)
76 for node_template in self._model.node_templates.itervalues():
77 for _ in range(self._scaling(node_template)['default_instances']):
78 node = self._topology.instantiate(node_template)
79 service.nodes[node.name] = node
81 service.groups = self._topology.instantiate(self._model.group_templates)
82 service.policies = self._topology.instantiate(self._model.policy_templates)
83 service.workflows = self._topology.instantiate(self._model.workflow_templates)
84 service.substitution = self._topology.instantiate(self._model.substitution_template)
85 service.outputs = self._topology.instantiate(self._model.outputs)
90 def _resolve_plugin_specification(plugin_specification, plugins):
93 for plugin in plugins:
94 if (plugin.name == plugin_specification.name and
95 (plugin_specification.version is None or
96 versions.VersionString(plugin.package_version) >=
97 plugin_specification.version)
99 matching_plugins.append(plugin)
100 plugin_specification.plugin = None
102 # Return highest version of plugin
103 plugin_specification.plugin = \
104 max(matching_plugins,
105 key=lambda plugin: versions.VersionString(plugin.package_version).key)
106 return plugin_specification.plugin is not None
108 def _scaling(self, node_template):
109 scaling = node_template.scaling
111 if any([scaling['min_instances'] < 0,
112 scaling['max_instances'] < scaling['min_instances'],
113 scaling['max_instances'] < 0,
115 scaling['default_instances'] < 0,
116 scaling['default_instances'] < scaling['min_instances'],
117 scaling['default_instances'] > scaling['max_instances']
119 self._topology.report(
120 'invalid scaling parameters for node template "{0}": min={min_instances}, max='
121 '{max_instances}, default={default_instances}'.format(self._model.name, **scaling),
122 level=self._topology.Issue.BETWEEN_TYPES)
126 def validate(self, **kwargs):
128 self._model.meta_data,
129 self._model.node_templates,
130 self._model.group_templates,
131 self._model.policy_templates,
132 self._model.substitution_template,
135 self._model.workflow_templates,
136 self._model.node_types,
137 self._model.group_types,
138 self._model.policy_types,
139 self._model.relationship_types,
140 self._model.capability_types,
141 self._model.interface_types,
142 self._model.artifact_types,
147 class ArtifactTemplate(common.TemplateHandlerBase):
148 def dump(self, out_stream):
149 out_stream.write(out_stream.node_style(self._model.name))
150 if self._model.description:
151 out_stream.write(out_stream.meta_style(self._model.description))
152 with out_stream.indent():
153 out_stream.write('Artifact type: {0}'.format(out_stream.type_style(
154 self._model.type.name)))
155 out_stream.write('Source path: {0}'.format(out_stream.literal_style(
156 self._model.source_path)))
157 if self._model.target_path is not None:
158 out_stream.write('Target path: {0}'.format(out_stream.literal_style(
159 self._model.target_path)))
160 if self._model.repository_url is not None:
161 out_stream.write('Repository URL: {0}'.format(
162 out_stream.literal_style(self._model.repository_url)))
163 if self._model.repository_credential:
164 out_stream.write('Repository credential: {0}'.format(
165 out_stream.literal_style(self._model.repository_credential)))
166 self._topology.dump(self._model.properties, out_stream, title='Properties')
168 def coerce(self, **kwargs):
169 self._topology.coerce(self._model.properties, **kwargs)
171 def instantiate(self, instance_cls, **_):
173 name=self._model.name,
174 type=self._model.type,
175 description=utils.deepcopy_with_locators(self._model.description),
176 source_path=self._model.source_path,
177 target_path=self._model.target_path,
178 repository_url=self._model.repository_url,
179 repository_credential=self._model.repository_credential,
180 artifact_template=self._model)
182 def validate(self, **kwargs):
183 self._topology.validate(self._model.properties, **kwargs)
186 class CapabilityTemplate(common.TemplateHandlerBase):
187 def dump(self, out_stream):
188 out_stream.write(out_stream.node_style(self._model.name))
189 if self._model.description:
190 out_stream.write(out_stream.meta_style(self._model.description))
191 with out_stream.indent():
192 out_stream.write('Type: {0}'.format(out_stream.type_style(self._model.type.name)))
194 'Occurrences: {0:d}{1}'.format(
195 self._model.min_occurrences or 0,
196 ' to {0:d}'.format(self._model.max_occurrences)
197 if self._model.max_occurrences is not None
199 if self._model.valid_source_node_types:
200 out_stream.write('Valid source node types: {0}'.format(
201 ', '.join((str(out_stream.type_style(v.name))
202 for v in self._model.valid_source_node_types))))
203 self._topology.dump(self._model.properties, out_stream, title='Properties')
205 def coerce(self, **kwargs):
206 self._topology.coerce(self._model.properties, **kwargs)
208 def instantiate(self, instance_cls, **_):
209 capability = instance_cls(
210 name=self._model.name,
211 type=self._model.type,
212 min_occurrences=self._model.min_occurrences,
213 max_occurrences=self._model.max_occurrences,
215 capability_template=self._model)
216 capability.properties = self._topology.instantiate(self._model.properties)
219 def validate(self, **kwargs):
220 self._topology.validate(self._model.properties, **kwargs)
223 class RequirementTemplate(common.TemplateHandlerBase):
224 def dump(self, out_stream):
226 out_stream.write(out_stream.node_style(self._model.name))
228 out_stream.write('Requirement:')
229 with out_stream.indent():
230 if self._model.target_node_type is not None:
231 out_stream.write('Target node type: {0}'.format(
232 out_stream.type_style(self._model.target_node_type.name)))
233 elif self._model.target_node_template is not None:
234 out_stream.write('Target node template: {0}'.format(
235 out_stream.node_style(self._model.target_node_template.name)))
236 if self._model.target_capability_type is not None:
237 out_stream.write('Target capability type: {0}'.format(
238 out_stream.type_style(self._model.target_capability_type.name)))
239 elif self._model.target_capability_name is not None:
240 out_stream.write('Target capability name: {0}'.format(
241 out_stream.node_style(self._model.target_capability_name)))
242 if self._model.target_node_template_constraints:
243 out_stream.write('Target node template constraints:')
244 with out_stream.indent():
245 for constraint in self._model.target_node_template_constraints:
246 out_stream.write(out_stream.literal_style(constraint))
247 if self._model.relationship_template:
248 out_stream.write('Relationship:')
249 with out_stream.indent():
250 self._topology.dump(self._model.relationship_template, out_stream)
252 def coerce(self, **kwargs):
253 self._topology.coerce(self._model.relationship_template, **kwargs)
255 def instantiate(self, instance_cls, **_):
258 def validate(self, **kwargs):
259 self._topology.validate(self._model.relationship_template, **kwargs)
262 class GroupTemplate(common.TemplateHandlerBase):
263 def dump(self, out_stream):
264 out_stream.write('Group template: {0}'.format(out_stream.node_style(self._model.name)))
265 if self._model.description:
266 out_stream.write(out_stream.meta_style(self._model.description))
267 with out_stream.indent():
268 out_stream.write('Type: {0}'.format(out_stream.type_style(self._model.type.name)))
269 self._topology.dump(self._model.properties, out_stream, title='Properties')
270 self._topology.dump(self._model.interface_templates, out_stream,
271 title='Interface Templates')
272 if self._model.node_templates:
273 out_stream.write('Member node templates: {0}'.format(', '.join(
274 (str(out_stream.node_style(v.name)) for v in self._model.node_templates))))
276 def coerce(self, **kwargs):
277 self._coerce(self._model.properties,
278 self._model.interface_templates,
281 def instantiate(self, instance_cls, **_):
282 group = instance_cls(
283 name=self._model.name,
284 type=self._model.type,
285 description=utils.deepcopy_with_locators(self._model.description),
286 group_template=self._model)
287 group.properties = self._topology.instantiate(self._model.properties)
288 group.interfaces = self._topology.instantiate(self._model.interface_templates)
289 if self._model.node_templates:
290 for node_template in self._model.node_templates:
291 group.nodes += node_template.nodes
294 def validate(self, **kwargs):
295 self._validate(self._model.properties,
296 self._model.interface_templates,
300 class InterfaceTemplate(common.TemplateHandlerBase):
301 def dump(self, out_stream):
302 out_stream.write(out_stream.node_style(self._model.name))
303 if self._model.description:
304 out_stream.write(out_stream.meta_style(self._model.description))
305 with out_stream.indent():
306 out_stream.write('Interface type: {0}'.format(out_stream.type_style(
307 self._model.type.name)))
308 self._topology.dump(self._model.inputs, out_stream, title='Inputs')
309 self._topology.dump(self._model.operation_templates, out_stream,
310 title='Operation templates')
312 def coerce(self, **kwargs):
313 self._coerce(self._model.inputs,
314 self._model.operation_templates,
317 def instantiate(self, instance_cls, **_):
318 interface = instance_cls(
319 name=self._model.name,
320 type=self._model.type,
321 description=utils.deepcopy_with_locators(self._model.description),
322 interface_template=self._model)
323 interface.inputs = self._topology.instantiate(self._model.inputs)
324 interface.operations = self._topology.instantiate(self._model.operation_templates)
327 def validate(self, **kwargs):
328 self._validate(self._model.inputs,
329 self._model.operation_templates,
333 class NodeTemplate(common.TemplateHandlerBase):
334 def dump(self, out_stream):
335 out_stream.write('Node template: {0}'.format(out_stream.node_style(self._model.name)))
336 with out_stream.indent():
337 if self._model.description:
338 out_stream.write(out_stream.meta_style(self._model.description))
339 out_stream.write('Type: {0}'.format(out_stream.type_style(self._model.type.name)))
340 self._topology.dump(self._model.properties, out_stream, title='Properties')
341 self._topology.dump(self._model.attributes, out_stream, title='Attributes')
343 self._model.interface_templates, out_stream, title='Interface Templates')
345 self._model.artifact_templates, out_stream, title='Artifact Templates')
347 self._model.capability_templates, out_stream, title='Capability Templates')
349 self._model.requirement_templates, out_stream, title='Requirement Templates')
351 def coerce(self, **kwargs):
352 self._coerce(self._model.properties,
353 self._model.attributes,
354 self._model.interface_templates,
355 self._model.artifact_templates,
356 self._model.capability_templates,
357 self._model.requirement_templates,
360 def instantiate(self, instance_cls, **_):
362 name=self._model._next_name,
363 type=self._model.type,
364 description=utils.deepcopy_with_locators(self._model.description),
365 node_template=self._model
368 node.properties = self._topology.instantiate(self._model.properties)
369 node.attributes = self._topology.instantiate(self._model.attributes)
370 node.interfaces = self._topology.instantiate(self._model.interface_templates)
371 node.artifacts = self._topology.instantiate(self._model.artifact_templates)
372 node.capabilities = self._topology.instantiate(self._model.capability_templates)
375 if 'tosca_name' in node.attributes and node.attributes['tosca_name'].type_name == 'string':
376 node.attributes['tosca_name'].value = self._model.name
377 if 'tosca_id' in node.attributes and node.attributes['tosca_id'].type_name == 'string':
378 node.attributes['tosca_id'].value = node.name
382 def validate(self, **kwargs):
383 self._validate(self._model.properties,
384 self._model.attributes,
385 self._model.interface_templates,
386 self._model.artifact_templates,
387 self._model.capability_templates,
388 self._model.requirement_templates,
392 class PolicyTemplate(common.TemplateHandlerBase):
393 def dump(self, out_stream):
394 out_stream.write('Policy template: {0}'.format(out_stream.node_style(self._model.name)))
395 if self._model.description:
396 out_stream.write(out_stream.meta_style(self._model.description))
397 with out_stream.indent():
398 out_stream.write('Type: {0}'.format(out_stream.type_style(self._model.type.name)))
399 self._topology.dump(self._model.properties, out_stream, title='Properties')
400 if self._model.node_templates:
401 out_stream.write('Target node templates: {0}'.format(', '.join(
402 (str(out_stream.node_style(v.name)) for v in self._model.node_templates))))
403 if self._model.group_templates:
404 out_stream.write('Target group templates: {0}'.format(', '.join(
405 (str(out_stream.node_style(v.name)) for v in self._model.group_templates))))
407 def coerce(self, **kwargs):
408 self._topology.coerce(self._model.properties, **kwargs)
410 def instantiate(self, instance_cls, **_):
411 policy = instance_cls(
412 name=self._model.name,
413 type=self._model.type,
414 description=utils.deepcopy_with_locators(self._model.description),
415 policy_template=self._model)
417 policy.properties = self._topology.instantiate(self._model.properties)
418 if self._model.node_templates:
419 for node_template in self._model.node_templates:
420 policy.nodes += node_template.nodes
421 if self._model.group_templates:
422 for group_template in self._model.group_templates:
423 policy.groups += group_template.groups
426 def validate(self, **kwargs):
427 self._topology.validate(self._model.properties, **kwargs)
430 class SubstitutionTemplate(common.TemplateHandlerBase):
432 def dump(self, out_stream):
433 out_stream.write('Substitution template:')
434 with out_stream.indent():
435 out_stream.write('Node type: {0}'.format(out_stream.type_style(
436 self._model.node_type.name)))
437 self._topology.dump(self._model.mappings, out_stream, title='Mappings')
439 def coerce(self, **kwargs):
440 self._topology.coerce(self._model.mappings, **kwargs)
442 def instantiate(self, instance_cls, **_):
443 return instance_cls(node_type=self._model.node_type, substitution_template=self._model)
445 def validate(self, **kwargs):
446 self._topology.validate(self._model.mappings, **kwargs)
449 class SubstitutionTemplateMapping(common.TemplateHandlerBase):
451 def dump(self, out_stream):
452 if self._model.capability_template is not None:
453 node_template = self._model.capability_template.node_template
455 node_template = self._model.requirement_template.node_template
456 out_stream.write('{0} -> {1}.{2}'.format(
457 out_stream.node_style(self._model.name),
458 out_stream.node_style(node_template.name),
459 out_stream.node_style(self._model.capability_template.name
460 if self._model.capability_template
461 else self._model.requirement_template.name)))
463 def coerce(self, **_):
466 def instantiate(self, instance_cls, **_):
467 substitution_mapping = instance_cls(
468 name=self._model.name,
469 requirement_template=self._model.requirement_template)
471 if self._model.capability_template is not None:
472 node_template = self._model.capability_template.node_template
474 node_template = self._model.requirement_template.node_template
475 nodes = node_template.nodes
477 self._topology.report(
478 'mapping "{0}" refers to node template "{1}" but there are no node instances'.
479 format(self._model.mapped_name, self._model.node_template.name),
480 level=self._topology.Issue.BETWEEN_INSTANCES)
482 # The TOSCA spec does not provide a way to choose the node,
483 # so we will just pick the first one
484 substitution_mapping.node_style = nodes[0]
485 if self._model.capability_template:
486 for a_capability in substitution_mapping.node_style.capabilities.itervalues():
487 if a_capability.capability_template.name == \
488 self._model.capability_template.name:
489 substitution_mapping.capability = a_capability
491 return substitution_mapping
493 def validate(self, **_):
494 if self._model.capability_template is None and self._model.requirement_template is None:
495 self._topology.report(
496 'mapping "{0}" refers to neither capability nor a requirement '
497 'in node template: {1}'.format(
498 self._model.name, formatting.safe_repr(self._model.node_template.name)),
499 level=self._topology.Issue.BETWEEN_TYPES)
502 class RelationshipTemplate(common.TemplateHandlerBase):
503 def dump(self, out_stream):
504 if self._model.type is not None:
505 out_stream.write('Relationship type: {0}'.format(out_stream.type_style(
506 self._model.type.name)))
508 out_stream.write('Relationship template: {0}'.format(
509 out_stream.node_style(self._model.name)))
510 if self._model.description:
511 out_stream.write(out_stream.meta_style(self._model.description))
512 with out_stream.indent():
513 self._topology.dump(self._model.properties, out_stream, title='Properties')
514 self._topology.dump(self._model.interface_templates, out_stream,
515 title='Interface Templates')
517 def coerce(self, **kwargs):
518 self._coerce(self._model.properties, self._model.interface_templates, **kwargs)
520 def instantiate(self, instance_cls, **_):
521 relationship = instance_cls(
522 name=self._model.name,
523 type=self._model.type,
524 relationship_template=self._model)
526 relationship.properties = self._topology.instantiate(self._model.properties)
527 relationship.interfaces = self._topology.instantiate(self._model.interface_templates)
530 def validate(self, **kwargs):
531 self._validate(self._model.properties, self._model.interface_templates, **kwargs)
534 class OperationTemplate(common.TemplateHandlerBase):
536 def dump(self, out_stream):
537 out_stream.write(out_stream.node_style(self._model.name))
538 if self._model.description:
539 out_stream.write(out_stream.meta_style(self._model.description))
540 with out_stream.indent():
541 if self._model.implementation is not None:
542 out_stream.write('Implementation: {0}'.format(
543 out_stream.literal_style(self._model.implementation)))
544 if self._model.dependencies:
545 out_stream.write('Dependencies: {0}'.format(', '.join(
546 (str(out_stream.literal_style(v)) for v in self._model.dependencies))))
547 self._topology.dump(self._model.inputs, out_stream, title='Inputs')
548 if self._model.executor is not None:
549 out_stream.write('Executor: {0}'.format(
550 out_stream.literal_style(self._model.executor)))
551 if self._model.max_attempts is not None:
552 out_stream.write('Max attempts: {0}'.format(out_stream.literal_style(
553 self._model.max_attempts)))
554 if self._model.retry_interval is not None:
555 out_stream.write('Retry interval: {0}'.format(
556 out_stream.literal_style(self._model.retry_interval)))
557 if self._model.plugin_specification is not None:
558 out_stream.write('Plugin specification: {0}'.format(
559 out_stream.literal_style(self._model.plugin_specification.name)))
560 self._topology.dump(self._model.configurations, out_stream, title='Configuration')
561 if self._model.function is not None:
562 out_stream.write('Function: {0}'.format(out_stream.literal_style(
563 self._model.function)))
565 def coerce(self, **kwargs):
566 self._coerce(self._model.inputs,
567 self._model.configurations,
570 def instantiate(self, instance_cls, **_):
571 operation = instance_cls(
572 name=self._model.name,
573 description=utils.deepcopy_with_locators(self._model.description),
574 relationship_edge=self._model.relationship_edge,
575 implementation=self._model.implementation,
576 dependencies=self._model.dependencies,
577 executor=self._model.executor,
578 function=self._model.function,
579 max_attempts=self._model.max_attempts,
580 retry_interval=self._model.retry_interval,
581 operation_template=self._model)
583 if (self._model.plugin_specification is not None and
584 self._model.plugin_specification.enabled):
585 operation.plugin = self._model.plugin_specification.plugin
587 operation.inputs = self._topology.instantiate(self._model.inputs)
588 operation.configurations = self._topology.instantiate(self._model.configurations)
592 def validate(self, **kwargs):
593 self._validate(self._model.inputs,
594 self._model.configurations,
598 class PluginSpecification(common.HandlerBase):
599 def validate(self, **kwargs):
602 def coerce(self, **kwargs):
605 def instantiate(self, **_):
608 def dump(self, out_stream):