Repository: incubator-ariatosca
Updated Branches:
  refs/heads/ARIA-122-Create-central-instantiation-module [created] c7e28595d


initial commit


Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo
Commit: 
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/c7e28595
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/c7e28595
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/c7e28595

Branch: refs/heads/ARIA-122-Create-central-instantiation-module
Commit: c7e28595d1e6dcb10aaac1169f0a53a0218b71ee
Parents: c0d76ad
Author: max-orlov <[email protected]>
Authored: Thu Mar 9 15:22:23 2017 +0200
Committer: max-orlov <[email protected]>
Committed: Thu Mar 9 15:22:23 2017 +0200

----------------------------------------------------------------------
 aria/orchestrator/instantiation.py         | 52 ++++++++++++++++
 aria/storage/modeling/structure.py         |  4 +-
 aria/storage/modeling/template_elements.py | 48 ++++++++++-----
 tests/conftest.py                          |  3 +-
 tests/orchestrator/test_instantiation.py   | 79 +++++++++++++++++++++++++
 5 files changed, 169 insertions(+), 17 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/c7e28595/aria/orchestrator/instantiation.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/instantiation.py 
b/aria/orchestrator/instantiation.py
new file mode 100644
index 0000000..a3b36bb
--- /dev/null
+++ b/aria/orchestrator/instantiation.py
@@ -0,0 +1,52 @@
+# 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.
+from aria.storage.modeling import utils
+from aria.utils.collections import deepcopy_with_locators
+from aria.storage.modeling import model
+
+
[email protected](instance_cls=model.ServiceInstance)
+def instantiate_service_instance(self, instance_cls, context, container):
+    service_instance = instance_cls
+    context.modeling.instance = service_instance
+
+    service_instance.description = deepcopy_with_locators(self.description)
+
+    if self.metadata is not None:
+        service_instance.metadata = self.metadata.instantiate(context, 
container)
+
+    for node_template in self.node_templates.itervalues():
+        for _ in range(node_template.default_instances):
+            node = node_template.instantiate(context, container)
+            service_instance.nodes[node.id] = node
+
+    utils.instantiate_dict(context, self, service_instance.groups, 
self.group_templates)
+    utils.instantiate_dict(context, self, service_instance.policies, 
self.policy_templates)
+    utils.instantiate_dict(context, self, service_instance.operations, 
self.operation_templates)
+
+    if self.substitution_template is not None:
+        service_instance.substitution = 
self.substitution_template.instantiate(context,
+                                                                               
container)
+
+    utils.instantiate_dict(context, self, service_instance.inputs, self.inputs)
+    utils.instantiate_dict(context, self, service_instance.outputs, 
self.outputs)
+
+    for name, the_input in context.modeling.inputs.iteritems():
+        if name not in service_instance.inputs:
+            context.validation.report('input "%s" is not supported' % name)
+        else:
+            service_instance.inputs[name].value = the_input
+
+    return service_instance
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/c7e28595/aria/storage/modeling/structure.py
----------------------------------------------------------------------
diff --git a/aria/storage/modeling/structure.py 
b/aria/storage/modeling/structure.py
index eacdb44..4ee6951 100644
--- a/aria/storage/modeling/structure.py
+++ b/aria/storage/modeling/structure.py
@@ -88,8 +88,8 @@ class ModelElementBase(ElementBase):
 
     All model elements can be instantiated into :class:`ServiceInstance` 
