summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorspisarski <s.pisarski@cablelabs.com>2017-10-30 12:08:58 -0600
committerspisarski <s.pisarski@cablelabs.com>2017-10-30 12:08:58 -0600
commit85eb362579efbbc57e2851b2da2fd9599461f1ae (patch)
tree42c3552eca410e5e7023b1339cb64ea42009a7c7
parent0dfca494ef7c2778babfac48d9b701953860b54f (diff)
Added method to OpenStackHeatStack to return OpenStackKeypair objects.
Continuation of the story SNAPS-153 for adding creator/state machine instances for OpenStack objects deployed via Heat. JIRA: SNAPS-175 Change-Id: I7196279086b1935b4ec4a01483d46921cc567b15 Signed-off-by: spisarski <s.pisarski@cablelabs.com>
-rw-r--r--docs/how-to-use/APITests.rst13
-rw-r--r--docs/how-to-use/IntegrationTests.rst11
-rw-r--r--snaps/openstack/create_stack.py29
-rw-r--r--snaps/openstack/tests/create_stack_tests.py76
-rw-r--r--snaps/openstack/tests/heat/keypair_heat_template.yaml39
-rw-r--r--snaps/openstack/utils/heat_utils.py26
-rw-r--r--snaps/openstack/utils/nova_utils.py12
-rw-r--r--snaps/openstack/utils/settings_utils.py26
-rw-r--r--snaps/openstack/utils/tests/heat_utils_tests.py173
-rw-r--r--snaps/test_suite_builder.py15
10 files changed, 334 insertions, 86 deletions
diff --git a/docs/how-to-use/APITests.rst b/docs/how-to-use/APITests.rst
index fbd7e67..9110162 100644
--- a/docs/how-to-use/APITests.rst
+++ b/docs/how-to-use/APITests.rst
@@ -454,7 +454,7 @@ 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 |
+| | | heat_utils.create_stack() to return the correct |
| | | Volume domain objects deployed with Heat |
+---------------------------------------+---------------+-----------------------------------------------------------+
| test_create_vol_types_with_stack | 1 | Tests ability of the function |
@@ -462,6 +462,17 @@ heat_utils_tests.py - HeatUtilsVolumeTests
| | | VolumeType domain objects deployed with Heat |
+---------------------------------------+---------------+-----------------------------------------------------------+
+heat_utils_tests.py - HeatUtilsKeypairTests
+-------------------------------------------
+
++---------------------------------------+---------------+-----------------------------------------------------------+
+| Test Name | Heat API | Description |
++=======================================+===============+===========================================================+
+| test_create_keypair_with_stack | 1 | Tests ability of the function |
+| | | heat_utils.create_stack() to return the correct |
+| | | Keypair 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 538c9c0..e00bc40 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 - CreateStackKeypairTests
+-----------------------------------------------
+
++---------------------------------------+---------------+-----------------------------------------------------------+
+| Test Name | Heat API | Description |
++=======================================+===============+===========================================================+
+| test_retrieve_keypair_creator | 1 | Ensures that an OpenStackHeatStack instance can return a |
+| | | OpenStackKeypair instance that it was responsible for |
+| | | deploying |
++---------------------------------------+---------------+-----------------------------------------------------------+
+
create_stack_tests.py - CreateComplexStackTests
-----------------------------------------------
diff --git a/snaps/openstack/create_stack.py b/snaps/openstack/create_stack.py
index d8f9d15..b565118 100644
--- a/snaps/openstack/create_stack.py
+++ b/snaps/openstack/create_stack.py
@@ -19,6 +19,7 @@ import time
from heatclient.exc import HTTPNotFound
from snaps.openstack.create_instance import OpenStackVmInstance
+from snaps.openstack.create_keypairs import OpenStackKeypair
from snaps.openstack.create_volume import OpenStackVolume
from snaps.openstack.create_volume_type import OpenStackVolumeType
from snaps.openstack.openstack_creator import OpenStackCloudObject
@@ -318,6 +319,34 @@ class OpenStackHeatStack(OpenStackCloudObject, object):
return out
+ def get_keypair_creators(self, outputs_pk_key=None):
+ """
+ Returns a list of keypair creator objects as configured by the heat
+ template
+ :return: list() of OpenStackKeypair objects
+ """
+
+ out = list()
+ nova = nova_utils.nova_client(self._os_creds)
+
+ keypairs = heat_utils.get_stack_keypairs(
+ self.__heat_cli, nova, self.__stack)
+
+ for keypair in keypairs:
+ settings = settings_utils.create_keypair_settings(
+ self.__heat_cli, self.__stack, keypair, outputs_pk_key)
+ creator = OpenStackKeypair(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 a2b2215..8f9339a 100644
--- a/snaps/openstack/tests/create_stack_tests.py
+++ b/snaps/openstack/tests/create_stack_tests.py
@@ -495,7 +495,7 @@ class CreateStackFloatingIpTests(OSIntegrationTestCase):
class CreateStackVolumeTests(OSIntegrationTestCase):
"""
- Tests for the CreateStack class defined in create_stack.py
+ Tests for the CreateStack class as they pertain to volumes
"""
def setUp(self):
@@ -589,6 +589,80 @@ class CreateStackVolumeTests(OSIntegrationTestCase):
self.assertEqual(volume_type.id, encryption.volume_type_id)
+class CreateStackKeypairTests(OSIntegrationTestCase):
+ """
+ Tests for the CreateStack class as they pertain to keypairs
+ """
+
+ 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.nova = nova_utils.nova_client(self.heat_creds)
+ self.stack_creator = None
+
+ self.keypair_name = self.guid + '-kp'
+
+ self.env_values = {
+ 'keypair_name': self.keypair_name}
+
+ self.heat_tmplt_path = pkg_resources.resource_filename(
+ 'snaps.openstack.tests.heat', 'keypair_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_keypair_creator(self):
+ """
+ Tests the creation of an OpenStack stack from Heat template file and
+ the retrieval of an OpenStackKeypair creator/state machine instance
+ """
+ kp_creators = self.stack_creator.get_keypair_creators('private_key')
+ self.assertEqual(1, len(kp_creators))
+
+ creator = kp_creators[0]
+
+ self.assertEqual(self.keypair_name, creator.get_keypair().name)
+ self.assertIsNotNone(creator.keypair_settings.private_filepath)
+
+ private_file_contents = file_utils.read_file(
+ creator.keypair_settings.private_filepath)
+ self.assertTrue(private_file_contents.startswith(
+ '-----BEGIN RSA PRIVATE KEY-----'))
+
+ keypair = nova_utils.get_keypair_by_id(
+ self.nova, creator.get_keypair().id)
+ self.assertIsNotNone(keypair)
+ self.assertEqual(creator.get_keypair(), keypair)
+
+
class CreateStackNegativeTests(OSIntegrationTestCase):
"""
Negative test cases for the CreateStack class
diff --git a/snaps/openstack/tests/heat/keypair_heat_template.yaml b/snaps/openstack/tests/heat/keypair_heat_template.yaml
new file mode 100644
index 0000000..ffb8892
--- /dev/null
+++ b/snaps/openstack/tests/heat/keypair_heat_template.yaml
@@ -0,0 +1,39 @@
+##############################################################################
+# 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: >
+ Test template that simply deploys a keypair with a generated key
+
+parameters:
+ keypair_name:
+ type: string
+ label: Keypair name
+ description: The name of the stack's keypair
+ default: keypair_name
+
+resources:
+ keypair:
+ type: OS::Nova::KeyPair
+ properties:
+ name: { get_param: keypair_name }
+ save_private_key: True
+
+outputs:
+ private_key:
+ description: "SSH Private Key"
+ value: { get_attr: [ keypair, private_key ]}
diff --git a/snaps/openstack/utils/heat_utils.py b/snaps/openstack/utils/heat_utils.py
index f2d4efd..f09857a 100644
--- a/snaps/openstack/utils/heat_utils.py
+++ b/snaps/openstack/utils/heat_utils.py
@@ -227,9 +227,31 @@ def get_stack_servers(heat_cli, nova, stack):
return out
+def get_stack_keypairs(heat_cli, nova, stack):
+ """
+ Returns a list of Keypair 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 VMInst domain objects
+ """
+
+ out = list()
+ resources = get_resources(heat_cli, stack, 'OS::Nova::KeyPair')
+ for resource in resources:
+ try:
+ keypair = nova_utils.get_keypair_by_id(nova, resource.id)
+ if keypair:
+ out.append(keypair)
+ except NotFound:
+ logger.warn('Keypair 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
+ Returns an instance of Volume domain objects created 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
@@ -251,7 +273,7 @@ def get_stack_volumes(heat_cli, cinder, stack):
def get_stack_volume_types(heat_cli, cinder, stack):
"""
- Returns an instance of NetworkSettings for each network owned by this stack
+ Returns an instance of VolumeType domain objects created 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
diff --git a/snaps/openstack/utils/nova_utils.py b/snaps/openstack/utils/nova_utils.py
index 42b7356..0820289 100644
--- a/snaps/openstack/utils/nova_utils.py
+++ b/snaps/openstack/utils/nova_utils.py
@@ -419,6 +419,18 @@ def get_keypair_by_name(nova, name):
return None
+def get_keypair_by_id(nova, kp_id):
+ """
+ Returns a list of all available keypairs
+ :param nova: the Nova client
+ :param kp_id: the ID of the keypair to return
+ :return: the keypair object
+ """
+ keypair = nova.keypairs.get(kp_id)
+ return Keypair(name=keypair.name, kp_id=keypair.id,
+ public_key=keypair.public_key)
+
+
def delete_keypair(nova, key):
"""
Deletes a keypair object from OpenStack
diff --git a/snaps/openstack/utils/settings_utils.py b/snaps/openstack/utils/settings_utils.py
index 7169319..68dbf71 100644
--- a/snaps/openstack/utils/settings_utils.py
+++ b/snaps/openstack/utils/settings_utils.py
@@ -109,6 +109,32 @@ def create_volume_type_settings(volume_type):
qos_spec_name=qos_spec_name, public=volume_type.public)
+def create_keypair_settings(heat_cli, stack, keypair, pk_output_key):
+ """
+ Instantiates a KeypairSettings object from a Keypair domain objects
+ :param heat_cli: the heat client
+ :param stack: the Stack domain object
+ :param keypair: the Keypair SNAPS domain object
+ :param pk_output_key: the key to the heat template's outputs for retrieval
+ of the private key file
+ :return: a KeypairSettings object
+ """
+ if pk_output_key:
+ outputs = heat_utils.get_outputs(heat_cli, stack)
+ for output in outputs:
+ if output.key == pk_output_key:
+ # Save to file
+ guid = uuid.uuid4()
+ key_file = file_utils.save_string_to_file(
+ output.value, str(guid), 0o400)
+
+ # Use outputs, file and resources for the KeypairSettings
+ return KeypairSettings(
+ name=keypair.name, private_filepath=key_file.name)
+
+ return KeypairSettings(name=keypair.name)
+
+
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 4f58613..b021701 100644
--- a/snaps/openstack/utils/tests/heat_utils_tests.py
+++ b/snaps/openstack/utils/tests/heat_utils_tests.py
@@ -169,22 +169,7 @@ class HeatUtilsCreateSimpleStackTests(OSComponentTestCase):
self.assertIsNotNone(outputs)
self.assertEqual(0, len(outputs))
- # 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.stack1.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.stack1))
neutron = neutron_utils.neutron_client(self.os_creds)
networks = heat_utils.get_stack_networks(
@@ -223,21 +208,7 @@ class HeatUtilsCreateSimpleStackTests(OSComponentTestCase):
self.stack1.id)
self.assertEqual(self.stack1, stack1_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.stack1.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.stack1))
self.stack2 = heat_utils.create_stack(self.heat_client,
self.stack_settings2)
@@ -319,21 +290,7 @@ class HeatUtilsCreateComplexStackTests(OSComponentTestCase):
self.heat_client = heat_utils.heat_client(self.os_creds)
self.stack = heat_utils.create_stack(self.heat_client, 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)
+ self.assertTrue(stack_active(self.heat_client, self.stack))
def tearDown(self):
"""
@@ -506,23 +463,7 @@ class HeatUtilsVolumeTests(OSComponentTestCase):
"""
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)
+ self.assertTrue(stack_active(self.heat_client, self.stack))
volumes = heat_utils.get_stack_volumes(
self.heat_client, self.cinder, self.stack)
@@ -541,23 +482,7 @@ class HeatUtilsVolumeTests(OSComponentTestCase):
"""
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)
+ self.assertTrue(stack_active(self.heat_client, self.stack))
volume_types = heat_utils.get_stack_volume_types(
self.heat_client, self.cinder, self.stack)
@@ -578,3 +503,91 @@ class HeatUtilsVolumeTests(OSComponentTestCase):
self.assertEqual(u'nova.volume.encryptors.luks.LuksEncryptor',
encryption.provider)
self.assertEqual(volume_type.id, encryption.volume_type_id)
+
+
+class HeatUtilsKeypairTests(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.keypair_name = guid + '-kp'
+
+ env_values = {
+ 'keypair_name': self.keypair_name}
+
+ heat_tmplt_path = pkg_resources.resource_filename(
+ 'snaps.openstack.tests.heat', 'keypair_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.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_keypair_with_stack(self):
+ """
+ Tests the creation of an OpenStack keypair with Heat.
+ """
+ self.stack = heat_utils.create_stack(
+ self.heat_client, self.stack_settings)
+ self.assertTrue(stack_active(self.heat_client, self.stack))
+
+ keypairs = heat_utils.get_stack_keypairs(
+ self.heat_client, self.nova, self.stack)
+
+ self.assertEqual(1, len(keypairs))
+ keypair = keypairs[0]
+
+ self.assertEqual(self.keypair_name, keypair.name)
+
+ outputs = heat_utils.get_outputs(self.heat_client, self.stack)
+
+ for output in outputs:
+ if output.key == 'private_key':
+ self.assertTrue(output.value.startswith(
+ '-----BEGIN RSA PRIVATE KEY-----'))
+
+ keypair = nova_utils.get_keypair_by_id(self.nova, keypair.id)
+ self.assertIsNotNone(keypair)
+
+ self.assertEqual(self.keypair_name, keypair.name)
+
+
+def stack_active(heat_cli, stack):
+ """
+ Blocks until stack application has successfully completed or failed
+ :param heat_cli: the Heat client
+ :param stack: the Stack domain object
+ :return: T/F
+ """
+ # 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(heat_cli, 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)
+
+ return is_active
diff --git a/snaps/test_suite_builder.py b/snaps/test_suite_builder.py
index 77a8a2a..1795a52 100644
--- a/snaps/test_suite_builder.py
+++ b/snaps/test_suite_builder.py
@@ -68,7 +68,8 @@ from snaps.openstack.tests.create_security_group_tests import (
SecurityGroupSettingsUnitTests)
from snaps.openstack.tests.create_stack_tests import (
StackSettingsUnitTests, CreateStackSuccessTests, CreateStackNegativeTests,
- CreateStackFloatingIpTests, CreateStackVolumeTests)
+ CreateStackFloatingIpTests, CreateStackKeypairTests,
+ CreateStackVolumeTests)
from snaps.openstack.tests.create_user_tests import (
UserSettingsUnitTests, CreateUserSuccessTests)
from snaps.openstack.tests.create_volume_tests import (
@@ -88,7 +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)
+ HeatUtilsCreateComplexStackTests, HeatUtilsVolumeTests,
+ HeatUtilsKeypairTests)
from snaps.openstack.utils.tests.keystone_utils_tests import (
KeystoneSmokeTests, KeystoneUtilsTests)
from snaps.openstack.utils.tests.neutron_utils_tests import (
@@ -330,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(
+ HeatUtilsKeypairTests, 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))
@@ -516,6 +522,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(
+ CreateStackKeypairTests, 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,