├── happy.png ├── toplevel.png ├── all-states.png ├── create-stack.png ├── delete-stack.png ├── update-stack.png ├── Makefile ├── toplevel.dot ├── delete-stack.dot ├── happy.dot ├── create-stack.dot ├── update-stack.dot ├── all-states.dot ├── toplevel.svg ├── delete-stack.svg ├── README.md ├── happy.svg ├── create-stack.svg ├── update-stack.svg └── all-states.svg /happy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rvedotrc/aws-cloudformation-stack-states/HEAD/happy.png -------------------------------------------------------------------------------- /toplevel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rvedotrc/aws-cloudformation-stack-states/HEAD/toplevel.png -------------------------------------------------------------------------------- /all-states.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rvedotrc/aws-cloudformation-stack-states/HEAD/all-states.png -------------------------------------------------------------------------------- /create-stack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rvedotrc/aws-cloudformation-stack-states/HEAD/create-stack.png -------------------------------------------------------------------------------- /delete-stack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rvedotrc/aws-cloudformation-stack-states/HEAD/delete-stack.png -------------------------------------------------------------------------------- /update-stack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rvedotrc/aws-cloudformation-stack-states/HEAD/update-stack.png -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | DOTS := $(shell echo *.dot) 2 | PNGS := $(patsubst %.dot, %.png, $(DOTS)) 3 | SVGS := $(patsubst %.dot, %.svg, $(DOTS)) 4 | 5 | default: all 6 | 7 | all: $(PNGS) $(SVGS) 8 | 9 | %.png: %.dot 10 | dot -Tpng -o$@.tmp $< && mv $@.tmp $@ 11 | 12 | %.svg: %.dot 13 | dot -Tsvg -o$@.tmp $< && mv $@.tmp $@ 14 | 15 | delete: 16 | rm -f $(PNGS) $(SVGS) 17 | 18 | clean: 19 | rm -f *.png *.svg 20 | $(MAKE) all 21 | 22 | -------------------------------------------------------------------------------- /toplevel.dot: -------------------------------------------------------------------------------- 1 | digraph toplevel { 2 | 3 | before_existence [ label="no stack" ] 4 | after_existence [ label="no stack" ] 5 | 6 | CREATED 7 | DELETED 8 | UPDATED 9 | 10 | before_existence -> CREATED 11 | 12 | CREATED -> UPDATED 13 | UPDATED -> UPDATED 14 | 15 | UPDATED -> DELETED 16 | 17 | CREATED -> DELETED 18 | DELETED -> after_existence [ label=" 90 days later" ] 19 | 20 | } 21 | // # vi: set sw=2 et ai : 22 | -------------------------------------------------------------------------------- /delete-stack.dot: -------------------------------------------------------------------------------- 1 | digraph delete_stack { 2 | 3 | after_existence [ layer="happy" label="no stack" ] 4 | 5 | deletable_stack [ label="stack\n(various states)" color="transparent" ] 6 | 7 | DELETE_COMPLETE [ layer="happy" ] 8 | DELETE_FAILED [ layer="sad" ] 9 | DELETE_IN_PROGRESS [ layer="happy" style=dotted ] 10 | 11 | deletable_stack -> DELETE_IN_PROGRESS -> try_delete -> check_delete 12 | try_delete [ shape="rect" label="Try deleting each resource\nthat has not already been\ndeleted (but see also the\nDeletionPolicy)" ] 13 | check_delete [ shape="diamond" label="Did the deletes\nall succeed?" ] 14 | check_delete -> DELETE_COMPLETE [ label="yes" ] 15 | check_delete -> DELETE_FAILED [ label="no" ] 16 | 17 | DELETE_FAILED -> deletable_stack [ constraint="false" ] 18 | DELETE_COMPLETE -> after_existence [ label=" 90 days later" ] 19 | 20 | } 21 | // # vi: set sw=2 et ai : 22 | -------------------------------------------------------------------------------- /happy.dot: -------------------------------------------------------------------------------- 1 | digraph happy { 2 | 3 | before_existence [ label="no stack" ] 4 | after_existence [ label="no stack" ] 5 | 6 | REVIEW_IN_PROGRESS [ style=dotted ] 7 | CREATE_COMPLETE 8 | CREATE_IN_PROGRESS [ style=dotted ] 9 | DELETE_COMPLETE 10 | DELETE_IN_PROGRESS [ style=dotted ] 11 | UPDATE_COMPLETE 12 | UPDATE_COMPLETE_CLEANUP_IN_PROGRESS [ style=dotted label="UPDATE_COMPLETE\nCLEANUP_IN_PROGRESS" ] 13 | UPDATE_IN_PROGRESS [ style=dotted ] 14 | 15 | before_existence -> CREATE_IN_PROGRESS 16 | before_existence -> REVIEW_IN_PROGRESS -> CREATE_IN_PROGRESS 17 | CREATE_IN_PROGRESS -> CREATE_COMPLETE 18 | 19 | REVIEW_IN_PROGRESS -> DELETE_COMPLETE // never fully created 20 | 21 | CREATE_COMPLETE -> UPDATE_IN_PROGRESS -> UPDATE_COMPLETE_CLEANUP_IN_PROGRESS -> UPDATE_COMPLETE 22 | UPDATE_COMPLETE -> UPDATE_IN_PROGRESS 23 | 24 | UPDATE_COMPLETE -> DELETE_IN_PROGRESS 25 | 26 | CREATE_COMPLETE -> DELETE_IN_PROGRESS 27 | DELETE_IN_PROGRESS -> DELETE_COMPLETE 28 | DELETE_COMPLETE -> after_existence [ label=" 90 days later" ] 29 | 30 | } 31 | // # vi: set sw=2 et ai : 32 | -------------------------------------------------------------------------------- /create-stack.dot: -------------------------------------------------------------------------------- 1 | digraph create_stack { 2 | 3 | before_existence [ label="no stack" ] 4 | 5 | REVIEW_IN_PROGRESS [ style=dotted ] 6 | CREATE_COMPLETE 7 | CREATE_IN_PROGRESS [ style=dotted ] 8 | CREATE_FAILED 9 | ROLLBACK_COMPLETE 10 | ROLLBACK_FAILED 11 | ROLLBACK_IN_PROGRESS [ style=dotted ] 12 | 13 | before_existence -> CREATE_IN_PROGRESS -> try_creates -> check_creates 14 | before_existence -> REVIEW_IN_PROGRESS -> CREATE_IN_PROGRESS 15 | try_creates [ shape="rect" label="Try creating the resources\n(respecting the dependency order)" ] 16 | check_creates [ label="Did the creates all succeed?" shape="diamond" ] 17 | check_creates -> CREATE_COMPLETE [ label="yes" ] 18 | check_creates -> do_we_need_rollback [ label="no" ] 19 | do_we_need_rollback [ shape="diamond" label="Did any of the creates succeed?" ] 20 | do_we_need_rollback -> CREATE_FAILED [ label="no" ] 21 | do_we_need_rollback -> ROLLBACK_IN_PROGRESS [ label="yes" ] 22 | 23 | ROLLBACK_IN_PROGRESS -> try_deletes -> check_deletes 24 | try_deletes [ shape="rect" label="Try deleting the resources\n(respecting the dependency order)" ] 25 | check_deletes [ shape="diamond" label="Did the deletes all succeed?" ] 26 | check_deletes -> ROLLBACK_COMPLETE [ label="yes" ] 27 | check_deletes -> ROLLBACK_FAILED [ label="no" ] 28 | 29 | // But would be useful to document: for each of those terminal states, what 30 | // states are the resources in? What happens to the stack next? 31 | 32 | // Resource statuses include: 33 | // CREATE_COMPLETE, UPDATE_COMPLETE, DELETE_COMPLETE, DELETE_FAILED, DELETE_SKIPPED. 34 | 35 | } 36 | // # vi: set sw=2 et ai : 37 | -------------------------------------------------------------------------------- /update-stack.dot: -------------------------------------------------------------------------------- 1 | digraph update_stack { 2 | 3 | CREATE_COMPLETE 4 | UPDATE_COMPLETE 5 | UPDATE_COMPLETE_CLEANUP_IN_PROGRESS [ style=dotted label="UPDATE_COMPLETE\nCLEANUP_IN_PROGRESS" ] 6 | UPDATE_IN_PROGRESS [ style=dotted ] 7 | UPDATE_ROLLBACK_COMPLETE 8 | UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS [ style=dotted label="UPDATE_ROLLBACK_COMPLETE\nCLEANUP_IN_PROGRESS" ] 9 | UPDATE_ROLLBACK_FAILED 10 | UPDATE_ROLLBACK_IN_PROGRESS [ style=dotted ] 11 | 12 | { CREATE_COMPLETE, UPDATE_COMPLETE } -> UPDATE_IN_PROGRESS -> try_rollforward_creates_and_updates -> check_rollforward_creates_and_updates 13 | try_rollforward_creates_and_updates [ shape="rect" label="Run the ROLLFORWARD plan\n(creates + updates)" ] 14 | check_rollforward_creates_and_updates [ label="Did the rollforward creates\n& updates all succeed?" shape="diamond" ] 15 | check_rollforward_creates_and_updates -> UPDATE_COMPLETE_CLEANUP_IN_PROGRESS [ label="yes (or no-op)" ] 16 | check_rollforward_creates_and_updates -> UPDATE_ROLLBACK_IN_PROGRESS [ label="no" ] 17 | 18 | UPDATE_COMPLETE_CLEANUP_IN_PROGRESS -> try_rollforward_cleanup -> check_rollforward_cleanup 19 | try_rollforward_cleanup [ shape="rect" label="Run the ROLLFORWARD plan\n(deletes)" ] 20 | check_rollforward_cleanup [ shape="diamond" label="Did the rollforward\ndeletes all succeed?" ] 21 | check_rollforward_cleanup -> UPDATE_COMPLETE_3 [ label="yes (or no-op)" ] 22 | check_rollforward_cleanup -> UPDATE_ROLLBACK_IN_PROGRESS [ label="no" ] 23 | UPDATE_COMPLETE_3 [ label="UPDATE_COMPLETE" ] 24 | 25 | UPDATE_ROLLBACK_IN_PROGRESS -> try_rollback_creates_and_updates -> check_rollback_creates_and_updates 26 | try_rollback_creates_and_updates [ shape="rect" label="Run the ROLLBACK plan\n(creates + updates)" ] 27 | check_rollback_creates_and_updates [ label="Did the rollback creates\n& updates all succeed?" shape="diamond" ] 28 | check_rollback_creates_and_updates -> UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS [ label="yes (or no-op)" ] 29 | check_rollback_creates_and_updates -> UPDATE_ROLLBACK_FAILED [ label="no" ] 30 | 31 | UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS -> try_rollback_cleanup -> check_rollback_cleanup 32 | try_rollback_cleanup [ shape="rect" label="Run the ROLLBACK plan\n(deletes)" ] 33 | check_rollback_cleanup [ shape="diamond" label="Did the rollback\ndeletes all succeed?" ] 34 | check_rollback_cleanup -> UPDATE_ROLLBACK_COMPLETE [ label="yes (or no-op)" ] 35 | check_rollback_cleanup -> UPDATE_ROLLBACK_FAILED [ label="no" ] 36 | 37 | // But would be useful to document: for each of those terminal states, what 38 | // states are the resources in? What happens to the stack next? 39 | 40 | } 41 | // # vi: set sw=2 et ai : 42 | -------------------------------------------------------------------------------- /all-states.dot: -------------------------------------------------------------------------------- 1 | digraph all_states { 2 | 3 | node [layer=all]; 4 | edge [layer=all]; 5 | 6 | layers="happy:sad" 7 | 8 | before_existence [ layer="happy" label="no stack" ] 9 | after_existence [ layer="happy" label="no stack" ] 10 | 11 | updateable_stack [ layer="happy" label="an updateable stack\n(various states)" color="transparent" ] 12 | stuck_stack [ layer="sad" label="a non-updateable stack\n(various states)" color="transparent" ] 13 | empty_stack [ layer="sad" label="non-deleted stack\nwith no extant resources\n(various states)" color="transparent" ] 14 | 15 | empty_stack -> DELETE_IN_PROGRESS [ layer="sad" ] 16 | 17 | CREATE_COMPLETE [ layer="happy" ] 18 | REVIEW_IN_PROGRESS [ layer="happy" style=dotted ] 19 | CREATE_IN_PROGRESS [ layer="happy" style=dotted ] 20 | CREATE_FAILED [ layer="sad" ] 21 | DELETE_COMPLETE [ layer="happy" ] 22 | DELETE_FAILED [ layer="sad" ] 23 | DELETE_IN_PROGRESS [ layer="happy" style=dotted ] 24 | ROLLBACK_COMPLETE [ layer="sad" ] 25 | ROLLBACK_FAILED [ layer="sad" ] 26 | ROLLBACK_IN_PROGRESS [ layer="sad" style=dotted ] 27 | UPDATE_COMPLETE [ layer="happy" ] 28 | UPDATE_COMPLETE_CLEANUP_IN_PROGRESS [ layer="happy" style=dotted label="UPDATE_COMPLETE\nCLEANUP_IN_PROGRESS" ] 29 | UPDATE_IN_PROGRESS [ layer="happy" style=dotted ] 30 | UPDATE_ROLLBACK_COMPLETE [ layer="sad" ] 31 | UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS [ layer="sad" style=dotted label="UPDATE_ROLLBACK_COMPLETE\nCLEANUP_IN_PROGRESS" ] 32 | UPDATE_ROLLBACK_FAILED [ layer="sad" ] 33 | UPDATE_ROLLBACK_IN_PROGRESS [ layer="sad" style=dotted ] 34 | 35 | edge [layer=happy]; 36 | before_existence -> CREATE_IN_PROGRESS 37 | before_existence -> REVIEW_IN_PROGRESS -> CREATE_IN_PROGRESS 38 | CREATE_IN_PROGRESS -> CREATE_COMPLETE 39 | CREATE_COMPLETE -> updateable_stack 40 | 41 | REVIEW_IN_PROGRESS -> DELETE_COMPLETE 42 | 43 | edge [layer=sad]; 44 | CREATE_IN_PROGRESS -> ROLLBACK_IN_PROGRESS -> ROLLBACK_COMPLETE 45 | ROLLBACK_COMPLETE -> empty_stack 46 | ROLLBACK_IN_PROGRESS -> ROLLBACK_FAILED 47 | ROLLBACK_FAILED -> stuck_stack 48 | 49 | edge [layer=sad]; 50 | CREATE_IN_PROGRESS -> CREATE_FAILED // ? 51 | CREATE_FAILED -> empty_stack // ? 52 | stuck_stack -> DELETE_IN_PROGRESS 53 | 54 | edge [layer=happy]; 55 | updateable_stack -> UPDATE_IN_PROGRESS -> UPDATE_COMPLETE_CLEANUP_IN_PROGRESS -> UPDATE_COMPLETE -> updateable_stack 56 | 57 | edge [layer=sad]; 58 | { UPDATE_IN_PROGRESS, UPDATE_COMPLETE_CLEANUP_IN_PROGRESS } -> UPDATE_ROLLBACK_IN_PROGRESS -> UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS -> { UPDATE_ROLLBACK_COMPLETE, UPDATE_ROLLBACK_FAILED } 59 | UPDATE_ROLLBACK_COMPLETE -> updateable_stack 60 | UPDATE_ROLLBACK_IN_PROGRESS -> UPDATE_ROLLBACK_FAILED -> stuck_stack // maybe? 61 | UPDATE_ROLLBACK_FAILED -> UPDATE_ROLLBACK_IN_PROGRESS 62 | 63 | edge [layer=happy]; 64 | updateable_stack -> DELETE_IN_PROGRESS 65 | DELETE_IN_PROGRESS -> DELETE_COMPLETE 66 | DELETE_COMPLETE -> after_existence [ label=" 90 days later" ] 67 | 68 | edge [layer=sad]; 69 | DELETE_IN_PROGRESS -> DELETE_FAILED [ constraint="false" ] 70 | DELETE_FAILED -> stuck_stack 71 | 72 | } 73 | // # vi: set sw=2 et ai : 74 | -------------------------------------------------------------------------------- /toplevel.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | toplevel 11 | 12 | 13 | before_existence 14 | 15 | no stack 16 | 17 | 18 | CREATED 19 | 20 | CREATED 21 | 22 | 23 | before_existence->CREATED 24 | 25 | 26 | 27 | 28 | after_existence 29 | 30 | no stack 31 | 32 | 33 | DELETED 34 | 35 | DELETED 36 | 37 | 38 | CREATED->DELETED 39 | 40 | 41 | 42 | 43 | UPDATED 44 | 45 | UPDATED 46 | 47 | 48 | CREATED->UPDATED 49 | 50 | 51 | 52 | 53 | DELETED->after_existence 54 | 55 | 56 | 90 days later 57 | 58 | 59 | UPDATED->DELETED 60 | 61 | 62 | 63 | 64 | UPDATED->UPDATED 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /delete-stack.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | delete_stack 11 | 12 | 13 | after_existence 14 | 15 | no stack 16 | 17 | 18 | deletable_stack 19 | 20 | stack 21 | (various states) 22 | 23 | 24 | DELETE_IN_PROGRESS 25 | 26 | DELETE_IN_PROGRESS 27 | 28 | 29 | deletable_stack->DELETE_IN_PROGRESS 30 | 31 | 32 | 33 | 34 | DELETE_COMPLETE 35 | 36 | DELETE_COMPLETE 37 | 38 | 39 | DELETE_COMPLETE->after_existence 40 | 41 | 42 | 90 days later 43 | 44 | 45 | DELETE_FAILED 46 | 47 | DELETE_FAILED 48 | 49 | 50 | DELETE_FAILED->deletable_stack 51 | 52 | 53 | 54 | 55 | try_delete 56 | 57 | Try deleting each resource 58 | that has not already been 59 | deleted (but see also the 60 | DeletionPolicy) 61 | 62 | 63 | DELETE_IN_PROGRESS->try_delete 64 | 65 | 66 | 67 | 68 | check_delete 69 | 70 | Did the deletes 71 | all succeed? 72 | 73 | 74 | try_delete->check_delete 75 | 76 | 77 | 78 | 79 | check_delete->DELETE_COMPLETE 80 | 81 | 82 | yes 83 | 84 | 85 | check_delete->DELETE_FAILED 86 | 87 | 88 | no 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | AWS CloudFormation Stack States 2 | =============================== 3 | 4 | The [AWS CloudFormation documentation](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html) 5 | includes a [list of all the possible stack states](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-describing-stacks.html): 6 | 7 | * `CREATE_COMPLETE` 8 | * `CREATE_IN_PROGRESS` 9 | * `CREATE_FAILED` 10 | * `DELETE_COMPLETE` 11 | * `DELETE_FAILED` 12 | * `DELETE_IN_PROGRESS` 13 | * `REVIEW_IN_PROGRESS` 14 | * `ROLLBACK_COMPLETE` 15 | * `ROLLBACK_FAILED` 16 | * `ROLLBACK_IN_PROGRESS` 17 | * `UPDATE_COMPLETE` 18 | * `UPDATE_COMPLETE_CLEANUP_IN_PROGRESS` 19 | * `UPDATE_IN_PROGRESS` 20 | * `UPDATE_ROLLBACK_COMPLETE` 21 | * `UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS` 22 | * `UPDATE_ROLLBACK_FAILED` 23 | * `UPDATE_ROLLBACK_IN_PROGRESS` 24 | 25 | However, it does not make it clear how the states relate to each other. 26 | 27 | This document aims to rectify that. 28 | 29 | *Caveat lector*: This document reflects *my understanding* of AWS 30 | CloudFormation. It is not definitive. I do not work for AWS. I've been 31 | using CloudFormation for a few years now, but there are features of it that 32 | I've not yet used. For all of those reasons, this document may not be 100% 33 | accurate. 34 | 35 | But I hope that it's helpful. 36 | 37 | With that said, let's get going. 38 | 39 | High-Level View 40 | --------------- 41 | 42 | At a high level, the lifecycle of a stack is: 43 | 44 | * the stack initially does not exist; 45 | * the stack is created; 46 | * the stack is updated (0 or more times); 47 | * the stack is deleted; 48 | * the stack finally does not exist. 49 | 50 | which you can visualise as follows: 51 | 52 | ![(diagram)](toplevel.png) 53 | 54 | However, "CREATED", "UPDATED" and "DELETED" are not real stack states – just a 55 | simplified model. So let's talk specifics. 56 | 57 | The Happy Path 58 | -------------- 59 | 60 | If we ignore all the error cases, the state diagram is as follows: 61 | 62 | ![(diagram)](happy.png) 63 | 64 | * the stack initially does not exist; 65 | * the stack is created: 66 | * by first passing through `CREATE_IN_PROGRESS` 67 | * before coming to rest at `CREATE_COMPLETE`; 68 | * zero or more times, the stack is updated, where each update consists of: 69 | * first passing through `UPDATE_IN_PROGRESS` 70 | * then passing through `UPDATE_COMPLETE_CLEANUP_IN_PROGRESS` 71 | * before coming to rest at `UPDATE_COMPLETE`; 72 | * the stack is deleted: 73 | * by first passing through `DELETE_IN_PROGRESS` 74 | * before coming to rest at `DELETE_COMPLETE`; 75 | * the stack finally does not exist. 76 | 77 | A couple of things to note here: 78 | 79 | Firstly, each stack state can be considered either to be "in motion" (all the stacks named `..._IN_PROGRESS`), or "at rest" (everything else). 80 | 81 | Secondly, note that once a stack has been deleted (`DELETE_COMPLETE`), the 82 | stack remains present in AWS CloudFormation for the next 90 days, so that the 83 | stack's metadata and events (log) can be inspected. After 90 days, the stack 84 | disappears from CloudFormation. 85 | 86 | There's also the `REVIEW_IN_PROGRESS` state, which (when used) sits right near the top, 87 | just after "the stack initially does not exist", but before 88 | `CREATE_IN_PROGRESS`. `REVIEW_IN_PROGRESS` is used if the stack is created 89 | via a change set. 90 | 91 | But: what about the error cases? 92 | 93 | Error Handling 94 | -------------- 95 | 96 | Let's complete the diagram by adding in all the states related to error 97 | handling: 98 | 99 | ![(diagram)](all-states.png) 100 | 101 | To make the diagram simpler, I've added a few "pseudo-states", to represent 102 | abstract concepts like "a stack is updateable". I've also assumed that some 103 | of the states that *can* be passed through are (in a manner of speaking) 104 | *always* passed through, even if the stack might spend zero time in that 105 | state. 106 | 107 | To break this down, let's look at how stacks are created, updated, and deleted. 108 | 109 | Change Sets 110 | ----------- 111 | 112 | Part of CloudFormation's job is to work out "how to get there from here" – 113 | what resource creations, updates and deletes need to happen, and in what 114 | order, to reach the requested outcome. 115 | 116 | The CreateStack, UpdateStack and DeleteStack API calls all make use of this 117 | approach: validate the request, work out what changes will be required, then 118 | make those changes. The [Change Sets API calls](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-changesets.html) 119 | can be used to inspect the planned changes before they are performed. 120 | 121 | The changes always break down into: 122 | 123 | * 0 or more resource creates / updates; 124 | * followed by 0 or more resource deletions. 125 | 126 | Some "updates" can be performed by updating the existing resources in-place; 127 | some work by doing a create of a new resource, then deleting the old one. 128 | 129 | If anything goes wrong, then CloudFormation may attempt to roll back to the 130 | previous steady state. This is done essentially by replaying the steps done 131 | so far, but in reverse order, and with the sense of all the changes reversed 132 | (create instead of delete, and vice versa). 133 | 134 | CreateStack 135 | ----------- 136 | 137 | For stack creation, the planned changes will always consist of resource 138 | creations only (no updates, no deletes): 139 | 140 | ![(diagram)](create-stack.png) 141 | 142 | If anything goes wrong, then any resources that *were* created need to be 143 | deleted (the `ROLLBACK_IN_PROGRESS` / `ROLLBACK_FAILED` / `ROLLBACK_COMPLETE` 144 | states). 145 | 146 | UpdateStack 147 | ----------- 148 | 149 | UpdateStack is the most complex case, because it may include resource creates, 150 | updates, and deletes. And if anything goes wrong, this means that the 151 | rollback too might involve deletes, updates, and creates: 152 | 153 | ![(diagram)](update-stack.png) 154 | 155 | If a stack reaches the `UPDATE_ROLLBACK_FAILED` state, the options are to 156 | attempt deletion (`DELETE_IN_PROGRESS`), re-attempt rollback 157 | (`UPDATE_ROLLBACK_IN_PROGRESS`), or to contact AWS support. See 158 | [the AWS blog post on "continue update rollback"](https://aws.amazon.com/blogs/devops/continue-rolling-back-an-update-for-aws-cloudformation-stacks-in-the-update_rollback_failed-state/) 159 | for more information. 160 | 161 | DeleteStack 162 | ----------- 163 | 164 | DeleteStack is reasonably straightforward; for each resource that is not 165 | already deleted, and for which the 166 | [DeletionPolicy](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-deletionpolicy.html) 167 | says to delete the resource, the resource deletion will be attempted. In case 168 | of problems, rollback (i.e. recreating resources) is *not* performed. 169 | 170 | ![(diagram)](delete-stack.png) 171 | 172 | If there are problems, the stack goes to the `DELETE_FAILED` state. Once the 173 | reason for the deletion failure has been identified and fixed, `DeleteStack` 174 | can be called again to re-try the deletion of any resources that have not yet 175 | been deleted. 176 | 177 | -------------------------------------------------------------------------------- /happy.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | happy 11 | 12 | 13 | 14 | before_existence 15 | 16 | no stack 17 | 18 | 19 | 20 | REVIEW_IN_PROGRESS 21 | 22 | REVIEW_IN_PROGRESS 23 | 24 | 25 | 26 | before_existence->REVIEW_IN_PROGRESS 27 | 28 | 29 | 30 | 31 | 32 | CREATE_IN_PROGRESS 33 | 34 | CREATE_IN_PROGRESS 35 | 36 | 37 | 38 | before_existence->CREATE_IN_PROGRESS 39 | 40 | 41 | 42 | 43 | 44 | after_existence 45 | 46 | no stack 47 | 48 | 49 | 50 | REVIEW_IN_PROGRESS->CREATE_IN_PROGRESS 51 | 52 | 53 | 54 | 55 | 56 | DELETE_COMPLETE 57 | 58 | DELETE_COMPLETE 59 | 60 | 61 | 62 | REVIEW_IN_PROGRESS->DELETE_COMPLETE 63 | 64 | 65 | 66 | 67 | 68 | CREATE_COMPLETE 69 | 70 | CREATE_COMPLETE 71 | 72 | 73 | 74 | DELETE_IN_PROGRESS 75 | 76 | DELETE_IN_PROGRESS 77 | 78 | 79 | 80 | CREATE_COMPLETE->DELETE_IN_PROGRESS 81 | 82 | 83 | 84 | 85 | 86 | UPDATE_IN_PROGRESS 87 | 88 | UPDATE_IN_PROGRESS 89 | 90 | 91 | 92 | CREATE_COMPLETE->UPDATE_IN_PROGRESS 93 | 94 | 95 | 96 | 97 | 98 | CREATE_IN_PROGRESS->CREATE_COMPLETE 99 | 100 | 101 | 102 | 103 | 104 | DELETE_COMPLETE->after_existence 105 | 106 | 107 | 90 days later 108 | 109 | 110 | 111 | DELETE_IN_PROGRESS->DELETE_COMPLETE 112 | 113 | 114 | 115 | 116 | 117 | UPDATE_COMPLETE 118 | 119 | UPDATE_COMPLETE 120 | 121 | 122 | 123 | UPDATE_COMPLETE->DELETE_IN_PROGRESS 124 | 125 | 126 | 127 | 128 | 129 | UPDATE_COMPLETE->UPDATE_IN_PROGRESS 130 | 131 | 132 | 133 | 134 | 135 | UPDATE_COMPLETE_CLEANUP_IN_PROGRESS 136 | 137 | UPDATE_COMPLETE 138 | CLEANUP_IN_PROGRESS 139 | 140 | 141 | 142 | UPDATE_COMPLETE_CLEANUP_IN_PROGRESS->UPDATE_COMPLETE 143 | 144 | 145 | 146 | 147 | 148 | UPDATE_IN_PROGRESS->UPDATE_COMPLETE_CLEANUP_IN_PROGRESS 149 | 150 | 151 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /create-stack.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | create_stack 11 | 12 | 13 | 14 | before_existence 15 | 16 | no stack 17 | 18 | 19 | 20 | REVIEW_IN_PROGRESS 21 | 22 | REVIEW_IN_PROGRESS 23 | 24 | 25 | 26 | before_existence->REVIEW_IN_PROGRESS 27 | 28 | 29 | 30 | 31 | 32 | CREATE_IN_PROGRESS 33 | 34 | CREATE_IN_PROGRESS 35 | 36 | 37 | 38 | before_existence->CREATE_IN_PROGRESS 39 | 40 | 41 | 42 | 43 | 44 | REVIEW_IN_PROGRESS->CREATE_IN_PROGRESS 45 | 46 | 47 | 48 | 49 | 50 | CREATE_COMPLETE 51 | 52 | CREATE_COMPLETE 53 | 54 | 55 | 56 | try_creates 57 | 58 | Try creating the resources 59 | (respecting the dependency order) 60 | 61 | 62 | 63 | CREATE_IN_PROGRESS->try_creates 64 | 65 | 66 | 67 | 68 | 69 | CREATE_FAILED 70 | 71 | CREATE_FAILED 72 | 73 | 74 | 75 | ROLLBACK_COMPLETE 76 | 77 | ROLLBACK_COMPLETE 78 | 79 | 80 | 81 | ROLLBACK_FAILED 82 | 83 | ROLLBACK_FAILED 84 | 85 | 86 | 87 | ROLLBACK_IN_PROGRESS 88 | 89 | ROLLBACK_IN_PROGRESS 90 | 91 | 92 | 93 | try_deletes 94 | 95 | Try deleting the resources 96 | (respecting the dependency order) 97 | 98 | 99 | 100 | ROLLBACK_IN_PROGRESS->try_deletes 101 | 102 | 103 | 104 | 105 | 106 | check_creates 107 | 108 | Did the creates all succeed? 109 | 110 | 111 | 112 | try_creates->check_creates 113 | 114 | 115 | 116 | 117 | 118 | check_creates->CREATE_COMPLETE 119 | 120 | 121 | yes 122 | 123 | 124 | 125 | do_we_need_rollback 126 | 127 | Did any of the creates succeed? 128 | 129 | 130 | 131 | check_creates->do_we_need_rollback 132 | 133 | 134 | no 135 | 136 | 137 | 138 | do_we_need_rollback->CREATE_FAILED 139 | 140 | 141 | no 142 | 143 | 144 | 145 | do_we_need_rollback->ROLLBACK_IN_PROGRESS 146 | 147 | 148 | yes 149 | 150 | 151 | 152 | check_deletes 153 | 154 | Did the deletes all succeed? 155 | 156 | 157 | 158 | try_deletes->check_deletes 159 | 160 | 161 | 162 | 163 | 164 | check_deletes->ROLLBACK_COMPLETE 165 | 166 | 167 | yes 168 | 169 | 170 | 171 | check_deletes->ROLLBACK_FAILED 172 | 173 | 174 | no 175 | 176 | 177 | 178 | -------------------------------------------------------------------------------- /update-stack.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | update_stack 11 | 12 | 13 | CREATE_COMPLETE 14 | 15 | CREATE_COMPLETE 16 | 17 | 18 | UPDATE_IN_PROGRESS 19 | 20 | UPDATE_IN_PROGRESS 21 | 22 | 23 | CREATE_COMPLETE->UPDATE_IN_PROGRESS 24 | 25 | 26 | 27 | 28 | UPDATE_COMPLETE 29 | 30 | UPDATE_COMPLETE 31 | 32 | 33 | UPDATE_COMPLETE->UPDATE_IN_PROGRESS 34 | 35 | 36 | 37 | 38 | UPDATE_COMPLETE_CLEANUP_IN_PROGRESS 39 | 40 | UPDATE_COMPLETE 41 | CLEANUP_IN_PROGRESS 42 | 43 | 44 | try_rollforward_cleanup 45 | 46 | Run the ROLLFORWARD plan 47 | (deletes) 48 | 49 | 50 | UPDATE_COMPLETE_CLEANUP_IN_PROGRESS->try_rollforward_cleanup 51 | 52 | 53 | 54 | 55 | try_rollforward_creates_and_updates 56 | 57 | Run the ROLLFORWARD plan 58 | (creates + updates) 59 | 60 | 61 | UPDATE_IN_PROGRESS->try_rollforward_creates_and_updates 62 | 63 | 64 | 65 | 66 | UPDATE_ROLLBACK_COMPLETE 67 | 68 | UPDATE_ROLLBACK_COMPLETE 69 | 70 | 71 | UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS 72 | 73 | UPDATE_ROLLBACK_COMPLETE 74 | CLEANUP_IN_PROGRESS 75 | 76 | 77 | try_rollback_cleanup 78 | 79 | Run the ROLLBACK plan 80 | (deletes) 81 | 82 | 83 | UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS->try_rollback_cleanup 84 | 85 | 86 | 87 | 88 | UPDATE_ROLLBACK_FAILED 89 | 90 | UPDATE_ROLLBACK_FAILED 91 | 92 | 93 | UPDATE_ROLLBACK_IN_PROGRESS 94 | 95 | UPDATE_ROLLBACK_IN_PROGRESS 96 | 97 | 98 | try_rollback_creates_and_updates 99 | 100 | Run the ROLLBACK plan 101 | (creates + updates) 102 | 103 | 104 | UPDATE_ROLLBACK_IN_PROGRESS->try_rollback_creates_and_updates 105 | 106 | 107 | 108 | 109 | check_rollforward_creates_and_updates 110 | 111 | Did the rollforward creates 112 | & updates all succeed? 113 | 114 | 115 | try_rollforward_creates_and_updates->check_rollforward_creates_and_updates 116 | 117 | 118 | 119 | 120 | check_rollforward_creates_and_updates->UPDATE_COMPLETE_CLEANUP_IN_PROGRESS 121 | 122 | 123 | yes (or no-op) 124 | 125 | 126 | check_rollforward_creates_and_updates->UPDATE_ROLLBACK_IN_PROGRESS 127 | 128 | 129 | no 130 | 131 | 132 | check_rollforward_cleanup 133 | 134 | Did the rollforward 135 | deletes all succeed? 136 | 137 | 138 | try_rollforward_cleanup->check_rollforward_cleanup 139 | 140 | 141 | 142 | 143 | check_rollforward_cleanup->UPDATE_ROLLBACK_IN_PROGRESS 144 | 145 | 146 | no 147 | 148 | 149 | UPDATE_COMPLETE_3 150 | 151 | UPDATE_COMPLETE 152 | 153 | 154 | check_rollforward_cleanup->UPDATE_COMPLETE_3 155 | 156 | 157 | yes (or no-op) 158 | 159 | 160 | check_rollback_creates_and_updates 161 | 162 | Did the rollback creates 163 | & updates all succeed? 164 | 165 | 166 | try_rollback_creates_and_updates->check_rollback_creates_and_updates 167 | 168 | 169 | 170 | 171 | check_rollback_creates_and_updates->UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS 172 | 173 | 174 | yes (or no-op) 175 | 176 | 177 | check_rollback_creates_and_updates->UPDATE_ROLLBACK_FAILED 178 | 179 | 180 | no 181 | 182 | 183 | check_rollback_cleanup 184 | 185 | Did the rollback 186 | deletes all succeed? 187 | 188 | 189 | try_rollback_cleanup->check_rollback_cleanup 190 | 191 | 192 | 193 | 194 | check_rollback_cleanup->UPDATE_ROLLBACK_COMPLETE 195 | 196 | 197 | yes (or no-op) 198 | 199 | 200 | check_rollback_cleanup->UPDATE_ROLLBACK_FAILED 201 | 202 | 203 | no 204 | 205 | 206 | 207 | -------------------------------------------------------------------------------- /all-states.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | all_states 12 | 13 | 14 | 15 | before_existence 16 | 17 | no stack 18 | 19 | 20 | 21 | REVIEW_IN_PROGRESS 22 | 23 | REVIEW_IN_PROGRESS 24 | 25 | 26 | 27 | before_existence->REVIEW_IN_PROGRESS 28 | 29 | 30 | 31 | 32 | 33 | CREATE_IN_PROGRESS 34 | 35 | CREATE_IN_PROGRESS 36 | 37 | 38 | 39 | before_existence->CREATE_IN_PROGRESS 40 | 41 | 42 | 43 | 44 | 45 | after_existence 46 | 47 | no stack 48 | 49 | 50 | 51 | updateable_stack 52 | 53 | an updateable stack 54 | (various states) 55 | 56 | 57 | 58 | DELETE_IN_PROGRESS 59 | 60 | DELETE_IN_PROGRESS 61 | 62 | 63 | 64 | updateable_stack->DELETE_IN_PROGRESS 65 | 66 | 67 | 68 | 69 | 70 | UPDATE_IN_PROGRESS 71 | 72 | UPDATE_IN_PROGRESS 73 | 74 | 75 | 76 | updateable_stack->UPDATE_IN_PROGRESS 77 | 78 | 79 | 80 | 81 | 82 | DELETE_COMPLETE 83 | 84 | DELETE_COMPLETE 85 | 86 | 87 | 88 | DELETE_IN_PROGRESS->DELETE_COMPLETE 89 | 90 | 91 | 92 | 93 | 94 | CREATE_COMPLETE 95 | 96 | CREATE_COMPLETE 97 | 98 | 99 | 100 | CREATE_COMPLETE->updateable_stack 101 | 102 | 103 | 104 | 105 | 106 | REVIEW_IN_PROGRESS->CREATE_IN_PROGRESS 107 | 108 | 109 | 110 | 111 | 112 | REVIEW_IN_PROGRESS->DELETE_COMPLETE 113 | 114 | 115 | 116 | 117 | 118 | CREATE_IN_PROGRESS->CREATE_COMPLETE 119 | 120 | 121 | 122 | 123 | 124 | DELETE_COMPLETE->after_existence 125 | 126 | 127 | 90 days later 128 | 129 | 130 | 131 | UPDATE_COMPLETE 132 | 133 | UPDATE_COMPLETE 134 | 135 | 136 | 137 | UPDATE_COMPLETE->updateable_stack 138 | 139 | 140 | 141 | 142 | 143 | UPDATE_COMPLETE_CLEANUP_IN_PROGRESS 144 | 145 | UPDATE_COMPLETE 146 | CLEANUP_IN_PROGRESS 147 | 148 | 149 | 150 | UPDATE_COMPLETE_CLEANUP_IN_PROGRESS->UPDATE_COMPLETE 151 | 152 | 153 | 154 | 155 | 156 | UPDATE_IN_PROGRESS->UPDATE_COMPLETE_CLEANUP_IN_PROGRESS 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | all_states 165 | 166 | 167 | 168 | stuck_stack 169 | 170 | a non-updateable stack 171 | (various states) 172 | 173 | 174 | 175 | stuck_stack->DELETE_IN_PROGRESS 176 | 177 | 178 | 179 | 180 | 181 | empty_stack 182 | 183 | non-deleted stack 184 | with no extant resources 185 | (various states) 186 | 187 | 188 | 189 | empty_stack->DELETE_IN_PROGRESS 190 | 191 | 192 | 193 | 194 | 195 | DELETE_FAILED 196 | 197 | DELETE_FAILED 198 | 199 | 200 | 201 | DELETE_IN_PROGRESS->DELETE_FAILED 202 | 203 | 204 | 205 | 206 | 207 | CREATE_FAILED 208 | 209 | CREATE_FAILED 210 | 211 | 212 | 213 | CREATE_IN_PROGRESS->CREATE_FAILED 214 | 215 | 216 | 217 | 218 | 219 | ROLLBACK_IN_PROGRESS 220 | 221 | ROLLBACK_IN_PROGRESS 222 | 223 | 224 | 225 | CREATE_IN_PROGRESS->ROLLBACK_IN_PROGRESS 226 | 227 | 228 | 229 | 230 | 231 | CREATE_FAILED->empty_stack 232 | 233 | 234 | 235 | 236 | 237 | DELETE_FAILED->stuck_stack 238 | 239 | 240 | 241 | 242 | 243 | ROLLBACK_COMPLETE 244 | 245 | ROLLBACK_COMPLETE 246 | 247 | 248 | 249 | ROLLBACK_COMPLETE->empty_stack 250 | 251 | 252 | 253 | 254 | 255 | ROLLBACK_FAILED 256 | 257 | ROLLBACK_FAILED 258 | 259 | 260 | 261 | ROLLBACK_FAILED->stuck_stack 262 | 263 | 264 | 265 | 266 | 267 | ROLLBACK_IN_PROGRESS->ROLLBACK_COMPLETE 268 | 269 | 270 | 271 | 272 | 273 | ROLLBACK_IN_PROGRESS->ROLLBACK_FAILED 274 | 275 | 276 | 277 | 278 | 279 | UPDATE_ROLLBACK_IN_PROGRESS 280 | 281 | UPDATE_ROLLBACK_IN_PROGRESS 282 | 283 | 284 | 285 | UPDATE_COMPLETE_CLEANUP_IN_PROGRESS->UPDATE_ROLLBACK_IN_PROGRESS 286 | 287 | 288 | 289 | 290 | 291 | UPDATE_IN_PROGRESS->UPDATE_ROLLBACK_IN_PROGRESS 292 | 293 | 294 | 295 | 296 | 297 | UPDATE_ROLLBACK_COMPLETE 298 | 299 | UPDATE_ROLLBACK_COMPLETE 300 | 301 | 302 | 303 | UPDATE_ROLLBACK_COMPLETE->updateable_stack 304 | 305 | 306 | 307 | 308 | 309 | UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS 310 | 311 | UPDATE_ROLLBACK_COMPLETE 312 | CLEANUP_IN_PROGRESS 313 | 314 | 315 | 316 | UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS->UPDATE_ROLLBACK_COMPLETE 317 | 318 | 319 | 320 | 321 | 322 | UPDATE_ROLLBACK_FAILED 323 | 324 | UPDATE_ROLLBACK_FAILED 325 | 326 | 327 | 328 | UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS->UPDATE_ROLLBACK_FAILED 329 | 330 | 331 | 332 | 333 | 334 | UPDATE_ROLLBACK_FAILED->stuck_stack 335 | 336 | 337 | 338 | 339 | 340 | UPDATE_ROLLBACK_FAILED->UPDATE_ROLLBACK_IN_PROGRESS 341 | 342 | 343 | 344 | 345 | 346 | UPDATE_ROLLBACK_IN_PROGRESS->UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS 347 | 348 | 349 | 350 | 351 | 352 | UPDATE_ROLLBACK_IN_PROGRESS->UPDATE_ROLLBACK_FAILED 353 | 354 | 355 | 356 | 357 | 358 | 359 | --------------------------------------------------------------------------------