@fjall/deploy-core 0.89.5 → 0.94.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +50 -21
- package/README.md +25 -0
- package/dist/.minified +1 -0
- package/dist/src/__test-utils__/awsMockHelpers.d.ts +20 -0
- package/dist/src/__test-utils__/awsMockHelpers.js +1 -0
- package/dist/src/__test-utils__/index.d.ts +1 -0
- package/dist/src/__test-utils__/index.js +1 -0
- package/dist/src/aws/AwsProvider.js +0 -1
- package/dist/src/aws/SimpleAwsProvider.js +1 -70
- package/dist/src/aws/index.d.ts +4 -2
- package/dist/src/aws/index.js +1 -3
- package/dist/src/aws/organisations/accounts.js +10 -10
- package/dist/src/aws/organisations/backup.js +4 -2
- package/dist/src/aws/organisations/costAllocation.js +4 -2
- package/dist/src/aws/organisations/delegatedAdmin.d.ts +9 -0
- package/dist/src/aws/organisations/delegatedAdmin.js +43 -0
- package/dist/src/aws/organisations/identityCentre.d.ts +1 -1
- package/dist/src/aws/organisations/identityCentre.js +6 -2
- package/dist/src/aws/organisations/index.d.ts +4 -3
- package/dist/src/aws/organisations/index.js +1 -12
- package/dist/src/aws/organisations/ipam.js +4 -2
- package/dist/src/aws/organisations/organisation.js +27 -18
- package/dist/src/aws/organisations/organisationalUnits.d.ts +26 -6
- package/dist/src/aws/organisations/organisationalUnits.js +149 -35
- package/dist/src/aws/organisations/policies.js +4 -3
- package/dist/src/aws/organisations/ram.js +6 -2
- package/dist/src/aws/organisations/serviceAccess.js +12 -6
- package/dist/src/aws/organisations/trustedAccess.js +6 -2
- package/dist/src/aws/organisations/types.d.ts +23 -1
- package/dist/src/aws/organisations/types.js +1 -16
- package/dist/src/aws/utils/__tests__/cloudformationTestHelpers.d.ts +6 -0
- package/dist/src/aws/utils/__tests__/cloudformationTestHelpers.js +1 -0
- package/dist/src/aws/utils/cloudformationEventHelpers.d.ts +48 -0
- package/dist/src/aws/utils/cloudformationEventHelpers.js +1 -0
- package/dist/src/aws/utils/cloudformationEventTypes.d.ts +45 -0
- package/dist/src/aws/utils/cloudformationEventTypes.js +1 -0
- package/dist/src/aws/utils/cloudformationEvents.d.ts +8 -54
- package/dist/src/aws/utils/cloudformationEvents.js +1 -596
- package/dist/src/aws/utils/index.d.ts +5 -0
- package/dist/src/aws/utils/index.js +1 -0
- package/dist/src/aws/utils/stackStatus.js +1 -90
- package/dist/src/events/index.d.ts +13 -0
- package/dist/src/events/index.js +1 -0
- package/dist/src/index.d.ts +34 -17
- package/dist/src/index.js +41 -21
- package/dist/src/orchestration/__tests__/cascadeTestHelpers.d.ts +12 -0
- package/dist/src/orchestration/__tests__/cascadeTestHelpers.js +78 -0
- package/dist/src/orchestration/activeDeploymentGuard.d.ts +10 -0
- package/dist/src/orchestration/activeDeploymentGuard.js +39 -0
- package/dist/src/orchestration/applicationDeploy.js +46 -229
- package/dist/src/orchestration/applicationDeployHelpers.d.ts +39 -0
- package/dist/src/orchestration/applicationDeployHelpers.js +223 -0
- package/dist/src/orchestration/applicationDestroy.d.ts +14 -0
- package/dist/src/orchestration/applicationDestroy.js +131 -0
- package/dist/src/orchestration/builders/dockerBuilder.d.ts +17 -0
- package/dist/src/orchestration/builders/dockerBuilder.js +98 -0
- package/dist/src/orchestration/builders/frameworkRegistry.d.ts +23 -0
- package/dist/src/orchestration/builders/frameworkRegistry.js +1 -0
- package/dist/src/orchestration/builders/index.d.ts +4 -0
- package/dist/src/orchestration/builders/index.js +1 -0
- package/dist/src/orchestration/builders/openNextBuilder.d.ts +21 -0
- package/dist/src/orchestration/builders/openNextBuilder.js +144 -0
- package/dist/src/orchestration/cascadeDestroyHelpers.d.ts +30 -0
- package/dist/src/orchestration/cascadeDestroyHelpers.js +1 -0
- package/dist/src/orchestration/cascadeHelpers.d.ts +46 -0
- package/dist/src/orchestration/cascadeHelpers.js +160 -0
- package/dist/src/orchestration/contextHelpers.d.ts +46 -2
- package/dist/src/orchestration/contextHelpers.js +93 -1
- package/dist/src/orchestration/destroy.d.ts +13 -0
- package/dist/src/orchestration/destroy.js +67 -0
- package/dist/src/orchestration/detectionPipeline.d.ts +2 -11
- package/dist/src/orchestration/detectionPipeline.js +29 -10
- package/dist/src/orchestration/dockerBuildHelper.d.ts +10 -0
- package/dist/src/orchestration/dockerBuildHelper.js +49 -0
- package/dist/src/orchestration/dockerInterface.d.ts +4 -2
- package/dist/src/orchestration/index.d.ts +8 -1
- package/dist/src/orchestration/index.js +1 -3
- package/dist/src/orchestration/manifestSecretParser.d.ts +11 -0
- package/dist/src/orchestration/manifestSecretParser.js +1 -0
- package/dist/src/orchestration/openNextBuild.d.ts +28 -0
- package/dist/src/orchestration/openNextBuild.js +243 -0
- package/dist/src/orchestration/organisationDeploy.js +110 -233
- package/dist/src/orchestration/organisationDestroy.d.ts +24 -0
- package/dist/src/orchestration/organisationDestroy.js +189 -0
- package/dist/src/orchestration/organisationSetup.d.ts +6 -4
- package/dist/src/orchestration/organisationSetup.js +28 -8
- package/dist/src/orchestration/resolveOperation.js +68 -6
- package/dist/src/orchestration/serviceFactory.d.ts +4 -0
- package/dist/src/orchestration/serviceFactory.js +1 -16
- package/dist/src/orchestration/spawnHelpers.d.ts +47 -0
- package/dist/src/orchestration/spawnHelpers.js +1 -0
- package/dist/src/orchestration/stackCleanup.d.ts +39 -0
- package/dist/src/orchestration/stackCleanup.js +1 -0
- package/dist/src/orchestration/welcomeImageHelper.d.ts +15 -0
- package/dist/src/orchestration/welcomeImageHelper.js +64 -0
- package/dist/src/services/application/ApplicationStackService.d.ts +21 -30
- package/dist/src/services/application/ApplicationStackService.js +16 -234
- package/dist/src/services/application/applicationStackHelpers.d.ts +46 -0
- package/dist/src/services/application/applicationStackHelpers.js +248 -0
- package/dist/src/services/application/index.d.ts +1 -0
- package/dist/src/services/application/index.js +1 -1
- package/dist/src/services/index.d.ts +6 -0
- package/dist/src/services/index.js +1 -0
- package/dist/src/services/infrastructure/CdkArgumentBuilder.js +1 -67
- package/dist/src/services/infrastructure/CdkCommandRunner.d.ts +10 -2
- package/dist/src/services/infrastructure/CdkCommandRunner.js +18 -15
- package/dist/src/services/infrastructure/CdkErrorFormatter.js +16 -194
- package/dist/src/services/infrastructure/CdkEventMonitoring.js +1 -41
- package/dist/src/services/infrastructure/CdkOutputAnalyser.js +1 -1
- package/dist/src/services/infrastructure/CdkOutputParser.js +2 -33
- package/dist/src/services/infrastructure/CdkProcessManager.d.ts +5 -0
- package/dist/src/services/infrastructure/CdkProcessManager.js +81 -47
- package/dist/src/services/infrastructure/CdkService.d.ts +7 -53
- package/dist/src/services/infrastructure/CdkService.js +41 -83
- package/dist/src/services/infrastructure/CdkServiceTypes.d.ts +50 -0
- package/dist/src/services/infrastructure/CdkServiceTypes.js +0 -0
- package/dist/src/services/infrastructure/CloudFormationService.js +9 -10
- package/dist/src/services/infrastructure/ICdkProcessManager.d.ts +27 -0
- package/dist/src/services/infrastructure/ICdkProcessManager.js +1 -0
- package/dist/src/services/infrastructure/__tests__/cloudFormationTestHelpers.d.ts +9 -0
- package/dist/src/services/infrastructure/__tests__/cloudFormationTestHelpers.js +1 -0
- package/dist/src/services/infrastructure/cdkServiceHelpers.d.ts +9 -0
- package/dist/src/services/infrastructure/cdkServiceHelpers.js +1 -0
- package/dist/src/services/infrastructure/constructMapEnrichment.d.ts +7 -0
- package/dist/src/services/infrastructure/constructMapEnrichment.js +1 -0
- package/dist/src/services/infrastructure/index.d.ts +3 -1
- package/dist/src/services/infrastructure/index.js +1 -7
- package/dist/src/services/supporting/TemplateHashService.js +1 -1
- package/dist/src/services/supporting/helpers.js +1 -81
- package/dist/src/services/supporting/index.js +1 -3
- package/dist/src/steps/index.d.ts +1 -0
- package/dist/src/steps/index.js +1 -0
- package/dist/src/steps/stepRegistry.d.ts +71 -0
- package/dist/src/steps/stepRegistry.js +505 -0
- package/dist/src/types/FjallState.js +1 -118
- package/dist/src/types/ProgressEvent.js +1 -48
- package/dist/src/types/application/ApplicationServiceTypes.js +1 -30
- package/dist/src/types/application/index.js +1 -1
- package/dist/src/types/callbacks.d.ts +76 -4
- package/dist/src/types/callbacks.js +0 -1
- package/dist/src/types/constants.d.ts +2 -0
- package/dist/src/types/constants.js +1 -6
- package/dist/src/types/credentials.js +0 -1
- package/dist/src/types/deployment/DeploymentServiceTypes.d.ts +5 -2
- package/dist/src/types/deployment/DeploymentServiceTypes.js +1 -1
- package/dist/src/types/deployment/DeploymentTypes.js +0 -1
- package/dist/src/types/deployment/cloudformation.js +0 -1
- package/dist/src/types/deployment/index.d.ts +3 -1
- package/dist/src/types/deployment/index.js +1 -1
- package/dist/src/types/deployment/parallel.js +1 -10
- package/dist/src/types/deploymentEventSchema.d.ts +158 -0
- package/dist/src/types/deploymentEventSchema.js +1 -0
- package/dist/src/types/detection.d.ts +22 -0
- package/dist/src/types/detection.js +1 -0
- package/dist/src/types/entitlements.d.ts +31 -0
- package/dist/src/types/entitlements.js +0 -0
- package/dist/src/types/errors/CdkError.js +1 -20
- package/dist/src/types/errors/ServiceError.d.ts +2 -1
- package/dist/src/types/errors/ServiceError.js +1 -119
- package/dist/src/types/errors/index.d.ts +2 -0
- package/dist/src/types/errors/index.js +1 -0
- package/dist/src/types/events.d.ts +3 -9
- package/dist/src/types/events.js +0 -5
- package/dist/src/types/frameworkBuilder.d.ts +96 -0
- package/dist/src/types/frameworkBuilder.js +8 -0
- package/dist/src/types/index.d.ts +19 -4
- package/dist/src/types/index.js +1 -9
- package/dist/src/types/operations.d.ts +3 -2
- package/dist/src/types/operations.js +1 -285
- package/dist/src/types/orgConfig.d.ts +2 -10
- package/dist/src/types/orgConfig.js +0 -11
- package/dist/src/types/params.d.ts +60 -1
- package/dist/src/types/patternDetection.d.ts +14 -16
- package/dist/src/types/patternDetection.js +14 -18
- package/dist/src/types/patternTypes.d.ts +19 -0
- package/dist/src/types/patternTypes.js +1 -0
- package/dist/src/types/stepDefinitions.d.ts +163 -0
- package/dist/src/types/stepDefinitions.js +98 -0
- package/dist/src/types/validation.js +0 -1
- package/dist/src/util/dockerfileDetection.d.ts +5 -0
- package/dist/src/util/dockerfileDetection.js +1 -0
- package/dist/src/util/index.d.ts +4 -3
- package/dist/src/util/index.js +1 -3
- package/dist/src/util/sequencedCallbacks.d.ts +44 -0
- package/dist/src/util/sequencedCallbacks.js +1 -0
- package/package.json +49 -8
- package/dist/src/aws/utils/CloudFormationFailureAnalyser.d.ts +0 -32
- package/dist/src/aws/utils/CloudFormationFailureAnalyser.js +0 -228
- package/dist/src/aws/utils/errors.d.ts +0 -26
- package/dist/src/aws/utils/errors.js +0 -59
- package/dist/src/util/fsHelpers.d.ts +0 -4
- package/dist/src/util/fsHelpers.js +0 -16
- package/dist/src/util/securityHelpers.d.ts +0 -31
- package/dist/src/util/securityHelpers.js +0 -124
- package/dist/src/util/singleton.d.ts +0 -2
- package/dist/src/util/singleton.js +0 -9
- package/dist/src/util/sleep.d.ts +0 -4
- package/dist/src/util/sleep.js +0 -4
|
@@ -2,8 +2,8 @@ import { spawn } from "child_process";
|
|
|
2
2
|
import { existsSync } from "fs";
|
|
3
3
|
import { join } from "path";
|
|
4
4
|
import { createRequire } from "module";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { logger } from "@fjall/util/logger";
|
|
6
|
+
import { filterDangerousEnvVars, maskSensitiveOutput } from "@fjall/util";
|
|
7
7
|
import { success, failure } from "@fjall/generator";
|
|
8
8
|
import { getErrorMessage } from "@fjall/util";
|
|
9
9
|
/**
|
|
@@ -17,8 +17,8 @@ function getCdkBinaryPath() {
|
|
|
17
17
|
const cdkEntry = require.resolve("aws-cdk/bin/cdk");
|
|
18
18
|
return { command: process.execPath, prefixArgs: [cdkEntry] };
|
|
19
19
|
}
|
|
20
|
-
catch {
|
|
21
|
-
logger.debug("CdkService", "Failed to resolve aws-cdk binary, falling back to npx");
|
|
20
|
+
catch (err) {
|
|
21
|
+
logger.debug("CdkService", "Failed to resolve aws-cdk binary, falling back to npx", { error: err instanceof Error ? err.message : String(err) });
|
|
22
22
|
return { command: "npx", prefixArgs: ["cdk"] };
|
|
23
23
|
}
|
|
24
24
|
}
|
|
@@ -29,28 +29,36 @@ export class CdkProcessManager {
|
|
|
29
29
|
runningProcesses = new Map();
|
|
30
30
|
processCounter = 0;
|
|
31
31
|
argBuilder;
|
|
32
|
+
exitHandler;
|
|
33
|
+
sigintHandler;
|
|
34
|
+
sigtermHandler;
|
|
32
35
|
constructor(argBuilder) {
|
|
33
36
|
this.argBuilder = argBuilder;
|
|
34
|
-
// Register cleanup handlers
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
// Register cleanup handlers (stored for deregistration)
|
|
38
|
+
this.exitHandler = () => this.cleanup();
|
|
39
|
+
this.sigintHandler = () => {
|
|
37
40
|
this.cleanup();
|
|
38
41
|
process.exit(130);
|
|
39
|
-
}
|
|
40
|
-
|
|
42
|
+
};
|
|
43
|
+
this.sigtermHandler = () => {
|
|
41
44
|
this.cleanup();
|
|
42
45
|
process.exit(143);
|
|
43
|
-
}
|
|
46
|
+
};
|
|
47
|
+
process.on("exit", this.exitHandler);
|
|
48
|
+
process.on("SIGINT", this.sigintHandler);
|
|
49
|
+
process.on("SIGTERM", this.sigtermHandler);
|
|
44
50
|
}
|
|
45
51
|
forceKillProcess(child) {
|
|
46
52
|
child.stdout?.destroy();
|
|
47
53
|
child.stderr?.destroy();
|
|
48
54
|
child.kill("SIGTERM");
|
|
49
|
-
setTimeout(() => {
|
|
55
|
+
const killTimer = setTimeout(() => {
|
|
50
56
|
if (child.exitCode === null) {
|
|
51
57
|
child.kill("SIGKILL");
|
|
52
58
|
}
|
|
53
59
|
}, SIGKILL_GRACE_PERIOD_MS);
|
|
60
|
+
killTimer.unref();
|
|
61
|
+
child.once("exit", () => clearTimeout(killTimer));
|
|
54
62
|
}
|
|
55
63
|
cleanup() {
|
|
56
64
|
for (const [_name, child] of this.runningProcesses) {
|
|
@@ -62,6 +70,12 @@ export class CdkProcessManager {
|
|
|
62
70
|
}
|
|
63
71
|
this.runningProcesses.clear();
|
|
64
72
|
}
|
|
73
|
+
dispose() {
|
|
74
|
+
this.cleanup();
|
|
75
|
+
process.removeListener("exit", this.exitHandler);
|
|
76
|
+
process.removeListener("SIGINT", this.sigintHandler);
|
|
77
|
+
process.removeListener("SIGTERM", this.sigtermHandler);
|
|
78
|
+
}
|
|
65
79
|
async runCdkCommandPassthrough(workingDir, args, options) {
|
|
66
80
|
return new Promise((resolve) => {
|
|
67
81
|
if (!existsSync(workingDir)) {
|
|
@@ -85,25 +99,38 @@ export class CdkProcessManager {
|
|
|
85
99
|
shell: false,
|
|
86
100
|
detached: false
|
|
87
101
|
});
|
|
102
|
+
if (!child.pid) {
|
|
103
|
+
child.on("error", (err) => {
|
|
104
|
+
logger.debug("CdkProcess", "Spawn error on failed child process", {
|
|
105
|
+
error: err.message
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
resolve(failure(`Failed to spawn CDK process - no PID. cwd=${workingDir}, args=${fullArgs.join(" ")}`));
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
88
111
|
// Track process for cleanup
|
|
89
|
-
const processId = `cdk-passthrough-${
|
|
112
|
+
const processId = `cdk-passthrough-${++this.processCounter}`;
|
|
90
113
|
this.runningProcesses.set(processId, child);
|
|
114
|
+
let processKilled = false;
|
|
115
|
+
let settled = false;
|
|
91
116
|
// Timeout to prevent indefinite hangs (default 30 minutes, matching deploy)
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
resolve(failure(`CDK command timed out after ${Math.floor(timeout / 60000)} minutes`));
|
|
100
|
-
}
|
|
101
|
-
}, timeout);
|
|
102
|
-
}
|
|
117
|
+
const timeoutMs = options?.timeout ?? 30 * 60 * 1000;
|
|
118
|
+
const timeoutHandle = setTimeout(() => {
|
|
119
|
+
if (!child.killed) {
|
|
120
|
+
processKilled = true;
|
|
121
|
+
this.forceKillProcess(child);
|
|
122
|
+
}
|
|
123
|
+
}, timeoutMs);
|
|
103
124
|
child.on("close", (code) => {
|
|
104
|
-
|
|
105
|
-
clearTimeout(timeoutHandle);
|
|
125
|
+
clearTimeout(timeoutHandle);
|
|
106
126
|
this.runningProcesses.delete(processId);
|
|
127
|
+
if (settled)
|
|
128
|
+
return;
|
|
129
|
+
settled = true;
|
|
130
|
+
if (processKilled) {
|
|
131
|
+
resolve(failure("CDK command timed out"));
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
107
134
|
if (code === 0 || options?.ignoreExitCode) {
|
|
108
135
|
resolve(success({ exitCode: code || 0 }));
|
|
109
136
|
}
|
|
@@ -112,9 +139,11 @@ export class CdkProcessManager {
|
|
|
112
139
|
}
|
|
113
140
|
});
|
|
114
141
|
child.on("error", (err) => {
|
|
115
|
-
|
|
116
|
-
clearTimeout(timeoutHandle);
|
|
142
|
+
clearTimeout(timeoutHandle);
|
|
117
143
|
this.runningProcesses.delete(processId);
|
|
144
|
+
if (settled || processKilled)
|
|
145
|
+
return;
|
|
146
|
+
settled = true;
|
|
118
147
|
resolve(failure(`Failed to run CDK command: ${err.message}`));
|
|
119
148
|
});
|
|
120
149
|
});
|
|
@@ -161,8 +190,10 @@ export class CdkProcessManager {
|
|
|
161
190
|
// CRITICAL: Attach error handler to prevent uncaught exception
|
|
162
191
|
// Node.js emits an async 'error' event on the child process even after spawn fails
|
|
163
192
|
// If we don't handle it, it becomes an uncaught exception and crashes the app
|
|
164
|
-
child.on("error", () => {
|
|
165
|
-
|
|
193
|
+
child.on("error", (err) => {
|
|
194
|
+
logger.debug("CdkProcess", "Deferred spawn error on failed child process", {
|
|
195
|
+
error: err.message
|
|
196
|
+
});
|
|
166
197
|
});
|
|
167
198
|
resolve(failure(spawnError));
|
|
168
199
|
return;
|
|
@@ -170,15 +201,14 @@ export class CdkProcessManager {
|
|
|
170
201
|
// Track process for cleanup
|
|
171
202
|
const processId = `cdk-${++this.processCounter}`;
|
|
172
203
|
this.runningProcesses.set(processId, child);
|
|
173
|
-
let
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
}
|
|
204
|
+
let settled = false;
|
|
205
|
+
const timeoutMs = options?.timeout ?? 30 * 60 * 1000;
|
|
206
|
+
const timeoutHandle = setTimeout(() => {
|
|
207
|
+
if (!child.killed) {
|
|
208
|
+
processKilled = true;
|
|
209
|
+
this.forceKillProcess(child);
|
|
210
|
+
}
|
|
211
|
+
}, timeoutMs);
|
|
182
212
|
child.stdout?.on("data", (data) => {
|
|
183
213
|
const chunk = data.toString();
|
|
184
214
|
output += chunk;
|
|
@@ -202,15 +232,19 @@ export class CdkProcessManager {
|
|
|
202
232
|
}
|
|
203
233
|
});
|
|
204
234
|
child.on("error", (error) => {
|
|
205
|
-
|
|
206
|
-
clearTimeout(timeoutHandle);
|
|
235
|
+
clearTimeout(timeoutHandle);
|
|
207
236
|
this.runningProcesses.delete(processId);
|
|
237
|
+
if (settled || processKilled)
|
|
238
|
+
return;
|
|
239
|
+
settled = true;
|
|
208
240
|
resolve(failure(getErrorMessage(error)));
|
|
209
241
|
});
|
|
210
242
|
child.on("close", (code) => {
|
|
211
|
-
|
|
212
|
-
clearTimeout(timeoutHandle);
|
|
243
|
+
clearTimeout(timeoutHandle);
|
|
213
244
|
this.runningProcesses.delete(processId);
|
|
245
|
+
if (settled)
|
|
246
|
+
return;
|
|
247
|
+
settled = true;
|
|
214
248
|
if (processKilled) {
|
|
215
249
|
resolve(failure("CDK command timed out"));
|
|
216
250
|
return;
|
|
@@ -219,25 +253,25 @@ export class CdkProcessManager {
|
|
|
219
253
|
// For diff command, we need to include stderr in output since CDK outputs errors there
|
|
220
254
|
const combinedOutput = output + (errorOutput ? `\n${errorOutput}` : "");
|
|
221
255
|
if (exitedClean) {
|
|
256
|
+
const rawOutput = options?.combineOutput ? combinedOutput : output;
|
|
222
257
|
resolve(success({
|
|
223
|
-
output:
|
|
258
|
+
output: maskSensitiveOutput(rawOutput),
|
|
224
259
|
exitCode: code || 0
|
|
225
260
|
}));
|
|
226
261
|
return;
|
|
227
262
|
}
|
|
228
|
-
// Parse error output for meaningful messages
|
|
263
|
+
// Parse error output for meaningful messages (match on raw before masking)
|
|
229
264
|
let errorMessage = errorOutput;
|
|
230
265
|
if (output) {
|
|
231
|
-
// Try to extract error from CDK output
|
|
232
266
|
const errorMatch = output.match(/❌.*?Error:(.*)$/m);
|
|
233
267
|
if (errorMatch) {
|
|
234
|
-
errorMessage = errorMatch[1]
|
|
268
|
+
errorMessage = errorMatch[1]?.trim() ?? "";
|
|
235
269
|
}
|
|
236
270
|
}
|
|
237
271
|
// Include stdout in the error string so callers can pattern-match on combined output
|
|
238
272
|
const errorText = errorMessage || `CDK command failed with exit code ${code}`;
|
|
239
273
|
const fullError = output ? `${errorText}\n${output}` : errorText;
|
|
240
|
-
resolve(failure(fullError));
|
|
274
|
+
resolve(failure(maskSensitiveOutput(fullError)));
|
|
241
275
|
});
|
|
242
276
|
});
|
|
243
277
|
}
|
|
@@ -1,72 +1,26 @@
|
|
|
1
1
|
import { type ResourceEvent } from "../../aws/utils/cloudformationEvents.js";
|
|
2
|
-
import type { DeploymentContext } from "../../types/deployment/DeploymentTypes.js";
|
|
3
|
-
import type { StepOutput } from "../../types/deployment/DeploymentTypes.js";
|
|
2
|
+
import type { DeploymentContext, StepOutput } from "../../types/deployment/DeploymentTypes.js";
|
|
4
3
|
import type { AwsProvider } from "../../aws/AwsProvider.js";
|
|
5
4
|
import type { Result } from "@fjall/generator";
|
|
6
5
|
import type { CdkError } from "../../types/errors/CdkError.js";
|
|
7
|
-
import type { EventLogWriterFactory } from "../../aws/utils/cloudformationEvents.js";
|
|
8
6
|
import { type CheckDifferencesResult } from "./CdkCommandRunner.js";
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
region?: string;
|
|
12
|
-
environment?: string;
|
|
13
|
-
stackName?: string;
|
|
14
|
-
managedAccount?: boolean;
|
|
15
|
-
accountName?: string;
|
|
16
|
-
imageVersion?: string;
|
|
17
|
-
orgId?: string;
|
|
18
|
-
rootId?: string;
|
|
19
|
-
managementAccountId?: string;
|
|
20
|
-
ipamPoolId?: string;
|
|
21
|
-
fjallOrgId?: string;
|
|
22
|
-
fjallOidcConfigured?: string;
|
|
23
|
-
orgConfig?: string;
|
|
24
|
-
}
|
|
25
|
-
export interface CdkOptions {
|
|
26
|
-
verbose?: boolean;
|
|
27
|
-
noPrompt?: boolean;
|
|
28
|
-
outputCallback?: (output: string) => void;
|
|
29
|
-
errorCallback?: (error: string) => void;
|
|
30
|
-
context?: CdkContext;
|
|
31
|
-
timeout?: number;
|
|
32
|
-
passThroughCDK?: boolean;
|
|
33
|
-
stacks?: string[];
|
|
34
|
-
noLookups?: boolean;
|
|
35
|
-
useCdkOut?: boolean;
|
|
36
|
-
credentials?: {
|
|
37
|
-
accessKeyId: string;
|
|
38
|
-
secretAccessKey: string;
|
|
39
|
-
sessionToken?: string;
|
|
40
|
-
};
|
|
41
|
-
outputDir?: string;
|
|
42
|
-
appDir?: string;
|
|
43
|
-
cdkOutputLogger?: {
|
|
44
|
-
writeCdkOutput(stream: "stdout" | "stderr", chunk: string): void;
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
export interface CdkOutput {
|
|
48
|
-
output?: string;
|
|
49
|
-
exitCode?: number;
|
|
50
|
-
}
|
|
51
|
-
export interface CdkServiceOptions {
|
|
52
|
-
eventLogWriterFactory?: EventLogWriterFactory;
|
|
53
|
-
}
|
|
7
|
+
import type { CdkOptions, CdkOutput, CdkServiceOptions } from "./CdkServiceTypes.js";
|
|
8
|
+
export type { CdkContext, CdkOptions, CdkOutput, CdkServiceOptions } from "./CdkServiceTypes.js";
|
|
54
9
|
export { type CheckDifferencesResult } from "./CdkCommandRunner.js";
|
|
55
10
|
export declare class CdkService {
|
|
56
11
|
private commandRunner;
|
|
57
12
|
private eventMonitor;
|
|
58
13
|
constructor(options?: CdkServiceOptions);
|
|
14
|
+
dispose(): void;
|
|
59
15
|
checkDifferences(path: string, stackName?: string, options?: CdkOptions): Promise<Result<CheckDifferencesResult, CdkError>>;
|
|
60
16
|
deploy(path: string, stackName?: string, options?: CdkOptions): Promise<Result<CdkOutput, string>>;
|
|
61
17
|
destroy(path: string, stackName?: string, options?: CdkOptions): Promise<Result<CdkOutput, string>>;
|
|
62
18
|
runImport(path: string, resourceMappingFile?: string, options?: CdkOptions): Promise<Result<CdkOutput, string>>;
|
|
63
19
|
synth(path: string, options?: CdkOptions): Promise<Result<CdkOutput, string>>;
|
|
64
20
|
bootstrap(accountId: string, region: string, options?: CdkOptions): Promise<Result<CdkOutput, string>>;
|
|
65
|
-
private resolveStackName;
|
|
66
|
-
private buildDeploymentCdkContext;
|
|
67
21
|
runCdkSynth(context: DeploymentContext, onOutput?: (chunk: string) => void): Promise<Result<StepOutput, string>>;
|
|
68
|
-
runCdkBootstrap(context: DeploymentContext, onOutput?: (chunk: string) => void): Promise<Result<StepOutput, string>>;
|
|
22
|
+
runCdkBootstrap(context: DeploymentContext, onOutput?: (chunk: string) => void, credentials?: CdkOptions["credentials"]): Promise<Result<StepOutput, string>>;
|
|
69
23
|
runCdkDiff(context: DeploymentContext, onOutput?: (chunk: string) => void): Promise<Result<StepOutput, string>>;
|
|
70
|
-
runCdkDeploy(context: DeploymentContext, stackPattern?: string, onOutput?: (chunk: string) => void, onResourceProgress?: (event: ResourceEvent) => void, aws?: AwsProvider): Promise<Result<StepOutput, string>>;
|
|
71
|
-
runCdkDestroy(context: DeploymentContext, stackPattern?: string, onOutput?: (chunk: string) => void, onResourceProgress?: (event: ResourceEvent) => void, aws?: AwsProvider, useCdkOut?: boolean): Promise<Result<StepOutput, string>>;
|
|
24
|
+
runCdkDeploy(context: DeploymentContext, stackPattern?: string, onOutput?: (chunk: string) => void, onResourceProgress?: (event: ResourceEvent) => void, aws?: AwsProvider, credentials?: CdkOptions["credentials"]): Promise<Result<StepOutput, string>>;
|
|
25
|
+
runCdkDestroy(context: DeploymentContext, stackPattern?: string, onOutput?: (chunk: string) => void, onResourceProgress?: (event: ResourceEvent) => void, aws?: AwsProvider, useCdkOut?: boolean, credentials?: CdkOptions["credentials"]): Promise<Result<StepOutput, string>>;
|
|
72
26
|
}
|
|
@@ -1,24 +1,30 @@
|
|
|
1
1
|
import { existsSync } from "fs";
|
|
2
2
|
import { join } from "path";
|
|
3
|
-
import { logger } from "@fjall/util";
|
|
3
|
+
import { logger } from "@fjall/util/logger";
|
|
4
4
|
import { success, failure } from "@fjall/generator";
|
|
5
5
|
import { DEFAULT_REGION } from "../../aws/utils/regions.js";
|
|
6
|
-
import {
|
|
7
|
-
import { getErrorMessage } from "@fjall/util";
|
|
6
|
+
import { getErrorMessage, maskSensitiveOutput } from "@fjall/util";
|
|
8
7
|
import { CdkEventMonitor, startStackMonitoring } from "./CdkEventMonitoring.js";
|
|
9
8
|
import { analyseDeployOutput, analyseDestroyResult, createEnhancedOutputCallback } from "./CdkOutputAnalyser.js";
|
|
10
9
|
import { CdkCommandRunner } from "./CdkCommandRunner.js";
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
import { CdkArgumentBuilder } from "./CdkArgumentBuilder.js";
|
|
11
|
+
import { CdkProcessManager } from "./CdkProcessManager.js";
|
|
12
|
+
import { wrapWithConstructMapEnrichment } from "./constructMapEnrichment.js";
|
|
13
|
+
import { STACK_DETECTION_FALLBACK_MS, resolveStackName, getFallbackStackName, buildDeploymentCdkContext } from "./cdkServiceHelpers.js";
|
|
13
14
|
export class CdkService {
|
|
14
15
|
commandRunner;
|
|
15
16
|
eventMonitor;
|
|
16
17
|
constructor(options) {
|
|
17
|
-
|
|
18
|
+
const processManager = options?.processManager ??
|
|
19
|
+
new CdkProcessManager(new CdkArgumentBuilder());
|
|
20
|
+
this.commandRunner = new CdkCommandRunner(processManager);
|
|
18
21
|
this.eventMonitor = new CdkEventMonitor({
|
|
19
22
|
eventLogWriterFactory: options?.eventLogWriterFactory
|
|
20
23
|
});
|
|
21
24
|
}
|
|
25
|
+
dispose() {
|
|
26
|
+
this.commandRunner.dispose();
|
|
27
|
+
}
|
|
22
28
|
// Delegate low-level commands to CdkCommandRunner
|
|
23
29
|
async checkDifferences(path, stackName, options) {
|
|
24
30
|
return this.commandRunner.checkDifferences(path, stackName, options);
|
|
@@ -38,48 +44,12 @@ export class CdkService {
|
|
|
38
44
|
async bootstrap(accountId, region, options) {
|
|
39
45
|
return this.commandRunner.bootstrap(accountId, region, options);
|
|
40
46
|
}
|
|
41
|
-
resolveStackName(stackPattern, context) {
|
|
42
|
-
if (stackPattern && !stackPattern.includes("*")) {
|
|
43
|
-
return stackPattern;
|
|
44
|
-
}
|
|
45
|
-
if (stackPattern) {
|
|
46
|
-
const stackTypeMatch = stackPattern.match(/\*?(\w+)\*?/);
|
|
47
|
-
if (stackTypeMatch) {
|
|
48
|
-
const stackType = stackTypeMatch[1];
|
|
49
|
-
const appName = context.target || "app";
|
|
50
|
-
return isApplicationStack(stackType)
|
|
51
|
-
? getApplicationStackName(appName, stackType)
|
|
52
|
-
: `${appName}${stackType}`;
|
|
53
|
-
}
|
|
54
|
-
return stackPattern;
|
|
55
|
-
}
|
|
56
|
-
return undefined;
|
|
57
|
-
}
|
|
58
|
-
buildDeploymentCdkContext(context, accountId, region, options) {
|
|
59
|
-
const environment = undefined;
|
|
60
|
-
return {
|
|
61
|
-
accountId,
|
|
62
|
-
region,
|
|
63
|
-
environment,
|
|
64
|
-
managedAccount: context.isManagedAccount,
|
|
65
|
-
...(options?.includeImageVersion !== false && {
|
|
66
|
-
imageVersion: context.imageVersion
|
|
67
|
-
}),
|
|
68
|
-
orgId: context.orgId,
|
|
69
|
-
rootId: context.rootId,
|
|
70
|
-
managementAccountId: context.managementAccountId,
|
|
71
|
-
ipamPoolId: context.ipamPoolId,
|
|
72
|
-
fjallOrgId: context.fjallOrgId,
|
|
73
|
-
fjallOidcConfigured: context.fjallOidcConfigured ? "true" : undefined,
|
|
74
|
-
orgConfig: context.orgConfig
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
47
|
async runCdkSynth(context, onOutput) {
|
|
78
48
|
const accountId = context.callerIdentity?.Account;
|
|
79
49
|
try {
|
|
80
50
|
const result = await this.synth(context.path, {
|
|
81
51
|
outputCallback: onOutput,
|
|
82
|
-
context:
|
|
52
|
+
context: buildDeploymentCdkContext(context, accountId, context.region || DEFAULT_REGION)
|
|
83
53
|
});
|
|
84
54
|
if (!result.success) {
|
|
85
55
|
return failure(result.error || "Failed to synthesise CloudFormation template");
|
|
@@ -95,7 +65,7 @@ export class CdkService {
|
|
|
95
65
|
return failure(`CDK synth failed: ${getErrorMessage(error)}`);
|
|
96
66
|
}
|
|
97
67
|
}
|
|
98
|
-
async runCdkBootstrap(context, onOutput) {
|
|
68
|
+
async runCdkBootstrap(context, onOutput, credentials) {
|
|
99
69
|
const accountId = context.callerIdentity?.Account;
|
|
100
70
|
const region = context.region || DEFAULT_REGION;
|
|
101
71
|
try {
|
|
@@ -107,7 +77,8 @@ export class CdkService {
|
|
|
107
77
|
return failure(`Dependencies not installed. Please run 'npm install' in ${context.path} before deploying.`);
|
|
108
78
|
}
|
|
109
79
|
const result = await this.bootstrap(accountId, region, {
|
|
110
|
-
outputCallback: onOutput
|
|
80
|
+
outputCallback: onOutput,
|
|
81
|
+
credentials
|
|
111
82
|
});
|
|
112
83
|
if (!result.success) {
|
|
113
84
|
return failure(result.error || "Failed to bootstrap AWS environment");
|
|
@@ -124,7 +95,7 @@ export class CdkService {
|
|
|
124
95
|
const result = await this.checkDifferences(context.path, undefined, {
|
|
125
96
|
verbose: context.options?.verbose,
|
|
126
97
|
outputCallback: onOutput,
|
|
127
|
-
context:
|
|
98
|
+
context: buildDeploymentCdkContext(context, accountId, context.region || DEFAULT_REGION)
|
|
128
99
|
});
|
|
129
100
|
if (!result.success) {
|
|
130
101
|
return failure(`CDK diff failed: ${result.error.message}`);
|
|
@@ -141,7 +112,7 @@ export class CdkService {
|
|
|
141
112
|
return failure(`CDK diff failed: ${getErrorMessage(error)}`);
|
|
142
113
|
}
|
|
143
114
|
}
|
|
144
|
-
async runCdkDeploy(context, stackPattern, onOutput, onResourceProgress, aws) {
|
|
115
|
+
async runCdkDeploy(context, stackPattern, onOutput, onResourceProgress, aws, credentials) {
|
|
145
116
|
const accountId = context.callerIdentity?.Account;
|
|
146
117
|
const region = context.region || DEFAULT_REGION;
|
|
147
118
|
if (!accountId) {
|
|
@@ -150,23 +121,16 @@ export class CdkService {
|
|
|
150
121
|
if (!aws) {
|
|
151
122
|
return failure("AwsProvider is required for deployment monitoring.");
|
|
152
123
|
}
|
|
124
|
+
// Read construct map from fjall-manifest.json (written during synth)
|
|
125
|
+
const enrichedOnResourceProgress = wrapWithConstructMapEnrichment(context.path, onResourceProgress);
|
|
153
126
|
let cfnMonitor = null;
|
|
154
127
|
let fallbackMonitoringTimeout;
|
|
155
128
|
try {
|
|
156
|
-
const targetStackName =
|
|
157
|
-
(
|
|
158
|
-
const deployType = context.deployType;
|
|
159
|
-
if (deployType === "organisation" ||
|
|
160
|
-
deployType === "platform" ||
|
|
161
|
-
deployType === "account") {
|
|
162
|
-
return getOrganisationStackName(deployType);
|
|
163
|
-
}
|
|
164
|
-
const appName = context.target || "app";
|
|
165
|
-
return `${appName}Network`;
|
|
166
|
-
})();
|
|
129
|
+
const targetStackName = resolveStackName(stackPattern, context) ??
|
|
130
|
+
getFallbackStackName(context);
|
|
167
131
|
cfnMonitor = await this.eventMonitor.createEventMonitor("deploy", targetStackName, region, context, aws);
|
|
168
132
|
if (onOutput) {
|
|
169
|
-
onOutput(`Starting CloudFormation deployment of ${targetStackName}...\n`);
|
|
133
|
+
onOutput(maskSensitiveOutput(`Starting CloudFormation deployment of ${targetStackName}...\n`));
|
|
170
134
|
onOutput(`Monitoring CloudFormation events (CDK process running in background)...\n`);
|
|
171
135
|
}
|
|
172
136
|
const state = {
|
|
@@ -175,7 +139,7 @@ export class CdkService {
|
|
|
175
139
|
stackDetected: false,
|
|
176
140
|
monitoringPromise: null
|
|
177
141
|
};
|
|
178
|
-
const enhancedOutputCallback = createEnhancedOutputCallback(state, onOutput, cfnMonitor,
|
|
142
|
+
const enhancedOutputCallback = createEnhancedOutputCallback(state, onOutput, cfnMonitor, enrichedOnResourceProgress);
|
|
179
143
|
// Fall back to predicted stack name if actual name not detected in time
|
|
180
144
|
fallbackMonitoringTimeout = setTimeout(() => {
|
|
181
145
|
if (!state.stackDetected && cfnMonitor && !state.monitoringPromise) {
|
|
@@ -184,7 +148,7 @@ export class CdkService {
|
|
|
184
148
|
stackDetected: state.stackDetected,
|
|
185
149
|
hasOnResourceProgress: !!onResourceProgress
|
|
186
150
|
});
|
|
187
|
-
state.monitoringPromise = startStackMonitoring(cfnMonitor, targetStackName,
|
|
151
|
+
state.monitoringPromise = startStackMonitoring(cfnMonitor, targetStackName, enrichedOnResourceProgress);
|
|
188
152
|
}
|
|
189
153
|
}, STACK_DETECTION_FALLBACK_MS);
|
|
190
154
|
const result = await this.deploy(context.path, targetStackName, {
|
|
@@ -192,37 +156,31 @@ export class CdkService {
|
|
|
192
156
|
outputCallback: enhancedOutputCallback,
|
|
193
157
|
useCdkOut: true,
|
|
194
158
|
cdkOutputLogger: cfnMonitor?.getEventLogger() ?? undefined,
|
|
195
|
-
context:
|
|
159
|
+
context: buildDeploymentCdkContext(context, accountId, region),
|
|
160
|
+
credentials
|
|
196
161
|
});
|
|
197
|
-
clearTimeout(fallbackMonitoringTimeout);
|
|
198
|
-
if (cfnMonitor) {
|
|
199
|
-
logger.debug("CdkService", "CDK process exited, stopping monitor", {
|
|
200
|
-
targetStackName,
|
|
201
|
-
stackDetected: state.stackDetected,
|
|
202
|
-
hadMonitoringPromise: !!state.monitoringPromise
|
|
203
|
-
});
|
|
204
|
-
cfnMonitor.stopMonitoring();
|
|
205
|
-
}
|
|
206
162
|
return analyseDeployOutput(state.cdkOutput, result, state.actualStackName);
|
|
207
163
|
}
|
|
208
164
|
catch (error) {
|
|
209
|
-
clearTimeout(fallbackMonitoringTimeout);
|
|
210
|
-
if (cfnMonitor) {
|
|
211
|
-
cfnMonitor.stopMonitoring();
|
|
212
|
-
}
|
|
213
165
|
const errorMsg = `CDK deploy failed: ${getErrorMessage(error)}`;
|
|
214
166
|
logger.error("CdkService", "CDK deployment exception", {
|
|
215
167
|
error: errorMsg
|
|
216
168
|
});
|
|
217
169
|
return failure(errorMsg);
|
|
218
170
|
}
|
|
171
|
+
finally {
|
|
172
|
+
clearTimeout(fallbackMonitoringTimeout);
|
|
173
|
+
if (cfnMonitor) {
|
|
174
|
+
cfnMonitor.stopMonitoring();
|
|
175
|
+
}
|
|
176
|
+
}
|
|
219
177
|
}
|
|
220
|
-
async runCdkDestroy(context, stackPattern, onOutput, onResourceProgress, aws, useCdkOut) {
|
|
178
|
+
async runCdkDestroy(context, stackPattern, onOutput, onResourceProgress, aws, useCdkOut, credentials) {
|
|
221
179
|
const accountId = context.callerIdentity?.Account;
|
|
222
180
|
const region = context.region || DEFAULT_REGION;
|
|
223
181
|
let cfnMonitor = null;
|
|
224
182
|
try {
|
|
225
|
-
const targetStackName =
|
|
183
|
+
const targetStackName = resolveStackName(stackPattern, context);
|
|
226
184
|
if (accountId && targetStackName && aws) {
|
|
227
185
|
cfnMonitor = await this.eventMonitor.createEventMonitor("destroy", targetStackName, region, context, aws);
|
|
228
186
|
cfnMonitor.startMonitoring(targetStackName, (event) => {
|
|
@@ -236,20 +194,20 @@ export class CdkService {
|
|
|
236
194
|
outputCallback: onOutput,
|
|
237
195
|
useCdkOut,
|
|
238
196
|
cdkOutputLogger: cfnMonitor?.getEventLogger() ?? undefined,
|
|
239
|
-
context:
|
|
197
|
+
context: buildDeploymentCdkContext(context, accountId, region, {
|
|
240
198
|
includeImageVersion: false
|
|
241
|
-
})
|
|
199
|
+
}),
|
|
200
|
+
credentials
|
|
242
201
|
});
|
|
243
|
-
if (cfnMonitor) {
|
|
244
|
-
cfnMonitor.stopMonitoring();
|
|
245
|
-
}
|
|
246
202
|
return analyseDestroyResult(result);
|
|
247
203
|
}
|
|
248
204
|
catch (error) {
|
|
205
|
+
return failure(`CDK destroy failed: ${getErrorMessage(error)}`);
|
|
206
|
+
}
|
|
207
|
+
finally {
|
|
249
208
|
if (cfnMonitor) {
|
|
250
209
|
cfnMonitor.stopMonitoring();
|
|
251
210
|
}
|
|
252
|
-
return failure(`CDK destroy failed: ${getErrorMessage(error)}`);
|
|
253
211
|
}
|
|
254
212
|
}
|
|
255
213
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { EventLogWriterFactory } from "../../aws/utils/cloudformationEvents.js";
|
|
2
|
+
import type { ICdkProcessManager } from "./ICdkProcessManager.js";
|
|
3
|
+
export interface CdkContext {
|
|
4
|
+
accountId?: string;
|
|
5
|
+
region?: string;
|
|
6
|
+
environment?: string;
|
|
7
|
+
managedAccount?: boolean;
|
|
8
|
+
accountName?: string;
|
|
9
|
+
imageVersion?: string;
|
|
10
|
+
orgId?: string;
|
|
11
|
+
rootId?: string;
|
|
12
|
+
managementAccountId?: string;
|
|
13
|
+
ipamPoolId?: string;
|
|
14
|
+
fjallOrgId?: string;
|
|
15
|
+
fjallOidcConfigured?: string;
|
|
16
|
+
orgConfig?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface CdkOptions {
|
|
19
|
+
verbose?: boolean;
|
|
20
|
+
noPrompt?: boolean;
|
|
21
|
+
outputCallback?: (output: string) => void;
|
|
22
|
+
errorCallback?: (error: string) => void;
|
|
23
|
+
context?: CdkContext;
|
|
24
|
+
timeout?: number;
|
|
25
|
+
passThroughCDK?: boolean;
|
|
26
|
+
stacks?: string[];
|
|
27
|
+
noLookups?: boolean;
|
|
28
|
+
useCdkOut?: boolean;
|
|
29
|
+
credentials?: {
|
|
30
|
+
accessKeyId: string;
|
|
31
|
+
secretAccessKey: string;
|
|
32
|
+
sessionToken?: string;
|
|
33
|
+
};
|
|
34
|
+
outputDir?: string;
|
|
35
|
+
appDir?: string;
|
|
36
|
+
cdkOutputLogger?: {
|
|
37
|
+
writeCdkOutput(stream: "stdout" | "stderr", chunk: string): void;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export interface CdkOutput {
|
|
41
|
+
output?: string;
|
|
42
|
+
exitCode?: number;
|
|
43
|
+
}
|
|
44
|
+
export interface CdkServiceOptions {
|
|
45
|
+
eventLogWriterFactory?: EventLogWriterFactory;
|
|
46
|
+
/** Optional process manager for CDK binary resolution. When provided, CdkCommandRunner
|
|
47
|
+
* uses this instead of creating its own CdkProcessManager (which relies on
|
|
48
|
+
* import.meta.url for binary resolution from deploy-core's node_modules). */
|
|
49
|
+
processManager?: ICdkProcessManager;
|
|
50
|
+
}
|
|
File without changes
|
|
@@ -2,9 +2,10 @@ import { CloudFormationClient, DeleteStackCommand, DescribeStacksCommand, ListEx
|
|
|
2
2
|
import { stackStatusMap } from "../../aws/utils/stackStatus.js";
|
|
3
3
|
import { success, failure } from "@fjall/generator";
|
|
4
4
|
import { BaseServiceError } from "../../types/errors/ServiceError.js";
|
|
5
|
-
import {
|
|
6
|
-
import { sleep } from "
|
|
7
|
-
import { STACK_NOT_FOUND_PATTERN } from "
|
|
5
|
+
import { logger } from "@fjall/util/logger";
|
|
6
|
+
import { getErrorMessage, sleep } from "@fjall/util";
|
|
7
|
+
import { STACK_NOT_FOUND_PATTERN } from "@fjall/util/aws";
|
|
8
|
+
import { extractErrorName } from "../../aws/organisations/types.js";
|
|
8
9
|
/**
|
|
9
10
|
* CloudFormation-specific error
|
|
10
11
|
*/
|
|
@@ -34,18 +35,16 @@ export class CloudFormationService {
|
|
|
34
35
|
* Classify an AWS SDK error into a typed CloudFormationError.
|
|
35
36
|
*/
|
|
36
37
|
classifyAwsError(error, fallbackMessage, stackName) {
|
|
37
|
-
const
|
|
38
|
-
? String(error.code)
|
|
39
|
-
: undefined;
|
|
38
|
+
const errorName = extractErrorName(error);
|
|
40
39
|
const errorMessage = getErrorMessage(error);
|
|
41
|
-
if (
|
|
40
|
+
if (errorName === "CredentialsError" || errorName === "UnauthorizedError") {
|
|
42
41
|
return new CloudFormationError(`AWS credentials error: ${errorMessage}`, "auth_error", stackName, undefined, error, false);
|
|
43
42
|
}
|
|
44
|
-
if (
|
|
45
|
-
|
|
43
|
+
if (errorName === "Throttling" ||
|
|
44
|
+
errorName === "TooManyRequestsException") {
|
|
46
45
|
return new CloudFormationError(`AWS rate limit exceeded: ${errorMessage}`, "throttled", stackName, undefined, error, true);
|
|
47
46
|
}
|
|
48
|
-
if (
|
|
47
|
+
if (errorName === "NetworkingError" || errorName === "ENOTFOUND") {
|
|
49
48
|
return new CloudFormationError(`Network error: ${errorMessage}`, "network_error", stackName, undefined, error, true);
|
|
50
49
|
}
|
|
51
50
|
return new CloudFormationError(`${fallbackMessage}: ${errorMessage}`, "unknown", stackName, undefined, error);
|