From dc24c3d90a7a3068256381d815c689b3f243707f Mon Sep 17 00:00:00 2001 From: spisarski Date: Mon, 31 Jul 2017 12:26:19 -0600 Subject: Changed heat_utils#get_stack_by_name to get_stack. Added stack_settings parameter to allow for more robust queries based on the known settings as required. JIRA: SNAPS-158 Change-Id: I538826f822307365b1afe997b71280b9ea500eab Signed-off-by: spisarski --- snaps/domain/stack.py | 4 + snaps/openstack/create_stack.py | 11 +- snaps/openstack/utils/heat_utils.py | 22 ++-- snaps/openstack/utils/tests/heat_utils_tests.py | 133 ++++++++++++++++++++---- 4 files changed, 142 insertions(+), 28 deletions(-) diff --git a/snaps/domain/stack.py b/snaps/domain/stack.py index eaa45b3..0302184 100644 --- a/snaps/domain/stack.py +++ b/snaps/domain/stack.py @@ -27,3 +27,7 @@ class Stack: """ self.name = name self.id = stack_id + + def __eq__(self, other): + return (self.name == other.name and + self.id == other.id) diff --git a/snaps/openstack/create_stack.py b/snaps/openstack/create_stack.py index cb06e8a..41cc725 100644 --- a/snaps/openstack/create_stack.py +++ b/snaps/openstack/create_stack.py @@ -55,8 +55,8 @@ class OpenStackHeatStack: :return: The OpenStack Stack object """ self.__heat_cli = heat_utils.heat_client(self.__os_creds) - self.__stack = heat_utils.get_stack_by_name(self.__heat_cli, - self.stack_settings.name) + self.__stack = heat_utils.get_stack( + self.__heat_cli, stack_settings=self.stack_settings) if self.__stack: logger.info('Found stack with name - ' + self.stack_settings.name) return self.__stack @@ -215,6 +215,13 @@ class StackSettings: if not self.template and not self.template_path: raise StackSettingsError('A Heat template is required') + def __eq__(self, other): + return (self.name == other.name and + self.template == other.template and + self.template_path == other.template_path and + self.env_values == other.env_values and + self.stack_create_timeout == other.stack_create_timeout) + class StackSettingsError(Exception): """ diff --git a/snaps/openstack/utils/heat_utils.py b/snaps/openstack/utils/heat_utils.py index ae367a0..a91a21c 100644 --- a/snaps/openstack/utils/heat_utils.py +++ b/snaps/openstack/utils/heat_utils.py @@ -41,19 +41,29 @@ def heat_client(os_creds): region_name=os_creds.region_name) -def get_stack_by_name(heat_cli, stack_name): +def get_stack(heat_cli, stack_settings=None, stack_name=None): """ - Returns a domain Stack object + Returns the first domain Stack object found. When stack_setting + is not None, the filter created will take the name attribute. When + stack_settings is None and stack_name is not, stack_name will be used + instead. When both are None, the first stack object received will be + returned, else None :param heat_cli: the OpenStack heat client - :param stack_name: the name of the heat stack + :param stack_settings: a StackSettings object + :param stack_name: the name of the heat stack to return :return: the Stack domain object else None """ - stacks = heat_cli.stacks.list(**{'name': stack_name}) + + stack_filter = dict() + if stack_settings: + stack_filter['stack_name'] = stack_settings.name + elif stack_name: + stack_filter['stack_name'] = stack_name + + stacks = heat_cli.stacks.list(**stack_filter) for stack in stacks: return Stack(name=stack.identifier, stack_id=stack.id) - return None - def get_stack_by_id(heat_cli, stack_id): """ diff --git a/snaps/openstack/utils/tests/heat_utils_tests.py b/snaps/openstack/utils/tests/heat_utils_tests.py index dda1111..90cc934 100644 --- a/snaps/openstack/utils/tests/heat_utils_tests.py +++ b/snaps/openstack/utils/tests/heat_utils_tests.py @@ -34,7 +34,7 @@ logger = logging.getLogger('nova_utils_tests') class HeatSmokeTests(OSComponentTestCase): """ - Tests to ensure that the nova client can communicate with the cloud + Tests to ensure that the heat client can communicate with the cloud """ def test_nova_connect_success(self): @@ -69,16 +69,16 @@ class HeatSmokeTests(OSComponentTestCase): class HeatUtilsCreateStackTests(OSComponentTestCase): """ - Test basic nova keypair functionality + Test basic Heat functionality """ def setUp(self): """ - Instantiates the CreateImage object that is responsible for downloading - and creating an OS image file within OpenStack + Instantiates OpenStack instances that cannot be spawned by Heat """ guid = self.__class__.__name__ + '-' + str(uuid.uuid4()) - stack_name = self.__class__.__name__ + '-' + str(guid) + '-stack' + stack_name1 = self.__class__.__name__ + '-' + str(guid) + '-stack1' + stack_name2 = self.__class__.__name__ + '-' + str(guid) + '-stack2' self.image_creator = OpenStackImage( self.os_creds, openstack_tests.cirros_image_settings( @@ -96,19 +96,29 @@ class HeatUtilsCreateStackTests(OSComponentTestCase): 'flavor_name': self.flavor_creator.flavor_settings.name} heat_tmplt_path = pkg_resources.resource_filename( 'snaps.openstack.tests.heat', 'test_heat_template.yaml') - self.stack_settings = StackSettings( - name=stack_name, template_path=heat_tmplt_path, + self.stack_settings1 = StackSettings( + name=stack_name1, template_path=heat_tmplt_path, env_values=env_values) - self.stack = None + self.stack_settings2 = StackSettings( + name=stack_name2, template_path=heat_tmplt_path, + env_values=env_values) + self.stack1 = None + self.stack2 = None self.heat_client = heat_utils.heat_client(self.os_creds) def tearDown(self): """ Cleans the image and downloaded image file """ - if self.stack: + if self.stack1: try: - heat_utils.delete_stack(self.heat_client, self.stack) + heat_utils.delete_stack(self.heat_client, self.stack1) + except: + pass + + if self.stack2: + try: + heat_utils.delete_stack(self.heat_client, self.stack2) except: pass @@ -125,21 +135,104 @@ class HeatUtilsCreateStackTests(OSComponentTestCase): pass def test_create_stack(self): + """ + Tests the creation of an OpenStack Heat stack1 that does not exist. + """ + self.stack1 = heat_utils.create_stack(self.heat_client, + self.stack_settings1) + + stack_query_1 = heat_utils.get_stack( + self.heat_client, stack_settings=self.stack_settings1) + self.assertEqual(self.stack1, stack_query_1) + + stack_query_2 = heat_utils.get_stack( + self.heat_client, stack_name=self.stack_settings1.name) + self.assertEqual(self.stack1, stack_query_2) + + stack_query_3 = heat_utils.get_stack_by_id(self.heat_client, + self.stack1.id) + self.assertEqual(self.stack1, stack_query_3) + + outputs = heat_utils.get_stack_outputs( + self.heat_client, self.stack1.id) + self.assertIsNotNone(outputs) + self.assertEqual(0, len(outputs)) + + 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) + + def test_create_stack_x2(self): """ Tests the creation of an OpenStack keypair that does not exist. """ - self.stack = heat_utils.create_stack(self.heat_client, - self.stack_settings) + self.stack1 = heat_utils.create_stack(self.heat_client, + self.stack_settings1) + + stack1_query_1 = heat_utils.get_stack( + self.heat_client, stack_settings=self.stack_settings1) + self.assertEqual(self.stack1, stack1_query_1) + + stack1_query_2 = heat_utils.get_stack( + self.heat_client, stack_name=self.stack_settings1.name) + self.assertEqual(self.stack1, stack1_query_2) + + stack1_query_3 = heat_utils.get_stack_by_id(self.heat_client, + self.stack1.id) + self.assertEqual(self.stack1, stack1_query_3) + + outputs = heat_utils.get_stack_outputs(self.heat_client, + self.stack1.id) + self.assertIsNotNone(outputs) + self.assertEqual(0, len(outputs)) + + 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.stack2 = heat_utils.create_stack(self.heat_client, + self.stack_settings2) + + stack2_query_1 = heat_utils.get_stack( + self.heat_client, stack_settings=self.stack_settings2) + self.assertEqual(self.stack2, stack2_query_1) - stack_query_1 = heat_utils.get_stack_by_name(self.heat_client, - self.stack_settings.name) - self.assertEqual(self.stack.id, stack_query_1.id) + stack2_query_2 = heat_utils.get_stack( + self.heat_client, stack_name=self.stack_settings2.name) + self.assertEqual(self.stack2, stack2_query_2) - stack_query_2 = heat_utils.get_stack_by_id(self.heat_client, - self.stack.id) - self.assertEqual(self.stack.id, stack_query_2.id) + stack2_query_3 = heat_utils.get_stack_by_id(self.heat_client, + self.stack2.id) + self.assertEqual(self.stack2, stack2_query_3) - outputs = heat_utils.get_stack_outputs(self.heat_client, self.stack.id) + outputs = heat_utils.get_stack_outputs(self.heat_client, + self.stack2.id) self.assertIsNotNone(outputs) self.assertEqual(0, len(outputs)) @@ -148,7 +241,7 @@ class HeatUtilsCreateStackTests(OSComponentTestCase): is_active = False while time.time() < end_time: status = heat_utils.get_stack_status(self.heat_client, - self.stack.id) + self.stack2.id) if status == create_stack.STATUS_CREATE_COMPLETE: is_active = True break -- cgit 1.2.3-korg