summaryrefslogtreecommitdiffstats
path: root/snaps/openstack/utils
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 /snaps/openstack/utils
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>
Diffstat (limited to 'snaps/openstack/utils')
-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
4 files changed, 155 insertions, 82 deletions
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