diff options
Diffstat (limited to 'snaps/openstack')
-rw-r--r-- | snaps/openstack/cluster_template.py | 94 | ||||
-rw-r--r-- | snaps/openstack/openstack_creator.py | 27 | ||||
-rw-r--r-- | snaps/openstack/tests/cluster_template_tests.py | 301 | ||||
-rw-r--r-- | snaps/openstack/utils/magnum_utils.py | 30 | ||||
-rw-r--r-- | snaps/openstack/utils/tests/magnum_utils_tests.py | 14 |
5 files changed, 464 insertions, 2 deletions
diff --git a/snaps/openstack/cluster_template.py b/snaps/openstack/cluster_template.py new file mode 100644 index 0000000..c4ba76d --- /dev/null +++ b/snaps/openstack/cluster_template.py @@ -0,0 +1,94 @@ +# Copyright (c) 2017 Cable Television Laboratories, Inc. ("CableLabs") +# and others. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging + +from magnumclient.common.apiclient.exceptions import NotFound + +from snaps.openstack.openstack_creator import OpenStackMagnumObject +from snaps.openstack.utils import magnum_utils + +__author__ = 'spisarski' + +logger = logging.getLogger('cluster_template') + + +class OpenStackClusterTemplate(OpenStackMagnumObject): + """ + Class responsible for managing an volume in OpenStack + """ + + def __init__(self, os_creds, cluster_template_config): + """ + Constructor + :param os_creds: The OpenStack connection credentials + :param cluster_template_config: The volume type settings + :return: + """ + super(self.__class__, self).__init__(os_creds) + + self.cluster_template_config = cluster_template_config + self.__cluster_template = None + + def initialize(self): + """ + Loads the existing Volume + :return: The Volume domain object or None + """ + super(self.__class__, self).initialize() + + self.__cluster_template = magnum_utils.get_cluster_template( + self._magnum, template_config=self.cluster_template_config) + + return self.__cluster_template + + def create(self): + """ + Creates the volume in OpenStack if it does not already exist and + returns the domain Volume object + :return: The Volume domain object or None + """ + self.initialize() + + if not self.__cluster_template: + self.__cluster_template = magnum_utils.create_cluster_template( + self._magnum, self.cluster_template_config) + logger.info( + 'Created volume type with name - %s', + self.cluster_template_config.name) + + return self.__cluster_template + + def clean(self): + """ + Cleanse environment of all artifacts + :return: void + """ + if self.__cluster_template: + try: + magnum_utils.delete_cluster_template( + self._magnum, self.__cluster_template.id) + except NotFound: + pass + + self.__cluster_template = None + + def get_cluster_template(self): + """ + Returns the domain Volume object as it was populated when create() was + called + :return: the object + """ + return self.__cluster_template diff --git a/snaps/openstack/openstack_creator.py b/snaps/openstack/openstack_creator.py index 945a78b..0caee9a 100644 --- a/snaps/openstack/openstack_creator.py +++ b/snaps/openstack/openstack_creator.py @@ -13,8 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. from snaps.domain.creator import CloudObject -from snaps.openstack.utils import (nova_utils, neutron_utils, keystone_utils, - cinder_utils) +from snaps.openstack.utils import ( + nova_utils, neutron_utils, keystone_utils, cinder_utils, magnum_utils) __author__ = 'spisarski' @@ -132,3 +132,26 @@ class OpenStackVolumeObject(OpenStackCloudObject): def clean(self): raise NotImplementedError('Do not override abstract method') + + +class OpenStackMagnumObject(OpenStackCloudObject): + """ + Abstract class for all OpenStack compute creators + """ + + def __init__(self, os_creds): + """ + Constructor + :param os_creds: the OpenStack credentials object + """ + super(OpenStackMagnumObject, self).__init__(os_creds) + self._magnum = None + + def initialize(self): + self._magnum = magnum_utils.magnum_client(self._os_creds) + + def create(self): + raise NotImplementedError('Do not override abstract method') + + def clean(self): + raise NotImplementedError('Do not override abstract method') diff --git a/snaps/openstack/tests/cluster_template_tests.py b/snaps/openstack/tests/cluster_template_tests.py new file mode 100644 index 0000000..791ace2 --- /dev/null +++ b/snaps/openstack/tests/cluster_template_tests.py @@ -0,0 +1,301 @@ +# Copyright (c) 2017 Cable Television Laboratories, Inc. ("CableLabs") +# and others. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from magnumclient.common.apiclient.exceptions import BadRequest, NotFound + +from snaps.config.cluster_template import ClusterTemplateConfig +from snaps.config.flavor import FlavorConfig +from snaps.config.keypair import KeypairConfig +from snaps.openstack.cluster_template import OpenStackClusterTemplate +from snaps.openstack.create_flavor import OpenStackFlavor +from snaps.openstack.create_image import OpenStackImage +from snaps.openstack.create_keypairs import OpenStackKeypair +from snaps.openstack.tests import openstack_tests + +try: + from urllib.request import URLError +except ImportError: + from urllib2 import URLError + +import logging +import uuid + +from snaps.openstack.tests.os_source_file_test import OSIntegrationTestCase +from snaps.openstack.utils import magnum_utils + +__author__ = 'spisarski' + +logger = logging.getLogger('cluster_template_tests') + + +class CreateClusterTemplateTests(OSIntegrationTestCase): + """ + Test for the OpenStackClusterTemplate class defined in py + without any QoS Specs or Encryption + """ + + def setUp(self): + """ + Instantiates the CreateClusterTemplate object that is responsible for + downloading and creating an OS template config file within OpenStack + """ + super(self.__class__, self).__start__() + + self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4()) + self.cluster_type_name = self.guid + '-cluster-type' + self.magnum = magnum_utils.magnum_client(self.os_creds) + + metadata = self.image_metadata + if not metadata: + metadata = dict() + if 'extra_properties' not in metadata: + metadata['extra_properties'] = dict() + metadata['extra_properties']['os_distro'] = 'cirros' + + os_image_settings = openstack_tests.cirros_image_settings( + name=self.guid + '-image', image_metadata=metadata) + + self.image_creator = OpenStackImage(self.os_creds, os_image_settings) + + self.flavor_creator = OpenStackFlavor( + self.os_creds, FlavorConfig( + name=self.guid + '-flavor', ram=512, disk=10, vcpus=1)) + + keypair_priv_filepath = 'tmp/' + self.guid + keypair_pub_filepath = keypair_priv_filepath + '.pub' + + self.keypair_creator = OpenStackKeypair( + self.os_creds, KeypairConfig( + name=self.guid + '-keypair', + public_filepath=keypair_pub_filepath, + private_filepath=keypair_priv_filepath)) + + self.cluster_template_creator = None + + self.cluster_template_config = ClusterTemplateConfig( + name=self.cluster_type_name, + image=self.image_creator.image_settings.name, + keypair=self.keypair_creator.keypair_settings.name, + external_net=self.ext_net_name, + flavor=self.flavor_creator.flavor_settings.name) + + try: + self.image_creator.create() + self.flavor_creator.create() + self.keypair_creator.create() + except: + self.tearDown() + raise + + def tearDown(self): + """ + Cleans the template config + """ + if self.cluster_template_creator: + try: + self.cluster_template_creator.clean() + except: + pass + if self.keypair_creator: + try: + self.keypair_creator.clean() + except: + pass + if self.flavor_creator: + try: + self.flavor_creator.clean() + except: + pass + if self.image_creator: + try: + self.image_creator.clean() + except: + pass + + super(self.__class__, self).__clean__() + + def test_create_cluster_template(self): + """ + Tests the creation of an OpenStack cluster template. + """ + # Create ClusterTemplate + self.cluster_template_creator = OpenStackClusterTemplate( + self.os_creds, self.cluster_template_config) + created_cluster_template = self.cluster_template_creator.create() + self.assertIsNotNone(created_cluster_template) + self.assertEqual(self.cluster_template_config.name, + created_cluster_template.name) + + retrieved_cluster_template1 = magnum_utils.get_cluster_template( + self.magnum, template_config=self.cluster_template_config) + self.assertIsNotNone(retrieved_cluster_template1) + self.assertEqual(created_cluster_template, retrieved_cluster_template1) + + retrieved_cluster_template2 = magnum_utils.get_cluster_template_by_id( + self.magnum, created_cluster_template.id) + self.assertEqual(created_cluster_template, retrieved_cluster_template2) + + def test_create_delete_cluster_template(self): + """ + Tests the creation then deletion of an OpenStack template config to + ensure clean() does not raise an Exception. + """ + # Create ClusterTemplate + self.cluster_template_creator = OpenStackClusterTemplate( + self.os_creds, self.cluster_template_config) + created_cluster_template = self.cluster_template_creator.create() + self.assertIsNotNone(created_cluster_template) + + self.cluster_template_creator.clean() + + tmplt = magnum_utils.get_cluster_template( + self.magnum, template_name=self.cluster_template_config.name) + self.assertIsNone(tmplt) + + def test_create_same_cluster_template(self): + """ + Tests the creation of an OpenStack cluster_template when one already + exists. + """ + # Create ClusterTemplate + self.cluster_template_creator = OpenStackClusterTemplate( + self.os_creds, self.cluster_template_config) + cluster_template1 = self.cluster_template_creator.create() + + retrieved_cluster_template = magnum_utils.get_cluster_template( + self.magnum, template_config=self.cluster_template_config) + self.assertEqual(cluster_template1, retrieved_cluster_template) + + # Should be retrieving the instance data + os_cluster_template_2 = OpenStackClusterTemplate( + self.os_creds, self.cluster_template_config) + cluster_template2 = os_cluster_template_2.create() + self.assertEqual(cluster_template2, cluster_template2) + + def test_create_cluster_template_bad_flavor(self): + """ + Tests the creation of an OpenStack cluster template raises an + exception with an invalid flavor. + """ + # Create ClusterTemplate + cluster_template_config = ClusterTemplateConfig( + name=self.cluster_type_name, + image=self.image_creator.image_settings.name, + keypair=self.keypair_creator.keypair_settings.name, + external_net=self.ext_net_name, + flavor='foo') + + self.cluster_template_creator = OpenStackClusterTemplate( + self.os_creds, cluster_template_config) + + with self.assertRaises(BadRequest): + self.cluster_template_creator.create() + + def test_create_cluster_template_bad_master_flavor(self): + """ + Tests the creation of an OpenStack cluster template raises an + exception with an invalid master flavor. + """ + # Create ClusterTemplate + cluster_template_config = ClusterTemplateConfig( + name=self.cluster_type_name, + image=self.image_creator.image_settings.name, + keypair=self.keypair_creator.keypair_settings.name, + external_net=self.ext_net_name, + flavor=self.flavor_creator.flavor_settings.name, + master_flavor='foo') + + self.cluster_template_creator = OpenStackClusterTemplate( + self.os_creds, cluster_template_config) + + with self.assertRaises(BadRequest): + self.cluster_template_creator.create() + + def test_create_cluster_template_bad_image(self): + """ + Tests the creation of an OpenStack cluster template raises an + exception with an invalid image. + """ + # Create ClusterTemplate + cluster_template_config = ClusterTemplateConfig( + name=self.cluster_type_name, + image='foo', + keypair=self.keypair_creator.keypair_settings.name, + external_net=self.ext_net_name, + flavor=self.flavor_creator.flavor_settings.name) + + self.cluster_template_creator = OpenStackClusterTemplate( + self.os_creds, cluster_template_config) + + with self.assertRaises(BadRequest): + self.cluster_template_creator.create() + + def test_create_cluster_template_bad_keypair(self): + """ + Tests the creation of an OpenStack cluster template raises an + exception with an invalid keypair. + """ + # Create ClusterTemplate + cluster_template_config = ClusterTemplateConfig( + name=self.cluster_type_name, + image=self.image_creator.image_settings.name, + keypair='foo', + external_net=self.ext_net_name, + flavor=self.flavor_creator.flavor_settings.name) + + self.cluster_template_creator = OpenStackClusterTemplate( + self.os_creds, cluster_template_config) + + with self.assertRaises(NotFound): + self.cluster_template_creator.create() + + def test_create_cluster_template_bad_network_driver(self): + """ + Tests the creation of an OpenStack cluster template raises an + exception with an invalid keypair. + """ + # Create ClusterTemplate + cluster_template_config = ClusterTemplateConfig( + name=self.cluster_type_name, + image=self.image_creator.image_settings.name, + keypair=self.keypair_creator.keypair_settings.name, + external_net=self.ext_net_name, + flavor=self.flavor_creator.flavor_settings.name, + network_driver='foo') + + self.cluster_template_creator = OpenStackClusterTemplate( + self.os_creds, cluster_template_config) + + with self.assertRaises(BadRequest): + self.cluster_template_creator.create() + + def test_create_cluster_template_bad_volume_driver(self): + """ + Tests the creation of an OpenStack cluster template raises an + exception with an invalid keypair. + """ + # Create ClusterTemplate + cluster_template_config = ClusterTemplateConfig( + name=self.cluster_type_name, + image=self.image_creator.image_settings.name, + keypair=self.keypair_creator.keypair_settings.name, + external_net=self.ext_net_name, + flavor=self.flavor_creator.flavor_settings.name, + volume_driver='foo') + + self.cluster_template_creator = OpenStackClusterTemplate( + self.os_creds, cluster_template_config) + + with self.assertRaises(BadRequest): + self.cluster_template_creator.create() diff --git a/snaps/openstack/utils/magnum_utils.py b/snaps/openstack/utils/magnum_utils.py index c744666..96ba6d1 100644 --- a/snaps/openstack/utils/magnum_utils.py +++ b/snaps/openstack/utils/magnum_utils.py @@ -35,6 +35,36 @@ def magnum_client(os_creds): session=keystone_utils.keystone_session(os_creds)) +def get_cluster_template(magnum, template_config=None, template_name=None): + """ + Returns the first ClusterTemplate domain object that matches the parameters + :param magnum: the Magnum client + :param template_config: a ClusterTemplateConfig object (optional) + :param template_name: the name of the template to lookup + :return: ClusterTemplate object or None + """ + name = None + if template_config: + name = template_config.name + elif template_name: + name = template_name + + os_templates = magnum.cluster_templates.list() + for os_template in os_templates: + if os_template.name == name: + return __map_os_cluster_template(os_template) + + +def get_cluster_template_by_id(magnum, tmplt_id): + """ + Returns the first ClusterTemplate domain object that matches the parameters + :param magnum: the Magnum client + :param tmplt_id: the template's ID + :return: ClusterTemplate object or None + """ + return __map_os_cluster_template(magnum.cluster_templates.get(tmplt_id)) + + def create_cluster_template(magnum, cluster_template_config): """ Creates a Magnum Cluster Template object in OpenStack diff --git a/snaps/openstack/utils/tests/magnum_utils_tests.py b/snaps/openstack/utils/tests/magnum_utils_tests.py index f6da810..766e3f2 100644 --- a/snaps/openstack/utils/tests/magnum_utils_tests.py +++ b/snaps/openstack/utils/tests/magnum_utils_tests.py @@ -144,6 +144,13 @@ class MagnumUtilsClusterTypeTests(OSComponentTestCase): self.assertTrue( validate_cluster_template(config, self.cluster_template)) + template_by_name = magnum_utils.get_cluster_template( + self.magnum, template_name=config.name) + self.assertEqual(self.cluster_template, template_by_name) + template_by_id = magnum_utils.get_cluster_template_by_id( + self.magnum, self.cluster_template.id) + self.assertEqual(self.cluster_template, template_by_id) + def test_create_cluster_template_all(self): config = ClusterTemplateConfig( name=self.cluster_type_name, @@ -168,6 +175,13 @@ class MagnumUtilsClusterTypeTests(OSComponentTestCase): self.assertTrue( validate_cluster_template(config, self.cluster_template)) + template_by_name = magnum_utils.get_cluster_template( + self.magnum, template_name=config.name) + self.assertEqual(self.cluster_template, template_by_name) + template_by_id = magnum_utils.get_cluster_template_by_id( + self.magnum, self.cluster_template.id) + self.assertEqual(self.cluster_template, template_by_id) + def test_create_cluster_template_bad_image(self): config = ClusterTemplateConfig( name=self.cluster_type_name, |