elements.
     """
-
-    def instantiate(self, context, container):
+    @classmethod
+    def instantiate(cls, *args, **kwargs):
         raise NotImplementedError
 
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/c7e28595/aria/storage/modeling/template_elements.py
----------------------------------------------------------------------
diff --git a/aria/storage/modeling/template_elements.py 
b/aria/storage/modeling/template_elements.py
index 4212b15..77d54a7 100644
--- a/aria/storage/modeling/template_elements.py
+++ b/aria/storage/modeling/template_elements.py
@@ -13,7 +13,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 from copy import deepcopy
-from types import FunctionType
+from functools import partial
+from types import FunctionType, MethodType
 
 from sqlalchemy import (
     Column,
@@ -41,7 +42,26 @@ from . import (
 # region Element templates
 
 
-class ServiceTemplateBase(structure.ModelMixin):
+class TemplateBase(structure.ModelMixin):
+
+    @classmethod
+    def instantiates(cls, func=None, instance_cls=None, override=False):
+        if not override:
+            try:
+                cls.instantiate()
+            except NotImplementedError:
+                pass
+            else:
+                # TODO: raise proper exception
+                raise BaseException("instantiation method was already 
registered for {0}"
+                                    .format(cls.__name__))
+        if func is None:
+            return partial(cls.instantiates, instance_cls=instance_cls, 
override=override)
+
+        cls.instantiate = MethodType(partial(func, instance_cls=instance_cls), 
None, cls)
+
+
+class ServiceTemplateBase(TemplateBase):
 
     __tablename__ = 'service_template'
 
@@ -172,7 +192,7 @@ class ServiceTemplateBase(structure.ModelMixin):
         utils.dump_dict_values(context, self.operation_templates, 'Operation 
templates')
 
 
-class InterfaceTemplateBase(structure.ModelMixin):
+class InterfaceTemplateBase(TemplateBase):
     __tablename__ = 'interface_template'
 
     __private_fields__ = ['node_template_fk',
@@ -256,7 +276,7 @@ class InterfaceTemplateBase(structure.ModelMixin):
             utils.dump_dict_values(context, self.operation_templates, 
'Operation templates')
 
 
-class OperationTemplateBase(structure.ModelMixin):
+class OperationTemplateBase(TemplateBase):
     __tablename__ = 'operation_template'
 
     __private_fields__ = ['service_template_fk',
@@ -351,7 +371,7 @@ class OperationTemplateBase(structure.ModelMixin):
             dump_parameters(context, self.inputs, 'Inputs')
 
 
-class ArtifactTemplateBase(structure.ModelMixin):
+class ArtifactTemplateBase(TemplateBase):
     """
     A file associated with a :class:`NodeTemplate`.
 
@@ -448,7 +468,7 @@ class ArtifactTemplateBase(structure.ModelMixin):
             dump_parameters(context, self.properties)
 
 
-class PolicyTemplateBase(structure.ModelMixin):
+class PolicyTemplateBase(TemplateBase):
     """
     Policies can be applied to zero or more :class:`NodeTemplate` or 
:class:`GroupTemplate`
     instances.
@@ -550,7 +570,7 @@ class PolicyTemplateBase(structure.ModelMixin):
                     (str(context.style.node(v)) for v in 
self.target_group_template_names)))
 
 
-class GroupPolicyTemplateBase(structure.ModelMixin):
+class GroupPolicyTemplateBase(TemplateBase):
     """
     Policies applied to groups.
 
@@ -624,7 +644,7 @@ class GroupPolicyTemplateBase(structure.ModelMixin):
             utils.dump_dict_values(context, self.triggers, 'Triggers')
 
 
-class GroupPolicyTriggerTemplateBase(structure.ModelMixin):
+class GroupPolicyTriggerTemplateBase(TemplateBase):
     """
     Triggers for :class:`GroupPolicyTemplate`.
 
@@ -697,7 +717,7 @@ class GroupPolicyTriggerTemplateBase(structure.ModelMixin):
             dump_parameters(context, self.properties)
 
 
-class MappingTemplateBase(structure.ModelMixin):
+class MappingTemplateBase(TemplateBase):
     """
     Used by :class:`SubstitutionTemplate` to map a capability or a requirement 
to a node.
 
@@ -744,7 +764,7 @@ class MappingTemplateBase(structure.ModelMixin):
                                       context.style.node(self.name)))
 
 
-class SubstitutionTemplateBase(structure.ModelMixin):
+class SubstitutionTemplateBase(TemplateBase):
     """
     Used to substitute a single node for the entire deployment.
 
@@ -815,7 +835,7 @@ class SubstitutionTemplateBase(structure.ModelMixin):
 
 # region Node templates
 
-class NodeTemplateBase(structure.ModelMixin):
+class NodeTemplateBase(TemplateBase):
     __tablename__ = 'node_template'
 
     __private_fields__ = ['service_template_fk',
@@ -939,7 +959,7 @@ class NodeTemplateBase(structure.ModelMixin):
             utils.dump_list_values(context, self.requirement_templates, 
'Requirement templates')
 
 
-class GroupTemplateBase(structure.ModelMixin):
+class GroupTemplateBase(TemplateBase):
     """
     A template for creating zero or more :class:`Group` instances.
 
