@aws-cdk/toolkit-lib 1.30.0 → 1.32.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.
Files changed (111) hide show
  1. package/build-info.json +2 -2
  2. package/lib/actions/bootstrap/index.d.ts +5 -0
  3. package/lib/actions/bootstrap/index.js +35 -2
  4. package/lib/actions/deploy/index.d.ts +6 -0
  5. package/lib/actions/deploy/index.js +1 -1
  6. package/lib/actions/destroy/index.d.ts +6 -0
  7. package/lib/actions/destroy/index.js +1 -1
  8. package/lib/actions/diff/private/helpers.js +36 -3
  9. package/lib/api/aws-auth/account-cache.js +36 -3
  10. package/lib/api/aws-auth/sdk-provider.js +36 -3
  11. package/lib/api/aws-auth/sdk.d.ts +2 -1
  12. package/lib/api/aws-auth/sdk.js +2 -1
  13. package/lib/api/aws-auth/user-agent.js +35 -2
  14. package/lib/api/aws-auth/util.js +35 -2
  15. package/lib/api/bootstrap/bootstrap-environment.js +35 -2
  16. package/lib/api/bootstrap/bootstrap-props.d.ts +6 -0
  17. package/lib/api/bootstrap/bootstrap-props.js +1 -1
  18. package/lib/api/bootstrap/deploy-bootstrap.js +39 -4
  19. package/lib/api/cloud-assembly/context-store.js +36 -3
  20. package/lib/api/cloud-assembly/environment.js +37 -4
  21. package/lib/api/cloud-assembly/private/context-aware-source.js +35 -2
  22. package/lib/api/cloud-assembly/private/exec.js +35 -2
  23. package/lib/api/cloud-assembly/private/prepare-source.js +39 -6
  24. package/lib/api/cloud-assembly/source-builder.js +37 -4
  25. package/lib/api/cloud-assembly/stack-assembly.js +8 -4
  26. package/lib/api/cloudformation/logical-id-map.js +35 -2
  27. package/lib/api/cloudformation/nested-stack-helpers.js +36 -3
  28. package/lib/api/cloudformation/template-body-parameter.js +42 -6
  29. package/lib/api/deployments/asset-manifest-builder.js +35 -2
  30. package/lib/api/deployments/assets.js +42 -6
  31. package/lib/api/deployments/cfn-api.d.ts +4 -2
  32. package/lib/api/deployments/cfn-api.js +47 -6
  33. package/lib/api/deployments/deploy-stack.d.ts +13 -0
  34. package/lib/api/deployments/deploy-stack.js +29 -9
  35. package/lib/api/deployments/deployment-result.d.ts +7 -1
  36. package/lib/api/deployments/deployment-result.js +1 -1
  37. package/lib/api/deployments/deployments.d.ts +5 -0
  38. package/lib/api/deployments/deployments.js +42 -4
  39. package/lib/api/diagnosing/format-utils.d.ts +29 -0
  40. package/lib/api/diagnosing/format-utils.js +141 -1
  41. package/lib/api/diagnosing/investigate-custom-resource.d.ts +17 -0
  42. package/lib/api/diagnosing/investigate-custom-resource.js +247 -0
  43. package/lib/api/diagnosing/investigate-ecs-service.d.ts +20 -0
  44. package/lib/api/diagnosing/investigate-ecs-service.js +242 -0
  45. package/lib/api/diagnosing/resource-identifiers.d.ts +39 -0
  46. package/lib/api/diagnosing/resource-identifiers.js +90 -0
  47. package/lib/api/diagnosing/resource-investigation.d.ts +2 -30
  48. package/lib/api/diagnosing/resource-investigation.js +9 -289
  49. package/lib/api/diff/diff-formatter.js +11 -8
  50. package/lib/api/drift/drift-formatter.js +20 -17
  51. package/lib/api/garbage-collection/garbage-collector.js +7 -4
  52. package/lib/api/garbage-collection/progress-printer.js +7 -4
  53. package/lib/api/hotswap/hotswap-deployments.js +47 -10
  54. package/lib/api/hotswap/hotswap-template-cache.js +36 -3
  55. package/lib/api/io/private/io-default-messages.js +35 -2
  56. package/lib/api/io/private/message-maker.d.ts +4 -0
  57. package/lib/api/io/private/message-maker.js +3 -1
  58. package/lib/api/io/private/messages.d.ts +5 -0
  59. package/lib/api/io/private/messages.js +55 -2
  60. package/lib/api/io/private/span.js +35 -2
  61. package/lib/api/logs-monitor/logs-monitor.js +40 -4
  62. package/lib/api/network-detector/network-detector.js +37 -4
  63. package/lib/api/notices/cached-data-source.js +35 -2
  64. package/lib/api/notices/filter.js +35 -2
  65. package/lib/api/notices/notices.js +35 -2
  66. package/lib/api/notices/web-data-source.js +35 -2
  67. package/lib/api/refactoring/digest.js +35 -2
  68. package/lib/api/refactoring/stack-definitions.js +40 -4
  69. package/lib/api/resource-import/importer.js +60 -17
  70. package/lib/api/resource-import/migrator.js +42 -6
  71. package/lib/api/rwlock.js +35 -2
  72. package/lib/api/settings.js +38 -5
  73. package/lib/api/source-tracing/private/stack-source-tracing.js +38 -5
  74. package/lib/api/stack-events/resource-errors.d.ts +12 -0
  75. package/lib/api/stack-events/resource-errors.js +2 -1
  76. package/lib/api/stack-events/stack-activity-monitor.d.ts +5 -0
  77. package/lib/api/stack-events/stack-activity-monitor.js +42 -2
  78. package/lib/api/stack-events/stack-event-poller.d.ts +8 -1
  79. package/lib/api/stack-events/stack-event-poller.js +19 -1
  80. package/lib/api/stack-events/stack-progress-monitor.js +35 -2
  81. package/lib/api/toolkit-info.js +7 -4
  82. package/lib/api/tree.js +36 -3
  83. package/lib/api/validate/validate-formatting.js +53 -17
  84. package/lib/api/work-graph/build-destroy-work-graph.js +35 -2
  85. package/lib/api/work-graph/work-graph-builder.js +35 -2
  86. package/lib/context-providers/index.js +35 -2
  87. package/lib/private/activity-printer/current.d.ts +19 -0
  88. package/lib/private/activity-printer/current.js +109 -17
  89. package/lib/private/activity-printer/history.js +50 -14
  90. package/lib/private/tools.js +38 -1
  91. package/lib/toolkit/non-interactive-io-host.js +11 -8
  92. package/lib/toolkit/private/collect-annotation-report.js +35 -2
  93. package/lib/toolkit/private/validation-report.js +36 -3
  94. package/lib/toolkit/toolkit-error.d.ts +20 -0
  95. package/lib/toolkit/toolkit-error.js +30 -2
  96. package/lib/toolkit/toolkit.d.ts +8 -0
  97. package/lib/toolkit/toolkit.js +107 -41
  98. package/lib/toolkit/types.d.ts +22 -0
  99. package/lib/toolkit/types.js +1 -1
  100. package/lib/util/cfn-express.d.ts +24 -0
  101. package/lib/util/cfn-express.js +55 -0
  102. package/lib/util/content-hash.js +35 -2
  103. package/lib/util/directories.js +38 -5
  104. package/lib/util/guess-language.js +36 -3
  105. package/lib/util/index.d.ts +1 -0
  106. package/lib/util/index.js +2 -1
  107. package/lib/util/package-info.js +35 -2
  108. package/lib/util/serialize.js +36 -3
  109. package/lib/util/version-range.js +35 -2
  110. package/lib/util/yaml-cfn.js +36 -3
  111. package/package.json +2 -2
