From 3c2924769969733632d22e128b48fccee0043069 Mon Sep 17 00:00:00 2001 From: Emma Foley Date: Mon, 19 Feb 2018 23:15:11 +0000 Subject: Add methods to get an existing stack * Add yardstick/orchestrator/heat.py:HeatStack.get * Add yardstick/benchmark/contexts/heay.py:HeatContext.retrieve_existing_stack JIRA: YARDSTICK-886 Change-Id: I6974b79a25f98066a49b1bc8ccd11383e7962091 Signed-off-by: Emma Foley --- yardstick/benchmark/contexts/heat.py | 9 +++ yardstick/orchestrator/heat.py | 27 ++++++-- yardstick/tests/unit/orchestrator/test_heat.py | 87 ++++++++++++++++++++++++++ 3 files changed, 118 insertions(+), 5 deletions(-) diff --git a/yardstick/benchmark/contexts/heat.py b/yardstick/benchmark/contexts/heat.py index be8815060..ed301a998 100644 --- a/yardstick/benchmark/contexts/heat.py +++ b/yardstick/benchmark/contexts/heat.py @@ -26,6 +26,7 @@ from yardstick.benchmark.contexts.model import Server from yardstick.benchmark.contexts.model import update_scheduler_hints from yardstick.common import exceptions as y_exc from yardstick.common.openstack_utils import get_neutron_client +from yardstick.orchestrator.heat import HeatStack from yardstick.orchestrator.heat import HeatTemplate from yardstick.common import constants as consts from yardstick.common.utils import source_env @@ -312,6 +313,14 @@ class HeatContext(Context): # let the other failures happen, we want stack trace raise + def _retrieve_existing_stack(self, stack_name): + stack = HeatStack(stack_name) + if stack.get(): + return stack + else: + LOG.warning("Stack %s does not exist", self.name) + return None + def deploy(self): """deploys template into a stack using cloud""" LOG.info("Deploying context '%s' START", self.name) diff --git a/yardstick/orchestrator/heat.py b/yardstick/orchestrator/heat.py index 403c7e8d9..78e9c3df2 100644 --- a/yardstick/orchestrator/heat.py +++ b/yardstick/orchestrator/heat.py @@ -44,6 +44,13 @@ class HeatStack(object): self._cloud = shade.openstack_cloud() self._stack = None + def _update_stack_tracking(self): + outputs = self._stack.outputs + self.outputs = {output['output_key']: output['output_value'] for output + in outputs} + if self.uuid: + _DEPLOYED_STACKS[self.uuid] = self._stack + def create(self, template, heat_parameters, wait, timeout): """Creates an OpenStack stack from a template""" with tempfile.NamedTemporaryFile('wb', delete=False) as template_file: @@ -52,11 +59,21 @@ class HeatStack(object): self._stack = self._cloud.create_stack( self.name, template_file=template_file.name, wait=wait, timeout=timeout, **heat_parameters) - outputs = self._stack.outputs - self.outputs = {output['output_key']: output['output_value'] for output - in outputs} - if self.uuid: - _DEPLOYED_STACKS[self.uuid] = self._stack + + self._update_stack_tracking() + + def get(self): + """Retrieves an existing stack from the target cloud + + Returns a bool indicating whether the stack exists in the target cloud + If the stack exists, it will be stored as self._stack + """ + self._stack = self._cloud.get_stack(self.name) + if not self._stack: + return False + + self._update_stack_tracking() + return True @staticmethod def stacks_exist(): diff --git a/yardstick/tests/unit/orchestrator/test_heat.py b/yardstick/tests/unit/orchestrator/test_heat.py index bde6647ed..9ab8740e3 100644 --- a/yardstick/tests/unit/orchestrator/test_heat.py +++ b/yardstick/tests/unit/orchestrator/test_heat.py @@ -9,6 +9,7 @@ import tempfile +import munch import mock from oslo_serialization import jsonutils from oslo_utils import uuidutils @@ -40,12 +41,16 @@ class HeatStackTestCase(unittest.TestCase): self._mock_stack_delete = mock.patch.object(self.heatstack._cloud, 'delete_stack') self.mock_stack_delete = self._mock_stack_delete.start() + self._mock_stack_get = mock.patch.object(self.heatstack._cloud, + 'get_stack') + self.mock_stack_get = self._mock_stack_get.start() self.addCleanup(self._cleanup) def _cleanup(self): self._mock_stack_create.stop() self._mock_stack_delete.stop() + self._mock_stack_get.stop() heat._DEPLOYED_STACKS = {} def test_create(self): @@ -101,6 +106,88 @@ class HeatStackTestCase(unittest.TestCase): self.assertFalse(heat._DEPLOYED_STACKS) self.mock_stack_delete.assert_called_once_with(id, wait=True) + def test_get(self): + # make sure shade/get_stack is called with the appropriate vars + self.mock_stack_get.return_value = munch.Munch( + id="my-existing-stack-id", + outputs=[ + { + u'output_value': u'b734d06a-dec7-...', + u'output_key': u'ares.demo-test-port-network_id', + u'description': u'' + }, + {u'output_value': u'b08da78c-2218-...', + u'output_key': u'ares.demo-test-port-subnet_id', + u'description': u'' + }, + {u'output_value': u'10.0.1.0/24', + u'output_key': u'demo-test-subnet-cidr', + u'description': u'' + }, + {u'output_value': u'b08da78c-2218-...', + u'output_key': u'demo-test-subnet', + u'description': u'' + }, + {u'output_value': u'b1a03624-aefc-...', + u'output_key': u'ares.demo', + u'description': u'' + }, + {u'output_value': u'266a8088-c630-...', + u'output_key': u'demo-secgroup', + u'description': u'' + }, + {u'output_value': u'10.0.1.5', + u'output_key': u'ares.demo-test-port', + u'description': u'' + }, + {u'output_value': u'10.0.1.1', + u'output_key': u'demo-test-subnet-gateway_ip', + u'description': u'' + }, + {u'output_value': u'', + u'output_key': u'ares.demo-test-port-device_id', + u'description': u'' + }, + {u'output_value': u'172.24.4.7', + u'output_key': u'ares.demo-fip', + u'description': u'' + }, + {u'output_value': u'fa:16:3e:6c:c3:0f', + u'output_key': u'ares.demo-test-port-mac_address', + u'description': u''} + ] + ) + expected_outputs = { + 'ares.demo-test-port-network_id': 'b734d06a-dec7-...', + 'ares.demo-test-port-subnet_id': 'b08da78c-2218-...', + 'demo-test-subnet-cidr': '10.0.1.0/24', + 'demo-test-subnet': 'b08da78c-2218-...', + 'ares.demo': 'b1a03624-aefc-...', + 'demo-secgroup': '266a8088-c630-...', + 'ares.demo-test-port': '10.0.1.5', + 'demo-test-subnet-gateway_ip': '10.0.1.1', + 'ares.demo-test-port-device_id': '', + 'ares.demo-fip': '172.24.4.7', + 'ares.demo-test-port-mac_address': 'fa:16:3e:6c:c3:0f', + } + + stack_id = "my-existing-stack-id" + self.heatstack.name = "my-existing-stack" + self.heatstack.get() + + self.mock_stack_get.assert_called_once_with(self.heatstack.name) + self.assertEqual(expected_outputs, self.heatstack.outputs) + self.assertEqual(1, len(heat._DEPLOYED_STACKS)) + self.assertEqual(self.heatstack._stack, + heat._DEPLOYED_STACKS[stack_id]) + + def test_get_invalid_name(self): + # No context matching this name exists + self.mock_stack_get.return_value = [] + self.heatstack.name = 'not-a-stack' + self.heatstack.get() + self.assertEqual(0, len(heat._DEPLOYED_STACKS)) + class HeatTemplateTestCase(unittest.TestCase): -- cgit 1.2.3-korg