summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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))