@@ -0,0 +1,247 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.investigateCustomResource = investigateCustomResource;
4
+ const format_utils_1 = require("./format-utils");
5
+ const resource_identifiers_1 = require("./resource-identifiers");
6
+ const util_1 = require("../../util");
7
+ /** Fallback look-back when no failure timestamp is available. */
8
+ const FALLBACK_LOG_WINDOW_MS = 30 * 60 * 1000;
9
+ /**
10
+ * How far before/after the failure event to search CloudWatch Logs when we have a timestamp.
11
+ *
12
+ * The pre-window absorbs minor clock skew; the post-window covers output the function
13
+ * emits while it runs after the CloudFormation event was recorded.
14
+ */
15
+ const LOG_WINDOW_BEFORE_MS = 2 * 60 * 1000;
16
+ const LOG_WINDOW_AFTER_MS = 15 * 60 * 1000;
17
+ /**
18
+ * Investigate a failed custom resource by surfacing its backing Lambda's CloudWatch logs.
19
+ *
20
+ * The CloudFormation event does not name the backing function — only the resource's
21
+ * `ServiceToken` (in the template) does. We resolve that to a function name, derive the
22
+ * log group (the `/aws/lambda/<fn>` convention, confirmed via the function's LoggingConfig
23
+ * only if the convention turns up empty), and fetch the relevant log lines.
24
+ *
25
+ * When the handler uses the cfn-response library, the failing log stream name is embedded
26
+ * in the status reason ("See the details in CloudWatch Log Stream: <name>"), so we can
27
+ * target that exact invocation.
28
+ */
29
+ async function investigateCustomResource(err, sdk, debug) {
30
+ if (!err.logicalId) {
31
+ await debug('Custom resource investigation: no logical ID available');
32
+ return [];
33
+ }
34
+ const stackName = err.stackArn;
35
+ if (!stackName) {
36
+ await debug('Custom resource investigation: no stack ARN available');
37
+ return [];
38
+ }
39
+ const cfn = sdk.cloudFormation();
40
+ const lambda = sdk.lambda();
41
+ const cwl = sdk.cloudWatchLogs();
42
+ const region = sdk.currentRegion;
43
+ // Fetch the template once: it carries both the ServiceToken and (for functions defined in
44
+ // this stack) the backing function's LoggingConfig. The template survives rollback even
45
+ // when the function itself is deleted, so it's the most reliable source for the log group.
46
+ const template = await getStackTemplate(cfn, stackName, debug);
47
+ if (!template) {
48
+ return [];
49
+ }
50
+ const serviceToken = template.Resources?.[err.logicalId]?.Properties?.ServiceToken;
51
+ if (serviceToken === undefined) {
52
+ await debug(`Custom resource investigation: no ServiceToken on resource "${err.logicalId}"`);
53
+ return [];
54
+ }
55
+ const referencedLogicalId = (0, resource_identifiers_1.serviceTokenReferencedLogicalId)(serviceToken);
56
+ const functionName = await resolveServiceTokenToFunctionName(cfn, stackName, serviceToken, referencedLogicalId, debug);
57
+ if (!functionName) {
58
+ await debug('Custom resource investigation: could not resolve ServiceToken to a Lambda function');
59
+ return [];
60
+ }
61
+ // Prefer the function's configured log group as derived from the template (rollback-proof).
62
+ // Only resolvable when the function is defined in this stack (ServiceToken is a Ref/GetAtt).
63
+ const templateLogGroup = referencedLogicalId
64
+ ? await resolveConfiguredLogGroup(cfn, stackName, template, referencedLogicalId, debug)
65
+ : undefined;
66
+ // The cfn-response library writes the failing log stream name into the status reason
67
+ // (and uses it as the default physical ID). Targeting it gives the exact invocation.
68
+ const streamName = (0, resource_identifiers_1.extractLogStreamName)(err.message) ?? (0, resource_identifiers_1.logStreamNameFromPhysicalId)(err.physicalId);
69
+ return fetchCustomResourceLogs(cwl, lambda, functionName, templateLogGroup, streamName, err.timestamp, region, debug);
70
+ }
71
+ /**
72
+ * Fetch and parse the stack's (original) template. Returns `undefined` if it can't be read.
73
+ */
74
+ async function getStackTemplate(cfn, stackName, debug) {
75
+ try {
76
+ const resp = await cfn.getTemplate({ StackName: stackName, TemplateStage: 'Original' });
77
+ if (!resp.TemplateBody) {
78
+ await debug('Custom resource investigation: empty template body');
79
+ return undefined;
80
+ }
81
+ return (0, util_1.deserializeStructure)(resp.TemplateBody);
82
+ }
83
+ catch (e) {
84
+ await debug(`Custom resource investigation: failed to read template: ${e.message}`);
85
+ return undefined;
86
+ }
87
+ }
88
+ /**
89
+ * Resolve the backing Lambda's configured log group from the template.
90
+ *
91
+ * The template survives rollback (when the live function may not), so it is the preferred
92
+ * source. Handles the function's `LoggingConfig.LogGroup` as:
93
+ * - a literal string (returned directly);
94
+ * - a `Ref` to an `AWS::Logs::LogGroup` with a literal `LogGroupName` (returned directly);
95
+ * - a `Ref` to an `AWS::Logs::LogGroup` whose name CloudFormation generates (the common CDK
96
+ * case) — resolved to its physical name via `describeStackResources`, which still returns
97
+ * RETAINed/orphaned resources after a rollback.
98
+ *
99
+ * Returns `undefined` when there is no configured log group or it can't be resolved
100
+ * (caller then falls back to the live function configuration).
101
+ */
102
+ async function resolveConfiguredLogGroup(cfn, stackName, template, functionLogicalId, debug) {
103
+ const logGroup = template.Resources?.[functionLogicalId]?.Properties?.LoggingConfig?.LogGroup;
104
+ if (typeof logGroup === 'string') {
105
+ return logGroup;
106
+ }
107
+ if (logGroup && typeof logGroup === 'object' && typeof logGroup.Ref === 'string') {
108
+ const referenced = template.Resources?.[logGroup.Ref];
109
+ const name = referenced?.Properties?.LogGroupName;
110
+ if (typeof name === 'string') {
111
+ return name;
112
+ }
113
+ // No explicit name (CloudFormation generates it) — resolve the log-group resource's
114
+ // physical name, which is the log group name.
115
+ return (await resolveStackResource(cfn, stackName, logGroup.Ref, debug))?.physicalId;
116
+ }
117
+ return undefined;
118
+ }
119
+ /**
120
+ * Resolve a resource's physical ID and type by logical ID. Returns `undefined` on failure.
121
+ */
122
+ async function resolveStackResource(cfn, stackName, logicalId, debug) {
123
+ try {
124
+ const resp = await cfn.describeStackResources({ StackName: stackName, LogicalResourceId: logicalId });
125
+ const resource = resp.StackResources?.[0];
126
+ return resource ? { physicalId: resource.PhysicalResourceId, resourceType: resource.ResourceType } : undefined;
127
+ }
128
+ catch (e) {
129
+ await debug(`Custom resource investigation: failed to resolve resource "${logicalId}": ${e.message}`);
130
+ return undefined;
131
+ }
132
+ }
133
+ /**
134
+ * Resolve a `ServiceToken` value (a literal ARN, an `Fn::GetAtt`, or a `Ref`) to a Lambda
135
+ * function name. Intrinsics are resolved via `describeStackResources`.
136
+ */
137
+ async function resolveServiceTokenToFunctionName(cfn, stackName, serviceToken, referencedLogicalId, debug) {
138
+ if (referencedLogicalId) {
139
+ const resource = await resolveStackResource(cfn, stackName, referencedLogicalId, debug);
140
+ // Only treat the reference as a Lambda function. Without this, a ServiceToken pointing at
141
+ // a non-Lambda resource (e.g. an SNS topic) whose physical ID is a bare name would be
142
+ // mistaken for a function name, producing a misleading /aws/lambda/<name> log lookup.
143
+ if (resource?.resourceType && resource.resourceType !== 'AWS::Lambda::Function') {
144
+ await debug(`Custom resource investigation: ServiceToken references a ${resource.resourceType}, not a Lambda function`);
145
+ return undefined;
146
+ }
147
+ return resource?.physicalId ? (0, resource_identifiers_1.functionNameFromArnOrName)(resource.physicalId) : undefined;
148
+ }
149
+ if (typeof serviceToken === 'string') {
150
+ return (0, resource_identifiers_1.functionNameFromArnOrName)(serviceToken);
151
+ }
152
+ await debug('Custom resource investigation: unsupported ServiceToken shape');
153
+ return undefined;
154
+ }
155
+ async function fetchCustomResourceLogs(cwl, lambda, functionName, templateLogGroup, streamName, timestamp, region, debug) {
156
+ const failureTime = timestamp?.valueOf();
157
+ const startTime = failureTime !== undefined ? failureTime - LOG_WINDOW_BEFORE_MS : Date.now() - FALLBACK_LOG_WINDOW_MS;
158
+ const endTime = failureTime !== undefined ? failureTime + LOG_WINDOW_AFTER_MS : undefined;
159
+ // Convention first; only pay for the configured group if the convention group doesn't yield usable lines (empty group or fetch error).
160
+ const conventionGroup = `/aws/lambda/${functionName}`;
161
+ let result = await fetchLogLines(cwl, conventionGroup, streamName, startTime, endTime, debug);
162
+ // The group we point the user at. Once we learn the function's configured log group, prefer
163
+ // it for the link even if it too is empty — it's where the function actually logs, whereas
164
+ // the convention group may not exist for advanced-logging functions.
165
+ let logGroup = conventionGroup;
166
+ if (result.kind !== 'lines') {
167
+ // Prefer the template-derived group (rollback-proof); fall back to the live function
168
+ // configuration only when the template couldn't tell us (e.g. unresolvable intrinsic, or
169
+ // the function is defined outside this stack).
170
+ const configuredGroup = templateLogGroup ?? await configuredLogGroup(lambda, functionName, debug);
171
+ if (configuredGroup && configuredGroup !== conventionGroup) {
172
+ logGroup = configuredGroup;
173
+ const configuredResult = await fetchLogLines(cwl, configuredGroup, streamName, startTime, endTime, debug);
174
+ // Keep the configured-group result unless it errored while the convention attempt was a
175
+ // clean empty (an "empty" answer is more informative to surface than a fetch error).
176
+ if (configuredResult.kind === 'lines' || result.kind !== 'empty') {
177
+ result = configuredResult;
178
+ }
179
+ }
180
+ }
181
+ // Lead with the log group so the user can tell which function these logs belong to
182
+ // (the formatter renders messages but not `source`, and the link is URL-encoded).
183
+ const header = `Logs from ${logGroup}:`;
184
+ const body = result.kind === 'lines'
185
+ ? result.lines
186
+ : result.kind === 'error'
187
+ ? ['Could not fetch logs (the log group may not exist, or the credentials lack logs:FilterLogEvents). See the console link below.']
188
+ : ['No log events found around the time of failure. The function may not have produced output, or logging may not be configured.'];
189
+ return [{
190
+ source: 'Custom Resource Lambda Logs',
191
+ messages: [header, ...body],
192
+ link: (0, format_utils_1.cloudWatchLogsConsoleUrl)(region, logGroup),
193
+ linkLabel: 'Logs',
194
+ }];
195
+ }
196
+ /**
197
+ * Fetch and trim recent log lines from a group.
198
+ *
199
+ * Tries the targeted stream first (most relevant), but the cfn-response stream name can be
200
+ * stale on update/rollback failures (it's pinned to the original create invocation). If the
201
+ * targeted query finds nothing, falls back to a group-wide scan over the time window so a
202
+ * stale stream can't hide the actual failing invocation's logs.
203
+ */
204
+ async function fetchLogLines(cwl, logGroup, streamName, startTime, endTime, debug) {
205
+ if (streamName) {
206
+ const targeted = await filterLogLines(cwl, logGroup, streamName, startTime, endTime, debug);
207
+ if (targeted.kind === 'lines') {
208
+ return targeted;
209
+ }
210
+ }
211
+ return filterLogLines(cwl, logGroup, undefined, startTime, endTime, debug);
212
+ }
213
+ async function filterLogLines(cwl, logGroup, streamName, startTime, endTime, debug) {
214
+ try {
215
+ const resp = await cwl.filterLogEvents({
216
+ logGroupName: logGroup,
217
+ startTime,
218
+ ...(endTime !== undefined ? { endTime } : {}),
219
+ limit: 1000,
220
+ ...(streamName ? { logStreamNames: [streamName] } : {}),
221
+ });
222
+ const events = resp.events ?? [];
223
+ if (events.length === 0) {
224
+ await debug(`Custom resource investigation: no log events in ${logGroup}${streamName ? ` (stream: ${streamName})` : ''}`);
225
+ return { kind: 'empty' };
226
+ }
227
+ // Lambda log events have a known structure (text- or JSON-format), unlike raw ECS
228
+ // container output, so we normalize them into readable lines before trimming.
229
+ return { kind: 'lines', lines: (0, format_utils_1.trimToRecentLines)((0, format_utils_1.parseLambdaLogEvents)(events)) };
230
+ }
231
+ catch (e) {
232
+ await debug(`Custom resource investigation: failed to fetch logs from ${logGroup}: ${e.message}`);
233
+ return { kind: 'error' };
234
+ }
235
+ }
236
+ /** Read the function's configured (advanced-logging) log group, if any. */
237
+ async function configuredLogGroup(lambda, functionName, debug) {
238
+ try {
239
+ const resp = await lambda.getFunctionConfiguration({ FunctionName: functionName });
240
+ return resp.LoggingConfig?.LogGroup;
241
+ }
242
+ catch (e) {
243
+ await debug(`Custom resource investigation: failed to read function configuration: ${e.message}`);
244
+ return undefined;
245
+ }
246
+ }
247
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW52ZXN0aWdhdGUtY3VzdG9tLXJlc291cmNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiaW52ZXN0aWdhdGUtY3VzdG9tLXJlc291cmNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBb0NBLDhEQW9EQztBQXhGRCxpREFBbUc7QUFDbkcsaUVBS2dDO0FBRWhDLHFDQUFrRDtBQUlsRCxpRUFBaUU7QUFDakUsTUFBTSxzQkFBc0IsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQztBQUU5Qzs7Ozs7R0FLRztBQUNILE1BQU0sb0JBQW9CLEdBQUcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUM7QUFDM0MsTUFBTSxtQkFBbUIsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQztBQUUzQzs7Ozs7Ozs7Ozs7R0FXRztBQUNJLEtBQUssVUFBVSx5QkFBeUIsQ0FDN0MsR0FBa0IsRUFDbEIsR0FBUSxFQUNSLEtBQXFDO0lBRXJDLElBQUksQ0FBQyxHQUFHLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDbkIsTUFBTSxLQUFLLENBQUMsd0RBQXdELENBQUMsQ0FBQztRQUN0RSxPQUFPLEVBQUUsQ0FBQztJQUNaLENBQUM7SUFDRCxNQUFNLFNBQVMsR0FBRyxHQUFHLENBQUMsUUFBUSxDQUFDO0lBQy9CLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztRQUNmLE1BQU0sS0FBSyxDQUFDLHVEQUF1RCxDQUFDLENBQUM7UUFDckUsT0FBTyxFQUFFLENBQUM7SUFDWixDQUFDO0lBRUQsTUFBTSxHQUFHLEdBQUcsR0FBRyxDQUFDLGNBQWMsRUFBRSxDQUFDO0lBQ2pDLE1BQU0sTUFBTSxHQUFHLEdBQUcsQ0FBQyxNQUFNLEVBQUUsQ0FBQztJQUM1QixNQUFNLEdBQUcsR0FBRyxHQUFHLENBQUMsY0FBYyxFQUFFLENBQUM7SUFDakMsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLGFBQWEsQ0FBQztJQUVqQywwRkFBMEY7SUFDMUYs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QUFPLEVBQUUsQ0FBQyxDQUFDO1FBQ2xHLE9BQU8sRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLENBQUM7SUFDM0IsQ0FBQztBQUNILENBQUM7QUFFRCwyRUFBMkU7QUFDM0UsS0FBSyxVQUFVLGtCQUFrQixDQUMvQixNQUFxQixFQUNyQixZQUFvQixFQUNwQixLQUFxQztJQUVyQyxJQUFJLENBQUM7UUFDSCxNQUFNLElBQUksR0FBRyxNQUFNLE1BQU0sQ0FBQyx3QkFBd0IsQ0FBQyxFQUFFLFlBQVksRUFBRSxZQUFZLEVBQUUsQ0FBQyxDQUFDO1FBQ25GLE9BQU8sSUFBSSxDQUFDLGFBQWEsRUFBRSxRQUFRLENBQUM7SUFDdEMsQ0FBQztJQUFDLE9BQU8sQ0FBTSxFQUFFLENBQUM7UUFDaEIsTUFBTSxLQUFLLENBQUMseUVBQXlFLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1FBQ2xHLE9BQU8sU0FBUyxDQUFDO0lBQ25CLENBQUM7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgdHJpbVRvUmVjZW50TGluZXMsIHBhcnNlTGFtYmRhTG9nRXZlbnRzLCBjbG91ZFdhdGNoTG9nc0NvbnNvbGVVcmwgfSBmcm9tICcuL2Zvcm1hdC11dGlscyc7XG5pbXBvcnQge1xuICBzZXJ2aWNlVG9rZW5SZWZlcmVuY2VkTG9naWNhbElkLFxuICBmdW5jdGlvbk5hbWVGcm9tQXJuT3JOYW1lLFxuICBleHRyYWN0TG9nU3RyZWFtTmFtZSxcbiAgbG9nU3RyZWFtTmFtZUZyb21QaHlzaWNhbElkLFxufSBmcm9tICcuL3Jlc291cmNlLWlkZW50aWZpZXJzJztcbmltcG9ydCB0eXBlIHsgQWRkaXRpb25hbERpYWdub3N0aWNDb250ZXh0IH0gZnJvbSAnLi4vLi4vYWN0aW9ucy9kaWFnbm9zZSc7XG5pbXBvcnQgeyBkZXNlcmlhbGl6ZVN0cnVjdHVyZSB9IGZyb20gJy4uLy4uL3V0aWwnO1xuaW1wb3J0IHR5cGUgeyBJQ2xvdWRGb3JtYXRpb25DbGllbnQsIElDbG91ZFdhdGNoTG9nc0NsaWVudCwgSUxhbWJkYUNsaWVudCwgU0RLIH0gZnJvbSAnLi4vYXdzLWF1dGgvc2RrJztcbmltcG9ydCB0eXBlIHsgUmVzb3VyY2VFcnJvciB9IGZyb20gJy4uL3N0YWNrLWV2ZW50cy9yZXNvdXJjZS1lcnJvcnMnO1xuXG4vKiogRmFsbGJhY2sgbG9vay1iYWNrIHdoZW4gbm8gZmFpbHVyZSB0aW1lc3RhbXAgaXMgYXZhaWxhYmxlLiAqL1xuY29uc3QgRkFMTEJBQ0tfTE9HX1dJTkRPV19NUyA9IDMwICogNjAgKiAxMDAwO1xuXG4vKipcbiAqIEhvdyBmYXIgYmVmb3JlL2FmdGVyIHRoZSBmYWlsdXJlIGV2ZW50IHRvIHNlYXJjaCBDbG91ZFdhdGNoIExvZ3Mgd2hlbiB3ZSBoYXZlIGEgdGltZXN0YW1wLlxuICpcbiAqIFRoZSBwcmUtd2luZG93IGFic29yYnMgbWlub3IgY2xvY2sgc2tldzsgdGhlIHBvc3Qtd2luZG93IGNvdmVycyBvdXRwdXQgdGhlIGZ1bmN0aW9uXG4gKiBlbWl0cyB3aGlsZSBpdCBydW5zIGFmdGVyIHRoZSBDbG91ZEZvcm1hdGlvbiBldmVudCB3YXMgcmVjb3JkZWQuXG4gKi9cbmNvbnN0IExPR19XSU5ET1dfQkVGT1JFX01TID0gMiAqIDYwICogMTAwMDtcbmNvbnN0IExPR19XSU5ET1dfQUZURVJfTVMgPSAxNSAqIDYwICogMTAwMDtcblxuLyoqXG4gKiBJbnZlc3RpZ2F0ZSBhIGZhaWxlZCBjdXN0b20gcmVzb3VyY2UgYnkgc3VyZmFjaW5nIGl0cyBiYWNraW5nIExhbWJkYSdzIENsb3VkV2F0Y2ggbG9ncy5cbiAqXG4gKiBUaGUgQ2xvdWRGb3JtYXRpb24gZXZlbnQgZG9lcyBub3QgbmFtZSB0aGUgYmFja2luZyBmdW5jdGlvbiDigJQgb25seSB0aGUgcmVzb3VyY2Unc1xuICogYFNlcnZpY2VUb2tlbmAgKGluIHRoZSB0ZW1wbGF0ZSkgZG9lcy4gV2UgcmVzb2x2ZSB0aGF0IHRvIGEgZnVuY3Rpb24gbmFtZSwgZGVyaXZlIHRoZVxuICogbG9nIGdyb3VwICh0aGUgYC9hd3MvbGFtYmRhLzxmbj5gIGNvbnZlbnRpb24sIGNvbmZpcm1lZCB2aWEgdGhlIGZ1bmN0aW9uJ3MgTG9nZ2luZ0NvbmZpZ1xuICogb25seSBpZiB0aGUgY29udmVudGlvbiB0dXJucyB1cCBlbXB0eSksIGFuZCBmZXRjaCB0aGUgcmVsZXZhbnQgbG9nIGxpbmVzLlxuICpcbiAqIFdoZW4gdGhlIGhhbmRsZXIgdXNlcyB0aGUgY2ZuLXJlc3BvbnNlIGxpYnJhcnksIHRoZSBmYWlsaW5nIGxvZyBzdHJlYW0gbmFtZSBpcyBlbWJlZGRlZFxuICogaW4gdGhlIHN0YXR1cyByZWFzb24gKFwiU2VlIHRoZSBkZXRhaWxzIGluIENsb3VkV2F0Y2ggTG9nIFN0cmVhbTogPG5hbWU+XCIpLCBzbyB3ZSBjYW5cbiAqIHRhcmdldCB0aGF0IGV4YWN0IGludm9jYXRpb24uXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBpbnZlc3RpZ2F0ZUN1c3RvbVJlc291cmNlKFxuICBlcnI6IFJlc291cmNlRXJyb3IsXG4gIHNkazogU0RLLFxuICBkZWJ1ZzogKG1zZzogc3RyaW5nKSA9PiBQcm9taXNlPHZvaWQ+LFxuKTogUHJvbWlzZTxBZGRpdGlvbmFsRGlhZ25vc3RpY0NvbnRleHRbXT4ge1xuICBpZiAoIWVyci5sb2dpY2FsSWQpIHtcbiAgICBhd2FpdCBkZWJ1ZygnQ3VzdG9tIHJlc291cmNlIGludmVzdGlnYXRpb246IG5vIGxvZ2ljYWwgSUQgYXZhaWxhYmxlJyk7XG4gICAgcmV0dXJuIFtdO1xuICB9XG4gIGNvbnN0IHN0YWNrTmFtZSA9IGVyci5zdGFja0FybjtcbiAgaWYgKCFzdGFja05hbWUpIHtcbiAgICBhd2FpdCBkZWJ1ZygnQ3VzdG9tIHJlc291cmNlIGludmVzdGlnYXRpb246IG5vIHN0YWNrIEFSTiBhdmFpbGFibGUnKTtcbiAgICByZXR1cm4gW107XG4gIH1cblxuICBjb25zdCBjZm4gPSBzZGsuY2xvdWRGb3JtYXRpb24oKTtcbiAgY29uc3QgbGFtYmRhID0gc2RrLmxhbWJkYSgpO1xuICBjb25zdCBjd2wgPSBzZGsuY2xvdWRXYXRjaExvZ3MoKTtcbiAgY29uc3QgcmVnaW9uID0gc2RrLmN1cnJlbnRSZWdpb247XG5cbiAgLy8gRmV0Y2ggdGhlIHRlbXBsYXRlIG9uY2U6IGl0IGNhcnJpZXMgYm90aCB0aGUgU2VydmljZVRva2VuIGFuZCAoZm9yIGZ1bmN0aW9ucyBkZWZpbmVkIGluXG4gIC8vIHRoaXMgc3RhY2spIHRoZSBiYWNraW5nIGZ1bmN0aW9uJ3MgTG9nZ2luZ0NvbmZpZy4gVGhlIHRlbXBsYXRlIHN1cnZpdmVzIHJvbGxiYWNrIGV2ZW5cbiAgLy8gd2hlbiB0aGUgZnVuY3Rpb24gaXRzZWxmIGlzIGRlbGV0ZWQsIHNvIGl0J3MgdGhlIG1vc3QgcmVsaWFibGUgc291cmNlIGZvciB0aGUgbG9nIGdyb3VwLlxuICBjb25zdCB0ZW1wbGF0ZSA9IGF3YWl0IGdldFN0YWNrVGVtcGxhdGUoY2ZuLCBzdGFja05hbWUsIGRlYnVnKTtcbiAgaWYgKCF0ZW1wbGF0ZSkge1xuICAgIHJldHVybiBbXTtcbiAgfVxuXG4gIGNvbnN0IHNlcnZpY2VUb2tlbiA9IHRlbXBsYXRlLlJlc291cmNlcz8uW2Vyci5sb2dpY2FsSWRdPy5Qcm9wZXJ0aWVzPy5TZXJ2aWNlVG9rZW47XG4gIGlmIChzZXJ2aWNlVG9rZW4gPT09IHVuZGVmaW5lZCkge1xuICAgIGF3YWl0IGRlYnVnKGBDdXN0b20gcmVzb3VyY2UgaW52ZXN0aWdhdGlvbjogbm8gU2VydmljZVRva2VuIG9uIHJlc291cmNlIFwiJHtlcnIubG9naWNhbElkfVwiYCk7XG4gICAgcmV0dXJuIFtdO1xuICB9XG5cbiAgY29uc3QgcmVmZXJlbmNlZExvZ2ljYWxJZCA9IHNlcnZpY2VUb2tlblJlZmVyZW5jZWRMb2dpY2FsSWQoc2VydmljZVRva2VuKTtcbiAgY29uc3QgZnVuY3Rpb25OYW1lID0gYXdhaXQgcmVzb2x2ZVNlcnZpY2VUb2tlblRvRnVuY3Rpb25OYW1lKGNmbiwgc3RhY2tOYW1lLCBzZXJ2aWNlVG9rZW4sIHJlZmVyZW5jZWRMb2dpY2FsSWQsIGRlYnVnKTtcbiAgaWYgKCFmdW5jdGlvbk5hbWUpIHtcbiAgICBhd2FpdCBkZWJ1ZygnQ3VzdG9tIHJlc291cmNlIGludmVzdGlnYXRpb246IGNvdWxkIG5vdCByZXNvbHZlIFNlcnZpY2VUb2tlbiB0byBhIExhbWJkYSBmdW5jdGlvbicpO1xuICAgIHJldHVybiBbXTtcbiAgfVxuXG4gIC8vIFByZWZlciB0aGUgZnVuY3Rpb24ncyBjb25maWd1cmVkIGxvZyBncm91cCBhcyBkZXJpdmVkIGZyb20gdGhlIHRlbXBsYXRlIChyb2xsYmFjay1wcm9vZikuXG4gIC8vIE9ubHkgcmVzb2x2YWJsZSB3aGVuIHRoZSBmdW5jdGlvbiBpcyBkZWZpbmVkIGluIHRoaXMgc3RhY2sgKFNlcnZpY2VUb2tlbiBpcyBhIFJlZi9HZXRBdHQpLlxuICBjb25zdCB0ZW1wbGF0ZUxvZ0dyb3VwID0gcmVmZXJlbmNlZExvZ2ljYWxJZFxuICAgID8gYXdhaXQgcmVzb2x2ZUNvbmZpZ3VyZWRMb2dHcm91cChjZm4sIHN0YWNrTmFtZSwgdGVtcGxhdGUsIHJlZmVyZW5jZWRMb2dpY2FsSWQsIGRlYnVnKVxuICAgIDogdW5kZWZpbmVkO1xuXG4gIC8vIFRoZSBjZm4tcmVzcG9uc2UgbGlicmFyeSB3cml0ZXMgdGhlIGZhaWxpbmcgbG9nIHN0cmVhbSBuYW1lIGludG8gdGhlIHN0YXR1cyByZWFzb25cbiAgLy8gKGFuZCB1c2VzIGl0IGFzIHRoZSBkZWZhdWx0IHBoeXNpY2FsIElEKS4gVGFyZ2V0aW5nIGl0IGdpdmVzIHRoZSBleGFjdCBpbnZvY2F0aW9uLlxuICBjb25zdCBzdHJlYW1OYW1lID0gZXh0cmFjdExvZ1N0cmVhbU5hbWUoZXJyLm1lc3NhZ2UpID8/IGxvZ1N0cmVhbU5hbWVGcm9tUGh5c2ljYWxJZChlcnIucGh5c2ljYWxJZCk7XG5cbiAgcmV0dXJuIGZldGNoQ3VzdG9tUmVzb3VyY2VMb2dzKGN3bCwgbGFtYmRhLCBmdW5jdGlvbk5hbWUsIHRlbXBsYXRlTG9nR3JvdXAsIHN0cmVhbU5hbWUsIGVyci50aW1lc3RhbXAsIHJlZ2lvbiwgZGVidWcpO1xufVxuXG4vKipcbiAqIEZldGNoIGFuZCBwYXJzZSB0aGUgc3RhY2sncyAob3JpZ2luYWwpIHRlbXBsYXRlLiBSZXR1cm5zIGB1bmRlZmluZWRgIGlmIGl0IGNhbid0IGJlIHJlYWQuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGdldFN0YWNrVGVtcGxhdGUoXG4gIGNmbjogSUNsb3VkRm9ybWF0aW9uQ2xpZW50LFxuICBzdGFja05hbWU6IHN0cmluZyxcbiAgZGVidWc6IChtc2c6IHN0cmluZykgPT4gUHJvbWlzZTx2b2lkPixcbik6IFByb21pc2U8YW55IHwgdW5kZWZpbmVkPiB7XG4gIHRyeSB7XG4gICAgY29uc3QgcmVzcCA9IGF3YWl0IGNmbi5nZXRUZW1wbGF0ZSh7IFN0YWNrTmFtZTogc3RhY2tOYW1lLCBUZW1wbGF0ZVN0YWdlOiAnT3JpZ2luYWwnIH0pO1xuICAgIGlmICghcmVzcC5UZW1wbGF0ZUJvZHkpIHtcbiAgICAgIGF3YWl0IGRlYnVnKCdDdXN0b20gcmVzb3VyY2UgaW52ZXN0aWdhdGlvbjogZW1wdHkgdGVtcGxhdGUgYm9keScpO1xuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG4gICAgcmV0dXJuIGRlc2VyaWFsaXplU3RydWN0dXJlKHJlc3AuVGVtcGxhdGVCb2R5KTtcbiAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgYXdhaXQgZGVidWcoYEN1c3RvbSByZXNvdXJjZSBpbnZlc3RpZ2F0aW9uOiBmYWlsZWQgdG8gcmVhZCB0ZW1wbGF0ZTogJHtlLm1lc3NhZ2V9YCk7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxufVxuXG4vKipcbiAqIFJlc29sdmUgdGhlIGJhY2tpbmcgTGFtYmRhJ3MgY29uZmlndXJlZCBsb2cgZ3JvdXAgZnJvbSB0aGUgdGVtcGxhdGUuXG4gKlxuICogVGhlIHRlbXBsYXRlIHN1cnZpdmVzIHJvbGxiYWNrICh3aGVuIHRoZSBsaXZlIGZ1bmN0aW9uIG1heSBub3QpLCBzbyBpdCBpcyB0aGUgcHJlZmVycmVkXG4gKiBzb3VyY2UuIEhhbmRsZXMgdGhlIGZ1bmN0aW9uJ3MgYExvZ2dpbmdDb25maWcuTG9nR3JvdXBgIGFzOlxuICogLSBhIGxpdGVyYWwgc3RyaW5nIChyZXR1cm5lZCBkaXJlY3RseSk7XG4gKiAtIGEgYFJlZmAgdG8gYW4gYEFXUzo6TG9nczo6TG9nR3JvdXBgIHdpdGggYSBsaXRlcmFsIGBMb2dHcm91cE5hbWVgIChyZXR1cm5lZCBkaXJlY3RseSk7XG4gKiAtIGEgYFJlZmAgdG8gYW4gYEFXUzo6TG9nczo6TG9nR3JvdXBgIHdob3NlIG5hbWUgQ2xvdWRGb3JtYXRpb24gZ2VuZXJhdGVzICh0aGUgY29tbW9uIENES1xuICogICBjYXNlKSDigJQgcmVzb2x2ZWQgdG8gaXRzIHBoeXNpY2FsIG5hbWUgdmlhIGBkZXNjcmliZVN0YWNrUmVzb3VyY2VzYCwgd2hpY2ggc3RpbGwgcmV0dXJuc1xuICogICBSRVRBSU5lZC9vcnBoYW5lZCByZXNvdXJjZXMgYWZ0ZXIgYSByb2xsYmFjay5cbiAqXG4gKiBSZXR1cm5zIGB1bmRlZmluZWRgIHdoZW4gdGhlcmUgaXMgbm8gY29uZmlndXJlZCBsb2cgZ3JvdXAgb3IgaXQgY2FuJ3QgYmUgcmVzb2x2ZWRcbiAqIChjYWxsZXIgdGhlbiBmYWxscyBiYWNrIHRvIHRoZSBsaXZlIGZ1bmN0aW9uIGNvbmZpZ3VyYXRpb24pLlxuICovXG5hc3luYyBmdW5jdGlvbiByZXNvbHZlQ29uZmlndXJlZExvZ0dyb3VwKFxuICBjZm46IElDbG91ZEZvcm1hdGlvbkNsaWVudCxcbiAgc3RhY2tOYW1lOiBzdHJpbmcsXG4gIHRlbXBsYXRlOiBhbnksXG4gIGZ1bmN0aW9uTG9naWNhbElkOiBzdHJpbmcsXG4gIGRlYnVnOiAobXNnOiBzdHJpbmcpID0+IFByb21pc2U8dm9pZD4sXG4pOiBQcm9taXNlPHN0cmluZyB8IHVuZGVmaW5lZD4ge1xuICBjb25zdCBsb2dHcm91cCA9IHRlbXBsYXRlLlJlc291cmNlcz8uW2Z1bmN0aW9uTG9naWNhbElkXT8uUHJvcGVydGllcz8uTG9nZ2luZ0NvbmZpZz8uTG9nR3JvdXA7XG4gIGlmICh0eXBlb2YgbG9nR3JvdXAgPT09ICdzdHJpbmcnKSB7XG4gICAgcmV0dXJuIGxvZ0dyb3VwO1xuICB9XG4gIGlmIChsb2dHcm91cCAmJiB0eXBlb2YgbG9nR3JvdXAgPT09ICdvYmplY3QnICYmIHR5cGVvZiBsb2dHcm91cC5SZWYgPT09ICdzdHJpbmcnKSB7XG4gICAgY29uc3QgcmVmZXJlbmNlZCA9IHRlbXBsYXRlLlJlc291cmNlcz8uW2xvZ0dyb3VwLlJlZl07XG4gICAgY29uc3QgbmFtZSA9IHJlZmVyZW5jZWQ/LlByb3BlcnRpZXM/LkxvZ0dyb3VwTmFtZTtcbiAgICBpZiAodHlwZW9mIG5hbWUgPT09ICdzdHJpbmcnKSB7XG4gICAgICByZXR1cm4gbmFtZTtcbiAgICB9XG4gICAgLy8gTm8gZXhwbGljaXQgbmFtZSAoQ2xvdWRGb3JtYXRpb24gZ2VuZXJhdGVzIGl0KSDigJQgcmVzb2x2ZSB0aGUgbG9nLWdyb3VwIHJlc291cmNlJ3NcbiAgICAvLyBwaHlzaWNhbCBuYW1lLCB3aGljaCBpcyB0aGUgbG9nIGdyb3VwIG5hbWUuXG4gICAgcmV0dXJuIChhd2FpdCByZXNvbHZlU3RhY2tSZXNvdXJjZShjZm4sIHN0YWNrTmFtZSwgbG9nR3JvdXAuUmVmLCBkZWJ1ZykpPy5waHlzaWNhbElkO1xuICB9XG4gIHJldHVybiB1bmRlZmluZWQ7XG59XG5cbi8qKlxuICogUmVzb2x2ZSBhIHJlc291cmNlJ3MgcGh5c2ljYWwgSUQgYW5kIHR5cGUgYnkgbG9naWNhbCBJRC4gUmV0dXJucyBgdW5kZWZpbmVkYCBvbiBmYWlsdXJlLlxuICovXG5hc3luYyBmdW5jdGlvbiByZXNvbHZlU3RhY2tSZXNvdXJjZShcbiAgY2ZuOiBJQ2xvdWRGb3JtYXRpb25DbGllbnQsXG4gIHN0YWNrTmFtZTogc3RyaW5nLFxuICBsb2dpY2FsSWQ6IHN0cmluZyxcbiAgZGVidWc6IChtc2c6IHN0cmluZykgPT4gUHJvbWlzZTx2b2lkPixcbik6IFByb21pc2U8eyBwaHlzaWNhbElkPzogc3RyaW5nOyByZXNvdXJjZVR5cGU/OiBzdHJpbmcgfSB8IHVuZGVmaW5lZD4ge1xuICB0cnkge1xuICAgIGNvbnN0IHJlc3AgPSBhd2FpdCBjZm4uZGVzY3JpYmVTdGFja1Jlc291cmNlcyh7IFN0YWNrTmFtZTogc3RhY2tOYW1lLCBMb2dpY2FsUmVzb3VyY2VJZDogbG9naWNhbElkIH0pO1xuICAgIGNvbnN0IHJlc291cmNlID0gcmVzcC5TdGFja1Jlc291cmNlcz8uWzBdO1xuICAgIHJldHVybiByZXNvdXJjZSA/IHsgcGh5c2ljYWxJZDogcmVzb3VyY2UuUGh5c2ljYWxSZXNvdXJjZUlkLCByZXNvdXJjZVR5cGU6IHJlc291cmNlLlJlc291cmNlVHlwZSB9IDogdW5kZWZpbmVkO1xuICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICBhd2FpdCBkZWJ1ZyhgQ3VzdG9tIHJlc291cmNlIGludmVzdGlnYXRpb246IGZhaWxlZCB0byByZXNvbHZlIHJlc291cmNlIFwiJHtsb2dpY2FsSWR9XCI6ICR7ZS5tZXNzYWdlfWApO1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbn1cblxuLyoqXG4gKiBSZXNvbHZlIGEgYFNlcnZpY2VUb2tlbmAgdmFsdWUgKGEgbGl0ZXJhbCBBUk4sIGFuIGBGbjo6R2V0QXR0YCwgb3IgYSBgUmVmYCkgdG8gYSBMYW1iZGFcbiAqIGZ1bmN0aW9uIG5hbWUuIEludHJpbnNpY3MgYXJlIHJlc29sdmVkIHZpYSBgZGVzY3JpYmVTdGFja1Jlc291cmNlc2AuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHJlc29sdmVTZXJ2aWNlVG9rZW5Ub0Z1bmN0aW9uTmFtZShcbiAgY2ZuOiBJQ2xvdWRGb3JtYXRpb25DbGllbnQsXG4gIHN0YWNrTmFtZTogc3RyaW5nLFxuICBzZXJ2aWNlVG9rZW46IGFueSxcbiAgcmVmZXJlbmNlZExvZ2ljYWxJZDogc3RyaW5nIHwgdW5kZWZpbmVkLFxuICBkZWJ1ZzogKG1zZzogc3RyaW5nKSA9PiBQcm9taXNlPHZvaWQ+LFxuKTogUHJvbWlzZTxzdHJpbmcgfCB1bmRlZmluZWQ+IHtcbiAgaWYgKHJlZmVyZW5jZWRMb2dpY2FsSWQpIHtcbiAgICBjb25zdCByZXNvdXJjZSA9IGF3YWl0IHJlc29sdmVTdGFja1Jlc291cmNlKGNmbiwgc3RhY2tOYW1lLCByZWZlcmVuY2VkTG9naWNhbElkLCBkZWJ1Zyk7XG4gICAgLy8gT25seSB0cmVhdCB0aGUgcmVmZXJlbmNlIGFzIGEgTGFtYmRhIGZ1bmN0aW9uLiBXaXRob3V0IHRoaXMsIGEgU2VydmljZVRva2VuIHBvaW50aW5nIGF0XG4gICAgLy8gYSBub24tTGFtYmRhIHJlc291cmNlIChlLmcuIGFuIFNOUyB0b3BpYykgd2hvc2UgcGh5c2ljYWwgSUQgaXMgYSBiYXJlIG5hbWUgd291bGQgYmVcbiAgICAvLyBtaXN0YWtlbiBmb3IgYSBmdW5jdGlvbiBuYW1lLCBwcm9kdWNpbmcgYSBtaXNsZWFkaW5nIC9hd3MvbGFtYmRhLzxuYW1lPiBsb2cgbG9va3VwLlxuICAgIGlmIChyZXNvdXJjZT8ucmVzb3VyY2VUeXBlICYmIHJlc291cmNlLnJlc291cmNlVHlwZSAhPT0gJ0FXUzo6TGFtYmRhOjpGdW5jdGlvbicpIHtcbiAgICAgIGF3YWl0IGRlYnVnKGBDdXN0b20gcmVzb3VyY2UgaW52ZXN0aWdhdGlvbjogU2VydmljZVRva2VuIHJlZmVyZW5jZXMgYSAke3Jlc291cmNlLnJlc291cmNlVHlwZX0sIG5vdCBhIExhbWJkYSBmdW5jdGlvbmApO1xuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG4gICAgcmV0dXJuIHJlc291cmNlPy5waHlzaWNhbElkID8gZnVuY3Rpb25OYW1lRnJvbUFybk9yTmFtZShyZXNvdXJjZS5waHlzaWNhbElkKSA6IHVuZGVmaW5lZDtcbiAgfVxuXG4gIGlmICh0eXBlb2Ygc2VydmljZVRva2VuID09PSAnc3RyaW5nJykge1xuICAgIHJldHVybiBmdW5jdGlvbk5hbWVGcm9tQXJuT3JOYW1lKHNlcnZpY2VUb2tlbik7XG4gIH1cblxuICBhd2FpdCBkZWJ1ZygnQ3VzdG9tIHJlc291cmNlIGludmVzdGlnYXRpb246IHVuc3VwcG9ydGVkIFNlcnZpY2VUb2tlbiBzaGFwZScpO1xuICByZXR1cm4gdW5kZWZpbmVkO1xufVxuXG5hc3luYyBmdW5jdGlvbiBmZXRjaEN1c3RvbVJlc291cmNlTG9ncyhcbiAgY3dsOiBJQ2xvdWRXYXRjaExvZ3NDbGllbnQsXG4gIGxhbWJkYTogSUxhbWJkYUNsaWVudCxcbiAgZnVuY3Rpb25OYW1lOiBzdHJpbmcsXG4gIHRlbXBsYXRlTG9nR3JvdXA6IHN0cmluZyB8IHVuZGVmaW5lZCxcbiAgc3RyZWFtTmFtZTogc3RyaW5nIHwgdW5kZWZpbmVkLFxuICB0aW1lc3RhbXA6IERhdGUgfCB1bmRlZmluZWQsXG4gIHJlZ2lvbjogc3RyaW5nLFxuICBkZWJ1ZzogKG1zZzogc3RyaW5nKSA9PiBQcm9taXNlPHZvaWQ+LFxuKTogUHJvbWlzZTxBZGRpdGlvbmFsRGlhZ25vc3RpY0NvbnRleHRbXT4ge1xuICBjb25zdCBmYWlsdXJlVGltZSA9IHRpbWVzdGFtcD8udmFsdWVPZigpO1xuICBjb25zdCBzdGFydFRpbWUgPSBmYWlsdXJlVGltZSAhPT0gdW5kZWZpbmVkID8gZmFpbHVyZVRpbWUgLSBMT0dfV0lORE9XX0JFRk9SRV9NUyA6IERhdGUubm93KCkgLSBGQUxMQkFDS19MT0dfV0lORE9XX01TO1xuICBjb25zdCBlbmRUaW1lID0gZmFpbHVyZVRpbWUgIT09IHVuZGVmaW5lZCA/IGZhaWx1cmVUaW1lICsgTE9HX1dJTkRPV19BRlRFUl9NUyA6IHVuZGVmaW5lZDtcblxuICAvLyBDb252ZW50aW9uIGZpcnN0OyBvbmx5IHBheSBmb3IgdGhlIGNvbmZpZ3VyZWQgZ3JvdXAgaWYgdGhlIGNvbnZlbnRpb24gZ3JvdXAgZG9lc24ndCB5aWVsZCB1c2FibGUgbGluZXMgKGVtcHR5IGdyb3VwIG9yIGZldGNoIGVycm9yKS5cbiAgY29uc3QgY29udmVudGlvbkdyb3VwID0gYC9hd3MvbGFtYmRhLyR7ZnVuY3Rpb25OYW1lfWA7XG4gIGxldCByZXN1bHQgPSBhd2FpdCBmZXRjaExvZ0xpbmVzKGN3bCwgY29udmVudGlvbkdyb3VwLCBzdHJlYW1OYW1lLCBzdGFydFRpbWUsIGVuZFRpbWUsIGRlYnVnKTtcbiAgLy8gVGhlIGdyb3VwIHdlIHBvaW50IHRoZSB1c2VyIGF0LiBPbmNlIHdlIGxlYXJuIHRoZSBmdW5jdGlvbidzIGNvbmZpZ3VyZWQgbG9nIGdyb3VwLCBwcmVmZXJcbiAgLy8gaXQgZm9yIHRoZSBsaW5rIGV2ZW4gaWYgaXQgdG9vIGlzIGVtcHR5IOKAlCBpdCdzIHdoZXJlIHRoZSBmdW5jdGlvbiBhY3R1YWxseSBsb2dzLCB3aGVyZWFzXG4gIC8vIHRoZSBjb252ZW50aW9uIGdyb3VwIG1heSBub3QgZXhpc3QgZm9yIGFkdmFuY2VkLWxvZ2dpbmcgZnVuY3Rpb25zLlxuICBsZXQgbG9nR3JvdXAgPSBjb252ZW50aW9uR3JvdXA7XG5cbiAgaWYgKHJlc3VsdC5raW5kICE9PSAnbGluZXMnKSB7XG4gICAgLy8gUHJlZmVyIHRoZSB0ZW1wbGF0ZS1kZXJpdmVkIGdyb3VwIChyb2xsYmFjay1wcm9vZik7IGZhbGwgYmFjayB0byB0aGUgbGl2ZSBmdW5jdGlvblxuICAgIC8vIGNvbmZpZ3VyYXRpb24gb25seSB3aGVuIHRoZSB0ZW1wbGF0ZSBjb3VsZG4ndCB0ZWxsIHVzIChlLmcuIHVucmVzb2x2YWJsZSBpbnRyaW5zaWMsIG9yXG4gICAgLy8gdGhlIGZ1bmN0aW9uIGlzIGRlZmluZWQgb3V0c2lkZSB0aGlzIHN0YWNrKS5cbiAgICBjb25zdCBjb25maWd1cmVkR3JvdXAgPSB0ZW1wbGF0ZUxvZ0dyb3VwID8/IGF3YWl0IGNvbmZpZ3VyZWRMb2dHcm91cChsYW1iZGEsIGZ1bmN0aW9uTmFtZSwgZGVidWcpO1xuICAgIGlmIChjb25maWd1cmVkR3JvdXAgJiYgY29uZmlndXJlZEdyb3VwICE9PSBjb252ZW50aW9uR3JvdXApIHtcbiAgICAgIGxvZ0dyb3VwID0gY29uZmlndXJlZEdyb3VwO1xuICAgICAgY29uc3QgY29uZmlndXJlZFJlc3VsdCA9IGF3YWl0IGZldGNoTG9nTGluZXMoY3dsLCBjb25maWd1cmVkR3JvdXAsIHN0cmVhbU5hbWUsIHN0YXJ0VGltZSwgZW5kVGltZSwgZGVidWcpO1xuICAgICAgLy8gS2VlcCB0aGUgY29uZmlndXJlZC1ncm91cCByZXN1bHQgdW5sZXNzIGl0IGVycm9yZWQgd2hpbGUgdGhlIGNvbnZlbnRpb24gYXR0ZW1wdCB3YXMgYVxuICAgICAgLy8gY2xlYW4gZW1wdHkgKGFuIFwiZW1wdHlcIiBhbnN3ZXIgaXMgbW9yZSBpbmZvcm1hdGl2ZSB0byBzdXJmYWNlIHRoYW4gYSBmZXRjaCBlcnJvcikuXG4gICAgICBpZiAoY29uZmlndXJlZFJlc3VsdC5raW5kID09PSAnbGluZXMnIHx8IHJlc3VsdC5raW5kICE9PSAnZW1wdHknKSB7XG4gICAgICAgIHJlc3VsdCA9IGNvbmZpZ3VyZWRSZXN1bHQ7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8gTGVhZCB3aXRoIHRoZSBsb2cgZ3JvdXAgc28gdGhlIHVzZXIgY2FuIHRlbGwgd2hpY2ggZnVuY3Rpb24gdGhlc2UgbG9ncyBiZWxvbmcgdG9cbiAgLy8gKHRoZSBmb3JtYXR0ZXIgcmVuZGVycyBtZXNzYWdlcyBidXQgbm90IGBzb3VyY2VgLCBhbmQgdGhlIGxpbmsgaXMgVVJMLWVuY29kZWQpLlxuICBjb25zdCBoZWFkZXIgPSBgTG9ncyBmcm9tICR7bG9nR3JvdXB9OmA7XG4gIGNvbnN0IGJvZHkgPSByZXN1bHQua2luZCA9PT0gJ2xpbmVzJ1xuICAgID8gcmVzdWx0LmxpbmVzXG4gICAgOiByZXN1bHQua2luZCA9PT0gJ2Vycm9yJ1xuICAgICAgPyBbJ0NvdWxkIG5vdCBmZXRjaCBsb2dzICh0aGUgbG9nIGdyb3VwIG1heSBub3QgZXhpc3QsIG9yIHRoZSBjcmVkZW50aWFscyBsYWNrIGxvZ3M6RmlsdGVyTG9nRXZlbnRzKS4gU2VlIHRoZSBjb25zb2xlIGxpbmsgYmVsb3cuJ11cbiAgICAgIDogWydObyBsb2cgZXZlbnRzIGZvdW5kIGFyb3VuZCB0aGUgdGltZSBvZiBmYWlsdXJlLiBUaGUgZnVuY3Rpb24gbWF5IG5vdCBoYXZlIHByb2R1Y2VkIG91dHB1dCwgb3IgbG9nZ2luZyBtYXkgbm90IGJlIGNvbmZpZ3VyZWQuJ107XG5cbiAgcmV0dXJuIFt7XG4gICAgc291cmNlOiAnQ3VzdG9tIFJlc291cmNlIExhbWJkYSBMb2dzJyxcbiAgICBtZXNzYWdlczogW2hlYWRlciwgLi4uYm9keV0sXG4gICAgbGluazogY2xvdWRXYXRjaExvZ3NDb25zb2xlVXJsKHJlZ2lvbiwgbG9nR3JvdXApLFxuICAgIGxpbmtMYWJlbDogJ0xvZ3MnLFxuICB9XTtcbn1cblxuLyoqXG4gKiBSZXN1bHQgb2YgYXR0ZW1wdGluZyB0byBmZXRjaCBsb2dzIGZyb20gYSBncm91cDogdGhlIGxpbmVzIG9uIHN1Y2Nlc3MsIG9yIGEgcmVhc29uIHdlXG4gKiBoYXZlIG5vbmUg4oCUIGRpc3Rpbmd1aXNoaW5nIGFuIGVtcHR5IGdyb3VwIGZyb20gYSBmYWlsZWQgZmV0Y2ggKGUuZy4gbWlzc2luZyBwZXJtaXNzaW9ucyksXG4gKiBzbyB0aGUgdXNlci1mYWNpbmcgbWVzc2FnZSBjYW4gcmVmbGVjdCB0aGUgcmVhbCBjYXVzZS5cbiAqL1xudHlwZSBMb2dGZXRjaFJlc3VsdCA9XG4gIHwgeyBraW5kOiAnbGluZXMnOyBsaW5lczogc3RyaW5nW10gfVxuICB8IHsga2luZDogJ2VtcHR5JyB9XG4gIHwgeyBraW5kOiAnZXJyb3InIH07XG5cbi8qKlxuICogRmV0Y2ggYW5kIHRyaW0gcmVjZW50IGxvZyBsaW5lcyBmcm9tIGEgZ3JvdXAuXG4gKlxuICogVHJpZXMgdGhlIHRhcmdldGVkIHN0cmVhbSBmaXJzdCAobW9zdCByZWxldmFudCksIGJ1dCB0aGUgY2ZuLXJlc3BvbnNlIHN0cmVhbSBuYW1lIGNhbiBiZVxuICogc3RhbGUgb24gdXBkYXRlL3JvbGxiYWNrIGZhaWx1cmVzIChpdCdzIHBpbm5lZCB0byB0aGUgb3JpZ2luYWwgY3JlYXRlIGludm9jYXRpb24pLiBJZiB0aGVcbiAqIHRhcmdldGVkIHF1ZXJ5IGZpbmRzIG5vdGhpbmcsIGZhbGxzIGJhY2sgdG8gYSBncm91cC13aWRlIHNjYW4gb3ZlciB0aGUgdGltZSB3aW5kb3cgc28gYVxuICogc3RhbGUgc3RyZWFtIGNhbid0IGhpZGUgdGhlIGFjdHVhbCBmYWlsaW5nIGludm9jYXRpb24ncyBsb2dzLlxuICovXG5hc3luYyBmdW5jdGlvbiBmZXRjaExvZ0xpbmVzKFxuICBjd2w6IElDbG91ZFdhdGNoTG9nc0NsaWVudCxcbiAgbG9nR3JvdXA6IHN0cmluZyxcbiAgc3RyZWFtTmFtZTogc3RyaW5nIHwgdW5kZWZpbmVkLFxuICBzdGFydFRpbWU6IG51bWJlcixcbiAgZW5kVGltZTogbnVtYmVyIHwgdW5kZWZpbmVkLFxuICBkZWJ1ZzogKG1zZzogc3RyaW5nKSA9PiBQcm9taXNlPHZvaWQ+LFxuKTogUHJvbWlzZTxMb2dGZXRjaFJlc3VsdD4ge1xuICBpZiAoc3RyZWFtTmFtZSkge1xuICAgIGNvbnN0IHRhcmdldGVkID0gYXdhaXQgZmlsdGVyTG9nTGluZXMoY3dsLCBsb2dHcm91cCwgc3RyZWFtTmFtZSwgc3RhcnRUaW1lLCBlbmRUaW1lLCBkZWJ1Zyk7XG4gICAgaWYgKHRhcmdldGVkLmtpbmQgPT09ICdsaW5lcycpIHtcbiAgICAgIHJldHVybiB0YXJnZXRlZDtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIGZpbHRlckxvZ0xpbmVzKGN3bCwgbG9nR3JvdXAsIHVuZGVmaW5lZCwgc3RhcnRUaW1lLCBlbmRUaW1lLCBkZWJ1Zyk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGZpbHRlckxvZ0xpbmVzKFxuICBjd2w6IElDbG91ZFdhdGNoTG9nc0NsaWVudCxcbiAgbG9nR3JvdXA6IHN0cmluZyxcbiAgc3RyZWFtTmFtZTogc3RyaW5nIHwgdW5kZWZpbmVkLFxuICBzdGFydFRpbWU6IG51bWJlcixcbiAgZW5kVGltZTogbnVtYmVyIHwgdW5kZWZpbmVkLFxuICBkZWJ1ZzogKG1zZzogc3RyaW5nKSA9PiBQcm9taXNlPHZvaWQ+LFxuKTogUHJvbWlzZTxMb2dGZXRjaFJlc3VsdD4ge1xuICB0cnkge1xuICAgIGNvbnN0IHJlc3AgPSBhd2FpdCBjd2wuZmlsdGVyTG9nRXZlbnRzKHtcbiAgICAgIGxvZ0dyb3VwTmFtZTogbG9nR3JvdXAsXG4gICAgICBzdGFydFRpbWUsXG4gICAgICAuLi4oZW5kVGltZSAhPT0gdW5kZWZpbmVkID8geyBlbmRUaW1lIH0gOiB7fSksXG4gICAgICBsaW1pdDogMTAwMCxcbiAgICAgIC4uLihzdHJlYW1OYW1lID8geyBsb2dTdHJlYW1OYW1lczogW3N0cmVhbU5hbWVdIH0gOiB7fSksXG4gICAgfSk7XG4gICAgY29uc3QgZXZlbnRzID0gcmVzcC5ldmVudHMgPz8gW107XG4gICAgaWYgKGV2ZW50cy5sZW5ndGggPT09IDApIHtcbiAgICAgIGF3YWl0IGRlYnVnKGBDdXN0b20gcmVzb3VyY2UgaW52ZXN0aWdhdGlvbjogbm8gbG9nIGV2ZW50cyBpbiAke2xvZ0dyb3VwfSR7c3RyZWFtTmFtZSA/IGAgKHN0cmVhbTogJHtzdHJlYW1OYW1lfSlgIDogJyd9YCk7XG4gICAgICByZXR1cm4geyBraW5kOiAnZW1wdHknIH07XG4gICAgfVxuICAgIC8vIExhbWJkYSBsb2cgZXZlbnRzIGhhdmUgYSBrbm93biBzdHJ1Y3R1cmUgKHRleHQtIG9yIEpTT04tZm9ybWF0KSwgdW5saWtlIHJhdyBFQ1NcbiAgICAvLyBjb250YWluZXIgb3V0cHV0LCBzbyB3ZSBub3JtYWxpemUgdGhlbSBpbnRvIHJlYWRhYmxlIGxpbmVzIGJlZm9yZSB0cmltbWluZy5cbiAgICByZXR1cm4geyBraW5kOiAnbGluZXMnLCBsaW5lczogdHJpbVRvUmVjZW50TGluZXMocGFyc2VMYW1iZGFMb2dFdmVudHMoZXZlbnRzKSkgfTtcbiAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgYXdhaXQgZGVidWcoYEN1c3RvbSByZXNvdXJjZSBpbnZlc3RpZ2F0aW9uOiBmYWlsZWQgdG8gZmV0Y2ggbG9ncyBmcm9tICR7bG9nR3JvdXB9OiAke2UubWVzc2FnZX1gKTtcbiAgICByZXR1cm4geyBraW5kOiAnZXJyb3InIH07XG4gIH1cbn1cblxuLyoqIFJlYWQgdGhlIGZ1bmN0aW9uJ3MgY29uZmlndXJlZCAoYWR2YW5jZWQtbG9nZ2luZykgbG9nIGdyb3VwLCBpZiBhbnkuICovXG5hc3luYyBmdW5jdGlvbiBjb25maWd1cmVkTG9nR3JvdXAoXG4gIGxhbWJkYTogSUxhbWJkYUNsaWVudCxcbiAgZnVuY3Rpb25OYW1lOiBzdHJpbmcsXG4gIGRlYnVnOiAobXNnOiBzdHJpbmcpID0+IFByb21pc2U8dm9pZD4sXG4pOiBQcm9taXNlPHN0cmluZyB8IHVuZGVmaW5lZD4ge1xuICB0cnkge1xuICAgIGNvbnN0IHJlc3AgPSBhd2FpdCBsYW1iZGEuZ2V0RnVuY3Rpb25Db25maWd1cmF0aW9uKHsgRnVuY3Rpb25OYW1lOiBmdW5jdGlvbk5hbWUgfSk7XG4gICAgcmV0dXJuIHJlc3AuTG9nZ2luZ0NvbmZpZz8uTG9nR3JvdXA7XG4gIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgIGF3YWl0IGRlYnVnKGBDdXN0b20gcmVzb3VyY2UgaW52ZXN0aWdhdGlvbjogZmFpbGVkIHRvIHJlYWQgZnVuY3Rpb24gY29uZmlndXJhdGlvbjogJHtlLm1lc3NhZ2V9YCk7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxufVxuIl19
@@ -0,0 +1,20 @@
1
+ import type { AdditionalDiagnosticContext } from '../../actions/diagnose';
2
+ import type { SDK } from '../aws-auth/sdk';
3
+ import type { ResourceError } from '../stack-events/resource-errors';
4
+ /**
5
+ * Options that influence how a resource is investigated.
6
+ */
7
+ export interface InvestigateOptions {
8
+ /**
9
+ * Whether CloudFormation rollback is enabled for this deployment.
10
+ *
11
+ * When rollback is enabled, a failed resource is torn down before we can
12
+ * inspect its runtime state, so we may suggest re-running with `--no-rollback`
13
+ * to retain that detail.
14
+ *
15
+ * @default true
16
+ */
17
+ readonly rollbackEnabled?: boolean;
18
+ }
19
+ export declare function investigateEcsService(err: ResourceError, sdk: SDK, debug: (msg: string) => Promise<void>, options: InvestigateOptions): Promise<AdditionalDiagnosticContext[]>;
20
+ //# sourceMappingURL=investigate-ecs-service.d.ts.map
@@ -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==