-
Notifications
You must be signed in to change notification settings - Fork 311
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
[V2] Improve Change Set behaviour #520
Comments
Hey @janrotter By default we want to make sure that dependencies are considered when acting on a stack. I can definitely see the case you’ve highlighted is an issue and I think what we will do is add something like a ‘-- no-dependencies’ flag, that can be applied to any command as an override so that you can act on a single stack. I know for the ‘delete’ command we print all the stacks that will be deleted during the confirmation stage; I don’t see any issue adding this for other command so that they are no surprises. Good suggestion. I’ll look to get a fix up for this on Monday and maybe if you have time once a branch is up you could help test it? Cheers, |
Hey @janrotter Got ahead of myself and pushed a WIP branch add-ignore-dependencies-option to try and resolve this. Single Stack/StackGroup commands should be possible on this branch if you do:
Could you just confirm this is the sort of behaviour you would be after/expect based on the comments above? If so, I will tidy things up a bit and update the docs and add some tests around this behaviour. Hopefully, get an I will deal with printing to the cli the stacks that will be operated on in a separate branch/issue. |
That's exactly it! Excellent work! I guess you could use something like this test from my pull request to ensure, that the What do you think about the change set update proposal I described previously? Would you be willing to pull something like that into the v2? I'm not sure how to handle the stacks that haven't been launched yet, but one solution could be to launch empty stacks with the relevant names and then apply change-sets to them (so that you can easily see the list of resources to create). (Related issue: #65) |
Thanks @janrotter - I will need to think about how best to deal with Change Sets. I like the idea in #65 whereby the user could be "stepped through" each change set. Although, with all the refactoring we have done we will be able to generate a full print out about what will happen ahead of time. In terms of updating whole StackGroup, I think this problem is probably solved with v2. Again not 100% best how to handle situation where Stack doesn't exist yet. Let me speak to a few folk tomorrow and I'll have a better idea about how we should implement. Maybe the flow should be something like you suggested:
I think safety is key, the user will want to be confident. I am happy to get the barebones of this working without having perfect output if it means we can get it into v2, due for release this upcoming week. We can then improve the output/messaging after v2 is out. |
I would propose something like:
If there are multiple batches Launching empty stacks and applying the change sets would make the output consistent for the user - you will see exactly what will be created/updated/removed for both existing and non-existing stacks. |
Thanks for the suggestion - will be sure to include this in the discussion. Just as an FYI more than anything else, what are Plan and Graph do is create batches where by each batch is executed in serial but each stack in the batch are executed concurrently. We can guarantee that by the time the launch_order is generated that there no stacks that will be generated without first having all of its dependencies resolved. So in the case you mentioned above, if we have a batch Take the case where the Stack dependencies are as follows (
The StackGraph is generated with edges that represent a "depends on" relationship and then launch order = [
set(A,B,C)
set(D,E,F,G)
set{H}
] In the above example, Sceptre has understood that If I understand your suggestion correctly then it might make things a bit simpler? |
I'd like to clarify what would be the expected behavior. Let's consider the sample sceptre v2 project:
After the launch (
Now we update the stack
and update the stack group (not working correctly at the moment as the test doesn't expect a dict with stacks as keys):
My expected output values would be now:
I'm afraid that the current implementation would end up with the following results as initially only the first change set is non-empty:
The current implementation executes the change-sets in the correct order, but the problem is that the change sets are created before the parameters can be properly resolved. Creating the change sets separately right before each batch (set) in the launch order is executed should fix that. |
Create changesets right before each batch set, reduces the value in change sets though. I think the ideal UX depends on the workflow For
note that this would mean, if you run
Thinking about it, without explicit prompting, there is always a change of getting stuck in a loop (and potentially one scepter can't be aware of if ssm parameters are used) Given that you can do nice stuff with hooks and change sets (e.g backup your current template and create a roll-back after the deployment (and cascading these if needed)) I hope the above workflows make it into the 2.x release, but guess they aren't needed for 2.0 as 1.0 doesn't have that functionality. |
After a short discussion with my coworker, we agreed that actually the launching of non existing stacks could be not required for the Assuming that the above is true, I have prepared a working proof of concept for the update with change-sets for multiple stacks: If you think that the general approach there is correct, I'd be happy to improve the implementation and submit a PR. |
Hey @janrotter Yeh launch has always been used to create or update. Where are update/create were more aimed at individual stacks. I think I would still like to propose a nice way, similar to something you suggested to handle change-sets. It is a best practice to use change-sets when updating CloudFormation and I think it would be useful to have Sceptre automatically manage Change Sets for the user. After speaking to some colleagues somethings came up:
If we use Change Sets by default it would also give us a nice output to present to the user too? |
I didn't know that you can create a change set for a non existing stack. That's great news! The change set name is already generated for the I don't know what the error handling should be for the change set update. I assumed it should just finish the current batch, report the result to the user and abort next batches. Then the user should resolve it (maybe by updating the stacks one by one with I think that the major use cases for multi-stack change set update/launch is to:
What do you think about extracting the second one as a |
Yeh just needs to be clear what the behaviour will be for certain. I think for the latter point we will add a feature to support Drift Detection - which is a recent addition to the CloudFormation offering. Won’t be until after 2.0 release. That will be the most robust way to see what the diff is between local and actual. |
ProposalFrom the documentation the below image shows how AWS sees the interaction with Change Sets. I don't think Sceptre should stray from this flow. We have currently have 6 CLI command groups that handle Change Sets.
I think we then have the following user use cases:
As it stands, with the ongoing work for My understanding is that there is appetite for a final use-case which is more of a guided/step-through process that merges a few of these commands together and produces a nicer output along the way. I believe that if we make this part seamless enough we can use Change Sets behind the scenes by default, without the user necessarily being aware/caring, thus enabling our users to easily follow an AWS best practice without thinking. The above vision of a Change Set world by default might take a bit of time to get right. A pseudocode example where we don't utilise AWS # ... command has been submitted, SceptreContext and Plan is created....
# First figure out what needs created
change_set_name = # generated or user specified
to_change = set()
to_create = set()
for each stack in plan.command_stacks:
if stack_exists:
to_change.add(stack_path)
else:
to_create(stack_path)
write_to_cli("You are about to create the following stacks: {}".format(launch_order))
# User input: y/N - continue if yes abort if no.
write_to_cli("Creating Stacks")
# Create the Stacks that don't exist
for stack_path in to_create:
result = plan.create(stack_path)
# log will capture and print out put of create() as it goes
if result == SUCCESS:
to_create.remove(stack_path)
to_change.add(stack_path)
elif result == FAILED:
write_to_cli("{} failed to create".format(stack_path))
# Probably need way to re-try of get user input to retry/abort
# Now create Change Sets
write_to_cli("You are about to create the following Change Sets: {}".format(to_change))
# User input: y/N - continue if yes abort if no.
write_to_cli("Creating Change Sets")
while to_change:
stack = to_change.pop()
plan.create_change_set(change_set_name)
# plan.create_change_set will print description of Change Set from AWS
write_to_cli("The following changes will be applied:")
for stack in plan.command_stacks:
plan.describe_change_set(change_set_name)
# plan.describe_change_set will print description of Change Set from AWS
# User input- Do you want to execute these Change Sets: y/N
succeeded = {}
failed = {}
for stack in plan.command_stacks:
result = plan.execute_change_set(change_set_name)
result == SUCCESS:
succeeded.append(stack: result)
result == FAILED:
failed.append(stack: result)
# print summary of succeeded and failed results
END There is probably a simpler solution to this but it shows the process of joining up the dots with the existing command into an existing flow. I could see this being useful as the default behaviour for something like update or create? Thoughts? |
Hi folks, I'm curious about the status of this work. I'm working on moving from a self-maintained tool to sceptre, and change set support is one of the big missing features. I'd be happy to contribute if there's a clear plan of record. There are a few points of confusion for me right now (not all related to change sets, but good change set support would resolve all):
I realize not all of these comments and questions are specific to change set support. I'm happy to open new issues for each if I'm not misunderstanding anything. |
Since all cli commands use
SceptrePlan
in sceptre 2.0 to modify the stacks, each time an action is taken on a stack, all stacks that it depends on take that action as well. This makes directly translating the sceptre 1.0 commands like:generate-template
andupdate-stack
to their 2.0 equivalents impossible.Please consider the following example:
The stack
B/dummy.yaml
hasdependencies: ["A/dummy.yaml"]
in the stack configuration.sceptre generate B/dummy.yaml
returnsdict_values([template_for_A/dummy.yaml, template_for_B/dummy.yaml])
sceptre launch B/dummy.yaml
asks for confirmation of stack B launch:Do you want to launch 'B/dummy.yaml' [y/N]: y
and begins to update the A:
sceptre update -c B/dummy.yaml
doesn't work at all (because the status here is a dict with statuses for all relevant changesets):The last example is particularly interesting. The stacks depend on each other, so generating the change sets for all of them at the beginning as it is implemented now is not correct (I assume we would be using the
!stack_output
resolver here).Is that behavior intentional? I would rather like to be notified that there are some other stacks that need updating as well instead of being surprised with the scope of changes.
I would gladly submit a pull request for the change set update, but I am not sure what is the expected behavior after the cli redesign. I have implemented something that behaves more or less like this:
Is that how it should work in 2.0 cli or do you have a different idea for that?
The text was updated successfully, but these errors were encountered: