diff --git a/shade/_heat/event_utils.py b/shade/_heat/event_utils.py index 69c286220..839f2aad4 100644 --- a/shade/_heat/event_utils.py +++ b/shade/_heat/event_utils.py @@ -86,7 +86,7 @@ def poll_for_events( if no_event_polls >= 2: # after 2 polls with no events, fall back to a stack get - stack = cloud.get_stack(stack_name) + stack = cloud.get_stack(stack_name, resolve_outputs=False) stack_status = stack['stack_status'] msg = msg_template % dict( name=stack_name, status=stack_status) diff --git a/shade/openstackcloud.py b/shade/openstackcloud.py index 687ca2e1d..5599c004e 100644 --- a/shade/openstackcloud.py +++ b/shade/openstackcloud.py @@ -1405,7 +1405,7 @@ class OpenStackCloud( :raises: ``OpenStackCloudException`` if something goes wrong during the OpenStack API call """ - stack = self.get_stack(name_or_id) + stack = self.get_stack(name_or_id, resolve_outputs=False) if stack is None: self.log.debug("Stack %s not found for deleting", name_or_id) return False @@ -1427,7 +1427,7 @@ class OpenStackCloud( marker=marker) except OpenStackCloudHTTPError: pass - stack = self.get_stack(name_or_id) + stack = self.get_stack(name_or_id, resolve_outputs=False) if stack and stack['stack_status'] == 'DELETE_FAILED': raise OpenStackCloudException( "Failed to delete stack {id}: {reason}".format( @@ -3323,12 +3323,14 @@ class OpenStackCloud( return self._normalize_floating_ip( self._get_and_munchify('floating_ip', data)) - def get_stack(self, name_or_id, filters=None): + def get_stack(self, name_or_id, filters=None, resolve_outputs=True): """Get exactly one stack. :param name_or_id: Name or ID of the desired stack. :param filters: a dict containing additional filters to use. e.g. {'stack_status': 'CREATE_COMPLETE'} + :param resolve_outputs: If True, then outputs for this + stack will be resolved :returns: a ``munch.Munch`` containing the stack description @@ -3340,8 +3342,11 @@ class OpenStackCloud( # stack names are mandatory and enforced unique in the project # so a StackGet can always be used for name or ID. try: + url = '/stacks/{name_or_id}'.format(name_or_id=name_or_id) + if not resolve_outputs: + url = '{url}?resolve_outputs=False'.format(url=url) data = self._orchestration_client.get( - '/stacks/{name_or_id}'.format(name_or_id=name_or_id), + url, error_message="Error fetching stack") stack = self._get_and_munchify('stack', data) # Treat DELETE_COMPLETE stacks as a NotFound diff --git a/shade/tests/unit/test_stack.py b/shade/tests/unit/test_stack.py index 5c4daa635..bc3380c22 100644 --- a/shade/tests/unit/test_stack.py +++ b/shade/tests/unit/test_stack.py @@ -112,20 +112,22 @@ class TestStack(base.RequestsMockTestCase): self.cloud.search_stacks() def test_delete_stack(self): + resolve = 'resolve_outputs=False' self.register_uris([ dict(method='GET', - uri='{endpoint}/stacks/{name}'.format( + uri='{endpoint}/stacks/{name}?{resolve}'.format( endpoint=fakes.ORCHESTRATION_ENDPOINT, - name=self.stack_name), + name=self.stack_name, resolve=resolve), status_code=302, headers=dict( - location='{endpoint}/stacks/{name}/{id}'.format( + location='{endpoint}/stacks/{name}/{id}?{resolve}'.format( endpoint=fakes.ORCHESTRATION_ENDPOINT, - id=self.stack_id, name=self.stack_name))), + id=self.stack_id, name=self.stack_name, + resolve=resolve))), dict(method='GET', - uri='{endpoint}/stacks/{name}/{id}'.format( + uri='{endpoint}/stacks/{name}/{id}?{resolve}'.format( endpoint=fakes.ORCHESTRATION_ENDPOINT, - id=self.stack_id, name=self.stack_name), + id=self.stack_id, name=self.stack_name, resolve=resolve), json={"stack": self.stack}), dict(method='DELETE', uri='{endpoint}/stacks/{id}'.format( @@ -136,30 +138,33 @@ class TestStack(base.RequestsMockTestCase): self.assert_calls() def test_delete_stack_not_found(self): + resolve = 'resolve_outputs=False' self.register_uris([ dict(method='GET', - uri='{endpoint}/stacks/stack_name'.format( - endpoint=fakes.ORCHESTRATION_ENDPOINT), + uri='{endpoint}/stacks/stack_name?{resolve}'.format( + endpoint=fakes.ORCHESTRATION_ENDPOINT, resolve=resolve), status_code=404), ]) self.assertFalse(self.cloud.delete_stack('stack_name')) self.assert_calls() def test_delete_stack_exception(self): + resolve = 'resolve_outputs=False' self.register_uris([ dict(method='GET', - uri='{endpoint}/stacks/{id}'.format( + uri='{endpoint}/stacks/{id}?{resolve}'.format( endpoint=fakes.ORCHESTRATION_ENDPOINT, - id=self.stack_id), + id=self.stack_id, resolve=resolve), status_code=302, headers=dict( - location='{endpoint}/stacks/{name}/{id}'.format( + location='{endpoint}/stacks/{name}/{id}?{resolve}'.format( endpoint=fakes.ORCHESTRATION_ENDPOINT, - id=self.stack_id, name=self.stack_name))), + id=self.stack_id, name=self.stack_name, + resolve=resolve))), dict(method='GET', - uri='{endpoint}/stacks/{name}/{id}'.format( + uri='{endpoint}/stacks/{name}/{id}?{resolve}'.format( endpoint=fakes.ORCHESTRATION_ENDPOINT, - id=self.stack_id, name=self.stack_name), + id=self.stack_id, name=self.stack_name, resolve=resolve), json={"stack": self.stack}), dict(method='DELETE', uri='{endpoint}/stacks/{id}'.format( @@ -177,20 +182,23 @@ class TestStack(base.RequestsMockTestCase): self.stack_id, self.stack_name, status='CREATE_COMPLETE') marker_qs = 'marker={e_id}&sort_dir=asc'.format( e_id=marker_event['id']) + resolve = 'resolve_outputs=False' self.register_uris([ dict(method='GET', - uri='{endpoint}/stacks/{id}'.format( + uri='{endpoint}/stacks/{id}?{resolve}'.format( endpoint=fakes.ORCHESTRATION_ENDPOINT, - id=self.stack_id), + id=self.stack_id, + resolve=resolve), status_code=302, headers=dict( - location='{endpoint}/stacks/{name}/{id}'.format( + location='{endpoint}/stacks/{name}/{id}?{resolve}'.format( endpoint=fakes.ORCHESTRATION_ENDPOINT, - id=self.stack_id, name=self.stack_name))), + id=self.stack_id, name=self.stack_name, + resolve=resolve))), dict(method='GET', - uri='{endpoint}/stacks/{name}/{id}'.format( + uri='{endpoint}/stacks/{name}/{id}?{resolve}'.format( endpoint=fakes.ORCHESTRATION_ENDPOINT, - id=self.stack_id, name=self.stack_name), + id=self.stack_id, name=self.stack_name, resolve=resolve), json={"stack": self.stack}), dict(method='GET', uri='{endpoint}/stacks/{id}/events?{qs}'.format( @@ -215,9 +223,9 @@ class TestStack(base.RequestsMockTestCase): status='DELETE_COMPLETE'), ]}), dict(method='GET', - uri='{endpoint}/stacks/{id}'.format( + uri='{endpoint}/stacks/{id}?{resolve}'.format( endpoint=fakes.ORCHESTRATION_ENDPOINT, - id=self.stack_id, name=self.stack_name), + id=self.stack_id, name=self.stack_name, resolve=resolve), status_code=404), ]) @@ -231,20 +239,22 @@ class TestStack(base.RequestsMockTestCase): self.stack_id, self.stack_name, status='CREATE_COMPLETE') marker_qs = 'marker={e_id}&sort_dir=asc'.format( e_id=marker_event['id']) + resolve = 'resolve_outputs=False' self.register_uris([ dict(method='GET', - uri='{endpoint}/stacks/{id}'.format( + uri='{endpoint}/stacks/{id}?{resolve}'.format( endpoint=fakes.ORCHESTRATION_ENDPOINT, - id=self.stack_id), + id=self.stack_id, resolve=resolve), status_code=302, headers=dict( - location='{endpoint}/stacks/{name}/{id}'.format( + location='{endpoint}/stacks/{name}/{id}?{resolve}'.format( endpoint=fakes.ORCHESTRATION_ENDPOINT, - id=self.stack_id, name=self.stack_name))), + id=self.stack_id, name=self.stack_name, + resolve=resolve))), dict(method='GET', - uri='{endpoint}/stacks/{name}/{id}'.format( + uri='{endpoint}/stacks/{name}/{id}?{resolve}'.format( endpoint=fakes.ORCHESTRATION_ENDPOINT, - id=self.stack_id, name=self.stack_name), + id=self.stack_id, name=self.stack_name, resolve=resolve), json={"stack": self.stack}), dict(method='GET', uri='{endpoint}/stacks/{id}/events?{qs}'.format( @@ -269,18 +279,19 @@ class TestStack(base.RequestsMockTestCase): status='DELETE_COMPLETE'), ]}), dict(method='GET', - uri='{endpoint}/stacks/{id}'.format( + uri='{endpoint}/stacks/{id}?resolve_outputs=False'.format( endpoint=fakes.ORCHESTRATION_ENDPOINT, id=self.stack_id, name=self.stack_name), status_code=302, headers=dict( - location='{endpoint}/stacks/{name}/{id}'.format( + location='{endpoint}/stacks/{name}/{id}?{resolve}'.format( endpoint=fakes.ORCHESTRATION_ENDPOINT, - id=self.stack_id, name=self.stack_name))), + id=self.stack_id, name=self.stack_name, + resolve=resolve))), dict(method='GET', - uri='{endpoint}/stacks/{name}/{id}'.format( + uri='{endpoint}/stacks/{name}/{id}?{resolve}'.format( endpoint=fakes.ORCHESTRATION_ENDPOINT, - id=self.stack_id, name=self.stack_name), + id=self.stack_id, name=self.stack_name, resolve=resolve), json={"stack": failed_stack}), ])