From 4500371f4a2d421b88ff60cf5aafde2f405a4b51 Mon Sep 17 00:00:00 2001 From: "Eric J. Holmes" Date: Tue, 6 Feb 2018 16:42:59 -0800 Subject: [PATCH 1/2] Remove DescribeStacks call from prepare_stack_for_update --- stacker/actions/build.py | 2 +- stacker/providers/aws/default.py | 6 +- stacker/tests/providers/aws/test_default.py | 103 ++++---------------- 3 files changed, 21 insertions(+), 90 deletions(-) diff --git a/stacker/actions/build.py b/stacker/actions/build.py index eb2b20bcf..964e2f0f0 100644 --- a/stacker/actions/build.py +++ b/stacker/actions/build.py @@ -282,7 +282,7 @@ def _launch_stack(self, stack, **kwargs): return NotUpdatedStatus() try: - if self.provider.prepare_stack_for_update(stack.fqn, tags): + if self.provider.prepare_stack_for_update(provider_stack, tags): existing_params = provider_stack.get('Parameters', []) self.provider.update_stack( stack.fqn, diff --git a/stacker/providers/aws/default.py b/stacker/providers/aws/default.py index 21717ae0b..2f39f05a6 100644 --- a/stacker/providers/aws/default.py +++ b/stacker/providers/aws/default.py @@ -694,7 +694,7 @@ def select_update_method(self, force_interactive, force_change_set): else: return self.default_update_stack - def prepare_stack_for_update(self, fqn, tags): + def prepare_stack_for_update(self, stack, tags): """Prepare a stack for updating It may involve deleting the stack if is has failed it's initial @@ -705,7 +705,7 @@ def prepare_stack_for_update(self, fqn, tags): enabled by the user, or because interactive mode is on. Args: - fqn (str): fully-qualified name of the stack to work on + stack (dict): a stack object returned from get_stack tags (list): list of expected tags that must be present in the stack if it must be re-created @@ -714,8 +714,6 @@ def prepare_stack_for_update(self, fqn, tags): re-created """ - stack = self.get_stack(fqn) - if self.is_stack_destroyed(stack): return False elif self.is_stack_completed(stack): diff --git a/stacker/tests/providers/aws/test_default.py b/stacker/tests/providers/aws/test_default.py index b50fb2103..48678c823 100644 --- a/stacker/tests/providers/aws/test_default.py +++ b/stacker/tests/providers/aws/test_default.py @@ -409,94 +409,45 @@ def test_select_update_method(self): i[1] ) - def test_prepare_stack_for_update_missing(self): - stack_name = "MockStack" - self.stubber.add_client_error( - "describe_stacks", - service_error_code="ValidationError", - service_message="Stack with id %s does not exist" % stack_name, - expected_params={"StackName": stack_name} - ) - - with self.assertRaises(exceptions.StackDoesNotExist): - with self.stubber: - self.provider.prepare_stack_for_update(stack_name, []) - def test_prepare_stack_for_update_completed(self): stack_name = "MockStack" - stack_response = { - "Stacks": [ - generate_describe_stacks_stack( - stack_name, stack_status="UPDATE_COMPLETE") - ] - } - self.stubber.add_response( - "describe_stacks", - stack_response, - expected_params={"StackName": stack_name} - ) + stack = generate_describe_stacks_stack( + stack_name, stack_status="UPDATE_COMPLETE") with self.stubber: self.assertTrue( - self.provider.prepare_stack_for_update(stack_name, [])) + self.provider.prepare_stack_for_update(stack, [])) def test_prepare_stack_for_update_in_progress(self): stack_name = "MockStack" - stack_response = { - "Stacks": [ - generate_describe_stacks_stack( - stack_name, stack_status="UPDATE_IN_PROGRESS") - ] - } - self.stubber.add_response( - "describe_stacks", - stack_response, - expected_params={"StackName": stack_name} - ) + stack = generate_describe_stacks_stack( + stack_name, stack_status="UPDATE_IN_PROGRESS") with self.assertRaises(exceptions.StackUpdateBadStatus) as raised: with self.stubber: - self.provider.prepare_stack_for_update(stack_name, []) + self.provider.prepare_stack_for_update(stack, []) self.assertIn('in-progress', raised.exception.message) def test_prepare_stack_for_update_non_recreatable(self): stack_name = "MockStack" - stack_response = { - "Stacks": [ - generate_describe_stacks_stack( - stack_name, stack_status="REVIEW_IN_PROGRESS") - ] - } - self.stubber.add_response( - "describe_stacks", - stack_response, - expected_params={"StackName": stack_name} - ) + stack = generate_describe_stacks_stack( + stack_name, stack_status="REVIEW_IN_PROGRESS") with self.assertRaises(exceptions.StackUpdateBadStatus) as raised: with self.stubber: - self.provider.prepare_stack_for_update(stack_name, []) + self.provider.prepare_stack_for_update(stack, []) self.assertIn('Unsupported state', raised.exception.message) def test_prepare_stack_for_update_disallowed(self): stack_name = "MockStack" - stack_response = { - "Stacks": [ - generate_describe_stacks_stack( - stack_name, stack_status="ROLLBACK_COMPLETE") - ] - } - self.stubber.add_response( - "describe_stacks", - stack_response, - expected_params={"StackName": stack_name} - ) + stack = generate_describe_stacks_stack( + stack_name, stack_status="ROLLBACK_COMPLETE") with self.assertRaises(exceptions.StackUpdateBadStatus) as raised: with self.stubber: - self.provider.prepare_stack_for_update(stack_name, []) + self.provider.prepare_stack_for_update(stack, []) self.assertIn('re-creation is disabled', raised.exception.message) # Ensure we point out to the user how to enable re-creation @@ -504,41 +455,23 @@ def test_prepare_stack_for_update_disallowed(self): def test_prepare_stack_for_update_bad_tags(self): stack_name = "MockStack" - stack_response = { - "Stacks": [ - generate_describe_stacks_stack( - stack_name, stack_status="ROLLBACK_COMPLETE") - ] - } - self.stubber.add_response( - "describe_stacks", - stack_response, - expected_params={"StackName": stack_name} - ) + stack = generate_describe_stacks_stack( + stack_name, stack_status="ROLLBACK_COMPLETE") self.provider.recreate_failed = True with self.assertRaises(exceptions.StackUpdateBadStatus) as raised: with self.stubber: self.provider.prepare_stack_for_update( - stack_name, + stack, tags=[{'Key': 'stacker_namespace', 'Value': 'test'}]) self.assertIn('tags differ', raised.exception.message.lower()) def test_prepare_stack_for_update_recreate(self): stack_name = "MockStack" - stack_response = { - "Stacks": [ - generate_describe_stacks_stack( - stack_name, stack_status="ROLLBACK_COMPLETE") - ] - } - self.stubber.add_response( - "describe_stacks", - stack_response, - expected_params={"StackName": stack_name} - ) + stack = generate_describe_stacks_stack( + stack_name, stack_status="ROLLBACK_COMPLETE") self.stubber.add_response( "delete_stack", @@ -550,7 +483,7 @@ def test_prepare_stack_for_update_recreate(self): with self.stubber: self.assertFalse( - self.provider.prepare_stack_for_update(stack_name, [])) + self.provider.prepare_stack_for_update(stack, [])) class TestProviderInteractiveMode(unittest.TestCase): From 7657f7ab030ddfd50b0b243129d35648ccbea1a0 Mon Sep 17 00:00:00 2001 From: "Eric J. Holmes" Date: Thu, 8 Feb 2018 18:27:44 -0800 Subject: [PATCH 2/2] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba00b761a..af7ffe6e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ - assertRenderedBlueprint always dumps current results [GH-528] - stacker now builds a DAG internally [GH-523] +- an unecessary DescribeStacks network call was removed [GH-529] ## 1.1.4 (2018-01-26)