Added cluster template creator/state machine class. 75/47975/1
authorspisarski <s.pisarski@cablelabs.com>
Tue, 28 Nov 2017 20:16:54 +0000 (13:16 -0700)
committerspisarski <s.pisarski@cablelabs.com>
Tue, 28 Nov 2017 20:16:54 +0000 (13:16 -0700)
Created class and tests for creating and managing cluster templates.

JIRA: SNAPS-235

Change-Id: Ia91aef9507fc39d1814dce03169aab0b784721a6
Signed-off-by: spisarski <s.pisarski@cablelabs.com>
docs/how-to-use/IntegrationTests.rst
snaps/config/cluster_template.py
snaps/config/tests/cluster_template_tests.py
snaps/domain/cluster_template.py
snaps/openstack/cluster_template.py [new file with mode: 0644]
snaps/openstack/openstack_creator.py
snaps/openstack/tests/cluster_template_tests.py [new file with mode: 0644]
snaps/openstack/utils/magnum_utils.py
snaps/openstack/utils/tests/magnum_utils_tests.py
snaps/test_suite_builder.py

index f3d17f7..80c93d0 100644 (file)
@@ -669,3 +669,38 @@ ansible_utils_tests.py - AnsibleProvisioningTests
 |                                       | Neutron 2     | apply a Ansible playbook containing Jinga2 substitution   |
 |                                       |               | values                                                    |
 +---------------------------------------+---------------+-----------------------------------------------------------+
+
+cluster_template_tests.py - CreateClusterTemplateTests
+------------------------------------------------------
+
++----------------------------------------+---------------+-----------------------------------------------------------+
+| Test Name                              |  Magnum API   | Description                                               |
++========================================+===============+===========================================================+
+| test_create_cluster_template           | 1             | Tests the creation of a Cluster template with the class   |
+|                                        |               | OpenStackClusterTemplate                                  |
++----------------------------------------+---------------+-----------------------------------------------------------+
+| test_create_delete_cluster_template    | 1             | Tests the creation and deletiong of a Cluster template    |
+|                                        |               | with the class OpenStackClusterTemplate                   |
++----------------------------------------+---------------+-----------------------------------------------------------+
+| test_create_same_cluster_template      | 1             | Tests the creation of a Cluster template 2x using the same|
+|                                        |               | config object to ensure it was only created once          |
++----------------------------------------+---------------+-----------------------------------------------------------+
+| test_create_cluster_template_bad_flavor| 1             | Tests to ensure OpenStackClusterTemplate#create() will    |
+|                                        |               | raise an exception when the flavor is invalid             |
++----------------------------------------+---------------+-----------------------------------------------------------+
+| test_create_cluster_template_bad_master| 1             | Tests to ensure OpenStackClusterTemplate#create() will    |
+| _flavor                                |               | raise an exception when the master flavor is invalid      |
++----------------------------------------+---------------+-----------------------------------------------------------+
+| test_create_cluster_template_bad_image | 1             | Tests to ensure OpenStackClusterTemplate#create() will    |
+|                                        |               | raise an exception when the image is invalid              |
++----------------------------------------+---------------+-----------------------------------------------------------+
+| test_create_cluster_template_bad       | 1             | Tests to ensure OpenStackClusterTemplate#create() will    |
+| _keypair                               |               | raise an exception when the keypair is invalid            |
++----------------------------------------+---------------+-----------------------------------------------------------+
+| test_create_cluster_template_bad       | 1             | Tests to ensure OpenStackClusterTemplate#create() will    |
+| _network_driver                        |               | raise an exception when the network driver is invalid     |
++----------------------------------------+---------------+-----------------------------------------------------------+
+| test_create_cluster_template_bad       | 1             | Tests to ensure OpenStackClusterTemplate#create() will    |
+| _volume_driver                         |               | raise an exception when the volume driver is invalid      |
++----------------------------------------+---------------+-----------------------------------------------------------+
+
index a20225a..a9ef45c 100644 (file)
@@ -50,7 +50,7 @@ class ClusterTemplateConfig(object):
     def __init__(self, **kwargs):
         """
         Constructor
-        :param name: the cluster type's name (required)
+        :param name: the cluster template's name (required)
         :param image: name or ID of the base image in Glance used to boot the
                       cluster's servers. The image must have the attribute
                       'os-distro' defined as appropriate for the cluster
@@ -110,7 +110,7 @@ class ClusterTemplateConfig(object):
                                This is configured in the private Neutron
                                network for the bay/cluster.
                                (default provided by Magnum - 8.8.8.8)
-        :param public: denotes whether or not the cluster type is public
+        :param public: denotes whether or not the cluster template is public
                        (default False)
         :param tls_disabled: denotes whether or not TLS should be enabled
                              (default False)
@@ -177,9 +177,9 @@ class ClusterTemplateConfig(object):
 
         if (not self.name or not self.image or not self.keypair
                 or not self.external_net):
-            raise ClusterTypeConfigError(
+            raise ClusterTemplateConfigError(
                 'The attributes name, image, keypair, and '
-                'external_net are required for ClusterTypeConfig')
+                'external_net are required for ClusterTemplateConfig')
 
     def magnum_dict(self):
         """
