| # 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. |
| |
| """ |
| ARIA modeling service template module |
| """ |
| |
| # pylint: disable=too-many-lines, no-self-argument, no-member, abstract-method |
| |
| from __future__ import absolute_import # so we can import standard 'types' |
| |
| from sqlalchemy import ( |
| Column, |
| Text, |
| Integer, |
| Boolean, |
| DateTime, |
| PickleType |
| ) |
| from sqlalchemy.ext.declarative import declared_attr |
| |
| from ..utils import (collections, formatting) |
| from .mixins import TemplateModelMixin |
| from . import ( |
| relationship, |
| types as modeling_types |
| ) |
| |
| |
| class ServiceTemplateBase(TemplateModelMixin): |
| """ |
| Template for creating :class:`Service` instances. |
| |
| Usually created by various DSL parsers, such as ARIA's TOSCA extension. However, it can also be |
| created programmatically. |
| """ |
| |
| __tablename__ = 'service_template' |
| |
| __private_fields__ = ('substitution_template_fk', |
| 'node_type_fk', |
| 'group_type_fk', |
| 'policy_type_fk', |
| 'relationship_type_fk', |
| 'capability_type_fk', |
| 'interface_type_fk', |
| 'artifact_type_fk') |
| |
| # region one_to_one relationships |
| |
| @declared_attr |
| def substitution_template(cls): |
| """ |
| Exposes an entire service as a single node. |
| |
| :type: :class:`SubstitutionTemplate` |
| """ |
| return relationship.one_to_one( |
| cls, 'substitution_template', back_populates=relationship.NO_BACK_POP) |
| |
| @declared_attr |
| def node_types(cls): |
| """ |
| Base for the node type hierarchy, |
| |
| :type: :class:`Type` |
| """ |
| return relationship.one_to_one( |
| cls, 'type', fk='node_type_fk', back_populates=relationship.NO_BACK_POP) |
| |
| @declared_attr |
| def group_types(cls): |
| """ |
| Base for the group type hierarchy, |
| |
| :type: :class:`Type` |
| """ |
| return relationship.one_to_one( |
| cls, 'type', fk='group_type_fk', back_populates=relationship.NO_BACK_POP) |
| |
| @declared_attr |
| def policy_types(cls): |
| """ |
| Base for the policy type hierarchy, |
| |
| :type: :class:`Type` |
| """ |
| return relationship.one_to_one( |
| cls, 'type', fk='policy_type_fk', back_populates=relationship.NO_BACK_POP) |
| |
| @declared_attr |
| def relationship_types(cls): |
| """ |
| Base for the relationship type hierarchy, |
| |
| :type: :class:`Type` |
| """ |
| return relationship.one_to_one( |
| cls, 'type', fk='relationship_type_fk', back_populates=relationship.NO_BACK_POP) |
| |
| @declared_attr |
| def capability_types(cls): |
| """ |
| Base for the capability type hierarchy, |
| |
| :type: :class:`Type` |
| """ |
| return relationship.one_to_one( |
| cls, 'type', fk='capability_type_fk', back_populates=relationship.NO_BACK_POP) |
| |
| @declared_attr |
| def interface_types(cls): |
| """ |
| Base for the interface type hierarchy, |
| |
| :type: :class:`Type` |
| """ |
| return relationship.one_to_one( |
| cls, 'type', fk='interface_type_fk', back_populates=relationship.NO_BACK_POP) |
| |
| @declared_attr |
| def artifact_types(cls): |
| """ |
| Base for the artifact type hierarchy, |
| |
| :type: :class:`Type` |
| """ |
| return relationship.one_to_one( |
| cls, 'type', fk='artifact_type_fk', back_populates=relationship.NO_BACK_POP) |
| |
| # endregion |
| |
| # region one_to_many relationships |
| |
| @declared_attr |
| def services(cls): |
| """ |
| Instantiated services. |
| |
| :type: [:class:`Service`] |
| """ |
| return relationship.one_to_many(cls, 'service', dict_key='name') |
| |
| @declared_attr |
| def node_templates(cls): |
| """ |
| Templates for creating nodes. |
| |
| :type: {:obj:`basestring`, :class:`NodeTemplate`} |
| """ |
| return relationship.one_to_many(cls, 'node_template', dict_key='name') |
| |
| @declared_attr |
| def group_templates(cls): |
| """ |
| Templates for creating groups. |
| |
| :type: {:obj:`basestring`, :class:`GroupTemplate`} |
| """ |
| return relationship.one_to_many(cls, 'group_template', dict_key='name') |
| |
| @declared_attr |
| def policy_templates(cls): |
| """ |
| Templates for creating policies. |
| |
| :type: {:obj:`basestring`, :class:`PolicyTemplate`} |
| """ |
| return relationship.one_to_many(cls, 'policy_template', dict_key='name') |
| |
| @declared_attr |
| def workflow_templates(cls): |
| """ |
| Templates for creating workflows. |
| |
| :type: {:obj:`basestring`, :class:`OperationTemplate`} |
| """ |
| return relationship.one_to_many(cls, 'operation_template', dict_key='name') |
| |
| @declared_attr |
| def outputs(cls): |
| """ |
| Declarations for output parameters are filled in after service installation. |
| |
| :type: {:obj:`basestring`: :class:`Output`} |
| """ |
| return relationship.one_to_many(cls, 'output', dict_key='name') |
| |
| @declared_attr |
| def inputs(cls): |
| """ |
| Declarations for externally provided parameters. |
| |
| :type: {:obj:`basestring`: :class:`Input`} |
| """ |
| return relationship.one_to_many(cls, 'input', dict_key='name') |
| |
| @declared_attr |
| def plugin_specifications(cls): |
| """ |
| Required plugins for instantiated services. |
| |
| :type: {:obj:`basestring`: :class:`PluginSpecification`} |
| """ |
| return relationship.one_to_many(cls, 'plugin_specification', dict_key='name') |
| |
| # endregion |
| |
| # region many_to_many relationships |
| |
| @declared_attr |
| def meta_data(cls): |
| """ |
| Associated metadata. |
| |
| :type: {:obj:`basestring`: :class:`Metadata`} |
| """ |
| # Warning! We cannot use the attr name "metadata" because it's used by SQLAlchemy! |
| return relationship.many_to_many(cls, 'metadata', dict_key='name') |
| |
| # endregion |
| |
| # region foreign keys |
| |
| @declared_attr |
| def substitution_template_fk(cls): |
| """For ServiceTemplate one-to-one to SubstitutionTemplate""" |
| return relationship.foreign_key('substitution_template', nullable=True) |
| |
| @declared_attr |
| def node_type_fk(cls): |
| """For ServiceTemplate one-to-one to Type""" |
| return relationship.foreign_key('type', nullable=True) |
| |
| @declared_attr |
| def group_type_fk(cls): |
| """For ServiceTemplate one-to-one to Type""" |
| return relationship.foreign_key('type', nullable=True) |
| |
| @declared_attr |
| def policy_type_fk(cls): |
| """For ServiceTemplate one-to-one to Type""" |
| return relationship.foreign_key('type', nullable=True) |
| |
| @declared_attr |
| def relationship_type_fk(cls): |
| """For ServiceTemplate one-to-one to Type""" |
| return relationship.foreign_key('type', nullable=True) |
| |
| @declared_attr |
| def capability_type_fk(cls): |
| """For ServiceTemplate one-to-one to Type""" |
| return relationship.foreign_key('type', nullable=True) |
| |
| @declared_attr |
| def interface_type_fk(cls): |
| """For ServiceTemplate one-to-one to Type""" |
| return relationship.foreign_key('type', nullable=True) |
| |
| @declared_attr |
| def artifact_type_fk(cls): |
| """For ServiceTemplate one-to-one to Type""" |
| return relationship.foreign_key('type', nullable=True) |
| |
| # endregion |
| |
| description = Column(Text, doc=""" |
| Human-readable description. |
| |
| :type: :obj:`basestring` |
| """) |
| |
| main_file_name = Column(Text, doc=""" |
| Filename of CSAR or YAML file from which this service template was parsed. |
| |
| :type: :obj:`basestring` |
| """) |
| |
| created_at = Column(DateTime, nullable=False, index=True, doc=""" |
| Creation timestamp. |
| |
| :type: :class:`~datetime.datetime` |
| """) |
| |
| updated_at = Column(DateTime, doc=""" |
| Update timestamp. |
| |
| :type: :class:`~datetime.datetime` |
| """) |
| |
| @property |
| def as_raw(self): |
| return collections.OrderedDict(( |
| ('description', self.description), |
| ('metadata', formatting.as_raw_dict(self.meta_data)), |
| ('node_templates', formatting.as_raw_list(self.node_templates)), |
| ('group_templates', formatting.as_raw_list(self.group_templates)), |
| ('policy_templates', formatting.as_raw_list(self.policy_templates)), |
| ('substitution_template', formatting.as_raw(self.substitution_template)), |
| ('inputs', formatting.as_raw_dict(self.inputs)), |
| ('outputs', formatting.as_raw_dict(self.outputs)), |
| ('workflow_templates', formatting.as_raw_list(self.workflow_templates)))) |
| |
| @property |
| def types_as_raw(self): |
| return collections.OrderedDict(( |
| ('node_types', formatting.as_raw(self.node_types)), |
| ('group_types', formatting.as_raw(self.group_types)), |
| ('policy_types', formatting.as_raw(self.policy_types)), |
| ('relationship_types', formatting.as_raw(self.relationship_types)), |
| ('capability_types', formatting.as_raw(self.capability_types)), |
| ('interface_types', formatting.as_raw(self.interface_types)), |
| ('artifact_types', formatting.as_raw(self.artifact_types)))) |
| |
| |
| class NodeTemplateBase(TemplateModelMixin): |
| """ |
| Template for creating zero or more :class:`Node` instances, which are typed vertices in the |
| service topology. |
| """ |
| |
| __tablename__ = 'node_template' |
| |
| __private_fields__ = ('type_fk', |
| 'service_template_fk') |
| |
| # region one_to_many relationships |
| |
| @declared_attr |
| def nodes(cls): |
| """ |
| Instantiated nodes. |
| |
| :type: [:class:`Node`] |
| """ |
| return relationship.one_to_many(cls, 'node') |
| |
| @declared_attr |
| def interface_templates(cls): |
| """ |
| Associated interface templates. |
| |
| :type: {:obj:`basestring`: :class:`InterfaceTemplate`} |
| """ |
| return relationship.one_to_many(cls, 'interface_template', dict_key='name') |
| |
| @declared_attr |
| def artifact_templates(cls): |
| """ |
| Associated artifacts. |
| |
| :type: {:obj:`basestring`: :class:`ArtifactTemplate`} |
| """ |
| return relationship.one_to_many(cls, 'artifact_template', dict_key='name') |
| |
| @declared_attr |
| def capability_templates(cls): |
| """ |
| Associated exposed capability templates. |
| |
| :type: {:obj:`basestring`: :class:`CapabilityTemplate`} |
| """ |
| return relationship.one_to_many(cls, 'capability_template', dict_key='name') |
| |
| @declared_attr |
| def requirement_templates(cls): |
| """ |
| Associated potential relationships with other nodes. |
| |
| :type: [:class:`RequirementTemplate`] |
| """ |
| return relationship.one_to_many(cls, 'requirement_template', other_fk='node_template_fk') |
| |
| @declared_attr |
| def properties(cls): |
| """ |
| Declarations for associated immutable parameters. |
| |
| :type: {:obj:`basestring`: :class:`Property`} |
| """ |
| return relationship.one_to_many(cls, 'property', dict_key='name') |
| |
| @declared_attr |
| def attributes(cls): |
| """ |
| Declarations for associated mutable parameters. |
| |
| :type: {:obj:`basestring`: :class:`Attribute`} |
| """ |
| return relationship.one_to_many(cls, 'attribute', dict_key='name') |
| |
| # endregion |
| |
| # region many_to_one relationships |
| |
| @declared_attr |
| def type(cls): |
| """ |
| Node type. |
| |
| :type: :class:`Type` |
| """ |
| return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP) |
| |
| @declared_attr |
| def service_template(cls): |
| """ |
| Containing service template. |
| |
| :type: :class:`ServiceTemplate` |
| """ |
| return relationship.many_to_one(cls, 'service_template') |
| |
| # endregion |
| |
| # region association proxies |
| |
| @declared_attr |
| def service_template_name(cls): |
| return relationship.association_proxy('service_template', 'name') |
| |
| @declared_attr |
| def type_name(cls): |
| return relationship.association_proxy('type', 'name') |
| |
| # endregion |
| |
| # region foreign_keys |
| |
| @declared_attr |
| def type_fk(cls): |
| """For NodeTemplate many-to-one to Type""" |
| return relationship.foreign_key('type') |
| |
| @declared_attr |
| def service_template_fk(cls): |
| """For ServiceTemplate one-to-many to NodeTemplate""" |
| return relationship.foreign_key('service_template') |
| |
| # endregion |
| |
| description = Column(Text, doc=""" |
| Human-readable description. |
| |
| :type: :obj:`basestring` |
| """) |
| |
| directives = Column(PickleType, doc=""" |
| Directives that apply to this node template. |
| |
| :type: [:obj:`basestring`] |
| """) |
| |
| default_instances = Column(Integer, default=1, doc=""" |
| Default number nodes that will appear in the service. |
| |
| :type: :obj:`int` |
| """) |
| |
| min_instances = Column(Integer, default=0, doc=""" |
| Minimum number nodes that will appear in the service. |
| |
| :type: :obj:`int` |
| """) |
| |
| max_instances = Column(Integer, default=None, doc=""" |
| Maximum number nodes that will appear in the service. |
| |
| :type: :obj:`int` |
| """) |
| |
| target_node_template_constraints = Column(PickleType, doc=""" |
| Constraints for filtering relationship targets. |
| |
| :type: [:class:`NodeTemplateConstraint`] |
| """) |
| |
| @property |
| def as_raw(self): |
| return collections.OrderedDict(( |
| ('name', self.name), |
| ('description', self.description), |
| ('type_name', self.type.name), |
| ('properties', formatting.as_raw_dict(self.properties)), |
| ('attributes', formatting.as_raw_dict(self.properties)), |
| ('interface_templates', formatting.as_raw_list(self.interface_templates)), |
| ('artifact_templates', formatting.as_raw_list(self.artifact_templates)), |
| ('capability_templates', formatting.as_raw_list(self.capability_templates)), |
| ('requirement_templates', formatting.as_raw_list(self.requirement_templates)))) |
| |
| def is_target_node_template_valid(self, target_node_template): |
| """ |
| Checks if ``target_node_template`` matches all our ``target_node_template_constraints``. |
| """ |
| |
| if self.target_node_template_constraints: |
| for node_template_constraint in self.target_node_template_constraints: |
| if not node_template_constraint.matches(self, target_node_template): |
| return False |
| return True |
| |
| @property |
| def _next_index(self): |
| """ |
| Next available node index. |
| |
| :returns: node index |
| :rtype: int |
| """ |
| |
| max_index = 0 |
| if self.nodes: |
| max_index = max(int(n.name.rsplit('_', 1)[-1]) for n in self.nodes) |
| return max_index + 1 |
| |
| @property |
| def _next_name(self): |
| """ |
| Next available node name. |
| |
| :returns: node name |
| :rtype: basestring |
| """ |
| |
| return '{name}_{index}'.format(name=self.name, index=self._next_index) |
| |
| @property |
| def scaling(self): |
| 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 self.capability_templates.itervalues(): |
| if capability_template.type.role == 'scaling': |
| extract_properties(capability_template.properties) |
| |
| # From service scaling policies |
| for policy_template in self.service_template.policy_templates.itervalues(): |
| if policy_template.type.role == 'scaling': |
| if policy_template.is_for_node_template(self.name): |
| extract_properties(policy_template.properties) |
| |
| # Defaults |
| scaling.setdefault('min_instances', 0) |
| scaling.setdefault('max_instances', 1) |
| scaling.setdefault('default_instances', 1) |
| |
| return scaling |
| |
| |
| class GroupTemplateBase(TemplateModelMixin): |
| """ |
| Template for creating a :class:`Group` instance, which is a typed logical container for zero or |
| more :class:`Node` instances. |
| """ |
| |
| __tablename__ = 'group_template' |
| |
| __private_fields__ = ('type_fk', |
| 'service_template_fk') |
| |
| # region one_to_many relationships |
| |
| @declared_attr |
| def groups(cls): |
| """ |
| Instantiated groups. |
| |
| :type: [:class:`Group`] |
| """ |
| return relationship.one_to_many(cls, 'group') |
| |
| @declared_attr |
| def interface_templates(cls): |
| """ |
| Associated interface templates. |
| |
| :type: {:obj:`basestring`: :class:`InterfaceTemplate`} |
| """ |
| return relationship.one_to_many(cls, 'interface_template', dict_key='name') |
| |
| @declared_attr |
| def properties(cls): |
| """ |
| Declarations for associated immutable parameters. |
| |
| :type: {:obj:`basestring`: :class:`Property`} |
| """ |
| return relationship.one_to_many(cls, 'property', dict_key='name') |
| |
| # endregion |
| |
| # region many_to_one relationships |
| |
| @declared_attr |
| def service_template(cls): |
| """ |
| Containing service template. |
| |
| :type: :class:`ServiceTemplate` |
| """ |
| return relationship.many_to_one(cls, 'service_template') |
| |
| @declared_attr |
| def type(cls): |
| """ |
| Group type. |
| |
| :type: :class:`Type` |
| """ |
| return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP) |
| |
| # endregion |
| |
| # region many_to_many relationships |
| |
| @declared_attr |
| def node_templates(cls): |
| """ |
| Nodes instantiated by these templates will be members of the group. |
| |
| :type: [:class:`NodeTemplate`] |
| """ |
| return relationship.many_to_many(cls, 'node_template') |
| |
| # endregion |
| |
| # region foreign keys |
| |
| @declared_attr |
| def type_fk(cls): |
| """For GroupTemplate many-to-one to Type""" |
| return relationship.foreign_key('type') |
| |
| @declared_attr |
| def service_template_fk(cls): |
| """For ServiceTemplate one-to-many to GroupTemplate""" |
| return relationship.foreign_key('service_template') |
| |
| # endregion |
| |
| description = Column(Text, doc=""" |
| Human-readable description. |
| |
| :type: :obj:`basestring` |
| """) |
| |
| @property |
| def as_raw(self): |
| return collections.OrderedDict(( |
| ('name', self.name), |
| ('description', self.description), |
| ('type_name', self.type.name), |
| ('properties', formatting.as_raw_dict(self.properties)), |
| ('interface_templates', formatting.as_raw_list(self.interface_templates)))) |
| |
| def contains_node_template(self, name): |
| for node_template in self.node_templates: |
| if node_template.name == name: |
| return True |
| return False |
| |
| |
| class PolicyTemplateBase(TemplateModelMixin): |
| """ |
| Template for creating a :class:`Policy` instance, which is a typed set of orchestration hints |
| applied to zero or more :class:`Node` or :class:`Group` instances. |
| """ |
| |
| __tablename__ = 'policy_template' |
| |
| __private_fields__ = ('type_fk', |
| 'service_template_fk') |
| |
| # region one_to_many relationships |
| |
| @declared_attr |
| def policies(cls): |
| """ |
| Instantiated policies. |
| |
| :type: [:class:`Policy`] |
| """ |
| return relationship.one_to_many(cls, 'policy') |
| |
| @declared_attr |
| def properties(cls): |
| """ |
| Declarations for associated immutable parameters. |
| |
| :type: {:obj:`basestring`: :class:`Property`} |
| """ |
| return relationship.one_to_many(cls, 'property', dict_key='name') |
| |
| # endregion |
| |
| # region many_to_one relationships |
| |
| @declared_attr |
| def service_template(cls): |
| """ |
| Containing service template. |
| |
| :type: :class:`ServiceTemplate` |
| """ |
| return relationship.many_to_one(cls, 'service_template') |
| |
| @declared_attr |
| def type(cls): |
| """ |
| Policy type. |
| |
| :type: :class:`Type` |
| """ |
| return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP) |
| |
| # endregion |
| |
| # region many_to_many relationships |
| |
| @declared_attr |
| def node_templates(cls): |
| """ |
| Policy will be enacted on all nodes instantiated by these templates. |
| |
| :type: {:obj:`basestring`: :class:`NodeTemplate`} |
| """ |
| return relationship.many_to_many(cls, 'node_template') |
| |
| @declared_attr |
| def group_templates(cls): |
| """ |
| Policy will be enacted on all nodes in all groups instantiated by these templates. |
| |
| :type: {:obj:`basestring`: :class:`GroupTemplate`} |
| """ |
| return relationship.many_to_many(cls, 'group_template') |
| |
| # endregion |
| |
| # region foreign keys |
| |
| @declared_attr |
| def type_fk(cls): |
| """For PolicyTemplate many-to-one to Type""" |
| return relationship.foreign_key('type') |
| |
| @declared_attr |
| def service_template_fk(cls): |
| """For ServiceTemplate one-to-many to PolicyTemplate""" |
| return relationship.foreign_key('service_template') |
| |
| # endregion |
| |
| description = Column(Text, doc=""" |
| Human-readable description. |
| |
| :type: :obj:`basestring` |
| """) |
| |
| @property |
| def as_raw(self): |
| return collections.OrderedDict(( |
| ('name', self.name), |
| ('description', self.description), |
| ('type_name', self.type.name), |
| ('properties', formatting.as_raw_dict(self.properties)))) |
| |
| def is_for_node_template(self, name): |
| for node_template in self.node_templates: |
| if node_template.name == name: |
| return True |
| for group_template in self.group_templates: |
| if group_template.contains_node_template(name): |
| return True |
| return False |
| |
| def is_for_group_template(self, name): |
| for group_template in self.group_templates: |
| if group_template.name == name: |
| return True |
| return False |
| |
| |
| class SubstitutionTemplateBase(TemplateModelMixin): |
| """ |
| Template for creating a :class:`Substitution` instance, which exposes an entire instantiated |
| service as a single node. |
| """ |
| |
| __tablename__ = 'substitution_template' |
| |
| __private_fields__ = ('node_type_fk',) |
| |
| # region one_to_many relationships |
| |
| @declared_attr |
| def substitutions(cls): |
| """ |
| Instantiated substitutions. |
| |
| :type: [:class:`Substitution`] |
| """ |
| return relationship.one_to_many(cls, 'substitution') |
| |
| @declared_attr |
| def mappings(cls): |
| """ |
| Map requirement and capabilities to exposed node. |
| |
| :type: {:obj:`basestring`: :class:`SubstitutionTemplateMapping`} |
| """ |
| return relationship.one_to_many(cls, 'substitution_template_mapping', dict_key='name') |
| |
| # endregion |
| |
| # region many_to_one relationships |
| |
| @declared_attr |
| def node_type(cls): |
| """ |
| Exposed node type. |
| |
| :type: :class:`Type` |
| """ |
| return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP) |
| |
| # endregion |
| |
| # region foreign keys |
| |
| @declared_attr |
| def node_type_fk(cls): |
| """For SubstitutionTemplate many-to-one to Type""" |
| return relationship.foreign_key('type') |
| |
| # endregion |
| |
| @property |
| def as_raw(self): |
| return collections.OrderedDict(( |
| ('node_type_name', self.node_type.name), |
| ('mappings', formatting.as_raw_dict(self.mappings)))) |
| |
| |
| class SubstitutionTemplateMappingBase(TemplateModelMixin): |
| """ |
| Used by :class:`SubstitutionTemplate` to map a capability template or a requirement template to |
| the exposed node. |
| |
| The :attr:`name` field should match the capability or requirement name on the exposed node's |
| type. |
| |
| Only one of :attr:`capability_template` and :attr:`requirement_template` can be set. |
| """ |
| |
| __tablename__ = 'substitution_template_mapping' |
| |
| __private_fields__ = ('substitution_template_fk', |
| 'capability_template_fk', |
| 'requirement_template_fk') |
| |
| # region one_to_one relationships |
| |
| @declared_attr |
| def capability_template(cls): |
| """ |
| Capability template to expose (can be ``None``). |
| |
| :type: :class:`CapabilityTemplate` |
| """ |
| return relationship.one_to_one( |
| cls, 'capability_template', back_populates=relationship.NO_BACK_POP) |
| |
| @declared_attr |
| def requirement_template(cls): |
| """ |
| Requirement template to expose (can be ``None``). |
| |
| :type: :class:`RequirementTemplate` |
| """ |
| return relationship.one_to_one( |
| cls, 'requirement_template', back_populates=relationship.NO_BACK_POP) |
| |
| # endregion |
| |
| # region many_to_one relationships |
| |
| @declared_attr |
| def substitution_template(cls): |
| """ |
| Containing substitution template. |
| |
| :type: :class:`SubstitutionTemplate` |
| """ |
| return relationship.many_to_one(cls, 'substitution_template', back_populates='mappings') |
| |
| # endregion |
| |
| # region foreign keys |
| |
| @declared_attr |
| def substitution_template_fk(cls): |
| """For SubstitutionTemplate one-to-many to SubstitutionTemplateMapping""" |
| return relationship.foreign_key('substitution_template') |
| |
| @declared_attr |
| def capability_template_fk(cls): |
| """For SubstitutionTemplate one-to-one to CapabilityTemplate""" |
| return relationship.foreign_key('capability_template', nullable=True) |
| |
| @declared_attr |
| def requirement_template_fk(cls): |
| """For SubstitutionTemplate one-to-one to RequirementTemplate""" |
| return relationship.foreign_key('requirement_template', nullable=True) |
| |
| # endregion |
| |
| @property |
| def as_raw(self): |
| return collections.OrderedDict(( |
| ('name', self.name),)) |
| |
| |
| class RequirementTemplateBase(TemplateModelMixin): |
| """ |
| Template for creating :class:`Relationship` instances, which are optionally-typed edges in the |
| service topology, connecting a :class:`Node` to a :class:`Capability` of another node. |
| |
| Note that there is no equivalent "Requirement" instance model. Instead, during instantiation a |
| requirement template is matched with a capability and a :class:`Relationship` is instantiated. |
| |
| A requirement template *must* target a :class:`CapabilityType` or a capability name. It can |
| optionally target a specific :class:`NodeType` or :class:`NodeTemplate`. |
| |
| Requirement templates may optionally contain a :class:`RelationshipTemplate`. If they do not, |
| a :class:`Relationship` will be instantiated with default values. |
| """ |
| |
| __tablename__ = 'requirement_template' |
| |
| __private_fields__ = ('target_capability_type_fk', |
| 'target_node_template_fk', |
| 'target_node_type_fk', |
| 'relationship_template_fk', |
| 'node_template_fk') |
| |
| # region one_to_one relationships |
| |
| @declared_attr |
| def target_capability_type(cls): |
| """ |
| Target capability type. |
| |
| :type: :class:`CapabilityType` |
| """ |
| return relationship.one_to_one(cls, |
| 'type', |
| fk='target_capability_type_fk', |
| back_populates=relationship.NO_BACK_POP) |
| |
| @declared_attr |
| def target_node_template(cls): |
| """ |
| Target node template (can be ``None``). |
| |
| :type: :class:`NodeTemplate` |
| """ |
| return relationship.one_to_one(cls, |
| 'node_template', |
| fk='target_node_template_fk', |
| back_populates=relationship.NO_BACK_POP) |
| |
| @declared_attr |
| def relationship_template(cls): |
| """ |
| Associated relationship template (can be ``None``). |
| |
| :type: :class:`RelationshipTemplate` |
| """ |
| return relationship.one_to_one(cls, 'relationship_template') |
| |
| # endregion |
| |
| # region one_to_many relationships |
| |
| @declared_attr |
| def relationships(cls): |
| """ |
| Instantiated relationships. |
| |
| :type: [:class:`Relationship`] |
| """ |
| return relationship.one_to_many(cls, 'relationship') |
| |
| # endregion |
| |
| # region many_to_one relationships |
| |
| @declared_attr |
| def node_template(cls): |
| """ |
| Containing node template. |
| |
| :type: :class:`NodeTemplate` |
| """ |
| return relationship.many_to_one(cls, 'node_template', fk='node_template_fk') |
| |
| @declared_attr |
| def target_node_type(cls): |
| """ |
| Target node type (can be ``None``). |
| |
| :type: :class:`Type` |
| """ |
| return relationship.many_to_one( |
| cls, 'type', fk='target_node_type_fk', back_populates=relationship.NO_BACK_POP) |
| |
| # endregion |
| |
| # region foreign keys |
| |
| @declared_attr |
| def target_node_type_fk(cls): |
| """For RequirementTemplate many-to-one to Type""" |
| return relationship.foreign_key('type', nullable=True) |
| |
| @declared_attr |
| def target_node_template_fk(cls): |
| """For RequirementTemplate one-to-one to NodeTemplate""" |
| return relationship.foreign_key('node_template', nullable=True) |
| |
| @declared_attr |
| def target_capability_type_fk(cls): |
| """For RequirementTemplate one-to-one to Type""" |
| return relationship.foreign_key('type', nullable=True) |
| |
| @declared_attr |
| def node_template_fk(cls): |
| """For NodeTemplate one-to-many to RequirementTemplate""" |
| return relationship.foreign_key('node_template') |
| |
| @declared_attr |
| def relationship_template_fk(cls): |
| """For RequirementTemplate one-to-one to RelationshipTemplate""" |
| return relationship.foreign_key('relationship_template', nullable=True) |
| |
| # endregion |
| |
| target_capability_name = Column(Text, doc=""" |
| Target capability name in node template or node type (can be ``None``). |
| |
| :type: :obj:`basestring` |
| """) |
| |
| target_node_template_constraints = Column(PickleType, doc=""" |
| Constraints for filtering relationship targets. |
| |
| :type: [:class:`NodeTemplateConstraint`] |
| """) |
| |
| @property |
| def as_raw(self): |
| return collections.OrderedDict(( |
| ('name', self.name), |
| ('target_node_type_name', self.target_node_type.name |
| if self.target_node_type is not None else None), |
| ('target_node_template_name', self.target_node_template.name |
| if self.target_node_template is not None else None), |
| ('target_capability_type_name', self.target_capability_type.name |
| if self.target_capability_type is not None else None), |
| ('target_capability_name', self.target_capability_name), |
| ('relationship_template', formatting.as_raw(self.relationship_template)))) |
| |
| |
| class RelationshipTemplateBase(TemplateModelMixin): |
| """ |
| Optional addition to a :class:`RequirementTemplate`. |
| |
| Note that a relationship template here is not exactly equivalent to a relationship template |
| entity in TOSCA. For example, a TOSCA requirement specifying a relationship type rather than a |
| relationship template would still be represented here as a relationship template. |
| """ |
| |
| __tablename__ = 'relationship_template' |
| |
| __private_fields__ = ('type_fk',) |
| |
| # region one_to_many relationships |
| |
| @declared_attr |
| def relationships(cls): |
| """ |
| Instantiated relationships. |
| |
| :type: [:class:`Relationship`] |
| """ |
| return relationship.one_to_many(cls, 'relationship') |
| |
| @declared_attr |
| def interface_templates(cls): |
| """ |
| Associated interface templates. |
| |
| :type: {:obj:`basestring`: :class:`InterfaceTemplate`} |
| """ |
| return relationship.one_to_many(cls, 'interface_template', dict_key='name') |
| |
| @declared_attr |
| def properties(cls): |
| """ |
| Declarations for associated immutable parameters. |
| |
| :type: {:obj:`basestring`: :class:`Property`} |
| """ |
| return relationship.one_to_many(cls, 'property', dict_key='name') |
| |
| # endregion |
| |
| # region many_to_one relationships |
| |
| @declared_attr |
| def type(cls): |
| """ |
| Relationship type. |
| |
| :type: :class:`Type` |
| """ |
| return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP) |
| |
| # endregion |
| |
| # region foreign keys |
| |
| @declared_attr |
| def type_fk(cls): |
| """For RelationshipTemplate many-to-one to Type""" |
| return relationship.foreign_key('type', nullable=True) |
| |
| # endregion |
| |
| description = Column(Text, doc=""" |
| Human-readable description. |
| |
| :type: :obj:`basestring` |
| """) |
| |
| @property |
| def as_raw(self): |
| return collections.OrderedDict(( |
| ('type_name', self.type.name if self.type is not None else None), |
| ('name', self.name), |
| ('description', self.description), |
| ('properties', formatting.as_raw_dict(self.properties)), |
| ('interface_templates', formatting.as_raw_list(self.interface_templates)))) |
| |
| |
| class CapabilityTemplateBase(TemplateModelMixin): |
| """ |
| Template for creating :class:`Capability` instances, typed attachments which serve two purposes: |
| to provide extra properties and attributes to :class:`Node` instances, and to expose targets for |
| :class:`Relationship` instances from other nodes. |
| """ |
| |
| __tablename__ = 'capability_template' |
| |
| __private_fields__ = ('type_fk', |
| 'node_template_fk') |
| |
| # region one_to_many relationships |
| |
| @declared_attr |
| def capabilities(cls): |
| """ |
| Instantiated capabilities. |
| |
| :type: [:class:`Capability`] |
| """ |
| return relationship.one_to_many(cls, 'capability') |
| |
| @declared_attr |
| def properties(cls): |
| """ |
| Declarations for associated immutable parameters. |
| |
| :type: {:obj:`basestring`: :class:`Property`} |
| """ |
| return relationship.one_to_many(cls, 'property', dict_key='name') |
| |
| # endregion |
| |
| # region many_to_one relationships |
| |
| @declared_attr |
| def node_template(cls): |
| """ |
| Containing node template. |
| |
| :type: :class:`NodeTemplate` |
| """ |
| return relationship.many_to_one(cls, 'node_template') |
| |
| @declared_attr |
| def type(cls): |
| """ |
| Capability type. |
| |
| :type: :class:`Type` |
| """ |
| return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP) |
| |
| # endregion |
| |
| # region many_to_many relationships |
| |
| @declared_attr |
| def valid_source_node_types(cls): |
| """ |
| Reject requirements that are not from these node types. |
| |
| :type: [:class:`Type`] |
| """ |
| return relationship.many_to_many(cls, 'type', prefix='valid_sources') |
| |
| # endregion |
| |
| # region foreign keys |
| |
| @declared_attr |
| def type_fk(cls): |
| """For CapabilityTemplate many-to-one to Type""" |
| return relationship.foreign_key('type') |
| |
| @declared_attr |
| def node_template_fk(cls): |
| """For NodeTemplate one-to-many to CapabilityTemplate""" |
| return relationship.foreign_key('node_template') |
| |
| # endregion |
| |
| description = Column(Text, doc=""" |
| Human-readable description. |
| |
| :type: :obj:`basestring` |
| """) |
| |
| min_occurrences = Column(Integer, default=None, doc=""" |
| Minimum number of requirement matches required. |
| |
| :type: :obj:`int` |
| """) |
| |
| max_occurrences = Column(Integer, default=None, doc=""" |
| Maximum number of requirement matches allowed. |
| |
| :type: :obj:`int` |
| """) |
| |
| @property |
| def as_raw(self): |
| return collections.OrderedDict(( |
| ('name', self.name), |
| ('description', self.description), |
| ('type_name', self.type.name), |
| ('min_occurrences', self.min_occurrences), |
| ('max_occurrences', self.max_occurrences), |
| ('valid_source_node_types', [v.name for v in self.valid_source_node_types]), |
| ('properties', formatting.as_raw_dict(self.properties)))) |
| |
| |
| class InterfaceTemplateBase(TemplateModelMixin): |
| """ |
| Template for creating :class:`Interface` instances, which are typed bundles of |
| :class:`Operation` instances. |
| |
| Can be associated with a :class:`NodeTemplate`, a :class:`GroupTemplate`, or a |
| :class:`RelationshipTemplate`. |
| """ |
| |
| __tablename__ = 'interface_template' |
| |
| __private_fields__ = ('type_fk', |
| 'node_template_fk', |
| 'group_template_fk', |
| 'relationship_template_fk') |
| |
| # region one_to_many relationships |
| |
| @declared_attr |
| def inputs(cls): |
| """ |
| Declarations for externally provided parameters that can be used by all operations of the |
| interface. |
| |
| :type: {:obj:`basestring`: :class:`Input`} |
| """ |
| return relationship.one_to_many(cls, 'input', dict_key='name') |
| |
| @declared_attr |
| def interfaces(cls): |
| """ |
| Instantiated interfaces. |
| |
| :type: [:class:`Interface`] |
| """ |
| return relationship.one_to_many(cls, 'interface') |
| |
| @declared_attr |
| def operation_templates(cls): |
| """ |
| Associated operation templates. |
| |
| :type: {:obj:`basestring`: :class:`OperationTemplate`} |
| """ |
| return relationship.one_to_many(cls, 'operation_template', dict_key='name') |
| |
| # endregion |
| |
| # region many_to_one relationships |
| |
| @declared_attr |
| def node_template(cls): |
| """ |
| Containing node template (can be ``None``). |
| |
| :type: :class:`NodeTemplate` |
| """ |
| return relationship.many_to_one(cls, 'node_template') |
| |
| @declared_attr |
| def group_template(cls): |
| """ |
| Containing group template (can be ``None``). |
| |
| :type: :class:`GroupTemplate` |
| """ |
| return relationship.many_to_one(cls, 'group_template') |
| |
| @declared_attr |
| def relationship_template(cls): |
| """ |
| Containing relationship template (can be ``None``). |
| |
| :type: :class:`RelationshipTemplate` |
| """ |
| return relationship.many_to_one(cls, 'relationship_template') |
| |
| @declared_attr |
| def type(cls): |
| """ |
| Interface type. |
| |
| :type: :class:`Type` |
| """ |
| return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP) |
| |
| # endregion |
| |
| # region foreign keys |
| |
| @declared_attr |
| def type_fk(cls): |
| """For InterfaceTemplate many-to-one to Type""" |
| return relationship.foreign_key('type') |
| |
| @declared_attr |
| def node_template_fk(cls): |
| """For NodeTemplate one-to-many to InterfaceTemplate""" |
| return relationship.foreign_key('node_template', nullable=True) |
| |
| @declared_attr |
| def group_template_fk(cls): |
| """For GroupTemplate one-to-many to InterfaceTemplate""" |
| return relationship.foreign_key('group_template', nullable=True) |
| |
| @declared_attr |
| def relationship_template_fk(cls): |
| """For RelationshipTemplate one-to-many to InterfaceTemplate""" |
| return relationship.foreign_key('relationship_template', nullable=True) |
| |
| # endregion |
| |
| description = Column(Text, doc=""" |
| Human-readable description. |
| |
| :type: :obj:`basestring` |
| """) |
| |
| @property |
| def as_raw(self): |
| return collections.OrderedDict(( |
| ('name', self.name), |
| ('description', self.description), |
| ('type_name', self.type.name), |
| ('inputs', formatting.as_raw_dict(self.inputs)), # pylint: disable=no-member |
| # TODO fix self.properties reference |
| ('operation_templates', formatting.as_raw_list(self.operation_templates)))) |
| |
| |
| class OperationTemplateBase(TemplateModelMixin): |
| """ |
| Template for creating :class:`Operation` instances, which are entry points to Python functions |
| called as part of a workflow execution. |
| """ |
| |
| __tablename__ = 'operation_template' |
| |
| __private_fields__ = ('service_template_fk', |
| 'interface_template_fk', |
| 'plugin_fk') |
| |
| # region one_to_one relationships |
| |
| @declared_attr |
| def plugin_specification(cls): |
| """ |
| Associated plugin specification. |
| |
| :type: :class:`PluginSpecification` |
| """ |
| return relationship.one_to_one( |
| cls, 'plugin_specification', back_populates=relationship.NO_BACK_POP) |
| |
| # endregion |
| |
| # region one_to_many relationships |
| |
| @declared_attr |
| def operations(cls): |
| """ |
| Instantiated operations. |
| |
| :type: [:class:`Operation`] |
| """ |
| return relationship.one_to_many(cls, 'operation') |
| |
| @declared_attr |
| def inputs(cls): |
| """ |
| Declarations for parameters provided to the :attr:`implementation`. |
| |
| :type: {:obj:`basestring`: :class:`Input`} |
| """ |
| return relationship.one_to_many(cls, 'input', dict_key='name') |
| |
| @declared_attr |
| def configurations(cls): |
| """ |
| Configuration parameters for the operation instance Python :attr:`function`. |
| |
| :type: {:obj:`basestring`: :class:`Configuration`} |
| """ |
| return relationship.one_to_many(cls, 'configuration', dict_key='name') |
| |
| # endregion |
| |
| # region many_to_one relationships |
| |
| @declared_attr |
| def service_template(cls): |
| """ |
| Containing service template (can be ``None``). For workflow operation templates. |
| |
| :type: :class:`ServiceTemplate` |
| """ |
| return relationship.many_to_one(cls, 'service_template', |
| back_populates='workflow_templates') |
| |
| @declared_attr |
| def interface_template(cls): |
| """ |
| Containing interface template (can be ``None``). |
| |
| :type: :class:`InterfaceTemplate` |
| """ |
| return relationship.many_to_one(cls, 'interface_template') |
| |
| # endregion |
| |
| # region foreign keys |
| |
| @declared_attr |
| def service_template_fk(cls): |
| """For ServiceTemplate one-to-many to OperationTemplate""" |
| return relationship.foreign_key('service_template', nullable=True) |
| |
| @declared_attr |
| def interface_template_fk(cls): |
| """For InterfaceTemplate one-to-many to OperationTemplate""" |
| return relationship.foreign_key('interface_template', nullable=True) |
| |
| @declared_attr |
| def plugin_specification_fk(cls): |
| """For OperationTemplate one-to-one to PluginSpecification""" |
| return relationship.foreign_key('plugin_specification', nullable=True) |
| |
| # endregion |
| |
| description = Column(Text, doc=""" |
| Human-readable description. |
| |
| :type: :obj:`basestring` |
| """) |
| |
| relationship_edge = Column(Boolean, doc=""" |
| When ``True`` specifies that the operation is on the relationship's target edge; ``False`` is |
| the source edge (only used by operations on relationships) |
| |
| :type: :obj:`bool` |
| """) |
| |
| implementation = Column(Text, doc=""" |
| Implementation (usually the name of an artifact). |
| |
| :type: :obj:`basestring` |
| """) |
| |
| dependencies = Column(modeling_types.StrictList(item_cls=basestring), doc=""" |
| Dependencies (usually names of artifacts). |
| |
| :type: [:obj:`basestring`] |
| """) |
| |
| function = Column(Text, doc=""" |
| Full path to Python function. |
| |
| :type: :obj:`basestring` |
| """) |
| |
| executor = Column(Text, doc=""" |
| Name of executor. |
| |
| :type: :obj:`basestring` |
| """) |
| |
| max_attempts = Column(Integer, doc=""" |
| Maximum number of attempts allowed in case of task failure. |
| |
| :type: :obj:`int` |
| """) |
| |
| retry_interval = Column(Integer, doc=""" |
| Interval between task retry attemps (in seconds). |
| |
| :type: :obj:`float` |
| """) |
| |
| @property |
| def as_raw(self): |
| return collections.OrderedDict(( |
| ('name', self.name), |
| ('description', self.description), |
| ('implementation', self.implementation), |
| ('dependencies', self.dependencies), |
| ('inputs', formatting.as_raw_dict(self.inputs)))) |
| |
| |
| class ArtifactTemplateBase(TemplateModelMixin): |
| """ |
| Template for creating an :class:`Artifact` instance, which is a typed file, either provided in a |
| CSAR or downloaded from a repository. |
| """ |
| |
| __tablename__ = 'artifact_template' |
| |
| __private_fields__ = ('type_fk', |
| 'node_template_fk') |
| |
| # region one_to_many relationships |
| |
| @declared_attr |
| def artifacts(cls): |
| """ |
| Instantiated artifacts. |
| |
| :type: [:class:`Artifact`] |
| """ |
| return relationship.one_to_many(cls, 'artifact') |
| |
| @declared_attr |
| def properties(cls): |
| """ |
| Declarations for associated immutable parameters. |
| |
| :type: {:obj:`basestring`: :class:`Property`} |
| """ |
| return relationship.one_to_many(cls, 'property', dict_key='name') |
| |
| # endregion |
| |
| # region many_to_one relationships |
| |
| @declared_attr |
| def node_template(cls): |
| """ |
| Containing node template. |
| |
| :type: :class:`NodeTemplate` |
| """ |
| return relationship.many_to_one(cls, 'node_template') |
| |
| @declared_attr |
| def type(cls): |
| """ |
| Artifact type. |
| |
| :type: :class:`Type` |
| """ |
| return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP) |
| |
| # endregion |
| |
| # region foreign keys |
| |
| @declared_attr |
| def type_fk(cls): |
| """For ArtifactTemplate many-to-one to Type""" |
| return relationship.foreign_key('type') |
| |
| @declared_attr |
| def node_template_fk(cls): |
| """For NodeTemplate one-to-many to ArtifactTemplate""" |
| return relationship.foreign_key('node_template') |
| |
| # endregion |
| |
| description = Column(Text, doc=""" |
| Human-readable description. |
| |
| :type: :obj:`basestring` |
| """) |
| |
| source_path = Column(Text, doc=""" |
| Source path (in CSAR or repository). |
| |
| :type: :obj:`basestring` |
| """) |
| |
| target_path = Column(Text, doc=""" |
| Path at which to install at destination. |
| |
| :type: :obj:`basestring` |
| """) |
| |
| repository_url = Column(Text, doc=""" |
| Repository URL. |
| |
| :type: :obj:`basestring` |
| """) |
| |
| repository_credential = Column(modeling_types.StrictDict(basestring, basestring), doc=""" |
| Credentials for accessing the repository. |
| |
| :type: {:obj:`basestring`, :obj:`basestring`} |
| """) |
| |
| @property |
| def as_raw(self): |
| return collections.OrderedDict(( |
| ('name', self.name), |
| ('description', self.description), |
| ('type_name', self.type.name), |
| ('source_path', self.source_path), |
| ('target_path', self.target_path), |
| ('repository_url', self.repository_url), |
| ('repository_credential', formatting.as_agnostic(self.repository_credential)), |
| ('properties', formatting.as_raw_dict(self.properties)))) |
| |
| |
| class PluginSpecificationBase(TemplateModelMixin): |
| """ |
| Requirement for a :class:`Plugin`. |
| |
| The actual plugin to be selected depends on those currently installed in ARIA. |
| """ |
| |
| __tablename__ = 'plugin_specification' |
| |
| __private_fields__ = ('service_template_fk', |
| 'plugin_fk') |
| |
| # region many_to_one relationships |
| |
| @declared_attr |
| def service_template(cls): |
| """ |
| Containing service template. |
| |
| :type: :class:`ServiceTemplate` |
| """ |
| return relationship.many_to_one(cls, 'service_template') |
| |
| @declared_attr |
| def plugin(cls): # pylint: disable=method-hidden |
| """ |
| Matched plugin. |
| |
| :type: :class:`Plugin` |
| """ |
| return relationship.many_to_one(cls, 'plugin', back_populates=relationship.NO_BACK_POP) |
| |
| # endregion |
| |
| # region foreign keys |
| |
| @declared_attr |
| def service_template_fk(cls): |
| """For ServiceTemplate one-to-many to PluginSpecification""" |
| return relationship.foreign_key('service_template', nullable=True) |
| |
| @declared_attr |
| def plugin_fk(cls): |
| """For PluginSpecification many-to-one to Plugin""" |
| return relationship.foreign_key('plugin', nullable=True) |
| |
| # endregion |
| |
| version = Column(Text, doc=""" |
| Minimum plugin version. |
| |
| :type: :obj:`basestring` |
| """) |
| |
| enabled = Column(Boolean, nullable=False, default=True, doc=""" |
| Whether the plugin is enabled. |
| |
| :type: :obj:`bool` |
| """) |
| |
| @property |
| def as_raw(self): |
| return collections.OrderedDict(( |
| ('name', self.name), |
| ('version', self.version), |
| ('enabled', self.enabled))) |