diff options
-rw-r--r-- | snaps/openstack/create_project.py | 8 | ||||
-rw-r--r-- | snaps/openstack/create_router.py | 24 | ||||
-rw-r--r-- | snaps/openstack/create_security_group.py | 34 | ||||
-rw-r--r-- | snaps/openstack/tests/create_flavor_tests.py | 70 | ||||
-rw-r--r-- | snaps/openstack/tests/create_image_tests.py | 9 | ||||
-rw-r--r-- | snaps/openstack/tests/create_project_tests.py | 7 | ||||
-rw-r--r-- | snaps/openstack/tests/create_router_tests.py | 13 | ||||
-rw-r--r-- | snaps/openstack/tests/create_security_group_tests.py | 18 | ||||
-rw-r--r-- | snaps/openstack/utils/glance_utils.py | 37 | ||||
-rw-r--r-- | snaps/openstack/utils/nova_utils.py | 11 |
10 files changed, 162 insertions, 69 deletions
diff --git a/snaps/openstack/create_project.py b/snaps/openstack/create_project.py index 0384ccc..a20033e 100644 --- a/snaps/openstack/create_project.py +++ b/snaps/openstack/create_project.py @@ -131,5 +131,11 @@ class ProjectSettings: self.enabled = True if not self.name: - raise Exception( + raise ProjectSettingsError( "The attribute name is required for ProjectSettings") + + +class ProjectSettingsError(Exception): + """ + Exception to be thrown when project settings attributes are incorrect + """ diff --git a/snaps/openstack/create_router.py b/snaps/openstack/create_router.py index db6ffe3..e50009c 100644 --- a/snaps/openstack/create_router.py +++ b/snaps/openstack/create_router.py @@ -39,7 +39,7 @@ class OpenStackRouter: self.__os_creds = os_creds if not router_settings: - raise Exception('router_settings is required') + raise RouterCreationError('router_settings is required') self.router_settings = router_settings self.__neutron = None @@ -84,7 +84,7 @@ class OpenStackRouter: self.__internal_router_interface = neutron_utils.add_interface_router( self.__neutron, self.__router, subnet=internal_subnet) else: - raise Exception( + raise RouterCreationError( 'Subnet not found with name ' + internal_subnet_name) for port_setting in self.router_settings.port_settings: @@ -108,7 +108,7 @@ class OpenStackRouter: self.__router, port=port) else: - raise Exception( + raise RouterCreationError( 'Error creating port with name - ' + port_setting.name) return self.__router @@ -163,6 +163,12 @@ class OpenStackRouter: return self.__internal_router_interface +class RouterCreationError(Exception): + """ + Exception to be thrown when an router instance cannot be created + """ + + class RouterSettings: """ Class representing a router configuration @@ -209,7 +215,7 @@ class RouterSettings: PortSettings(**interface['port'])) if not self.name: - raise Exception('Name is required') + raise RouterSettingsError('Name is required') def dict_for_neutron(self, neutron, os_creds): """ @@ -239,7 +245,7 @@ class RouterSettings: if project_id: out['project_id'] = project_id else: - raise Exception( + raise RouterSettingsError( 'Could not find project ID for project named - ' + self.project_name) if self.admin_state_up is not None: @@ -251,7 +257,7 @@ class RouterSettings: ext_gw['network_id'] = ext_net.id out['external_gateway_info'] = ext_gw else: - raise Exception( + raise RouterSettingsError( 'Could not find the external network named - ' + self.external_gateway) @@ -259,3 +265,9 @@ class RouterSettings: # TODO: Add external_fixed_ips Tests return {'router': out} + + +class RouterSettingsError(Exception): + """ + Exception to be thrown when router settings attributes are incorrect + """ diff --git a/snaps/openstack/create_security_group.py b/snaps/openstack/create_security_group.py index 3dbf559..4291796 100644 --- a/snaps/openstack/create_security_group.py +++ b/snaps/openstack/create_security_group.py @@ -240,11 +240,11 @@ class SecurityGroupSettings: **rule_setting)) if not self.name: - raise Exception('The attribute name is required') + raise SecurityGroupSettingsError('The attribute name is required') for rule_setting in self.rule_settings: if rule_setting.sec_grp_name is not self.name: - raise Exception( + raise SecurityGroupSettingsError( 'Rule settings must correspond with the name of this ' 'security group') @@ -272,7 +272,7 @@ class SecurityGroupSettings: if project_id: out['project_id'] = project_id else: - raise Exception( + raise SecurityGroupSettingsError( 'Could not find project ID for project named - ' + self.project_name) @@ -305,6 +305,13 @@ class Ethertype(enum.Enum): IPv6 = 6 +class SecurityGroupSettingsError(Exception): + """ + Exception to be thrown when security group settings attributes are + invalid + """ + + class SecurityGroupRuleSettings: """ Class representing a keypair configuration @@ -368,7 +375,8 @@ class SecurityGroupRuleSettings: self.remote_ip_prefix = kwargs.get('remote_ip_prefix') if not self.direction or not self.sec_grp_name: - raise Exception('direction and sec_grp_name are required') + raise SecurityGroupRuleSettingsError( + 'direction and sec_grp_name are required') def dict_for_neutron(self, neutron): """ @@ -399,7 +407,7 @@ class SecurityGroupRuleSettings: if sec_grp: out['security_group_id'] = sec_grp.id else: - raise Exception( + raise SecurityGroupRuleSettingsError( 'Cannot locate security group with name - ' + self.sec_grp_name) if self.remote_group_id: @@ -490,7 +498,8 @@ def map_direction(direction): elif dir_str == 'ingress': return Direction.ingress else: - raise Exception('Invalid Direction - ' + dir_str) + raise SecurityGroupRuleSettingsError( + 'Invalid Direction - ' + dir_str) def map_protocol(protocol): @@ -516,7 +525,8 @@ def map_protocol(protocol): elif proto_str == 'null': return Protocol.null else: - raise Exception('Invalid Protocol - ' + proto_str) + raise SecurityGroupRuleSettingsError( + 'Invalid Protocol - ' + proto_str) def map_ethertype(ethertype): @@ -538,4 +548,12 @@ def map_ethertype(ethertype): elif eth_str == 'IPv4': return Ethertype.IPv4 else: - raise Exception('Invalid Ethertype - ' + eth_str) + raise SecurityGroupRuleSettingsError( + 'Invalid Ethertype - ' + eth_str) + + +class SecurityGroupRuleSettingsError(Exception): + """ + Exception to be thrown when security group rule settings attributes are + invalid + """ diff --git a/snaps/openstack/tests/create_flavor_tests.py b/snaps/openstack/tests/create_flavor_tests.py index 11306f4..4852d06 100644 --- a/snaps/openstack/tests/create_flavor_tests.py +++ b/snaps/openstack/tests/create_flavor_tests.py @@ -15,6 +15,7 @@ import unittest import uuid +from snaps.openstack import create_flavor from snaps.openstack.create_flavor import FlavorSettings, OpenStackFlavor, \ FlavorSettingsError from snaps.openstack.tests.os_source_file_test import OSComponentTestCase @@ -294,7 +295,7 @@ class CreateFlavorTests(OSComponentTestCase): vcpus=1) self.flavor_creator = OpenStackFlavor(self.os_creds, flavor_settings) flavor = self.flavor_creator.create() - self.assertTrue(validate_flavor(flavor_settings, flavor)) + self.assertTrue(validate_flavor(self.nova, flavor_settings, flavor)) def test_create_flavor_existing(self): """ @@ -306,7 +307,7 @@ class CreateFlavorTests(OSComponentTestCase): vcpus=1) self.flavor_creator = OpenStackFlavor(self.os_creds, flavor_settings) flavor = self.flavor_creator.create() - self.assertTrue(validate_flavor(flavor_settings, flavor)) + self.assertTrue(validate_flavor(self.nova, flavor_settings, flavor)) flavor_creator_2 = OpenStackFlavor(self.os_creds, flavor_settings) flavor2 = flavor_creator_2.create() @@ -322,7 +323,7 @@ class CreateFlavorTests(OSComponentTestCase): vcpus=1) self.flavor_creator = OpenStackFlavor(self.os_creds, flavor_settings) flavor = self.flavor_creator.create() - self.assertTrue(validate_flavor(flavor_settings, flavor)) + self.assertTrue(validate_flavor(self.nova, flavor_settings, flavor)) # Clean Flavor self.flavor_creator.clean() @@ -333,7 +334,7 @@ class CreateFlavorTests(OSComponentTestCase): def test_create_delete_flavor(self): """ - Tests the creation of an OpenStack Security Group, the deletion, then + Tests the creation of an OpenStack Flavor, the deletion, then cleanup to ensure clean() does not raise any exceptions. """ @@ -342,7 +343,7 @@ class CreateFlavorTests(OSComponentTestCase): vcpus=1) self.flavor_creator = OpenStackFlavor(self.os_creds, flavor_settings) flavor = self.flavor_creator.create() - self.assertTrue(validate_flavor(flavor_settings, flavor)) + self.assertTrue(validate_flavor(self.nova, flavor_settings, flavor)) # Delete Flavor nova_utils.delete_flavor(self.nova, flavor) @@ -354,17 +355,62 @@ class CreateFlavorTests(OSComponentTestCase): self.assertIsNone(self.flavor_creator.get_flavor()) - # TODO - Add more tests to exercise all configuration options + def test_create_flavor_all_settings(self): + """ + Tests the creation of an OpenStack Flavor, the deletion, then + cleanup to ensure clean() does not + raise any exceptions. + """ + # Create Flavor + flavor_settings = FlavorSettings( + name=self.flavor_name, ram=1, disk=1, vcpus=1, ephemeral=2, swap=3, + rxtx_factor=2.2, is_public=False, + metadata=create_flavor.MEM_PAGE_SIZE_ANY) + self.flavor_creator = OpenStackFlavor(self.os_creds, flavor_settings) + flavor = self.flavor_creator.create() + self.assertTrue(validate_flavor(self.nova, flavor_settings, flavor)) + + # Delete Flavor + nova_utils.delete_flavor(self.nova, flavor) + self.assertIsNone( + nova_utils.get_flavor_by_name(self.nova, flavor_settings.name)) + + # Attempt to cleanup + self.flavor_creator.clean() + + self.assertIsNone(self.flavor_creator.get_flavor()) -def validate_flavor(flavor_settings, flavor): +def validate_flavor(nova, flavor_settings, flavor): """ Validates the flavor_settings against the OpenStack flavor object + :param nova: the nova client :param flavor_settings: the settings used to create the flavor :param flavor: the OpenStack flavor object """ - return flavor is not None \ - and flavor_settings.name == flavor.name \ - and flavor_settings.ram == flavor.ram \ - and flavor_settings.disk == flavor.disk \ - and flavor_settings.vcpus == flavor.vcpus + setting_meta = dict() + if flavor_settings.metadata: + setting_meta = flavor_settings.metadata + metadata = nova_utils.get_flavor_keys(nova, flavor) + + equals = True + for key, value in setting_meta.items(): + if metadata[key] != value: + equals = False + break + + swap = str() + if flavor_settings.swap != 0: + swap = flavor_settings.swap + + return ( + flavor is not None and + flavor_settings.name == flavor.name and + flavor_settings.ram == flavor.ram and + flavor_settings.disk == flavor.disk and + flavor_settings.vcpus == flavor.vcpus and + flavor_settings.ephemeral == flavor.ephemeral and + swap == flavor.swap and + flavor_settings.rxtx_factor == flavor.rxtx_factor and + flavor_settings.is_public == flavor.is_public and + equals) diff --git a/snaps/openstack/tests/create_image_tests.py b/snaps/openstack/tests/create_image_tests.py index d538fef..6c9b175 100644 --- a/snaps/openstack/tests/create_image_tests.py +++ b/snaps/openstack/tests/create_image_tests.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 glanceclient.exc import HTTPBadRequest try: from urllib.request import URLError @@ -514,8 +515,14 @@ class CreateImageNegativeTests(OSIntegrationTestCase): img_format=os_image_settings.format, url="http://foo.bar")) - with self.assertRaises(URLError): + try: self.image_creator.create() + except HTTPBadRequest: + pass + except URLError: + pass + except Exception as e: + self.fail('Invalid Exception ' + str(e)) def test_bad_image_file(self): """ diff --git a/snaps/openstack/tests/create_project_tests.py b/snaps/openstack/tests/create_project_tests.py index 3c6b2d1..f2af0d9 100644 --- a/snaps/openstack/tests/create_project_tests.py +++ b/snaps/openstack/tests/create_project_tests.py @@ -15,7 +15,8 @@ import unittest import uuid -from snaps.openstack.create_project import OpenStackProject, ProjectSettings +from snaps.openstack.create_project import ( + OpenStackProject, ProjectSettings, ProjectSettingsError) from snaps.openstack.create_security_group import OpenStackSecurityGroup from snaps.openstack.create_security_group import SecurityGroupSettings from snaps.openstack.create_user import OpenStackUser @@ -32,11 +33,11 @@ class ProjectSettingsUnitTests(unittest.TestCase): """ def test_no_params(self): - with self.assertRaises(Exception): + with self.assertRaises(ProjectSettingsError): ProjectSettings() def test_empty_config(self): - with self.assertRaises(Exception): + with self.assertRaises(ProjectSettingsError): ProjectSettings(**dict()) def test_name_only(self): diff --git a/snaps/openstack/tests/create_router_tests.py b/snaps/openstack/tests/create_router_tests.py index 5f2534d..efa0993 100644 --- a/snaps/openstack/tests/create_router_tests.py +++ b/snaps/openstack/tests/create_router_tests.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016 Cable Television Laboratories, Inc. ("CableLabs") +# Copyright (c) 2017 Cable Television Laboratories, Inc. ("CableLabs") # and others. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,7 +20,8 @@ from snaps.openstack import create_router from snaps.openstack.create_network import ( NetworkSettings, PortSettings) from snaps.openstack.create_network import OpenStackNetwork -from snaps.openstack.create_router import RouterSettings +from snaps.openstack.create_router import ( + RouterSettings, RouterSettingsError, RouterCreationError) from snaps.openstack.tests.os_source_file_test import OSIntegrationTestCase from snaps.openstack.utils import neutron_utils @@ -38,11 +39,11 @@ class RouterSettingsUnitTests(unittest.TestCase): """ def test_no_params(self): - with self.assertRaises(Exception): + with self.assertRaises(RouterSettingsError): RouterSettings() def test_empty_config(self): - with self.assertRaises(Exception): + with self.assertRaises(RouterSettingsError): RouterSettings(**dict()) def test_name_only(self): @@ -338,7 +339,7 @@ class CreateRouterNegativeTests(OSIntegrationTestCase): """ Test creating a router without a name. """ - with self.assertRaises(Exception): + with self.assertRaises(RouterSettingsError): router_settings = RouterSettings( name=None, external_gateway=self.ext_net_name) self.router_creator = create_router.OpenStackRouter( @@ -349,7 +350,7 @@ class CreateRouterNegativeTests(OSIntegrationTestCase): """ Test creating a router without a valid network gateway name. """ - with self.assertRaises(Exception): + with self.assertRaises(RouterSettingsError): router_settings = RouterSettings(name=self.guid + '-pub-router', external_gateway="Invalid_name") self.router_creator = create_router.OpenStackRouter( diff --git a/snaps/openstack/tests/create_security_group_tests.py b/snaps/openstack/tests/create_security_group_tests.py index 75c6387..dd28d7d 100644 --- a/snaps/openstack/tests/create_security_group_tests.py +++ b/snaps/openstack/tests/create_security_group_tests.py @@ -19,7 +19,9 @@ from snaps.openstack import create_security_group from snaps.openstack.create_security_group import (SecurityGroupSettings, SecurityGroupRuleSettings, Direction, Ethertype, - Protocol) + Protocol, + SecurityGroupRuleSettingsError, + SecurityGroupSettingsError) from snaps.openstack.tests import validation_utils from snaps.openstack.tests.os_source_file_test import OSIntegrationTestCase from snaps.openstack.utils import neutron_utils @@ -33,19 +35,19 @@ class SecurityGroupRuleSettingsUnitTests(unittest.TestCase): """ def test_no_params(self): - with self.assertRaises(Exception): + with self.assertRaises(SecurityGroupRuleSettingsError): SecurityGroupRuleSettings() def test_empty_config(self): - with self.assertRaises(Exception): + with self.assertRaises(SecurityGroupRuleSettingsError): SecurityGroupRuleSettings(**dict()) def test_name_only(self): - with self.assertRaises(Exception): + with self.assertRaises(SecurityGroupRuleSettingsError): SecurityGroupRuleSettings(sec_grp_name='foo') def test_config_with_name_only(self): - with self.assertRaises(Exception): + with self.assertRaises(SecurityGroupRuleSettingsError): SecurityGroupRuleSettings(**{'sec_grp_name': 'foo'}) def test_name_and_direction(self): @@ -105,11 +107,11 @@ class SecurityGroupSettingsUnitTests(unittest.TestCase): """ def test_no_params(self): - with self.assertRaises(Exception): + with self.assertRaises(SecurityGroupSettingsError): SecurityGroupSettings() def test_empty_config(self): - with self.assertRaises(Exception): + with self.assertRaises(SecurityGroupSettingsError): SecurityGroupSettings(**dict()) def test_name_only(self): @@ -123,7 +125,7 @@ class SecurityGroupSettingsUnitTests(unittest.TestCase): def test_invalid_rule(self): rule_setting = SecurityGroupRuleSettings(sec_grp_name='bar', direction=Direction.ingress) - with self.assertRaises(Exception): + with self.assertRaises(SecurityGroupSettingsError): SecurityGroupSettings(name='foo', rule_settings=[rule_setting]) def test_all(self): diff --git a/snaps/openstack/utils/glance_utils.py b/snaps/openstack/utils/glance_utils.py index 1010757..090846c 100644 --- a/snaps/openstack/utils/glance_utils.py +++ b/snaps/openstack/utils/glance_utils.py @@ -106,35 +106,24 @@ def __create_image_v1(glance, image_settings): :return: the OpenStack image object :raise exceptions from the Glance client or IOError when opening a file """ - created_image = None + kwargs = { + 'name': image_settings.name, 'disk_format': image_settings.format, + 'container_format': 'bare', 'is_public': image_settings.public} + + if image_settings.extra_properties: + kwargs['properties'] = image_settings.extra_properties - # TODO/REFACTOR - replace each call with one including kwargs if image_settings.url: - if image_settings.extra_properties: - created_image = glance.images.create( - name=image_settings.name, disk_format=image_settings.format, - container_format="bare", location=image_settings.url, - properties=image_settings.extra_properties, - is_public=image_settings.public) - else: - created_image = glance.images.create( - name=image_settings.name, disk_format=image_settings.format, - container_format="bare", location=image_settings.url, - is_public=image_settings.public) + kwargs['location'] = image_settings.url elif image_settings.image_file: image_file = open(image_settings.image_file, 'rb') - if image_settings.extra_properties: - created_image = glance.images.create( - name=image_settings.name, disk_format=image_settings.format, - container_format="bare", data=image_file, - properties=image_settings.extra_properties, - is_public=image_settings.public) - else: - created_image = glance.images.create( - name=image_settings.name, disk_format=image_settings.format, - container_format="bare", data=image_file, - is_public=image_settings.public) + kwargs['data'] = image_file + else: + logger.warn('Unable to create image with name - %s. No file or URL', + image_settings.name) + return None + created_image = glance.images.create(**kwargs) return Image(name=image_settings.name, image_id=created_image.id, size=created_image.size, properties=created_image.properties) diff --git a/snaps/openstack/utils/nova_utils.py b/snaps/openstack/utils/nova_utils.py index 16b3984..70b1e7b 100644 --- a/snaps/openstack/utils/nova_utils.py +++ b/snaps/openstack/utils/nova_utils.py @@ -454,6 +454,17 @@ def set_flavor_keys(nova, flavor, metadata): os_flavor.set_keys(metadata) +def get_flavor_keys(nova, flavor): + """ + Sets metadata on the flavor + :param nova: the Nova client + :param flavor: the SNAPS flavor domain object + """ + os_flavor = __get_os_flavor(nova, flavor) + if os_flavor: + return os_flavor.get_keys() + + def add_security_group(nova, vm, security_group_name): """ Adds a security group to an existing VM |