forked from anomalyco/sst
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathremove.mjs
More file actions
140 lines (120 loc) · 3.54 KB
/
Copy pathremove.mjs
File metadata and controls
140 lines (120 loc) · 3.54 KB
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
"use strict";
import path from "path";
import chalk from "chalk";
import { logger } from "@serverless-stack/core";
import paths from "./util/paths.mjs";
import {
synth,
writeConfig,
destroyInit,
destroyPoll,
} from "./util/cdkHelpers.mjs";
import { STACK_DESTROY_STATUS } from "@serverless-stack/core";
export default async function (argv, config, cliInfo) {
// Skip building functions on remove
await writeConfig({
...config,
skipBuild: true,
});
const { stack, debugStack } = argv;
// Case 1: --debug-stack is provided
if (debugStack) {
await removeDebugStack(config, cliInfo);
return;
}
// Case 2: a stack is provided
else if (stack) {
const stackId = stack && buildStackId(config, stack);
return await removeAppStacks(config, cliInfo, stackId);
}
// Case 3: remove all stacks and the debug stack
else {
await removeDebugStack(config, cliInfo);
return await removeAppStacks(config, cliInfo);
}
////////////////
// Remove app //
////////////////
}
async function removeDebugStack(config, cliInfo) {
logger.info(chalk.grey(`Removing debug stack`));
// Note: When removing the debug stack, the current working directory is user's app.
// Setting the current working directory to debug stack cdk app directory to allow
// Lambda Function construct be able to reference code with relative path.
process.chdir(path.join(paths.ownPath, "assets", "debug-stack"));
try {
await removeStacks({
...cliInfo.cdkOptions,
app: [
"node",
"bin/index.mjs",
config.name,
config.stage,
config.region,
`"${paths.appPath}"`,
].join(" "),
output: "cdk.out",
});
} finally {
// Note: Restore working directory
process.chdir(paths.appPath);
}
}
async function removeAppStacks(config, cliInfo, stackId) {
logger.info(chalk.grey("Removing " + (stackId ? stackId : "stacks")));
// Print remove result
const stackStates = await removeStacks(cliInfo.cdkOptions, stackId);
printResults(stackStates);
// Check all stacks deployed successfully
if (
stackStates.some(({ status }) => status === STACK_DESTROY_STATUS.FAILED)
) {
throw new Error(`Failed to remove the app`);
}
return stackStates.map((stackState) => ({
name: stackState.name,
status: stackState.status,
}));
}
async function removeStacks(cdkOptions, stackId) {
// Build
await synth(cdkOptions);
// Initialize destroy
let { stackStates, isCompleted } = await destroyInit(cdkOptions, stackId);
// Loop until remove is complete
do {
// Update remove status
const response = await destroyPoll(cdkOptions, stackStates);
stackStates = response.stackStates;
isCompleted = response.isCompleted;
// Wait for 5 seconds
if (!isCompleted) {
logger.info("Checking remove status...");
await new Promise((resolve) => setTimeout(resolve, 5000));
}
} while (!isCompleted);
return stackStates;
}
function printResults(stackStates) {
stackStates.forEach(({ name, status, errorMessage }) => {
logger.info(`\nStack ${name}`);
logger.info(` Status: ${formatStackStatus(status)}`);
if (errorMessage) {
logger.info(` Error: ${errorMessage}`);
}
});
logger.info("");
}
function buildStackId(config, stack) {
const stackPrefix = `${config.stage}-${config.name}-`;
return stack.startsWith(stackPrefix)
? stack
: `${stackPrefix}${stack}`;
}
function formatStackStatus(status) {
return {
succeeded: "removed",
failed: "failed",
skipped: "not removed",
}[status];
}