Skip to content

Commit 642dadc

Browse files
committed
add doc about destroying resources and ordering
1 parent fdab170 commit 642dadc

11 files changed

Lines changed: 287 additions & 0 deletions

‎docs/destroying.md‎

Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
# Terraform Core Resource Destruction Notes
2+
3+
This document intends to describe some of the details and complications
4+
involved in the destructions of resources. It covers the ordering defined for
5+
related create and destroy operations, as well as changes to the lifecycle
6+
ordering imposed by `create_before_destroy`. It is not intended to enumerate
7+
all possible combinations of dependency ordering, only to outline the basics
8+
and document some of the more complicated aspects of resource destruction.
9+
10+
The graph diagrams here will continue to use the inverted graph structure used
11+
internally by Terraform, where edges represent dependencies rather than order
12+
of operations.
13+
14+
## Simple Resource Creation
15+
16+
In order to describe resource destruction, we first need to create the
17+
resources and define their order. The order of creation is that which fulfills
18+
the dependencies for each resource. In this example, `A` has no dependencies,
19+
`B` depends on `A`, and `C` depends on `B`, and transitively depends on `A`.
20+
21+
![Simple Resource Creation](./images/simple_create.png)
22+
<!--
23+
digraph create {
24+
subgraph nodes {
25+
rank=same;
26+
a [label="A create"];
27+
b [label="B create"];
28+
c [label="C create"];
29+
b -> c [dir=back];
30+
a -> b [dir=back];
31+
}
32+
}
33+
-->
34+
35+
## Resource Updates
36+
37+
An existing resource may be updated with references to a newly created
38+
resource. The ordering here is exactly the same as one would expect for
39+
creation.
40+
41+
![Simple Resource Updates](./images/simple_update.png)
42+
<!--
43+
digraph update {
44+
subgraph nodes {
45+
rank=same;
46+
a [label="A create"];
47+
b [label="B update"];
48+
c [label="C update"];
49+
b -> c [dir=back];
50+
a -> b [dir=back];
51+
}
52+
}
53+
-->
54+
55+
## Simple Resource Destruction
56+
57+
The order for destroying resource is exactly the inverse used to create them.
58+
This example shows the graph for the destruction of the same nodes defined
59+
above. While destroy nodes will not contain attribute references, we will
60+
continue to use the inverted edges showing dependencies for destroy, so the
61+
operational ordering is still opposite the flow of the arrows.
62+
63+
![Simple Resource Destruction](./images/simple_destroy.png)
64+
<!--
65+
digraph destroy {
66+
subgraph nodes {
67+
rank=same;
68+
a [label="A destroy"];
69+
b [label="B destroy"];
70+
c [label="C destroy"];
71+
a -> b;
72+
b -> c;
73+
}
74+
}
75+
-->
76+
77+
78+
## Resource Replacement
79+
80+
Resource replacement is the logical combination of the above scenarios. Here we
81+
will show the replacement steps involved when `B` depends on `A`.
82+
83+
84+
In this first example, we simultaneously replace both `A` and `B`. Here `B` is
85+
destroyed before `A`, then `A` is recreated before `B`.
86+
87+
![Replace All](./images/replace_all.png)
88+
<!--
89+
digraph replacement {
90+
subgraph create {
91+
rank=same;
92+
a [label="A create"];
93+
b [label="B create"];
94+
a -> b [dir=back];
95+
}
96+
subgraph destroy {
97+
rank=same;
98+
a_d [label="A destroy"];
99+
b_d [label="B destroy"];
100+
a_d -> b_d;
101+
}
102+
103+
a -> a_d;
104+
b -> a_d [style=dotted];
105+
b -> b_d;
106+
}
107+
-->
108+
109+
110+
This second example replaces only `A`, while updating `B`. Resource `B` is only
111+
updated once `A` has been destroyed and recreated.
112+
113+
![Replace Dependency](./images/replace_one.png)
114+
<!--
115+
digraph replacement {
116+
subgraph create {
117+
rank=same;
118+
a [label="A create"];
119+
b [label="B update"];
120+
a -> b [dir=back];
121+
}
122+
subgraph destroy {
123+
rank=same;
124+
a_d [label="A destroy"];
125+
}
126+
127+
a -> a_d;
128+
b -> a_d [style=dotted];
129+
}
130+
-->
131+
132+
While the dependency edge from `B update` to `A destroy` isn't necessary in
133+
these examples, it is shown here as an implementation detail which will be
134+
mentioned later on.
135+
136+
## Create Before Destroy
137+
138+
Currently, the only user-controllable method for changing the ordering of
139+
create and destroy operations is with the `create_before_destroy` resource
140+
`lifecycle` attribute. This has the obvious effect of causing a resource to be
141+
created before it is destroyed when replacement is required, but has a couple
142+
of other effects we will detail here.
143+
144+
Taking the previous replacement examples, we can change the behavior of `A` to
145+
be that of `create_before_destroy`.
146+
147+
![Replace all, dependency is create_before_destroy](./images/replace_all_cbd_dep.png)
148+
<!--
149+
digraph replacement {
150+
subgraph create {
151+
rank=same;
152+
a [label="A create"];
153+
b [label="B create"];
154+
a -> b [dir=back];
155+
}
156+
subgraph destroy {
157+
rank=same;
158+
a_d [label="A destroy"];
159+
b_d [label="B destroy"];
160+
a_d -> b_d;
161+
}
162+
163+
a -> a_d [dir=back];
164+
b -> a_d [dir=back];
165+
b -> b_d;
166+
}
167+
-->
168+
169+
Note that in this first example, the creation of `B` is inserted in between the
170+
creation of `A` and the destruction of `A`. This becomes more important in the
171+
update example below.
172+
173+
174+
![Replace dependency, dependency is create_before_destroy](./images/replace_dep_cbd_dep.png)
175+
<!--
176+
digraph replacement {
177+
subgraph create {
178+
rank=same;
179+
a [label="A create"];
180+
b [label="B update"];
181+
a -> b [dir=back];
182+
}
183+
subgraph destroy {
184+
rank=same;
185+
a_d [label="A destroy"];
186+
}
187+
188+
a -> a_d [dir=back];
189+
b -> a_d [dir=back];
190+
}
191+
-->
192+
193+
Here we can see clearly how `B` is updated after the creation of `A` and before
194+
the destruction of `A`. To introduce another term, the prior resource `A` is
195+
sometimes referred to as "deposed" before it is destroyed, to disambiguate it
196+
from the newly created `A`.
197+
198+
The transformation used to create these graphs is also where we use the extra
199+
edges mentioned above connecting `B` to `A destroy`. The algorithm to change a
200+
resource from the default ordering to `create_before_destroy` simply inverts
201+
any incoming edges from other resources, which automatically creates the
202+
necessary dependency ordering for dependent updates. This also ensures that
203+
reduced versions of this example still adhere to the same ordering rules, such
204+
as when the dependency is only being removed:
205+
206+
![Update a destroyed create_before_destroy dependency](./images/update_destroy_cbd.png)
207+
<!--
208+
digraph update {
209+
subgraph create {
210+
rank=same;
211+
b [label="B update"];
212+
}
213+
subgraph destroy {
214+
rank=same;
215+
a_d [label="A destroy"];
216+
}
217+
218+
b -> a_d [dir=back];
219+
}
220+
-->
221+
222+
223+
### Forced Create Before Destroy
224+
225+
In the previous examples, only resource `A` was being used as is it were
226+
`create_before_destroy`. The minimal graphs used show that it works in
227+
isolation, but that is only when the `create_before_destroy` resource has no
228+
dependencies of it own. When a `create_before_resource` depends on another
229+
resource, that dependency is "infected" by the `create_before_destroy`
230+
lifecycle attribute.
231+
232+
This example demonstrates why forcing `create_before_destroy` is necessary. `B`
233+
has `create_before_destroy` while `A` does not. If we only invert the ordering
234+
for `B`, we can see that results in a cycle.
235+
236+
![Incorrect create_before_destroy replacement](./images/replace_cbd_incorrect.png)
237+
<!--
238+
digraph replacement {
239+
subgraph create {
240+
rank=same;
241+
a [label="A create"];
242+
b [label="B create"];
243+
a -> b [dir=back];
244+
}
245+
subgraph destroy {
246+
rank=same;
247+
a_d [label="A destroy"];
248+
b_d [label="B destroy"];
249+
a_d -> b_d;
250+
}
251+
252+
a -> a_d;
253+
b -> a_d [style=dotted];
254+
b -> b_d [dir=back];
255+
}
256+
-->
257+
258+
In order to resolve these cycles, and all resources that precede a resource
259+
with `create_before_destroy` must in turn be handled in the same manner.
260+
Reversing the incoming edged to `A destroy` resolves the problem:
261+
262+
![Correct create_before_destroy replacement](./images/replace_cbd_all.png)
263+
<!--
264+
digraph replacement {
265+
subgraph create {
266+
rank=same;
267+
a [label="A create"];
268+
b [label="B create"];
269+
a -> b [dir=back];
270+
}
271+
subgraph destroy {
272+
rank=same;
273+
a_d [label="A destroy"];
274+
b_d [label="B destroy"];
275+
a_d -> b_d;
276+
}
277+
278+
a -> a_d [dir=back];
279+
b -> a_d [dir=back];
280+
b -> b_d [dir=back];
281+
}
282+
-->
283+
284+
This also demonstrates why `create_before_destry` cannot be overridden when
285+
it is inherited; changing the behaviour here isn't possible without removing
286+
the initial reason for `create_before_destroy`; otherwise cycles are always
287+
introduced into the graph.

‎docs/images/replace_all.png‎

11.5 KB
Loading

‎docs/images/replace_all_cbd.png‎

11.5 KB
Loading
12 KB
Loading
11.5 KB
Loading
13 KB
Loading

‎docs/images/replace_one.png‎

12.7 KB
Loading

‎docs/images/simple_create.png‎

5.13 KB
Loading

‎docs/images/simple_destroy.png‎

5.78 KB
Loading

‎docs/images/simple_update.png‎

8.06 KB
Loading

0 commit comments

Comments
 (0)