@@ -243,9 +243,9 @@ class ClusterTemplateConfig(object):
         return out
 
 
-class ClusterTypeConfigError(Exception):
+class ClusterTemplateConfigError(Exception):
     """
-    Exception to be thrown when a cluster type configuration is incorrect
+    Exception to be thrown when a cluster template configuration is incorrect
     """
 
 
@@ -265,7 +265,8 @@ def map_server_type(server_type):
         for this_type in ServerType:
             if this_type.value == server_type:
                 return this_type
-        raise ClusterTypeConfigError('Invalid server type - ' + server_type)
+        raise ClusterTemplateConfigError(
+            'Invalid server type - ' + server_type)
 
 
 def map_coe(coe):
@@ -284,7 +285,7 @@ def map_coe(coe):
         for this_type in ContainerOrchestrationEngine:
             if this_type.value == coe:
                 return this_type
-        raise ClusterTypeConfigError('Invalid COE - ' + coe)
+        raise ClusterTemplateConfigError('Invalid COE - ' + coe)
 
 
 def map_docker_storage_driver(driver):
@@ -303,4 +304,5 @@ def map_docker_storage_driver(driver):
         for this_type in DockerStorageDriver:
             if this_type.value == driver:
                 return this_type
-        raise ClusterTypeConfigError('Invalid DockerStorageDriver - ' + driver)
+        raise ClusterTemplateConfigError(
+            'Invalid DockerStorageDriver - ' + driver)
index 5c695b9..e06b783 100644 (file)
@@ -14,9 +14,9 @@
 # limitations under the License.
 import unittest
 
-from snaps.config.cluster_template import ClusterTemplateConfig, \
-    ClusterTypeConfigError, ServerType, DockerStorageDriver, \
-    ContainerOrchestrationEngine
+from snaps.config.cluster_template import (
+    ClusterTemplateConfig, ClusterTemplateConfigError, ServerType,
+    DockerStorageDriver, ContainerOrchestrationEngine)
 
 
 class ClusterTemplateConfigUnitTests(unittest.TestCase):
