summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorspisarski <s.pisarski@cablelabs.com>2017-11-28 13:16:54 -0700
committerspisarski <s.pisarski@cablelabs.com>2017-11-28 13:16:54 -0700
commit530ca566f0554d69ac11dd3b919be25c2e689ed6 (patch)
tree1a2013266bfaa0ce467b38c7b3ffcf64eac8408d
parent0e06ebe62fcff9b491a0edd89bdf511f88d091e7 (diff)
Added cluster template creator/state machine class.
Created class and tests for creating and managing cluster templates. JIRA: SNAPS-235 Change-Id: Ia91aef9507fc39d1814dce03169aab0b784721a6 Signed-off-by: spisarski <s.pisarski@cablelabs.com>
-rw-r--r--docs/how-to-use/IntegrationTests.rst35
-rw-r--r--snaps/config/cluster_template.py20
-rw-r--r--snaps/config/tests/cluster_template_tests.py12
-rw-r--r--snaps/domain/cluster_template.py42
-rw-r--r--snaps/openstack/cluster_template.py94
-rw-r--r--snaps/openstack/openstack_creator.py27
-rw-r--r--snaps/openstack/tests/cluster_template_tests.py301
-rw-r--r--snaps/openstack/utils/magnum_utils.py30
-rw-r--r--snaps/openstack/utils/tests/magnum_utils_tests.py14
-rw-r--r--snaps/test_suite_builder.py5
10 files changed, 563 insertions, 17 deletions
diff --git a/docs/how-to-use/IntegrationTests.rst b/docs/how-to-use/IntegrationTests.rst
index f3d17f7..80c93d0 100644
--- a/docs/how-to-use/IntegrationTests.rst
+++ b/docs/how-to-use/IntegrationTests.rst
@@ -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 |
++----------------------------------------+---------------+-----------------------------------------------------------+
+
diff --git a/snaps/config/cluster_template.py b/snaps/config/cluster_template.py
index a20225a..a9ef45c 100644
--- a/snaps/config/cluster_template.py
+++ b/snaps/config/cluster_template.py
@@ -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)
diff --git a/snaps/config/tests/cluster_template_tests.py b/snaps/config/tests/cluster_template_tests.py
index 5c695b9..e06b783 100644
--- a/snaps/config/tests/cluster_template_tests.py
+++ b/snaps/config/tests/cluster_template_tests.py
@@ -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):
diff --git a/snaps/domain/cluster_template.py b/snaps/domain/cluster_template.py
index 01af88a..83892b2 100644
--- a/snaps/domain/cluster_template.py
+++ b/snaps/domain/cluster_template.py
@@ -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
index 0000000..c4ba76d
--- /dev/null
+++ b/snaps/openstack/cluster_template.py
@@ -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
diff --git a/snaps/openstack/openstack_creator.py b/snaps/openstack/openstack_creator.py
index 945a78b..0caee9a 100644
--- a/snaps/openstack/openstack_creator.py
+++ b/snaps/openstack/openstack_creator.py
@@ -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
index 0000000..791ace2
--- /dev/null
+++ b/snaps/openstack/tests/cluster_template_tests.py
@@ -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()
diff --git a/snaps/openstack/utils/magnum_utils.py b/snaps/openstack/utils/magnum_utils.py
index c744666..96ba6d1 100644
--- a/snaps/openstack/utils/magnum_utils.py
+++ b/snaps/openstack/utils/magnum_utils.py
@@ -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
diff --git a/snaps/openstack/utils/tests/magnum_utils_tests.py b/snaps/openstack/utils/tests/magnum_utils_tests.py
index f6da810..766e3f2 100644
--- a/snaps/openstack/utils/tests/magnum_utils_tests.py
+++ b/snaps/openstack/utils/tests/magnum_utils_tests.py
@@ -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,
diff --git a/snaps/test_suite_builder.py b/snaps/test_suite_builder.py
index 27d4f85..e73c400 100644
--- a/snaps/test_suite_builder.py
+++ b/snaps/test_suite_builder.py
@@ -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))