summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorspisarski <s.pisarski@cablelabs.com>2017-10-30 14:22:20 -0600
committerspisarski <s.pisarski@cablelabs.com>2017-10-31 07:57:06 -0600
commitb20a368daa581e3f649ac5a772da31cd09fdb484 (patch)
treeedda6bab9d5918b7a989d4bf6425069094e1d625
parent85eb362579efbbc57e2851b2da2fd9599461f1ae (diff)
Added method to OpenStackHeatStack to return OpenStackFlavor objects.
Continuation of the story SNAPS-153 for adding creator/state machine instances for OpenStack objects deployed via Heat. JIRA: SNAPS-174 Change-Id: I791e427efc487045c0f72cd836dabd9a66a4f60f Signed-off-by: spisarski <s.pisarski@cablelabs.com>
-rw-r--r--docs/how-to-use/APITests.rst11
-rw-r--r--docs/how-to-use/IntegrationTests.rst11
-rw-r--r--docs/how-to-use/UnitTests.rst9
-rw-r--r--snaps/domain/flavor.py11
-rw-r--r--snaps/openstack/create_stack.py27
-rw-r--r--snaps/openstack/tests/create_flavor_tests.py2
-rw-r--r--snaps/openstack/tests/create_stack_tests.py62
-rw-r--r--snaps/openstack/tests/heat/flavor_heat_template.yaml27
-rw-r--r--snaps/openstack/utils/heat_utils.py23
-rw-r--r--snaps/openstack/utils/keystone_utils.py2
-rw-r--r--snaps/openstack/utils/settings_utils.py13
-rw-r--r--snaps/openstack/utils/tests/heat_utils_tests.py73
-rw-r--r--snaps/openstack/utils/tests/settings_utils_tests.py18
-rw-r--r--snaps/test_suite_builder.py21
14 files changed, 280 insertions, 30 deletions
diff --git a/docs/how-to-use/APITests.rst b/docs/how-to-use/APITests.rst
index 9110162..ed4779a 100644
--- a/docs/how-to-use/APITests.rst
+++ b/docs/how-to-use/APITests.rst
@@ -473,6 +473,17 @@ heat_utils_tests.py - HeatUtilsKeypairTests
| | | Keypair domain objects deployed with Heat |
+---------------------------------------+---------------+-----------------------------------------------------------+
+heat_utils_tests.py - HeatUtilsFlavorTests
+------------------------------------------
+
++---------------------------------------+---------------+-----------------------------------------------------------+
+| Test Name | Heat API | Description |
++=======================================+===============+===========================================================+
+| test_create_flavor_with_stack | 1 | Tests ability of the function |
+| | | heat_utils.get_stack_flavors() to return the correct |
+| | | Flavor 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 e00bc40..4772357 100644
--- a/docs/how-to-use/IntegrationTests.rst
+++ b/docs/how-to-use/IntegrationTests.rst
@@ -396,6 +396,17 @@ create_stack_tests.py - CreateStackVolumeTests
| | | deploying |
+---------------------------------------+---------------+-----------------------------------------------------------+
+create_stack_tests.py - CreateStackFlavorTests
+----------------------------------------------
+
++---------------------------------------+---------------+-----------------------------------------------------------+
+| Test Name | Heat API | Description |
++=======================================+===============+===========================================================+
+| test_retrieve_flavor_creator | 1 | Ensures that an OpenStackHeatStack instance can return a |
+| | | OpenStackFlavor instance that it was responsible for |
+| | | deploying |
++---------------------------------------+---------------+-----------------------------------------------------------+
+
create_stack_tests.py - CreateStackKeypairTests
-----------------------------------------------
diff --git a/docs/how-to-use/UnitTests.rst b/docs/how-to-use/UnitTests.rst
index 3cb26db..4a360d4 100644
--- a/docs/how-to-use/UnitTests.rst
+++ b/docs/how-to-use/UnitTests.rst
@@ -294,11 +294,16 @@ VmInstDomainObjectTests
Ensures that all required members are included when constructing a
VmInst domain object
-SettingsUtilsVolumeTests
-------------------------
+SettingsUtilsUnitTests
+----------------------
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
+
+
+Ensures that the settings_utils.py#create_flavor_settings() function properly
+maps a snaps.domain.Flavor object correctly to a
+snaps.openstack.create_flavor.FlavorSettings object \ No newline at end of file
diff --git a/snaps/domain/flavor.py b/snaps/domain/flavor.py
index 035ca64..bf84cf4 100644
--- a/snaps/domain/flavor.py
+++ b/snaps/domain/flavor.py
@@ -23,7 +23,7 @@ class Flavor:
"""
Constructor
:param name: the flavor's name
- :param flavor_id: the flavor's id
+ :param flavor_id or id: the flavor's id
:param ram: the flavor's RAM in MB
:param disk: the flavor's disk size in GB
:param vcpus: the flavor's number of virtual CPUs
@@ -33,11 +33,16 @@ class Flavor:
:param is_public: denotes if flavor can be used by other projects
"""
self.name = kwargs.get('name')
- self.id = kwargs.get('id')
+ self.id = kwargs.get('flavor_id', kwargs.get('id'))
self.ram = kwargs.get('ram')
self.disk = kwargs.get('disk')
self.vcpus = kwargs.get('vcpus')
self.ephemeral = kwargs.get('ephemeral')
- self.swap = kwargs.get('swap')
+
+ if kwargs.get('swap'):
+ self.swap = int(kwargs.get('swap'))
+ else:
+ self.swap = None
+
self.rxtx_factor = kwargs.get('rxtx_factor')
self.is_public = kwargs.get('is_public')
diff --git a/snaps/openstack/create_stack.py b/snaps/openstack/create_stack.py
index b565118..1820e2a 100644
--- a/snaps/openstack/create_stack.py
+++ b/snaps/openstack/create_stack.py
@@ -18,6 +18,7 @@ import time
from heatclient.exc import HTTPNotFound
+from snaps.openstack.create_flavor import OpenStackFlavor
from snaps.openstack.create_instance import OpenStackVmInstance
from snaps.openstack.create_keypairs import OpenStackKeypair
from snaps.openstack.create_volume import OpenStackVolume
@@ -347,6 +348,32 @@ class OpenStackHeatStack(OpenStackCloudObject, object):
return out
+ def get_flavor_creators(self):
+ """
+ Returns a list of Flavor creator objects as configured by the heat
+ template
+ :return: list() of OpenStackFlavor objects
+ """
+
+ out = list()
+ nova = nova_utils.nova_client(self._os_creds)
+
+ flavors = heat_utils.get_stack_flavors(
+ self.__heat_cli, nova, self.__stack)
+
+ for flavor in flavors:
+ settings = settings_utils.create_flavor_settings(flavor)
+ creator = OpenStackFlavor(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 _stack_status_check(self, expected_status_code, block, timeout,
poll_interval, fail_status):
"""
diff --git a/snaps/openstack/tests/create_flavor_tests.py b/snaps/openstack/tests/create_flavor_tests.py
index 4852d06..3eb07bd 100644
--- a/snaps/openstack/tests/create_flavor_tests.py
+++ b/snaps/openstack/tests/create_flavor_tests.py
@@ -399,7 +399,7 @@ def validate_flavor(nova, flavor_settings, flavor):
equals = False
break
- swap = str()
+ swap = None
if flavor_settings.swap != 0:
swap = flavor_settings.swap
diff --git a/snaps/openstack/tests/create_stack_tests.py b/snaps/openstack/tests/create_stack_tests.py
index 8f9339a..94085a0 100644
--- a/snaps/openstack/tests/create_stack_tests.py
+++ b/snaps/openstack/tests/create_stack_tests.py
@@ -589,6 +589,68 @@ class CreateStackVolumeTests(OSIntegrationTestCase):
self.assertEqual(volume_type.id, encryption.volume_type_id)
+class CreateStackFlavorTests(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.heat_tmplt_path = pkg_resources.resource_filename(
+ 'snaps.openstack.tests.heat', 'flavor_heat_template.yaml')
+
+ stack_settings = StackSettings(
+ name=self.guid + '-stack',
+ template_path=self.heat_tmplt_path)
+ 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_flavor_creator(self):
+ """
+ Tests the creation of an OpenStack stack from Heat template file and
+ the retrieval of an OpenStackVolume creator/state machine instance
+ """
+ flavor_creators = self.stack_creator.get_flavor_creators()
+ self.assertEqual(1, len(flavor_creators))
+
+ creator = flavor_creators[0]
+ self.assertTrue(creator.get_flavor().name.startswith(self.guid))
+ self.assertEqual(1024, creator.get_flavor().ram)
+ self.assertEqual(200, creator.get_flavor().disk)
+ self.assertEqual(8, creator.get_flavor().vcpus)
+ self.assertEqual(0, creator.get_flavor().ephemeral)
+ self.assertIsNone(creator.get_flavor().swap)
+ self.assertEqual(1.0, creator.get_flavor().rxtx_factor)
+ self.assertTrue(creator.get_flavor().is_public)
+
+
class CreateStackKeypairTests(OSIntegrationTestCase):
"""
Tests for the CreateStack class as they pertain to keypairs
diff --git a/snaps/openstack/tests/heat/flavor_heat_template.yaml b/snaps/openstack/tests/heat/flavor_heat_template.yaml
new file mode 100644
index 0000000..060c85c
--- /dev/null
+++ b/snaps/openstack/tests/heat/flavor_heat_template.yaml
@@ -0,0 +1,27 @@
+##############################################################################
+# 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
+
+resources:
+ flavor:
+ type: OS::Nova::Flavor
+ properties:
+ ram: 1024
+ vcpus: 8
+ disk: 200
diff --git a/snaps/openstack/utils/heat_utils.py b/snaps/openstack/utils/heat_utils.py
index f09857a..ad354e0 100644
--- a/snaps/openstack/utils/heat_utils.py
+++ b/snaps/openstack/utils/heat_utils.py
@@ -293,6 +293,29 @@ def get_stack_volume_types(heat_cli, cinder, stack):
return out
+def get_stack_flavors(heat_cli, nova, stack):
+ """
+ Returns an instance of Flavor SNAPS domain object for each flavor created
+ by this stack
+ :param heat_cli: the OpenStack heat client object
+ :param nova: 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::Nova::Flavor')
+ for resource in resources:
+ try:
+ flavor = nova_utils.get_flavor_by_id(nova, resource.id)
+ if flavor:
+ out.append(flavor)
+ except NotFound:
+ logger.warn('Flavor cannot be located with ID %s', resource.id)
+
+ 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/keystone_utils.py b/snaps/openstack/utils/keystone_utils.py
index 46f6fb8..387f6c7 100644
--- a/snaps/openstack/utils/keystone_utils.py
+++ b/snaps/openstack/utils/keystone_utils.py
@@ -367,7 +367,7 @@ def grant_user_role_to_project(keystone, role, user, project):
"""
os_role = get_role_by_id(keystone, role.id)
- logger.info('Granting role %s to project %s', role.name, project)
+ logger.info('Granting role %s to project %s', role.name, project.name)
if keystone.version == V2_VERSION_STR:
keystone.roles.add_user_role(user, os_role, tenant=project)
else:
diff --git a/snaps/openstack/utils/settings_utils.py b/snaps/openstack/utils/settings_utils.py
index 68dbf71..2ab3c28 100644
--- a/snaps/openstack/utils/settings_utils.py
+++ b/snaps/openstack/utils/settings_utils.py
@@ -15,6 +15,7 @@
import uuid
from snaps import file_utils
+from snaps.openstack.create_flavor import FlavorSettings
from snaps.openstack.create_instance import (
VmInstanceSettings, FloatingIpSettings)
from snaps.openstack.create_keypairs import KeypairSettings
@@ -109,6 +110,18 @@ def create_volume_type_settings(volume_type):
qos_spec_name=qos_spec_name, public=volume_type.public)
+def create_flavor_settings(flavor):
+ """
+ Returns a VolumeSettings object
+ :param flavor: a SNAPS-OO Volume object
+ """
+ return FlavorSettings(
+ name=flavor.name, flavor_id=flavor.id, ram=flavor.ram,
+ disk=flavor.disk, vcpus=flavor.vcpus, ephemeral=flavor.ephemeral,
+ swap=flavor.swap, rxtx_factor=flavor.rxtx_factor,
+ is_public=flavor.is_public)
+
+
def create_keypair_settings(heat_cli, stack, keypair, pk_output_key):
"""
Instantiates a KeypairSettings object from a Keypair domain objects
diff --git a/snaps/openstack/utils/tests/heat_utils_tests.py b/snaps/openstack/utils/tests/heat_utils_tests.py
index b021701..567cf7b 100644
--- a/snaps/openstack/utils/tests/heat_utils_tests.py
+++ b/snaps/openstack/utils/tests/heat_utils_tests.py
@@ -225,22 +225,7 @@ class HeatUtilsCreateSimpleStackTests(OSComponentTestCase):
self.stack2.id)
self.assertEqual(self.stack2, stack2_query_3)
- 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.stack2.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)
+ self.assertTrue(stack_active(self.heat_client, self.stack2))
class HeatUtilsCreateComplexStackTests(OSComponentTestCase):
@@ -505,6 +490,62 @@ class HeatUtilsVolumeTests(OSComponentTestCase):
self.assertEqual(volume_type.id, encryption.volume_type_id)
+class HeatUtilsFlavorTests(OSComponentTestCase):
+ """
+ Test Heat volume functionality
+ """
+
+ def setUp(self):
+ """
+ Instantiates OpenStack instances that cannot be spawned by Heat
+ """
+ guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
+ self.name_prefix = guid
+ stack_name = guid + '-stack'
+
+ heat_tmplt_path = pkg_resources.resource_filename(
+ 'snaps.openstack.tests.heat', 'flavor_heat_template.yaml')
+ self.stack_settings = StackSettings(
+ name=stack_name, template_path=heat_tmplt_path)
+ self.stack = None
+ self.heat_client = heat_utils.heat_client(self.os_creds)
+ self.nova = nova_utils.nova_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_flavor_with_stack(self):
+ """
+ Tests the creation of an OpenStack volume with Heat.
+ """
+ self.stack = heat_utils.create_stack(
+ self.heat_client, self.stack_settings)
+
+ self.assertTrue(stack_active(self.heat_client, self.stack))
+
+ flavors = heat_utils.get_stack_flavors(
+ self.heat_client, self.nova, self.stack)
+
+ self.assertEqual(1, len(flavors))
+
+ flavor = flavors[0]
+ self.assertTrue(flavor.name.startswith(self.name_prefix))
+ self.assertEqual(1024, flavor.ram)
+ self.assertEqual(200, flavor.disk)
+ self.assertEqual(8, flavor.vcpus)
+ self.assertEqual(0, flavor.ephemeral)
+ self.assertIsNone(flavor.swap)
+ self.assertEqual(1.0, flavor.rxtx_factor)
+ self.assertTrue(flavor.is_public)
+
+
class HeatUtilsKeypairTests(OSComponentTestCase):
"""
Test Heat volume functionality
diff --git a/snaps/openstack/utils/tests/settings_utils_tests.py b/snaps/openstack/utils/tests/settings_utils_tests.py
index cb14039..69bdf7c 100644
--- a/snaps/openstack/utils/tests/settings_utils_tests.py
+++ b/snaps/openstack/utils/tests/settings_utils_tests.py
@@ -18,6 +18,7 @@ import unittest
import os
import uuid
+from snaps.domain.flavor import Flavor
from snaps.domain.volume import (
Volume, VolumeType, VolumeTypeEncryption, QoSSpec)
from snaps.openstack import (
@@ -346,7 +347,7 @@ class SettingsUtilsVmInstTests(OSComponentTestCase):
derived_image_settings.name)
-class SettingsUtilsVolumeTests(unittest.TestCase):
+class SettingsUtilsUnitTests(unittest.TestCase):
"""
Exercises the settings_utils.py functions around volumes
"""
@@ -386,3 +387,18 @@ class SettingsUtilsVolumeTests(unittest.TestCase):
self.assertEqual(encryption.key_size, encrypt_settings.key_size)
self.assertEqual(qos_spec.name, settings.qos_spec_name)
+
+ def test_flavor_settings_from_flavor(self):
+ flavor = Flavor(
+ name='flavor-name', flavor_id='flavor-id', ram=99, disk=101,
+ vcpus=9, ephemeral=3, swap=5, rxtx_factor=7, is_public=False)
+ settings = settings_utils.create_flavor_settings(flavor)
+ self.assertEqual(flavor.name, settings.name)
+ self.assertEqual(flavor.id, settings.flavor_id)
+ self.assertEqual(flavor.ram, settings.ram)
+ self.assertEqual(flavor.disk, settings.disk)
+ self.assertEqual(flavor.vcpus, settings.vcpus)
+ self.assertEqual(flavor.ephemeral, settings.ephemeral)
+ self.assertEqual(flavor.swap, settings.swap)
+ self.assertEqual(flavor.rxtx_factor, settings.rxtx_factor)
+ self.assertEqual(flavor.is_public, settings.is_public)
diff --git a/snaps/test_suite_builder.py b/snaps/test_suite_builder.py
index 1795a52..6d2ba5f 100644
--- a/snaps/test_suite_builder.py
+++ b/snaps/test_suite_builder.py
@@ -68,8 +68,8 @@ from snaps.openstack.tests.create_security_group_tests import (
SecurityGroupSettingsUnitTests)
from snaps.openstack.tests.create_stack_tests import (
StackSettingsUnitTests, CreateStackSuccessTests, CreateStackNegativeTests,
- CreateStackFloatingIpTests, CreateStackKeypairTests,
- CreateStackVolumeTests)
+ CreateStackFlavorTests, CreateStackFloatingIpTests,
+ CreateStackKeypairTests, CreateStackVolumeTests)
from snaps.openstack.tests.create_user_tests import (
UserSettingsUnitTests, CreateUserSuccessTests)
from snaps.openstack.tests.create_volume_tests import (
@@ -89,8 +89,8 @@ from snaps.openstack.utils.tests.glance_utils_tests import (
GlanceSmokeTests, GlanceUtilsTests)
from snaps.openstack.utils.tests.heat_utils_tests import (
HeatSmokeTests, HeatUtilsCreateSimpleStackTests,
- HeatUtilsCreateComplexStackTests, HeatUtilsVolumeTests,
- HeatUtilsKeypairTests)
+ HeatUtilsCreateComplexStackTests, HeatUtilsFlavorTests,
+ HeatUtilsKeypairTests, HeatUtilsVolumeTests)
from snaps.openstack.utils.tests.keystone_utils_tests import (
KeystoneSmokeTests, KeystoneUtilsTests)
from snaps.openstack.utils.tests.neutron_utils_tests import (
@@ -101,7 +101,7 @@ from snaps.openstack.utils.tests.nova_utils_tests import (
NovaSmokeTests, NovaUtilsKeypairTests, NovaUtilsFlavorTests,
NovaUtilsInstanceTests, NovaUtilsInstanceVolumeTests)
from snaps.openstack.utils.tests.settings_utils_tests import (
- SettingsUtilsVolumeTests)
+ SettingsUtilsUnitTests)
from snaps.provisioning.tests.ansible_utils_tests import (
AnsibleProvisioningTests)
from snaps.tests.file_utils_tests import FileUtilsTests
@@ -203,7 +203,7 @@ def add_unit_tests(suite):
suite.addTest(unittest.TestLoader().loadTestsFromTestCase(
VolumeSettingsUnitTests))
suite.addTest(unittest.TestLoader().loadTestsFromTestCase(
- SettingsUtilsVolumeTests))
+ SettingsUtilsUnitTests))
def add_openstack_client_tests(suite, os_creds, ext_net_name,
@@ -332,6 +332,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(
+ HeatUtilsFlavorTests, os_creds=os_creds,
+ ext_net_name=ext_net_name, log_level=log_level,
+ image_metadata=image_metadata))
+ suite.addTest(OSComponentTestCase.parameterize(
HeatUtilsKeypairTests, os_creds=os_creds,
ext_net_name=ext_net_name, log_level=log_level,
image_metadata=image_metadata))
@@ -522,6 +526,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(
+ CreateStackFlavorTests, 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(
CreateStackKeypairTests, os_creds=os_creds, ext_net_name=ext_net_name,
use_keystone=use_keystone,
flavor_metadata=flavor_metadata, image_metadata=image_metadata,