@@ -25,15 +25,15 @@ class ClusterTemplateConfigUnitTests(unittest.TestCase):
     """
 
     def test_no_params(self):
-        with self.assertRaises(ClusterTypeConfigError):
+        with self.assertRaises(ClusterTemplateConfigError):
             ClusterTemplateConfig()
 
     def test_empty_config(self):
-        with self.assertRaises(ClusterTypeConfigError):
+        with self.assertRaises(ClusterTemplateConfigError):
             ClusterTemplateConfig(config=dict())
 
     def test_name_only(self):
-        with self.assertRaises(ClusterTypeConfigError):
+        with self.assertRaises(ClusterTemplateConfigError):
             ClusterTemplateConfig(name='foo')
 
     def test_minimal_named(self):
index 01af88a..83892b2 100644 (file)
@@ -131,3 +131,45 @@ class ClusterTemplate(object):
         self.volume_driver = kwargs.get('volume_driver')
         self.master_lb_enabled = kwargs.get('master_lb_enabled', True)
         self.labels = kwargs.get('labels')
+
+    def __eq__(self, other):
+        labels_eq = False
+        if (self.labels and isinstance(self.labels, dict)
+                and len(self.labels) == 0):
+            if (other.labels and isinstance(other.labels, dict)
+                    and len(other.labels) == 0):
+                labels_eq = True
+        elif not self.labels:
+            if (not other.labels or
+                    (isinstance(other.labels, dict)
+                     and len(other.labels) == 0)):
+                labels_eq = True
+        else:
+            labels_eq = self.labels == other.labels
+
+        return (self.name == other.name
+                and self.id == other.id
+                and self.image == other.image
+                and self.keypair == other.keypair
+                and self.network_driver == other.network_driver
+                and self.external_net == other.external_net
+                and self.floating_ip_enabled == other.floating_ip_enabled
+                and self.docker_volume_size == other.docker_volume_size
+                and self.server_type == other.server_type
+                and self.flavor == other.flavor
+                and self.master_flavor == other.master_flavor
+                and self.coe == other.coe
+                and self.fixed_net == other.fixed_net
+                and self.fixed_subnet == other.fixed_subnet
+                and self.registry_enabled == other.registry_enabled
+                and self.insecure_registry == other.insecure_registry
+                and self.docker_storage_driver == other.docker_storage_driver
+                and self.dns_nameserver == other.dns_nameserver
+                and self.public == other.public
+                and self.tls_disabled == other.tls_disabled
+                and self.http_proxy == other.http_proxy
+                and self.https_proxy == other.https_proxy
+                and self.no_proxy == other.no_proxy
+                and self.volume_driver == other.volume_driver
+                and self.master_lb_enabled == other.master_lb_enabled
+                and labels_eq)
diff --git a/snaps/openstack/cluster_template.py b/snaps/openstack/cluster_template.py
new file mode 100644 (file)
index 0000000..c4ba76d
--- /dev/null
@@ -0,0 +1,94 @@
+# Copyright (c) 2017 Cable Television Laboratories, Inc. ("CableLabs")
+#                    and others.  All rights reserved.
+#
+# Licensed 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 logging
+
+from magnumclient.common.apiclient.exceptions import NotFound
+
+from snaps.openstack.openstack_creator import OpenStackMagnumObject
+from snaps.openstack.utils import magnum_utils
+
+__author__ = 'spisarski'
+
+logger = logging.getLogger('cluster_template')
+
+
+class OpenStackClusterTemplate(OpenStackMagnumObject):
+    """
+    Class responsible for managing an volume in OpenStack
+    """
+
+    def __init__(self, os_creds, cluster_template_config):
+        """
+        Constructor
+        :param os_creds: The OpenStack connection credentials
+        :param cluster_template_config: The volume type settings
+        :return:
+        """
+        super(self.__class__, self).__init__(os_creds)
+
+        self.cluster_template_config = cluster_template_config
+        self.__cluster_template = None
+
+    def initialize(self):
+        """
+        Loads the existing Volume
+        :return: The Volume domain object or None
+        """
+        super(self.__class__, self).initialize()
+
+        self.__cluster_template = magnum_utils.get_cluster_template(
+            self._magnum, template_config=self.cluster_template_config)
+
+        return self.__cluster_template
+
+    def create(self):
+        """
+        Creates the volume in OpenStack if it does not already exist and
+        returns the domain Volume object
+        :return: The Volume domain object or None
+        """
+        self.initialize()
+
+        if not self.__cluster_template:
+            self.__cluster_template = magnum_utils.create_cluster_template(
+                self._magnum, self.cluster_template_config)
+            logger.info(
+                'Created volume type with name - %s',
+                self.cluster_template_config.name)
+
+        return self.__cluster_template
+
+    def clean(self):
+        """
+        Cleanse environment of all artifacts
+        :return: void
+        """
+        if self.__cluster_template:
+            try:
+                magnum_utils.delete_cluster_template(
+                    self._magnum, self.__cluster_template.id)
+            except NotFound:
+                pass
+
+        self.__cluster_template = None
+
+    def get_cluster_template(self):
+        """
+        Returns the domain Volume object as it was populated when create() was
+        called
+        :return: the object
+        """
+        return self.__cluster_template
index 945a78b..0caee9a 100644 (file)
@@ -13,8 +13,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 from snaps.domain.creator import CloudObject
-from snaps.openstack.utils import (nova_utils, neutron_utils, keystone_utils,
-                                   cinder_utils)
+from snaps.openstack.utils import (
+    nova_utils, neutron_utils, keystone_utils, cinder_utils, magnum_utils)
 
 __author__ = 'spisarski'
 
@@ -132,3 +132,26 @@ class OpenStackVolumeObject(OpenStackCloudObject):
 
     def clean(self):
         raise NotImplementedError('Do not override abstract method')
+
+
+class OpenStackMagnumObject(OpenStackCloudObject):
+    """
+    Abstract class for all OpenStack compute creators
+    """
+
+    def __init__(self, os_creds):
+        """
+        Constructor
+        :param os_creds: the OpenStack credentials object
+        """
+        super(OpenStackMagnumObject, self).__init__(os_creds)
+        self._magnum = None
+
+    def initialize(self):
+        self._magnum = magnum_utils.magnum_client(self._os_creds)
+
+    def create(self):
+        raise NotImplementedError('Do not override abstract method')
+
+    def clean(self):
+        raise NotImplementedError('Do not override abstract method')
diff --git a/snaps/openstack/tests/cluster_template_tests.py b/snaps/openstack/tests/cluster_template_tests.py
new file mode 100644 (file)
index 0000000..791ace2
--- /dev/null
@@ -0,0 +1,301 @@
+# Copyright (c) 2017 Cable Television Laboratories, Inc. ("CableLabs")
+#                    and others.  All rights reserved.
+#
+# Licensed 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 magnumclient.common.apiclient.exceptions import BadRequest, NotFound
+
+from snaps.config.cluster_template import ClusterTemplateConfig
+from snaps.config.flavor import FlavorConfig
+from snaps.config.keypair import KeypairConfig
+from snaps.openstack.cluster_template import OpenStackClusterTemplate
+from snaps.openstack.create_flavor import OpenStackFlavor
+from snaps.openstack.create_image import OpenStackImage
+from snaps.openstack.create_keypairs import OpenStackKeypair
+from snaps.openstack.tests import openstack_tests
+
+try:
+    from urllib.request import URLError
+except ImportError:
+    from urllib2 import URLError
+
+import logging
+import uuid
+
+from snaps.openstack.tests.os_source_file_test import OSIntegrationTestCase
+from snaps.openstack.utils import magnum_utils
+
+__author__ = 'spisarski'
+
+logger = logging.getLogger('cluster_template_tests')
+
+
+class CreateClusterTemplateTests(OSIntegrationTestCase):
+    """
+    Test for the OpenStackClusterTemplate class defined in py
+    without any QoS Specs or Encryption
+    """
+
+    def setUp(self):
+        """
+        Instantiates the CreateClusterTemplate object that is responsible for
+        downloading and creating an OS template config file within OpenStack
+        """
+        super(self.__class__, self).__start__()
+
+        self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
+        self.cluster_type_name = self.guid + '-cluster-type'
+        self.magnum = magnum_utils.magnum_client(self.os_creds)
+
+        metadata = self.image_metadata
+        if not metadata:
+            metadata = dict()
+        if 'extra_properties' not in metadata:
+            metadata['extra_properties'] = dict()
+        metadata['extra_properties']['os_distro'] = 'cirros'
+
+        os_image_settings = openstack_tests.cirros_image_settings(
+            name=self.guid + '-image', image_metadata=metadata)
+
+        self.image_creator = OpenStackImage(self.os_creds, os_image_settings)
+
+        self.flavor_creator = OpenStackFlavor(
+            self.os_creds, FlavorConfig(
+                name=self.guid + '-flavor', ram=512, disk=10, vcpus=1))
+
+        keypair_priv_filepath = 'tmp/' + self.guid
+        keypair_pub_filepath = keypair_priv_filepath + '.pub'
+
+        self.keypair_creator = OpenStackKeypair(
+            self.os_creds, KeypairConfig(
+                name=self.guid + '-keypair',
+                public_filepath=keypair_pub_filepath,
+                private_filepath=keypair_priv_filepath))
+
+        self.cluster_template_creator = None
+
+        self.cluster_template_config = ClusterTemplateConfig(
+            name=self.cluster_type_name,
+            image=self.image_creator.image_settings.name,
+            keypair=self.keypair_creator.keypair_settings.name,
+            external_net=self.ext_net_name,
+            flavor=self.flavor_creator.flavor_settings.name)
+
+        try:
+            self.image_creator.create()
+            self.flavor_creator.create()
+            self.keypair_creator.create()
+        except:
+            self.tearDown()
+            raise
+
+    def tearDown(self):
+        """
+        Cleans the template config
+        """
+        if self.cluster_template_creator:
+            try:
+                self.cluster_template_creator.clean()
+            except:
+                pass
+        if self.keypair_creator:
+            try:
+                self.keypair_creator.clean()
+            except:
+                pass
+        if self.flavor_creator:
+            try:
+                self.flavor_creator.clean()
+            except:
+                pass
+        if self.image_creator:
+            try:
+                self.image_creator.clean()
+            except:
+                pass
+
+        super(self.__class__, self).__clean__()
+
+    def test_create_cluster_template(self):
+        """
+        Tests the creation of an OpenStack cluster template.
+        """
+        # Create ClusterTemplate
+        self.cluster_template_creator = OpenStackClusterTemplate(
+            self.os_creds, self.cluster_template_config)
+        created_cluster_template = self.cluster_template_creator.create()
+        self.assertIsNotNone(created_cluster_template)
+        self.assertEqual(self.cluster_template_config.name,
+                         created_cluster_template.name)
+
+        retrieved_cluster_template1 = magnum_utils.get_cluster_template(
+            self.magnum, template_config=self.cluster_template_config)
+        self.assertIsNotNone(retrieved_cluster_template1)
+        self.assertEqual(created_cluster_template, retrieved_cluster_template1)
+
+        retrieved_cluster_template2 = magnum_utils.get_cluster_template_by_id(
+            self.magnum, created_cluster_template.id)
+        self.assertEqual(created_cluster_template, retrieved_cluster_template2)
+
+    def test_create_delete_cluster_template(self):
+        """
+        Tests the creation then deletion of an OpenStack template config to
+        ensure clean() does not raise an Exception.
+        """
+        # Create ClusterTemplate
+        self.cluster_template_creator = OpenStackClusterTemplate(
+            self.os_creds, self.cluster_template_config)
+        created_cluster_template = self.cluster_template_creator.create()
+        self.assertIsNotNone(created_cluster_template)
+
+        self.cluster_template_creator.clean()
+
+        tmplt = magnum_utils.get_cluster_template(
+            self.magnum, template_name=self.cluster_template_config.name)
+        self.assertIsNone(tmplt)
+
+    def test_create_same_cluster_template(self):
+        """
+        Tests the creation of an OpenStack cluster_template when one already
+        exists.
+        """
+        # Create ClusterTemplate
+        self.cluster_template_creator = OpenStackClusterTemplate(
+            self.os_creds, self.cluster_template_config)
+        cluster_template1 = self.cluster_template_creator.create()
+
+        retrieved_cluster_template = magnum_utils.get_cluster_template(
+            self.magnum, template_config=self.cluster_template_config)
+        self.assertEqual(cluster_template1, retrieved_cluster_template)
+
+        # Should be retrieving the instance data
+        os_cluster_template_2 = OpenStackClusterTemplate(
+            self.os_creds, self.cluster_template_config)
+        cluster_template2 = os_cluster_template_2.create()
+        self.assertEqual(cluster_template2, cluster_template2)
+
+    def test_create_cluster_template_bad_flavor(self):
+        """
+        Tests the creation of an OpenStack cluster template raises an
+        exception with an invalid flavor.
+        """
+        # Create ClusterTemplate
+        cluster_template_config = ClusterTemplateConfig(
+            name=self.cluster_type_name,
+            image=self.image_creator.image_settings.name,
+            keypair=self.keypair_creator.keypair_settings.name,
+            external_net=self.ext_net_name,
+            flavor='foo')
+
+        self.cluster_template_creator = OpenStackClusterTemplate(
+            self.os_creds, cluster_template_config)
+
+        with self.assertRaises(BadRequest):
+            self.cluster_template_creator.create()
+
+    def test_create_cluster_template_bad_master_flavor(self):
+        """
+        Tests the creation of an OpenStack cluster template raises an
+        exception with an invalid master flavor.
+        """
+        # Create ClusterTemplate
+        cluster_template_config = ClusterTemplateConfig(
+            name=self.cluster_type_name,
+            image=self.image_creator.image_settings.name,
+            keypair=self.keypair_creator.keypair_settings.name,
+            external_net=self.ext_net_name,
+            flavor=self.flavor_creator.flavor_settings.name,
+            master_flavor='foo')
+
+        self.cluster_template_creator = OpenStackClusterTemplate(
+            self.os_creds, cluster_template_config)
+
+        with self.assertRaises(BadRequest):
+            self.cluster_template_creator.create()
+
+    def test_create_cluster_template_bad_image(self):
+        """
+        Tests the creation of an OpenStack cluster template raises an
+        exception with an invalid image.
+        """
+        # Create ClusterTemplate
+        cluster_template_config = ClusterTemplateConfig(
+            name=self.cluster_type_name,
+            image='foo',
+            keypair=self.keypair_creator.keypair_settings.name,
+            external_net=self.ext_net_name,
+            flavor=self.flavor_creator.flavor_settings.name)
+
+        self.cluster_template_creator = OpenStackClusterTemplate(
+            self.os_creds, cluster_template_config)
+
+        with self.assertRaises(BadRequest):
+            self.cluster_template_creator.create()
+
+    def test_create_cluster_template_bad_keypair(self):
+        """
+        Tests the creation of an OpenStack cluster template raises an
+        exception with an invalid keypair.
+        """
+        # Create ClusterTemplate
+        cluster_template_config = ClusterTemplateConfig(
+            name=self.cluster_type_name,
+            image=self.image_creator.image_settings.name,
+            keypair='foo',
+            external_net=self.ext_net_name,
+            flavor=self.flavor_creator.flavor_settings.name)
+
+        self.cluster_template_creator = OpenStackClusterTemplate(
+            self.os_creds, cluster_template_config)
+
+        with self.assertRaises(NotFound):
+            self.cluster_template_creator.create()
+
+    def test_create_cluster_template_bad_network_driver(self):
+        """
+        Tests the creation of an OpenStack cluster template raises an
+        exception with an invalid keypair.
+        """
+        # Create ClusterTemplate
+        cluster_template_config = ClusterTemplateConfig(
+            name=self.cluster_type_name,
+            image=self.image_creator.image_settings.name,
+            keypair=self.keypair_creator.keypair_settings.name,
+            external_net=self.ext_net_name,
+            flavor=self.flavor_creator.flavor_settings.name,
+            network_driver='foo')
+
+        self.cluster_template_creator = OpenStackClusterTemplate(
+            self.os_creds, cluster_template_config)
+
+        with self.assertRaises(BadRequest):
+            self.cluster_template_creator.create()
+
+    def test_create_cluster_template_bad_volume_driver(self):
+        """
+        Tests the creation of an OpenStack cluster template raises an
+        exception with an invalid keypair.
+        """
+        # Create ClusterTemplate
+        cluster_template_config = ClusterTemplateConfig(
+            name=self.cluster_type_name,
+            image=self.image_creator.image_settings.name,
+            keypair=self.keypair_creator.keypair_settings.name,
+            external_net=self.ext_net_name,
+            flavor=self.flavor_creator.flavor_settings.name,
+            volume_driver='foo')
+
+        self.cluster_template_creator = OpenStackClusterTemplate(
+            self.os_creds, cluster_template_config)
+
+        with self.assertRaises(BadRequest):
+            self.cluster_template_creator.create()
index c744666..96ba6d1 100644 (file)
@@ -35,6 +35,36 @@ def magnum_client(os_creds):
                   session=keystone_utils.keystone_session(os_creds))
 
 
+def get_cluster_template(magnum, template_config=None, template_name=None):
+    """
+    Returns the first ClusterTemplate domain object that matches the parameters
+    :param magnum: the Magnum client
+    :param template_config: a ClusterTemplateConfig object (optional)
+    :param template_name: the name of the template to lookup
+    :return: ClusterTemplate object or None
+    """
+    name = None
+    if template_config:
+        name = template_config.name
+    elif template_name:
+        name = template_name
+
+    os_templates = magnum.cluster_templates.list()
+    for os_template in os_templates:
+        if os_template.name == name:
+            return __map_os_cluster_template(os_template)
+
+
+def get_cluster_template_by_id(magnum, tmplt_id):
+    """
+    Returns the first ClusterTemplate domain object that matches the parameters
+    :param magnum: the Magnum client
+    :param tmplt_id: the template's ID
+    :return: ClusterTemplate object or None
+    """
+    return __map_os_cluster_template(magnum.cluster_templates.get(tmplt_id))
+
+
 def create_cluster_template(magnum, cluster_template_config):
     """
     Creates a Magnum Cluster Template object in OpenStack
