@aws-cdk/toolkit-lib 1.29.1 → 1.31.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/build-info.json +2 -2
- package/lib/actions/bootstrap/index.js +35 -2
- package/lib/actions/diagnose/index.d.ts +28 -0
- package/lib/actions/diagnose/index.js +1 -1
- package/lib/actions/diff/private/helpers.js +36 -3
- package/lib/actions/validate/index.d.ts +2 -0
- package/lib/actions/validate/index.js +1 -1
- package/lib/api/aws-auth/account-cache.js +36 -3
- package/lib/api/aws-auth/sdk-provider.js +36 -3
- package/lib/api/aws-auth/sdk.d.ts +7 -2
- package/lib/api/aws-auth/sdk.js +6 -1
- package/lib/api/aws-auth/user-agent.js +35 -2
- package/lib/api/aws-auth/util.js +35 -2
- package/lib/api/bootstrap/bootstrap-environment.js +35 -2
- package/lib/api/bootstrap/deploy-bootstrap.js +37 -4
- package/lib/api/cloud-assembly/context-store.js +36 -3
- package/lib/api/cloud-assembly/environment.js +40 -4
- package/lib/api/cloud-assembly/private/context-aware-source.js +35 -2
- package/lib/api/cloud-assembly/private/exec.js +35 -2
- package/lib/api/cloud-assembly/private/prepare-source.js +39 -6
- package/lib/api/cloud-assembly/source-builder.js +37 -4
- package/lib/api/cloud-assembly/stack-assembly.js +8 -4
- package/lib/api/cloud-assembly/stack-collection.d.ts +2 -0
- package/lib/api/cloud-assembly/stack-collection.js +3 -1
- package/lib/api/cloudformation/logical-id-map.js +35 -2
- package/lib/api/cloudformation/nested-stack-helpers.js +36 -3
- package/lib/api/cloudformation/template-body-parameter.js +42 -6
- package/lib/api/deployments/asset-manifest-builder.js +35 -2
- package/lib/api/deployments/assets.js +42 -6
- package/lib/api/deployments/cfn-api.d.ts +4 -2
- package/lib/api/deployments/cfn-api.js +47 -6
- package/lib/api/deployments/deploy-stack.js +11 -6
- package/lib/api/deployments/deployments.js +42 -4
- package/lib/api/diagnosing/diagnosis-formatting.js +54 -13
- package/lib/api/diagnosing/format-utils.d.ts +32 -0
- package/lib/api/diagnosing/format-utils.js +176 -0
- package/lib/api/diagnosing/investigate-custom-resource.d.ts +17 -0
- package/lib/api/diagnosing/investigate-custom-resource.js +247 -0
- package/lib/api/diagnosing/investigate-ecs-service.d.ts +20 -0
- package/lib/api/diagnosing/investigate-ecs-service.js +242 -0
- package/lib/api/diagnosing/resource-identifiers.d.ts +39 -0
- package/lib/api/diagnosing/resource-identifiers.js +90 -0
- package/lib/api/diagnosing/resource-investigation.d.ts +13 -0
- package/lib/api/diagnosing/resource-investigation.js +22 -0
- package/lib/api/diagnosing/stack-diagnoser.d.ts +39 -3
- package/lib/api/diagnosing/stack-diagnoser.js +71 -30
- package/lib/api/diff/diff-formatter.js +11 -8
- package/lib/api/drift/drift-formatter.js +20 -17
- package/lib/api/garbage-collection/garbage-collector.js +7 -4
- package/lib/api/garbage-collection/progress-printer.js +7 -4
- package/lib/api/hotswap/hotswap-deployments.js +46 -10
- package/lib/api/hotswap/hotswap-template-cache.js +36 -3
- package/lib/api/io/private/io-default-messages.js +35 -2
- package/lib/api/io/private/message-maker.d.ts +4 -0
- package/lib/api/io/private/message-maker.js +3 -1
- package/lib/api/io/private/messages.d.ts +2 -0
- package/lib/api/io/private/messages.js +44 -3
- package/lib/api/io/private/span.js +35 -2
- package/lib/api/logs-monitor/logs-monitor.js +40 -4
- package/lib/api/network-detector/network-detector.js +37 -4
- package/lib/api/notices/cached-data-source.js +35 -2
- package/lib/api/notices/filter.js +35 -2
- package/lib/api/notices/notices.js +35 -2
- package/lib/api/notices/web-data-source.js +35 -2
- package/lib/api/refactoring/digest.js +35 -2
- package/lib/api/refactoring/stack-definitions.js +40 -4
- package/lib/api/resource-import/importer.js +58 -15
- package/lib/api/resource-import/migrator.js +42 -6
- package/lib/api/rwlock.js +35 -2
- package/lib/api/settings.js +38 -5
- package/lib/api/source-tracing/private/stack-source-tracing.js +38 -5
- package/lib/api/stack-events/resource-errors.d.ts +12 -0
- package/lib/api/stack-events/resource-errors.js +2 -1
- package/lib/api/stack-events/stack-activity-monitor.js +35 -2
- package/lib/api/stack-events/stack-progress-monitor.js +35 -2
- package/lib/api/toolkit-info.js +7 -4
- package/lib/api/tree.js +36 -3
- package/lib/api/validate/validate-formatting.d.ts +9 -2
- package/lib/api/validate/validate-formatting.js +161 -77
- package/lib/api/work-graph/build-destroy-work-graph.js +35 -2
- package/lib/api/work-graph/work-graph-builder.js +35 -2
- package/lib/context-providers/index.js +35 -2
- package/lib/private/activity-printer/current.js +52 -16
- package/lib/private/activity-printer/history.js +50 -14
- package/lib/private/tools.js +64 -25
- package/lib/toolkit/non-interactive-io-host.js +11 -8
- package/lib/toolkit/private/collect-annotation-report.d.ts +12 -0
- package/lib/toolkit/private/collect-annotation-report.js +118 -0
- package/lib/toolkit/private/validation-report.d.ts +32 -0
- package/lib/toolkit/private/validation-report.js +152 -0
- package/lib/toolkit/toolkit-error.d.ts +20 -0
- package/lib/toolkit/toolkit-error.js +30 -2
- package/lib/toolkit/toolkit.d.ts +12 -7
- package/lib/toolkit/toolkit.js +104 -101
- package/lib/toolkit/types.d.ts +1 -0
- package/lib/toolkit/types.js +1 -1
- package/lib/util/content-hash.js +35 -2
- package/lib/util/directories.js +38 -5
- package/lib/util/glob-matcher.d.ts +19 -7
- package/lib/util/glob-matcher.js +63 -14
- package/lib/util/guess-language.js +36 -3
- package/lib/util/package-info.js +35 -2
- package/lib/util/serialize.js +36 -3
- package/lib/util/version-range.js +35 -2
- package/lib/util/yaml-cfn.js +36 -3
- package/package.json +5 -5
- package/lib/api/diagnosing/tree-builder.d.ts +0 -13
- package/lib/api/diagnosing/tree-builder.js +0 -86
- package/lib/api/diagnosing/tree.d.ts +0 -19
- package/lib/api/diagnosing/tree.js +0 -72
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.investigateEcsService = investigateEcsService;
|
|
4
|
+
const format_utils_1 = require("./format-utils");
|
|
5
|
+
const resource_identifiers_1 = require("./resource-identifiers");
|
|
6
|
+
/** Fallback look-back when no failure timestamp is available. */
|
|
7
|
+
const FALLBACK_LOG_WINDOW_MS = 30 * 60 * 1000;
|
|
8
|
+
async function investigateEcsService(err, sdk, debug, options) {
|
|
9
|
+
const physicalId = err.physicalId;
|
|
10
|
+
if (!physicalId) {
|
|
11
|
+
await debug('ECS investigation: no physical ID available');
|
|
12
|
+
return [];
|
|
13
|
+
}
|
|
14
|
+
const { cluster, serviceName } = (0, resource_identifiers_1.parseEcsServiceIdentifier)(physicalId);
|
|
15
|
+
if (!serviceName) {
|
|
16
|
+
await debug(`ECS investigation: could not parse service identifier from "${physicalId}"`);
|
|
17
|
+
return [];
|
|
18
|
+
}
|
|
19
|
+
const region = sdk.currentRegion;
|
|
20
|
+
const ecs = sdk.ecs();
|
|
21
|
+
const cwl = sdk.cloudWatchLogs();
|
|
22
|
+
const service = await describeService(ecs, cluster, serviceName, debug);
|
|
23
|
+
if (!service) {
|
|
24
|
+
// The service is gone. The most common reason is that CloudFormation rolled the
|
|
25
|
+
// deployment back and deleted it, taking the task/runtime detail with it. If rollback
|
|
26
|
+
// was enabled, point the user at the flag that would have retained that detail.
|
|
27
|
+
if (options.rollbackEnabled) {
|
|
28
|
+
return [{
|
|
29
|
+
source: 'ECS Service',
|
|
30
|
+
messages: [
|
|
31
|
+
'The service and its tasks were removed during rollback, so container-level failure detail is unavailable.',
|
|
32
|
+
'Re-run the deployment with `--no-rollback` to retain the failed tasks and see why they stopped.',
|
|
33
|
+
],
|
|
34
|
+
}];
|
|
35
|
+
}
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
const results = [];
|
|
39
|
+
const stoppedTaskResult = await getStoppedTaskReasons(ecs, cluster, serviceName, region, service, debug);
|
|
40
|
+
if (stoppedTaskResult.context) {
|
|
41
|
+
results.push(stoppedTaskResult.context);
|
|
42
|
+
}
|
|
43
|
+
const taskDefinitionArn = service.taskDefinition;
|
|
44
|
+
if (!taskDefinitionArn) {
|
|
45
|
+
return results;
|
|
46
|
+
}
|
|
47
|
+
const taskDefInfo = await getTaskDefinitionInfo(ecs, taskDefinitionArn, debug);
|
|
48
|
+
if (!taskDefInfo) {
|
|
49
|
+
return results;
|
|
50
|
+
}
|
|
51
|
+
const logConfigs = taskDefInfo.logConfigs;
|
|
52
|
+
if (logConfigs.length === 0) {
|
|
53
|
+
results.push({
|
|
54
|
+
source: 'CloudWatch Logs',
|
|
55
|
+
messages: [
|
|
56
|
+
'No CloudWatch Logs configuration found. Enable logging to see container output on failure.',
|
|
57
|
+
'Example:',
|
|
58
|
+
' taskDefinition.addContainer("app", {',
|
|
59
|
+
' // ...',
|
|
60
|
+
' logging: ecs.LogDrivers.awsLogs({ streamPrefix: "my-service" }),',
|
|
61
|
+
' });',
|
|
62
|
+
],
|
|
63
|
+
});
|
|
64
|
+
return results;
|
|
65
|
+
}
|
|
66
|
+
// `logConfigs` has one entry per container in the task definition that uses the awslogs
|
|
67
|
+
// driver — a handful at most — so this fan-out is bounded by the task shape and needs no
|
|
68
|
+
// explicit concurrency limit.
|
|
69
|
+
// eslint-disable-next-line @cdklabs/promiseall-no-unbounded-parallelism
|
|
70
|
+
const logResults = await Promise.all(logConfigs.map(cfg => fetchRecentLogs(cwl, cfg, region, stoppedTaskResult.taskIds, debug)));
|
|
71
|
+
const logContexts = logResults.filter((c) => c !== undefined);
|
|
72
|
+
results.push(...logContexts);
|
|
73
|
+
if (logContexts.length === 0) {
|
|
74
|
+
results.push({
|
|
75
|
+
source: 'CloudWatch Logs',
|
|
76
|
+
messages: ['No CloudWatch Logs found.'],
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
return results;
|
|
80
|
+
}
|
|
81
|
+
async function describeService(ecs, cluster, serviceName, debug) {
|
|
82
|
+
try {
|
|
83
|
+
const resp = await ecs.describeServices({ cluster, services: [serviceName] });
|
|
84
|
+
const service = resp.services?.[0];
|
|
85
|
+
if (!service) {
|
|
86
|
+
await debug(`ECS investigation: service "${serviceName}" not found`);
|
|
87
|
+
}
|
|
88
|
+
return service;
|
|
89
|
+
}
|
|
90
|
+
catch (e) {
|
|
91
|
+
await debug(`ECS investigation: failed to describe service: ${e.message}`);
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
async function getStoppedTaskReasons(ecs, cluster, serviceName, region, service, debug) {
|
|
96
|
+
try {
|
|
97
|
+
// Ask ECS for the service's stopped tasks. The IDs we need live in "has started 1 tasks: (task <id>)" events
|
|
98
|
+
const taskIds = await listStoppedTaskIds(ecs, cluster, serviceName, debug);
|
|
99
|
+
const messages = [];
|
|
100
|
+
if (taskIds.length > 0) {
|
|
101
|
+
// Show details from the most recently stopped task only.
|
|
102
|
+
const tasksResp = await ecs.describeTasks({ cluster, tasks: [taskIds[0]] });
|
|
103
|
+
const task = tasksResp.tasks?.[0];
|
|
104
|
+
if (task) {
|
|
105
|
+
if (task.stoppedReason) {
|
|
106
|
+
messages.push(`Task stopped: ${task.stoppedReason}`);
|
|
107
|
+
}
|
|
108
|
+
for (const container of task.containers ?? []) {
|
|
109
|
+
if (container.reason) {
|
|
110
|
+
messages.push(`Container "${container.name}": ${container.reason}`);
|
|
111
|
+
}
|
|
112
|
+
if (container.exitCode != null && container.exitCode !== 0) {
|
|
113
|
+
messages.push(`Container "${container.name}" exited with code ${container.exitCode}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (messages.length > 0 && taskIds.length > 1) {
|
|
118
|
+
messages.push(`(${taskIds.length - 1} other failed task(s) not shown)`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// Fall back to the most relevant service event if we couldn't get a task-level reason
|
|
122
|
+
// (e.g. tasks already aged out, or no stopped tasks retained).
|
|
123
|
+
if (messages.length === 0) {
|
|
124
|
+
const failureEvent = (service.events ?? [])
|
|
125
|
+
.find(e => e.message?.includes('stopped') || e.message?.includes('failed') || e.message?.includes('unhealthy'));
|
|
126
|
+
if (failureEvent?.message) {
|
|
127
|
+
messages.push(failureEvent.message);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (messages.length === 0) {
|
|
131
|
+
return { taskIds };
|
|
132
|
+
}
|
|
133
|
+
return {
|
|
134
|
+
context: {
|
|
135
|
+
source: 'ECS Stopped Tasks',
|
|
136
|
+
messages,
|
|
137
|
+
link: (0, resource_identifiers_1.ecsStoppedTasksConsoleUrl)(region, cluster ?? 'default', serviceName),
|
|
138
|
+
linkLabel: 'Tasks',
|
|
139
|
+
},
|
|
140
|
+
taskIds,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
catch (e) {
|
|
144
|
+
await debug(`ECS investigation: failed to get stopped task reasons: ${e.message}`);
|
|
145
|
+
return { taskIds: [] };
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Maximum number of stopped task IDs to consider. We only render detail for the most
|
|
150
|
+
* recent one, but keep a few so we can report how many others failed.
|
|
151
|
+
*/
|
|
152
|
+
const MAX_STOPPED_TASKS = 3;
|
|
153
|
+
/**
|
|
154
|
+
* List the bare task IDs of the service's stopped tasks, newest first.
|
|
155
|
+
*
|
|
156
|
+
* Prefers scoping by service name; if that yields nothing (some ECS API versions only
|
|
157
|
+
* apply the service filter to running tasks), falls back to listing the cluster's stopped
|
|
158
|
+
* tasks. Returns an empty array if none are retained (e.g. they aged out, or rollback
|
|
159
|
+
* already drained the cluster).
|
|
160
|
+
*/
|
|
161
|
+
async function listStoppedTaskIds(ecs, cluster, serviceName, debug) {
|
|
162
|
+
const toIds = (arns) => (arns ?? []).map(arn => arn.split('/').pop()).filter((id) => !!id);
|
|
163
|
+
let arns;
|
|
164
|
+
try {
|
|
165
|
+
const byService = await ecs.listTasks({ cluster, serviceName, desiredStatus: 'STOPPED' });
|
|
166
|
+
arns = byService.taskArns;
|
|
167
|
+
if (!arns || arns.length === 0) {
|
|
168
|
+
const byCluster = await ecs.listTasks({ cluster, desiredStatus: 'STOPPED' });
|
|
169
|
+
arns = byCluster.taskArns;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
catch (e) {
|
|
173
|
+
await debug(`ECS investigation: failed to list stopped tasks: ${e.message}`);
|
|
174
|
+
return [];
|
|
175
|
+
}
|
|
176
|
+
return toIds(arns).slice(0, MAX_STOPPED_TASKS);
|
|
177
|
+
}
|
|
178
|
+
async function getTaskDefinitionInfo(ecs, taskDefinitionArn, debug) {
|
|
179
|
+
try {
|
|
180
|
+
const resp = await ecs.describeTaskDefinition({ taskDefinition: taskDefinitionArn });
|
|
181
|
+
const containers = resp.taskDefinition?.containerDefinitions ?? [];
|
|
182
|
+
const logConfigs = [];
|
|
183
|
+
for (const container of containers) {
|
|
184
|
+
const logConfig = container.logConfiguration;
|
|
185
|
+
if (logConfig?.logDriver === 'awslogs') {
|
|
186
|
+
const logGroup = logConfig.options?.['awslogs-group'];
|
|
187
|
+
if (logGroup) {
|
|
188
|
+
logConfigs.push({
|
|
189
|
+
logGroup,
|
|
190
|
+
streamPrefix: logConfig.options?.['awslogs-stream-prefix'],
|
|
191
|
+
containerName: container.name,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return { logConfigs };
|
|
197
|
+
}
|
|
198
|
+
catch (e) {
|
|
199
|
+
await debug(`ECS investigation: failed to describe task definition: ${e.message}`);
|
|
200
|
+
return undefined;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
async function fetchRecentLogs(cwl, logConfig, region, taskIds, debug) {
|
|
204
|
+
try {
|
|
205
|
+
// Target the most recently failed task's log stream for the most relevant output
|
|
206
|
+
const lastTaskId = taskIds[0];
|
|
207
|
+
const targetStream = (logConfig.streamPrefix && logConfig.containerName && lastTaskId)
|
|
208
|
+
? `${logConfig.streamPrefix}/${logConfig.containerName}/${lastTaskId}`
|
|
209
|
+
: undefined;
|
|
210
|
+
const resp = await cwl.filterLogEvents({
|
|
211
|
+
logGroupName: logConfig.logGroup,
|
|
212
|
+
startTime: Date.now() - FALLBACK_LOG_WINDOW_MS,
|
|
213
|
+
limit: 1000,
|
|
214
|
+
...(targetStream
|
|
215
|
+
? { logStreamNames: [targetStream] }
|
|
216
|
+
: logConfig.streamPrefix ? { logStreamNamePrefix: logConfig.streamPrefix } : {}),
|
|
217
|
+
});
|
|
218
|
+
const events = resp.events ?? [];
|
|
219
|
+
if (events.length === 0) {
|
|
220
|
+
await debug(`ECS investigation: no recent log events in ${logConfig.logGroup}${targetStream ? ` (targeted stream: ${targetStream})` : ''}`);
|
|
221
|
+
return undefined;
|
|
222
|
+
}
|
|
223
|
+
const messages = (0, format_utils_1.trimToRecentLines)(events.map(e => e.message?.trimEnd()).filter((m) => m != null));
|
|
224
|
+
if (taskIds.length > 1) {
|
|
225
|
+
messages.push(`(showing logs from last failed task; ${taskIds.length - 1} other failed task(s) available in console)`);
|
|
226
|
+
}
|
|
227
|
+
const source = logConfig.containerName
|
|
228
|
+
? `CloudWatch Logs: ${logConfig.logGroup} (container: ${logConfig.containerName})`
|
|
229
|
+
: `CloudWatch Logs: ${logConfig.logGroup}`;
|
|
230
|
+
return {
|
|
231
|
+
source,
|
|
232
|
+
messages,
|
|
233
|
+
link: (0, format_utils_1.cloudWatchLogsConsoleUrl)(region, logConfig.logGroup),
|
|
234
|
+
linkLabel: 'Logs',
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
catch (e) {
|
|
238
|
+
await debug(`ECS investigation: failed to fetch logs from ${logConfig.logGroup}: ${e.message}`);
|
|
239
|
+
return undefined;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW52ZXN0aWdhdGUtZWNzLXNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbnZlc3RpZ2F0ZS1lY3Mtc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQXlCQSxzREF5RkM7QUFsSEQsaURBQTZFO0FBQzdFLGlFQUE4RjtBQUs5RixpRUFBaUU7QUFDakUsTUFBTSxzQkFBc0IsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQztBQWtCdkMsS0FBSyxVQUFVLHFCQUFxQixDQUN6QyxHQUFrQixFQUNsQixHQUFRLEVBQ1IsS0FBcUMsRUFDckMsT0FBMkI7SUFFM0IsTUFBTSxVQUFVLEdBQUcsR0FBRyxDQUFDLFVBQVUsQ0FBQztJQUNsQyxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7UUFDaEIsTUFBTSxLQUFLLENBQUMsNkNBQTZDLENBQUMsQ0FBQztRQUMzRCxPQUFPLEVBQUUsQ0FBQztJQUNaLENBQUM7SUFFRCxNQUFNLEVBQUUsT0FBTyxFQUFFLFdBQVcsRUFBRSxHQUFHLElBQUEsZ0RBQXlCLEVBQUMsVUFBVSxDQUFDLENBQUM7SUFDdkUsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBQ2pCLE1BQU0sS0FBSyxDQUFDLCtEQUErRCxVQUFVLEdBQUcsQ0FBQyxDQUFDO1FBQzFGLE9BQU8sRUFBRSxDQUFDO0lBQ1osQ0FBQztJQUVELE1BQU0sTUFBTSxHQUFHLEdBQUcsQ0FBQyxhQUFhLENBQUM7SUFDakMsTUFBTSxHQUFHLEdBQUcsR0FBRyxDQUFDLEdBQUcsRUFBRSxDQUFDO0lBQ3RCLE1BQU0sR0FBRyxHQUFHLEdBQUcsQ0FBQyxjQUFjLEVBQUUsQ0FBQztJQUVqQyxNQUFNLE9BQU8sR0FBRyxNQUFNLGVBQWUsQ0FBQyxHQUFHLEVBQUUsT0FBTyxFQUFFLFdBQVcsRUFBRSxLQUFLLENBQUMsQ0FBQztJQUN4RSxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDYixnRkFBZ0Y7UUFDaEYsc0ZBQXNGO1FB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UyxFQUFFLE1BQU07U0FDbEIsQ0FBQztJQUNKLENBQUM7SUFBQyxPQUFPLENBQU0sRUFBRSxDQUFDO1FBQ2hCLE1BQU0sS0FBSyxDQUFDLGdEQUFnRCxTQUFTLENBQUMsUUFBUSxLQUFLLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1FBQ2hHLE9BQU8sU0FBUyxDQUFDO0lBQ25CLENBQUM7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgdHJpbVRvUmVjZW50TGluZXMsIGNsb3VkV2F0Y2hMb2dzQ29uc29sZVVybCB9IGZyb20gJy4vZm9ybWF0LXV0aWxzJztcbmltcG9ydCB7IHBhcnNlRWNzU2VydmljZUlkZW50aWZpZXIsIGVjc1N0b3BwZWRUYXNrc0NvbnNvbGVVcmwgfSBmcm9tICcuL3Jlc291cmNlLWlkZW50aWZpZXJzJztcbmltcG9ydCB0eXBlIHsgQWRkaXRpb25hbERpYWdub3N0aWNDb250ZXh0IH0gZnJvbSAnLi4vLi4vYWN0aW9ucy9kaWFnbm9zZSc7XG5pbXBvcnQgdHlwZSB7IElDbG91ZFdhdGNoTG9nc0NsaWVudCwgSUVDU0NsaWVudCwgU0RLIH0gZnJvbSAnLi4vYXdzLWF1dGgvc2RrJztcbmltcG9ydCB0eXBlIHsgUmVzb3VyY2VFcnJvciB9IGZyb20gJy4uL3N0YWNrLWV2ZW50cy9yZXNvdXJjZS1lcnJvcnMnO1xuXG4vKiogRmFsbGJhY2sgbG9vay1iYWNrIHdoZW4gbm8gZmFpbHVyZSB0aW1lc3RhbXAgaXMgYXZhaWxhYmxlLiAqL1xuY29uc3QgRkFMTEJBQ0tfTE9HX1dJTkRPV19NUyA9IDMwICogNjAgKiAxMDAwO1xuXG4vKipcbiAqIE9wdGlvbnMgdGhhdCBpbmZsdWVuY2UgaG93IGEgcmVzb3VyY2UgaXMgaW52ZXN0aWdhdGVkLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEludmVzdGlnYXRlT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBXaGV0aGVyIENsb3VkRm9ybWF0aW9uIHJvbGxiYWNrIGlzIGVuYWJsZWQgZm9yIHRoaXMgZGVwbG95bWVudC5cbiAgICpcbiAgICogV2hlbiByb2xsYmFjayBpcyBlbmFibGVkLCBhIGZhaWxlZCByZXNvdXJjZSBpcyB0b3JuIGRvd24gYmVmb3JlIHdlIGNhblxuICAgKiBpbnNwZWN0IGl0cyBydW50aW1lIHN0YXRlLCBzbyB3ZSBtYXkgc3VnZ2VzdCByZS1ydW5uaW5nIHdpdGggYC0tbm8tcm9sbGJhY2tgXG4gICAqIHRvIHJldGFpbiB0aGF0IGRldGFpbC5cbiAgICpcbiAgICogQGRlZmF1bHQgdHJ1ZVxuICAgKi9cbiAgcmVhZG9ubHkgcm9sbGJhY2tFbmFibGVkPzogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGludmVzdGlnYXRlRWNzU2VydmljZShcbiAgZXJyOiBSZXNvdXJjZUVycm9yLFxuICBzZGs6IFNESyxcbiAgZGVidWc6IChtc2c6IHN0cmluZykgPT4gUHJvbWlzZTx2b2lkPixcbiAgb3B0aW9uczogSW52ZXN0aWdhdGVPcHRpb25zLFxuKTogUHJvbWlzZTxBZGRpdGlvbmFsRGlhZ25vc3RpY0NvbnRleHRbXT4ge1xuICBjb25zdCBwaHlzaWNhbElkID0gZXJyLnBoeXNpY2FsSWQ7XG4gIGlmICghcGh5c2ljYWxJZCkge1xuICAgIGF3YWl0IGRlYnVnKCdFQ1MgaW52ZXN0aWdhdGlvbjogbm8gcGh5c2ljYWwgSUQgYXZhaWxhYmxlJyk7XG4gICAgcmV0dXJuIFtdO1xuICB9XG5cbiAgY29uc3QgeyBjbHVzdGVyLCBzZXJ2aWNlTmFtZSB9ID0gcGFyc2VFY3NTZXJ2aWNlSWRlbnRpZmllcihwaHlzaWNhbElkKTtcbiAgaWYgKCFzZXJ2aWNlTmFtZSkge1xuICAgIGF3YWl0IGRlYnVnKGBFQ1MgaW52ZXN0aWdhdGlvbjogY291bGQgbm90IHBhcnNlIHNlcnZpY2UgaWRlbnRpZmllciBmcm9tIFwiJHtwaHlzaWNhbElkfVwiYCk7XG4gICAgcmV0dXJuIFtdO1xuICB9XG5cbiAgY29uc3QgcmVnaW9uID0gc2RrLmN1cnJlbnRSZWdpb247XG4gIGNvbnN0IGVjcyA9IHNkay5lY3MoKTtcbiAgY29uc3QgY3dsID0gc2RrLmNsb3VkV2F0Y2hMb2dzKCk7XG5cbiAgY29uc3Qgc2VydmljZSA9IGF3YWl0IGRlc2NyaWJlU2VydmljZShlY3MsIGNsdXN0ZXIsIHNlcnZpY2VOYW1lLCBkZWJ1Zyk7XG4gIGlmICghc2VydmljZSkge1xuICAgIC8vIFRoZSBzZXJ2aWNlIGlzIGdvbmUuIFRoZSBtb3N0IGNvbW1vbiByZWFzb24gaXMgdGhhdCBDbG91ZEZvcm1hdGlvbiByb2xsZWQgdGhlXG4gICAgLy8gZGVwbG95bWVudCBiYWNrIGFuZCBkZWxldGVkIGl0LCB0YWtpbmcgdGhlIHRhc2svcnVudGltZSBkZXRhaWwgd2l0aCBpdC4gSWYgcm9sbGJhY2tcbiAgICAvLyB3YXMgZW5hYmxlZCwgcG9pbnQgdGhlIHVzZXIgYXQgdGhlIGZsYWcgdGhhdCB3b3VsZCBoYXZlIHJldGFpbmVkIHRoYXQgZGV0YWlsLlxuICAgIGlmIChvcHRpb25zLnJvbGxiYWNrRW5hYmxlZCkge1xuICAgICAgcmV0dXJuIFt7XG4gICAgICAgIHNvdXJjZTogJ0VDUyBTZXJ2aWNlJyxcbiAgICAgICAgbWVzc2FnZXM6IFtcbiAgICAgICAgICAnVGhlIHNlcnZpY2UgYW5kIGl0cyB0YXNrcyB3ZXJlIHJlbW92ZWQgZHVyaW5nIHJvbGxiYWNrLCBzbyBjb250YWluZXItbGV2ZWwgZmFpbHVyZSBkZXRhaWwgaXMgdW5hdmFpbGFibGUuJyxcbiAgICAgICAgICAnUmUtcnVuIHRoZSBkZXBsb3ltZW50IHdpdGggYC0tbm8tcm9sbGJhY2tgIHRvIHJldGFpbiB0aGUgZmFpbGVkIHRhc2tzIGFuZCBzZWUgd2h5IHRoZXkgc3RvcHBlZC4nLFxuICAgICAgICBdLFxuICAgICAgfV07XG4gICAgfVxuICAgIHJldHVybiBbXTtcbiAgfVxuXG4gIGNvbnN0IHJlc3VsdHM6IEFkZGl0aW9uYWxEaWFnbm9zdGljQ29udGV4dFtdID0gW107XG5cbiAgY29uc3Qgc3RvcHBlZFRhc2tSZXN1bHQgPSBhd2FpdCBnZXRTdG9wcGVkVGFza1JlYXNvbnMoZWNzLCBjbHVzdGVyLCBzZXJ2aWNlTmFtZSwgcmVnaW9uLCBzZXJ2aWNlLCBkZWJ1Zyk7XG4gIGlmIChzdG9wcGVkVGFza1Jlc3VsdC5jb250ZXh0KSB7XG4gICAgcmVzdWx0cy5wdXNoKHN0b3BwZWRUYXNrUmVzdWx0LmNvbnRleHQpO1xuICB9XG5cbiAgY29uc3QgdGFza0RlZmluaXRpb25Bcm4gPSBzZXJ2aWNlLnRhc2tEZWZpbml0aW9uO1xuICBpZiAoIXRhc2tEZWZpbml0aW9uQXJuKSB7XG4gICAgcmV0dXJuIHJlc3VsdHM7XG4gIH1cblxuICBjb25zdCB0YXNrRGVmSW5mbyA9IGF3YWl0IGdldFRhc2tEZWZpbml0aW9uSW5mbyhlY3MsIHRhc2tEZWZpbml0aW9uQXJuLCBkZWJ1Zyk7XG4gIGlmICghdGFza0RlZkluZm8pIHtcbiAgICByZXR1cm4gcmVzdWx0cztcbiAgfVxuXG4gIGNvbnN0IGxvZ0NvbmZpZ3MgPSB0YXNrRGVmSW5mby5sb2dDb25maWdzO1xuXG4gIGlmIChsb2dDb25maWdzLmxlbmd0aCA9PT0gMCkge1xuICAgIHJlc3VsdHMucHVzaCh7XG4gICAgICBzb3VyY2U6ICdDbG91ZFdhdGNoIExvZ3MnLFxuICAgICAgbWVzc2FnZXM6IFtcbiAgICAgICAgJ05vIENsb3VkV2F0Y2ggTG9ncyBjb25maWd1cmF0aW9uIGZvdW5kLiBFbmFibGUgbG9nZ2luZyB0byBzZWUgY29udGFpbmVyIG91dHB1dCBvbiBmYWlsdXJlLicsXG4gICAgICAgICdFeGFtcGxlOicsXG4gICAgICAgICcgIHRhc2tEZWZpbml0aW9uLmFkZENvbnRhaW5lcihcImFwcFwiLCB7JyxcbiAgICAgICAgJyAgICAvLyAuLi4nLFxuICAgICAgICAnICAgIGxvZ2dpbmc6IGVjcy5Mb2dEcml2ZXJzLmF3c0xvZ3MoeyBzdHJlYW1QcmVmaXg6IFwibXktc2VydmljZVwiIH0pLCcsXG4gICAgICAgICcgIH0pOycsXG4gICAgICBdLFxuICAgIH0pO1xuICAgIHJldHVybiByZXN1bHRzO1xuICB9XG5cbiAgLy8gYGxvZ0NvbmZpZ3NgIGhhcyBvbmUgZW50cnkgcGVyIGNvbnRhaW5lciBpbiB0aGUgdGFzayBkZWZpbml0aW9uIHRoYXQgdXNlcyB0aGUgYXdzbG9nc1xuICAvLyBkcml2ZXIg4oCUIGEgaGFuZGZ1bCBhdCBtb3N0IOKAlCBzbyB0aGlzIGZhbi1vdXQgaXMgYm91bmRlZCBieSB0aGUgdGFzayBzaGFwZSBhbmQgbmVlZHMgbm9cbiAgLy8gZXhwbGljaXQgY29uY3VycmVuY3kgbGltaXQuXG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAY2RrbGFicy9wcm9taXNlYWxsLW5vLXVuYm91bmRlZC1wYXJhbGxlbGlzbVxuICBjb25zdCBsb2dSZXN1bHRzID0gYXdhaXQgUHJvbWlzZS5hbGwobG9nQ29uZmlncy5tYXAoY2ZnID0+IGZldGNoUmVjZW50TG9ncyhjd2wsIGNmZywgcmVnaW9uLCBzdG9wcGVkVGFza1Jlc3VsdC50YXNrSWRzLCBkZWJ1ZykpKTtcbiAgY29uc3QgbG9nQ29udGV4dHMgPSBsb2dSZXN1bHRzLmZpbHRlcigoYyk6IGMgaXMgQWRkaXRpb25hbERpYWdub3N0aWNDb250ZXh0ID0+IGMgIT09IHVuZGVmaW5lZCk7XG5cbiAgcmVzdWx0cy5wdXNoKC4uLmxvZ0NvbnRleHRzKTtcbiAgaWYgKGxvZ0NvbnRleHRzLmxlbmd0aCA9PT0gMCkge1xuICAgIHJlc3VsdHMucHVzaCh7XG4gICAgICBzb3VyY2U6ICdDbG91ZFdhdGNoIExvZ3MnLFxuICAgICAgbWVzc2FnZXM6IFsnTm8gQ2xvdWRXYXRjaCBMb2dzIGZvdW5kLiddLFxuICAgIH0pO1xuICB9XG5cbiAgcmV0dXJuIHJlc3VsdHM7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGRlc2NyaWJlU2VydmljZShcbiAgZWNzOiBJRUNTQ2xpZW50LFxuICBjbHVzdGVyOiBzdHJpbmcgfCB1bmRlZmluZWQsXG4gIHNlcnZpY2VOYW1lOiBzdHJpbmcsXG4gIGRlYnVnOiAobXNnOiBzdHJpbmcpID0+IFByb21pc2U8dm9pZD4sXG4pIHtcbiAgdHJ5IHtcbiAgICBjb25zdCByZXNwID0gYXdhaXQgZWNzLmRlc2NyaWJlU2VydmljZXMoeyBjbHVzdGVyLCBzZXJ2aWNlczogW3NlcnZpY2VOYW1lXSB9KTtcbiAgICBjb25zdCBzZXJ2aWNlID0gcmVzcC5zZXJ2aWNlcz8uWzBdO1xuICAgIGlmICghc2VydmljZSkge1xuICAgICAgYXdhaXQgZGVidWcoYEVDUyBpbnZlc3RpZ2F0aW9uOiBzZXJ2aWNlIFwiJHtzZXJ2aWNlTmFtZX1cIiBub3QgZm91bmRgKTtcbiAgICB9XG4gICAgcmV0dXJuIHNlcnZpY2U7XG4gIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgIGF3YWl0IGRlYnVnKGBFQ1MgaW52ZXN0aWdhdGlvbjogZmFpbGVkIHRvIGRlc2NyaWJlIHNlcnZpY2U6ICR7ZS5tZXNzYWdlfWApO1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbn1cblxuaW50ZXJmYWNlIFN0b3BwZWRUYXNrUmVzdWx0IHtcbiAgY29udGV4dD86IEFkZGl0aW9uYWxEaWFnbm9zdGljQ29udGV4dDtcbiAgdGFza0lkczogc3RyaW5nW107XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGdldFN0b3BwZWRUYXNrUmVhc29ucyhcbiAgZWNzOiBJRUNTQ2xpZW50LFxuICBjbHVzdGVyOiBzdHJpbmcgfCB1bmRlZmluZWQsXG4gIHNlcnZpY2VOYW1lOiBzdHJpbmcsXG4gIHJlZ2lvbjogc3RyaW5nLFxuICBzZXJ2aWNlOiB7IGV2ZW50cz86IEFycmF5PHsgbWVzc2FnZT86IHN0cmluZyB9PjsgW2tleTogc3RyaW5nXTogYW55IH0sXG4gIGRlYnVnOiAobXNnOiBzdHJpbmcpID0+IFByb21pc2U8dm9pZD4sXG4pOiBQcm9taXNlPFN0b3BwZWRUYXNrUmVzdWx0PiB7XG4gIHRyeSB7XG4gICAgLy8gQXNrIEVDUyBmb3IgdGhlIHNlcnZpY2UncyBzdG9wcGVkIHRhc2tzLiBUaGUgSURzIHdlIG5lZWQgbGl2ZSBpbiBcImhhcyBzdGFydGVkIDEgdGFza3M6ICh0YXNrIDxpZD4pXCIgZXZlbnRzXG4gICAgY29uc3QgdGFza0lkcyA9IGF3YWl0IGxpc3RTdG9wcGVkVGFza0lkcyhlY3MsIGNsdXN0ZXIsIHNlcnZpY2VOYW1lLCBkZWJ1Zyk7XG5cbiAgICBjb25zdCBtZXNzYWdlczogc3RyaW5nW10gPSBbXTtcblxuICAgIGlmICh0YXNrSWRzLmxlbmd0aCA+IDApIHtcbiAgICAgIC8vIFNob3cgZGV0YWlscyBmcm9tIHRoZSBtb3N0IHJlY2VudGx5IHN0b3BwZWQgdGFzayBvbmx5LlxuICAgICAgY29uc3QgdGFza3NSZXNwID0gYXdhaXQgZWNzLmRlc2NyaWJlVGFza3MoeyBjbHVzdGVyLCB0YXNrczogW3Rhc2tJZHNbMF1dIH0pO1xuICAgICAgY29uc3QgdGFzayA9IHRhc2tzUmVzcC50YXNrcz8uWzBdO1xuICAgICAgaWYgKHRhc2spIHtcbiAgICAgICAgaWYgKHRhc2suc3RvcHBlZFJlYXNvbikge1xuICAgICAgICAgIG1lc3NhZ2VzLnB1c2goYFRhc2sgc3RvcHBlZDogJHt0YXNrLnN0b3BwZWRSZWFzb259YCk7XG4gICAgICAgIH1cbiAgICAgICAgZm9yIChjb25zdCBjb250YWluZXIgb2YgdGFzay5jb250YWluZXJzID8/IFtdKSB7XG4gICAgICAgICAgaWYgKGNvbnRhaW5lci5yZWFzb24pIHtcbiAgICAgICAgICAgIG1lc3NhZ2VzLnB1c2goYENvbnRhaW5lciBcIiR7Y29udGFpbmVyLm5hbWV9XCI6ICR7Y29udGFpbmVyLnJlYXNvbn1gKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKGNvbnRhaW5lci5leGl0Q29kZSAhPSBudWxsICYmIGNvbnRhaW5lci5leGl0Q29kZSAhPT0gMCkge1xuICAgICAgICAgICAgbWVzc2FnZXMucHVzaChgQ29udGFpbmVyIFwiJHtjb250YWluZXIubmFtZX1cIiBleGl0ZWQgd2l0aCBjb2RlICR7Y29udGFpbmVyLmV4aXRDb2RlfWApO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaWYgKG1lc3NhZ2VzLmxlbmd0aCA+IDAgJiYgdGFza0lkcy5sZW5ndGggPiAxKSB7XG4gICAgICAgIG1lc3NhZ2VzLnB1c2goYCgke3Rhc2tJZHMubGVuZ3RoIC0gMX0gb3RoZXIgZmFpbGVkIHRhc2socykgbm90IHNob3duKWApO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEZhbGwgYmFjayB0byB0aGUgbW9zdCByZWxldmFudCBzZXJ2aWNlIGV2ZW50IGlmIHdlIGNvdWxkbid0IGdldCBhIHRhc2stbGV2ZWwgcmVhc29uXG4gICAgLy8gKGUuZy4gdGFza3MgYWxyZWFkeSBhZ2VkIG91dCwgb3Igbm8gc3RvcHBlZCB0YXNrcyByZXRhaW5lZCkuXG4gICAgaWYgKG1lc3NhZ2VzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgY29uc3QgZmFpbHVyZUV2ZW50ID0gKHNlcnZpY2UuZXZlbnRzID8/IFtdKVxuICAgICAgICAuZmluZChlID0+IGUubWVzc2FnZT8uaW5jbHVkZXMoJ3N0b3BwZWQnKSB8fCBlLm1lc3NhZ2U/LmluY2x1ZGVzKCdmYWlsZWQnKSB8fCBlLm1lc3NhZ2U/LmluY2x1ZGVzKCd1bmhlYWx0aHknKSk7XG4gICAgICBpZiAoZmFpbHVyZUV2ZW50Py5tZXNzYWdlKSB7XG4gICAgICAgIG1lc3NhZ2VzLnB1c2goZmFpbHVyZUV2ZW50Lm1lc3NhZ2UpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChtZXNzYWdlcy5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybiB7IHRhc2tJZHMgfTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgY29udGV4dDoge1xuICAgICAgICBzb3VyY2U6ICdFQ1MgU3RvcHBlZCBUYXNrcycsXG4gICAgICAgIG1lc3NhZ2VzLFxuICAgICAgICBsaW5rOiBlY3NTdG9wcGVkVGFza3NDb25zb2xlVXJsKHJlZ2lvbiwgY2x1c3RlciA/PyAnZGVmYXVsdCcsIHNlcnZpY2VOYW1lKSxcbiAgICAgICAgbGlua0xhYmVsOiAnVGFza3MnLFxuICAgICAgfSxcbiAgICAgIHRhc2tJZHMsXG4gICAgfTtcbiAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgYXdhaXQgZGVidWcoYEVDUyBpbnZlc3RpZ2F0aW9uOiBmYWlsZWQgdG8gZ2V0IHN0b3BwZWQgdGFzayByZWFzb25zOiAke2UubWVzc2FnZX1gKTtcbiAgICByZXR1cm4geyB0YXNrSWRzOiBbXSB9O1xuICB9XG59XG5cbi8qKlxuICogTWF4aW11bSBudW1iZXIgb2Ygc3RvcHBlZCB0YXNrIElEcyB0byBjb25zaWRlci4gV2Ugb25seSByZW5kZXIgZGV0YWlsIGZvciB0aGUgbW9zdFxuICogcmVjZW50IG9uZSwgYnV0IGtlZXAgYSBmZXcgc28gd2UgY2FuIHJlcG9ydCBob3cgbWFueSBvdGhlcnMgZmFpbGVkLlxuICovXG5jb25zdCBNQVhfU1RPUFBFRF9UQVNLUyA9IDM7XG5cbi8qKlxuICogTGlzdCB0aGUgYmFyZSB0YXNrIElEcyBvZiB0aGUgc2VydmljZSdzIHN0b3BwZWQgdGFza3MsIG5ld2VzdCBmaXJzdC5cbiAqXG4gKiBQcmVmZXJzIHNjb3BpbmcgYnkgc2VydmljZSBuYW1lOyBpZiB0aGF0IHlpZWxkcyBub3RoaW5nIChzb21lIEVDUyBBUEkgdmVyc2lvbnMgb25seVxuICogYXBwbHkgdGhlIHNlcnZpY2UgZmlsdGVyIHRvIHJ1bm5pbmcgdGFza3MpLCBmYWxscyBiYWNrIHRvIGxpc3RpbmcgdGhlIGNsdXN0ZXIncyBzdG9wcGVkXG4gKiB0YXNrcy4gUmV0dXJucyBhbiBlbXB0eSBhcnJheSBpZiBub25lIGFyZSByZXRhaW5lZCAoZS5nLiB0aGV5IGFnZWQgb3V0LCBvciByb2xsYmFja1xuICogYWxyZWFkeSBkcmFpbmVkIHRoZSBjbHVzdGVyKS5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gbGlzdFN0b3BwZWRUYXNrSWRzKFxuICBlY3M6IElFQ1NDbGllbnQsXG4gIGNsdXN0ZXI6IHN0cmluZyB8IHVuZGVmaW5lZCxcbiAgc2VydmljZU5hbWU6IHN0cmluZyxcbiAgZGVidWc6IChtc2c6IHN0cmluZykgPT4gUHJvbWlzZTx2b2lkPixcbik6IFByb21pc2U8c3RyaW5nW10+IHtcbiAgY29uc3QgdG9JZHMgPSAoYXJuczogc3RyaW5nW10gfCB1bmRlZmluZWQpID0+IChhcm5zID8/IFtdKS5tYXAoYXJuID0+IGFybi5zcGxpdCgnLycpLnBvcCgpKS5maWx0ZXIoKGlkKTogaWQgaXMgc3RyaW5nID0+ICEhaWQpO1xuXG4gIGxldCBhcm5zOiBzdHJpbmdbXSB8IHVuZGVmaW5lZDtcbiAgdHJ5IHtcbiAgICBjb25zdCBieVNlcnZpY2UgPSBhd2FpdCBlY3MubGlzdFRhc2tzKHsgY2x1c3Rlciwgc2VydmljZU5hbWUsIGRlc2lyZWRTdGF0dXM6ICdTVE9QUEVEJyB9KTtcbiAgICBhcm5zID0gYnlTZXJ2aWNlLnRhc2tBcm5zO1xuICAgIGlmICghYXJucyB8fCBhcm5zLmxlbmd0aCA9PT0gMCkge1xuICAgICAgY29uc3QgYnlDbHVzdGVyID0gYXdhaXQgZWNzLmxpc3RUYXNrcyh7IGNsdXN0ZXIsIGRlc2lyZWRTdGF0dXM6ICdTVE9QUEVEJyB9KTtcbiAgICAgIGFybnMgPSBieUNsdXN0ZXIudGFza0FybnM7XG4gICAgfVxuICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICBhd2FpdCBkZWJ1ZyhgRUNTIGludmVzdGlnYXRpb246IGZhaWxlZCB0byBsaXN0IHN0b3BwZWQgdGFza3M6ICR7ZS5tZXNzYWdlfWApO1xuICAgIHJldHVybiBbXTtcbiAgfVxuXG4gIHJldHVybiB0b0lkcyhhcm5zKS5zbGljZSgwLCBNQVhfU1RPUFBFRF9UQVNLUyk7XG59XG5cbmludGVyZmFjZSBBd3NMb2dzQ29uZmlnIHtcbiAgbG9nR3JvdXA6IHN0cmluZztcbiAgc3RyZWFtUHJlZml4Pzogc3RyaW5nO1xuICBjb250YWluZXJOYW1lPzogc3RyaW5nO1xufVxuXG5pbnRlcmZhY2UgVGFza0RlZmluaXRpb25JbmZvIHtcbiAgbG9nQ29uZmlnczogQXdzTG9nc0NvbmZpZ1tdO1xufVxuXG5hc3luYyBmdW5jdGlvbiBnZXRUYXNrRGVmaW5pdGlvbkluZm8oXG4gIGVjczogSUVDU0NsaWVudCxcbiAgdGFza0RlZmluaXRpb25Bcm46IHN0cmluZyxcbiAgZGVidWc6IChtc2c6IHN0cmluZykgPT4gUHJvbWlzZTx2b2lkPixcbik6IFByb21pc2U8VGFza0RlZmluaXRpb25JbmZvIHwgdW5kZWZpbmVkPiB7XG4gIHRyeSB7XG4gICAgY29uc3QgcmVzcCA9IGF3YWl0IGVjcy5kZXNjcmliZVRhc2tEZWZpbml0aW9uKHsgdGFza0RlZmluaXRpb246IHRhc2tEZWZpbml0aW9uQXJuIH0pO1xuICAgIGNvbnN0IGNvbnRhaW5lcnMgPSByZXNwLnRhc2tEZWZpbml0aW9uPy5jb250YWluZXJEZWZpbml0aW9ucyA/PyBbXTtcbiAgICBjb25zdCBsb2dDb25maWdzOiBBd3NMb2dzQ29uZmlnW10gPSBbXTtcbiAgICBmb3IgKGNvbnN0IGNvbnRhaW5lciBvZiBjb250YWluZXJzKSB7XG4gICAgICBjb25zdCBsb2dDb25maWcgPSBjb250YWluZXIubG9nQ29uZmlndXJhdGlvbjtcbiAgICAgIGlmIChsb2dDb25maWc/LmxvZ0RyaXZlciA9PT0gJ2F3c2xvZ3MnKSB7XG4gICAgICAgIGNvbnN0IGxvZ0dyb3VwID0gbG9nQ29uZmlnLm9wdGlvbnM/LlsnYXdzbG9ncy1ncm91cCddO1xuICAgICAgICBpZiAobG9nR3JvdXApIHtcbiAgICAgICAgICBsb2dDb25maWdzLnB1c2goe1xuICAgICAgICAgICAgbG9nR3JvdXAsXG4gICAgICAgICAgICBzdHJlYW1QcmVmaXg6IGxvZ0NvbmZpZy5vcHRpb25zPy5bJ2F3c2xvZ3Mtc3RyZWFtLXByZWZpeCddLFxuICAgICAgICAgICAgY29udGFpbmVyTmFtZTogY29udGFpbmVyLm5hbWUsXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHsgbG9nQ29uZmlncyB9O1xuICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICBhd2FpdCBkZWJ1ZyhgRUNTIGludmVzdGlnYXRpb246IGZhaWxlZCB0byBkZXNjcmliZSB0YXNrIGRlZmluaXRpb246ICR7ZS5tZXNzYWdlfWApO1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gZmV0Y2hSZWNlbnRMb2dzKFxuICBjd2w6IElDbG91ZFdhdGNoTG9nc0NsaWVudCxcbiAgbG9nQ29uZmlnOiBBd3NMb2dzQ29uZmlnLFxuICByZWdpb246IHN0cmluZyxcbiAgdGFza0lkczogc3RyaW5nW10sXG4gIGRlYnVnOiAobXNnOiBzdHJpbmcpID0+IFByb21pc2U8dm9pZD4sXG4pOiBQcm9taXNlPEFkZGl0aW9uYWxEaWFnbm9zdGljQ29udGV4dCB8IHVuZGVmaW5lZD4ge1xuICB0cnkge1xuICAgIC8vIFRhcmdldCB0aGUgbW9zdCByZWNlbnRseSBmYWlsZWQgdGFzaydzIGxvZyBzdHJlYW0gZm9yIHRoZSBtb3N0IHJlbGV2YW50IG91dHB1dFxuICAgIGNvbnN0IGxhc3RUYXNrSWQgPSB0YXNrSWRzWzBdO1xuICAgIGNvbnN0IHRhcmdldFN0cmVhbSA9IChsb2dDb25maWcuc3RyZWFtUHJlZml4ICYmIGxvZ0NvbmZpZy5jb250YWluZXJOYW1lICYmIGxhc3RUYXNrSWQpXG4gICAgICA/IGAke2xvZ0NvbmZpZy5zdHJlYW1QcmVmaXh9LyR7bG9nQ29uZmlnLmNvbnRhaW5lck5hbWV9LyR7bGFzdFRhc2tJZH1gXG4gICAgICA6IHVuZGVmaW5lZDtcblxuICAgIGNvbnN0IHJlc3AgPSBhd2FpdCBjd2wuZmlsdGVyTG9nRXZlbnRzKHtcbiAgICAgIGxvZ0dyb3VwTmFtZTogbG9nQ29uZmlnLmxvZ0dyb3VwLFxuICAgICAgc3RhcnRUaW1lOiBEYXRlLm5vdygpIC0gRkFMTEJBQ0tfTE9HX1dJTkRPV19NUyxcbiAgICAgIGxpbWl0OiAxMDAwLFxuICAgICAgLi4uKHRhcmdldFN0cmVhbVxuICAgICAgICA/IHsgbG9nU3RyZWFtTmFtZXM6IFt0YXJnZXRTdHJlYW1dIH1cbiAgICAgICAgOiBsb2dDb25maWcuc3RyZWFtUHJlZml4ID8geyBsb2dTdHJlYW1OYW1lUHJlZml4OiBsb2dDb25maWcuc3RyZWFtUHJlZml4IH0gOiB7fSksXG4gICAgfSk7XG5cbiAgICBjb25zdCBldmVudHMgPSByZXNwLmV2ZW50cyA/PyBbXTtcbiAgICBpZiAoZXZlbnRzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgYXdhaXQgZGVidWcoYEVDUyBpbnZlc3RpZ2F0aW9uOiBubyByZWNlbnQgbG9nIGV2ZW50cyBpbiAke2xvZ0NvbmZpZy5sb2dHcm91cH0ke3RhcmdldFN0cmVhbSA/IGAgKHRhcmdldGVkIHN0cmVhbTogJHt0YXJnZXRTdHJlYW19KWAgOiAnJ31gKTtcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgY29uc3QgbWVzc2FnZXMgPSB0cmltVG9SZWNlbnRMaW5lcyhcbiAgICAgIGV2ZW50cy5tYXAoZSA9PiBlLm1lc3NhZ2U/LnRyaW1FbmQoKSkuZmlsdGVyKChtKTogbSBpcyBzdHJpbmcgPT4gbSAhPSBudWxsKSxcbiAgICApO1xuXG4gICAgaWYgKHRhc2tJZHMubGVuZ3RoID4gMSkge1xuICAgICAgbWVzc2FnZXMucHVzaChgKHNob3dpbmcgbG9ncyBmcm9tIGxhc3QgZmFpbGVkIHRhc2s7ICR7dGFza0lkcy5sZW5ndGggLSAxfSBvdGhlciBmYWlsZWQgdGFzayhzKSBhdmFpbGFibGUgaW4gY29uc29sZSlgKTtcbiAgICB9XG5cbiAgICBjb25zdCBzb3VyY2UgPSBsb2dDb25maWcuY29udGFpbmVyTmFtZVxuICAgICAgPyBgQ2xvdWRXYXRjaCBMb2dzOiAke2xvZ0NvbmZpZy5sb2dHcm91cH0gKGNvbnRhaW5lcjogJHtsb2dDb25maWcuY29udGFpbmVyTmFtZX0pYFxuICAgICAgOiBgQ2xvdWRXYXRjaCBMb2dzOiAke2xvZ0NvbmZpZy5sb2dHcm91cH1gO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIHNvdXJjZSxcbiAgICAgIG1lc3NhZ2VzLFxuICAgICAgbGluazogY2xvdWRXYXRjaExvZ3NDb25zb2xlVXJsKHJlZ2lvbiwgbG9nQ29uZmlnLmxvZ0dyb3VwKSxcbiAgICAgIGxpbmtMYWJlbDogJ0xvZ3MnLFxuICAgIH07XG4gIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgIGF3YWl0IGRlYnVnKGBFQ1MgaW52ZXN0aWdhdGlvbjogZmFpbGVkIHRvIGZldGNoIGxvZ3MgZnJvbSAke2xvZ0NvbmZpZy5sb2dHcm91cH06ICR7ZS5tZXNzYWdlfWApO1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbn1cbiJdfQ==
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/** Pure parsers for resource identifiers used during failure diagnosis. */
|
|
2
|
+
/**
|
|
3
|
+
* Parse an ECS service physical resource ID into cluster and service identifiers.
|
|
4
|
+
*
|
|
5
|
+
* The cluster portion is a name (not an ARN) — `describeServices`/`describeTasks`
|
|
6
|
+
* accept either form for their `cluster` parameter, so this is fine downstream.
|
|
7
|
+
*
|
|
8
|
+
* Recognized formats:
|
|
9
|
+
* - Long ARN: `arn:aws:ecs:region:account:service/cluster-name/service-name` (current default)
|
|
10
|
+
* - Path: `cluster-name/service-name`
|
|
11
|
+
* - Bare service name (uses the default cluster)
|
|
12
|
+
*/
|
|
13
|
+
export declare function parseEcsServiceIdentifier(physicalId: string): {
|
|
14
|
+
cluster?: string;
|
|
15
|
+
serviceName?: string;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* If a ServiceToken is an `Fn::GetAtt` or `Ref` intrinsic, return the referenced logical ID.
|
|
19
|
+
*/
|
|
20
|
+
export declare function serviceTokenReferencedLogicalId(serviceToken: any): string | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* Extract a Lambda function name from a function ARN or a bare name.
|
|
23
|
+
*
|
|
24
|
+
* Returns `undefined` for non-Lambda ARNs (e.g. an SNS-topic ServiceToken).
|
|
25
|
+
*/
|
|
26
|
+
export declare function functionNameFromArnOrName(arnOrName: string): string | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Extract the log stream name out of a cfn-response failure reason
|
|
29
|
+
* ("See the details in CloudWatch Log Stream: <name>").
|
|
30
|
+
*/
|
|
31
|
+
export declare function extractLogStreamName(message: string | undefined): string | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* cfn-response defaults the physical ID to the log stream name. Use it only when it looks
|
|
34
|
+
* like a Lambda log stream (`YYYY/MM/DD/...`), so a user-provided physical ID isn't mistaken
|
|
35
|
+
* for one.
|
|
36
|
+
*/
|
|
37
|
+
export declare function logStreamNameFromPhysicalId(physicalId: string | undefined): string | undefined;
|
|
38
|
+
export declare function ecsStoppedTasksConsoleUrl(region: string, cluster: string, serviceName: string): string;
|
|
39
|
+
//# sourceMappingURL=resource-identifiers.d.ts.map
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/** Pure parsers for resource identifiers used during failure diagnosis. */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.parseEcsServiceIdentifier = parseEcsServiceIdentifier;
|
|
5
|
+
exports.serviceTokenReferencedLogicalId = serviceTokenReferencedLogicalId;
|
|
6
|
+
exports.functionNameFromArnOrName = functionNameFromArnOrName;
|
|
7
|
+
exports.extractLogStreamName = extractLogStreamName;
|
|
8
|
+
exports.logStreamNameFromPhysicalId = logStreamNameFromPhysicalId;
|
|
9
|
+
exports.ecsStoppedTasksConsoleUrl = ecsStoppedTasksConsoleUrl;
|
|
10
|
+
/**
|
|
11
|
+
* Parse an ECS service physical resource ID into cluster and service identifiers.
|
|
12
|
+
*
|
|
13
|
+
* The cluster portion is a name (not an ARN) — `describeServices`/`describeTasks`
|
|
14
|
+
* accept either form for their `cluster` parameter, so this is fine downstream.
|
|
15
|
+
*
|
|
16
|
+
* Recognized formats:
|
|
17
|
+
* - Long ARN: `arn:aws:ecs:region:account:service/cluster-name/service-name` (current default)
|
|
18
|
+
* - Path: `cluster-name/service-name`
|
|
19
|
+
* - Bare service name (uses the default cluster)
|
|
20
|
+
*/
|
|
21
|
+
function parseEcsServiceIdentifier(physicalId) {
|
|
22
|
+
const arnMatch = physicalId.match(/^arn:[^:]+:ecs:[^:]*:[^:]*:service\/([^/]+)\/([^/]+)$/);
|
|
23
|
+
if (arnMatch) {
|
|
24
|
+
return { cluster: arnMatch[1], serviceName: arnMatch[2] };
|
|
25
|
+
}
|
|
26
|
+
const parts = physicalId.split('/');
|
|
27
|
+
if (parts.length === 2 && parts[0] && parts[1]) {
|
|
28
|
+
return { cluster: parts[0], serviceName: parts[1] };
|
|
29
|
+
}
|
|
30
|
+
if (parts.length === 1 && parts[0]) {
|
|
31
|
+
return { serviceName: parts[0] };
|
|
32
|
+
}
|
|
33
|
+
return {};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* If a ServiceToken is an `Fn::GetAtt` or `Ref` intrinsic, return the referenced logical ID.
|
|
37
|
+
*/
|
|
38
|
+
function serviceTokenReferencedLogicalId(serviceToken) {
|
|
39
|
+
if (!serviceToken || typeof serviceToken !== 'object') {
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
const getAtt = serviceToken['Fn::GetAtt'];
|
|
43
|
+
// Array form (JSON / CDK output): ["LogicalId", "Arn"].
|
|
44
|
+
if (Array.isArray(getAtt) && typeof getAtt[0] === 'string') {
|
|
45
|
+
return getAtt[0];
|
|
46
|
+
}
|
|
47
|
+
// String short-form (how YAML `!GetAtt LogicalId.Arn` deserializes): "LogicalId.Attr".
|
|
48
|
+
if (typeof getAtt === 'string') {
|
|
49
|
+
return getAtt.split('.')[0] || undefined;
|
|
50
|
+
}
|
|
51
|
+
if (typeof serviceToken.Ref === 'string') {
|
|
52
|
+
return serviceToken.Ref;
|
|
53
|
+
}
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Extract a Lambda function name from a function ARN or a bare name.
|
|
58
|
+
*
|
|
59
|
+
* Returns `undefined` for non-Lambda ARNs (e.g. an SNS-topic ServiceToken).
|
|
60
|
+
*/
|
|
61
|
+
function functionNameFromArnOrName(arnOrName) {
|
|
62
|
+
const arnMatch = arnOrName.match(/^arn:[^:]+:lambda:[^:]*:[^:]*:function:([^:]+)/);
|
|
63
|
+
if (arnMatch) {
|
|
64
|
+
return arnMatch[1];
|
|
65
|
+
}
|
|
66
|
+
if (arnOrName.startsWith('arn:')) {
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
return arnOrName || undefined;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Extract the log stream name out of a cfn-response failure reason
|
|
73
|
+
* ("See the details in CloudWatch Log Stream: <name>").
|
|
74
|
+
*/
|
|
75
|
+
function extractLogStreamName(message) {
|
|
76
|
+
const match = message?.match(/CloudWatch Log Stream:\s*(\S+)/);
|
|
77
|
+
return match ? match[1] : undefined;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* cfn-response defaults the physical ID to the log stream name. Use it only when it looks
|
|
81
|
+
* like a Lambda log stream (`YYYY/MM/DD/...`), so a user-provided physical ID isn't mistaken
|
|
82
|
+
* for one.
|
|
83
|
+
*/
|
|
84
|
+
function logStreamNameFromPhysicalId(physicalId) {
|
|
85
|
+
return physicalId && /^\d{4}\/\d{2}\/\d{2}\/.+/.test(physicalId) ? physicalId : undefined;
|
|
86
|
+
}
|
|
87
|
+
function ecsStoppedTasksConsoleUrl(region, cluster, serviceName) {
|
|
88
|
+
return `https://${region}.console.aws.amazon.com/ecs/v2/clusters/${cluster}/services/${serviceName}/tasks?status=STOPPED®ion=${region}`;
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVzb3VyY2UtaWRlbnRpZmllcnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJyZXNvdXJjZS1pZGVudGlmaWVycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsMkVBQTJFOztBQWEzRSw4REFlQztBQUtELDBFQWlCQztBQU9ELDhEQVNDO0FBTUQsb0RBR0M7QUFPRCxrRUFFQztBQUVELDhEQUVDO0FBdEZEOzs7Ozs7Ozs7O0dBVUc7QUFDSCxTQUFnQix5QkFBeUIsQ0FBQyxVQUFrQjtJQUMxRCxNQUFNLFFBQVEsR0FBRyxVQUFVLENBQUMsS0FBSyxDQUFDLHVEQUF1RCxDQUFDLENBQUM7SUFDM0YsSUFBSSxRQUFRLEVBQUUsQ0FBQztRQUNiLE9BQU8sRUFBRSxPQUFPLEVBQUUsUUFBUSxDQUFDLENBQUMsQ0FBQyxFQUFFLFdBQVcsRUFBRSxRQUFRLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztJQUM1RCxDQUFDO0lBRUQsTUFBTSxLQUFLLEdBQUcsVUFBVSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUNwQyxJQUFJLEtBQUssQ0FBQyxNQUFNLEtBQUssQ0FBQyxJQUFJLEtBQUssQ0FBQyxDQUFDLENBQUMsSUFBSSxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUMvQyxPQUFPLEVBQUUsT0FBTyxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxXQUFXLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7SUFDdEQsQ0FBQztJQUNELElBQUksS0FBSyxDQUFDLE1BQU0sS0FBSyxDQUFDLElBQUksS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDbkMsT0FBTyxFQUFFLFdBQVcsRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztJQUNuQyxDQUFDO0lBRUQsT0FBTyxFQUFFLENBQUM7QUFDWixDQUFDO0FBRUQ7O0dBRUc7QUFDSCxTQUFnQiwrQkFBK0IsQ0FBQyxZQUFpQjtJQUMvRCxJQUFJLENBQUMsWUFBWSxJQUFJLE9BQU8sWUFBWSxLQUFLLFFBQVEsRUFBRSxDQUFDO1FBQ3RELE9BQU8sU0FBUyxDQUFDO0lBQ25CLENBQUM7SUFDRCxNQUFNLE1BQU0sR0FBRyxZQUFZLENBQUMsWUFBWSxDQUFDLENBQUM7SUFDMUMsd0RBQXdEO0lBQ3hELElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsSUFBSSxPQUFPLE1BQU0sQ0FBQyxDQUFDLENBQUMsS0FBSyxRQUFRLEVBQUUsQ0FBQztRQUMzRCxPQUFPLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNuQixDQUFDO0lBQ0QsdUZBQXVGO0lBQ3ZGLElBQUksT0FBTyxNQUFNLEtBQUssUUFBUSxFQUFFLENBQUM7UUFDL0IsT0FBTyxNQUFNLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLFNBQVMsQ0FBQztJQUMzQyxDQUFDO0lBQ0QsSUFBSSxPQUFPLFlBQVksQ0FBQyxHQUFHLEtBQUssUUFBUSxFQUFFLENBQUM7UUFDekMsT0FBTyxZQUFZLENBQUMsR0FBRyxDQUFDO0lBQzFCLENBQUM7SUFDRCxPQUFPLFNBQVMsQ0FBQztBQUNuQixDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILFNBQWdCLHlCQUF5QixDQUFDLFNBQWlCO0lBQ3pELE1BQU0sUUFBUSxHQUFHLFNBQVMsQ0FBQyxLQUFLLENBQUMsZ0RBQWdELENBQUMsQ0FBQztJQUNuRixJQUFJLFFBQVEsRUFBRSxDQUFDO1FBQ2IsT0FBTyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDckIsQ0FBQztJQUNELElBQUksU0FBUyxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO1FBQ2pDLE9BQU8sU0FBUyxDQUFDO0lBQ25CLENBQUM7SUFDRCxPQUFPLFNBQVMsSUFBSSxTQUFTLENBQUM7QUFDaEMsQ0FBQztBQUVEOzs7R0FHRztBQUNILFNBQWdCLG9CQUFvQixDQUFDLE9BQTJCO0lBQzlELE1BQU0sS0FBSyxHQUFHLE9BQU8sRUFBRSxLQUFLLENBQUMsZ0NBQWdDLENBQUMsQ0FBQztJQUMvRCxPQUFPLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7QUFDdEMsQ0FBQztBQUVEOzs7O0dBSUc7QUFDSCxTQUFnQiwyQkFBMkIsQ0FBQyxVQUE4QjtJQUN4RSxPQUFPLFVBQVUsSUFBSSwwQkFBMEIsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO0FBQzVGLENBQUM7QUFFRCxTQUFnQix5QkFBeUIsQ0FBQyxNQUFjLEVBQUUsT0FBZSxFQUFFLFdBQW1CO0lBQzVGLE9BQU8sV0FBVyxNQUFNLDJDQUEyQyxPQUFPLGFBQWEsV0FBVyxnQ0FBZ0MsTUFBTSxFQUFFLENBQUM7QUFDN0ksQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKiBQdXJlIHBhcnNlcnMgZm9yIHJlc291cmNlIGlkZW50aWZpZXJzIHVzZWQgZHVyaW5nIGZhaWx1cmUgZGlhZ25vc2lzLiAqL1xuXG4vKipcbiAqIFBhcnNlIGFuIEVDUyBzZXJ2aWNlIHBoeXNpY2FsIHJlc291cmNlIElEIGludG8gY2x1c3RlciBhbmQgc2VydmljZSBpZGVudGlmaWVycy5cbiAqXG4gKiBUaGUgY2x1c3RlciBwb3J0aW9uIGlzIGEgbmFtZSAobm90IGFuIEFSTikg4oCUIGBkZXNjcmliZVNlcnZpY2VzYC9gZGVzY3JpYmVUYXNrc2BcbiAqIGFjY2VwdCBlaXRoZXIgZm9ybSBmb3IgdGhlaXIgYGNsdXN0ZXJgIHBhcmFtZXRlciwgc28gdGhpcyBpcyBmaW5lIGRvd25zdHJlYW0uXG4gKlxuICogUmVjb2duaXplZCBmb3JtYXRzOlxuICogLSBMb25nIEFSTjogYGFybjphd3M6ZWNzOnJlZ2lvbjphY2NvdW50OnNlcnZpY2UvY2x1c3Rlci1uYW1lL3NlcnZpY2UtbmFtZWAgKGN1cnJlbnQgZGVmYXVsdClcbiAqIC0gUGF0aDogYGNsdXN0ZXItbmFtZS9zZXJ2aWNlLW5hbWVgXG4gKiAtIEJhcmUgc2VydmljZSBuYW1lICh1c2VzIHRoZSBkZWZhdWx0IGNsdXN0ZXIpXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwYXJzZUVjc1NlcnZpY2VJZGVudGlmaWVyKHBoeXNpY2FsSWQ6IHN0cmluZyk6IHsgY2x1c3Rlcj86IHN0cmluZzsgc2VydmljZU5hbWU/OiBzdHJpbmcgfSB7XG4gIGNvbnN0IGFybk1hdGNoID0gcGh5c2ljYWxJZC5tYXRjaCgvXmFybjpbXjpdKzplY3M6W146XSo6W146XSo6c2VydmljZVxcLyhbXi9dKylcXC8oW14vXSspJC8pO1xuICBpZiAoYXJuTWF0Y2gpIHtcbiAgICByZXR1cm4geyBjbHVzdGVyOiBhcm5NYXRjaFsxXSwgc2VydmljZU5hbWU6IGFybk1hdGNoWzJdIH07XG4gIH1cblxuICBjb25zdCBwYXJ0cyA9IHBoeXNpY2FsSWQuc3BsaXQoJy8nKTtcbiAgaWYgKHBhcnRzLmxlbmd0aCA9PT0gMiAmJiBwYXJ0c1swXSAmJiBwYXJ0c1sxXSkge1xuICAgIHJldHVybiB7IGNsdXN0ZXI6IHBhcnRzWzBdLCBzZXJ2aWNlTmFtZTogcGFydHNbMV0gfTtcbiAgfVxuICBpZiAocGFydHMubGVuZ3RoID09PSAxICYmIHBhcnRzWzBdKSB7XG4gICAgcmV0dXJuIHsgc2VydmljZU5hbWU6IHBhcnRzWzBdIH07XG4gIH1cblxuICByZXR1cm4ge307XG59XG5cbi8qKlxuICogSWYgYSBTZXJ2aWNlVG9rZW4gaXMgYW4gYEZuOjpHZXRBdHRgIG9yIGBSZWZgIGludHJpbnNpYywgcmV0dXJuIHRoZSByZWZlcmVuY2VkIGxvZ2ljYWwgSUQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzZXJ2aWNlVG9rZW5SZWZlcmVuY2VkTG9naWNhbElkKHNlcnZpY2VUb2tlbjogYW55KTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgaWYgKCFzZXJ2aWNlVG9rZW4gfHwgdHlwZW9mIHNlcnZpY2VUb2tlbiAhPT0gJ29iamVjdCcpIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG4gIGNvbnN0IGdldEF0dCA9IHNlcnZpY2VUb2tlblsnRm46OkdldEF0dCddO1xuICAvLyBBcnJheSBmb3JtIChKU09OIC8gQ0RLIG91dHB1dCk6IFtcIkxvZ2ljYWxJZFwiLCBcIkFyblwiXS5cbiAgaWYgKEFycmF5LmlzQXJyYXkoZ2V0QXR0KSAmJiB0eXBlb2YgZ2V0QXR0WzBdID09PSAnc3RyaW5nJykge1xuICAgIHJldHVybiBnZXRBdHRbMF07XG4gIH1cbiAgLy8gU3RyaW5nIHNob3J0LWZvcm0gKGhvdyBZQU1MIGAhR2V0QXR0IExvZ2ljYWxJZC5Bcm5gIGRlc2VyaWFsaXplcyk6IFwiTG9naWNhbElkLkF0dHJcIi5cbiAgaWYgKHR5cGVvZiBnZXRBdHQgPT09ICdzdHJpbmcnKSB7XG4gICAgcmV0dXJuIGdldEF0dC5zcGxpdCgnLicpWzBdIHx8IHVuZGVmaW5lZDtcbiAgfVxuICBpZiAodHlwZW9mIHNlcnZpY2VUb2tlbi5SZWYgPT09ICdzdHJpbmcnKSB7XG4gICAgcmV0dXJuIHNlcnZpY2VUb2tlbi5SZWY7XG4gIH1cbiAgcmV0dXJuIHVuZGVmaW5lZDtcbn1cblxuLyoqXG4gKiBFeHRyYWN0IGEgTGFtYmRhIGZ1bmN0aW9uIG5hbWUgZnJvbSBhIGZ1bmN0aW9uIEFSTiBvciBhIGJhcmUgbmFtZS5cbiAqXG4gKiBSZXR1cm5zIGB1bmRlZmluZWRgIGZvciBub24tTGFtYmRhIEFSTnMgKGUuZy4gYW4gU05TLXRvcGljIFNlcnZpY2VUb2tlbikuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmdW5jdGlvbk5hbWVGcm9tQXJuT3JOYW1lKGFybk9yTmFtZTogc3RyaW5nKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgYXJuTWF0Y2ggPSBhcm5Pck5hbWUubWF0Y2goL15hcm46W146XSs6bGFtYmRhOlteOl0qOlteOl0qOmZ1bmN0aW9uOihbXjpdKykvKTtcbiAgaWYgKGFybk1hdGNoKSB7XG4gICAgcmV0dXJuIGFybk1hdGNoWzFdO1xuICB9XG4gIGlmIChhcm5Pck5hbWUuc3RhcnRzV2l0aCgnYXJuOicpKSB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuICByZXR1cm4gYXJuT3JOYW1lIHx8IHVuZGVmaW5lZDtcbn1cblxuLyoqXG4gKiBFeHRyYWN0IHRoZSBsb2cgc3RyZWFtIG5hbWUgb3V0IG9mIGEgY2ZuLXJlc3BvbnNlIGZhaWx1cmUgcmVhc29uXG4gKiAoXCJTZWUgdGhlIGRldGFpbHMgaW4gQ2xvdWRXYXRjaCBMb2cgU3RyZWFtOiA8bmFtZT5cIikuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBleHRyYWN0TG9nU3RyZWFtTmFtZShtZXNzYWdlOiBzdHJpbmcgfCB1bmRlZmluZWQpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICBjb25zdCBtYXRjaCA9IG1lc3NhZ2U/Lm1hdGNoKC9DbG91ZFdhdGNoIExvZyBTdHJlYW06XFxzKihcXFMrKS8pO1xuICByZXR1cm4gbWF0Y2ggPyBtYXRjaFsxXSA6IHVuZGVmaW5lZDtcbn1cblxuLyoqXG4gKiBjZm4tcmVzcG9uc2UgZGVmYXVsdHMgdGhlIHBoeXNpY2FsIElEIHRvIHRoZSBsb2cgc3RyZWFtIG5hbWUuIFVzZSBpdCBvbmx5IHdoZW4gaXQgbG9va3NcbiAqIGxpa2UgYSBMYW1iZGEgbG9nIHN0cmVhbSAoYFlZWVkvTU0vREQvLi4uYCksIHNvIGEgdXNlci1wcm92aWRlZCBwaHlzaWNhbCBJRCBpc24ndCBtaXN0YWtlblxuICogZm9yIG9uZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGxvZ1N0cmVhbU5hbWVGcm9tUGh5c2ljYWxJZChwaHlzaWNhbElkOiBzdHJpbmcgfCB1bmRlZmluZWQpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICByZXR1cm4gcGh5c2ljYWxJZCAmJiAvXlxcZHs0fVxcL1xcZHsyfVxcL1xcZHsyfVxcLy4rLy50ZXN0KHBoeXNpY2FsSWQpID8gcGh5c2ljYWxJZCA6IHVuZGVmaW5lZDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGVjc1N0b3BwZWRUYXNrc0NvbnNvbGVVcmwocmVnaW9uOiBzdHJpbmcsIGNsdXN0ZXI6IHN0cmluZywgc2VydmljZU5hbWU6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiBgaHR0cHM6Ly8ke3JlZ2lvbn0uY29uc29sZS5hd3MuYW1hem9uLmNvbS9lY3MvdjIvY2x1c3RlcnMvJHtjbHVzdGVyfS9zZXJ2aWNlcy8ke3NlcnZpY2VOYW1lfS90YXNrcz9zdGF0dXM9U1RPUFBFRCZyZWdpb249JHtyZWdpb259YDtcbn1cbiJdfQ==
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type InvestigateOptions } from './investigate-ecs-service';
|
|
2
|
+
import type { AdditionalDiagnosticContext } from '../../actions/diagnose';
|
|
3
|
+
import type { SDK } from '../aws-auth/sdk';
|
|
4
|
+
import type { ResourceError } from '../stack-events/resource-errors';
|
|
5
|
+
export type { InvestigateOptions };
|
|
6
|
+
/**
|
|
7
|
+
* Investigate a failed resource using AWS service APIs to gather additional root cause context.
|
|
8
|
+
*
|
|
9
|
+
* Returns additional diagnostic context (e.g. log lines) or an empty array if
|
|
10
|
+
* investigation is not possible or yields no results for this resource type.
|
|
11
|
+
*/
|
|
12
|
+
export declare function investigateResource(err: ResourceError, sdk: SDK, debug: (msg: string) => Promise<void>, options?: InvestigateOptions): Promise<AdditionalDiagnosticContext[]>;
|
|
13
|
+
//# sourceMappingURL=resource-investigation.d.ts.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.investigateResource = investigateResource;
|
|
4
|
+
const investigate_custom_resource_1 = require("./investigate-custom-resource");
|
|
5
|
+
const investigate_ecs_service_1 = require("./investigate-ecs-service");
|
|
6
|
+
/**
|
|
7
|
+
* Investigate a failed resource using AWS service APIs to gather additional root cause context.
|
|
8
|
+
*
|
|
9
|
+
* Returns additional diagnostic context (e.g. log lines) or an empty array if
|
|
10
|
+
* investigation is not possible or yields no results for this resource type.
|
|
11
|
+
*/
|
|
12
|
+
async function investigateResource(err, sdk, debug, options = {}) {
|
|
13
|
+
const resourceType = err.resourceType ?? '';
|
|
14
|
+
if (resourceType === 'AWS::ECS::Service') {
|
|
15
|
+
return (0, investigate_ecs_service_1.investigateEcsService)(err, sdk, debug, options);
|
|
16
|
+
}
|
|
17
|
+
if (resourceType === 'AWS::CloudFormation::CustomResource' || resourceType.startsWith('Custom::')) {
|
|
18
|
+
return (0, investigate_custom_resource_1.investigateCustomResource)(err, sdk, debug);
|
|
19
|
+
}
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVzb3VyY2UtaW52ZXN0aWdhdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInJlc291cmNlLWludmVzdGlnYXRpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFjQSxrREFjQztBQTVCRCwrRUFBMEU7QUFDMUUsdUVBQTJGO0FBTzNGOzs7OztHQUtHO0FBQ0ksS0FBSyxVQUFVLG1CQUFtQixDQUN2QyxHQUFrQixFQUNsQixHQUFRLEVBQ1IsS0FBcUMsRUFDckMsVUFBOEIsRUFBRTtJQUVoQyxNQUFNLFlBQVksR0FBRyxHQUFHLENBQUMsWUFBWSxJQUFJLEVBQUUsQ0FBQztJQUM1QyxJQUFJLFlBQVksS0FBSyxtQkFBbUIsRUFBRSxDQUFDO1FBQ3pDLE9BQU8sSUFBQSwrQ0FBcUIsRUFBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLEtBQUssRUFBRSxPQUFPLENBQUMsQ0FBQztJQUN6RCxDQUFDO0lBQ0QsSUFBSSxZQUFZLEtBQUsscUNBQXFDLElBQUksWUFBWSxDQUFDLFVBQVUsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDO1FBQ2xHLE9BQU8sSUFBQSx1REFBeUIsRUFBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBQ3BELENBQUM7SUFDRCxPQUFPLEVBQUUsQ0FBQztBQUNaLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBpbnZlc3RpZ2F0ZUN1c3RvbVJlc291cmNlIH0gZnJvbSAnLi9pbnZlc3RpZ2F0ZS1jdXN0b20tcmVzb3VyY2UnO1xuaW1wb3J0IHsgaW52ZXN0aWdhdGVFY3NTZXJ2aWNlLCB0eXBlIEludmVzdGlnYXRlT3B0aW9ucyB9IGZyb20gJy4vaW52ZXN0aWdhdGUtZWNzLXNlcnZpY2UnO1xuaW1wb3J0IHR5cGUgeyBBZGRpdGlvbmFsRGlhZ25vc3RpY0NvbnRleHQgfSBmcm9tICcuLi8uLi9hY3Rpb25zL2RpYWdub3NlJztcbmltcG9ydCB0eXBlIHsgU0RLIH0gZnJvbSAnLi4vYXdzLWF1dGgvc2RrJztcbmltcG9ydCB0eXBlIHsgUmVzb3VyY2VFcnJvciB9IGZyb20gJy4uL3N0YWNrLWV2ZW50cy9yZXNvdXJjZS1lcnJvcnMnO1xuXG5leHBvcnQgdHlwZSB7IEludmVzdGlnYXRlT3B0aW9ucyB9O1xuXG4vKipcbiAqIEludmVzdGlnYXRlIGEgZmFpbGVkIHJlc291cmNlIHVzaW5nIEFXUyBzZXJ2aWNlIEFQSXMgdG8gZ2F0aGVyIGFkZGl0aW9uYWwgcm9vdCBjYXVzZSBjb250ZXh0LlxuICpcbiAqIFJldHVybnMgYWRkaXRpb25hbCBkaWFnbm9zdGljIGNvbnRleHQgKGUuZy4gbG9nIGxpbmVzKSBvciBhbiBlbXB0eSBhcnJheSBpZlxuICogaW52ZXN0aWdhdGlvbiBpcyBub3QgcG9zc2libGUgb3IgeWllbGRzIG5vIHJlc3VsdHMgZm9yIHRoaXMgcmVzb3VyY2UgdHlwZS5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGludmVzdGlnYXRlUmVzb3VyY2UoXG4gIGVycjogUmVzb3VyY2VFcnJvcixcbiAgc2RrOiBTREssXG4gIGRlYnVnOiAobXNnOiBzdHJpbmcpID0+IFByb21pc2U8dm9pZD4sXG4gIG9wdGlvbnM6IEludmVzdGlnYXRlT3B0aW9ucyA9IHt9LFxuKTogUHJvbWlzZTxBZGRpdGlvbmFsRGlhZ25vc3RpY0NvbnRleHRbXT4ge1xuICBjb25zdCByZXNvdXJjZVR5cGUgPSBlcnIucmVzb3VyY2VUeXBlID8/ICcnO1xuICBpZiAocmVzb3VyY2VUeXBlID09PSAnQVdTOjpFQ1M6OlNlcnZpY2UnKSB7XG4gICAgcmV0dXJuIGludmVzdGlnYXRlRWNzU2VydmljZShlcnIsIHNkaywgZGVidWcsIG9wdGlvbnMpO1xuICB9XG4gIGlmIChyZXNvdXJjZVR5cGUgPT09ICdBV1M6OkNsb3VkRm9ybWF0aW9uOjpDdXN0b21SZXNvdXJjZScgfHwgcmVzb3VyY2VUeXBlLnN0YXJ0c1dpdGgoJ0N1c3RvbTo6JykpIHtcbiAgICByZXR1cm4gaW52ZXN0aWdhdGVDdXN0b21SZXNvdXJjZShlcnIsIHNkaywgZGVidWcpO1xuICB9XG4gIHJldHVybiBbXTtcbn1cbiJdfQ==
|
|
@@ -11,7 +11,21 @@ export interface CloudFormationStackDiagnoserProps {
|
|
|
11
11
|
readonly sourceTracer: ISourceTracer;
|
|
12
12
|
readonly ioHelper: IoHelper;
|
|
13
13
|
readonly topLevelStackHierarchicalId: string;
|
|
14
|
+
/**
|
|
15
|
+
* Optionally: a function to return an SDK that can be used for additional
|
|
16
|
+
* (readonly) exploratory calls.
|
|
17
|
+
*
|
|
18
|
+
* Typically, this should be an SDK that is primed with the "lookup" role, or similar.
|
|
19
|
+
*
|
|
20
|
+
* This is necessary because the "deploy" role will not typically have permissions to
|
|
21
|
+
* do very much.
|
|
22
|
+
*
|
|
23
|
+
* Regardless, if lookups of additional information fail, they are emitted at debug
|
|
24
|
+
* level and their information is simply not added to the output.
|
|
25
|
+
*/
|
|
26
|
+
readonly additionalExplorationSdkProvider?: SdkProvider;
|
|
14
27
|
}
|
|
28
|
+
export type SdkProvider = () => Promise<SDK>;
|
|
15
29
|
/**
|
|
16
30
|
* Diagnose a stack's failed state
|
|
17
31
|
*
|
|
@@ -25,10 +39,27 @@ export interface CloudFormationStackDiagnoserProps {
|
|
|
25
39
|
* This class works at the CloudFormation level, and does not deal with tracing
|
|
26
40
|
* CloudFormation errors to construct code sources yet.
|
|
27
41
|
*/
|
|
42
|
+
/**
|
|
43
|
+
* Options that affect how a diagnosis is performed.
|
|
44
|
+
*/
|
|
45
|
+
export interface DiagnoseOptions {
|
|
46
|
+
/**
|
|
47
|
+
* Whether CloudFormation rollback is enabled for this deployment.
|
|
48
|
+
*
|
|
49
|
+
* When rollback is enabled, failed resources are torn down before we can
|
|
50
|
+
* inspect their runtime state (e.g. ECS tasks), so the investigation degrades
|
|
51
|
+
* to durable sources and may suggest re-running with `--no-rollback`.
|
|
52
|
+
*
|
|
53
|
+
* @default true
|
|
54
|
+
*/
|
|
55
|
+
readonly rollbackEnabled?: boolean;
|
|
56
|
+
}
|
|
28
57
|
export declare class CloudFormationStackDiagnoser {
|
|
29
58
|
private readonly props;
|
|
30
59
|
private readonly cfn;
|
|
31
60
|
private parentStackLogicalIds;
|
|
61
|
+
private _additionalExplorationSdkPromise?;
|
|
62
|
+
private rollbackEnabled;
|
|
32
63
|
constructor(props: CloudFormationStackDiagnoserProps);
|
|
33
64
|
/**
|
|
34
65
|
* Diagnose a stack's root cause given no pre-existing state
|
|
@@ -41,7 +72,7 @@ export declare class CloudFormationStackDiagnoser {
|
|
|
41
72
|
/**
|
|
42
73
|
* Diagnose potential problems with the change set
|
|
43
74
|
*/
|
|
44
|
-
diagnoseFromErrorCollection(errors: ResourceErrors, stack: Stack): Promise<StackDiagnosis>;
|
|
75
|
+
diagnoseFromErrorCollection(errors: ResourceErrors, stack: Stack, allowFallback?: boolean, options?: DiagnoseOptions): Promise<StackDiagnosis>;
|
|
45
76
|
/**
|
|
46
77
|
* Diagnose a deployment failure via stack events
|
|
47
78
|
*
|
|
@@ -65,8 +96,9 @@ export declare class CloudFormationStackDiagnoser {
|
|
|
65
96
|
* error.
|
|
66
97
|
*/
|
|
67
98
|
private _reportChangeSetFailureFromEvents;
|
|
68
|
-
private
|
|
69
|
-
private
|
|
99
|
+
private enhanceErrors;
|
|
100
|
+
private enhanceError;
|
|
101
|
+
private investigateResourceBestEffort;
|
|
70
102
|
/**
|
|
71
103
|
* Build a generic stack error from the given change set information
|
|
72
104
|
*
|
|
@@ -94,6 +126,10 @@ export declare class CloudFormationStackDiagnoser {
|
|
|
94
126
|
* ```
|
|
95
127
|
*/
|
|
96
128
|
private _tryDetectFailedAutoImport;
|
|
129
|
+
/**
|
|
130
|
+
* Return the additional exploration SDK, if available.
|
|
131
|
+
*/
|
|
132
|
+
private additionalExplorationSdk;
|
|
97
133
|
}
|
|
98
134
|
/**
|
|
99
135
|
* Return true if the given change set has no changes
|