summaryrefslogtreecommitdiffstats
path: root/snaps/openstack
diff options
context:
space:
mode:
Diffstat (limited to 'snaps/openstack')
-rw-r--r--snaps/openstack/create_stack.py76
-rw-r--r--snaps/openstack/tests/create_stack_tests.py53
-rw-r--r--snaps/openstack/tests/heat/test_heat_template.yaml13
-rw-r--r--snaps/openstack/utils/heat_utils.py52
-rw-r--r--snaps/openstack/utils/neutron_utils.py29
-rw-r--r--snaps/openstack/utils/tests/heat_utils_tests.py30
-rw-r--r--snaps/openstack/utils/tests/neutron_utils_tests.py60
7 files changed, 283 insertions, 30 deletions
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):
"""