ariatosca-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "ASF GitHub Bot (JIRA)" <j...@apache.org>
Subject [jira] [Commented] (ARIA-105) Integrate new models into parser
Date Mon, 20 Mar 2017 16:12:42 GMT

    [ https://issues.apache.org/jira/browse/ARIA-105?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15932939#comment-15932939
] 

ASF GitHub Bot commented on ARIA-105:
-------------------------------------

Github user tliron commented on a diff in the pull request:

    https://github.com/apache/incubator-ariatosca/pull/72#discussion_r106943948
  
    --- Diff: aria/modeling/service_instance.py ---
    @@ -0,0 +1,1553 @@
    +# 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.
    +
    +# pylint: disable=too-many-lines, no-self-argument, no-member, abstract-method
    +
    +from sqlalchemy import (
    +    Column,
    +    Text,
    +    Integer
    +)
    +from sqlalchemy import DateTime
    +from sqlalchemy.ext.associationproxy import association_proxy
    +from sqlalchemy.ext.declarative import declared_attr
    +
    +from .mixins import InstanceModelMixin
    +from ..parser import validation
    +from ..parser.consumption import ConsumptionContext
    +from ..utils import collections, formatting, console
    +from . import (
    +    relationships,
    +    utils,
    +    types as modeling_types
    +)
    +
    +
    +class ServiceBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
    +    """
    +    A service is usually an instance of a :class:`ServiceTemplate`.
    +
    +    You will usually not create it programmatically, but instead instantiate it from
a service
    +    template.
    +
    +    :ivar name: Name (unique for this ARIA installation)
    +    :vartype name: basestring
    +    :ivar service_template: Template from which this service was instantiated (optional)
    +    :vartype service_template: :class:`ServiceTemplate`
    +    :ivar description: Human-readable description
    +    :vartype description: string
    +    :ivar meta_data: Custom annotations
    +    :vartype meta_data: {basestring: :class:`Metadata`}
    +    :ivar node: Nodes
    +    :vartype node: {basestring: :class:`Node`}
    +    :ivar groups: Groups of nodes
    +    :vartype groups: {basestring: :class:`Group`}
    +    :ivar policies: Policies
    +    :vartype policies: {basestring: :class:`Policy`]}
    +    :ivar substitution: The entire service can appear as a node
    +    :vartype substitution: :class:`Substitution`
    +    :ivar inputs: Externally provided parameters
    +    :vartype inputs: {basestring: :class:`Parameter`}
    +    :ivar outputs: These parameters are filled in after service installation
    +    :vartype outputs: {basestring: :class:`Parameter`}
    +    :ivar workflows: Custom workflows that can be performed on the service
    +    :vartype workflows: {basestring: :class:`Operation`}
    +    :ivar plugin_specifications: Plugins required to be installed
    +    :vartype plugin_specifications: {basestring: :class:`PluginSpecification`}
    +    :ivar created_at: Creation timestamp
    +    :vartype created_at: :class:`datetime.datetime`
    +    :ivar updated_at: Update timestamp
    +    :vartype updated_at: :class:`datetime.datetime`
    +
    +    :ivar permalink: ??
    +    :vartype permalink: basestring
    +    :ivar scaling_groups: ??
    +    :vartype scaling_groups: {}
    +
    +    :ivar modifications: Modifications of this service
    +    :vartype modifications: [:class:`ServiceModification`]
    +    :ivar updates: Updates of this service
    +    :vartype updates: [:class:`ServiceUpdate`]
    +    :ivar executions: Executions on this service
    +    :vartype executions: [:class:`Execution`]
    +    """
    +
    +    __tablename__ = 'service'
    +
    +    @declared_attr
    +    def service_template(cls):
    +        return relationships.many_to_one(cls, 'service_template')
    +
    +    description = Column(Text)
    +
    +    @declared_attr
    +    def meta_data(cls):
    +        # Warning! We cannot use the attr name "metadata" because it's used by SQLAlchemy!
    +        return relationships.many_to_many(cls, 'metadata', dict_key='name')
    +
    +    @declared_attr
    +    def nodes(cls):
    +        return relationships.one_to_many(cls, 'node', dict_key='name')
    +
    +    @declared_attr
    +    def groups(cls):
    +        return relationships.one_to_many(cls, 'group', dict_key='name')
    +
    +    @declared_attr
    +    def policies(cls):
    +        return relationships.one_to_many(cls, 'policy', dict_key='name')
    +
    +    @declared_attr
    +    def substitution(cls):
    +        return relationships.one_to_one(cls, 'substitution')
    +
    +    @declared_attr
    +    def inputs(cls):
    +        return relationships.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
    +
    +    @declared_attr
    +    def outputs(cls):
    +        return relationships.many_to_many(cls, 'parameter', prefix='outputs', dict_key='name')
    +
    +    @declared_attr
    +    def workflows(cls):
    +        return relationships.one_to_many(cls, 'operation', dict_key='name')
    +
    +    @declared_attr
    +    def plugin_specifications(cls):
    +        return relationships.many_to_many(cls, 'plugin_specification')
    +
    +    created_at = Column(DateTime, nullable=False, index=True)
    +    updated_at = Column(DateTime)
    +
    +    # region orchestration
    +
    +    permalink = Column(Text)
    +    scaling_groups = Column(modeling_types.Dict)
    +
    +    # endregion
    +
    +    # region foreign keys
    +
    +    @declared_attr
    +    def substitution_fk(cls):
    +        """Service one-to-one to Substitution"""
    +        return relationships.fk('substitution', nullable=True)
    +
    +    @declared_attr
    +    def service_template_fk(cls):
    +        """For Service many-to-one to ServiceTemplate"""
    +        return relationships.fk('service_template', nullable=True)
    +
    +    # endregion
    +
    +    # region association proxies
    +
    +    @declared_attr
    +    def service_template_name(cls):
    +        """Required for use by SQLAlchemy queries"""
    +        return association_proxy('service_template', 'name')
    +
    +    # endregion
    +
    +    def satisfy_requirements(self):
    +        satisfied = True
    +        for node in self.nodes.itervalues():
    +            if not node.satisfy_requirements():
    +                satisfied = False
    +        return satisfied
    +
    +    def validate_capabilities(self):
    +        satisfied = True
    +        for node in self.nodes.itervalues():
    +            if not node.validate_capabilities():
    +                satisfied = False
    +        return satisfied
    +
    +    def is_node_a_target(self, target_node):
    +        for node in self.nodes.itervalues():
    +            if self._is_node_a_target(node, target_node):
    +                return True
    +        return False
    +
    +    def _is_node_a_target(self, source_node, target_node):
    +        if source_node.outbound_relationships:
    +            for relationship in source_node.outbound_relationships:
    +                if relationship.target_node.name == target_node.name:
    +                    return True
    +                else:
    +                    node = relationship.target_node
    +                    if node is not None:
    +                        if self._is_node_a_target(node, target_node):
    +                            return True
    +        return False
    +
    +    @property
    +    def as_raw(self):
    +        return collections.OrderedDict((
    +            ('description', self.description),
    +            ('metadata', formatting.as_raw_dict(self.meta_data)),
    +            ('nodes', formatting.as_raw_list(self.nodes)),
    +            ('groups', formatting.as_raw_list(self.groups)),
    +            ('policies', formatting.as_raw_list(self.policies)),
    +            ('substitution', formatting.as_raw(self.substitution)),
    +            ('inputs', formatting.as_raw_dict(self.inputs)),
    +            ('outputs', formatting.as_raw_dict(self.outputs)),
    +            ('workflows', formatting.as_raw_list(self.workflows))))
    +
    +    def validate(self):
    +        utils.validate_dict_values(self.meta_data)
    +        utils.validate_dict_values(self.nodes)
    +        utils.validate_dict_values(self.groups)
    +        utils.validate_dict_values(self.policies)
    +        if self.substitution is not None:
    +            self.substitution.validate()
    +        utils.validate_dict_values(self.inputs)
    +        utils.validate_dict_values(self.outputs)
    +        utils.validate_dict_values(self.workflows)
    +
    +    def coerce_values(self, container, report_issues):
    +        utils.coerce_dict_values(container, self.meta_data, report_issues)
    +        utils.coerce_dict_values(container, self.nodes, report_issues)
    +        utils.coerce_dict_values(container, self.groups, report_issues)
    +        utils.coerce_dict_values(container, self.policies, report_issues)
    +        if self.substitution is not None:
    +            self.substitution.coerce_values(container, report_issues)
    +        utils.coerce_dict_values(container, self.inputs, report_issues)
    +        utils.coerce_dict_values(container, self.outputs, report_issues)
    +        utils.coerce_dict_values(container, self.workflows, report_issues)
    +
    +    def dump(self):
    +        context = ConsumptionContext.get_thread_local()
    +        if self.description is not None:
    +            console.puts(context.style.meta(self.description))
    +        utils.dump_dict_values(self.meta_data, 'Metadata')
    +        for node in self.nodes.itervalues():
    +            node.dump()
    +        for group in self.groups.itervalues():
    +            group.dump()
    +        for policy in self.policies.itervalues():
    +            policy.dump()
    +        if self.substitution is not None:
    +            self.substitution.dump()
    +        utils.dump_dict_values(self.inputs, 'Inputs')
    +        utils.dump_dict_values(self.outputs, 'Outputs')
    +        utils.dump_dict_values(self.workflows, 'Workflows')
    +
    +    def dump_graph(self):
    +        for node in self.nodes.itervalues():
    +            if not self.is_node_a_target(node):
    +                self._dump_graph_node(node)
    +
    +    def _dump_graph_node(self, node):
    +        context = ConsumptionContext.get_thread_local()
    +        console.puts(context.style.node(node.name))
    +        if node.outbound_relationships:
    +            with context.style.indent:
    +                for relationship in node.outbound_relationships:
    +                    if relationship.relationship_template is not None:
    +                        relationship_name = context.style.node(
    +                            relationship.relationship_template.name)
    +                    elif relationship.type is not None:
    +                        relationship_name = context.style.type(relationship.type.name)
    +                    else:
    +                        relationship_name = '?'
    +                    if relationship.target_capability is not None:
    +                        capability_name = context.style.node(relationship.target_capability.name)
    +                    else:
    +                        capability_name = None
    +                    if capability_name is not None:
    +                        console.puts('-> {0} {1}'.format(relationship_name, capability_name))
    +                    else:
    +                        console.puts('-> {0}'.format(relationship_name))
    +                    target_node = relationship.target_node
    +                    with console.indent(3):
    +                        self._dump_graph_node(target_node)
    +
    +    __private_fields__ = ['substitution_fk',
    +                          'service_template_fk',
    +                          'service_template_name']
    +
    +
    +class NodeBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
    +    """
    +    Usually an instance of a :class:`NodeTemplate`.
    +
    +    Nodes may have zero or more :class:`Relationship` instances to other nodes.
    +
    +    :ivar name: Name (unique for this service)
    +    :vartype name: basestring
    +    :ivar node_template: Template from which this node was instantiated (optional)
    +    :vartype node_template: :class:`NodeTemplate`
    +    :ivar type: Node type
    +    :vartype type: :class:`Type`
    +    :ivar description: Human-readable description
    +    :vartype description: string
    +    :ivar properties: Associated parameters
    +    :vartype properties: {basestring: :class:`Parameter`}
    +    :ivar interfaces: Bundles of operations
    +    :vartype interfaces: {basestring: :class:`Interface`}
    +    :ivar artifacts: Associated files
    +    :vartype artifacts: {basestring: :class:`Artifact`}
    +    :ivar capabilities: Exposed capabilities
    +    :vartype capabilities: {basestring: :class:`Capability`}
    +    :ivar outbound_relationships: Relationships to other nodes
    +    :vartype outbound_relationships: [:class:`Relationship`]
    +    :ivar inbound_relationships: Relationships from other nodes
    +    :vartype inbound_relationships: [:class:`Relationship`]
    +    :ivar plugin_specifications: Plugins required to be installed on the node's host
    +    :vartype plugin_specifications: {basestring: :class:`PluginSpecification`}
    +    :ivar host: Host node (can be self)
    +    :vartype host: :class:`Node`
    +
    +    :ivar runtime_properties: TODO: should be replaced with attributes
    +    :vartype runtime_properties: {}
    +    :ivar scaling_groups: ??
    +    :vartype scaling_groups: []
    +    :ivar state: ??
    +    :vartype state: basestring
    +    :ivar version: Used by `aria.storage.instrumentation`
    +    :vartype version: int
    +
    +    :ivar service: Containing service
    +    :vartype service: :class:`Service`
    +    :ivar groups: We are a member of these groups
    +    :vartype groups: [:class:`Group`]
    +    :ivar policies: Policies enacted on this node
    +    :vartype policies: [:class:`Policy`]
    +    :ivar substitution_mapping: Our contribution to service substitution
    +    :vartype substitution_mapping: :class:`SubstitutionMapping`
    +    :ivar tasks: Tasks on this node
    +    :vartype tasks: [:class:`Task`]
    +    """
    +
    +    __tablename__ = 'node'
    +
    +    @declared_attr
    +    def node_template(cls):
    +        return relationships.many_to_one(cls, 'node_template')
    +
    +    @declared_attr
    +    def type(cls):
    +        return relationships.many_to_one(cls, 'type')
    +
    +    description = Column(Text)
    +
    +    @declared_attr
    +    def properties(cls):
    +        return relationships.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
    +
    +    @declared_attr
    +    def interfaces(cls):
    +        return relationships.one_to_many(cls, 'interface', dict_key='name')
    +
    +    @declared_attr
    +    def artifacts(cls):
    +        return relationships.one_to_many(cls, 'artifact', dict_key='name')
    +
    +    @declared_attr
    +    def capabilities(cls):
    +        return relationships.one_to_many(cls, 'capability', dict_key='name')
    +
    +    @declared_attr
    +    def outbound_relationships(cls):
    +        return relationships.one_to_many(cls, 'relationship', child_fk='source_node_fk',
    +                                         child_property='source_node')
    +
    +    @declared_attr
    +    def inbound_relationships(cls):
    +        return relationships.one_to_many(cls, 'relationship', child_fk='target_node_fk',
    +                                         child_property='target_node')
    +
    +    @declared_attr
    +    def plugin_specifications(cls):
    +        return relationships.many_to_many(cls, 'plugin_specification', dict_key='name')
    +
    +    @declared_attr
    +    def host(cls):
    +        return relationships.one_to_one_self(cls, 'host_fk')
    +
    +    # region orchestration
    +
    +    runtime_properties = Column(modeling_types.Dict)
    +    scaling_groups = Column(modeling_types.List)
    +    state = Column(Text, nullable=False)
    +    version = Column(Integer, default=1)
    +
    +    __mapper_args__ = {'version_id_col': version} # Enable SQLAlchemy automatic version
