@fjall/deploy-core 0.89.4 → 0.89.6
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.d.ts +2 -2
- package/dist/src/aws/AwsProvider.js +0 -1
- package/dist/src/aws/SimpleAwsProvider.d.ts +2 -3
- package/dist/src/aws/SimpleAwsProvider.js +1 -73
- 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 -224
- 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 +47 -2
- package/dist/src/orchestration/contextHelpers.js +94 -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 +130 -228
- 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 -52
- package/dist/src/services/infrastructure/CdkService.js +41 -82
- 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.d.ts +1 -1
- 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.d.ts +1 -0
- 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 +61 -0
- 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,71 +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
|
-
orgConfig?: string;
|
|
23
|
-
}
|
|
24
|
-
export interface CdkOptions {
|
|
25
|
-
verbose?: boolean;
|
|
26
|
-
noPrompt?: boolean;
|
|
27
|
-
outputCallback?: (output: string) => void;
|
|
28
|
-
errorCallback?: (error: string) => void;
|
|
29
|
-
context?: CdkContext;
|
|
30
|
-
timeout?: number;
|
|
31
|
-
passThroughCDK?: boolean;
|
|
32
|
-
stacks?: string[];
|
|
33
|
-
noLookups?: boolean;
|
|
34
|
-
useCdkOut?: boolean;
|
|
35
|
-
credentials?: {
|
|
36
|
-
accessKeyId: string;
|
|
37
|
-
secretAccessKey: string;
|
|
38
|
-
sessionToken?: string;
|
|
39
|
-
};
|
|
40
|
-
outputDir?: string;
|
|
41
|
-
appDir?: string;
|
|
42
|
-
cdkOutputLogger?: {
|
|
43
|
-
writeCdkOutput(stream: "stdout" | "stderr", chunk: string): void;
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
export interface CdkOutput {
|
|
47
|
-
output?: string;
|
|
48
|
-
exitCode?: number;
|
|
49
|
-
}
|
|
50
|
-
export interface CdkServiceOptions {
|
|
51
|
-
eventLogWriterFactory?: EventLogWriterFactory;
|
|
52
|
-
}
|
|
7
|
+
import type { CdkOptions, CdkOutput, CdkServiceOptions } from "./CdkServiceTypes.js";
|
|
8
|
+
export type { CdkContext, CdkOptions, CdkOutput, CdkServiceOptions } from "./CdkServiceTypes.js";
|
|
53
9
|
export { type CheckDifferencesResult } from "./CdkCommandRunner.js";
|
|
54
10
|
export declare class CdkService {
|
|
55
11
|
private commandRunner;
|
|
56
12
|
private eventMonitor;
|
|
57
13
|
constructor(options?: CdkServiceOptions);
|
|
14
|
+
dispose(): void;
|
|
58
15
|
checkDifferences(path: string, stackName?: string, options?: CdkOptions): Promise<Result<CheckDifferencesResult, CdkError>>;
|
|
59
16
|
deploy(path: string, stackName?: string, options?: CdkOptions): Promise<Result<CdkOutput, string>>;
|
|
60
17
|
destroy(path: string, stackName?: string, options?: CdkOptions): Promise<Result<CdkOutput, string>>;
|
|
61
18
|
runImport(path: string, resourceMappingFile?: string, options?: CdkOptions): Promise<Result<CdkOutput, string>>;
|
|
62
19
|
synth(path: string, options?: CdkOptions): Promise<Result<CdkOutput, string>>;
|
|
63
20
|
bootstrap(accountId: string, region: string, options?: CdkOptions): Promise<Result<CdkOutput, string>>;
|
|
64
|
-
private resolveStackName;
|
|
65
|
-
private buildDeploymentCdkContext;
|
|
66
21
|
runCdkSynth(context: DeploymentContext, onOutput?: (chunk: string) => void): Promise<Result<StepOutput, string>>;
|
|
67
|
-
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>>;
|
|
68
23
|
runCdkDiff(context: DeploymentContext, onOutput?: (chunk: string) => void): Promise<Result<StepOutput, string>>;
|
|
69
|
-
runCdkDeploy(context: DeploymentContext, stackPattern?: string, onOutput?: (chunk: string) => void, onResourceProgress?: (event: ResourceEvent) => void, aws?: AwsProvider): Promise<Result<StepOutput, string>>;
|
|
70
|
-
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>>;
|
|
71
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,47 +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
|
-
orgConfig: context.orgConfig
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
47
|
async runCdkSynth(context, onOutput) {
|
|
77
48
|
const accountId = context.callerIdentity?.Account;
|
|
78
49
|
try {
|
|
79
50
|
const result = await this.synth(context.path, {
|
|
80
51
|
outputCallback: onOutput,
|
|
81
|
-
context:
|
|
52
|
+
context: buildDeploymentCdkContext(context, accountId, context.region || DEFAULT_REGION)
|
|
82
53
|
});
|
|
83
54
|
if (!result.success) {
|
|
84
55
|
return failure(result.error || "Failed to synthesise CloudFormation template");
|
|
@@ -94,7 +65,7 @@ export class CdkService {
|
|
|
94
65
|
return failure(`CDK synth failed: ${getErrorMessage(error)}`);
|
|
95
66
|
}
|
|
96
67
|
}
|
|
97
|
-
async runCdkBootstrap(context, onOutput) {
|
|
68
|
+
async runCdkBootstrap(context, onOutput, credentials) {
|
|
98
69
|
const accountId = context.callerIdentity?.Account;
|
|
99
70
|
const region = context.region || DEFAULT_REGION;
|
|
100
71
|
try {
|
|
@@ -106,7 +77,8 @@ export class CdkService {
|
|
|
106
77
|
return failure(`Dependencies not installed. Please run 'npm install' in ${context.path} before deploying.`);
|
|
107
78
|
}
|
|
108
79
|
const result = await this.bootstrap(accountId, region, {
|
|
109
|
-
outputCallback: onOutput
|
|
80
|
+
outputCallback: onOutput,
|
|
81
|
+
credentials
|
|
110
82
|
});
|
|
111
83
|
if (!result.success) {
|
|
112
84
|
return failure(result.error || "Failed to bootstrap AWS environment");
|
|
@@ -123,7 +95,7 @@ export class CdkService {
|
|
|
123
95
|
const result = await this.checkDifferences(context.path, undefined, {
|
|
124
96
|
verbose: context.options?.verbose,
|
|
125
97
|
outputCallback: onOutput,
|
|
126
|
-
context:
|
|
98
|
+
context: buildDeploymentCdkContext(context, accountId, context.region || DEFAULT_REGION)
|
|
127
99
|
});
|
|
128
100
|
if (!result.success) {
|
|
129
101
|
return failure(`CDK diff failed: ${result.error.message}`);
|
|
@@ -140,7 +112,7 @@ export class CdkService {
|
|
|
140
112
|
return failure(`CDK diff failed: ${getErrorMessage(error)}`);
|
|
141
113
|
}
|
|
142
114
|
}
|
|
143
|
-
async runCdkDeploy(context, stackPattern, onOutput, onResourceProgress, aws) {
|
|
115
|
+
async runCdkDeploy(context, stackPattern, onOutput, onResourceProgress, aws, credentials) {
|
|
144
116
|
const accountId = context.callerIdentity?.Account;
|
|
145
117
|
const region = context.region || DEFAULT_REGION;
|
|
146
118
|
if (!accountId) {
|
|
@@ -149,23 +121,16 @@ export class CdkService {
|
|
|
149
121
|
if (!aws) {
|
|
150
122
|
return failure("AwsProvider is required for deployment monitoring.");
|
|
151
123
|
}
|
|
124
|
+
// Read construct map from fjall-manifest.json (written during synth)
|
|
125
|
+
const enrichedOnResourceProgress = wrapWithConstructMapEnrichment(context.path, onResourceProgress);
|
|
152
126
|
let cfnMonitor = null;
|
|
153
127
|
let fallbackMonitoringTimeout;
|
|
154
128
|
try {
|
|
155
|
-
const targetStackName =
|
|
156
|
-
(
|
|
157
|
-
const deployType = context.deployType;
|
|
158
|
-
if (deployType === "organisation" ||
|
|
159
|
-
deployType === "platform" ||
|
|
160
|
-
deployType === "account") {
|
|
161
|
-
return getOrganisationStackName(deployType);
|
|
162
|
-
}
|
|
163
|
-
const appName = context.target || "app";
|
|
164
|
-
return `${appName}Network`;
|
|
165
|
-
})();
|
|
129
|
+
const targetStackName = resolveStackName(stackPattern, context) ??
|
|
130
|
+
getFallbackStackName(context);
|
|
166
131
|
cfnMonitor = await this.eventMonitor.createEventMonitor("deploy", targetStackName, region, context, aws);
|
|
167
132
|
if (onOutput) {
|
|
168
|
-
onOutput(`Starting CloudFormation deployment of ${targetStackName}...\n`);
|
|
133
|
+
onOutput(maskSensitiveOutput(`Starting CloudFormation deployment of ${targetStackName}...\n`));
|
|
169
134
|
onOutput(`Monitoring CloudFormation events (CDK process running in background)...\n`);
|
|
170
135
|
}
|
|
171
136
|
const state = {
|
|
@@ -174,7 +139,7 @@ export class CdkService {
|
|
|
174
139
|
stackDetected: false,
|
|
175
140
|
monitoringPromise: null
|
|
176
141
|
};
|
|
177
|
-
const enhancedOutputCallback = createEnhancedOutputCallback(state, onOutput, cfnMonitor,
|
|
142
|
+
const enhancedOutputCallback = createEnhancedOutputCallback(state, onOutput, cfnMonitor, enrichedOnResourceProgress);
|
|
178
143
|
// Fall back to predicted stack name if actual name not detected in time
|
|
179
144
|
fallbackMonitoringTimeout = setTimeout(() => {
|
|
180
145
|
if (!state.stackDetected && cfnMonitor && !state.monitoringPromise) {
|
|
@@ -183,7 +148,7 @@ export class CdkService {
|
|
|
183
148
|
stackDetected: state.stackDetected,
|
|
184
149
|
hasOnResourceProgress: !!onResourceProgress
|
|
185
150
|
});
|
|
186
|
-
state.monitoringPromise = startStackMonitoring(cfnMonitor, targetStackName,
|
|
151
|
+
state.monitoringPromise = startStackMonitoring(cfnMonitor, targetStackName, enrichedOnResourceProgress);
|
|
187
152
|
}
|
|
188
153
|
}, STACK_DETECTION_FALLBACK_MS);
|
|
189
154
|
const result = await this.deploy(context.path, targetStackName, {
|
|
@@ -191,37 +156,31 @@ export class CdkService {
|
|
|
191
156
|
outputCallback: enhancedOutputCallback,
|
|
192
157
|
useCdkOut: true,
|
|
193
158
|
cdkOutputLogger: cfnMonitor?.getEventLogger() ?? undefined,
|
|
194
|
-
context:
|
|
159
|
+
context: buildDeploymentCdkContext(context, accountId, region),
|
|
160
|
+
credentials
|
|
195
161
|
});
|
|
196
|
-
clearTimeout(fallbackMonitoringTimeout);
|
|
197
|
-
if (cfnMonitor) {
|
|
198
|
-
logger.debug("CdkService", "CDK process exited, stopping monitor", {
|
|
199
|
-
targetStackName,
|
|
200
|
-
stackDetected: state.stackDetected,
|
|
201
|
-
hadMonitoringPromise: !!state.monitoringPromise
|
|
202
|
-
});
|
|
203
|
-
cfnMonitor.stopMonitoring();
|
|
204
|
-
}
|
|
205
162
|
return analyseDeployOutput(state.cdkOutput, result, state.actualStackName);
|
|
206
163
|
}
|
|
207
164
|
catch (error) {
|
|
208
|
-
clearTimeout(fallbackMonitoringTimeout);
|
|
209
|
-
if (cfnMonitor) {
|
|
210
|
-
cfnMonitor.stopMonitoring();
|
|
211
|
-
}
|
|
212
165
|
const errorMsg = `CDK deploy failed: ${getErrorMessage(error)}`;
|
|
213
166
|
logger.error("CdkService", "CDK deployment exception", {
|
|
214
167
|
error: errorMsg
|
|
215
168
|
});
|
|
216
169
|
return failure(errorMsg);
|
|
217
170
|
}
|
|
171
|
+
finally {
|
|
172
|
+
clearTimeout(fallbackMonitoringTimeout);
|
|
173
|
+
if (cfnMonitor) {
|
|
174
|
+
cfnMonitor.stopMonitoring();
|
|
175
|
+
}
|
|
176
|
+
}
|
|
218
177
|
}
|
|
219
|
-
async runCdkDestroy(context, stackPattern, onOutput, onResourceProgress, aws, useCdkOut) {
|
|
178
|
+
async runCdkDestroy(context, stackPattern, onOutput, onResourceProgress, aws, useCdkOut, credentials) {
|
|
220
179
|
const accountId = context.callerIdentity?.Account;
|
|
221
180
|
const region = context.region || DEFAULT_REGION;
|
|
222
181
|
let cfnMonitor = null;
|
|
223
182
|
try {
|
|
224
|
-
const targetStackName =
|
|
183
|
+
const targetStackName = resolveStackName(stackPattern, context);
|
|
225
184
|
if (accountId && targetStackName && aws) {
|
|
226
185
|
cfnMonitor = await this.eventMonitor.createEventMonitor("destroy", targetStackName, region, context, aws);
|
|
227
186
|
cfnMonitor.startMonitoring(targetStackName, (event) => {
|
|
@@ -235,20 +194,20 @@ export class CdkService {
|
|
|
235
194
|
outputCallback: onOutput,
|
|
236
195
|
useCdkOut,
|
|
237
196
|
cdkOutputLogger: cfnMonitor?.getEventLogger() ?? undefined,
|
|
238
|
-
context:
|
|
197
|
+
context: buildDeploymentCdkContext(context, accountId, region, {
|
|
239
198
|
includeImageVersion: false
|
|
240
|
-
})
|
|
199
|
+
}),
|
|
200
|
+
credentials
|
|
241
201
|
});
|
|
242
|
-
if (cfnMonitor) {
|
|
243
|
-
cfnMonitor.stopMonitoring();
|
|
244
|
-
}
|
|
245
202
|
return analyseDestroyResult(result);
|
|
246
203
|
}
|
|
247
204
|
catch (error) {
|
|
205
|
+
return failure(`CDK destroy failed: ${getErrorMessage(error)}`);
|
|
206
|
+
}
|
|
207
|
+
finally {
|
|
248
208
|
if (cfnMonitor) {
|
|
249
209
|
cfnMonitor.stopMonitoring();
|
|
250
210
|
}
|
|
251
|
-
return failure(`CDK destroy failed: ${getErrorMessage(error)}`);
|
|
252
211
|
}
|
|
253
212
|
}
|
|
254
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);
|