-
Notifications
You must be signed in to change notification settings - Fork 4.1k
/
Copy pathprepare-app.ts
105 lines (90 loc) · 3.66 KB
/
prepare-app.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import { ConstructOrder } from 'constructs';
import { CfnResource } from '../cfn-resource';
import { IConstruct } from '../construct-compat';
import { Stack } from '../stack';
import { Stage } from '../stage';
import { resolveReferences } from './refs';
/**
* Prepares the app for synthesis. This function is called by the root `prepare`
* (normally this the App, but if a Stack is a root, it is called by the stack),
* which means it's the last 'prepare' that executes.
*
* It takes care of reifying cross-references between stacks (or nested stacks),
* and of creating assets for nested stack templates.
*
* @param root The root of the construct tree.
*/
export function prepareApp(root: IConstruct) {
// apply dependencies between resources in depending subtrees
for (const dependency of root.node.dependencies) {
const targetCfnResources = findCfnResources(dependency.target);
const sourceCfnResources = findCfnResources(dependency.source);
for (const target of targetCfnResources) {
for (const source of sourceCfnResources) {
source.addDependsOn(target);
}
}
}
resolveReferences(root);
// depth-first (children first) queue of nested stacks. We will pop a stack
// from the head of this queue to prepare its template asset.
//
// Depth-first since the a nested stack's template hash will be reflected in
// its parent's template, which then changes the parent's hash, etc.
const queue = findAllNestedStacks(root);
if (queue.length > 0) {
while (queue.length > 0) {
const nested = queue.shift()!;
defineNestedStackAsset(nested);
}
// ▷[ Given the legacy synthesizer and a 3-or-deeper nesting of nested stacks ]
//
// Adding nested stack assets may haved added CfnParameters to the top-level
// stack which are referenced in a deeper-level stack. The values of these
// parameters need to be carried through to the right location via Nested
// Stack parameters, which `resolveReferences()` will do.
//
// Yes, this may add `Parameter` elements to a template whose hash has
// already been calculated, but the invariant that if the functional part
// of the template changes its hash will change is still upheld.
resolveReferences(root);
}
}
/**
* Prepares the assets for nested stacks in this app.
* @returns `true` if assets were added to the parent of a nested stack, which
* implies that another round of reference resolution is in order. If this
* function returns `false`, we know we are done.
*/
function defineNestedStackAsset(nestedStack: Stack) {
// this is needed temporarily until we move NestedStack to '@aws-cdk/core'.
const nested: INestedStackPrivateApi = nestedStack as any;
nested._prepareTemplateAsset();
}
function findAllNestedStacks(root: IConstruct) {
const result = new Array<Stack>();
const includeStack = (stack: IConstruct): stack is Stack => {
if (!Stack.isStack(stack)) { return false; }
if (!stack.nested) { return false; }
// test: if we are not within a stage, then include it.
if (!Stage.of(stack)) { return true; }
return Stage.of(stack) === root;
};
// create a list of all nested stacks in depth-first post order this means
// that we first prepare the leaves and then work our way up.
for (const stack of root.node.findAll(ConstructOrder.POSTORDER /* <== important */)) {
if (includeStack(stack)) {
result.push(stack);
}
}
return result;
}
/**
* Find all resources in a set of constructs
*/
function findCfnResources(root: IConstruct): CfnResource[] {
return root.node.findAll().filter(CfnResource.isCfnResource);
}
interface INestedStackPrivateApi {
_prepareTemplateAsset(): boolean;
}