index f6da810..766e3f2 100644 (file)
@@ -144,6 +144,13 @@ class MagnumUtilsClusterTypeTests(OSComponentTestCase):
         self.assertTrue(
             validate_cluster_template(config, self.cluster_template))
 
+        template_by_name = magnum_utils.get_cluster_template(
+            self.magnum, template_name=config.name)
+        self.assertEqual(self.cluster_template, template_by_name)
+        template_by_id = magnum_utils.get_cluster_template_by_id(
+            self.magnum, self.cluster_template.id)
+        self.assertEqual(self.cluster_template, template_by_id)
+
     def test_create_cluster_template_all(self):
         config = ClusterTemplateConfig(
             name=self.cluster_type_name,
@@ -168,6 +175,13 @@ class MagnumUtilsClusterTypeTests(OSComponentTestCase):
         self.assertTrue(
             validate_cluster_template(config, self.cluster_template))
 
+        template_by_name = magnum_utils.get_cluster_template(
+            self.magnum, template_name=config.name)
+        self.assertEqual(self.cluster_template, template_by_name)
+        template_by_id = magnum_utils.get_cluster_template_by_id(
+            self.magnum, self.cluster_template.id)
+        self.assertEqual(self.cluster_template, template_by_id)
+
     def test_create_cluster_template_bad_image(self):
         config = ClusterTemplateConfig(
             name=self.cluster_type_name,
index 27d4f85..e73c400 100644 (file)
@@ -55,6 +55,8 @@ from snaps.domain.test.vm_inst_tests import (
 from snaps.domain.test.volume_tests import (
     QoSSpecDomainObjectTests, VolumeTypeDomainObjectTests,
     VolumeTypeEncryptionObjectTests, VolumeDomainObjectTests)
+from snaps.openstack.tests.cluster_template_tests import (
+    CreateClusterTemplateTests)
 from snaps.openstack.tests.conf.os_credentials_tests import (
     ProxySettingsUnitTests, OSCredsUnitTests)
 from snaps.openstack.tests.create_flavor_tests import (
@@ -729,3 +731,6 @@ def add_openstack_staging_tests(suite, os_creds, ext_net_name,
     suite.addTest(OSComponentTestCase.parameterize(
         MagnumUtilsClusterTypeTests, os_creds=os_creds,
         ext_net_name=ext_net_name, log_level=log_level))
+    suite.addTest(OSComponentTestCase.parameterize(
+        CreateClusterTemplateTests, os_creds=os_creds,
+        ext_net_name=ext_net_name, log_level=log_level))