Merge "SNAPS Stack creators can now return SNAPS network creators."
authorSteven Pisarski <s.pisarski@cablelabs.com>
Fri, 11 Aug 2017 14:46:05 +0000 (14:46 +0000)
committerGerrit Code Review <gerrit@opnfv.org>
Fri, 11 Aug 2017 14:46:05 +0000 (14:46 +0000)
14 files changed:
docs/how-to-use/IntegrationTests.rst
docs/how-to-use/UnitTests.rst
snaps/domain/network.py
snaps/domain/stack.py
snaps/domain/test/network_tests.py
snaps/domain/test/stack_tests.py
snaps/openstack/create_stack.py
snaps/openstack/tests/create_stack_tests.py
snaps/openstack/tests/heat/test_heat_template.yaml
snaps/openstack/utils/heat_utils.py
snaps/openstack/utils/neutron_utils.py
snaps/openstack/utils/tests/heat_utils_tests.py
snaps/openstack/utils/tests/neutron_utils_tests.py
snaps/test_suite_builder.py

index e5c9901..8ef54ec 100644 (file)
@@ -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
 ------------------------------------------------
index cdf466e..6f4dd6c 100644 (file)
@@ -210,6 +210,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
 ---------------------------
 
index 2c71db8..0b56c43 100644 (file)
@@ -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:
index 0302184..df4d4e4 100644 (file)
@@ -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
index 4fd20d4..0534b49 100644 (file)
@@ -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):
index a6fd8a3..e0e1ae7 100644 (file)
 # 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)
index 41cc725..454cb18 100644 (file)
@@ -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)
index fe33cd2..967e803 100644 (file)
@@ -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):
     """
index d81a71c..ffb82d6 100644 (file)
@@ -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
 
index a91a21c..c2919cb 100644 (file)
@@ -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
index c615bd5..e21c905 100644 (file)
@@ -188,6 +188,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
index 16ce9fb..92432f6 100644 (file)
@@ -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.
index f6fc2bb..5493f5b 100644 (file)
@@ -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):
         """
index f0bae6e..e264b59 100644 (file)
@@ -27,7 +27,8 @@ from snaps.domain.test.project_tests import (
     ProjectDomainObjectTests, DomainDomainObjectTests,
     ComputeQuotasDomainObjectTests, NetworkQuotasDomainObjectTests)
 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)
@@ -156,6 +157,8 @@ def add_unit_tests(suite):
         VmInstanceSettingsUnitTests))
     suite.addTest(unittest.TestLoader().loadTestsFromTestCase(
         StackDomainObjectTests))
+    suite.addTest(unittest.TestLoader().loadTestsFromTestCase(
+        ResourceDomainObjectTests))
     suite.addTest(unittest.TestLoader().loadTestsFromTestCase(
         StackSettingsUnitTests))
     suite.addTest(unittest.TestLoader().loadTestsFromTestCase(