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.
17 ARIA modeling service template module
20 # pylint: disable=too-many-lines, no-self-argument, no-member, abstract-method
22 from __future__ import absolute_import # so we can import standard 'types'
24 from sqlalchemy import (
32 from sqlalchemy.ext.declarative import declared_attr
34 from ..utils import (collections, formatting)
35 from .mixins import TemplateModelMixin
38 types as modeling_types
42 class ServiceTemplateBase(TemplateModelMixin):
44 Template for creating :class:`Service` instances.
46 Usually created by various DSL parsers, such as ARIA's TOSCA extension. However, it can also be
47 created programmatically.
50 __tablename__ = 'service_template'
52 __private_fields__ = ('substitution_template_fk',
56 'relationship_type_fk',
61 # region one_to_one relationships
64 def substitution_template(cls):
66 Exposes an entire service as a single node.
68 :type: :class:`SubstitutionTemplate`
70 return relationship.one_to_one(
71 cls, 'substitution_template', back_populates=relationship.NO_BACK_POP)
76 Base for the node type hierarchy,
80 return relationship.one_to_one(
81 cls, 'type', fk='node_type_fk', back_populates=relationship.NO_BACK_POP)
86 Base for the group type hierarchy,
90 return relationship.one_to_one(
91 cls, 'type', fk='group_type_fk', back_populates=relationship.NO_BACK_POP)
94 def policy_types(cls):
96 Base for the policy type hierarchy,
100 return relationship.one_to_one(
101 cls, 'type', fk='policy_type_fk', back_populates=relationship.NO_BACK_POP)
104 def relationship_types(cls):
106 Base for the relationship type hierarchy,
110 return relationship.one_to_one(
111 cls, 'type', fk='relationship_type_fk', back_populates=relationship.NO_BACK_POP)
114 def capability_types(cls):
116 Base for the capability type hierarchy,
120 return relationship.one_to_one(
121 cls, 'type', fk='capability_type_fk', back_populates=relationship.NO_BACK_POP)
124 def interface_types(cls):
126 Base for the interface type hierarchy,
130 return relationship.one_to_one(
131 cls, 'type', fk='interface_type_fk', back_populates=relationship.NO_BACK_POP)
134 def artifact_types(cls):
136 Base for the artifact type hierarchy,
140 return relationship.one_to_one(
141 cls, 'type', fk='artifact_type_fk', back_populates=relationship.NO_BACK_POP)
145 # region one_to_many relationships
150 Instantiated services.
152 :type: [:class:`Service`]
154 return relationship.one_to_many(cls, 'service', dict_key='name')
157 def node_templates(cls):
159 Templates for creating nodes.
161 :type: {:obj:`basestring`, :class:`NodeTemplate`}
163 return relationship.one_to_many(cls, 'node_template', dict_key='name')
166 def group_templates(cls):
168 Templates for creating groups.
170 :type: {:obj:`basestring`, :class:`GroupTemplate`}
172 return relationship.one_to_many(cls, 'group_template', dict_key='name')
175 def policy_templates(cls):
177 Templates for creating policies.
179 :type: {:obj:`basestring`, :class:`PolicyTemplate`}
181 return relationship.one_to_many(cls, 'policy_template', dict_key='name')
184 def workflow_templates(cls):
186 Templates for creating workflows.
188 :type: {:obj:`basestring`, :class:`OperationTemplate`}
190 return relationship.one_to_many(cls, 'operation_template', dict_key='name')
195 Declarations for output parameters are filled in after service installation.
197 :type: {:obj:`basestring`: :class:`Output`}
199 return relationship.one_to_many(cls, 'output', dict_key='name')
204 Declarations for externally provided parameters.
206 :type: {:obj:`basestring`: :class:`Input`}
208 return relationship.one_to_many(cls, 'input', dict_key='name')
211 def plugin_specifications(cls):
213 Required plugins for instantiated services.
215 :type: {:obj:`basestring`: :class:`PluginSpecification`}
217 return relationship.one_to_many(cls, 'plugin_specification', dict_key='name')
221 # region many_to_many relationships
228 :type: {:obj:`basestring`: :class:`Metadata`}
230 # Warning! We cannot use the attr name "metadata" because it's used by SQLAlchemy!
231 return relationship.many_to_many(cls, 'metadata', dict_key='name')
235 # region foreign keys
238 def substitution_template_fk(cls):
239 """For ServiceTemplate one-to-one to SubstitutionTemplate"""
240 return relationship.foreign_key('substitution_template', nullable=True)
243 def node_type_fk(cls):
244 """For ServiceTemplate one-to-one to Type"""
245 return relationship.foreign_key('type', nullable=True)
248 def group_type_fk(cls):
249 """For ServiceTemplate one-to-one to Type"""
250 return relationship.foreign_key('type', nullable=True)
253 def policy_type_fk(cls):
254 """For ServiceTemplate one-to-one to Type"""
255 return relationship.foreign_key('type', nullable=True)
258 def relationship_type_fk(cls):
259 """For ServiceTemplate one-to-one to Type"""
260 return relationship.foreign_key('type', nullable=True)
263 def capability_type_fk(cls):
264 """For ServiceTemplate one-to-one to Type"""
265 return relationship.foreign_key('type', nullable=True)
268 def interface_type_fk(cls):
269 """For ServiceTemplate one-to-one to Type"""
270 return relationship.foreign_key('type', nullable=True)
273 def artifact_type_fk(cls):
274 """For ServiceTemplate one-to-one to Type"""
275 return relationship.foreign_key('type', nullable=True)
279 description = Column(Text, doc="""
280 Human-readable description.
282 :type: :obj:`basestring`
285 main_file_name = Column(Text, doc="""
286 Filename of CSAR or YAML file from which this service template was parsed.
288 :type: :obj:`basestring`
291 created_at = Column(DateTime, nullable=False, index=True, doc="""
294 :type: :class:`~datetime.datetime`
297 updated_at = Column(DateTime, doc="""
300 :type: :class:`~datetime.datetime`
305 return collections.OrderedDict((
306 ('description', self.description),
307 ('metadata', formatting.as_raw_dict(self.meta_data)),
308 ('node_templates', formatting.as_raw_list(self.node_templates)),
309 ('group_templates', formatting.as_raw_list(self.group_templates)),
310 ('policy_templates', formatting.as_raw_list(self.policy_templates)),
311 ('substitution_template', formatting.as_raw(self.substitution_template)),
312 ('inputs', formatting.as_raw_dict(self.inputs)),
313 ('outputs', formatting.as_raw_dict(self.outputs)),
314 ('workflow_templates', formatting.as_raw_list(self.workflow_templates))))
317 def types_as_raw(self):
318 return collections.OrderedDict((
319 ('node_types', formatting.as_raw(self.node_types)),
320 ('group_types', formatting.as_raw(self.group_types)),
321 ('policy_types', formatting.as_raw(self.policy_types)),
322 ('relationship_types', formatting.as_raw(self.relationship_types)),
323 ('capability_types', formatting.as_raw(self.capability_types)),
324 ('interface_types', formatting.as_raw(self.interface_types)),
325 ('artifact_types', formatting.as_raw(self.artifact_types))))
328 class NodeTemplateBase(TemplateModelMixin):
330 Template for creating zero or more :class:`Node` instances, which are typed vertices in the
334 __tablename__ = 'node_template'
336 __private_fields__ = ('type_fk',
337 'service_template_fk')
339 # region one_to_many relationships
346 :type: [:class:`Node`]
348 return relationship.one_to_many(cls, 'node')
351 def interface_templates(cls):
353 Associated interface templates.
355 :type: {:obj:`basestring`: :class:`InterfaceTemplate`}
357 return relationship.one_to_many(cls, 'interface_template', dict_key='name')
360 def artifact_templates(cls):
362 Associated artifacts.
364 :type: {:obj:`basestring`: :class:`ArtifactTemplate`}
366 return relationship.one_to_many(cls, 'artifact_template', dict_key='name')
369 def capability_templates(cls):
371 Associated exposed capability templates.
373 :type: {:obj:`basestring`: :class:`CapabilityTemplate`}
375 return relationship.one_to_many(cls, 'capability_template', dict_key='name')
378 def requirement_templates(cls):
380 Associated potential relationships with other nodes.
382 :type: [:class:`RequirementTemplate`]
384 return relationship.one_to_many(cls, 'requirement_template', other_fk='node_template_fk')
389 Declarations for associated immutable parameters.
391 :type: {:obj:`basestring`: :class:`Property`}
393 return relationship.one_to_many(cls, 'property', dict_key='name')
398 Declarations for associated mutable parameters.
400 :type: {:obj:`basestring`: :class:`Attribute`}
402 return relationship.one_to_many(cls, 'attribute', dict_key='name')
406 # region many_to_one relationships
415 return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
418 def service_template(cls):
420 Containing service template.
422 :type: :class:`ServiceTemplate`
424 return relationship.many_to_one(cls, 'service_template')
428 # region association proxies
431 def service_template_name(cls):
432 return relationship.association_proxy('service_template', 'name')
436 return relationship.association_proxy('type', 'name')
440 # region foreign_keys
444 """For NodeTemplate many-to-one to Type"""
445 return relationship.foreign_key('type')
448 def service_template_fk(cls):
449 """For ServiceTemplate one-to-many to NodeTemplate"""
450 return relationship.foreign_key('service_template')
454 description = Column(Text, doc="""
455 Human-readable description.
457 :type: :obj:`basestring`
460 directives = Column(PickleType, doc="""
461 Directives that apply to this node template.
463 :type: [:obj:`basestring`]
466 default_instances = Column(Integer, default=1, doc="""
467 Default number nodes that will appear in the service.
472 min_instances = Column(Integer, default=0, doc="""
473 Minimum number nodes that will appear in the service.
478 max_instances = Column(Integer, default=None, doc="""
479 Maximum number nodes that will appear in the service.
484 target_node_template_constraints = Column(PickleType, doc="""
485 Constraints for filtering relationship targets.
487 :type: [:class:`NodeTemplateConstraint`]
492 return collections.OrderedDict((
494 ('description', self.description),
495 ('type_name', self.type.name),
496 ('properties', formatting.as_raw_dict(self.properties)),
497 ('attributes', formatting.as_raw_dict(self.properties)),
498 ('interface_templates', formatting.as_raw_list(self.interface_templates)),
499 ('artifact_templates', formatting.as_raw_list(self.artifact_templates)),
500 ('capability_templates', formatting.as_raw_list(self.capability_templates)),
501 ('requirement_templates', formatting.as_raw_list(self.requirement_templates))))
503 def is_target_node_template_valid(self, target_node_template):
505 Checks if ``target_node_template`` matches all our ``target_node_template_constraints``.
508 if self.target_node_template_constraints:
509 for node_template_constraint in self.target_node_template_constraints:
510 if not node_template_constraint.matches(self, target_node_template):
515 def _next_index(self):
517 Next available node index.
525 max_index = max(int(n.name.rsplit('_', 1)[-1]) for n in self.nodes)
529 def _next_name(self):
531 Next available node name.
537 return '{name}_{index}'.format(name=self.name, index=self._next_index)
543 def extract_property(properties, name):
546 prop = properties.get(name)
547 if (prop is not None) and (prop.type_name == 'integer') and (prop.value is not None):
548 scaling[name] = prop.value
550 def extract_properties(properties):
551 extract_property(properties, 'min_instances')
552 extract_property(properties, 'max_instances')
553 extract_property(properties, 'default_instances')
555 # From our scaling capabilities
556 for capability_template in self.capability_templates.itervalues():
557 if capability_template.type.role == 'scaling':
558 extract_properties(capability_template.properties)
560 # From service scaling policies
561 for policy_template in self.service_template.policy_templates.itervalues():
562 if policy_template.type.role == 'scaling':
563 if policy_template.is_for_node_template(self.name):
564 extract_properties(policy_template.properties)
567 scaling.setdefault('min_instances', 0)
568 scaling.setdefault('max_instances', 1)
569 scaling.setdefault('default_instances', 1)
574 class GroupTemplateBase(TemplateModelMixin):
576 Template for creating a :class:`Group` instance, which is a typed logical container for zero or
577 more :class:`Node` instances.
580 __tablename__ = 'group_template'
582 __private_fields__ = ('type_fk',
583 'service_template_fk')
585 # region one_to_many relationships
592 :type: [:class:`Group`]
594 return relationship.one_to_many(cls, 'group')
597 def interface_templates(cls):
599 Associated interface templates.
601 :type: {:obj:`basestring`: :class:`InterfaceTemplate`}
603 return relationship.one_to_many(cls, 'interface_template', dict_key='name')
608 Declarations for associated immutable parameters.
610 :type: {:obj:`basestring`: :class:`Property`}
612 return relationship.one_to_many(cls, 'property', dict_key='name')
616 # region many_to_one relationships
619 def service_template(cls):
621 Containing service template.
623 :type: :class:`ServiceTemplate`
625 return relationship.many_to_one(cls, 'service_template')
634 return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
638 # region many_to_many relationships
641 def node_templates(cls):
643 Nodes instantiated by these templates will be members of the group.
645 :type: [:class:`NodeTemplate`]
647 return relationship.many_to_many(cls, 'node_template')
651 # region foreign keys
655 """For GroupTemplate many-to-one to Type"""
656 return relationship.foreign_key('type')
659 def service_template_fk(cls):
660 """For ServiceTemplate one-to-many to GroupTemplate"""
661 return relationship.foreign_key('service_template')
665 description = Column(Text, doc="""
666 Human-readable description.
668 :type: :obj:`basestring`
673 return collections.OrderedDict((
675 ('description', self.description),
676 ('type_name', self.type.name),
677 ('properties', formatting.as_raw_dict(self.properties)),
678 ('interface_templates', formatting.as_raw_list(self.interface_templates))))
680 def contains_node_template(self, name):
681 for node_template in self.node_templates:
682 if node_template.name == name:
687 class PolicyTemplateBase(TemplateModelMixin):
689 Template for creating a :class:`Policy` instance, which is a typed set of orchestration hints
690 applied to zero or more :class:`Node` or :class:`Group` instances.
693 __tablename__ = 'policy_template'
695 __private_fields__ = ('type_fk',
696 'service_template_fk')
698 # region one_to_many relationships
703 Instantiated policies.
705 :type: [:class:`Policy`]
707 return relationship.one_to_many(cls, 'policy')
712 Declarations for associated immutable parameters.
714 :type: {:obj:`basestring`: :class:`Property`}
716 return relationship.one_to_many(cls, 'property', dict_key='name')
720 # region many_to_one relationships
723 def service_template(cls):
725 Containing service template.
727 :type: :class:`ServiceTemplate`
729 return relationship.many_to_one(cls, 'service_template')
738 return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
742 # region many_to_many relationships
745 def node_templates(cls):
747 Policy will be enacted on all nodes instantiated by these templates.
749 :type: {:obj:`basestring`: :class:`NodeTemplate`}
751 return relationship.many_to_many(cls, 'node_template')
754 def group_templates(cls):
756 Policy will be enacted on all nodes in all groups instantiated by these templates.
758 :type: {:obj:`basestring`: :class:`GroupTemplate`}
760 return relationship.many_to_many(cls, 'group_template')
764 # region foreign keys
768 """For PolicyTemplate many-to-one to Type"""
769 return relationship.foreign_key('type')
772 def service_template_fk(cls):
773 """For ServiceTemplate one-to-many to PolicyTemplate"""
774 return relationship.foreign_key('service_template')
778 description = Column(Text, doc="""
779 Human-readable description.
781 :type: :obj:`basestring`
786 return collections.OrderedDict((
788 ('description', self.description),
789 ('type_name', self.type.name),
790 ('properties', formatting.as_raw_dict(self.properties))))
792 def is_for_node_template(self, name):
793 for node_template in self.node_templates:
794 if node_template.name == name:
796 for group_template in self.group_templates:
797 if group_template.contains_node_template(name):
801 def is_for_group_template(self, name):
802 for group_template in self.group_templates:
803 if group_template.name == name:
808 class SubstitutionTemplateBase(TemplateModelMixin):
810 Template for creating a :class:`Substitution` instance, which exposes an entire instantiated
811 service as a single node.
814 __tablename__ = 'substitution_template'
816 __private_fields__ = ('node_type_fk',)
818 # region one_to_many relationships
821 def substitutions(cls):
823 Instantiated substitutions.
825 :type: [:class:`Substitution`]
827 return relationship.one_to_many(cls, 'substitution')
832 Map requirement and capabilities to exposed node.
834 :type: {:obj:`basestring`: :class:`SubstitutionTemplateMapping`}
836 return relationship.one_to_many(cls, 'substitution_template_mapping', dict_key='name')
840 # region many_to_one relationships
849 return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
853 # region foreign keys
856 def node_type_fk(cls):
857 """For SubstitutionTemplate many-to-one to Type"""
858 return relationship.foreign_key('type')
864 return collections.OrderedDict((
865 ('node_type_name', self.node_type.name),
866 ('mappings', formatting.as_raw_dict(self.mappings))))
869 class SubstitutionTemplateMappingBase(TemplateModelMixin):
871 Used by :class:`SubstitutionTemplate` to map a capability template or a requirement template to
874 The :attr:`name` field should match the capability or requirement name on the exposed node's
877 Only one of :attr:`capability_template` and :attr:`requirement_template` can be set.
880 __tablename__ = 'substitution_template_mapping'
882 __private_fields__ = ('substitution_template_fk',
883 'capability_template_fk',
884 'requirement_template_fk')
886 # region one_to_one relationships
889 def capability_template(cls):
891 Capability template to expose (can be ``None``).
893 :type: :class:`CapabilityTemplate`
895 return relationship.one_to_one(
896 cls, 'capability_template', back_populates=relationship.NO_BACK_POP)
899 def requirement_template(cls):
901 Requirement template to expose (can be ``None``).
903 :type: :class:`RequirementTemplate`
905 return relationship.one_to_one(
906 cls, 'requirement_template', back_populates=relationship.NO_BACK_POP)
910 # region many_to_one relationships
913 def substitution_template(cls):
915 Containing substitution template.
917 :type: :class:`SubstitutionTemplate`
919 return relationship.many_to_one(cls, 'substitution_template', back_populates='mappings')
923 # region foreign keys
926 def substitution_template_fk(cls):
927 """For SubstitutionTemplate one-to-many to SubstitutionTemplateMapping"""
928 return relationship.foreign_key('substitution_template')
931 def capability_template_fk(cls):
932 """For SubstitutionTemplate one-to-one to CapabilityTemplate"""
933 return relationship.foreign_key('capability_template', nullable=True)
936 def requirement_template_fk(cls):
937 """For SubstitutionTemplate one-to-one to RequirementTemplate"""
938 return relationship.foreign_key('requirement_template', nullable=True)
944 return collections.OrderedDict((
945 ('name', self.name),))
948 class RequirementTemplateBase(TemplateModelMixin):
950 Template for creating :class:`Relationship` instances, which are optionally-typed edges in the
951 service topology, connecting a :class:`Node` to a :class:`Capability` of another node.
953 Note that there is no equivalent "Requirement" instance model. Instead, during instantiation a
954 requirement template is matched with a capability and a :class:`Relationship` is instantiated.
956 A requirement template *must* target a :class:`CapabilityType` or a capability name. It can
957 optionally target a specific :class:`NodeType` or :class:`NodeTemplate`.
959 Requirement templates may optionally contain a :class:`RelationshipTemplate`. If they do not,
960 a :class:`Relationship` will be instantiated with default values.
963 __tablename__ = 'requirement_template'
965 __private_fields__ = ('target_capability_type_fk',
966 'target_node_template_fk',
967 'target_node_type_fk',
968 'relationship_template_fk',
971 # region one_to_one relationships
974 def target_capability_type(cls):
976 Target capability type.
978 :type: :class:`CapabilityType`
980 return relationship.one_to_one(cls,
982 fk='target_capability_type_fk',
983 back_populates=relationship.NO_BACK_POP)
986 def target_node_template(cls):
988 Target node template (can be ``None``).
990 :type: :class:`NodeTemplate`
992 return relationship.one_to_one(cls,
994 fk='target_node_template_fk',
995 back_populates=relationship.NO_BACK_POP)
998 def relationship_template(cls):
1000 Associated relationship template (can be ``None``).
1002 :type: :class:`RelationshipTemplate`
1004 return relationship.one_to_one(cls, 'relationship_template')
1008 # region one_to_many relationships
1011 def relationships(cls):
1013 Instantiated relationships.
1015 :type: [:class:`Relationship`]
1017 return relationship.one_to_many(cls, 'relationship')
1021 # region many_to_one relationships
1024 def node_template(cls):
1026 Containing node template.
1028 :type: :class:`NodeTemplate`
1030 return relationship.many_to_one(cls, 'node_template', fk='node_template_fk')
1033 def target_node_type(cls):
1035 Target node type (can be ``None``).
1037 :type: :class:`Type`
1039 return relationship.many_to_one(
1040 cls, 'type', fk='target_node_type_fk', back_populates=relationship.NO_BACK_POP)
1044 # region foreign keys
1047 def target_node_type_fk(cls):
1048 """For RequirementTemplate many-to-one to Type"""
1049 return relationship.foreign_key('type', nullable=True)
1052 def target_node_template_fk(cls):
1053 """For RequirementTemplate one-to-one to NodeTemplate"""
1054 return relationship.foreign_key('node_template', nullable=True)
1057 def target_capability_type_fk(cls):
1058 """For RequirementTemplate one-to-one to Type"""
1059 return relationship.foreign_key('type', nullable=True)
1062 def node_template_fk(cls):
1063 """For NodeTemplate one-to-many to RequirementTemplate"""
1064 return relationship.foreign_key('node_template')
1067 def relationship_template_fk(cls):
1068 """For RequirementTemplate one-to-one to RelationshipTemplate"""
1069 return relationship.foreign_key('relationship_template', nullable=True)
1073 target_capability_name = Column(Text, doc="""
1074 Target capability name in node template or node type (can be ``None``).
1076 :type: :obj:`basestring`
1079 target_node_template_constraints = Column(PickleType, doc="""
1080 Constraints for filtering relationship targets.
1082 :type: [:class:`NodeTemplateConstraint`]
1087 return collections.OrderedDict((
1088 ('name', self.name),
1089 ('target_node_type_name', self.target_node_type.name
1090 if self.target_node_type is not None else None),
1091 ('target_node_template_name', self.target_node_template.name
1092 if self.target_node_template is not None else None),
1093 ('target_capability_type_name', self.target_capability_type.name
1094 if self.target_capability_type is not None else None),
1095 ('target_capability_name', self.target_capability_name),
1096 ('relationship_template', formatting.as_raw(self.relationship_template))))
1099 class RelationshipTemplateBase(TemplateModelMixin):
1101 Optional addition to a :class:`RequirementTemplate`.
1103 Note that a relationship template here is not exactly equivalent to a relationship template
1104 entity in TOSCA. For example, a TOSCA requirement specifying a relationship type rather than a
1105 relationship template would still be represented here as a relationship template.
1108 __tablename__ = 'relationship_template'
1110 __private_fields__ = ('type_fk',)
1112 # region one_to_many relationships
1115 def relationships(cls):
1117 Instantiated relationships.
1119 :type: [:class:`Relationship`]
1121 return relationship.one_to_many(cls, 'relationship')
1124 def interface_templates(cls):
1126 Associated interface templates.
1128 :type: {:obj:`basestring`: :class:`InterfaceTemplate`}
1130 return relationship.one_to_many(cls, 'interface_template', dict_key='name')
1133 def properties(cls):
1135 Declarations for associated immutable parameters.
1137 :type: {:obj:`basestring`: :class:`Property`}
1139 return relationship.one_to_many(cls, 'property', dict_key='name')
1143 # region many_to_one relationships
1150 :type: :class:`Type`
1152 return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
1156 # region foreign keys
1160 """For RelationshipTemplate many-to-one to Type"""
1161 return relationship.foreign_key('type', nullable=True)
1165 description = Column(Text, doc="""
1166 Human-readable description.
1168 :type: :obj:`basestring`
1173 return collections.OrderedDict((
1174 ('type_name', self.type.name if self.type is not None else None),
1175 ('name', self.name),
1176 ('description', self.description),
1177 ('properties', formatting.as_raw_dict(self.properties)),
1178 ('interface_templates', formatting.as_raw_list(self.interface_templates))))
1181 class CapabilityTemplateBase(TemplateModelMixin):
1183 Template for creating :class:`Capability` instances, typed attachments which serve two purposes:
1184 to provide extra properties and attributes to :class:`Node` instances, and to expose targets for
1185 :class:`Relationship` instances from other nodes.
1188 __tablename__ = 'capability_template'
1190 __private_fields__ = ('type_fk',
1193 # region one_to_many relationships
1196 def capabilities(cls):
1198 Instantiated capabilities.
1200 :type: [:class:`Capability`]
1202 return relationship.one_to_many(cls, 'capability')
1205 def properties(cls):
1207 Declarations for associated immutable parameters.
1209 :type: {:obj:`basestring`: :class:`Property`}
1211 return relationship.one_to_many(cls, 'property', dict_key='name')
1215 # region many_to_one relationships
1218 def node_template(cls):
1220 Containing node template.
1222 :type: :class:`NodeTemplate`
1224 return relationship.many_to_one(cls, 'node_template')
1231 :type: :class:`Type`
1233 return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
1237 # region many_to_many relationships
1240 def valid_source_node_types(cls):
1242 Reject requirements that are not from these node types.
1244 :type: [:class:`Type`]
1246 return relationship.many_to_many(cls, 'type', prefix='valid_sources')
1250 # region foreign keys
1254 """For CapabilityTemplate many-to-one to Type"""
1255 return relationship.foreign_key('type')
1258 def node_template_fk(cls):
1259 """For NodeTemplate one-to-many to CapabilityTemplate"""
1260 return relationship.foreign_key('node_template')
1264 description = Column(Text, doc="""
1265 Human-readable description.
1267 :type: :obj:`basestring`
1270 min_occurrences = Column(Integer, default=None, doc="""
1271 Minimum number of requirement matches required.
1276 max_occurrences = Column(Integer, default=None, doc="""
1277 Maximum number of requirement matches allowed.
1284 return collections.OrderedDict((
1285 ('name', self.name),
1286 ('description', self.description),
1287 ('type_name', self.type.name),
1288 ('min_occurrences', self.min_occurrences),
1289 ('max_occurrences', self.max_occurrences),
1290 ('valid_source_node_types', [v.name for v in self.valid_source_node_types]),
1291 ('properties', formatting.as_raw_dict(self.properties))))
1294 class InterfaceTemplateBase(TemplateModelMixin):
1296 Template for creating :class:`Interface` instances, which are typed bundles of
1297 :class:`Operation` instances.
1299 Can be associated with a :class:`NodeTemplate`, a :class:`GroupTemplate`, or a
1300 :class:`RelationshipTemplate`.
1303 __tablename__ = 'interface_template'
1305 __private_fields__ = ('type_fk',
1307 'group_template_fk',
1308 'relationship_template_fk')
1310 # region one_to_many relationships
1315 Declarations for externally provided parameters that can be used by all operations of the
1318 :type: {:obj:`basestring`: :class:`Input`}
1320 return relationship.one_to_many(cls, 'input', dict_key='name')
1323 def interfaces(cls):
1325 Instantiated interfaces.
1327 :type: [:class:`Interface`]
1329 return relationship.one_to_many(cls, 'interface')
1332 def operation_templates(cls):
1334 Associated operation templates.
1336 :type: {:obj:`basestring`: :class:`OperationTemplate`}
1338 return relationship.one_to_many(cls, 'operation_template', dict_key='name')
1342 # region many_to_one relationships
1345 def node_template(cls):
1347 Containing node template (can be ``None``).
1349 :type: :class:`NodeTemplate`
1351 return relationship.many_to_one(cls, 'node_template')
1354 def group_template(cls):
1356 Containing group template (can be ``None``).
1358 :type: :class:`GroupTemplate`
1360 return relationship.many_to_one(cls, 'group_template')
1363 def relationship_template(cls):
1365 Containing relationship template (can be ``None``).
1367 :type: :class:`RelationshipTemplate`
1369 return relationship.many_to_one(cls, 'relationship_template')
1376 :type: :class:`Type`
1378 return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
1382 # region foreign keys
1386 """For InterfaceTemplate many-to-one to Type"""
1387 return relationship.foreign_key('type')
1390 def node_template_fk(cls):
1391 """For NodeTemplate one-to-many to InterfaceTemplate"""
1392 return relationship.foreign_key('node_template', nullable=True)
1395 def group_template_fk(cls):
1396 """For GroupTemplate one-to-many to InterfaceTemplate"""
1397 return relationship.foreign_key('group_template', nullable=True)
1400 def relationship_template_fk(cls):
1401 """For RelationshipTemplate one-to-many to InterfaceTemplate"""
1402 return relationship.foreign_key('relationship_template', nullable=True)
1406 description = Column(Text, doc="""
1407 Human-readable description.
1409 :type: :obj:`basestring`
1414 return collections.OrderedDict((
1415 ('name', self.name),
1416 ('description', self.description),
1417 ('type_name', self.type.name),
1418 ('inputs', formatting.as_raw_dict(self.inputs)), # pylint: disable=no-member
1419 # TODO fix self.properties reference
1420 ('operation_templates', formatting.as_raw_list(self.operation_templates))))
1423 class OperationTemplateBase(TemplateModelMixin):
1425 Template for creating :class:`Operation` instances, which are entry points to Python functions
1426 called as part of a workflow execution.
1429 __tablename__ = 'operation_template'
1431 __private_fields__ = ('service_template_fk',
1432 'interface_template_fk',
1435 # region one_to_one relationships
1438 def plugin_specification(cls):
1440 Associated plugin specification.
1442 :type: :class:`PluginSpecification`
1444 return relationship.one_to_one(
1445 cls, 'plugin_specification', back_populates=relationship.NO_BACK_POP)
1449 # region one_to_many relationships
1452 def operations(cls):
1454 Instantiated operations.
1456 :type: [:class:`Operation`]
1458 return relationship.one_to_many(cls, 'operation')
1463 Declarations for parameters provided to the :attr:`implementation`.
1465 :type: {:obj:`basestring`: :class:`Input`}
1467 return relationship.one_to_many(cls, 'input', dict_key='name')
1470 def configurations(cls):
1472 Configuration parameters for the operation instance Python :attr:`function`.
1474 :type: {:obj:`basestring`: :class:`Configuration`}
1476 return relationship.one_to_many(cls, 'configuration', dict_key='name')
1480 # region many_to_one relationships
1483 def service_template(cls):
1485 Containing service template (can be ``None``). For workflow operation templates.
1487 :type: :class:`ServiceTemplate`
1489 return relationship.many_to_one(cls, 'service_template',
1490 back_populates='workflow_templates')
1493 def interface_template(cls):
1495 Containing interface template (can be ``None``).
1497 :type: :class:`InterfaceTemplate`
1499 return relationship.many_to_one(cls, 'interface_template')
1503 # region foreign keys
1506 def service_template_fk(cls):
1507 """For ServiceTemplate one-to-many to OperationTemplate"""
1508 return relationship.foreign_key('service_template', nullable=True)
1511 def interface_template_fk(cls):
1512 """For InterfaceTemplate one-to-many to OperationTemplate"""
1513 return relationship.foreign_key('interface_template', nullable=True)
1516 def plugin_specification_fk(cls):
1517 """For OperationTemplate one-to-one to PluginSpecification"""
1518 return relationship.foreign_key('plugin_specification', nullable=True)
1522 description = Column(Text, doc="""
1523 Human-readable description.
1525 :type: :obj:`basestring`
1528 relationship_edge = Column(Boolean, doc="""
1529 When ``True`` specifies that the operation is on the relationship's target edge; ``False`` is
1530 the source edge (only used by operations on relationships)
1535 implementation = Column(Text, doc="""
1536 Implementation (usually the name of an artifact).
1538 :type: :obj:`basestring`
1541 dependencies = Column(modeling_types.StrictList(item_cls=basestring), doc="""
1542 Dependencies (usually names of artifacts).
1544 :type: [:obj:`basestring`]
1547 function = Column(Text, doc="""
1548 Full path to Python function.
1550 :type: :obj:`basestring`
1553 executor = Column(Text, doc="""
1556 :type: :obj:`basestring`
1559 max_attempts = Column(Integer, doc="""
1560 Maximum number of attempts allowed in case of task failure.
1565 retry_interval = Column(Integer, doc="""
1566 Interval between task retry attemps (in seconds).
1573 return collections.OrderedDict((
1574 ('name', self.name),
1575 ('description', self.description),
1576 ('implementation', self.implementation),
1577 ('dependencies', self.dependencies),
1578 ('inputs', formatting.as_raw_dict(self.inputs))))
1581 class ArtifactTemplateBase(TemplateModelMixin):
1583 Template for creating an :class:`Artifact` instance, which is a typed file, either provided in a
1584 CSAR or downloaded from a repository.
1587 __tablename__ = 'artifact_template'
1589 __private_fields__ = ('type_fk',
1592 # region one_to_many relationships
1597 Instantiated artifacts.
1599 :type: [:class:`Artifact`]
1601 return relationship.one_to_many(cls, 'artifact')
1604 def properties(cls):
1606 Declarations for associated immutable parameters.
1608 :type: {:obj:`basestring`: :class:`Property`}
1610 return relationship.one_to_many(cls, 'property', dict_key='name')
1614 # region many_to_one relationships
1617 def node_template(cls):
1619 Containing node template.
1621 :type: :class:`NodeTemplate`
1623 return relationship.many_to_one(cls, 'node_template')
1630 :type: :class:`Type`
1632 return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
1636 # region foreign keys
1640 """For ArtifactTemplate many-to-one to Type"""
1641 return relationship.foreign_key('type')
1644 def node_template_fk(cls):
1645 """For NodeTemplate one-to-many to ArtifactTemplate"""
1646 return relationship.foreign_key('node_template')
1650 description = Column(Text, doc="""
1651 Human-readable description.
1653 :type: :obj:`basestring`
1656 source_path = Column(Text, doc="""
1657 Source path (in CSAR or repository).
1659 :type: :obj:`basestring`
1662 target_path = Column(Text, doc="""
1663 Path at which to install at destination.
1665 :type: :obj:`basestring`
1668 repository_url = Column(Text, doc="""
1671 :type: :obj:`basestring`
1674 repository_credential = Column(modeling_types.StrictDict(basestring, basestring), doc="""
1675 Credentials for accessing the repository.
1677 :type: {:obj:`basestring`, :obj:`basestring`}
1682 return collections.OrderedDict((
1683 ('name', self.name),
1684 ('description', self.description),
1685 ('type_name', self.type.name),
1686 ('source_path', self.source_path),
1687 ('target_path', self.target_path),
1688 ('repository_url', self.repository_url),
1689 ('repository_credential', formatting.as_agnostic(self.repository_credential)),
1690 ('properties', formatting.as_raw_dict(self.properties))))
1693 class PluginSpecificationBase(TemplateModelMixin):
1695 Requirement for a :class:`Plugin`.
1697 The actual plugin to be selected depends on those currently installed in ARIA.
1700 __tablename__ = 'plugin_specification'
1702 __private_fields__ = ('service_template_fk',
1705 # region many_to_one relationships
1708 def service_template(cls):
1710 Containing service template.
1712 :type: :class:`ServiceTemplate`
1714 return relationship.many_to_one(cls, 'service_template')
1717 def plugin(cls): # pylint: disable=method-hidden
1721 :type: :class:`Plugin`
1723 return relationship.many_to_one(cls, 'plugin', back_populates=relationship.NO_BACK_POP)
1727 # region foreign keys
1730 def service_template_fk(cls):
1731 """For ServiceTemplate one-to-many to PluginSpecification"""
1732 return relationship.foreign_key('service_template', nullable=True)
1736 """For PluginSpecification many-to-one to Plugin"""
1737 return relationship.foreign_key('plugin', nullable=True)
1741 version = Column(Text, doc="""
1742 Minimum plugin version.
1744 :type: :obj:`basestring`
1747 enabled = Column(Boolean, nullable=False, default=True, doc="""
1748 Whether the plugin is enabled.
1755 return collections.OrderedDict((
1756 ('name', self.name),
1757 ('version', self.version),
1758 ('enabled', self.enabled)))