diff options
author | spisarski <s.pisarski@cablelabs.com> | 2017-08-09 14:17:26 -0600 |
---|---|---|
committer | spisarski <s.pisarski@cablelabs.com> | 2017-08-09 14:37:41 -0600 |
commit | 2b9b2d64c5be98405aaaf98db58f06b35b8af983 (patch) | |
tree | 7eac6cb5a5182371b5602e53bb613234c5eff11c | |
parent | 430905e7f76e4a074167a49ca2bfbf727eebcefd (diff) |
SNAPS Stack creators can now return SNAPS network creators.
As Heat Stacks are responsible for spawning objects in OpenStack,
the class OpenStackHeatStack which is responsible for applying and
managing the state of a stack now can retrieve OpenStackNetwork
objects for the networks created in the stack for clients who would
like to query the networks and subnets or update them outside of
Heat.
JIRA: SNAPS-171
Change-Id: I9bf0b81d4f7bfeb1b6392f345022c7d9a57d0415
Signed-off-by: spisarski <s.pisarski@cablelabs.com>
-rw-r--r-- | docs/how-to-use/IntegrationTests.rst | 3 | ||||
-rw-r--r-- | docs/how-to-use/UnitTests.rst | 6 | ||||
-rw-r--r-- | snaps/domain/network.py | 40 | ||||
-rw-r--r-- | snaps/domain/stack.py | 14 | ||||
-rw-r--r-- | snaps/domain/test/network_tests.py | 73 | ||||
-rw-r--r-- | snaps/domain/test/stack_tests.py | 20 | ||||
-rw-r--r-- | snaps/openstack/create_stack.py | 76 | ||||
-rw-r--r-- | snaps/openstack/tests/create_stack_tests.py | 53 | ||||
-rw-r--r-- | snaps/openstack/tests/heat/test_heat_template.yaml | 13 | ||||
-rw-r--r-- | snaps/openstack/utils/heat_utils.py | 52 | ||||
-rw-r--r-- | snaps/openstack/utils/neutron_utils.py | 29 | ||||
-rw-r--r-- | snaps/openstack/utils/tests/heat_utils_tests.py | 30 | ||||
-rw-r--r-- | snaps/openstack/utils/tests/neutron_utils_tests.py | 60 | ||||
-rw-r--r-- | snaps/test_suite_builder.py | 5 |
14 files changed, 423 insertions, 51 deletions
diff --git a/docs/how-to-use/IntegrationTests.rst b/docs/how-to-use/IntegrationTests.rst index e5c9901..8ef54ec 100644 --- a/docs/how-to-use/IntegrationTests.rst +++ b/docs/how-to-use/IntegrationTests.rst @@ -247,6 +247,9 @@ create_stack_tests.py - CreateStackSuccessTests | test_create_same_stack | 2 | Ensures that a Heat stack with the same name cannot be | | | | created 2x | +---------------------------------------+---------------+-----------------------------------------------------------+ +| test_create_same_stack | 2 | Ensures that a Heat stack with the same name cannot be | +| | | created 2x | ++---------------------------------------+---------------+-----------------------------------------------------------+ create_stack_tests.py - CreateStackNegativeTests ------------------------------------------------ diff --git a/docs/how-to-use/UnitTests.rst b/docs/how-to-use/UnitTests.rst index ac42892..badf0e8 100644 --- a/docs/how-to-use/UnitTests.rst +++ b/docs/how-to-use/UnitTests.rst @@ -198,6 +198,12 @@ StackDomainObjectTests Ensures that all required members are included when constructing a Stack domain object +ResourceDomainObjectTests +------------------------- + +Ensures that all required members are included when constructing a +Resource domain object + FloatingIpSettingsUnitTests --------------------------- diff --git a/snaps/domain/network.py b/snaps/domain/network.py index 2c71db8..0b56c43 100644 --- a/snaps/domain/network.py +++ b/snaps/domain/network.py @@ -25,11 +25,16 @@ class Network: """ self.name = kwargs.get('name') self.id = kwargs.get('id') - self.type = kwargs.get('provider:network_type') + self.admin_state_up = kwargs.get('admin_state_up') + self.shared = kwargs.get('shared') + self.external = kwargs.get('router:external', kwargs.get('external')) + self.type = kwargs.get('provider:network_type', kwargs.get('type')) def __eq__(self, other): return (self.name == other.name and self.id == other.id and - self.type == other.type) + self.admin_state_up == other.admin_state_up and + self.shared == other.shared and + self.external == other.external and self.type == other.type) class Subnet: @@ -44,10 +49,37 @@ class Subnet: self.name = kwargs.get('name') self.id = kwargs.get('id') self.cidr = kwargs.get('cidr') + self.ip_version = kwargs.get('ip_version') + self.gateway_ip = kwargs.get('gateway_ip') + self.enable_dhcp = kwargs.get('enable_dhcp') + self.dns_nameservers = kwargs.get('dns_nameservers') + self.host_routes = kwargs.get('host_routes') + self.ipv6_ra_mode = kwargs.get('ipv6_ra_mode') + self.ipv6_address_mode = kwargs.get('ipv6_address_mode') + + self.start = None + self.end = None + if ('allocation_pools' in kwargs and + len(kwargs['allocation_pools']) > 0): + # Will need to ultimately support a list of pools + pools = kwargs['allocation_pools'][0] + if 'start' in pools: + self.start = pools['start'] + if 'end' in pools: + self.end = pools['end'] def __eq__(self, other): - return (self.name == other.name and self.id == other.id and - self.cidr == other.cidr) + return (self.name == other.name and + self.id == other.id and + self.cidr == other.cidr and + self.ip_version == other.ip_version and + self.gateway_ip == other.gateway_ip and + self.enable_dhcp == other.enable_dhcp and + self.dns_nameservers == other.dns_nameservers and + self.host_routes == other.host_routes and + self.ipv6_ra_mode == other.ipv6_ra_mode and + self.ipv6_address_mode == other.ipv6_address_mode and + self.start == other.start and self.end == other.end) class Port: diff --git a/snaps/domain/stack.py b/snaps/domain/stack.py index 0302184..df4d4e4 100644 --- a/snaps/domain/stack.py +++ b/snaps/domain/stack.py @@ -31,3 +31,17 @@ class Stack: def __eq__(self, other): return (self.name == other.name and self.id == other.id) + + +class Resource: + """ + SNAPS domain object for resources created by a heat template + """ + def __init__(self, resource_type, resource_id): + """ + Constructor + :param resource_type: the type + :param resource_id: the ID attached to the resource of the given type + """ + self.type = resource_type + self.id = resource_id diff --git a/snaps/domain/test/network_tests.py b/snaps/domain/test/network_tests.py index 4fd20d4..0534b49 100644 --- a/snaps/domain/test/network_tests.py +++ b/snaps/domain/test/network_tests.py @@ -24,18 +24,40 @@ class NetworkObjectTests(unittest.TestCase): Tests the construction of the snaps.domain.network.Network class """ - def test_construction_kwargs(self): + def test_construction_kwargs_1(self): + network = Network( + **{'name': 'foo', 'id': 'bar', 'provider:network_type': 'flat', + 'admin_state_up': False, 'shared': True, + 'router:external': False}) + self.assertEqual('foo', network.name) + self.assertEqual('bar', network.id) + self.assertEqual('flat', network.type) + self.assertFalse(network.admin_state_up) + self.assertFalse(network.external) + self.assertTrue(network.shared) + + def test_construction_kwargs_2(self): network = Network( - **{'name': 'name', 'id': 'id', 'provider:network_type': 'flat'}) - self.assertEqual('name', network.name) - self.assertEqual('id', network.id) + **{'name': 'foo', 'id': 'bar', 'type': 'flat', + 'admin_state_up': False, 'shared': True, + 'external': False}) + self.assertEqual('foo', network.name) + self.assertEqual('bar', network.id) self.assertEqual('flat', network.type) + self.assertFalse(network.admin_state_up) + self.assertFalse(network.external) + self.assertTrue(network.shared) def test_construction_named(self): - network = Network(id='id', name='name') - self.assertEqual('name', network.name) - self.assertEqual('id', network.id) - self.assertIsNone(network.type) + network = Network( + name='foo', id='bar', type='flat', admin_state_up=False, + shared=True, external=False) + self.assertEqual('foo', network.name) + self.assertEqual('bar', network.id) + self.assertEqual('flat', network.type) + self.assertFalse(network.admin_state_up) + self.assertFalse(network.external) + self.assertTrue(network.shared) class SubnetObjectTests(unittest.TestCase): @@ -45,16 +67,39 @@ class SubnetObjectTests(unittest.TestCase): def test_construction_kwargs(self): subnet = Subnet( - **{'name': 'name', 'id': 'id', 'cidr': '10.0.0.0/24'}) - self.assertEqual('name', subnet.name) - self.assertEqual('id', subnet.id) + **{'name': 'foo', 'id': 'bar', 'cidr': '10.0.0.0/24', + 'ip_version': 4, 'gateway_ip': '10.0.0.1', 'enable_dhcp': True, + 'dns_nameservers': ['8.8.8.8'], 'host_routes': list(), + 'ipv6_ra_mode': 'hello', 'ipv6_address_mode': 'world'}) + self.assertEqual('foo', subnet.name) + self.assertEqual('bar', subnet.id) self.assertEqual('10.0.0.0/24', subnet.cidr) + self.assertEqual(4, subnet.ip_version) + self.assertEqual('10.0.0.1', subnet.gateway_ip) + self.assertTrue(subnet.enable_dhcp) + self.assertEqual(1, len(subnet.dns_nameservers)) + self.assertEqual('8.8.8.8', subnet.dns_nameservers[0]) + self.assertEqual(list(), subnet.host_routes) + self.assertEqual('hello', subnet.ipv6_ra_mode) + self.assertEqual('world', subnet.ipv6_address_mode) def test_construction_named(self): - subnet = Subnet(cidr='10.0.0.0/24', id='id', name='name') - self.assertEqual('name', subnet.name) - self.assertEqual('id', subnet.id) + subnet = Subnet( + name='foo', id='bar', cidr='10.0.0.0/24', + ip_version=4, gateway_ip='10.0.0.1', enable_dhcp=True, + dns_nameservers=['8.8.8.8'], host_routes=list(), + ipv6_ra_mode='hello', ipv6_address_mode='world') + self.assertEqual('foo', subnet.name) + self.assertEqual('bar', subnet.id) self.assertEqual('10.0.0.0/24', subnet.cidr) + self.assertEqual(4, subnet.ip_version) + self.assertEqual('10.0.0.1', subnet.gateway_ip) + self.assertTrue(subnet.enable_dhcp) + self.assertEqual(1, len(subnet.dns_nameservers)) + self.assertEqual('8.8.8.8', subnet.dns_nameservers[0]) + self.assertEqual(list(), subnet.host_routes) + self.assertEqual('hello', subnet.ipv6_ra_mode) + self.assertEqual('world', subnet.ipv6_address_mode) class PortDomainObjectTests(unittest.TestCase): diff --git a/snaps/domain/test/stack_tests.py b/snaps/domain/test/stack_tests.py index a6fd8a3..e0e1ae7 100644 --- a/snaps/domain/test/stack_tests.py +++ b/snaps/domain/test/stack_tests.py @@ -14,12 +14,12 @@ # limitations under the License. import unittest -from snaps.domain.stack import Stack +from snaps.domain.stack import Stack, Resource class StackDomainObjectTests(unittest.TestCase): """ - Tests the construction of the snaps.domain.test.Stack class + Tests the construction of the snaps.domain.Stack class """ def test_construction_positional(self): @@ -31,3 +31,19 @@ class StackDomainObjectTests(unittest.TestCase): stack = Stack(stack_id='id', name='name') self.assertEqual('name', stack.name) self.assertEqual('id', stack.id) + + +class ResourceDomainObjectTests(unittest.TestCase): + """ + Tests the construction of the snaps.domain.Resource class + """ + + def test_construction_positional(self): + resource = Resource('foo', 'bar') + self.assertEqual('foo', resource.type) + self.assertEqual('bar', resource.id) + + def test_construction_named(self): + resource = Resource(resource_id='bar', resource_type='foo') + self.assertEqual('foo', resource.type) + self.assertEqual('bar', resource.id) diff --git a/snaps/openstack/create_stack.py b/snaps/openstack/create_stack.py index 41cc725..454cb18 100644 --- a/snaps/openstack/create_stack.py +++ b/snaps/openstack/create_stack.py @@ -17,7 +17,10 @@ import logging import time from heatclient.exc import HTTPNotFound -from snaps.openstack.utils import heat_utils + +from snaps.openstack.create_network import ( + OpenStackNetwork, NetworkSettings, SubnetSettings) +from snaps.openstack.utils import heat_utils, neutron_utils __author__ = 'spisarski' @@ -51,7 +54,11 @@ class OpenStackHeatStack: """ Creates the heat stack in OpenStack if it does not already exist and returns the domain Stack object - :param cleanup: Denotes whether or not this is being called for cleanup + :param cleanup: When true, this object is initialized only via queries, + else objects will be created when the queries return + None. The name of this parameter should be changed to + something like 'readonly' as the same goes with all of + the other creator classes. :return: The OpenStack Stack object """ self.__heat_cli = heat_utils.heat_client(self.__os_creds) @@ -132,6 +139,65 @@ class OpenStackHeatStack: return self._stack_status_check(STATUS_CREATE_COMPLETE, block, timeout, poll_interval) + def get_network_creators(self): + """ + Returns a list of network creator objects as configured by the heat + template + :return: list() of OpenStackNetwork objects + """ + + neutron = neutron_utils.neutron_client(self.__os_creds) + + out = list() + stack_networks = heat_utils.get_stack_networks( + self.__heat_cli, neutron, self.__stack) + + for stack_network in stack_networks: + net_settings = self.__create_network_settings( + neutron, stack_network) + net_creator = OpenStackNetwork(self.__os_creds, net_settings) + out.append(net_creator) + net_creator.create(cleanup=True) + + return out + + def __create_network_settings(self, neutron, network): + """ + Returns a NetworkSettings object + :param neutron: the neutron client + :param network: a SNAPS-OO Network domain object + :return: + """ + return NetworkSettings( + name=network.name, network_type=network.type, + subnet_settings=self.__create_subnet_settings(neutron, network)) + + def __create_subnet_settings(self, neutron, network): + """ + Returns a list of SubnetSettings objects for a given network + :param neutron: the OpenStack neutron client + :param network: the SNAPS-OO Network domain object + :return: a list + """ + out = list() + + subnets = neutron_utils.get_subnets_by_network(neutron, network) + for subnet in subnets: + kwargs = dict() + kwargs['cidr'] = subnet.cidr + kwargs['ip_version'] = subnet.ip_version + kwargs['name'] = subnet.name + kwargs['start'] = subnet.start + kwargs['end'] = subnet.end + kwargs['gateway_ip'] = subnet.gateway_ip + kwargs['enable_dhcp'] = subnet.enable_dhcp + kwargs['dns_nameservers'] = subnet.dns_nameservers + kwargs['host_routes'] = subnet.host_routes + kwargs['ipv6_ra_mode'] = subnet.ipv6_ra_mode + kwargs['ipv6_address_mode'] = subnet.ipv6_address_mode + out.append(SubnetSettings(**kwargs)) + return out + def _stack_status_check(self, expected_status_code, block, timeout, poll_interval): """ @@ -228,14 +294,8 @@ class StackSettingsError(Exception): Exception to be thrown when an stack settings are incorrect """ - def __init__(self, message): - Exception.__init__(self, message) - class StackCreationError(Exception): """ Exception to be thrown when an stack cannot be created """ - - def __init__(self, message): - Exception.__init__(self, message) diff --git a/snaps/openstack/tests/create_stack_tests.py b/snaps/openstack/tests/create_stack_tests.py index fe33cd2..967e803 100644 --- a/snaps/openstack/tests/create_stack_tests.py +++ b/snaps/openstack/tests/create_stack_tests.py @@ -33,7 +33,7 @@ from snaps.openstack import create_stack from snaps.openstack.create_stack import StackSettings, StackSettingsError from snaps.openstack.tests import openstack_tests from snaps.openstack.tests.os_source_file_test import OSIntegrationTestCase -from snaps.openstack.utils import heat_utils +from snaps.openstack.utils import heat_utils, neutron_utils __author__ = 'spisarski' @@ -132,7 +132,7 @@ class CreateStackSuccessTests(OSIntegrationTestCase): """ super(self.__class__, self).__start__() - self.guid = str(uuid.uuid4()) + self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4()) self.heat_creds = self.admin_os_creds self.heat_creds.project_name = self.admin_os_creds.project_name @@ -142,7 +142,7 @@ class CreateStackSuccessTests(OSIntegrationTestCase): self.image_creator = OpenStackImage( self.heat_creds, openstack_tests.cirros_image_settings( - name=self.__class__.__name__ + '-' + str(self.guid) + '-image', + name=self.guid + '-image', image_metadata=self.image_metadata)) self.image_creator.create() @@ -153,9 +153,13 @@ class CreateStackSuccessTests(OSIntegrationTestCase): vcpus=1)) self.flavor_creator.create() + self.network_name = self.guid + '-net' + self.subnet_name = self.guid + '-subnet' self.env_values = { 'image_name': self.image_creator.image_settings.name, - 'flavor_name': self.flavor_creator.flavor_settings.name} + 'flavor_name': self.flavor_creator.flavor_settings.name, + 'net_name': self.network_name, + 'subnet_name': self.subnet_name} self.heat_tmplt_path = pkg_resources.resource_filename( 'snaps.openstack.tests.heat', 'test_heat_template.yaml') @@ -208,6 +212,11 @@ class CreateStackSuccessTests(OSIntegrationTestCase): self.assertIsNotNone(self.stack_creator.get_outputs()) self.assertEquals(0, len(self.stack_creator.get_outputs())) + resources = heat_utils.get_resources( + self.heat_cli, self.stack_creator.get_stack()) + self.assertIsNotNone(resources) + self.assertEqual(4, len(resources)) + def test_create_stack_template_dict(self): """ Tests the creation of an OpenStack stack from a heat dict() object. @@ -309,6 +318,42 @@ class CreateStackSuccessTests(OSIntegrationTestCase): stack2 = stack_creator2.create() self.assertEqual(created_stack1.id, stack2.id) + def test_retrieve_network_creators(self): + """ + Tests the creation of an OpenStack stack from Heat template file and + the retrieval of the network creator. + """ + stack_settings = StackSettings( + name=self.__class__.__name__ + '-' + str(self.guid) + '-stack', + template_path=self.heat_tmplt_path, + env_values=self.env_values) + self.stack_creator = create_stack.OpenStackHeatStack(self.heat_creds, + stack_settings) + created_stack = self.stack_creator.create() + self.assertIsNotNone(created_stack) + + net_creators = self.stack_creator.get_network_creators() + self.assertIsNotNone(net_creators) + self.assertEqual(1, len(net_creators)) + self.assertEqual(self.network_name, net_creators[0].get_network().name) + + neutron = neutron_utils.neutron_client(self.os_creds) + net_by_name = neutron_utils.get_network( + neutron, network_name=net_creators[0].get_network().name) + self.assertEqual(net_creators[0].get_network(), net_by_name) + self.assertIsNotNone(neutron_utils.get_network_by_id( + neutron, net_creators[0].get_network().id)) + + self.assertEqual(1, len(net_creators[0].get_subnets())) + subnet = net_creators[0].get_subnets()[0] + subnet_by_name = neutron_utils.get_subnet( + neutron, subnet_name=subnet.name) + self.assertEqual(subnet, subnet_by_name) + + subnet_by_id = neutron_utils.get_subnet_by_id(neutron, subnet.id) + self.assertIsNotNone(subnet_by_id) + self.assertEqual(subnet_by_name, subnet_by_id) + class CreateStackNegativeTests(OSIntegrationTestCase): """ diff --git a/snaps/openstack/tests/heat/test_heat_template.yaml b/snaps/openstack/tests/heat/test_heat_template.yaml index d81a71c..ffb82d6 100644 --- a/snaps/openstack/tests/heat/test_heat_template.yaml +++ b/snaps/openstack/tests/heat/test_heat_template.yaml @@ -13,16 +13,27 @@ parameters: label: Instance Type description: Type of instance (flavor) to be used default: m1.small + net_name: + type: string + label: Test network name + description: The name of the stack's network + default: test_net + subnet_name: + type: string + label: Test subnet name + description: The name of the stack's subnet + default: test_subnet resources: private_net: type: OS::Neutron::Net properties: - name: test_net + name: { get_param: net_name } private_subnet: type: OS::Neutron::Subnet properties: + name: { get_param: subnet_name } network_id: { get_resource: private_net } cidr: 10.0.0.0/24 diff --git a/snaps/openstack/utils/heat_utils.py b/snaps/openstack/utils/heat_utils.py index a91a21c..c2919cb 100644 --- a/snaps/openstack/utils/heat_utils.py +++ b/snaps/openstack/utils/heat_utils.py @@ -20,9 +20,9 @@ from heatclient.common.template_format import yaml_loader from oslo_serialization import jsonutils from snaps import file_utils -from snaps.domain.stack import Stack +from snaps.domain.stack import Stack, Resource -from snaps.openstack.utils import keystone_utils +from snaps.openstack.utils import keystone_utils, neutron_utils __author__ = 'spisarski' @@ -130,6 +130,54 @@ def delete_stack(heat_cli, stack): heat_cli.stacks.delete(stack.id) +def __get_os_resources(heat_cli, stack): + """ + Returns all of the OpenStack resource objects for a given stack + :param heat_cli: the OpenStack heat client + :param stack: the SNAPS-OO Stack domain object + :return: a list + """ + return heat_cli.resources.list(stack.id) + + +def get_resources(heat_cli, stack): + """ + Returns all of the OpenStack resource objects for a given stack + :param heat_cli: the OpenStack heat client + :param stack: the SNAPS-OO Stack domain object + :return: a list + """ + os_resources = __get_os_resources(heat_cli, stack) + + if os_resources: + out = list() + for os_resource in os_resources: + out.append(Resource(resource_type=os_resource.resource_type, + resource_id=os_resource.physical_resource_id)) + return out + + +def get_stack_networks(heat_cli, neutron, stack): + """ + Returns an instance of NetworkSettings for each network owned by this stack + :param heat_cli: the OpenStack heat client object + :param neutron: the OpenStack neutron client object + :param stack: the SNAPS-OO Stack domain object + :return: a list of NetworkSettings + """ + + out = list() + resources = get_resources(heat_cli, stack) + for resource in resources: + if resource.type == 'OS::Neutron::Net': + network = neutron_utils.get_network_by_id( + neutron, resource.id) + if network: + out.append(network) + + return out + + def parse_heat_template_str(tmpl_str): """ Takes a heat template string, performs some simple validation and returns a diff --git a/snaps/openstack/utils/neutron_utils.py b/snaps/openstack/utils/neutron_utils.py index e7b002a..076557b 100644 --- a/snaps/openstack/utils/neutron_utils.py +++ b/snaps/openstack/utils/neutron_utils.py @@ -187,6 +187,35 @@ def get_subnet(neutron, subnet_settings=None, subnet_name=None): return Subnet(**subnet) +def get_subnet_by_id(neutron, subnet_id): + """ + Returns a SNAPS-OO Subnet domain object for a given ID + :param neutron: the OpenStack neutron client + :param subnet_id: the subnet ID + :return: a Subnet object + """ + os_subnet = neutron.show_subnet(subnet_id) + if os_subnet and 'subnet' in os_subnet: + return Subnet(**os_subnet['subnet']) + + +def get_subnets_by_network(neutron, network): + """ + Returns a list of SNAPS-OO Subnet domain objects + :param neutron: the OpenStack neutron client + :param network: the SNAPS-OO Network domain object + :return: a list of Subnet objects + """ + out = list() + + os_subnets = neutron.list_subnets(network_id=network.id) + + for os_subnet in os_subnets['subnets']: + out.append(Subnet(**os_subnet)) + + return out + + def create_router(neutron, os_creds, router_settings): """ Creates a router for OpenStack diff --git a/snaps/openstack/utils/tests/heat_utils_tests.py b/snaps/openstack/utils/tests/heat_utils_tests.py index 16ce9fb..92432f6 100644 --- a/snaps/openstack/utils/tests/heat_utils_tests.py +++ b/snaps/openstack/utils/tests/heat_utils_tests.py @@ -25,7 +25,7 @@ from snaps.openstack.create_image import OpenStackImage from snaps.openstack.create_stack import StackSettings from snaps.openstack.tests import openstack_tests from snaps.openstack.tests.os_source_file_test import OSComponentTestCase -from snaps.openstack.utils import heat_utils +from snaps.openstack.utils import heat_utils, neutron_utils __author__ = 'spisarski' @@ -77,13 +77,14 @@ class HeatUtilsCreateStackTests(OSComponentTestCase): Instantiates OpenStack instances that cannot be spawned by Heat """ guid = self.__class__.__name__ + '-' + str(uuid.uuid4()) - stack_name1 = self.__class__.__name__ + '-' + str(guid) + '-stack1' - stack_name2 = self.__class__.__name__ + '-' + str(guid) + '-stack2' + stack_name1 = guid + '-stack1' + stack_name2 = guid + '-stack2' + self.network_name = guid + '-net' + self.subnet_name = guid + '-subnet' self.image_creator = OpenStackImage( self.os_creds, openstack_tests.cirros_image_settings( - name=self.__class__.__name__ + '-' + str(guid) + '-image', - image_metadata=self.image_metadata)) + name=guid + '-image', image_metadata=self.image_metadata)) self.image_creator.create() # Create Flavor @@ -93,7 +94,9 @@ class HeatUtilsCreateStackTests(OSComponentTestCase): self.flavor_creator.create() env_values = {'image_name': self.image_creator.image_settings.name, - 'flavor_name': self.flavor_creator.flavor_settings.name} + 'flavor_name': self.flavor_creator.flavor_settings.name, + 'net_name': self.network_name, + 'subnet_name': self.subnet_name} heat_tmplt_path = pkg_resources.resource_filename( 'snaps.openstack.tests.heat', 'test_heat_template.yaml') self.stack_settings1 = StackSettings( @@ -175,6 +178,21 @@ class HeatUtilsCreateStackTests(OSComponentTestCase): self.assertTrue(is_active) + resources = heat_utils.get_resources(self.heat_client, self.stack1) + self.assertIsNotNone(resources) + self.assertEqual(4, len(resources)) + + neutron = neutron_utils.neutron_client(self.os_creds) + networks = heat_utils.get_stack_networks( + self.heat_client, neutron, self.stack1) + self.assertIsNotNone(networks) + self.assertEqual(1, len(networks)) + self.assertEqual(self.network_name, networks[0].name) + + subnets = neutron_utils.get_subnets_by_network(neutron, networks[0]) + self.assertEqual(1, len(subnets)) + self.assertEqual(self.subnet_name, subnets[0].name) + def test_create_stack_x2(self): """ Tests the creation of an OpenStack keypair that does not exist. diff --git a/snaps/openstack/utils/tests/neutron_utils_tests.py b/snaps/openstack/utils/tests/neutron_utils_tests.py index f6fc2bb..5493f5b 100644 --- a/snaps/openstack/utils/tests/neutron_utils_tests.py +++ b/snaps/openstack/utils/tests/neutron_utils_tests.py @@ -152,9 +152,15 @@ class NeutronUtilsSubnetTests(OSComponentTestCase): Cleans the remote OpenStack objects """ if self.subnet: - neutron_utils.delete_subnet(self.neutron, self.subnet) + try: + neutron_utils.delete_subnet(self.neutron, self.subnet) + except: + pass if self.network: - neutron_utils.delete_network(self.neutron, self.network) + try: + neutron_utils.delete_network(self.neutron, self.network) + except: + pass def test_create_subnet(self): """ @@ -173,6 +179,16 @@ class NeutronUtilsSubnetTests(OSComponentTestCase): self.assertTrue(validate_subnet( self.neutron, subnet_setting.name, subnet_setting.cidr, True)) + subnet_query1 = neutron_utils.get_subnet( + self.neutron, subnet_name=subnet_setting.name) + self.assertEqual(self.subnet, subnet_query1) + + subnet_query2 = neutron_utils.get_subnets_by_network(self.neutron, + self.network) + self.assertIsNotNone(subnet_query2) + self.assertEqual(1, len(subnet_query2)) + self.assertEqual(self.subnet, subnet_query2[0]) + def test_create_subnet_null_name(self): """ Tests the neutron_utils.create_neutron_subnet() function for an @@ -201,13 +217,23 @@ class NeutronUtilsSubnetTests(OSComponentTestCase): self.neutron, self.net_config.network_settings.name, True)) subnet_setting = self.net_config.network_settings.subnet_settings[0] - neutron_utils.create_subnet( + self.subnet = neutron_utils.create_subnet( self.neutron, subnet_setting, self.os_creds, network=self.network) self.assertTrue(validate_subnet( self.neutron, subnet_setting.name, subnet_setting.cidr, True)) self.assertFalse(validate_subnet( self.neutron, '', subnet_setting.cidr, True)) + subnet_query1 = neutron_utils.get_subnet( + self.neutron, subnet_name=subnet_setting.name) + self.assertEqual(self.subnet, subnet_query1) + + subnet_query2 = neutron_utils.get_subnets_by_network(self.neutron, + self.network) + self.assertIsNotNone(subnet_query2) + self.assertEqual(1, len(subnet_query2)) + self.assertEqual(self.subnet, subnet_query2[0]) + def test_create_subnet_null_cidr(self): """ Tests the neutron_utils.create_neutron_subnet() function for an @@ -272,17 +298,29 @@ class NeutronUtilsRouterTests(OSComponentTestCase): self.subnet) if self.router: - neutron_utils.delete_router(self.neutron, self.router) - validate_router(self.neutron, self.router.name, False) + try: + neutron_utils.delete_router(self.neutron, self.router) + validate_router(self.neutron, self.router.name, False) + except: + pass if self.port: - neutron_utils.delete_port(self.neutron, self.port) + try: + neutron_utils.delete_port(self.neutron, self.port) + except: + pass if self.subnet: - neutron_utils.delete_subnet(self.neutron, self.subnet) + try: + neutron_utils.delete_subnet(self.neutron, self.subnet) + except: + pass if self.network: - neutron_utils.delete_network(self.neutron, self.network) + try: + neutron_utils.delete_network(self.neutron, self.network) + except: + pass def test_create_router_simple(self): """ @@ -757,7 +795,11 @@ class NeutronUtilsFloatingIpTests(OSComponentTestCase): Cleans the image and downloaded image file """ if self.floating_ip: - neutron_utils.delete_floating_ip(self.neutron, self.floating_ip) + try: + neutron_utils.delete_floating_ip( + self.neutron, self.floating_ip) + except: + pass def test_floating_ips(self): """ diff --git a/snaps/test_suite_builder.py b/snaps/test_suite_builder.py index b80fcab..9beb422 100644 --- a/snaps/test_suite_builder.py +++ b/snaps/test_suite_builder.py @@ -26,7 +26,8 @@ from snaps.domain.test.network_tests import ( from snaps.domain.test.project_tests import ( ProjectDomainObjectTests, DomainDomainObjectTests) from snaps.domain.test.role_tests import RoleDomainObjectTests -from snaps.domain.test.stack_tests import StackDomainObjectTests +from snaps.domain.test.stack_tests import ( + StackDomainObjectTests, ResourceDomainObjectTests) from snaps.domain.test.user_tests import UserDomainObjectTests from snaps.domain.test.vm_inst_tests import ( VmInstDomainObjectTests, FloatingIpDomainObjectTests) @@ -152,6 +153,8 @@ def add_unit_tests(suite): suite.addTest(unittest.TestLoader().loadTestsFromTestCase( StackDomainObjectTests)) suite.addTest(unittest.TestLoader().loadTestsFromTestCase( + ResourceDomainObjectTests)) + suite.addTest(unittest.TestLoader().loadTestsFromTestCase( StackSettingsUnitTests)) suite.addTest(unittest.TestLoader().loadTestsFromTestCase( VmInstDomainObjectTests)) |