summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorspisarski <s.pisarski@cablelabs.com>2017-11-22 14:55:43 -0700
committerspisarski <s.pisarski@cablelabs.com>2017-11-22 16:24:12 -0700
commitfb6654aafdc5303077325691b7f468b27d7493c6 (patch)
tree68290a72557a5b3ae1ba79dda287203f7d29456a
parent0e377731a20617c9cdb886a597395c61ae490e38 (diff)
Implemented the ability to create Magnum Cluster Type objects.
This patch is the second of several necessary for the addition of Magnum support. This one implements a create and delete function to magnum_utils.py as well as the necessary config and domain classes for sending and receiving Cluster Type data to OpenStack. JIRA: SNAPS-233 Change-Id: Iad1959b98eaabc4ef5f41b70a23f6b1306259650 Signed-off-by: spisarski <s.pisarski@cablelabs.com>
-rw-r--r--docs/how-to-use/APITests.rst11
-rw-r--r--docs/how-to-use/UnitTests.rst12
-rw-r--r--snaps/config/cluster_template.py306
-rw-r--r--snaps/config/network.py9
-rw-r--r--snaps/config/tests/cluster_template_tests.py180
-rw-r--r--snaps/config/volume.py5
-rw-r--r--snaps/domain/cluster_template.py133
-rw-r--r--snaps/domain/test/cluster_template_tests.py109
-rw-r--r--snaps/openstack/tests/openstack_tests.py16
-rw-r--r--snaps/openstack/utils/magnum_utils.py73
-rw-r--r--snaps/openstack/utils/tests/magnum_utils_tests.py126
-rw-r--r--snaps/test_suite_builder.py12
12 files changed, 970 insertions, 22 deletions
diff --git a/docs/how-to-use/APITests.rst b/docs/how-to-use/APITests.rst
index ee0d894..6a7c317 100644
--- a/docs/how-to-use/APITests.rst
+++ b/docs/how-to-use/APITests.rst
@@ -544,6 +544,17 @@ heat_utils_tests.py - HeatUtilsFlavorTests
| | | Flavor domain objects deployed with Heat |
+---------------------------------------+---------------+-----------------------------------------------------------+
+magnum_utils_tests.py - MagnumUtilsTests
+----------------------------------------
+
++---------------------------------------+---------------+-----------------------------------------------------------+
+| Test Name | Magnum API | Description |
++=======================================+===============+===========================================================+
+| test_create_cluster_template_simple | 1 | Tests ability of the function |
+| | | magnum_utils.create_cluster_template() to create a simple |
+| | | cluster template OpenStack object with minimal config |
++---------------------------------------+---------------+-----------------------------------------------------------+
+
settings_utils_tests.py - SettingsUtilsNetworkingTests
------------------------------------------------------
diff --git a/docs/how-to-use/UnitTests.rst b/docs/how-to-use/UnitTests.rst
index cb0c5f3..5bd4f08 100644
--- a/docs/how-to-use/UnitTests.rst
+++ b/docs/how-to-use/UnitTests.rst
@@ -396,6 +396,18 @@ VmInstDomainObjectTests
Ensures that all required members are included when constructing a
VmInst domain object
+ClusterTemplateConfigUnitTests
+------------------------------
+
+Ensures that all required members are included when constructing a
+ClusterTemplateConfig object
+
+ClusterTemplateUnitTests
+------------------------
+
+Ensures that all required members are included when constructing a
+ClusterTemplate object
+
SettingsUtilsUnitTests
----------------------
diff --git a/snaps/config/cluster_template.py b/snaps/config/cluster_template.py
new file mode 100644
index 0000000..a20225a
--- /dev/null
+++ b/snaps/config/cluster_template.py
@@ -0,0 +1,306 @@
+# Copyright (c) 2016 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 enum
+from neutronclient.common.utils import str2bool
+
+
+class ServerType(enum.Enum):
+ """
+ The cluter server types supported
+ """
+ vm = 'vm'
+ baremetal = 'baremetal'
+
+
+class ContainerOrchestrationEngine(enum.Enum):
+ """
+ The types of supported COEs
+ """
+ kubernetes = 'kubernetes'
+ swarm = 'swarm'
+ mesos = 'mesos'
+
+
+class DockerStorageDriver(enum.Enum):
+ """
+ Drivers for managing storage for the images in the container's writable
+ layer
+ """
+ devicemapper = 'devicemapper'
+ overlay = 'overlay'
+
+
+class ClusterTemplateConfig(object):
+ """
+ Configuration settings for OpenStack cluster template creation
+ """
+
+ def __init__(self, **kwargs):
+ """
+ Constructor
+ :param name: the cluster type'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
+ driver (required)
+ :param keypair: name or ID of the keypair to gain cluster machine
+ access (required)
+ :param network_driver: The name of a network driver for providing the
+ networks for the containers. Note that this is
+ different and separate from the Neutron network
+ for the bay/cluster. The operation and
+ networking model are specific to the particular
+ driver (optional)
+ :param external_net: name or IDof the external Neutron network to
+ provide connectivity to the cluster (required)
+ :param floating_ip_enabled: Whether enable or not using the floating IP
+ of cloud provider. Some cloud providers
+ used floating IP, some used public IP,
+ thus Magnum provide this option for
+ specifying the choice of using floating IP
+ (default - True)
+ :param docker_volume_size: The size in GB for the local storage on each
+ server for the Docker daemon to cache the
+ images and host the containers. Cinder
+ volumes provide the storage. The default is
+ 25 GB. For the devicemapper storage driver,
+ the minimum value is 3GB. For the overlay
+ storage driver, the minimum value is 1GB.
+ (default - 3)
+ :param server_type: ServerType enumeration (default - vm)
+ :param flavor: name or ID of the nova flavor for booting the node
+ servers (default - m1.small)
+ :param master_flavor: name or ID of the nova flavor of the master node
+ for this cluster (optional)
+ :param coe: ContainerOrchestrationEngine enum instance
+ (default - kubernetes)
+ :param fixed_net: name of a Neutron network to provide connectivity
+ to the internal network for the cluster
+ (optional)
+ :param fixed_subnet: Fixed subnet that are using to allocate network
+ address for nodes in bay/cluster (optional)
+ :param registry_enabled: Docker images by default are pulled from the
+ public Docker registry, but in some cases,
+ users may want to use a private registry.
+ This option provides an alternative registry
+ based on the Registry V2: Magnum will create a
+ local registry in the bay/cluster backed by
+ swift to host the images (default - True)
+ :param insecure_registry: The URL pointing to the user's own private
+ insecure docker registry to deploy and run
+ docker containers (optional)
+ :param docker_storage_driver: DockerStorageDriver enum instance to
+ manage storage for the images and
+ container's writable layer
+ (default - devicemapper)
+ :param dns_nameserver: The DNS nameserver for the servers and
+ containers in the bay/cluster to use.
+ 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
+ (default False)
+ :param tls_disabled: denotes whether or not TLS should be enabled
+ (default False)
+ :param http_proxy: host:port for a proxy to use when direct HTTP
+ access from the servers to sites on the external
+ internet is blocked (optional)
+ :param https_proxy: host:port for a proxy to use when direct HTTPS
+ access from the servers to sites on the external
+ internet is blocked (optional)
+ :param no_proxy: comma separated list of IPs that should not be
+ redirected through the proxy (optional)
+ :param volume_driver: The name of a volume driver for managing the
+ persistent storage for the containers. The
+ functionality supported are specific to the
+ driver (optional)
+ :param master_lb_enabled: Since multiple masters may exist in a
+ bay/cluster, a Neutron load balancer is
+ created to provide the API endpoint for the
+ bay/cluster and to direct requests to the
+ masters. In some cases, such as when the
+ LBaaS service is not available, this option
+ can be set to false to create a bay/cluster
+ without the load balancer. In this case, one
+ of the masters will serve as the API endpoint
+ (default - True)
+ :param labels: Arbitrary labels in the form of a dict. The accepted
+ keys and valid values are defined in the bay/cluster
+ drivers. They are used as a way to pass additional
+ parameters that are specific to a bay/cluster driver.
+ (optional)
+ """
+ self.name = kwargs.get('name')
+ self.image = kwargs.get('image')
+ self.keypair = kwargs.get('keypair')
+ self.network_driver = kwargs.get('network_driver')
+ self.external_net = kwargs.get('external_net')
+ self.floating_ip_enabled = str2bool(
+ str(kwargs.get('floating_ip_enabled', True)))
+ self.docker_volume_size = int(kwargs.get('docker_volume_size', 3))
+ self.server_type = map_server_type(
+ kwargs.get('server_type', ServerType.vm))
+ self.flavor = kwargs.get('flavor')
+ self.master_flavor = kwargs.get('master_flavor')
+ self.coe = map_coe(
+ kwargs.get('coe', ContainerOrchestrationEngine.kubernetes))
+ self.fixed_net = kwargs.get('fixed_net')
+ self.fixed_subnet = kwargs.get('fixed_subnet')
+ self.registry_enabled = str2bool(
+ str(kwargs.get('registry_enabled', True)))
+ self.insecure_registry = kwargs.get('insecure_registry')
+ self.docker_storage_driver = map_docker_storage_driver(
+ kwargs.get('docker_storage_driver',
+ DockerStorageDriver.devicemapper))
+ self.dns_nameserver = kwargs.get('dns_nameserver')
+ self.public = str2bool(str(kwargs.get('public', False)))
+ self.tls_disabled = str2bool(str(kwargs.get('tls_disabled', False)))
+ self.http_proxy = kwargs.get('http_proxy')
+ self.https_proxy = kwargs.get('https_proxy')
+ self.no_proxy = kwargs.get('no_proxy')
+ self.volume_driver = kwargs.get('volume_driver')
+ self.master_lb_enabled = str2bool(
+ str(kwargs.get('master_lb_enabled', True)))
+ self.labels = kwargs.get('labels')
+
+ if (not self.name or not self.image or not self.keypair
+ or not self.external_net):
+ raise ClusterTypeConfigError(
+ 'The attributes name, image, keypair, and '
+ 'external_net are required for ClusterTypeConfig')
+
+ def magnum_dict(self):
+ """
+ Returns a dictionary object representing this object.
+ This is meant to be sent into as kwargs into the Magnum client
+
+ :return: the dictionary object
+ """
+ out = dict()
+
+ if self.name:
+ out['name'] = self.name
+ if self.image:
+ out['image_id'] = self.image
+ if self.keypair:
+ out['keypair_id'] = self.keypair
+ if self.network_driver:
+ out['network_driver'] = self.network_driver
+ if self.external_net:
+ out['external_network_id'] = self.external_net
+ if self.floating_ip_enabled:
+ out['floating_ip_enabled'] = self.floating_ip_enabled
+ if self.docker_volume_size:
+ out['docker_volume_size'] = self.docker_volume_size
+ if self.server_type:
+ out['server_type'] = self.server_type.value
+ if self.flavor:
+ out['flavor_id'] = self.flavor
+ if self.master_flavor:
+ out['master_flavor_id'] = self.master_flavor
+ if self.coe:
+ out['coe'] = self.coe.value
+ if self.fixed_net:
+ out['fixed_network'] = self.fixed_net
+ if self.fixed_subnet:
+ out['fixed_subnet'] = self.fixed_subnet
+ if self.registry_enabled:
+ out['registry_enabled'] = self.registry_enabled
+ if self.insecure_registry:
+ out['insecure_registry'] = self.insecure_registry
+ if self.docker_storage_driver:
+ out['docker_storage_driver'] = self.docker_storage_driver.value
+ if self.dns_nameserver:
+ out['dns_nameserver'] = self.dns_nameserver
+ if self.public:
+ out['public'] = self.public
+ if self.tls_disabled:
+ out['tls_disabled'] = self.tls_disabled
+ if self.http_proxy:
+ out['http_proxy'] = self.http_proxy
+ if self.https_proxy:
+ out['https_proxy'] = self.https_proxy
+ if self.no_proxy:
+ out['no_proxy'] = self.no_proxy
+ if self.volume_driver:
+ out['volume_driver'] = self.volume_driver
+ if self.master_lb_enabled:
+ out['master_lb_enabled'] = self.master_lb_enabled
+ if self.labels:
+ out['labels'] = self.labels
+ return out
+
+
+class ClusterTypeConfigError(Exception):
+ """
+ Exception to be thrown when a cluster type configuration is incorrect
+ """
+
+
+def map_server_type(server_type):
+ """
+ Takes a the server_type value maps it to the ServerType enum. When None
+ return None
+ :param server_type: the server_type value to map
+ :return: the ServerType enum object
+ :raise: ClusterTypeConfigError if value is invalid
+ """
+ if not server_type:
+ return None
+ if isinstance(server_type, ServerType):
+ return server_type
+ elif isinstance(server_type, str):
+ for this_type in ServerType:
+ if this_type.value == server_type:
+ return this_type
+ raise ClusterTypeConfigError('Invalid server type - ' + server_type)
+
+
+def map_coe(coe):
+ """
+ Takes a the coe value maps it to the ContainerOrchestrationEngine enum.
+ When None return None
+ :param coe: the COE value to map
+ :return: the ContainerOrchestrationEngine enum object
+ :raise: ClusterTypeConfigError if value is invalid
+ """
+ if not coe:
+ return None
+ if isinstance(coe, ContainerOrchestrationEngine):
+ return coe
+ elif isinstance(coe, str):
+ for this_type in ContainerOrchestrationEngine:
+ if this_type.value == coe:
+ return this_type
+ raise ClusterTypeConfigError('Invalid COE - ' + coe)
+
+
+def map_docker_storage_driver(driver):
+ """
+ Takes a the coe value maps it to the ContainerOrchestrationEngine enum.
+ When None return None
+ :param driver: the docker storage driver value to map
+ :return: the DockerStorageDriver enum object
+ :raise: ClusterTypeConfigError if value is invalid
+ """
+ if not driver:
+ return None
+ if isinstance(driver, DockerStorageDriver):
+ return driver
+ elif isinstance(driver, str):
+ for this_type in DockerStorageDriver:
+ if this_type.value == driver:
+ return this_type
+ raise ClusterTypeConfigError('Invalid DockerStorageDriver - ' + driver)
diff --git a/snaps/config/network.py b/snaps/config/network.py
index bc6ae1b..f48cd27 100644
--- a/snaps/config/network.py
+++ b/snaps/config/network.py
@@ -13,6 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import enum
+from neutronclient.common.utils import str2bool
from snaps.openstack.utils import keystone_utils, neutron_utils
@@ -52,19 +53,19 @@ class NetworkConfig(object):
self.name = kwargs.get('name')
if kwargs.get('admin_state_up') is not None:
- self.admin_state_up = bool(kwargs['admin_state_up'])
+ self.admin_state_up = str2bool(str(kwargs['admin_state_up']))
else:
self.admin_state_up = True
if kwargs.get('shared') is not None:
- self.shared = bool(kwargs['shared'])
+ self.shared = str2bool(str(kwargs['shared']))
else:
self.shared = None
self.project_name = kwargs.get('project_name')
if kwargs.get('external') is not None:
- self.external = bool(kwargs.get('external'))
+ self.external = str2bool(str(kwargs.get('external')))
else:
self.external = False
@@ -370,7 +371,7 @@ class PortConfig(object):
self.network_name = kwargs.get('network_name')
if kwargs.get('admin_state_up') is not None:
- self.admin_state_up = bool(kwargs['admin_state_up'])
+ self.admin_state_up = str2bool(str(kwargs['admin_state_up']))
else:
self.admin_state_up = True
diff --git a/snaps/config/tests/cluster_template_tests.py b/snaps/config/tests/cluster_template_tests.py
new file mode 100644
index 0000000..5c695b9
--- /dev/null
+++ b/snaps/config/tests/cluster_template_tests.py
@@ -0,0 +1,180 @@
+# 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 unittest
+
+from snaps.config.cluster_template import ClusterTemplateConfig, \
+ ClusterTypeConfigError, ServerType, DockerStorageDriver, \
+ ContainerOrchestrationEngine
+
+
+class ClusterTemplateConfigUnitTests(unittest.TestCase):
+ """
+ Tests the construction of the ClusterTemplateConfig class
+ """
+
+ def test_no_params(self):
+ with self.assertRaises(ClusterTypeConfigError):
+ ClusterTemplateConfig()
+
+ def test_empty_config(self):
+ with self.assertRaises(ClusterTypeConfigError):
+ ClusterTemplateConfig(config=dict())
+
+ def test_name_only(self):
+ with self.assertRaises(ClusterTypeConfigError):
+ ClusterTemplateConfig(name='foo')
+
+ def test_minimal_named(self):
+ config = ClusterTemplateConfig(
+ name='foo', image='bar', keypair='keys', external_net='external')
+ self.assertIsNotNone(config)
+ self.assertEqual('foo', config.name)
+ self.assertEqual('bar', config.image)
+ self.assertEqual('keys', config.keypair)
+ self.assertIsNone(config.network_driver)
+ self.assertEqual('external', config.external_net)
+ self.assertTrue(config.floating_ip_enabled)
+ self.assertEqual(3, config.docker_volume_size)
+ self.assertEqual(ServerType.vm, config.server_type)
+ self.assertIsNone(config.flavor)
+ self.assertIsNone(config.master_flavor)
+ self.assertEqual(ContainerOrchestrationEngine.kubernetes, config.coe)
+ self.assertIsNone(config.fixed_net)
+ self.assertIsNone(config.fixed_subnet)
+ self.assertTrue(config.registry_enabled)
+ self.assertIsNone(config.insecure_registry)
+ self.assertEqual(DockerStorageDriver.devicemapper,
+ config.docker_storage_driver)
+ self.assertIsNone(config.dns_nameserver)
+ self.assertFalse(config.public)
+ self.assertFalse(config.tls_disabled)
+ self.assertIsNone(config.http_proxy)
+ self.assertIsNone(config.https_proxy)
+ self.assertIsNone(config.no_proxy)
+ self.assertIsNone(config.volume_driver)
+ self.assertTrue(config.master_lb_enabled)
+ self.assertIsNone(config.labels)
+
+ def test_minimal_config(self):
+ config = ClusterTemplateConfig(
+ **{'name': 'foo', 'image': 'bar', 'keypair': 'keys',
+ 'external_net': 'external'})
+ self.assertIsNotNone(config)
+ self.assertEqual('foo', config.name)
+ self.assertEqual('bar', config.image)
+ self.assertEqual('keys', config.keypair)
+ self.assertIsNone(config.network_driver)
+ self.assertEqual('external', config.external_net)
+ self.assertTrue(config.floating_ip_enabled)
+ self.assertEqual(3, config.docker_volume_size)
+ self.assertEqual(ServerType.vm, config.server_type)
+ self.assertIsNone(config.flavor)
+ self.assertIsNone(config.master_flavor)
+ self.assertEqual(ContainerOrchestrationEngine.kubernetes, config.coe)
+ self.assertIsNone(config.fixed_net)
+ self.assertIsNone(config.fixed_subnet)
+ self.assertTrue(config.registry_enabled)
+ self.assertIsNone(config.insecure_registry)
+ self.assertEqual(DockerStorageDriver.devicemapper,
+ config.docker_storage_driver)
+ self.assertIsNone(config.dns_nameserver)
+ self.assertFalse(config.public)
+ self.assertFalse(config.tls_disabled)
+ self.assertIsNone(config.http_proxy)
+ self.assertIsNone(config.https_proxy)
+ self.assertIsNone(config.no_proxy)
+ self.assertIsNone(config.volume_driver)
+ self.assertTrue(config.master_lb_enabled)
+ self.assertIsNone(config.labels)
+
+ def test_all_named(self):
+ labels = {'foo': 'bar'}
+ config = ClusterTemplateConfig(
+ name='foo', image='bar', keypair='keys', network_driver='driver',
+ external_net='external', docker_volume_size=99,
+ server_type=ServerType.baremetal, flavor='testFlavor',
+ master_flavor='masterFlavor',
+ coe=ContainerOrchestrationEngine.kubernetes, fixed_net='fixedNet',
+ fixed_subnet='fixedSubnet', registry_enabled=False,
+ docker_storage_driver=DockerStorageDriver.overlay,
+ dns_nameserver='8.8.4.4', public=True, tls=False,
+ http_proxy='http://foo:8080', https_proxy='https://foo:443',
+ no_proxy='foo,bar', volume_driver='volDriver',
+ master_lb_enabled=False, labels=labels)
+ self.assertIsNotNone(config)
+ self.assertEqual('foo', config.name)
+ self.assertEqual('bar', config.image)
+ self.assertEqual('keys', config.keypair)
+ self.assertEqual('driver', config.network_driver)
+ self.assertEqual('external', config.external_net)
+ self.assertEqual(99, config.docker_volume_size)
+ self.assertEqual(ServerType.baremetal, config.server_type)
+ self.assertEqual('testFlavor', config.flavor)
+ self.assertEqual('masterFlavor', config.master_flavor)
+ self.assertEqual(ContainerOrchestrationEngine.kubernetes, config.coe)
+ self.assertEqual('fixedNet', config.fixed_net)
+ self.assertEqual('fixedSubnet', config.fixed_subnet)
+ self.assertFalse(config.registry_enabled)
+ self.assertEqual(DockerStorageDriver.overlay,
+ config.docker_storage_driver)
+ self.assertEqual('8.8.4.4', config.dns_nameserver)
+ self.assertTrue(config.public)
+ self.assertFalse(config.tls_disabled)
+ self.assertEqual('http://foo:8080', config.http_proxy)
+ self.assertEqual('https://foo:443', config.https_proxy)
+ self.assertEqual('foo,bar', config.no_proxy)
+ self.assertEqual('volDriver', config.volume_driver)
+ self.assertFalse(config.master_lb_enabled)
+ self.assertEqual(labels, config.labels)
+
+ def test_all_config(self):
+ labels = {'foo': 'bar'}
+ config = ClusterTemplateConfig(**{
+ 'name': 'foo', 'image': 'bar', 'keypair': 'keys',
+ 'network_driver': 'driver', 'external_net': 'external',
+ 'docker_volume_size': '99', 'server_type': 'baremetal',
+ 'flavor': 'testFlavor', 'master_flavor': 'masterFlavor',
+ 'coe': 'kubernetes', 'fixed_net': 'fixedNet',
+ 'fixed_subnet': 'fixedSubnet', 'registry_enabled': 'false',
+ 'docker_storage_driver': 'overlay', 'dns_nameserver': '8.8.4.4',
+ 'public': 'true', 'tls': 'false', 'http_proxy': 'http://foo:8080',
+ 'https_proxy': 'https://foo:443', 'no_proxy': 'foo,bar',
+ 'volume_driver': 'volDriver', 'master_lb_enabled': 'false',
+ 'labels': labels})
+ self.assertIsNotNone(config)
+ self.assertEqual('foo', config.name)
+ self.assertEqual('bar', config.image)
+ self.assertEqual('keys', config.keypair)
+ self.assertEqual('driver', config.network_driver)
+ self.assertEqual('external', config.external_net)
+ self.assertEqual(99, config.docker_volume_size)
+ self.assertEqual(ServerType.baremetal, config.server_type)
+ self.assertEqual('testFlavor', config.flavor)
+ self.assertEqual('masterFlavor', config.master_flavor)
+ self.assertEqual(ContainerOrchestrationEngine.kubernetes, config.coe)
+ self.assertEqual('fixedNet', config.fixed_net)
+ self.assertEqual('fixedSubnet', config.fixed_subnet)
+ self.assertFalse(config.registry_enabled)
+ self.assertEqual(DockerStorageDriver.overlay,
+ config.docker_storage_driver)
+ self.assertEqual('8.8.4.4', config.dns_nameserver)
+ self.assertTrue(config.public)
+ self.assertFalse(config.tls_disabled)
+ self.assertEqual('http://foo:8080', config.http_proxy)
+ self.assertEqual('https://foo:443', config.https_proxy)
+ self.assertEqual('foo,bar', config.no_proxy)
+ self.assertEqual('volDriver', config.volume_driver)
+ self.assertFalse(config.master_lb_enabled)
+ self.assertEqual(labels, config.labels)
diff --git a/snaps/config/volume.py b/snaps/config/volume.py
index 20ca985..a31e8f5 100644
--- a/snaps/config/volume.py
+++ b/snaps/config/volume.py
@@ -12,6 +12,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
+from neutronclient.common.utils import str2bool
class VolumeConfig(object):
@@ -37,8 +38,8 @@ class VolumeConfig(object):
self.type_name = kwargs.get('type_name')
self.availability_zone = kwargs.get('availability_zone')
- if kwargs.get('availability_zone'):
- self.multi_attach = bool(kwargs.get('availability_zone'))
+ if kwargs.get('multi_attach'):
+ self.multi_attach = str2bool(str(kwargs.get('multi_attach')))
else:
self.multi_attach = False
diff --git a/snaps/domain/cluster_template.py b/snaps/domain/cluster_template.py
new file mode 100644
index 0000000..01af88a
--- /dev/null
+++ b/snaps/domain/cluster_template.py
@@ -0,0 +1,133 @@
+# Copyright (c) 2016 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.
+
+
+class ClusterTemplate(object):
+ """
+ Class for OpenStack cluster template domain object
+ """
+
+ def __init__(self, **kwargs):
+ """
+ Constructor
+ :param id: the cluster template's UUID
+ :param name: the cluster template's name
+ :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
+ driver
+ :param keypair: name or ID of the keypair to gain cluster machine
+ access
+ :param network_driver: The name of a network driver for providing the
+ networks for the containers. Note that this is
+ different and separate from the Neutron network
+ for the bay/cluster. The operation and
+ networking model are specific to the particular
+ driver
+ :param external_net: name or IDof the external Neutron network to
+ provide connectivity to the cluster
+ :param floating_ip_enabled: Whether enable or not using the floating IP
+ of cloud provider. Some cloud providers
+ used floating IP, some used public IP,
+ thus Magnum provide this option for
+ specifying the choice of using floating IP
+ :param docker_volume_size: The size in GB for the local storage on each
+ server for the Docker daemon to cache the
+ images and host the containers. Cinder
+ volumes provide the storage. The default is
+ 25 GB. For the devicemapper storage driver,
+ the minimum value is 3GB. For the overlay
+ storage driver, the minimum value is 1GB.
+ :param server_type: server type string
+ :param flavor: name or ID of the nova flavor for booting the node
+ servers
+ :param master_flavor: name or ID of the nova flavor of the master node
+ for this cluster
+ :param coe: ContainerOrchestrationEngine enum instance
+ :param fixed_net: name of a Neutron network to provide connectivity
+ to the internal network for the cluster
+ :param fixed_subnet: Fixed subnet that are using to allocate network
+ address for nodes in bay/cluster
+ :param registry_enabled: Docker images by default are pulled from the
+ public Docker registry, but in some cases,
+ users may want to use a private registry.
+ This option provides an alternative registry
+ based on the Registry V2: Magnum will create a
+ local registry in the bay/cluster backed by
+ swift to host the images
+ :param insecure_registry: The URL pointing to the user's own private
+ insecure docker registry to deploy and run
+ docker containers
+ :param docker_storage_driver: DockerStorageDriver enum instance to
+ manage storage for the images and
+ container's writable layer
+ :param dns_nameserver: The DNS nameserver for the servers and
+ containers in the bay/cluster to use.
+ This is configured in the private Neutron
+ network for the bay/cluster.
+ :param public: denotes whether or not the cluster type is public
+ :param tls_disabled: denotes whether or not TLS should be enabled
+ :param http_proxy: host:port for a proxy to use when direct HTTP
+ access from the servers to sites on the external
+ internet is blocked
+ :param https_proxy: host:port for a proxy to use when direct HTTPS
+ access from the servers to sites on the external
+ internet is blocked
+ :param no_proxy: comma separated list of IPs that should not be
+ redirected through the proxy
+ :param volume_driver: The name of a volume driver for managing the
+ persistent storage for the containers. The
+ functionality supported are specific to the
+ driver
+ :param master_lb_enabled: Since multiple masters may exist in a
+ bay/cluster, a Neutron load balancer is
+ created to provide the API endpoint for the
+ bay/cluster and to direct requests to the
+ masters. In some cases, such as when the
+ LBaaS service is not available, this option
+ can be set to false to create a bay/cluster
+ without the load balancer. In this case, one
+ of the masters will serve as the API endpoint
+ :param labels: Arbitrary labels in the form of a dict. The accepted
+ keys and valid values are defined in the bay/cluster
+ drivers. They are used as a way to pass additional
+ parameters that are specific to a bay/cluster driver.
+ """
+ self.id = kwargs.get('id')
+ self.name = kwargs.get('name')
+ self.image = kwargs.get('image')
+ self.keypair = kwargs.get('keypair')
+ self.network_driver = kwargs.get('network_driver')
+ self.external_net = kwargs.get('external_net')
+ self.floating_ip_enabled = kwargs.get('floating_ip_enabled')
+ self.docker_volume_size = int(kwargs.get('docker_volume_size', 3))
+ self.server_type = kwargs.get('server_type')
+ self.flavor = kwargs.get('flavor')
+ self.master_flavor = kwargs.get('master_flavor')
+ self.coe = kwargs.get('coe')
+ self.fixed_net = kwargs.get('fixed_net')
+ self.fixed_subnet = kwargs.get('fixed_subnet')
+ self.registry_enabled = kwargs.get('registry_enabled')
+ self.insecure_registry = kwargs.get('insecure_registry')
+ self.docker_storage_driver = kwargs.get('docker_storage_driver')
+ self.dns_nameserver = kwargs.get('dns_nameserver')
+ self.public = kwargs.get('public', False)
+ self.tls_disabled = kwargs.get('tls_disabled')
+ self.http_proxy = kwargs.get('http_proxy')
+ self.https_proxy = kwargs.get('https_proxy')
+ self.no_proxy = kwargs.get('no_proxy')
+ self.volume_driver = kwargs.get('volume_driver')
+ self.master_lb_enabled = kwargs.get('master_lb_enabled', True)
+ self.labels = kwargs.get('labels')
diff --git a/snaps/domain/test/cluster_template_tests.py b/snaps/domain/test/cluster_template_tests.py
new file mode 100644
index 0000000..76e5663
--- /dev/null
+++ b/snaps/domain/test/cluster_template_tests.py
@@ -0,0 +1,109 @@
+# 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 unittest
+
+from snaps.config.cluster_template import (
+ ContainerOrchestrationEngine, ServerType, DockerStorageDriver)
+from snaps.domain.cluster_template import ClusterTemplate
+
+
+class ClusterTemplateUnitTests(unittest.TestCase):
+ """
+ Tests the construction of the ClusterTypeConfig class
+ """
+ def test_all_named(self):
+ labels = {'foo': 'bar'}
+ config = ClusterTemplate(
+ id='tmplt-id', name='foo', image='bar', keypair='keys',
+ network_driver='driver', external_net='external',
+ docker_volume_size=99, server_type=ServerType.baremetal.value,
+ flavor='testFlavor', master_flavor='masterFlavor',
+ coe=ContainerOrchestrationEngine.kubernetes.value,
+ fixed_net='fixedNet', fixed_subnet='fixedSubnet',
+ registry_enabled=False,
+ docker_storage_driver=DockerStorageDriver.overlay.value,
+ dns_nameserver='8.8.4.4', public=True, tls=False,
+ http_proxy='http://foo:8080', https_proxy='https://foo:443',
+ no_proxy='foo,bar', volume_driver='volDriver',
+ master_lb_enabled=False, labels=labels)
+ self.assertIsNotNone(config)
+ self.assertEqual('tmplt-id', config.id)
+ self.assertEqual('foo', config.name)
+ self.assertEqual('bar', config.image)
+ self.assertEqual('keys', config.keypair)
+ self.assertEqual('driver', config.network_driver)
+ self.assertEqual('external', config.external_net)
+ self.assertEqual(99, config.docker_volume_size)
+ self.assertEqual(ServerType.baremetal.value, config.server_type)
+ self.assertEqual('testFlavor', config.flavor)
+ self.assertEqual('masterFlavor', config.master_flavor)
+ self.assertEqual(ContainerOrchestrationEngine.kubernetes.value,
+ config.coe)
+ self.assertEqual('fixedNet', config.fixed_net)
+ self.assertEqual('fixedSubnet', config.fixed_subnet)
+ self.assertFalse(config.registry_enabled)
+ self.assertEqual(DockerStorageDriver.overlay.value,
+ config.docker_storage_driver)
+ self.assertEqual('8.8.4.4', config.dns_nameserver)
+ self.assertTrue(config.public)
+ self.assertFalse(config.tls_disabled)
+ self.assertEqual('http://foo:8080', config.http_proxy)
+ self.assertEqual('https://foo:443', config.https_proxy)
+ self.assertEqual('foo,bar', config.no_proxy)
+ self.assertEqual('volDriver', config.volume_driver)
+ self.assertFalse(config.master_lb_enabled)
+ self.assertEqual(labels, config.labels)
+
+ def test_all_config(self):
+ labels = {'foo': 'bar'}
+ config = ClusterTemplate(**{
+ 'id': 'tmplt-id', 'name': 'foo', 'image': 'bar', 'keypair': 'keys',
+ 'network_driver': 'driver', 'external_net': 'external',
+ 'docker_volume_size': '99', 'server_type': 'baremetal',
+ 'flavor': 'testFlavor', 'master_flavor': 'masterFlavor',
+ 'coe': 'kubernetes', 'fixed_net': 'fixedNet',
+ 'fixed_subnet': 'fixedSubnet', 'registry_enabled': False,
+ 'docker_storage_driver': 'overlay', 'dns_nameserver': '8.8.4.4',
+ 'public': 'true', 'tls': 'false', 'http_proxy': 'http://foo:8080',
+ 'https_proxy': 'https://foo:443', 'no_proxy': 'foo,bar',
+ 'volume_driver': 'volDriver', 'master_lb_enabled': False,
+ 'labels': labels})
+ self.assertIsNotNone(config)
+ self.assertEqual('tmplt-id', config.id)
+ self.assertEqual('foo', config.name)
+ self.assertEqual('bar', config.image)
+ self.assertEqual('keys', config.keypair)
+ self.assertEqual('driver', config.network_driver)
+ self.assertEqual('external', config.external_net)
+ self.assertEqual(99, config.docker_volume_size)
+ self.assertEqual(ServerType.baremetal.value, config.server_type)
+ self.assertEqual('testFlavor', config.flavor)
+ self.assertEqual('masterFlavor', config.master_flavor)
+ self.assertEqual(ContainerOrchestrationEngine.kubernetes.value,
+ config.coe)
+ self.assertEqual('fixedNet', config.fixed_net)
+ self.assertEqual('fixedSubnet', config.fixed_subnet)
+ self.assertFalse(config.registry_enabled)
+ self.assertEqual(DockerStorageDriver.overlay.value,
+ config.docker_storage_driver)
+ self.assertEqual('8.8.4.4', config.dns_nameserver)
+ self.assertTrue(config.public)
+ self.assertFalse(config.tls_disabled)
+ self.assertEqual('http://foo:8080', config.http_proxy)
+ self.assertEqual('https://foo:443', config.https_proxy)
+ self.assertEqual('foo,bar', config.no_proxy)
+ self.assertEqual('volDriver', config.volume_driver)
+ self.assertFalse(config.master_lb_enabled)
+ self.assertEqual(labels, config.labels)
diff --git a/snaps/openstack/tests/openstack_tests.py b/snaps/openstack/tests/openstack_tests.py
index 78e8601..4b00922 100644
--- a/snaps/openstack/tests/openstack_tests.py
+++ b/snaps/openstack/tests/openstack_tests.py
@@ -174,17 +174,15 @@ def create_image_settings(image_name, image_user, image_format, metadata,
return ImageConfig(**metadata['config'])
disk_file = None
- if metadata:
+ if metadata and ('disk_url' in metadata or 'disk_file' in metadata):
disk_url = metadata.get('disk_url')
disk_file = metadata.get('disk_file')
elif not disk_url:
disk_url = default_url
- else:
- disk_url = disk_url
- if metadata and \
- ('kernel_file' in metadata or 'kernel_url' in metadata) and \
- kernel_settings is None:
+ if (metadata
+ and ('kernel_file' in metadata or 'kernel_url' in metadata)
+ and kernel_settings is None):
kernel_image_settings = ImageConfig(
name=image_name + '-kernel', image_user=image_user,
img_format=image_format, image_file=metadata.get('kernel_file'),
@@ -192,9 +190,9 @@ def create_image_settings(image_name, image_user, image_format, metadata,
else:
kernel_image_settings = kernel_settings
- if metadata and \
- ('ramdisk_file' in metadata or 'ramdisk_url' in metadata) and \
- ramdisk_settings is None:
+ if (metadata
+ and ('ramdisk_file' in metadata or 'ramdisk_url' in metadata)
+ and ramdisk_settings is None):
ramdisk_image_settings = ImageConfig(
name=image_name + '-ramdisk', image_user=image_user,
img_format=image_format,
diff --git a/snaps/openstack/utils/magnum_utils.py b/snaps/openstack/utils/magnum_utils.py
index abc771a..c744666 100644
--- a/snaps/openstack/utils/magnum_utils.py
+++ b/snaps/openstack/utils/magnum_utils.py
@@ -16,18 +16,81 @@ import logging
from magnumclient.client import Client
+from snaps.domain.cluster_template import ClusterTemplate
from snaps.openstack.utils import keystone_utils
__author__ = 'spisarski'
-logger = logging.getLogger('heat_utils')
+logger = logging.getLogger('magnum_utils')
def magnum_client(os_creds):
"""
- Retrieves the Heat client
- :param os_creds: the OpenStack credentials
+ Retrieves the Magnum client
+ :param os_creds: the OpenStack credentialsf
:return: the client
"""
- logger.debug('Retrieving Nova Client')
- return Client(session=keystone_utils.keystone_session(os_creds))
+ logger.debug('Retrieving Magnum Client')
+ return Client(str(os_creds.magnum_api_version),
+ session=keystone_utils.keystone_session(os_creds))
+
+
+def create_cluster_template(magnum, cluster_template_config):
+ """
+ Creates a Magnum Cluster Template object in OpenStack
+ :param magnum: the Magnum client
+ :param cluster_template_config: a ClusterTemplateConfig object
+ :return: a SNAPS ClusterTemplate domain object
+ """
+ config_dict = cluster_template_config.magnum_dict()
+ os_cluster_template = magnum.cluster_templates.create(**config_dict)
+ logger.info('Creating cluster template named [%s]',
+ cluster_template_config.name)
+ return __map_os_cluster_template(os_cluster_template)
+
+
+def delete_cluster_template(magnum, tmplt_id):
+ """
+ Deletes a Cluster Template from OpenStack
+ :param magnum: the Magnum client
+ :param tmplt_id: the cluster template ID to delete
+ """
+ logger.info('Deleting cluster template with ID [%s]', tmplt_id)
+ magnum.cluster_templates.delete(tmplt_id)
+
+
+def __map_os_cluster_template(os_tmplt):
+ """
+ Returns a SNAPS ClusterTemplate object from an OpenStack ClusterTemplate
+ object
+ :param os_tmplt: the OpenStack ClusterTemplate object
+ :return: SNAPS ClusterTemplate object
+ """
+ return ClusterTemplate(
+ id=os_tmplt.uuid,
+ name=os_tmplt.name,
+ image=os_tmplt.image_id,
+ keypair=os_tmplt.keypair_id,
+ network_driver=os_tmplt.network_driver,
+ external_net=os_tmplt.external_network_id,
+ floating_ip_enabled=os_tmplt.floating_ip_enabled,
+ docker_volume_size=os_tmplt.docker_volume_size,
+ server_type=os_tmplt.server_type,
+ flavor=os_tmplt.flavor_id,
+ master_flavor=os_tmplt.master_flavor_id,
+ coe=os_tmplt.coe,
+ fixed_net=os_tmplt.fixed_network,
+ fixed_subnet=os_tmplt.fixed_subnet,
+ registry_enabled=os_tmplt.registry_enabled,
+ insecure_registry=os_tmplt.insecure_registry,
+ docker_storage_driver=os_tmplt.docker_storage_driver,
+ dns_nameserver=os_tmplt.dns_nameserver,
+ public=os_tmplt.public,
+ tls_disabled=os_tmplt.tls_disabled,
+ http_proxy=os_tmplt.http_proxy,
+ https_proxy=os_tmplt.https_proxy,
+ no_proxy=os_tmplt.no_proxy,
+ volume_driver=os_tmplt.volume_driver,
+ master_lb_enabled=os_tmplt.master_lb_enabled,
+ labels=os_tmplt.labels
+ )
diff --git a/snaps/openstack/utils/tests/magnum_utils_tests.py b/snaps/openstack/utils/tests/magnum_utils_tests.py
index 48ead80..9e47900 100644
--- a/snaps/openstack/utils/tests/magnum_utils_tests.py
+++ b/snaps/openstack/utils/tests/magnum_utils_tests.py
@@ -13,8 +13,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import logging
+import uuid
+from snaps.config.cluster_template import ClusterTemplateConfig
+from snaps.config.keypair import KeypairConfig
+from snaps.openstack.create_image import OpenStackImage
+from snaps.openstack.create_keypairs import OpenStackKeypair
from snaps.openstack.os_credentials import OSCreds
+from snaps.openstack.tests import openstack_tests
from snaps.openstack.tests.os_source_file_test import OSComponentTestCase
from snaps.openstack.utils import magnum_utils
@@ -35,7 +41,7 @@ class MagnumSmokeTests(OSComponentTestCase):
magnum = magnum_utils.magnum_client(self.os_creds)
# This should not throw an exception
- magnum.clusters.list()
+ self.assertIsNotNone(magnum.clusters.list())
def test_nova_connect_fail(self):
"""
@@ -48,3 +54,121 @@ class MagnumSmokeTests(OSComponentTestCase):
auth_url=self.os_creds.auth_url,
project_name=self.os_creds.project_name,
proxy_settings=self.os_creds.proxy_settings))
+
+
+class MagnumUtilsTests(OSComponentTestCase):
+ """
+ Tests individual functions within magnum_utils.py
+ """
+
+ def setUp(self):
+ 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)
+
+ 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 = None
+
+ try:
+ self.image_creator.create()
+ self.keypair_creator.create()
+ except:
+ self.tearDown()
+ raise
+
+ def tearDown(self):
+ if self.cluster_template:
+ try:
+ magnum_utils.delete_cluster_template(
+ self.magnum, self.cluster_template.id)
+ except:
+ pass
+ if self.keypair_creator:
+ try:
+ self.keypair_creator.clean()
+ except:
+ pass
+ if self.image_creator:
+ try:
+ self.image_creator.clean()
+ except:
+ pass
+
+ def test_create_cluster_template_simple(self):
+ 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)
+
+ self.cluster_template = magnum_utils.create_cluster_template(
+ self.magnum, config)
+ self.assertIsNotNone(self.cluster_template)
+ self.assertTrue(
+ validate_cluster_template(config, self.cluster_template))
+
+
+def validate_cluster_template(tmplt_config, tmplt_obj):
+ """
+ Returns true if the configuration matches the ClusterTemplate object
+ :param tmplt_config: the ClusterTemplateConfig object
+ :param tmplt_obj: the ClusterTemplate domain object
+ :return: T/F
+ """
+ if not tmplt_config.network_driver:
+ network_driver = 'flannel'
+ else:
+ network_driver = tmplt_config.network_driver
+
+ return (
+ tmplt_config.coe.value == tmplt_obj.coe and
+ tmplt_config.dns_nameserver == tmplt_obj.dns_nameserver and
+ tmplt_config.docker_storage_driver.value
+ == tmplt_obj.docker_storage_driver and
+ tmplt_config.docker_volume_size == tmplt_obj.docker_volume_size and
+ tmplt_config.external_net == tmplt_obj.external_net and
+ tmplt_config.fixed_net == tmplt_obj.fixed_net and
+ tmplt_config.fixed_subnet == tmplt_obj.fixed_subnet and
+ tmplt_config.flavor == tmplt_obj.flavor and
+ tmplt_config.floating_ip_enabled == tmplt_obj.floating_ip_enabled and
+ tmplt_config.http_proxy == tmplt_obj.http_proxy and
+ tmplt_config.https_proxy == tmplt_obj.https_proxy and
+ tmplt_config.no_proxy == tmplt_obj.no_proxy and
+ tmplt_config.image == tmplt_obj.image and
+ tmplt_config.insecure_registry == tmplt_obj.insecure_registry and
+ tmplt_config.keypair == tmplt_obj.keypair and
+ tmplt_config.labels == tmplt_obj.labels and
+ tmplt_config.master_flavor == tmplt_obj.master_flavor and
+ tmplt_config.master_lb_enabled == tmplt_obj.master_lb_enabled and
+ tmplt_config.name == tmplt_obj.name and
+ network_driver == tmplt_obj.network_driver and
+ tmplt_config.no_proxy == tmplt_obj.no_proxy and
+ tmplt_config.public == tmplt_obj.public and
+ tmplt_config.registry_enabled == tmplt_obj.registry_enabled and
+ tmplt_config.server_type.value == tmplt_obj.server_type and
+ tmplt_config.tls_disabled == tmplt_obj.tls_disabled and
+ tmplt_config.volume_driver == tmplt_obj.volume_driver
+ )
+ # def test_create_cluster_simple(self):
+ # cluster = magnum_utils.create_cluster(self.magnum, 'foo')
+ # self.assertIsNotNone(cluster)
diff --git a/snaps/test_suite_builder.py b/snaps/test_suite_builder.py
index dba60f7..496caf7 100644
--- a/snaps/test_suite_builder.py
+++ b/snaps/test_suite_builder.py
@@ -16,6 +16,8 @@
import logging
import unittest
+from snaps.config.tests.cluster_template_tests import (
+ ClusterTemplateConfigUnitTests)
from snaps.config.tests.network_tests import (
NetworkConfigUnitTests, SubnetConfigUnitTests, PortConfigUnitTests)
from snaps.config.tests.security_group_tests import (
@@ -33,6 +35,7 @@ from snaps.config.tests.keypair_tests import KeypairConfigUnitTests
from snaps.config.tests.flavor_tests import FlavorConfigUnitTests
import snaps.config.tests.image_tests as image_tests
import snaps.openstack.tests.create_image_tests as creator_tests
+from snaps.domain.test.cluster_template_tests import ClusterTemplateUnitTests
from snaps.domain.test.flavor_tests import FlavorDomainObjectTests
from snaps.domain.test.image_tests import ImageDomainObjectTests
from snaps.domain.test.keypair_tests import KeypairDomainObjectTests
@@ -121,7 +124,7 @@ from snaps.openstack.utils.tests.nova_utils_tests import (
from snaps.openstack.utils.tests.settings_utils_tests import (
SettingsUtilsUnitTests)
from snaps.openstack.utils.tests.magnum_utils_tests import (
- MagnumSmokeTests)
+ MagnumSmokeTests, MagnumUtilsTests)
from snaps.provisioning.tests.ansible_utils_tests import (
AnsibleProvisioningTests)
from snaps.tests.file_utils_tests import FileUtilsTests
@@ -257,6 +260,10 @@ def add_unit_tests(suite):
suite.addTest(unittest.TestLoader().loadTestsFromTestCase(
VolumeSettingsUnitTests))
suite.addTest(unittest.TestLoader().loadTestsFromTestCase(
+ ClusterTemplateConfigUnitTests))
+ suite.addTest(unittest.TestLoader().loadTestsFromTestCase(
+ ClusterTemplateUnitTests))
+ suite.addTest(unittest.TestLoader().loadTestsFromTestCase(
SettingsUtilsUnitTests))
@@ -719,3 +726,6 @@ def add_openstack_staging_tests(suite, os_creds, ext_net_name,
suite.addTest(OSComponentTestCase.parameterize(
MagnumSmokeTests, os_creds=os_creds,
ext_net_name=ext_net_name, log_level=log_level))
+ suite.addTest(OSComponentTestCase.parameterize(
+ MagnumUtilsTests, os_creds=os_creds,
+ ext_net_name=ext_net_name, log_level=log_level))