@@ -1048,7 +1068,7 @@ class GroupTemplateBase(structure.ModelMixin):
 
 # region Relationship templates
 
-class RequirementTemplateBase(structure.ModelMixin):
+class RequirementTemplateBase(TemplateBase):
     """
     A requirement for a :class:`NodeTemplate`. During instantiation will be 
matched with a
     capability of another
@@ -1214,7 +1234,7 @@ class RequirementTemplateBase(structure.ModelMixin):
                     self.relationship_template.dump(context)
 
 
-class CapabilityTemplateBase(structure.ModelMixin):
+class CapabilityTemplateBase(TemplateBase):
     """
     A capability of a :class:`NodeTemplate`. Nodes expose zero or more 
capabilities that can be
     matched with :class:`Requirement` instances of other nodes.

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/c7e28595/tests/conftest.py
----------------------------------------------------------------------
diff --git a/tests/conftest.py b/tests/conftest.py
index c501eeb..9338bd6 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -22,7 +22,8 @@ import aria
 
 @pytest.fixture(scope='session', autouse=True)
 def install_aria_extensions():
-    aria.install_aria_extensions()
+    pass
+    # aria.install_aria_extensions()
 
 
 @pytest.fixture(autouse=True)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/c7e28595/tests/orchestrator/test_instantiation.py
----------------------------------------------------------------------
diff --git a/tests/orchestrator/test_instantiation.py 
b/tests/orchestrator/test_instantiation.py
new file mode 100644
index 0000000..e159e04
--- /dev/null
+++ b/tests/orchestrator/test_instantiation.py
@@ -0,0 +1,79 @@
+# 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.
+
+import pytest
+
+from aria.storage.modeling import model_base, structure
+
+
[email protected](autouse=True)
+def cleanup_instantiator(request):
+    instantiator = MockTemplate.instantiate
+
+    def clear_instantiator():
+        MockTemplate.instantiate = instantiator
+    request.addfinalizer(clear_instantiator)
+
+
+class MockTemplate(model_base.template_elements.TemplateBase):
+    def __init__(self, template_name):
+        self.template_name = template_name
+
+
+class MockInstnace(structure.ModelMixin):
+    def __init__(self, instance_name):
+        self.instance_name = instance_name
+
+
+def test_base_instantiation():
+    name = 'my_name'
+
+    @MockTemplate.instantiates(instance_cls=MockInstnace)
+    def initiator(self, instance_cls):
+        return instance_cls(self.template_name)
+
+    mock_template = MockTemplate(name)
+    mock_instance = mock_template.instantiate()
+
+    assert mock_instance.instance_name == mock_template.template_name == name
+
+
+def test_reinstantiate():
+
+    name = 'my_name'
+
+    @MockTemplate.instantiates(instance_cls=MockInstnace)
+    def initiator(self, instance_cls):
+        return instance_cls(self.template_name)
+
+    mock_template = MockTemplate(name)
+    mock_instance = mock_template.instantiate()
+    assert mock_instance.instance_name == mock_template.template_name == name
+
+    def new_initiator(self, instance_cls):
+        return instance_cls('new_{0}'.format(self.template_name))
+
+    with pytest.raises(BaseException):
+        MockTemplate.instantiates(func=new_initiator, 
instance_cls=MockInstnace)
+
+    mock_template = MockTemplate(name)
+    mock_instance = mock_template.instantiate()
+    assert mock_instance.instance_name == mock_template.template_name == name
+
+    MockTemplate.instantiates(func=new_initiator, instance_cls=MockInstnace, 
override=True)
+    mock_template = MockTemplate(name)
+    mock_instance = mock_template.instantiate()
+    assert mock_template.template_name == name
+    assert mock_instance.instance_name == 'new_{0}'.format(name)

Reply via email to