Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove DescribeStacks call from prepare_stack_for_update #529

Merged
merged 2 commits into from
Feb 9, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
2 changes: 1 addition & 1 deletion stacker/actions/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
6 changes: 2 additions & 4 deletions stacker/providers/aws/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to update the docstring.

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
Expand All @@ -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

Expand All @@ -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):
Expand Down
103 changes: 18 additions & 85 deletions stacker/tests/providers/aws/test_default.py
Original file line number Diff line number Diff line change
Expand Up @@ -409,136 +409,69 @@ 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
self.assertIn('--recreate-failed', raised.exception.message)

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",
Expand All @@ -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):
Expand Down