summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Pisarski <s.pisarski@cablelabs.com>2017-10-30 15:24:00 +0000
committerGerrit Code Review <gerrit@opnfv.org>2017-10-30 15:24:00 +0000
commit0dfca494ef7c2778babfac48d9b701953860b54f (patch)
tree777d30f3ecfca3f4bc689dfaa24c4bcd2b2fc634
parentff6141ac35b4e0abd551c4d1f08a1e62ab538ec3 (diff)
parent6b7307374f6cfcad9eec8986aba8fdd8e08c8574 (diff)
Merge "Return OpenStackVolume and OpenStackVolumeType instances from heat."
-rw-r--r--docs/how-to-use/APITests.rst15
-rw-r--r--docs/how-to-use/IntegrationTests.rst39
-rw-r--r--docs/how-to-use/UnitTests.rst9
-rw-r--r--snaps/openstack/create_stack.py75
-rw-r--r--snaps/openstack/tests/create_stack_tests.py98
-rw-r--r--snaps/openstack/tests/heat/volume_heat_template.yaml51
-rw-r--r--snaps/openstack/utils/heat_utils.py97
-rw-r--r--snaps/openstack/utils/settings_utils.py46
-rw-r--r--snaps/openstack/utils/tests/heat_utils_tests.py120
-rw-r--r--snaps/openstack/utils/tests/settings_utils_tests.py47
-rw-r--r--snaps/test_suite_builder.py19
11 files changed, 562 insertions, 54 deletions
diff --git a/docs/how-to-use/APITests.rst b/docs/how-to-use/APITests.rst
index 3ac272b..fbd7e67 100644
--- a/docs/how-to-use/APITests.rst
+++ b/docs/how-to-use/APITests.rst
@@ -447,6 +447,21 @@ heat_utils_tests.py - HeatUtilsCreateComplexStackTests
| | | by Heat |
+---------------------------------------+---------------+-----------------------------------------------------------+
+heat_utils_tests.py - HeatUtilsVolumeTests
+------------------------------------------
+
++---------------------------------------+---------------+-----------------------------------------------------------+
+| Test Name | Heat API | Description |
++=======================================+===============+===========================================================+
+| test_create_vol_with_stack | 1 | Tests ability of the function |
+| | | heat_utils.get_stack_volumes() to return the correct |
+| | | Volume domain objects deployed with Heat |
++---------------------------------------+---------------+-----------------------------------------------------------+
+| test_create_vol_types_with_stack | 1 | Tests ability of the function |
+| | | heat_utils.get_stack_volumes_types() to return the correct|
+| | | VolumeType domain objects deployed with Heat |
++---------------------------------------+---------------+-----------------------------------------------------------+
+
settings_utils_tests.py - SettingsUtilsNetworkingTests
------------------------------------------------------
diff --git a/docs/how-to-use/IntegrationTests.rst b/docs/how-to-use/IntegrationTests.rst
index 5a734ef..538c9c0 100644
--- a/docs/how-to-use/IntegrationTests.rst
+++ b/docs/how-to-use/IntegrationTests.rst
@@ -360,34 +360,49 @@ create_stack_tests.py - CreateStackSuccessTests
-----------------------------------------------
+---------------------------------------+---------------+-----------------------------------------------------------+
-| Test Name | Neutron API | Description |
+| Test Name | Heat API | Description |
+=======================================+===============+===========================================================+
-| test_create_stack_template_file | 2 | Ensures that a Heat stack can be created with a file-based|
+| test_create_stack_template_file | 1 | Ensures that a Heat stack can be created with a file-based|
| | | Heat template file |
+---------------------------------------+---------------+-----------------------------------------------------------+
-| test_create_stack_template_dict | 2 | Ensures that a Heat stack can be created with a dictionary|
+| test_create_stack_template_dict | 1 | Ensures that a Heat stack can be created with a dictionary|
| | | Heat template |
+---------------------------------------+---------------+-----------------------------------------------------------+
-| test_create_delete_stack | 2 | Ensures that a Heat stack can be created and deleted |
+| test_create_delete_stack | 1 | Ensures that a Heat stack can be created and deleted |
| | | while having clean() called 2x without an exception |
+---------------------------------------+---------------+-----------------------------------------------------------+
-| test_create_same_stack | 2 | Ensures that a Heat stack with the same name cannot be |
+| test_create_same_stack | 1 | Ensures that a Heat stack with the same name cannot be |
| | | created 2x |
+---------------------------------------+---------------+-----------------------------------------------------------+
-| test_retrieve_network_creators | 2 | Ensures that an OpenStackHeatStack instance can return an |
+| test_retrieve_network_creators | 1 | Ensures that an OpenStackHeatStack instance can return an |
| | | OpenStackNetwork instance configured as deployed |
+---------------------------------------+---------------+-----------------------------------------------------------+
-| test_retrieve_vm_inst_creators | 2 | Ensures that an OpenStackHeatStack instance can return an |
+| test_retrieve_vm_inst_creators | 1 | Ensures that an OpenStackHeatStack instance can return an |
| | | OpenStackVmInstance instance configured as deployed |
+---------------------------------------+---------------+-----------------------------------------------------------+
+create_stack_tests.py - CreateStackVolumeTests
+----------------------------------------------
+
++---------------------------------------+---------------+-----------------------------------------------------------+
+| Test Name | Heat API | Description |
++=======================================+===============+===========================================================+
+| test_retrieve_volume_creator | 1 | Ensures that an OpenStackHeatStack instance can return a |
+| | | OpenStackVolume instance that it was responsible for |
+| | | deploying |
++---------------------------------------+---------------+-----------------------------------------------------------+
+| test_retrieve_volume_type_creator | 1 | Ensures that an OpenStackHeatStack instance can return a |
+| | | OpenStackVolumeType instance that it was responsible for |
+| | | deploying |
++---------------------------------------+---------------+-----------------------------------------------------------+
+
create_stack_tests.py - CreateComplexStackTests
-----------------------------------------------
+---------------------------------------+---------------+-----------------------------------------------------------+
-| Test Name | Neutron API | Description |
+| Test Name | Heat API | Description |
+=======================================+===============+===========================================================+
-| test_connect_via_ssh_heat_vm | 2 | Ensures that two OpenStackHeatStack instances can return |
+| test_connect_via_ssh_heat_vm | 1 | Ensures that two OpenStackHeatStack instances can return |
| | | OpenStackVmInstance instances one configured with a |
| | | floating IP and keypair and can be access via SSH |
+---------------------------------------+---------------+-----------------------------------------------------------+
@@ -396,12 +411,12 @@ create_stack_tests.py - CreateStackNegativeTests
------------------------------------------------
+----------------------------------------+---------------+-----------------------------------------------------------+
-| Test Name | Neutron API | Description |
+| Test Name | Heat API | Description |
+========================================+===============+===========================================================+
-| test_missing_dependencies | 2 | Ensures that a Heat template fails to deploy when expected|
+| test_missing_dependencies | 1 | Ensures that a Heat template fails to deploy when expected|
| | | dependencies are missing |
+----------------------------------------+---------------+-----------------------------------------------------------+
-| test_bad_stack_file | 2 | Ensures that a Heat template fails to deploy when the Heat|
+| test_bad_stack_file | 1 | Ensures that a Heat template fails to deploy when the Heat|
| | | template file does not exist |
+----------------------------------------+---------------+-----------------------------------------------------------+
diff --git a/docs/how-to-use/UnitTests.rst b/docs/how-to-use/UnitTests.rst
index f6f52b5..3cb26db 100644
--- a/docs/how-to-use/UnitTests.rst
+++ b/docs/how-to-use/UnitTests.rst
@@ -293,3 +293,12 @@ VmInstDomainObjectTests
Ensures that all required members are included when constructing a
VmInst domain object
+
+SettingsUtilsVolumeTests
+------------------------
+
+Ensures that the settings_utils.py#create_volume_settings() function properly
+maps a snaps.domain.Volume object correctly to a
+snaps.openstack.create_volume.VolumeSettings object as well as a
+snaps.domain.VolumeType object to a
+snaps.openstack.create_volume.VolumeSettings object
diff --git a/snaps/openstack/create_stack.py b/snaps/openstack/create_stack.py
index 22edb65..d8f9d15 100644
--- a/snaps/openstack/create_stack.py
+++ b/snaps/openstack/create_stack.py
@@ -19,8 +19,11 @@ import time
from heatclient.exc import HTTPNotFound
from snaps.openstack.create_instance import OpenStackVmInstance
+from snaps.openstack.create_volume import OpenStackVolume
+from snaps.openstack.create_volume_type import OpenStackVolumeType
from snaps.openstack.openstack_creator import OpenStackCloudObject
-from snaps.openstack.utils import nova_utils, settings_utils, glance_utils
+from snaps.openstack.utils import (
+ nova_utils, settings_utils, glance_utils, cinder_utils)
from snaps.openstack.create_network import OpenStackNetwork
from snaps.openstack.utils import heat_utils, neutron_utils
@@ -95,25 +98,22 @@ class OpenStackHeatStack(OpenStackCloudObject, object):
self.initialize()
if self.__stack:
- logger.info('Found stack with name - ' + self.stack_settings.name)
+ logger.info('Found stack with name - %s', self.stack_settings.name)
return self.__stack
else:
self.__stack = heat_utils.create_stack(self.__heat_cli,
self.stack_settings)
logger.info(
- 'Created stack with name - ' + self.stack_settings.name)
+ 'Created stack with name - %s', self.stack_settings.name)
if self.__stack and self.stack_complete(block=True):
- logger.info(
- 'Stack is now active with name - ' +
- self.stack_settings.name)
+ logger.info('Stack is now active with name - %s',
+ self.stack_settings.name)
return self.__stack
else:
status = heat_utils.get_stack_status_reason(self.__heat_cli,
self.__stack.id)
- logger.error(
- 'ERROR: STACK CREATION FAILED: ' + status)
- raise StackCreationError(
- 'Failure while creating stack')
+ logger.error('ERROR: STACK CREATION FAILED: %s', status)
+ raise StackCreationError('Failure while creating stack')
def clean(self):
"""
@@ -122,7 +122,7 @@ class OpenStackHeatStack(OpenStackCloudObject, object):
"""
if self.__stack:
try:
- logger.info('Deleting stack - %s' + self.__stack.name)
+ logger.info('Deleting stack - %s', self.__stack.name)
heat_utils.delete_stack(self.__heat_cli, self.__stack)
try:
@@ -265,6 +265,59 @@ class OpenStackHeatStack(OpenStackCloudObject, object):
return out
+ def get_volume_creators(self):
+ """
+ Returns a list of Volume creator objects as configured by the heat
+ template
+ :return: list() of OpenStackVolume objects
+ """
+
+ out = list()
+ cinder = cinder_utils.cinder_client(self._os_creds)
+
+ volumes = heat_utils.get_stack_volumes(
+ self.__heat_cli, cinder, self.__stack)
+
+ for volume in volumes:
+ settings = settings_utils.create_volume_settings(volume)
+ creator = OpenStackVolume(self._os_creds, settings)
+ out.append(creator)
+
+ try:
+ creator.initialize()
+ except Exception as e:
+ logger.error(
+ 'Unexpected error initializing volume creator - %s', e)
+
+ return out
+
+ def get_volume_type_creators(self):
+ """
+ Returns a list of VolumeType creator objects as configured by the heat
+ template
+ :return: list() of OpenStackVolumeType objects
+ """
+
+ out = list()
+ cinder = cinder_utils.cinder_client(self._os_creds)
+
+ vol_types = heat_utils.get_stack_volume_types(
+ self.__heat_cli, cinder, self.__stack)
+
+ for volume in vol_types:
+ settings = settings_utils.create_volume_type_settings(volume)
+ creator = OpenStackVolumeType(self._os_creds, settings)
+ out.append(creator)
+
+ try:
+ creator.initialize()
+ except Exception as e:
+ logger.error(
+ 'Unexpected error initializing volume type creator - %s',
+ e)
+
+ return out
+
def _stack_status_check(self, expected_status_code, block, timeout,
poll_interval, fail_status):
"""
diff --git a/snaps/openstack/tests/create_stack_tests.py b/snaps/openstack/tests/create_stack_tests.py
index d96462a..a2b2215 100644
--- a/snaps/openstack/tests/create_stack_tests.py
+++ b/snaps/openstack/tests/create_stack_tests.py
@@ -394,7 +394,7 @@ class CreateStackSuccessTests(OSIntegrationTestCase):
nova, vm_inst_creators[0].get_vm_inst().id))
-class CreateComplexStackTests(OSIntegrationTestCase):
+class CreateStackFloatingIpTests(OSIntegrationTestCase):
"""
Tests for the CreateStack class defined in create_stack.py
"""
@@ -493,6 +493,102 @@ class CreateComplexStackTests(OSIntegrationTestCase):
self.assertEqual(0, len(vm_settings.floating_ip_settings))
+class CreateStackVolumeTests(OSIntegrationTestCase):
+ """
+ Tests for the CreateStack class defined in create_stack.py
+ """
+
+ def setUp(self):
+ """
+ Instantiates the CreateStack object that is responsible for downloading
+ and creating an OS stack file within OpenStack
+ """
+ super(self.__class__, self).__start__()
+
+ 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
+
+ self.heat_cli = heat_utils.heat_client(self.heat_creds)
+ self.stack_creator = None
+
+ self.volume_name = self.guid + '-volume'
+ self.volume_type_name = self.guid + '-volume-type'
+
+ self.env_values = {
+ 'volume_name': self.volume_name,
+ 'volume_type_name': self.volume_type_name}
+
+ self.heat_tmplt_path = pkg_resources.resource_filename(
+ 'snaps.openstack.tests.heat', 'volume_heat_template.yaml')
+
+ 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)
+ self.created_stack = self.stack_creator.create()
+ self.assertIsNotNone(self.created_stack)
+
+ def tearDown(self):
+ """
+ Cleans the stack and downloaded stack file
+ """
+ if self.stack_creator:
+ try:
+ self.stack_creator.clean()
+ except:
+ pass
+
+ super(self.__class__, self).__clean__()
+
+ def test_retrieve_volume_creator(self):
+ """
+ Tests the creation of an OpenStack stack from Heat template file and
+ the retrieval of an OpenStackVolume creator/state machine instance
+ """
+ volume_creators = self.stack_creator.get_volume_creators()
+ self.assertEqual(1, len(volume_creators))
+
+ creator = volume_creators[0]
+ self.assertEqual(self.volume_name, creator.volume_settings.name)
+ self.assertEqual(self.volume_name, creator.get_volume().name)
+ self.assertEqual(self.volume_type_name,
+ creator.volume_settings.type_name)
+ self.assertEqual(self.volume_type_name, creator.get_volume().type)
+ self.assertEqual(1, creator.volume_settings.size)
+ self.assertEqual(1, creator.get_volume().size)
+
+ def test_retrieve_volume_type_creator(self):
+ """
+ Tests the creation of an OpenStack stack from Heat template file and
+ the retrieval of an OpenStackVolume creator/state machine instance
+ """
+ volume_type_creators = self.stack_creator.get_volume_type_creators()
+ self.assertEqual(1, len(volume_type_creators))
+
+ creator = volume_type_creators[0]
+ self.assertIsNotNone(creator)
+
+ volume_type = creator.get_volume_type()
+ self.assertIsNotNone(volume_type)
+
+ self.assertEqual(self.volume_type_name, volume_type.name)
+ self.assertTrue(volume_type.public)
+ self.assertIsNone(volume_type.qos_spec)
+
+ encryption = volume_type.encryption
+ self.assertIsNotNone(encryption)
+ self.assertIsNone(encryption.cipher)
+ self.assertEqual('front-end', encryption.control_location)
+ self.assertIsNone(encryption.key_size)
+ self.assertEqual(u'nova.volume.encryptors.luks.LuksEncryptor',
+ encryption.provider)
+ self.assertEqual(volume_type.id, encryption.volume_type_id)
+
+
class CreateStackNegativeTests(OSIntegrationTestCase):
"""
Negative test cases for the CreateStack class
diff --git a/snaps/openstack/tests/heat/volume_heat_template.yaml b/snaps/openstack/tests/heat/volume_heat_template.yaml
new file mode 100644
index 0000000..7b6e55a
--- /dev/null
+++ b/snaps/openstack/tests/heat/volume_heat_template.yaml
@@ -0,0 +1,51 @@
+##############################################################################
+# Copyright (c) 2017 Cable Television Laboratories, Inc. ("CableLabs")
+# and others. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##############################################################################
+heat_template_version: 2015-04-30
+
+description: Simple template to deploy a single volume with encryption
+
+parameters:
+ volume_name:
+ type: string
+ label: Volume name
+ description: The name of the volume
+ default: test-vol-name
+ volume_type_name:
+ type: string
+ label: Volume Type name
+ description: The name of the volume type
+ default: test-vol-type-name
+
+resources:
+ volume_type:
+ type: OS::Cinder::VolumeType
+ properties:
+ name: { get_param: volume_type_name }
+
+ encryption_vol_type:
+ type: OS::Cinder::EncryptedVolumeType
+ properties:
+ provider: nova.volume.encryptors.luks.LuksEncryptor
+ control_location: front-end
+ volume_type: { get_resource: volume_type }
+
+ volume:
+ type: OS::Cinder::Volume
+ properties:
+ name: { get_param: volume_name }
+ size: 1
+ volume_type: { get_resource: encryption_vol_type }
diff --git a/snaps/openstack/utils/heat_utils.py b/snaps/openstack/utils/heat_utils.py
index 8b9395b..f2d4efd 100644
--- a/snaps/openstack/utils/heat_utils.py
+++ b/snaps/openstack/utils/heat_utils.py
@@ -23,7 +23,8 @@ from oslo_serialization import jsonutils
from snaps import file_utils
from snaps.domain.stack import Stack, Resource, Output
-from snaps.openstack.utils import keystone_utils, neutron_utils, nova_utils
+from snaps.openstack.utils import keystone_utils, neutron_utils, nova_utils, \
+ cinder_utils
__author__ = 'spisarski'
@@ -140,20 +141,24 @@ def __get_os_resources(heat_cli, stack):
return heat_cli.resources.list(stack.id)
-def get_resources(heat_cli, stack):
+def get_resources(heat_cli, stack, res_type=None):
"""
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
+ :param res_type: the type name to filter
+ :return: a list of Resource domain objects
"""
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))
+ if ((res_type and os_resource.resource_type == res_type)
+ or not res_type):
+ out.append(Resource(
+ resource_type=os_resource.resource_type,
+ resource_id=os_resource.physical_resource_id))
return out
@@ -163,7 +168,7 @@ def get_outputs(heat_cli, stack):
for given stack
:param heat_cli: the OpenStack heat client
:param stack: the SNAPS-OO Stack domain object
- :return: a list
+ :return: a list of Output domain objects
"""
out = list()
@@ -182,46 +187,86 @@ def get_outputs(heat_cli, stack):
def get_stack_networks(heat_cli, neutron, stack):
"""
- Returns an instance of NetworkSettings for each network owned by this stack
+ Returns a list of Network domain objects deployed 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
+ :return: a list of Network objects
"""
out = list()
- resources = get_resources(heat_cli, stack)
+ resources = get_resources(heat_cli, stack, 'OS::Neutron::Net')
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)
+ network = neutron_utils.get_network_by_id(
+ neutron, resource.id)
+ if network:
+ out.append(network)
return out
def get_stack_servers(heat_cli, nova, stack):
"""
- Returns an instance of NetworkSettings for each network owned by this stack
+ Returns a list of VMInst domain objects associated with a Stack
:param heat_cli: the OpenStack heat client object
:param nova: the OpenStack nova client object
:param stack: the SNAPS-OO Stack domain object
- :return: a list of NetworkSettings
+ :return: a list of VMInst domain objects
"""
out = list()
- resources = get_resources(heat_cli, stack)
+ resources = get_resources(heat_cli, stack, 'OS::Nova::Server')
for resource in resources:
- if resource.type == 'OS::Nova::Server':
- try:
- server = nova_utils.get_server_object_by_id(
- nova, resource.id)
- if server:
- out.append(server)
- except NotFound:
- logger.warn(
- 'VmInst cannot be located with ID %s', resource.id)
+ try:
+ server = nova_utils.get_server_object_by_id(nova, resource.id)
+ if server:
+ out.append(server)
+ except NotFound:
+ logger.warn('VmInst cannot be located with ID %s', resource.id)
+
+ return out
+
+
+def get_stack_volumes(heat_cli, cinder, stack):
+ """
+ Returns an instance of NetworkSettings for each network owned by this stack
+ :param heat_cli: the OpenStack heat client object
+ :param cinder: the OpenStack cinder client object
+ :param stack: the SNAPS-OO Stack domain object
+ :return: a list of Volume domain objects
+ """
+
+ out = list()
+ resources = get_resources(heat_cli, stack, 'OS::Cinder::Volume')
+ for resource in resources:
+ try:
+ server = cinder_utils.get_volume_by_id(cinder, resource.id)
+ if server:
+ out.append(server)
+ except NotFound:
+ logger.warn('Volume cannot be located with ID %s', resource.id)
+
+ return out
+
+
+def get_stack_volume_types(heat_cli, cinder, stack):
+ """
+ Returns an instance of NetworkSettings for each network owned by this stack
+ :param heat_cli: the OpenStack heat client object
+ :param cinder: the OpenStack cinder client object
+ :param stack: the SNAPS-OO Stack domain object
+ :return: a list of VolumeType domain objects
+ """
+
+ out = list()
+ resources = get_resources(heat_cli, stack, 'OS::Cinder::VolumeType')
+ for resource in resources:
+ try:
+ vol_type = cinder_utils.get_volume_type_by_id(cinder, resource.id)
+ if vol_type:
+ out.append(vol_type)
+ except NotFound:
+ logger.warn('VolumeType cannot be located with ID %s', resource.id)
return out
diff --git a/snaps/openstack/utils/settings_utils.py b/snaps/openstack/utils/settings_utils.py
index 7f00075..7169319 100644
--- a/snaps/openstack/utils/settings_utils.py
+++ b/snaps/openstack/utils/settings_utils.py
@@ -20,6 +20,9 @@ from snaps.openstack.create_instance import (
from snaps.openstack.create_keypairs import KeypairSettings
from snaps.openstack.create_network import (
PortSettings, SubnetSettings, NetworkSettings)
+from snaps.openstack.create_volume import VolumeSettings
+from snaps.openstack.create_volume_type import (
+ VolumeTypeSettings, VolumeTypeEncryptionSettings, ControlLocation)
from snaps.openstack.utils import (
neutron_utils, nova_utils, heat_utils, glance_utils)
@@ -63,6 +66,49 @@ def create_subnet_settings(neutron, network):
return out
+def create_volume_settings(volume):
+ """
+ Returns a VolumeSettings object
+ :param volume: a SNAPS-OO Volume object
+ """
+
+ return VolumeSettings(
+ name=volume.name, description=volume.description,
+ size=volume.size, type_name=volume.type,
+ availability_zone=volume.availability_zone,
+ multi_attach=volume.multi_attach)
+
+
+def create_volume_type_settings(volume_type):
+ """
+ Returns a VolumeTypeSettings object
+ :param volume_type: a SNAPS-OO VolumeType object
+ """
+
+ control = None
+ if volume_type.encryption:
+ if (volume_type.encryption.control_location
+ == ControlLocation.front_end.value):
+ control = ControlLocation.front_end
+ else:
+ control = ControlLocation.back_end
+
+ encrypt_settings = VolumeTypeEncryptionSettings(
+ name=volume_type.encryption.__class__,
+ provider_class=volume_type.encryption.provider,
+ control_location=control,
+ cipher=volume_type.encryption.cipher,
+ key_size=volume_type.encryption.key_size)
+
+ qos_spec_name = None
+ if volume_type.qos_spec:
+ qos_spec_name = volume_type.qos_spec.name
+
+ return VolumeTypeSettings(
+ name=volume_type.name, encryption=encrypt_settings,
+ qos_spec_name=qos_spec_name, public=volume_type.public)
+
+
def create_vm_inst_settings(nova, neutron, server):
"""
Returns a NetworkSettings object
diff --git a/snaps/openstack/utils/tests/heat_utils_tests.py b/snaps/openstack/utils/tests/heat_utils_tests.py
index 6f75f89..4f58613 100644
--- a/snaps/openstack/utils/tests/heat_utils_tests.py
+++ b/snaps/openstack/utils/tests/heat_utils_tests.py
@@ -27,7 +27,8 @@ 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, neutron_utils, nova_utils, settings_utils, glance_utils)
+ heat_utils, neutron_utils, nova_utils, settings_utils, glance_utils,
+ cinder_utils)
__author__ = 'spisarski'
@@ -460,3 +461,120 @@ class HeatUtilsCreateComplexStackTests(OSComponentTestCase):
priv_key_key='private_key')
self.assertIsNotNone(keypair2_settings)
self.assertEqual(self.keypair_name, keypair2_settings.name)
+
+
+class HeatUtilsVolumeTests(OSComponentTestCase):
+ """
+ Test Heat volume functionality
+ """
+
+ def setUp(self):
+ """
+ Instantiates OpenStack instances that cannot be spawned by Heat
+ """
+ guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
+ stack_name = guid + '-stack'
+ self.volume_name = guid + '-vol'
+ self.volume_type_name = guid + '-vol-type'
+
+ env_values = {
+ 'volume_name': self.volume_name,
+ 'volume_type_name': self.volume_type_name}
+
+ heat_tmplt_path = pkg_resources.resource_filename(
+ 'snaps.openstack.tests.heat', 'volume_heat_template.yaml')
+ self.stack_settings = StackSettings(
+ name=stack_name, template_path=heat_tmplt_path,
+ env_values=env_values)
+ self.stack = None
+ self.heat_client = heat_utils.heat_client(self.os_creds)
+ self.cinder = cinder_utils.cinder_client(self.os_creds)
+
+ def tearDown(self):
+ """
+ Cleans the image and downloaded image file
+ """
+ if self.stack:
+ try:
+ heat_utils.delete_stack(self.heat_client, self.stack)
+ except:
+ pass
+
+ def test_create_vol_with_stack(self):
+ """
+ Tests the creation of an OpenStack volume with Heat.
+ """
+ self.stack = heat_utils.create_stack(
+ self.heat_client, self.stack_settings)
+
+ # Wait until stack deployment has completed
+ end_time = time.time() + create_stack.STACK_COMPLETE_TIMEOUT
+ is_active = False
+ while time.time() < end_time:
+ status = heat_utils.get_stack_status(self.heat_client,
+ self.stack.id)
+ if status == create_stack.STATUS_CREATE_COMPLETE:
+ is_active = True
+ break
+ elif status == create_stack.STATUS_CREATE_FAILED:
+ is_active = False
+ break
+
+ time.sleep(3)
+
+ self.assertTrue(is_active)
+
+ volumes = heat_utils.get_stack_volumes(
+ self.heat_client, self.cinder, self.stack)
+
+ self.assertEqual(1, len(volumes))
+
+ volume = volumes[0]
+ self.assertEqual(self.volume_name, volume.name)
+ self.assertEqual(self.volume_type_name, volume.type)
+ self.assertEqual(1, volume.size)
+ self.assertEqual(False, volume.multi_attach)
+
+ def test_create_vol_types_with_stack(self):
+ """
+ Tests the creation of an OpenStack volume with Heat.
+ """
+ self.stack = heat_utils.create_stack(
+ self.heat_client, self.stack_settings)
+
+ # Wait until stack deployment has completed
+ end_time = time.time() + create_stack.STACK_COMPLETE_TIMEOUT
+ is_active = False
+ while time.time() < end_time:
+ status = heat_utils.get_stack_status(self.heat_client,
+ self.stack.id)
+ if status == create_stack.STATUS_CREATE_COMPLETE:
+ is_active = True
+ break
+ elif status == create_stack.STATUS_CREATE_FAILED:
+ is_active = False
+ break
+
+ time.sleep(3)
+
+ self.assertTrue(is_active)
+
+ volume_types = heat_utils.get_stack_volume_types(
+ self.heat_client, self.cinder, self.stack)
+
+ self.assertEqual(1, len(volume_types))
+
+ volume_type = volume_types[0]
+
+ self.assertEqual(self.volume_type_name, volume_type.name)
+ self.assertTrue(volume_type.public)
+ self.assertIsNone(volume_type.qos_spec)
+
+ encryption = volume_type.encryption
+ self.assertIsNotNone(encryption)
+ self.assertIsNone(encryption.cipher)
+ self.assertEqual('front-end', encryption.control_location)
+ self.assertIsNone(encryption.key_size)
+ self.assertEqual(u'nova.volume.encryptors.luks.LuksEncryptor',
+ encryption.provider)
+ self.assertEqual(volume_type.id, encryption.volume_type_id)
diff --git a/snaps/openstack/utils/tests/settings_utils_tests.py b/snaps/openstack/utils/tests/settings_utils_tests.py
index f84e6a0..cb14039 100644
--- a/snaps/openstack/utils/tests/settings_utils_tests.py
+++ b/snaps/openstack/utils/tests/settings_utils_tests.py
@@ -13,14 +13,19 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import logging
+import unittest
+
import os
import uuid
+from snaps.domain.volume import (
+ Volume, VolumeType, VolumeTypeEncryption, QoSSpec)
from snaps.openstack import (
create_image, create_network, create_router, create_flavor,
create_keypairs, create_instance)
from snaps.openstack.create_network import (
NetworkSettings, OpenStackNetwork, SubnetSettings)
+from snaps.openstack.create_qos import Consumer
from snaps.openstack.create_security_group import (
SecurityGroupRuleSettings, Direction, Protocol, OpenStackSecurityGroup,
SecurityGroupSettings)
@@ -339,3 +344,45 @@ class SettingsUtilsVmInstTests(OSComponentTestCase):
self.assertIsNotNone(derived_image_settings)
self.assertEqual(self.image_creator.image_settings.name,
derived_image_settings.name)
+
+
+class SettingsUtilsVolumeTests(unittest.TestCase):
+ """
+ Exercises the settings_utils.py functions around volumes
+ """
+
+ def test_vol_settings_from_vol(self):
+ volume = Volume(
+ name='vol-name', volume_id='vol-id', description='desc', size=99,
+ vol_type='vol-type', availability_zone='zone1', multi_attach=True)
+ settings = settings_utils.create_volume_settings(volume)
+ self.assertEqual(volume.name, settings.name)
+ self.assertEqual(volume.description, settings.description)
+ self.assertEqual(volume.size, settings.size)
+ self.assertEqual(volume.type, settings.type_name)
+ self.assertEqual(volume.availability_zone, settings.availability_zone)
+ self.assertEqual(volume.multi_attach, settings.multi_attach)
+
+ def test_vol_type_settings_from_vol(self):
+ encryption = VolumeTypeEncryption(
+ volume_encryption_id='vol-encrypt-id', volume_type_id='vol-typ-id',
+ control_location='front-end', provider='FooClass', cipher='1',
+ key_size=1)
+ qos_spec = QoSSpec(name='qos-spec-name', spec_id='qos-spec-id',
+ consumer=Consumer.back_end)
+ volume_type = VolumeType(
+ name='vol-type-name', volume_type_id='vol-type-id', public=True,
+ encryption=encryption, qos_spec=qos_spec)
+
+ settings = settings_utils.create_volume_type_settings(volume_type)
+ self.assertEqual(volume_type.name, settings.name)
+ self.assertEqual(volume_type.public, settings.public)
+
+ encrypt_settings = settings.encryption
+ self.assertIsNotNone(encrypt_settings)
+ self.assertEqual(encryption.control_location,
+ encrypt_settings.control_location.value)
+ self.assertEqual(encryption.cipher, encrypt_settings.cipher)
+ self.assertEqual(encryption.key_size, encrypt_settings.key_size)
+
+ self.assertEqual(qos_spec.name, settings.qos_spec_name)
diff --git a/snaps/test_suite_builder.py b/snaps/test_suite_builder.py
index f06b027..77a8a2a 100644
--- a/snaps/test_suite_builder.py
+++ b/snaps/test_suite_builder.py
@@ -68,7 +68,7 @@ from snaps.openstack.tests.create_security_group_tests import (
SecurityGroupSettingsUnitTests)
from snaps.openstack.tests.create_stack_tests import (
StackSettingsUnitTests, CreateStackSuccessTests, CreateStackNegativeTests,
- CreateComplexStackTests)
+ CreateStackFloatingIpTests, CreateStackVolumeTests)
from snaps.openstack.tests.create_user_tests import (
UserSettingsUnitTests, CreateUserSuccessTests)
from snaps.openstack.tests.create_volume_tests import (
@@ -88,7 +88,7 @@ from snaps.openstack.utils.tests.glance_utils_tests import (
GlanceSmokeTests, GlanceUtilsTests)
from snaps.openstack.utils.tests.heat_utils_tests import (
HeatSmokeTests, HeatUtilsCreateSimpleStackTests,
- HeatUtilsCreateComplexStackTests)
+ HeatUtilsCreateComplexStackTests, HeatUtilsVolumeTests)
from snaps.openstack.utils.tests.keystone_utils_tests import (
KeystoneSmokeTests, KeystoneUtilsTests)
from snaps.openstack.utils.tests.neutron_utils_tests import (
@@ -98,6 +98,8 @@ from snaps.openstack.utils.tests.neutron_utils_tests import (
from snaps.openstack.utils.tests.nova_utils_tests import (
NovaSmokeTests, NovaUtilsKeypairTests, NovaUtilsFlavorTests,
NovaUtilsInstanceTests, NovaUtilsInstanceVolumeTests)
+from snaps.openstack.utils.tests.settings_utils_tests import (
+ SettingsUtilsVolumeTests)
from snaps.provisioning.tests.ansible_utils_tests import (
AnsibleProvisioningTests)
from snaps.tests.file_utils_tests import FileUtilsTests
@@ -198,6 +200,8 @@ def add_unit_tests(suite):
VolumeTypeSettingsUnitTests))
suite.addTest(unittest.TestLoader().loadTestsFromTestCase(
VolumeSettingsUnitTests))
+ suite.addTest(unittest.TestLoader().loadTestsFromTestCase(
+ SettingsUtilsVolumeTests))
def add_openstack_client_tests(suite, os_creds, ext_net_name,
@@ -322,6 +326,10 @@ def add_openstack_api_tests(suite, os_creds, ext_net_name, use_keystone=True,
ext_net_name=ext_net_name, log_level=log_level,
image_metadata=image_metadata))
suite.addTest(OSComponentTestCase.parameterize(
+ HeatUtilsVolumeTests, os_creds=os_creds,
+ ext_net_name=ext_net_name, log_level=log_level,
+ image_metadata=image_metadata))
+ suite.addTest(OSComponentTestCase.parameterize(
CinderUtilsQoSTests, os_creds=os_creds,
ext_net_name=ext_net_name, log_level=log_level,
image_metadata=image_metadata))
@@ -503,6 +511,11 @@ def add_openstack_integration_tests(suite, os_creds, ext_net_name,
flavor_metadata=flavor_metadata, image_metadata=image_metadata,
log_level=log_level))
suite.addTest(OSIntegrationTestCase.parameterize(
+ CreateStackVolumeTests, os_creds=os_creds, ext_net_name=ext_net_name,
+ use_keystone=use_keystone,
+ flavor_metadata=flavor_metadata, image_metadata=image_metadata,
+ log_level=log_level))
+ suite.addTest(OSIntegrationTestCase.parameterize(
CreateStackNegativeTests, os_creds=os_creds, ext_net_name=ext_net_name,
use_keystone=use_keystone,
flavor_metadata=flavor_metadata, image_metadata=image_metadata,
@@ -515,7 +528,7 @@ def add_openstack_integration_tests(suite, os_creds, ext_net_name,
flavor_metadata=flavor_metadata, image_metadata=image_metadata,
log_level=log_level))
suite.addTest(OSIntegrationTestCase.parameterize(
- CreateComplexStackTests, os_creds=os_creds,
+ CreateStackFloatingIpTests, os_creds=os_creds,
ext_net_name=ext_net_name, use_keystone=use_keystone,
flavor_metadata=flavor_metadata, image_metadata=image_metadata,
log_level=log_level))