Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id B6C89200C31 for ; Wed, 22 Feb 2017 00:49:46 +0100 (CET) Received: by cust-asf.ponee.io (Postfix) id B3BB8160B74; Tue, 21 Feb 2017 23:49:46 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 12A44160B68 for ; Wed, 22 Feb 2017 00:49:44 +0100 (CET) Received: (qmail 18526 invoked by uid 500); 21 Feb 2017 23:49:44 -0000 Mailing-List: contact dev-help@ariatosca.incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@ariatosca.incubator.apache.org Delivered-To: mailing list dev@ariatosca.incubator.apache.org Received: (qmail 18513 invoked by uid 99); 21 Feb 2017 23:49:44 -0000 Received: from pnap-us-west-generic-nat.apache.org (HELO spamd1-us-west.apache.org) (209.188.14.142) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 21 Feb 2017 23:49:44 +0000 Received: from localhost (localhost [127.0.0.1]) by spamd1-us-west.apache.org (ASF Mail Server at spamd1-us-west.apache.org) with ESMTP id BE059C67D0 for ; Tue, 21 Feb 2017 23:49:43 +0000 (UTC) X-Virus-Scanned: Debian amavisd-new at spamd1-us-west.apache.org X-Spam-Flag: NO X-Spam-Score: -3.221 X-Spam-Level: X-Spam-Status: No, score=-3.221 tagged_above=-999 required=6.31 tests=[KAM_ASCII_DIVIDERS=0.8, KAM_LAZY_DOMAIN_SECURITY=1, RCVD_IN_DNSWL_HI=-5, RCVD_IN_MSPIKE_H3=-0.01, RCVD_IN_MSPIKE_WL=-0.01, RP_MATCHES_RCVD=-0.001] autolearn=disabled Received: from mx1-lw-eu.apache.org ([10.40.0.8]) by localhost (spamd1-us-west.apache.org [10.40.0.7]) (amavisd-new, port 10024) with ESMTP id PDKUWwHdsoWt for ; Tue, 21 Feb 2017 23:49:41 +0000 (UTC) Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by mx1-lw-eu.apache.org (ASF Mail Server at mx1-lw-eu.apache.org) with SMTP id 64F405F4A8 for ; Tue, 21 Feb 2017 23:49:39 +0000 (UTC) Received: (qmail 18504 invoked by uid 99); 21 Feb 2017 23:49:38 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 21 Feb 2017 23:49:38 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 7893FDFC1C; Tue, 21 Feb 2017 23:49:38 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: emblemparade@apache.org To: dev@ariatosca.incubator.apache.org Message-Id: <08d86530b7624a6db46c1d28e59329e6@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: incubator-ariatosca git commit: Added RelationshipTemplate; added one-to-many support Date: Tue, 21 Feb 2017 23:49:38 +0000 (UTC) archived-at: Tue, 21 Feb 2017 23:49:46 -0000 Repository: incubator-ariatosca Updated Branches: refs/heads/ARIA-105-integrate-modeling 58e105237 -> f28b0af15 Added RelationshipTemplate; added one-to-many support Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/f28b0af1 Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/f28b0af1 Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/f28b0af1 Branch: refs/heads/ARIA-105-integrate-modeling Commit: f28b0af157e13c41482921ecba03409c07ca2660 Parents: 58e1052 Author: Tal Liron Authored: Tue Feb 21 17:49:14 2017 -0600 Committer: Tal Liron Committed: Tue Feb 21 17:49:14 2017 -0600 ---------------------------------------------------------------------- aria/modeling/instance_elements.py | 42 ++- aria/modeling/model.py | 10 +- aria/modeling/structure.py | 24 +- aria/modeling/template_elements.py | 292 ++++++++++++++++--- aria/modeling/type.py | 2 +- .../simple_v1_0/modeling/__init__.py | 49 +++- 6 files changed, 354 insertions(+), 65 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/f28b0af1/aria/modeling/instance_elements.py ---------------------------------------------------------------------- diff --git a/aria/modeling/instance_elements.py b/aria/modeling/instance_elements.py index 0666c8a..5ebe692 100644 --- a/aria/modeling/instance_elements.py +++ b/aria/modeling/instance_elements.py @@ -33,11 +33,11 @@ from . import ( type as aria_types ) + # pylint: disable=no-self-argument, no-member, abstract-method # region Element instances - class ServiceInstanceBase(structure.ModelMixin): __tablename__ = 'service_instance' @@ -64,6 +64,7 @@ class ServiceInstanceBase(structure.ModelMixin): # endregion # region foreign keys + @declared_attr def substitution_fk(cls): return cls.foreign_key('substitution', nullable=True) @@ -75,12 +76,15 @@ class ServiceInstanceBase(structure.ModelMixin): # endregion # region one-to-one relationships + @declared_attr def substitution(cls): return cls.one_to_one_relationship('substitution') + # endregion # region many-to-one relationships + @declared_attr def service_template(cls): return cls.many_to_one_relationship('service_template') @@ -184,6 +188,7 @@ class OperationBase(structure.ModelMixin): return cls.foreign_key('interface', nullable=True) # endregion + description = Column(Text) implementation = Column(Text) dependencies = Column(aria_types.StrictList(item_cls=basestring)) @@ -195,6 +200,7 @@ class OperationBase(structure.ModelMixin): operation = Column(Boolean) # region many-to-one relationships + @declared_attr def service_instance(cls): return cls.many_to_one_relationship('service_instance') @@ -202,6 +208,9 @@ class OperationBase(structure.ModelMixin): @declared_attr def interface(cls): return cls.many_to_one_relationship('interface') + + # endregion + # region many-to-many relationships @declared_attr @@ -268,6 +277,7 @@ class InterfaceBase(structure.ModelMixin): # region foreign_keys + @declared_attr def group_fk(cls): return cls.foreign_key('group', nullable=True) @@ -363,11 +373,13 @@ class CapabilityBase(structure.ModelMixin): __private_fields__ = ['node_fk'] # region foreign_keys + @declared_attr def node_fk(cls): return cls.foreign_key('node') # endregion + type_name = Column(Text) min_occurrences = Column(Integer, default=None) # optional @@ -375,14 +387,15 @@ class CapabilityBase(structure.ModelMixin): occurrences = Column(Integer, default=0) # region many-to-one relationships + @declared_attr def node(cls): return cls.many_to_one_relationship('node') # endregion - # region many-to-many relationships + @declared_attr def properties(cls): return cls.many_to_many_relationship('parameter', table_prefix='properties') @@ -469,13 +482,13 @@ class ArtifactBase(structure.ModelMixin): repository_credential = Column(aria_types.StrictDict(basestring, basestring)) # region many-to-one relationships + @declared_attr def node(cls): return cls.many_to_one_relationship('node') # endregion - # region many-to-many relationships @declared_attr @@ -547,11 +560,13 @@ class PolicyBase(structure.ModelMixin): return cls.foreign_key('service_instance') # endregion + type_name = Column(Text) target_node_ids = Column(aria_types.StrictList(basestring)) target_group_ids = Column(aria_types.StrictList(basestring)) # region many-to-one relationships + @declared_attr def service_instnce(cls): return cls.many_to_one_relationship('service_instance') @@ -629,6 +644,7 @@ class GroupPolicyBase(structure.ModelMixin): type_name = Column(Text) # region many-to-one relationships + @declared_attr def group(cls): return cls.many_to_one_relationship('group') @@ -636,6 +652,7 @@ class GroupPolicyBase(structure.ModelMixin): # end region # region many-to-many relationships + @declared_attr def properties(cls): return cls.many_to_many_relationship('parameter', table_prefix='properties') @@ -796,7 +813,6 @@ class SubstitutionBase(structure.ModelMixin): table_prefix='requirements', relationship_kwargs=dict(lazy='dynamic')) - # endregion @property @@ -828,9 +844,9 @@ class SubstitutionBase(structure.ModelMixin): utils.dump_dict_values(context, self.capabilities, 'Capability mappings') utils.dump_dict_values(context, self.requirements, 'Requirement mappings') - # endregion + # region Node instances class NodeBase(structure.ModelMixin): @@ -857,6 +873,7 @@ class NodeBase(structure.ModelMixin): 'node_template_fk'] # region foreign_keys + @declared_attr def service_instance_fk(cls): return cls.foreign_key('service_instance') @@ -875,6 +892,7 @@ class NodeBase(structure.ModelMixin): template_name = Column(Text) # region orchestrator required columns + runtime_properties = Column(aria_types.Dict) scaling_groups = Column(aria_types.List) state = Column(Text, nullable=False) @@ -912,9 +930,11 @@ class NodeBase(structure.ModelMixin): @declared_attr def service_template(cls): return association_proxy('service_instance', 'service_template') + # endregion # region many-to-one relationships + @declared_attr def service_instance(cls): return cls.many_to_one_relationship('service_instance') @@ -1091,11 +1111,15 @@ class GroupBase(structure.ModelMixin): member_group_ids = Column(aria_types.StrictList(basestring)) # region many-to-one relationships + @declared_attr def service_instance(cls): return cls.many_to_one_relationship('service_instance') + # endregion + # region many-to-many relationships + @declared_attr def properties(cls): return cls.many_to_many_relationship('parameter', table_prefix='properties') @@ -1147,8 +1171,8 @@ class GroupBase(structure.ModelMixin): # endregion -# region Relationship instances +# region Relationship instances class RelationshipBase(structure.ModelMixin): """ @@ -1179,7 +1203,8 @@ class RelationshipBase(structure.ModelMixin): type_name = Column(Text) template_name = Column(Text) - # # region orchestrator required columns + # region orchestrator required columns + source_position = Column(Integer) target_position = Column(Integer) @@ -1222,9 +1247,10 @@ class RelationshipBase(structure.ModelMixin): @declared_attr def target_node_name(cls): return association_proxy('target_node', cls.name_column_name()) + # endregion - # region many-to-many relationship + # region many-to-many relationships @declared_attr def properties(cls): http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/f28b0af1/aria/modeling/model.py ---------------------------------------------------------------------- diff --git a/aria/modeling/model.py b/aria/modeling/model.py index b16fed0..2777353 100644 --- a/aria/modeling/model.py +++ b/aria/modeling/model.py @@ -41,6 +41,7 @@ __all__ = ( 'GroupPolicyTriggerTemplate', 'RequirementTemplate', 'CapabilityTemplate', + 'RelationshipTemplate', 'Mapping', 'Substitution', @@ -68,8 +69,8 @@ aria_declarative_base = declarative_base(cls=structure.ModelIDMixin) # pylint: disable=abstract-method -# region elements +# region elements class Parameter(aria_declarative_base, elements.ParameterBase): pass @@ -137,8 +138,12 @@ class CapabilityTemplate(aria_declarative_base, template_elements.CapabilityTemp pass +class RelationshipTemplate(aria_declarative_base, template_elements.RelationshipTemplateBase): + pass + # endregion + # region instance models class Mapping(aria_declarative_base, instance_elements.MappingBase): @@ -192,9 +197,9 @@ class GroupPolicy(aria_declarative_base, instance_elements.GroupPolicyBase): class GroupPolicyTrigger(aria_declarative_base, instance_elements.GroupPolicyTriggerBase): pass - # endregion + # region orchestrator models class Execution(aria_declarative_base, orchestrator_elements.Execution): @@ -222,4 +227,5 @@ class Plugin(aria_declarative_base, orchestrator_elements.PluginBase): class Task(aria_declarative_base, orchestrator_elements.TaskBase): pass + # endregion http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/f28b0af1/aria/modeling/structure.py ---------------------------------------------------------------------- diff --git a/aria/modeling/structure.py b/aria/modeling/structure.py index eacdb44..8d2401a 100644 --- a/aria/modeling/structure.py +++ b/aria/modeling/structure.py @@ -28,6 +28,7 @@ classes: """ from sqlalchemy.orm import relationship, backref +from sqlalchemy.orm.collections import attribute_mapped_collection from sqlalchemy.ext import associationproxy from sqlalchemy import ( Column, @@ -138,6 +139,17 @@ class ModelMixin(ModelElementBase): backref=backref(backreference or cls.__tablename__, uselist=False)) @classmethod + def one_to_many_relationship(cls, other_table_name, backreference=None, key_column_name=None): + # See: http://docs.sqlalchemy.org/en/latest/orm/collections.html + collection_class = attribute_mapped_collection(key_column_name) \ + if key_column_name \ + else list + + return relationship(lambda: cls._get_cls_by_tablename(other_table_name), + backref=backref(backreference or cls.__tablename__, uselist=False), + collection_class=collection_class) + + @classmethod def many_to_one_relationship(cls, parent_table_name, foreign_key_column=None, @@ -184,7 +196,8 @@ class ModelMixin(ModelElementBase): post_update=True) @classmethod - def many_to_many_relationship(cls, other_table_name, table_prefix, relationship_kwargs=None): + def many_to_many_relationship(cls, other_table_name, table_prefix, key_column_name=None, + relationship_kwargs=None): """Return a many-to-many SQL relationship object Notes: @@ -194,7 +207,8 @@ class ModelMixin(ModelElementBase): :param cls: The class of the table we're connecting from :param other_table_name: The class of the table we're connecting to :param table_prefix: Custom prefix for the helper table name and the - backreference name + backreference name + :param key_column_name: If provided, will use a dict class with this column as the key """ current_table_name = cls.__tablename__ current_column_name = '{0}_id'.format(current_table_name) @@ -219,10 +233,16 @@ class ModelMixin(ModelElementBase): other_foreign_key ) + # See: http://docs.sqlalchemy.org/en/latest/orm/collections.html + collection_class = attribute_mapped_collection(key_column_name) \ + if key_column_name \ + else list + return relationship( lambda: cls._get_cls_by_tablename(other_table_name), secondary=secondary_table, backref=backref(backref_name), + collection_class=collection_class, **(relationship_kwargs or {}) ) http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/f28b0af1/aria/modeling/template_elements.py ---------------------------------------------------------------------- diff --git a/aria/modeling/template_elements.py b/aria/modeling/template_elements.py index 60e31f8..8d750b1 100644 --- a/aria/modeling/template_elements.py +++ b/aria/modeling/template_elements.py @@ -12,6 +12,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. + from copy import deepcopy from types import FunctionType @@ -25,9 +26,8 @@ from sqlalchemy import ( from sqlalchemy.ext.associationproxy import association_proxy from sqlalchemy.ext.declarative import declared_attr -from aria.parser import validation -from aria.utils import collections, formatting, console - +from ..parser import validation +from ..utils import collections, formatting, console from . import ( utils, instance_elements, @@ -35,13 +35,31 @@ from . import ( type as aria_type ) -# pylint: disable=no-self-argument, no-member, abstract-method +# pylint: disable=no-self-argument, no-member, abstract-method # region Element templates - class ServiceTemplateBase(structure.ModelMixin): + """ + A service model is a normalized service template from which :class:`ServiceInstance` instances + can be created. + + It is usually created by various DSL parsers, such as ARIA's TOSCA extension. However, it + can also be created programmatically. + + Properties: + + * :code:`description`: Human-readable description + * :code:`metadata`: :class:`Metadata` + * :code:`node_templates`: Dict of :class:`NodeTemplate` + * :code:`group_templates`: Dict of :class:`GroupTemplate` + * :code:`policy_templates`: Dict of :class:`PolicyTemplate` + * :code:`substitution_template`: :class:`SubstituionTemplate` + * :code:`inputs`: Dict of :class:`Parameter` + * :code:`outputs`: Dict of :class:`Parameter` + * :code:`operation_templates`: Dict of :class:`Operation` + """ __tablename__ = 'service_template' @@ -60,6 +78,7 @@ class ServiceTemplateBase(structure.ModelMixin): # endregion # region foreign keys + @declared_attr def substitution_template_fk(cls): return cls.foreign_key('substitution_template', nullable=True) @@ -67,20 +86,24 @@ class ServiceTemplateBase(structure.ModelMixin): # endregion # region one-to-one relationships + @declared_attr def substitution_template(cls): return cls.one_to_one_relationship('substitution_template') + # endregion # region many-to-many relationships @declared_attr def inputs(cls): - return cls.many_to_many_relationship('parameter', table_prefix='inputs') + return cls.many_to_many_relationship('parameter', table_prefix='inputs', + key_column_name='name') @declared_attr def outputs(cls): - return cls.many_to_many_relationship('parameter', table_prefix='outputs') + return cls.many_to_many_relationship('parameter', table_prefix='outputs', + key_column_name='name') # endregion @@ -173,10 +196,23 @@ class ServiceTemplateBase(structure.ModelMixin): class InterfaceTemplateBase(structure.ModelMixin): + """ + A typed set of :class:`OperationTemplate`. + + Properties: + + * :code:`name`: Name + * :code:`description`: Description + * :code:`type_name`: Must be represented in the :class:`ModelingContext` + * :code:`inputs`: Dict of :class:`Parameter` + * :code:`operation_templates`: Dict of :class:`OperationTemplate` + """ + __tablename__ = 'interface_template' __private_fields__ = ['node_template_fk', - 'group_template_fk'] + 'group_template_fk', + 'relationship_template_fk'] # region foreign keys @@ -188,15 +224,28 @@ class InterfaceTemplateBase(structure.ModelMixin): def group_template_fk(cls): return cls.foreign_key('group_template', nullable=True) + @declared_attr + def relationship_template_fk(cls): + return cls.foreign_key('relationship_template', nullable=True) + # endregion description = Column(Text) type_name = Column(Text) - # region many-to-one relationship + # region one-to-many relationships + @declared_attr - def node_template(cls): - return cls.many_to_one_relationship('node_template') + def operation_templates(cls): + return cls.one_to_many_relationship('operation_template', key_column_name='name') + + # endregion + + # region many-to-one relationships + + #@declared_attr + #def node_template(cls): + # return cls.many_to_one_relationship('node_template') @declared_attr def group_template(cls): @@ -208,12 +257,13 @@ class InterfaceTemplateBase(structure.ModelMixin): @declared_attr def inputs(cls): - return cls.many_to_many_relationship('parameter', table_prefix='inputs') + return cls.many_to_many_relationship('parameter', table_prefix='inputs', + key_column_name='name') @declared_attr def properties(cls): return cls.many_to_many_relationship('parameter', table_prefix='properties', - collection_class=dict) + key_column_name='name') # endregion @@ -259,6 +309,21 @@ class InterfaceTemplateBase(structure.ModelMixin): class OperationTemplateBase(structure.ModelMixin): + """ + An operation in a :class:`InterfaceTemplate`. + + Properties: + + * :code:`name`: Name + * :code:`description`: Description + * :code:`implementation`: Implementation string (interpreted by the orchestrator) + * :code:`dependencies`: List of strings (interpreted by the orchestrator) + * :code:`executor`: Executor string (interpreted by the orchestrator) + * :code:`max_retries`: Maximum number of retries allowed in case of failure + * :code:`retry_interval`: Interval between retries + * :code:`inputs`: Dict of :class:`Parameter` + """ + __tablename__ = 'operation_template' __private_fields__ = ['service_template_fk', @@ -284,24 +349,30 @@ class OperationTemplateBase(structure.ModelMixin): retry_interval = Column(Integer) # region orchestrator required columns + plugin = Column(Text) operation = Column(Boolean) + # endregion + # region many-to-one relationships + @declared_attr def service_template(cls): return cls.many_to_one_relationship('service_template') - @declared_attr - def interface_template(cls): - return cls.many_to_one_relationship('interface_template') + #@declared_attr + #def interface_template(cls): + # return cls.many_to_one_relationship('interface_template') + # endregion # region many-to-many relationships @declared_attr def inputs(cls): - return cls.many_to_many_relationship('parameter', table_prefix='inputs') + return cls.many_to_many_relationship('parameter', table_prefix='inputs', + key_column_name='name') # endregion @@ -368,6 +439,7 @@ class ArtifactTemplateBase(structure.ModelMixin): * :code:`repository_credential`: Dict of string * :code:`properties`: Dict of :class:`Parameter` """ + __tablename__ = 'artifact_template' __private_fields__ = ['node_template_fk'] @@ -387,10 +459,12 @@ class ArtifactTemplateBase(structure.ModelMixin): repository_url = Column(Text) repository_credential = Column(aria_type.StrictDict(basestring, basestring)) - # region many-to-one relationship - @declared_attr - def node_template(cls): - return cls.many_to_one_relationship('node_template') + # region many-to-one relationships + + #@declared_attr + #def node_template(cls): + # return cls.many_to_one_relationship('node_template') + # endregion # region many-to-many relationships @@ -398,7 +472,7 @@ class ArtifactTemplateBase(structure.ModelMixin): @declared_attr def properties(cls): return cls.many_to_many_relationship('parameter', table_prefix='properties', - collection_class=dict) + key_column_name='name') # endregion @@ -487,7 +561,8 @@ class PolicyTemplateBase(structure.ModelMixin): target_node_template_names = Column(aria_type.StrictList(basestring)) target_group_template_names = Column(aria_type.StrictList(basestring)) - # region many-to-one relationship + # region many-to-one relationships + @declared_attr def service_template(cls): return cls.many_to_one_relationship('service_template') @@ -503,7 +578,7 @@ class PolicyTemplateBase(structure.ModelMixin): @declared_attr def properties(cls): return cls.many_to_many_relationship('parameter', table_prefix='properties', - collection_class=dict) + key_column_name='name') # endregion @@ -572,6 +647,7 @@ class GroupPolicyTemplateBase(structure.ModelMixin): __private_fields__ = ['group_template_fk'] # region foreign keys + @declared_attr def group_template_fk(cls): return cls.foreign_key('group_template') @@ -586,7 +662,7 @@ class GroupPolicyTemplateBase(structure.ModelMixin): @declared_attr def properties(cls): return cls.many_to_many_relationship('parameter', table_prefix='properties', - collection_class=dict) + key_column_name='name') # endregion @@ -655,7 +731,8 @@ class GroupPolicyTriggerTemplateBase(structure.ModelMixin): description = Column(Text) implementation = Column(Text) - # region many-to-one relationship + # region many-to-one relationships + @declared_attr def group_policy_template(cls): return cls.many_to_one_relationship('group_policy_template') @@ -668,7 +745,7 @@ class GroupPolicyTriggerTemplateBase(structure.ModelMixin): @declared_attr def properties(cls): return cls.many_to_many_relationship('parameter', table_prefix='properties', - collection_class=dict) + key_column_name='name') # endregion @@ -713,6 +790,7 @@ class MappingTemplateBase(structure.ModelMixin): * :code:`node_template_name`: Must be represented in the :class:`ServiceModel` * :code:`name`: Name of capability or requirement at the node template """ + __tablename__ = 'mapping_template' mapped_name = Column(Text) @@ -760,6 +838,7 @@ class SubstitutionTemplateBase(structure.ModelMixin): * :code:`capability_templates`: Dict of :class:`MappingTemplate` * :code:`requirement_templates`: Dict of :class:`MappingTemplate` """ + __tablename__ = 'substitution_template' node_type_name = Column(Text) @@ -822,6 +901,25 @@ class SubstitutionTemplateBase(structure.ModelMixin): # region Node templates class NodeTemplateBase(structure.ModelMixin): + """ + A template for creating zero or more :class:`Node` instances. + + Properties: + + * :code:`name`: Name (will be used as a prefix for node IDs) + * :code:`description`: Description + * :code:`type_name`: Must be represented in the :class:`ModelingContext` + * :code:`default_instances`: Default number nodes that will appear in the deployment plan + * :code:`min_instances`: Minimum number nodes that will appear in the deployment plan + * :code:`max_instances`: Maximum number nodes that will appear in the deployment plan + * :code:`properties`: Dict of :class:`Parameter` + * :code:`interface_templates`: Dict of :class:`InterfaceTemplate` + * :code:`artifact_templates`: Dict of :class:`ArtifactTemplate` + * :code:`capability_templates`: Dict of :class:`CapabilityTemplate` + * :code:`requirement_templates`: List of :class:`RequirementTemplate` + * :code:`target_node_template_constraints`: List of :class:`FunctionType` + """ + __tablename__ = 'node_template' __private_fields__ = ['service_template_fk', @@ -861,19 +959,36 @@ class NodeTemplateBase(structure.ModelMixin): # endregion - # region many-to-one relationship + # region many-to-one relationships + @declared_attr def service_template(cls): return cls.many_to_one_relationship('service_template') # endregion + # region one-to-many relationships + + @declared_attr + def interface_templates(cls): + return cls.one_to_many_relationship('interface_template', key_column_name='name') + + @declared_attr + def artifact_templates(cls): + return cls.one_to_many_relationship('artifact_template', key_column_name='name') + + @declared_attr + def capability_templates(cls): + return cls.one_to_many_relationship('capability_template', key_column_name='name') + + # endregion + # region many-to-many relationships @declared_attr def properties(cls): return cls.many_to_many_relationship('parameter', table_prefix='properties', - collection_class=dict) + key_column_name='name') # endregion @@ -964,6 +1079,7 @@ class GroupTemplateBase(structure.ModelMixin): * :code:`member_node_template_names`: Must be represented in the :class:`ServiceModel` * :code:`member_group_template_names`: Must be represented in the :class:`ServiceModel` """ + __tablename__ = 'group_template' __private_fields__ = ['service_template_fk'] @@ -981,7 +1097,8 @@ class GroupTemplateBase(structure.ModelMixin): member_node_template_names = Column(aria_type.StrictList(basestring)) member_group_template_names = Column(aria_type.StrictList(basestring)) - # region many-to-one relationship + # region many-to-one relationships + @declared_attr def service_template(cls): return cls.many_to_one_relationship('service_template') @@ -993,7 +1110,7 @@ class GroupTemplateBase(structure.ModelMixin): @declared_attr def properties(cls): return cls.many_to_many_relationship('parameter', table_prefix='properties', - collection_class=dict) + key_column_name='name') # endregion @@ -1075,6 +1192,7 @@ class RequirementTemplateBase(structure.ModelMixin): * :code:`target_capability_name`: Name of capability in target node * :code:`relationship_template`: :class:`RelationshipTemplate` """ + __tablename__ = 'requirement_template' __private_fields__ = ['node_template_fk'] @@ -1087,7 +1205,6 @@ class RequirementTemplateBase(structure.ModelMixin): # endregion - target_node_type_name = Column(Text) target_node_template_name = Column(Text) target_node_template_constraints = Column(aria_type.StrictList(FunctionType)) @@ -1096,10 +1213,12 @@ class RequirementTemplateBase(structure.ModelMixin): # CHECK: ??? relationship_template = Column(Text) # optional - # region many-to-one relationship + # region many-to-one relationships + @declared_attr def node_template(cls): return cls.many_to_one_relationship('node_template') + # endregion def instantiate(self, context, container): @@ -1237,6 +1356,7 @@ class CapabilityTemplateBase(structure.ModelMixin): * :code:`valid_source_node_type_names`: Must be represented in the :class:`ModelingContext` * :code:`properties`: Dict of :class:`Parameter` """ + __tablename__ = 'capability_template' __private_fields__ = ['node_template_fk'] @@ -1256,10 +1376,12 @@ class CapabilityTemplateBase(structure.ModelMixin): # CHECK: type? valid_source_node_type_names = Column(Text) - # region many-to-one relationship - @declared_attr - def node_template(cls): - return cls.many_to_one_relationship('node_template') + # region many-to-one relationships + + #@declared_attr + #def node_template(cls): + # return cls.many_to_one_relationship('node_template') + # endregion # region many-to-many relationships @@ -1267,7 +1389,7 @@ class CapabilityTemplateBase(structure.ModelMixin): @declared_attr def properties(cls): return cls.many_to_many_relationship('parameter', table_prefix='properties', - collection_class=dict) + key_column_name='name') # endregion @@ -1343,6 +1465,100 @@ class CapabilityTemplateBase(structure.ModelMixin): for v in self.valid_source_node_type_names))) dump_parameters(context, self.properties) + +class RelationshipTemplateBase(structure.ModelMixin): + """ + Optional addition to a :class:`Requirement` in :class:`NodeTemplate` that can be applied when + the requirement is matched with a capability. + + Properties: + + * :code:`type_name`: Must be represented in the :class:`ModelingContext` + * :code:`template_name`: Must be represented in the :class:`ServiceModel` + * :code:`description`: Description + * :code:`properties`: Dict of :class:`Parameter` + * :code:`source_interface_templates`: Dict of :class:`InterfaceTemplate` + * :code:`target_interface_templates`: Dict of :class:`InterfaceTemplate` + """ + + __tablename__ = 'relationship_template' + + description = Column(Text) + type_name = Column(Text) + + # region many-to-many relationships + + @declared_attr + def properties(cls): + return cls.many_to_many_relationship('parameter', table_prefix='properties', + key_column_name='name') + + # endregion + + # region one-to-many relationships + + @declared_attr + def interface_templates(cls): + return cls.one_to_many_relationship('interface_template', key_column_name='name') + + # endregion + + @property + def as_raw(self): + return collections.OrderedDict(( + ('type_name', self.type_name), + ('template_name', self.template_name), + ('description', self.description), + ('properties', formatting.as_raw_dict(self.properties)), + ('source_interface_templates', + formatting.as_raw_list(self.source_interface_templates)), + ('target_interface_templates', + formatting.as_raw_list(self.target_interface_templates)))) + + def instantiate(self, context, container): + relationship = instance_elements.RelationshipBase(name=self.template_name, + type_name=self.type_name) + utils.instantiate_dict(context, container, + relationship.properties, self.properties) + utils.instantiate_dict(context, container, + relationship.source_interfaces, self.source_interface_templates) + utils.instantiate_dict(context, container, + relationship.target_interfaces, self.target_interface_templates) + return relationship + + def validate(self, context): + if context.modeling.relationship_types.get_descendant(self.type_name) is None: + context.validation.report( + 'relationship template "{0}" has an unknown type: {1}'.format( + self.name, + formatting.safe_repr(self.type_name)), # pylint: disable=no-member + # TODO fix self.name reference + level=validation.Issue.BETWEEN_TYPES) + + utils.validate_dict_values(context, self.properties) + utils.validate_dict_values(context, self.source_interface_templates) + utils.validate_dict_values(context, self.target_interface_templates) + + def coerce_values(self, context, container, report_issues): + utils.coerce_dict_values(context, self, self.properties, report_issues) + utils.coerce_dict_values(context, self, self.source_interface_templates, report_issues) + utils.coerce_dict_values(context, self, self.target_interface_templates, report_issues) + + def dump(self, context): + if self.type_name is not None: + console.puts('Relationship type: {0}'.format(context.style.type(self.type_name))) + else: + console.puts('Relationship template: {0}'.format( + context.style.node(self.template_name))) + if self.description: + console.puts(context.style.meta(self.description)) + with context.style.indent: + utils.dump_parameters(context, self.properties) + utils.dump_interfaces(context, self.source_interface_templates, + 'Source interface templates') + utils.dump_interfaces(context, self.target_interface_templates, + 'Target interface templates') + # endregion http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/f28b0af1/aria/modeling/type.py ---------------------------------------------------------------------- diff --git a/aria/modeling/type.py b/aria/modeling/type.py index 9e3de3d..2c6453b 100644 --- a/aria/modeling/type.py +++ b/aria/modeling/type.py @@ -23,7 +23,7 @@ from sqlalchemy import ( ) from sqlalchemy.ext import mutable -from .. import exceptions +from ..storage import exceptions class _MutableType(TypeDecorator): http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/f28b0af1/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py ---------------------------------------------------------------------- diff --git a/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py b/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py index 0d33182..9676c0b 100644 --- a/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py +++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py @@ -14,10 +14,12 @@ # limitations under the License. import re +from types import FunctionType -from aria.parser.modeling import Type, RelationshipType, PolicyType, RelationshipTemplate +from aria.parser.modeling import Type, RelationshipType, PolicyType +from aria.modeling import type as aria_type from aria.modeling.model import (ServiceTemplate as ServiceModel, NodeTemplate, - RequirementTemplate, CapabilityTemplate, + RequirementTemplate, RelationshipTemplate, CapabilityTemplate, GroupTemplate, PolicyTemplate, SubstitutionTemplate, MappingTemplate, InterfaceTemplate, OperationTemplate, ArtifactTemplate, Metadata, Parameter) @@ -31,6 +33,7 @@ from aria.modeling.model import (ServiceTemplate as ServiceModel, NodeTemplate, from ..data_types import coerce_value from platform import node + def create_service_model(context): # pylint: disable=too-many-locals,too-many-branches model = ServiceModel() @@ -80,8 +83,8 @@ def create_service_model(context): # pylint: disable=too-many-locals,too-many-br node_templates = context.presentation.get('service_template', 'topology_template', 'node_templates') if node_templates: - for node_template_name, node_template in node_templates.iteritems(): - model.node_templates[node_template_name] = create_node_template(context, node_template) + for node_template in node_templates.itervalues(): + model.node_templates.append(create_node_template(context, node_template)) groups = context.presentation.get('service_template', 'topology_template', 'groups') if groups: @@ -113,6 +116,7 @@ def create_service_model(context): # pylint: disable=too-many-locals,too-many-br return model + def create_node_template(context, node_template): node_type = node_template._get_type(context) model = NodeTemplate(name=node_template._name, type_name=node_type._name) @@ -140,11 +144,13 @@ def create_node_template(context, node_template): model.capability_templates[capability_name] = create_capability_template(context, capability) + model.target_node_template_constraints = aria_type.StrictList(FunctionType) create_node_filter_constraint_lambdas(context, node_template.node_filter, model.target_node_template_constraints) return model + def create_interface_template(context, interface): interface_type = interface._get_type(context) model = InterfaceTemplate(name=interface._name, type_name=interface_type._name) @@ -166,6 +172,7 @@ def create_interface_template(context, interface): return model if model.operation_templates else None + def create_operation_template(context, operation): # pylint: disable=unused-argument model = OperationTemplate(name=operation._name) @@ -187,6 +194,7 @@ def create_operation_template(context, operation): # pylint: disable=unused-argu return model + def create_artifact_template(context, artifact): model = ArtifactTemplate(name=artifact._name, type_name=artifact.type, source_path=artifact.file) @@ -208,6 +216,7 @@ def create_artifact_template(context, artifact): return model + def create_requirement_template(context, requirement): model = {'name': requirement._name} @@ -236,12 +245,15 @@ def create_requirement_template(context, requirement): return model + def create_relationship_type(context, relationship_type): # pylint: disable=unused-argument return RelationshipType(relationship_type._name) + def create_policy_type(context, policy_type): # pylint: disable=unused-argument return PolicyType(policy_type._name) + def create_relationship_template(context, relationship): relationship_type, relationship_type_variant = relationship._get_type(context) if relationship_type_variant == 'relationship_type': @@ -255,10 +267,11 @@ def create_relationship_template(context, relationship): model.description = relationship_template.description.value create_properties_from_assignments(model.properties, relationship.properties) - create_interface_templates(context, model.source_interface_templates, relationship.interfaces) + create_interface_templates(context, model.interface_templates, relationship.interfaces) return model + def create_capability_template(context, capability): capability_type = capability._get_type(context) model = CapabilityTemplate(name=capability._name, type_name=capability_type._name) @@ -280,6 +293,7 @@ def create_capability_template(context, capability): return model + def create_group_template(context, group): group_type = group._get_type(context) model = GroupTemplate(name=group._name, type_name=group_type._name) @@ -297,6 +311,7 @@ def create_group_template(context, group): return model + def create_policy_template(context, policy): policy_type = policy._get_type(context) model = PolicyTemplate(name=policy._name, type_name=policy_type._name) @@ -314,6 +329,7 @@ def create_policy_template(context, policy): return model + # # Utils # @@ -346,19 +362,22 @@ def create_types(context, root, types, normalize=None): if container is not None: container.children.append(model) + def create_properties_from_values(properties, source_properties): if source_properties: for property_name, prop in source_properties.iteritems(): - properties.append(Parameter(name=property_name, - type=prop.type, - str_value=prop.value, - description=prop.description)) + properties[property_name] = Parameter(type=prop.type, + str_value=prop.value, + description=prop.description) + def create_properties_from_assignments(properties, source_properties): if source_properties: for property_name, prop in source_properties.iteritems(): - properties[property_name] = Parameter(prop.value.type, prop.value.value, - prop.value.description) + properties[property_name] = Parameter(type=prop.value.type, + str_value=prop.value.value, + description=prop.value.description) + def create_interface_templates(context, interfaces, source_interfaces): if source_interfaces: @@ -367,7 +386,8 @@ def create_interface_templates(context, interfaces, source_interfaces): if interface is not None: interfaces[interface_name] = interface -def create_node_filter_constraint_lambdas(context, node_filter, node_type_constraints): + +def create_node_filter_constraint_lambdas(context, node_filter, target_node_template_constraints): if node_filter is None: return @@ -377,7 +397,7 @@ def create_node_filter_constraint_lambdas(context, node_filter, node_type_constr func = create_constraint_clause_lambda(context, node_filter, constraint_clause, property_name, None) if func is not None: - node_type_constraints.append(func) + target_node_template_constraints.append(func) capabilities = node_filter.capabilities if capabilities is not None: @@ -388,7 +408,8 @@ def create_node_filter_constraint_lambdas(context, node_filter, node_type_constr func = create_constraint_clause_lambda(context, node_filter, constraint_clause, property_name, capability_name) if func is not None: - node_type_constraints.append(func) + target_node_template_constraints.append(func) + def create_constraint_clause_lambda(context, node_filter, constraint_clause, property_name, # pylint: disable=too-many-return-statements capability_name):