counting
    +
    +    @property
    +    def ip(self):
    +        # TODO: totally broken
    +        if not self.host_fk:
    +            return None
    +        host_node = self.host
    +        if 'ip' in host_node.runtime_properties:  # pylint: disable=no-member
    +            return host_node.runtime_properties['ip']  # pylint: disable=no-member
    +        host_node = host_node.node_template  # pylint: disable=no-member
    +        host_ip_property = host_node.properties.get('ip')
    +        if host_ip_property:
    +            return host_ip_property.value
    +        return None
    +
    +    # endregion
    +
    +    # region foreign_keys
    +
    +    @declared_attr
    +    def type_fk(cls):
    +        """For Node many-to-one to Type"""
    +        return relationships.fk('type')
    +
    +    @declared_attr
    +    def host_fk(cls):
    +        """For Node one-to-one to Node"""
    +        return relationships.fk('node', nullable=True)
    +
    +    @declared_attr
    +    def service_fk(cls):
    +        """For Service one-to-many to Node"""
    +        return relationships.fk('service')
    +
    +    @declared_attr
    +    def node_template_fk(cls):
    +        """For Node many-to-one to NodeTemplate"""
    +        return relationships.fk('node_template', nullable=True)
    +
    +    # endregion
    +
    +    # region association proxies
    +
    +    @declared_attr
    +    def service_name(cls):
    +        """Required for use by SQLAlchemy queries"""
    +        return association_proxy('service', 'name')
    +
    +    # endregion
    +
    +    def satisfy_requirements(self):
    +        node_template = self.node_template
    +        satisfied = True
    +        for requirement_template in node_template.requirement_templates:
    +            # Find target template
    +            target_node_template, target_node_capability = \
    +                requirement_template.find_target(node_template)
    +            if target_node_template is not None:
    +                satisfied = self._satisfy_capability(target_node_capability,
    +                                                     target_node_template,
    +                                                     requirement_template)
    +            else:
    +                context = ConsumptionContext.get_thread_local()
    +                context.validation.report('requirement "{0}" of node "{1}" has no target
node '
    +                                          'template'.format(requirement_template.name,
self.name),
    +                                          level=validation.Issue.BETWEEN_INSTANCES)
    +                satisfied = False
    +        return satisfied
    +
    +    def _satisfy_capability(self, target_node_capability, target_node_template,
    +                            requirement_template):
    +        from . import models
    +        context = ConsumptionContext.get_thread_local()
    +        # Find target nodes
    +        target_nodes = target_node_template.nodes.all()
    +        if target_nodes:
    +            target_node = None
    +            target_capability = None
    +
    +            if target_node_capability is not None:
    +                # Relate to the first target node that has capacity
    +                for node in target_nodes:
    +                    target_capability = node.capabilities.get(target_node_capability.name)
    +                    if target_capability.relate():
    +                        target_node = node
    +                        break
    +            else:
    +                # Use first target node
    +                target_node = target_nodes[0]
    +
    +            if target_node is not None:
    +                if requirement_template.relationship_template is not None:
    +                    relationship = \
    +                        requirement_template.relationship_template.instantiate(self)
    +                else:
    +                    relationship = models.Relationship(target_capability=target_capability)
    +                relationship.name = requirement_template.name
    +                relationship.requirement_template = requirement_template
    +                relationship.target_node = target_node
    +                self.outbound_relationships.append(relationship)
    +                return True
    +            else:
    +                context.validation.report('requirement "{0}" of node "{1}" targets node
'
    +                                          'template "{2}" but its instantiated nodes
do not '
    +                                          'have enough capacity'.format(
    +                                              requirement_template.name,
    +                                              self.name,
    +                                              target_node_template.name),
    +                                          level=validation.Issue.BETWEEN_INSTANCES)
    +                return False
    +        else:
    +            context.validation.report('requirement "{0}" of node "{1}" targets node template
'
    +                                      '"{2}" but it has no instantiated nodes'.format(
    +                                          requirement_template.name,
    +                                          self.name,
    +                                          target_node_template.name),
    +                                      level=validation.Issue.BETWEEN_INSTANCES)
    +            return False
    +
    +    def validate_capabilities(self):
    +        context = ConsumptionContext.get_thread_local()
    +        satisfied = False
    +        for capability in self.capabilities.itervalues():
    +            if not capability.has_enough_relationships:
    +                context.validation.report('capability "{0}" of node "{1}" requires at
least {2:d} '
    +                                          'relationships but has {3:d}'.format(
    +                                              capability.name,
    +                                              self.name,
    +                                              capability.min_occurrences,
    +                                              capability.occurrences),
    +                                          level=validation.Issue.BETWEEN_INSTANCES)
    +                satisfied = False
    +        return satisfied
    +
    +    @property
    +    def as_raw(self):
    +        return collections.OrderedDict((
    +            ('name', self.name),
    +            ('type_name', self.type.name),
    +            ('properties', formatting.as_raw_dict(self.properties)),
    +            ('interfaces', formatting.as_raw_list(self.interfaces)),
    +            ('artifacts', formatting.as_raw_list(self.artifacts)),
    +            ('capabilities', formatting.as_raw_list(self.capabilities)),
    +            ('relationships', formatting.as_raw_list(self.outbound_relationships))))
    +
    +    def validate(self):
    +        context = ConsumptionContext.get_thread_local()
    +        if len(self.name) > context.modeling.id_max_length:
    +            context.validation.report('"{0}" has an ID longer than the limit of {1:d}
characters: '
    +                                      '{2:d}'.format(
    +                                          self.name,
    +                                          context.modeling.id_max_length,
    +                                          len(self.name)),
    +                                      level=validation.Issue.BETWEEN_INSTANCES)
    +
    +        # TODO: validate that node template is of type?
    +
    +        utils.validate_dict_values(self.properties)
    +        utils.validate_dict_values(self.interfaces)
    +        utils.validate_dict_values(self.artifacts)
    +        utils.validate_dict_values(self.capabilities)
    +        utils.validate_list_values(self.outbound_relationships)
    +
    +    def coerce_values(self, container, report_issues):
    +        utils.coerce_dict_values(self, self.properties, report_issues)
    +        utils.coerce_dict_values(self, self.interfaces, report_issues)
    +        utils.coerce_dict_values(self, self.artifacts, report_issues)
    +        utils.coerce_dict_values(self, self.capabilities, report_issues)
    +        utils.coerce_list_values(self, self.outbound_relationships, report_issues)
    +
    +    def dump(self):
    +        context = ConsumptionContext.get_thread_local()
    +        console.puts('Node: {0}'.format(context.style.node(self.name)))
    +        with context.style.indent:
    +            console.puts('Type: {0}'.format(context.style.type(self.type.name)))
    +            console.puts('Template: {0}'.format(context.style.node(self.node_template.name)))
    +            utils.dump_dict_values(self.properties, 'Properties')
    +            utils.dump_interfaces(self.interfaces)
    +            utils.dump_dict_values(self.artifacts, 'Artifacts')
    +            utils.dump_dict_values(self.capabilities, 'Capabilities')
    +            utils.dump_list_values(self.outbound_relationships, 'Relationships')
    +
    +    __private_fields__ = ['type_fk',
    +                          'host_fk',
    +                          'service_fk',
    +                          'node_template_fk',
    +                          'service_name']
    +
    +class GroupBase(InstanceModelMixin):
    +    """
    +    Usually an instance of a :class:`GroupTemplate`.
    +
    +    :ivar name: Name (unique for this service)
    +    :vartype name: basestring
    +    :ivar group_template: Template from which this group was instantiated (optional)
    +    :vartype group_template: :class:`GroupTemplate`
    +    :ivar type: Group type
    +    :vartype type: :class:`Type`
    +    :ivar description: Human-readable description
    +    :vartype description: string
    +    :ivar nodes: Members of this group
    +    :vartype nodes: [:class:`Node`]
    +    :ivar properties: Associated parameters
    +    :vartype properties: {basestring: :class:`Parameter`}
    +    :ivar interfaces: Bundles of operations
    +    :vartype interfaces: {basestring: :class:`Interface`}
    +
    +    :ivar service: Containing service
    +    :vartype service: :class:`Service`
    +    :ivar policies: Policies enacted on this group
    +    :vartype policies: [:class:`Policy`]
    +    """
    +
    +    __tablename__ = 'group'
    +
    +    @declared_attr
    +    def group_template(cls):
    +        return relationships.many_to_one(cls, 'group_template')
    +
    +    @declared_attr
    +    def type(cls):
    +        return relationships.many_to_one(cls, 'type')
    +
    +    description = Column(Text)
    +
    +    @declared_attr
    +    def nodes(cls):
    +        return relationships.many_to_many(cls, 'node')
    +
    +    @declared_attr
    +    def properties(cls):
    +        return relationships.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
    +
    +    @declared_attr
    +    def interfaces(cls):
    +        return relationships.one_to_many(cls, 'interface', dict_key='name')
    +
    +    # region foreign_keys
    +
    +    @declared_attr
    +    def type_fk(cls):
    +        """For Group many-to-one to Type"""
    +        return relationships.fk('type')
    +
    +    @declared_attr
    +    def service_fk(cls):
    +        """For Service one-to-many to Group"""
    +        return relationships.fk('service')
    +
    +    @declared_attr
    +    def group_template_fk(cls):
    +        """For Group many-to-one to GroupTemplate"""
    +        return relationships.fk('group_template', nullable=True)
    +
    +    # endregion
    +
    +    @property
    +    def as_raw(self):
    +        return collections.OrderedDict((
    +            ('name', self.name),
    +            ('properties', formatting.as_raw_dict(self.properties)),
    +            ('interfaces', formatting.as_raw_list(self.interfaces))))
    +
    +    def validate(self):
    +        utils.validate_dict_values(self.properties)
    +        utils.validate_dict_values(self.interfaces)
    +
    +    def coerce_values(self, container, report_issues):
    +        utils.coerce_dict_values(container, self.properties, report_issues)
    +        utils.coerce_dict_values(container, self.interfaces, report_issues)
    +
    +    def dump(self):
    +        context = ConsumptionContext.get_thread_local()
    +        console.puts('Group: {0}'.format(context.style.node(self.name)))
    +        with context.style.indent:
    +            console.puts('Type: {0}'.format(context.style.type(self.type.name)))
    +            utils.dump_dict_values(self.properties, 'Properties')
    +            utils.dump_interfaces(self.interfaces)
    +            if self.nodes:
    +                console.puts('Member nodes:')
    +                with context.style.indent:
    +                    for node in self.nodes:
    +                        console.puts(context.style.node(node.name))
    +
    +    __private_fields__ = ['type_fk',
    +                          'service_fk',
    +                          'group_template_fk']
    +
    +
    +class PolicyBase(InstanceModelMixin):
    +    """
    +    Usually an instance of a :class:`PolicyTemplate`.
    +
    +    :ivar name: Name (unique for this service)
    +    :vartype name: basestring
    +    :ivar policy_template: Template from which this policy was instantiated (optional)
    +    :vartype policy_template: :class:`PolicyTemplate`
    +    :ivar type: Policy type
    +    :vartype type: :class:`Type`
    +    :ivar description: Human-readable description
    +    :vartype description: string
    +    :ivar nodes: Policy will be enacted on all these nodes
    +    :vartype nodes: [:class:`Node`]
    +    :ivar groups: Policy will be enacted on all nodes in these groups
    +    :vartype groups: [:class:`Group`]
    +    :ivar properties: Associated parameters
    +    :vartype properties: {basestring: :class:`Parameter`}
    +
    +    :ivar service: Containing service
    +    :vartype service: :class:`Service`
    +    """
    +
    +    __tablename__ = 'policy'
    +
    +    @declared_attr
    +    def policy_template(cls):
    +        return relationships.many_to_one(cls, 'policy_template')
    +
    +    @declared_attr
    +    def type(cls):
    +        return relationships.many_to_one(cls, 'type')
    +
    +    description = Column(Text)
    +
    +    @declared_attr
    +    def properties(cls):
    +        return relationships.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
    +
    +    @declared_attr
    +    def nodes(cls):
    +        return relationships.many_to_many(cls, 'node')
    +
    +    @declared_attr
    +    def groups(cls):
    +        return relationships.many_to_many(cls, 'group')
    +
    +    # region foreign_keys
    +
    +    @declared_attr
    +    def type_fk(cls):
    +        """For Policy many-to-one to Type"""
    +        return relationships.fk('type')
    +
    +    @declared_attr
    +    def service_fk(cls):
    +        """For Service one-to-many to Policy"""
    +        return relationships.fk('service')
    +
    +    @declared_attr
    +    def policy_template_fk(cls):
    +        """For Policy many-to-one to PolicyTemplate"""
    +        return relationships.fk('policy_template', nullable=True)
    +
    +    # endregion
    +
    +    @property
    +    def as_raw(self):
    +        return collections.OrderedDict((
    +            ('name', self.name),
    +            ('type_name', self.type.name),
    +            ('properties', formatting.as_raw_dict(self.properties))))
    +
    +    def validate(self):
    +        utils.validate_dict_values(self.properties)
    +
    +    def coerce_values(self, container, report_issues):
    +        utils.coerce_dict_values(container, self.properties, report_issues)
    +
    +    def dump(self):
    +        context = ConsumptionContext.get_thread_local()
    +        console.puts('Policy: {0}'.format(context.style.node(self.name)))
    +        with context.style.indent:
    +            console.puts('Type: {0}'.format(context.style.type(self.type.name)))
    +            utils.dump_dict_values(self.properties, 'Properties')
    +            if self.nodes:
    +                console.puts('Target nodes:')
    +                with context.style.indent:
    +                    for node in self.nodes:
    +                        console.puts(context.style.node(node.name))
    +            if self.groups:
    +                console.puts('Target groups:')
    +                with context.style.indent:
    +                    for group in self.groups:
    +                        console.puts(context.style.node(group.name))
    +
    +    __private_fields__ = ['type_fk',
    +                          'service_fk',
    +                          'policy_template_fk']
    +
    +
    +class SubstitutionBase(InstanceModelMixin):
    +    """
    +    Used to substitute a single node for the entire deployment.
    +
    +    Usually an instance of a :class:`SubstitutionTemplate`.
    +
    +    :ivar substitution_template: Template from which this substitution was instantiated
(optional)
    +    :vartype substitution_template: :class:`SubstitutionTemplate`
    +    :ivar node_type: Exposed node type
    +    :vartype node_type: :class:`Type`
    +    :ivar mappings: Requirement and capability mappings
    +    :vartype mappings: {basestring: :class:`SubstitutionTemplate`}
    +
    +    :ivar service: Containing service
    +    :vartype service: :class:`Service`
    +    """
    +
    +    __tablename__ = 'substitution'
    +
    +    @declared_attr
    +    def substitution_template(cls):
    +        return relationships.many_to_one(cls, 'substitution_template')
    +
    +    @declared_attr
    +    def node_type(cls):
    +        return relationships.many_to_one(cls, 'type')
    +
    +    @declared_attr
    +    def mappings(cls):
    +        return relationships.one_to_many(cls, 'substitution_mapping', dict_key='name')
    +
    +    # region foreign_keys
    +
    +    @declared_attr
    +    def node_type_fk(cls):
    +        """For Substitution many-to-one to Type"""
    +        return relationships.fk('type')
    +
    +    @declared_attr
    +    def substitution_template_fk(cls):
    +        """For Substitution many-to-one to SubstitutionTemplate"""
    +        return relationships.fk('substitution_template', nullable=True)
    +
    +    # endregion
    +
    +    @property
    +    def as_raw(self):
    +        return collections.OrderedDict((
    +            ('node_type_name', self.node_type_name),
    +            ('mappings', formatting.as_raw_dict(self.mappings))))
    +
    +    def validate(self):
    +        utils.validate_dict_values(self.mappings)
    +
    +    def coerce_values(self, container, report_issues):
    +        utils.coerce_dict_values(container, self.mappings, report_issues)
    +
    +    def dump(self):
    +        context = ConsumptionContext.get_thread_local()
    +        console.puts('Substitution:')
    +        with context.style.indent:
    +            console.puts('Node type: {0}'.format(context.style.type(self.node_type.name)))
    +            utils.dump_dict_values(self.mappings, 'Mappings')
    +
    +    __private_fields__ = ['node_type_fk',
    +                          'substitution_template_fk']
    +
    +
    +class SubstitutionMappingBase(InstanceModelMixin):
    +    """
    +    Used by :class:`Substitution` to map a capability or a requirement to a node.
    +
    +    Only one of `capability_template` and `requirement_template` can be set.
    +
    +    Usually an instance of a :class:`SubstitutionTemplate`.
    +
    +    :ivar name: Exposed capability or requirement name
    +    :vartype name: basestring
    +    :ivar node: Node
    +    :vartype node: :class:`Node`
    +    :ivar capability: Capability in the node
    +    :vartype capability: :class:`Capability`
    +    :ivar requirement_template: Requirement template in the node template
    +    :vartype requirement_template: :class:`RequirementTemplate`
    +
    +    :ivar substitution: Containing substitution
    +    :vartype substitution: :class:`Substitution`
    +    """
    +
    +    __tablename__ = 'substitution_mapping'
    +
    +    @declared_attr
    +    def node(cls):
    +        return relationships.one_to_one(cls, 'node')
    +
    +    @declared_attr
    +    def capability(cls):
    +        return relationships.one_to_one(cls, 'capability')
    +
    +    @declared_attr
    +    def requirement_template(cls):
    +        return relationships.one_to_one(cls, 'requirement_template')
    +
    +    # region foreign keys
    +
    +    @declared_attr
    +    def substitution_fk(cls):
    +        """For Substitution one-to-many to SubstitutionMapping"""
    +        return relationships.fk('substitution')
    +
    +    @declared_attr
    +    def node_fk(cls):
    +        """For Substitution one-to-one to NodeTemplate"""
    +        return relationships.fk('node')
    +
    +    @declared_attr
    +    def capability_fk(cls):
    +        """For Substitution one-to-one to Capability"""
    +        return relationships.fk('capability', nullable=True)
    +
    +    @declared_attr
    +    def requirement_template_fk(cls):
    +        """For Substitution one-to-one to RequirementTemplate"""
    +        return relationships.fk('requirement_template', nullable=True)
    +
    +    # endregion
    +
    +    @property
    +    def as_raw(self):
    +        return collections.OrderedDict((
    +            ('name', self.name)))
    +
    +    def validate(self):
    +        context = ConsumptionContext.get_thread_local()
    +        if (self.capability is None) and (self.requirement_template is None):
    +            context.validation.report('mapping "{0}" refers to neither capability nor
a requirement'
    +                                      ' in node: {1}'.format(
    +                                          self.name,
    +                                          formatting.safe_repr(self.node.name)),
    +                                      level=validation.Issue.BETWEEN_TYPES)
    +
    +    def dump(self):
    +        context = ConsumptionContext.get_thread_local()
    +        console.puts('{0} -> {1}.{2}'.format(
    +            context.style.node(self.name),
    +            context.style.node(self.node.name),
    +            context.style.node(self.capability.name
    +                               if self.capability
    +                               else self.requirement_template.name)))
    +
    +    __private_fields__ = ['substitution_fk',
    +                          'node_fk',
    +                          'capability_fk',
    +                          'requirement_template_fk']
    +
    +
    +class RelationshipBase(InstanceModelMixin):
    +    """
    +    Connects :class:`Node` to a capability in another node.
    +
    +    Might be an instance of a :class:`RelationshipTemplate`.
    +
    +    :ivar name: Name (usually the name of the requirement at the source node template)
    +    :vartype name: basestring
    +    :ivar relationship_template: Template from which this relationship was instantiated
(optional)
    +    :vartype relationship_template: :class:`RelationshipTemplate`
    +    :ivar requirement_template: Template from which this relationship was instantiated
(optional)
    +    :vartype requirement_template: :class:`RequirementTemplate`
    +    :ivar type: Relationship type
    +    :vartype type: :class:`Type`
    +    :ivar target_capability: Capability at the target node (optional)
    +    :vartype target_capability: :class:`Capability`
    +    :ivar properties: Associated parameters
    +    :vartype properties: {basestring: :class:`Parameter`}
    +    :ivar interfaces: Bundles of operations
    +    :vartype interfaces: {basestring: :class:`Interfaces`}
    +
    +    :ivar source_position: ??
    +    :vartype source_position: int
    +    :ivar target_position: ??
    +    :vartype target_position: int
    +
    +    :ivar source_node: Source node
    +    :vartype source_node: :class:`Node`
    +    :ivar target_node: Target node
    +    :vartype target_node: :class:`Node`
    +    :ivar tasks: Tasks on this node
    +    :vartype tasks: [:class:`Task`]
    +    """
    +
    +    __tablename__ = 'relationship'
    +
    +    @declared_attr
    +    def relationship_template(cls):
    +        return relationships.many_to_one(cls, 'relationship_template')
    +
    +    @declared_attr
    +    def requirement_template(cls):
    +        return relationships.many_to_one(cls, 'requirement_template')
    +
    +    @declared_attr
    +    def type(cls):
    +        return relationships.many_to_one(cls, 'type')
    +
    +    @declared_attr
    +    def target_capability(cls):
    +        return relationships.one_to_one(cls, 'capability')
    +
    +    @declared_attr
    +    def properties(cls):
    +        return relationships.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
    +
    +    @declared_attr
    +    def interfaces(cls):
    +        return relationships.one_to_many(cls, 'interface', dict_key='name')
    +
    +    # region orchestration
    +
    +    source_position = Column(Integer) # ???
    +    target_position = Column(Integer) # ???
    +
    +    # endregion
    +
    +    # region foreign keys
    +
    +    @declared_attr
    +    def type_fk(cls):
    +        """For Relationship many-to-one to Type"""
    +        return relationships.fk('type', nullable=True)
    +
    +    @declared_attr
    +    def source_node_fk(cls):
    +        """For Node one-to-many to Relationship"""
    +        return relationships.fk('node')
    +
    +    @declared_attr
    +    def target_node_fk(cls):
    +        """For Node one-to-many to Relationship"""
    +        return relationships.fk('node')
    +
    +    @declared_attr
    +    def target_capability_fk(cls):
    +        """For Relationship one-to-one to Capability"""
    +        return relationships.fk('capability', nullable=True)
    +
    +    @declared_attr
    +    def requirement_template_fk(cls):
    +        """For Relationship many-to-one to RequirementTemplate"""
    +        return relationships.fk('requirement_template', nullable=True)
    +
    +    @declared_attr
    +    def relationship_template_fk(cls):
    +        """For Relationship many-to-one to RelationshipTemplate"""
    +        return relationships.fk('relationship_template', nullable=True)
    +
    +    # endregion
    +
    +    # region association proxies
    +
    +    @declared_attr
    +    def source_node_name(cls):
    +        """Required for use by SQLAlchemy queries"""
    +        return association_proxy('source_node', 'name')
    +
    +    @declared_attr
    +    def target_node_name(cls):
    +        """Required for use by SQLAlchemy queries"""
    +        return association_proxy('target_node', 'name')
    +
    +    # endregion
    +
    +    @property
    +    def as_raw(self):
    +        return collections.OrderedDict((
    +            ('name', self.name),
    +            ('target_node_id', self.target_node.name),
    +            ('type_name', self.type.name
    +             if self.type is not None else None),
    +            ('template_name', self.relationship_template.name
    +             if self.relationship_template is not None else None),
    +            ('properties', formatting.as_raw_dict(self.properties)),
    +            ('interfaces', formatting.as_raw_list(self.interfaces))))
    +
    +    def validate(self):
    +        utils.validate_dict_values(self.properties)
    +        utils.validate_dict_values(self.interfaces)
    +
    +    def coerce_values(self, container, report_issues):
    +        utils.coerce_dict_values(container, self.properties, report_issues)
    +        utils.coerce_dict_values(container, self.interfaces, report_issues)
    +
    +    def dump(self):
    +        context = ConsumptionContext.get_thread_local()
    +        if self.name:
    +            console.puts('{0} ->'.format(context.style.node(self.name)))
    +        else:
    +            console.puts('->')
    +        with context.style.indent:
    +            console.puts('Node: {0}'.format(context.style.node(self.target_node.name)))
    +            if self.target_capability:
    +                console.puts('Capability: {0}'.format(context.style.node(
    +                    self.target_capability.name)))
    +            if self.type is not None:
    +                console.puts('Relationship type: {0}'.format(context.style.type(self.type.name)))
    +            if (self.relationship_template is not None) and self.relationship_template.name:
    +                console.puts('Relationship template: {0}'.format(
    +                    context.style.node(self.relationship_template.name)))
    +            utils.dump_dict_values(self.properties, 'Properties')
    +            utils.dump_interfaces(self.interfaces, 'Interfaces')
    +
    +    __private_fields__ = ['type_fk',
    --- End diff --
    
    I always prefer everything private to be pushed to the end, because it's an implementation
detail. People reading the code want to see what's public first. But I will change it to your
preference.


> Integrate new models into parser
> --------------------------------
>
>                 Key: ARIA-105
>                 URL: https://issues.apache.org/jira/browse/ARIA-105
>             Project: AriaTosca
>          Issue Type: Task
>            Reporter: Ran Ziv
>            Assignee: Tal Liron
>




--
This message was sent by Atlassian JIRA
(v6.3.15#6346)


Mime
View raw message