summaryrefslogtreecommitdiffstats
path: root/snaps/openstack
diff options
context:
space:
mode:
Diffstat (limited to 'snaps/openstack')
-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
9 files changed, 228 insertions, 19 deletions
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)