@go-to-k/cdkd 0.284.51 → 0.284.53
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/dist/{asg-provider-CynKJdi4.js → asg-provider-Ciurx_UV.js} +2 -2
- package/dist/{asg-provider-CynKJdi4.js.map → asg-provider-Ciurx_UV.js.map} +1 -1
- package/dist/cli.js +2 -2
- package/dist/{deploy-engine-Dnp730rc.js → deploy-engine-DOP4V6eK.js} +303 -52
- package/dist/deploy-engine-DOP4V6eK.js.map +1 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/{program-DjH_cfVU.js → program-9yMSf-LQ.js} +49 -19
- package/dist/{program-DjH_cfVU.js.map → program-9yMSf-LQ.js.map} +1 -1
- package/dist/{version-CJG_PFNb.js → version-CaIqvSUG.js} +2 -2
- package/dist/{version-CJG_PFNb.js.map → version-CaIqvSUG.js.map} +1 -1
- package/package.json +1 -1
- package/dist/deploy-engine-Dnp730rc.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as getLiveRenderer, d as generateResourceNameWithFallback, f as getCurrentStackName, h as withStackName, l as applyDefaultNameForFallback, n as getLogger, p as looksLikeCdkdGeneratedName, u as generateResourceName } from "./logger-zRrlbaQt.js";
|
|
2
|
-
import { t as getCdkdVersion } from "./version-
|
|
2
|
+
import { t as getCdkdVersion } from "./version-CaIqvSUG.js";
|
|
3
3
|
import { randomUUID } from "node:crypto";
|
|
4
4
|
import { CreateBucketCommand, DeleteObjectCommand, DeleteObjectsCommand, GetBucketLocationCommand, GetObjectCommand, HeadBucketCommand, HeadObjectCommand, ListObjectsV2Command, NoSuchKey, PutBucketEncryptionCommand, PutBucketPolicyCommand, PutObjectCommand, PutPublicAccessBlockCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
|
|
5
5
|
import { CloudControlClient, CreateResourceCommand, DeleteResourceCommand, GetResourceCommand, GetResourceRequestStatusCommand, ListResourcesCommand, UpdateResourceCommand } from "@aws-sdk/client-cloudcontrol";
|
|
@@ -110,11 +110,17 @@ const IAM_PROPAGATION_ERROR_MESSAGE_PATTERNS = [
|
|
|
110
110
|
"is not a valid role to allow SNS"
|
|
111
111
|
];
|
|
112
112
|
/**
|
|
113
|
-
* The NON-IAM-propagation
|
|
114
|
-
* transient failures whose recovery
|
|
115
|
-
*
|
|
116
|
-
* load-related (throttling), where hammering AWS with dense retries
|
|
117
|
-
* and exponential backoff is the correct shape.
|
|
113
|
+
* The NON-IAM-propagation, NON-name-cooldown third of
|
|
114
|
+
* {@link RETRYABLE_ERROR_MESSAGE_PATTERNS}: transient failures whose recovery
|
|
115
|
+
* window is either long (a resource still leaving a Pending/Creating state) or
|
|
116
|
+
* genuinely load-related (throttling), where hammering AWS with dense retries
|
|
117
|
+
* is harmful and exponential backoff is the correct shape.
|
|
118
|
+
*
|
|
119
|
+
* The name-cooldown spellings used to live here too (`wait 60 seconds`, S3's
|
|
120
|
+
* `conflicting conditional operation`); they moved to
|
|
121
|
+
* {@link NAME_COOLDOWN_ERROR_MESSAGE_PATTERNS} so the ordinary-create path and
|
|
122
|
+
* the delete-then-re-create sites read ONE list instead of two that drifted
|
|
123
|
+
* apart (issue [#2116](https://github.com/go-to-k/cdkd/issues/2116)).
|
|
118
124
|
*/
|
|
119
125
|
const OTHER_TRANSIENT_ERROR_MESSAGE_PATTERNS = [
|
|
120
126
|
"currently in the following state: Pending",
|
|
@@ -123,10 +129,8 @@ const OTHER_TRANSIENT_ERROR_MESSAGE_PATTERNS = [
|
|
|
123
129
|
"DependencyViolation",
|
|
124
130
|
"does not exist",
|
|
125
131
|
"Schema is currently being altered",
|
|
126
|
-
"conflicting conditional operation",
|
|
127
132
|
"scheduled for deletion",
|
|
128
133
|
"Could not deliver test message",
|
|
129
|
-
"wait 60 seconds",
|
|
130
134
|
"concurrent update operation",
|
|
131
135
|
"because it is in use",
|
|
132
136
|
"Rate exceeded",
|
|
@@ -135,15 +139,101 @@ const OTHER_TRANSIENT_ERROR_MESSAGE_PATTERNS = [
|
|
|
135
139
|
"Unable to complete operation due to concurrent modification"
|
|
136
140
|
];
|
|
137
141
|
/**
|
|
142
|
+
* The **name-cooldown** third of {@link RETRYABLE_ERROR_MESSAGE_PATTERNS}:
|
|
143
|
+
* an AWS service that holds a resource's NAME (or other unique identifier)
|
|
144
|
+
* while an ASYNCHRONOUS delete of the previous holder is still in flight, so a
|
|
145
|
+
* create of the same name inside that window is refused with a
|
|
146
|
+
* service-specific message. The window always clears on its own — the delete
|
|
147
|
+
* that opened it is already running — which is what makes every entry here
|
|
148
|
+
* retryable rather than terminal, whichever call site hits it.
|
|
149
|
+
*
|
|
150
|
+
* Read by BOTH consumers, which is the whole point of the list existing
|
|
151
|
+
* (issue [#2116](https://github.com/go-to-k/cdkd/issues/2116)):
|
|
152
|
+
*
|
|
153
|
+
* - {@link isNameCooldownError}, and through it
|
|
154
|
+
* {@link isRecreateRetryableError}, the retry filter at the
|
|
155
|
+
* delete-then-re-create sites (the deploy engine's `--replace` delete-first
|
|
156
|
+
* fallback, the recreate-via-* path, the rollback executor's
|
|
157
|
+
* delete-new-first) — the sites where cdkd itself just deleted the name
|
|
158
|
+
* holder;
|
|
159
|
+
* - {@link RETRYABLE_ERROR_MESSAGE_PATTERNS}, i.e. the ORDINARY create path,
|
|
160
|
+
* where a fresh `cdkd deploy` process has no idea a prior `cdkd destroy`
|
|
161
|
+
* deleted anything.
|
|
162
|
+
*
|
|
163
|
+
* The second consumer is the reachable one and was the measured failure in
|
|
164
|
+
* #2116: destroy-then-redeploy is a routine dev loop, CloudFormation absorbs
|
|
165
|
+
* the window and converges, and cdkd claims template compatibility with
|
|
166
|
+
* CloudFormation — so failing the whole deploy (26 resources created and
|
|
167
|
+
* rolled back, on the run that filed the issue) over a condition that clears
|
|
168
|
+
* in seconds is a parity defect. Before this list, the two consumers held
|
|
169
|
+
* DIFFERENT spellings of the same SQS error: the wire message
|
|
170
|
+
* (`wait 60 seconds`) was in the generic table so an ordinary create retried
|
|
171
|
+
* it, while the error CODE (`QueueDeletedRecently`) was not — so whether the
|
|
172
|
+
* identical AWS condition was survivable depended on which spelling the SDK
|
|
173
|
+
* happened to surface.
|
|
174
|
+
*
|
|
175
|
+
* Bounded, not unbounded: since #2116 the ordinary-create path rides
|
|
176
|
+
* `withRetry`'s NAME-COOLDOWN grid (8 retries, 2s/4s/8s then capped at 10s ≈
|
|
177
|
+
* 64s of sleep — `NAME_COOLDOWN_INITIAL_DELAY_MS` in `./retry.ts`), which is
|
|
178
|
+
* the same budget the re-create sites already carried. It is deliberately NOT
|
|
179
|
+
* the generic 47s schedule this path used to inherit: SQS's own sentence names
|
|
180
|
+
* a 60-second window, so 47s would not converge, it would merely fail 47s
|
|
181
|
+
* later. A name that is NOT in fact being
|
|
182
|
+
* released — a genuine, permanent collision — is a different signature
|
|
183
|
+
* ({@link isNameCollisionError}) and is deliberately NOT here, so it still
|
|
184
|
+
* fails fast into the actionable `--replace` refusal instead of burning a
|
|
185
|
+
* budget it cannot survive.
|
|
186
|
+
*
|
|
187
|
+
* **What must NOT go in this list.** Every entry below is specific to a delete
|
|
188
|
+
* that is ALREADY in flight and clears within a budget. Three candidates the
|
|
189
|
+
* sibling sweep turned up are recorded here as deliberate EXCLUSIONS rather
|
|
190
|
+
* than left unmentioned, because "absent" and "considered and rejected" are
|
|
191
|
+
* indistinguishable to the next person doing this sweep:
|
|
192
|
+
*
|
|
193
|
+
* - **ELBv2 `DuplicateLoadBalancerName`** and **DynamoDB's create-side
|
|
194
|
+
* `Table already exists: <name>`** — AWS raises both for a resource that
|
|
195
|
+
* merely EXISTS, just as readily as for a deleting one, so neither is
|
|
196
|
+
* distinguishable from a terminal collision. Promoting either would convert
|
|
197
|
+
* a fast, actionable `--replace` refusal into a full retry budget ending in
|
|
198
|
+
* the same failure. (DynamoDB's `Table is being deleted` IS distinguishable,
|
|
199
|
+
* but promoting THAT one re-multiplies the destroy-runner budget arithmetic
|
|
200
|
+
* `src/provisioning/dynamodb-index-busy-delete.ts` derives against the
|
|
201
|
+
* per-resource deadline — a different reason, so it is stated separately
|
|
202
|
+
* rather than folded in with the two above.)
|
|
203
|
+
* - **Secrets Manager `scheduled for deletion`** — the same one-sided shape as
|
|
204
|
+
* S3's entry (generic table only, invisible to
|
|
205
|
+
* {@link isRecreateRetryableError}), and the provider does delete with
|
|
206
|
+
* `ForceDeleteWithoutRecovery: true`, so it LOOKS like it belongs. It is
|
|
207
|
+
* excluded because that single message covers TWO conditions with wildly
|
|
208
|
+
* different windows: a force-deleted secret's name releasing in
|
|
209
|
+
* seconds-to-minutes, and a secret scheduled for deletion with a
|
|
210
|
+
* `RecoveryWindowInDays` of 7-30 DAYS, which no bounded budget can ride out
|
|
211
|
+
* and which a user reaches by deleting a secret outside cdkd. A budget that
|
|
212
|
+
* cannot converge on half its population is worse than failing fast, so the
|
|
213
|
+
* entry stays where it already was — in the generic table, retryable on an
|
|
214
|
+
* ordinary create and terminal at the re-create sites, unchanged by #2116.
|
|
215
|
+
*/
|
|
216
|
+
const NAME_COOLDOWN_ERROR_MESSAGE_PATTERNS = [
|
|
217
|
+
"QueueDeletedRecently",
|
|
218
|
+
"wait 60 seconds",
|
|
219
|
+
"StateMachineDeleting",
|
|
220
|
+
"State Machine is being deleted",
|
|
221
|
+
"conflicting conditional operation"
|
|
222
|
+
];
|
|
223
|
+
/**
|
|
138
224
|
* Patterns that mark an AWS error as a transient/retryable failure.
|
|
139
225
|
* Each entry is a substring match against the error message; all of these
|
|
140
226
|
* are situations where the same call typically succeeds after a short delay
|
|
141
227
|
* because of eventual consistency or just-created-dependency propagation.
|
|
142
228
|
*
|
|
143
|
-
* Composed from the
|
|
229
|
+
* Composed from the three halves above so retryability has ONE source of truth
|
|
144
230
|
* while `withRetry` can still pick a per-class backoff cadence.
|
|
145
231
|
*/
|
|
146
|
-
const RETRYABLE_ERROR_MESSAGE_PATTERNS = [
|
|
232
|
+
const RETRYABLE_ERROR_MESSAGE_PATTERNS = [
|
|
233
|
+
...IAM_PROPAGATION_ERROR_MESSAGE_PATTERNS,
|
|
234
|
+
...OTHER_TRANSIENT_ERROR_MESSAGE_PATTERNS,
|
|
235
|
+
...NAME_COOLDOWN_ERROR_MESSAGE_PATTERNS
|
|
236
|
+
];
|
|
147
237
|
/**
|
|
148
238
|
* HTTP status codes that always indicate a transient failure worth retrying.
|
|
149
239
|
* 429 = Too Many Requests (throttle), 503 = Service Unavailable.
|
|
@@ -575,26 +665,31 @@ function isNameCollisionError(message) {
|
|
|
575
665
|
return /(?<!\b(?:must|not|should|may|cannot)\s)already exists?\b/i.test(message) || message.includes("AlreadyExists");
|
|
576
666
|
}
|
|
577
667
|
/**
|
|
578
|
-
* Match
|
|
579
|
-
*
|
|
580
|
-
*
|
|
581
|
-
*
|
|
582
|
-
*
|
|
583
|
-
*
|
|
584
|
-
*
|
|
585
|
-
*
|
|
586
|
-
*
|
|
587
|
-
*
|
|
588
|
-
*
|
|
589
|
-
*
|
|
590
|
-
*
|
|
668
|
+
* Match a same-name re-creation cooldown — an AWS service still holding a
|
|
669
|
+
* resource's name while its asynchronous delete finishes. Every recognised
|
|
670
|
+
* spelling lives in {@link NAME_COOLDOWN_ERROR_MESSAGE_PATTERNS}; add new ones
|
|
671
|
+
* THERE rather than here, so the ordinary-create path
|
|
672
|
+
* ({@link RETRYABLE_ERROR_MESSAGE_PATTERNS}, which composes that list) cannot
|
|
673
|
+
* drift out of step with the delete-then-re-create sites again. That drift is
|
|
674
|
+
* exactly what issue [#2116](https://github.com/go-to-k/cdkd/issues/2116)
|
|
675
|
+
* found: SQS's wire message was retryable on an ordinary create while its
|
|
676
|
+
* error code was not, and the Step Functions spelling was recognised by
|
|
677
|
+
* neither.
|
|
678
|
+
*
|
|
679
|
+
* The delete-then-re-create sites (the deploy engine's `--replace`
|
|
680
|
+
* delete-first fallback and the rollback executor's reverse-replacement)
|
|
681
|
+
* override the retry filter with {@link isNameCollisionError}, which these
|
|
682
|
+
* signatures do NOT match — so a replacement revert used to fail fast
|
|
683
|
+
* mid-flight with the resource absent from both AWS and state (issue #1206).
|
|
684
|
+
* Those sites OR this matcher into their retry filter, with a schedule long
|
|
685
|
+
* enough to cover the 60s SQS window.
|
|
591
686
|
*
|
|
592
687
|
* Kept separate from {@link isNameCollisionError} on purpose: a cooldown at a
|
|
593
688
|
* create-first site must NOT be treated as a collision (deleting the new
|
|
594
689
|
* resource would not release the cooldown on the old name).
|
|
595
690
|
*/
|
|
596
691
|
function isNameCooldownError(message) {
|
|
597
|
-
return
|
|
692
|
+
return NAME_COOLDOWN_ERROR_MESSAGE_PATTERNS.some((p) => message.includes(p));
|
|
598
693
|
}
|
|
599
694
|
/**
|
|
600
695
|
* Retry filter for the delete-then-re-create sites: the old name holder was
|
|
@@ -989,8 +1084,10 @@ var PartialFailureError = class PartialFailureError extends CdkdError {
|
|
|
989
1084
|
* is the whole point: the message interpolates the resource's LOGICAL ID,
|
|
990
1085
|
* and the retry classifiers match by SUBSTRING, so a perfectly ordinary
|
|
991
1086
|
* composite CDK id like `MyDependencyViolationSub` made
|
|
992
|
-
* `isRetryableTransientError` return true (`DependencyViolation`
|
|
993
|
-
* whitespace-free entry in `RETRYABLE_ERROR_MESSAGE_PATTERNS
|
|
1087
|
+
* `isRetryableTransientError` return true (`DependencyViolation` was then the
|
|
1088
|
+
* only whitespace-free entry in `RETRYABLE_ERROR_MESSAGE_PATTERNS`; the
|
|
1089
|
+
* name-cooldown error CODES `QueueDeletedRecently` / `StateMachineDeleting`
|
|
1090
|
+
* joined it under issue #2116, so the hazard is wider, not narrower) and burned the
|
|
994
1091
|
* full generic schedule — 8 retries, ~47s of pure sleep — on a path that was
|
|
995
1092
|
* never going to succeed, before the fallback the error exists to trigger was
|
|
996
1093
|
* even reached.
|
|
@@ -6938,7 +7035,8 @@ const STATE_SCHEMA_VERSIONS_READABLE = [
|
|
|
6938
7035
|
5,
|
|
6939
7036
|
6,
|
|
6940
7037
|
7,
|
|
6941
|
-
8
|
|
7038
|
+
8,
|
|
7039
|
+
9
|
|
6942
7040
|
];
|
|
6943
7041
|
/**
|
|
6944
7042
|
* Returns true when a recorded `DeletionPolicy` should prevent cdkd from
|
|
@@ -6954,6 +7052,50 @@ const STATE_SCHEMA_VERSIONS_READABLE = [
|
|
|
6954
7052
|
function shouldRetainResource(deletionPolicy) {
|
|
6955
7053
|
return deletionPolicy === "Retain" || deletionPolicy === "RetainExceptOnCreate";
|
|
6956
7054
|
}
|
|
7055
|
+
/**
|
|
7056
|
+
* The keys of `state.outputs` an `Fn::ImportValue` may bind to (issue
|
|
7057
|
+
* [#2193](https://github.com/go-to-k/cdkd/issues/2193)) — THE predicate
|
|
7058
|
+
* behind "what does this stack export". Four readers used to answer that
|
|
7059
|
+
* by walking `outputs` wholesale (the exports index on update and on
|
|
7060
|
+
* rebuild, the resolver's state scan, and the local-command loader's
|
|
7061
|
+
* `Fn::ImportValue` fallback scan), and each therefore took a plain Output
|
|
7062
|
+
* name for an export; they all go through here now, so the rule cannot
|
|
7063
|
+
* drift between them.
|
|
7064
|
+
*
|
|
7065
|
+
* A record whose `exportNames` is unknown (pre-v9, or a v9 partial save that
|
|
7066
|
+
* carried a pre-v9 bag forward) keeps the legacy rule — every key — until
|
|
7067
|
+
* its next deploy writes the set. A known set is intersected with the bag:
|
|
7068
|
+
* an alias whose value did not resolve publishes nothing, and a name the
|
|
7069
|
+
* bag does not hold cannot be served.
|
|
7070
|
+
*
|
|
7071
|
+
* `outputs` is typed required but every consumer treats it as optional (a
|
|
7072
|
+
* state file may simply have none), so it is read defensively here too.
|
|
7073
|
+
*/
|
|
7074
|
+
function importableOutputKeys(state) {
|
|
7075
|
+
const outputs = state.outputs ?? {};
|
|
7076
|
+
if (state.exportNames === void 0) return Object.keys(outputs);
|
|
7077
|
+
return state.exportNames.filter((name) => Object.hasOwn(outputs, name));
|
|
7078
|
+
}
|
|
7079
|
+
/** `state.outputs` narrowed to its {@link importableOutputKeys}. */
|
|
7080
|
+
function importableOutputs(state) {
|
|
7081
|
+
const outputs = state.outputs ?? {};
|
|
7082
|
+
const picked = Object.create(null);
|
|
7083
|
+
for (const name of importableOutputKeys(state)) picked[name] = outputs[name];
|
|
7084
|
+
return picked;
|
|
7085
|
+
}
|
|
7086
|
+
/**
|
|
7087
|
+
* The `exportNames` half of a record whose `outputs` bag is being CARRIED
|
|
7088
|
+
* FORWARD unchanged rather than re-resolved (a partial save on a failed
|
|
7089
|
+
* deploy, `cdkd import` over an existing record). The two travel together:
|
|
7090
|
+
* carrying the bag without its set would turn a known-exports record back
|
|
7091
|
+
* into a "not known" one, and inventing `[]` for a pre-v9 bag would deny
|
|
7092
|
+
* every consumer of a stack that never had the chance to write the set.
|
|
7093
|
+
* Spread this next to `outputs: previous.outputs` — never write the field
|
|
7094
|
+
* by hand at such a site.
|
|
7095
|
+
*/
|
|
7096
|
+
function exportNamesCarriedFrom(previous) {
|
|
7097
|
+
return previous.exportNames === void 0 ? {} : { exportNames: previous.exportNames };
|
|
7098
|
+
}
|
|
6957
7099
|
|
|
6958
7100
|
//#endregion
|
|
6959
7101
|
//#region src/types/rollback-journal.ts
|
|
@@ -7327,7 +7469,7 @@ var S3StateBackend = class {
|
|
|
7327
7469
|
const { expectedEtag, migrateLegacy } = options;
|
|
7328
7470
|
const body = {
|
|
7329
7471
|
...state,
|
|
7330
|
-
version:
|
|
7472
|
+
version: 9,
|
|
7331
7473
|
stackName,
|
|
7332
7474
|
region
|
|
7333
7475
|
};
|
|
@@ -9715,6 +9857,68 @@ const IAM_PROPAGATION_MAX_DELAY_MS = 2e3;
|
|
|
9715
9857
|
* generic one by more than 0.75s in the early band.
|
|
9716
9858
|
*/
|
|
9717
9859
|
const IAM_PROPAGATION_MAX_RETRIES = 26;
|
|
9860
|
+
/**
|
|
9861
|
+
* Backoff for the NAME-COOLDOWN class on the DEFAULT schedule — an AWS service
|
|
9862
|
+
* still holding a resource's name while an asynchronous delete of the previous
|
|
9863
|
+
* holder finishes (`NAME_COOLDOWN_ERROR_MESSAGE_PATTERNS` in
|
|
9864
|
+
* ./retryable-errors.ts). Issue
|
|
9865
|
+
* [#2116](https://github.com/go-to-k/cdkd/issues/2116).
|
|
9866
|
+
*
|
|
9867
|
+
* **Why this class does not inherit the generic schedule.** The generic one
|
|
9868
|
+
* sleeps 1+2+4+8+8+8+8+8 = 47s, and the longest window in this class NAMES its
|
|
9869
|
+
* own duration: SQS's own sentence is "You must wait 60 seconds after deleting
|
|
9870
|
+
* a queue before you can create another with the same name." A 47s budget
|
|
9871
|
+
* against a 60s window does not converge — it just fails 47s later, which is
|
|
9872
|
+
* strictly worse than failing at once. That mismatch was live for as long as
|
|
9873
|
+
* `wait 60 seconds` has been in the generic table.
|
|
9874
|
+
*
|
|
9875
|
+
* **Where the numbers come from — precedent, not a fresh guess.** They are the
|
|
9876
|
+
* delete-then-re-create sites' existing budget, chosen for this exact window
|
|
9877
|
+
* (`deploy-engine.ts`'s `--replace` fallback and `rollback-executor.ts`'s
|
|
9878
|
+
* reverse-replacement both pass `maxRetries: 8, initialDelayMs: 2_000,
|
|
9879
|
+
* maxDelayMs: 10_000`). Adopting it here makes the ordinary create path and
|
|
9880
|
+
* the re-create sites ride the SAME window with the SAME budget, which is the
|
|
9881
|
+
* property #2116 is about: whether a cooldown is survivable must not depend on
|
|
9882
|
+
* which call site met it.
|
|
9883
|
+
*
|
|
9884
|
+
* 2 + 4 + 8 + 10 x 5 = 64s over 8 retries
|
|
9885
|
+
*
|
|
9886
|
+
* Probe grid (seconds after the first failure): 2, 6, 14, 24, 34, 44, 54, 64 —
|
|
9887
|
+
* covering SQS's 60s and, with room to spare, the ~23s of `status: DELETING`
|
|
9888
|
+
* measured on an idle Step Functions state machine
|
|
9889
|
+
* (`tests/integration/custom-resource-provider`).
|
|
9890
|
+
*
|
|
9891
|
+
* **What it does NOT claim.** A window LONGER than 64s still fails, with the
|
|
9892
|
+
* same AWS message as before. This class converts "always fails" into "fails
|
|
9893
|
+
* only past a budget derived from the longest window AWS itself documents" —
|
|
9894
|
+
* and, unlike the generic schedule, a run that exhausts it now says so (see
|
|
9895
|
+
* the give-up summary in {@link withRetry}), so a too-short budget is
|
|
9896
|
+
* reportable rather than indistinguishable from having no retry at all.
|
|
9897
|
+
*
|
|
9898
|
+
* The retry COUNT is deliberately the generic 8 rather than a new ceiling, so
|
|
9899
|
+
* nothing about the loop's own exit condition moves. Same reason the dense IAM
|
|
9900
|
+
* grid needed its own count and this does not.
|
|
9901
|
+
*
|
|
9902
|
+
* **But "only the delay grid changes" understates the effect at the NESTED
|
|
9903
|
+
* sites, so state the compounding rather than implying there is none.** Three
|
|
9904
|
+
* call sites wrap a DEFAULT-schedule `withRetry` inside their own outer loop
|
|
9905
|
+
* (`deploy-engine.ts`'s two `--replace` / recreate sites and
|
|
9906
|
+
* `rollback-executor.ts`'s reverse-replacement). The inner loop is the one
|
|
9907
|
+
* this grid changes, and the outer one re-enters it per attempt, so the
|
|
9908
|
+
* product grows with it: total sleep on a cooldown at those sites measures
|
|
9909
|
+
* **487s -> 640s (8.1 -> 10.7 min)**. That is accepted, not overlooked -- it
|
|
9910
|
+
* stays inside the 30-minute per-resource `withResourceDeadline`, and the
|
|
9911
|
+
* alternative is an inner loop that cannot ride out the window it is nested
|
|
9912
|
+
* for. A reader auditing those budgets needs the number, which is why it is
|
|
9913
|
+
* here and not left to be re-derived.
|
|
9914
|
+
*
|
|
9915
|
+
* `dynamodb-index-busy-delete.ts` is unaffected and that was checked rather
|
|
9916
|
+
* than assumed: it passes all four knobs, so `defaultSchedule` is false and
|
|
9917
|
+
* this grid never applies to it -- its own deadline arithmetic stands.
|
|
9918
|
+
*/
|
|
9919
|
+
const NAME_COOLDOWN_INITIAL_DELAY_MS = 2e3;
|
|
9920
|
+
/** Cap for the name-cooldown backoff. See {@link NAME_COOLDOWN_INITIAL_DELAY_MS}. */
|
|
9921
|
+
const NAME_COOLDOWN_MAX_DELAY_MS = 1e4;
|
|
9718
9922
|
const defaultSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
9719
9923
|
/**
|
|
9720
9924
|
* Run `operation`, retrying transient failures with exponential backoff
|
|
@@ -9734,6 +9938,13 @@ const defaultSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
|
9734
9938
|
* re-create sites' ~64s budget covering SQS's 60s name cooldown) and gets it
|
|
9735
9939
|
* verbatim.
|
|
9736
9940
|
*
|
|
9941
|
+
* A THIRD class rides its own grid on the default schedule since issue
|
|
9942
|
+
* [#2116](https://github.com/go-to-k/cdkd/issues/2116): a NAME COOLDOWN (a
|
|
9943
|
+
* service still holding a name while an async delete finishes) gets
|
|
9944
|
+
* 2s/4s/8s then 10s to a 64s total, because the longest window in that class
|
|
9945
|
+
* NAMES its duration -- SQS says "wait 60 seconds" -- and the generic 47s
|
|
9946
|
+
* cannot ride out a 60s wait. See {@link NAME_COOLDOWN_INITIAL_DELAY_MS}.
|
|
9947
|
+
*
|
|
9737
9948
|
* The class is re-evaluated per attempt, so a propagation retry that runs into
|
|
9738
9949
|
* a throttle backs OFF exponentially for that attempt instead of hammering.
|
|
9739
9950
|
*
|
|
@@ -9764,6 +9975,8 @@ async function withRetry(operation, logicalId, opts = {}) {
|
|
|
9764
9975
|
let sawPropagation = false;
|
|
9765
9976
|
let propagationRetries = 0;
|
|
9766
9977
|
let propagationSleptMs = 0;
|
|
9978
|
+
let nameCooldownRetries = 0;
|
|
9979
|
+
let nameCooldownSleptMs = 0;
|
|
9767
9980
|
let serverErrorRetries = 0;
|
|
9768
9981
|
for (let attempt = 0; attempt <= attemptCeiling; attempt++) try {
|
|
9769
9982
|
return await operation();
|
|
@@ -9774,12 +9987,15 @@ async function withRetry(operation, logicalId, opts = {}) {
|
|
|
9774
9987
|
const retryable = opts.isRetryable ? opts.isRetryable(message, error) : isRetryableTransientError(error, message);
|
|
9775
9988
|
const propagation = defaultSchedule && isIamPropagationError(message);
|
|
9776
9989
|
if (propagation) sawPropagation = true;
|
|
9990
|
+
const nameCooldown = defaultSchedule && !propagation && isNameCooldownError(message);
|
|
9777
9991
|
const attemptLimit = sawPropagation ? 26 : maxRetries;
|
|
9778
9992
|
if (!retryable || attempt >= attemptLimit) {
|
|
9779
|
-
if (propagationRetries > 0 || serverErrorRetries > 0) {
|
|
9993
|
+
if (propagationRetries > 0 || serverErrorRetries > 0 || nameCooldownRetries > 0) {
|
|
9780
9994
|
const budgetExhausted = sawPropagation && attempt >= attemptLimit;
|
|
9995
|
+
const nameCooldownBudgetExhausted = nameCooldownRetries >= maxRetries && attempt >= attemptLimit;
|
|
9781
9996
|
const spent = [];
|
|
9782
9997
|
if (propagationRetries > 0) spent.push(`${propagationRetries} IAM-propagation ${propagationRetries === 1 ? "retry" : "retries"} over ${(propagationSleptMs / 1e3).toFixed(2)}s of propagation backoff${budgetExhausted ? " (the full propagation budget)" : ""}`);
|
|
9998
|
+
if (nameCooldownRetries > 0) spent.push(`${nameCooldownRetries} name-cooldown ${nameCooldownRetries === 1 ? "retry" : "retries"} over ${(nameCooldownSleptMs / 1e3).toFixed(2)}s waiting for the name to be released${nameCooldownBudgetExhausted ? " (the full name-cooldown budget)" : ""}`);
|
|
9783
9999
|
if (serverErrorRetries > 0) spent.push(`${serverErrorRetries} transient server-error ${serverErrorRetries === 1 ? "retry" : "retries"} (HTTP 5xx)`);
|
|
9784
10000
|
const summary = () => `${logicalId}: gave up after ${spent.join(" and ")} - ${message}` + formatRetryClassificationSignals(error);
|
|
9785
10001
|
try {
|
|
@@ -9788,7 +10004,7 @@ async function withRetry(operation, logicalId, opts = {}) {
|
|
|
9788
10004
|
}
|
|
9789
10005
|
throw error;
|
|
9790
10006
|
}
|
|
9791
|
-
const delay = propagation ? Math.min(250 * Math.pow(2, attempt), IAM_PROPAGATION_MAX_DELAY_MS) : Math.min(initialDelayMs * Math.pow(2, attempt), maxDelayMs);
|
|
10007
|
+
const delay = propagation ? Math.min(250 * Math.pow(2, attempt), IAM_PROPAGATION_MAX_DELAY_MS) : nameCooldown ? Math.min(NAME_COOLDOWN_INITIAL_DELAY_MS * Math.pow(2, attempt), NAME_COOLDOWN_MAX_DELAY_MS) : Math.min(initialDelayMs * Math.pow(2, attempt), maxDelayMs);
|
|
9792
10008
|
const backoffThroughThisAttemptMs = propagation ? propagationSleptMs + delay : propagationSleptMs;
|
|
9793
10009
|
opts.logger?.debug(` ⏳ Retrying ${logicalId} in ${delay / 1e3}s (attempt ${attempt + 1}/${attemptLimit}${propagation ? `, ${(backoffThroughThisAttemptMs / 1e3).toFixed(2)}s backoff through this attempt` : ""}) - ${message}`);
|
|
9794
10010
|
for (let waited = 0; waited < delay; waited += 1e3) {
|
|
@@ -9798,6 +10014,9 @@ async function withRetry(operation, logicalId, opts = {}) {
|
|
|
9798
10014
|
if (propagation) {
|
|
9799
10015
|
propagationRetries++;
|
|
9800
10016
|
propagationSleptMs = backoffThroughThisAttemptMs;
|
|
10017
|
+
} else if (nameCooldown) {
|
|
10018
|
+
nameCooldownRetries++;
|
|
10019
|
+
nameCooldownSleptMs += delay;
|
|
9801
10020
|
} else if (opts.isRetryable === void 0 && isTransientServerError(error)) serverErrorRetries++;
|
|
9802
10021
|
}
|
|
9803
10022
|
throw lastError;
|
|
@@ -16216,7 +16435,8 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
16216
16435
|
* criterion `retryable-errors.ts` documents as insufficient: the classifiers
|
|
16217
16436
|
* match by SUBSTRING, and `sourceClause` interpolates template-controlled
|
|
16218
16437
|
* text, so a logical id like `MyDependencyViolationHandler` puts
|
|
16219
|
-
* `DependencyViolation` (
|
|
16438
|
+
* `DependencyViolation` (a whitespace-free entry in the table — the only
|
|
16439
|
+
* one until issue #2116 added the name-cooldown error codes) into the
|
|
16220
16440
|
* message. Reachability is real even though resolution runs outside
|
|
16221
16441
|
* `withRetry` on the flat path: `NestedStackProvider.create` runs a child
|
|
16222
16442
|
* `DeployEngine.deploy()` and re-throws, and the parent wraps `create()` in
|
|
@@ -16559,7 +16779,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
16559
16779
|
continue;
|
|
16560
16780
|
}
|
|
16561
16781
|
const { state } = stateData;
|
|
16562
|
-
if (state.
|
|
16782
|
+
if (importableOutputKeys(state).includes(exportName)) {
|
|
16563
16783
|
const value = state.outputs[exportName];
|
|
16564
16784
|
this.logger.info(`Resolved Fn::ImportValue: ${loggedExportName} (from stack: ${refStack} / ${lookupRegion}; ${carriesDynamicReference(value) ? "redacted dynamic reference" : "literal value"})`);
|
|
16565
16785
|
if (context.exportIndex) context.exportIndex.patchEntry(exportName, {
|
|
@@ -18231,7 +18451,7 @@ var CloudControlProvider = class {
|
|
|
18231
18451
|
if (context?.finalSnapshotIdentifier !== void 0) throw new ProvisioningError(`${logicalId} (${resourceType}) requires a final snapshot (DeletionPolicy: Snapshot), but the Cloud Control API delete route has no final-snapshot parameter. Re-run with --skip-final-snapshot after snapshotting manually, or retain the resource.`, resourceType, logicalId, physicalId);
|
|
18232
18452
|
if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
|
|
18233
18453
|
this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
|
|
18234
|
-
const { ASGProvider } = await import("./asg-provider-
|
|
18454
|
+
const { ASGProvider } = await import("./asg-provider-Ciurx_UV.js").then((n) => n.n);
|
|
18235
18455
|
return await new ASGProvider().delete(logicalId, physicalId, resourceType, _properties, context);
|
|
18236
18456
|
}
|
|
18237
18457
|
const isProtectedEc2Instance = context?.removeProtection === true && resourceType === "AWS::EC2::Instance";
|
|
@@ -26030,7 +26250,8 @@ async function replayRollback(operations, stateResources, stackName, ctx, option
|
|
|
26030
26250
|
* hang the flag exists to prevent. Those providers retry internally.
|
|
26031
26251
|
* - **Interrupt.** `replayRollback` polls interrupts only BETWEEN ops, so an
|
|
26032
26252
|
* un-threaded `isInterrupted` leaves Ctrl-C dead for the length of the
|
|
26033
|
-
* backoff schedule
|
|
26253
|
+
* backoff schedule per op — ~47s on the generic grid, or ~64s if the op
|
|
26254
|
+
* hits a name cooldown, which rides its own longer grid since issue #2116.
|
|
26034
26255
|
*
|
|
26035
26256
|
* Returns the provider's result so the caller can honour
|
|
26036
26257
|
* `effectiveProperties` (issue #1644) — both revert arms used to write the
|
|
@@ -26336,8 +26557,13 @@ async function updateWithRollbackRetry(provider, args, logicalId, logger, isInte
|
|
|
26336
26557
|
* on attempt 0 and it reaches the caller's catch on the FIRST outer attempt,
|
|
26337
26558
|
* exactly as before. The SQS cooldown IS matched by the inner classifier (the
|
|
26338
26559
|
* generic table carries `wait 60 seconds`), which is the same division of
|
|
26339
|
-
* labour the deploy engine's named-replacement site documents
|
|
26340
|
-
*
|
|
26560
|
+
* labour the deploy engine's named-replacement site documents. Since issue
|
|
26561
|
+
* #2116 the inner retry rides the name-cooldown grid (≈64s) rather than the
|
|
26562
|
+
* generic ~47s one, so it covers the whole 60s window on its own instead of
|
|
26563
|
+
* absorbing most of it and leaving a tail for the outer loop; the outer loop
|
|
26564
|
+
* now earns its place by ALSO covering the late name release that the inner
|
|
26565
|
+
* default classifier rejects. The two compound — measured at 640s of total
|
|
26566
|
+
* sleep on a cooldown, inside the 30-minute per-resource deadline.
|
|
26341
26567
|
*/
|
|
26342
26568
|
async function createWithRollbackRetry(provider, create, logicalId, logger, isInterrupted, secrets, outer) {
|
|
26343
26569
|
if (provider.disableOuterRetry) return await create();
|
|
@@ -27658,6 +27884,17 @@ var DeployEngine = class {
|
|
|
27658
27884
|
*/
|
|
27659
27885
|
outputsTemplateSource = {};
|
|
27660
27886
|
/**
|
|
27887
|
+
* The export aliases the last `resolveOutputs` pass WROTE into its bag
|
|
27888
|
+
* (issue #2193) — exactly the keys `outputs[exportName] = value` landed on,
|
|
27889
|
+
* so an alias the pass refused (secret-bearing name, collision with a
|
|
27890
|
+
* published output name) or skipped (unresolved value, condition-suppressed
|
|
27891
|
+
* output) is not in it. Persisted as `StackState.exportNames` by the saves
|
|
27892
|
+
* that persist that bag, and the set the exports index is fed from. Reset
|
|
27893
|
+
* at the top of every `resolveOutputs`, so it is only meaningful right
|
|
27894
|
+
* after that call returns — read it there, not later.
|
|
27895
|
+
*/
|
|
27896
|
+
resolvedExportNames = [];
|
|
27897
|
+
/**
|
|
27661
27898
|
* Whether {@link outputsTemplateSource} may be used to POSITION the outputs
|
|
27662
27899
|
* redaction. False once an outputs pass threw partway: the post-loop
|
|
27663
27900
|
* name pass never ran, so the bag holds only the alias keys written before
|
|
@@ -28033,11 +28270,12 @@ var DeployEngine = class {
|
|
|
28033
28270
|
renderer.start();
|
|
28034
28271
|
const currentStateData = await this.stateBackend.getState(stackName, this.stackRegion);
|
|
28035
28272
|
const currentState = currentStateData?.state ?? {
|
|
28036
|
-
version:
|
|
28273
|
+
version: 9,
|
|
28037
28274
|
region: this.stackRegion,
|
|
28038
28275
|
stackName,
|
|
28039
28276
|
resources: {},
|
|
28040
28277
|
outputs: {},
|
|
28278
|
+
exportNames: [],
|
|
28041
28279
|
lastModified: Date.now()
|
|
28042
28280
|
};
|
|
28043
28281
|
const currentEtag = currentStateData?.etag;
|
|
@@ -28094,16 +28332,20 @@ var DeployEngine = class {
|
|
|
28094
28332
|
const resolvedOutputs = this.redactOutputs(await this.resolveOutputs(effectiveTemplate, currentState.resources, stackName, parameterValues, conditions));
|
|
28095
28333
|
const resolutionFailed = Object.values(resolvedOutputs).some((v) => v === void 0);
|
|
28096
28334
|
const outputsChanged = !resolutionFailed && !outputMapsEqual(persistedOutputs, resolvedOutputs);
|
|
28335
|
+
const currentEffectiveExports = new Set(importableOutputKeys(currentState));
|
|
28336
|
+
const resolvedExportSet = new Set(this.resolvedExportNames);
|
|
28337
|
+
const exportSetChanged = !resolutionFailed && (currentEffectiveExports.size !== resolvedExportSet.size || [...resolvedExportSet].some((k) => !currentEffectiveExports.has(k)));
|
|
28097
28338
|
if (resolutionFailed && !outputMapsEqual(persistedOutputs, resolvedOutputs)) this.logger.warn("Outputs changed but one or more could not be resolved; keeping the previously persisted outputs. A downstream Fn::ImportValue may fail until the next deploy.");
|
|
28098
28339
|
const observedRefresh = this.observedCaptureTasks.size > 0;
|
|
28099
28340
|
if (observedRefresh) await this.drainObservedCaptures(currentState.resources);
|
|
28100
|
-
if (observedRefresh || outputsChanged) try {
|
|
28341
|
+
if (observedRefresh || outputsChanged || exportSetChanged) try {
|
|
28101
28342
|
const refreshedState = {
|
|
28102
|
-
version:
|
|
28343
|
+
version: 9,
|
|
28103
28344
|
region: this.stackRegion,
|
|
28104
28345
|
stackName: currentState.stackName,
|
|
28105
28346
|
resources: currentState.resources,
|
|
28106
28347
|
outputs: outputsChanged ? resolvedOutputs : persistedOutputs,
|
|
28348
|
+
...resolutionFailed ? exportNamesCarriedFrom(currentState) : { exportNames: [...this.resolvedExportNames] },
|
|
28107
28349
|
...crossStackReadsForPartialSave(currentState, this.recordedImports, this.recordedOutputReads),
|
|
28108
28350
|
lastModified: Date.now()
|
|
28109
28351
|
};
|
|
@@ -28111,10 +28353,11 @@ var DeployEngine = class {
|
|
|
28111
28353
|
if (currentEtag !== void 0) saveOptions.expectedEtag = currentEtag;
|
|
28112
28354
|
if (migrationPending) saveOptions.migrateLegacy = true;
|
|
28113
28355
|
await this.stateBackend.saveState(stackName, this.stackRegion, this.withParentInfo(refreshedState), saveOptions);
|
|
28114
|
-
if (outputsChanged) {
|
|
28115
|
-
persistedOutputs =
|
|
28116
|
-
this.logger.info("Persisted Outputs-only change (no resource diff).");
|
|
28117
|
-
|
|
28356
|
+
if (outputsChanged || exportSetChanged) {
|
|
28357
|
+
persistedOutputs = refreshedState.outputs;
|
|
28358
|
+
if (outputsChanged) this.logger.info("Persisted Outputs-only change (no resource diff).");
|
|
28359
|
+
else this.logger.debug("Persisted export-set change (no outputs-value diff, no-change path, #2193)");
|
|
28360
|
+
if (this.exportIndexStore) await this.exportIndexStore.updateForStack(stackName, this.stackRegion, importableOutputs(refreshedState));
|
|
28118
28361
|
} else this.logger.debug("Persisted refreshed observedProperties (no-change path)");
|
|
28119
28362
|
} catch (saveError) {
|
|
28120
28363
|
this.logger.warn(`Failed to persist no-change state update: ${saveError instanceof Error ? saveError.message : String(saveError)} — drift baseline / outputs will be re-resolved on next deploy.`);
|
|
@@ -28161,7 +28404,7 @@ var DeployEngine = class {
|
|
|
28161
28404
|
await this.drainObservedCaptures(newState.resources);
|
|
28162
28405
|
const newEtag = await this.stateBackend.saveState(stackName, this.stackRegion, this.withParentInfo(newState));
|
|
28163
28406
|
this.logger.debug(`State saved (ETag: ${newEtag})`);
|
|
28164
|
-
await Promise.all([this.deleteRollbackJournalBestEffort(stackName), this.exportIndexStore ? this.exportIndexStore.updateForStack(stackName, this.stackRegion, newState
|
|
28407
|
+
await Promise.all([this.deleteRollbackJournalBestEffort(stackName), this.exportIndexStore ? this.exportIndexStore.updateForStack(stackName, this.stackRegion, importableOutputs(newState)) : Promise.resolve()]);
|
|
28165
28408
|
const durationMs = Date.now() - startTime;
|
|
28166
28409
|
const unchangedCount = this.diffCalculator.filterByType(changes, "NO_CHANGE").length + actualCounts.skipped;
|
|
28167
28410
|
return {
|
|
@@ -28219,11 +28462,12 @@ var DeployEngine = class {
|
|
|
28219
28462
|
saveChain = saveChain.then(async () => {
|
|
28220
28463
|
try {
|
|
28221
28464
|
const partialState = {
|
|
28222
|
-
version:
|
|
28465
|
+
version: 9,
|
|
28223
28466
|
region: this.stackRegion,
|
|
28224
28467
|
stackName: currentState.stackName,
|
|
28225
28468
|
resources: newResources,
|
|
28226
28469
|
outputs: currentState.outputs,
|
|
28470
|
+
...exportNamesCarriedFrom(currentState),
|
|
28227
28471
|
...crossStackReadsForPartialSave(currentState, this.recordedImports, this.recordedOutputReads),
|
|
28228
28472
|
lastModified: Date.now()
|
|
28229
28473
|
};
|
|
@@ -28349,11 +28593,12 @@ var DeployEngine = class {
|
|
|
28349
28593
|
const initialDeploy = currentEtag === void 0;
|
|
28350
28594
|
try {
|
|
28351
28595
|
const preRollbackState = {
|
|
28352
|
-
version:
|
|
28596
|
+
version: 9,
|
|
28353
28597
|
region: this.stackRegion,
|
|
28354
28598
|
stackName: currentState.stackName,
|
|
28355
28599
|
resources: newResources,
|
|
28356
28600
|
outputs: currentState.outputs,
|
|
28601
|
+
...exportNamesCarriedFrom(currentState),
|
|
28357
28602
|
...crossStackReadsForPartialSave(currentState, this.recordedImports, this.recordedOutputReads),
|
|
28358
28603
|
lastModified: Date.now()
|
|
28359
28604
|
};
|
|
@@ -28384,11 +28629,12 @@ var DeployEngine = class {
|
|
|
28384
28629
|
}
|
|
28385
28630
|
try {
|
|
28386
28631
|
const postRollbackState = {
|
|
28387
|
-
version:
|
|
28632
|
+
version: 9,
|
|
28388
28633
|
region: this.stackRegion,
|
|
28389
28634
|
stackName: currentState.stackName,
|
|
28390
28635
|
resources: newResources,
|
|
28391
28636
|
outputs: currentState.outputs,
|
|
28637
|
+
...exportNamesCarriedFrom(currentState),
|
|
28392
28638
|
...crossStackReadsForPartialSave(currentState, this.recordedImports, this.recordedOutputReads),
|
|
28393
28639
|
lastModified: Date.now()
|
|
28394
28640
|
};
|
|
@@ -28400,11 +28646,12 @@ var DeployEngine = class {
|
|
|
28400
28646
|
try {
|
|
28401
28647
|
const freshEtag = (await this.stateBackend.getState(stackName, this.stackRegion))?.etag;
|
|
28402
28648
|
const postRollbackState = {
|
|
28403
|
-
version:
|
|
28649
|
+
version: 9,
|
|
28404
28650
|
region: this.stackRegion,
|
|
28405
28651
|
stackName: currentState.stackName,
|
|
28406
28652
|
resources: newResources,
|
|
28407
28653
|
outputs: currentState.outputs,
|
|
28654
|
+
...exportNamesCarriedFrom(currentState),
|
|
28408
28655
|
...crossStackReadsForPartialSave(currentState, this.recordedImports, this.recordedOutputReads),
|
|
28409
28656
|
lastModified: Date.now()
|
|
28410
28657
|
};
|
|
@@ -28428,11 +28675,12 @@ var DeployEngine = class {
|
|
|
28428
28675
|
}
|
|
28429
28676
|
return {
|
|
28430
28677
|
state: {
|
|
28431
|
-
version:
|
|
28678
|
+
version: 9,
|
|
28432
28679
|
region: this.stackRegion,
|
|
28433
28680
|
stackName: currentState.stackName,
|
|
28434
28681
|
resources: newResources,
|
|
28435
28682
|
outputs,
|
|
28683
|
+
exportNames: [...this.resolvedExportNames],
|
|
28436
28684
|
...this.recordedImports.length > 0 && { imports: [...this.recordedImports] },
|
|
28437
28685
|
...this.recordedOutputReads.length > 0 && { outputReads: [...this.recordedOutputReads] },
|
|
28438
28686
|
lastModified: Date.now()
|
|
@@ -28465,11 +28713,12 @@ var DeployEngine = class {
|
|
|
28465
28713
|
*/
|
|
28466
28714
|
async persistStateAfterOutputFailure(stackName, currentState, newResources, currentEtag, pendingMigration) {
|
|
28467
28715
|
const buildState = () => ({
|
|
28468
|
-
version:
|
|
28716
|
+
version: 9,
|
|
28469
28717
|
region: this.stackRegion,
|
|
28470
28718
|
stackName: currentState.stackName,
|
|
28471
28719
|
resources: newResources,
|
|
28472
28720
|
outputs: currentState.outputs,
|
|
28721
|
+
...exportNamesCarriedFrom(currentState),
|
|
28473
28722
|
...crossStackReadsForPartialSave(currentState, this.recordedImports, this.recordedOutputReads),
|
|
28474
28723
|
lastModified: Date.now()
|
|
28475
28724
|
});
|
|
@@ -29471,6 +29720,7 @@ var DeployEngine = class {
|
|
|
29471
29720
|
* then (issue #1919).
|
|
29472
29721
|
*/
|
|
29473
29722
|
async resolveOutputs(template, resources, stackName, parameterValues, conditions) {
|
|
29723
|
+
this.resolvedExportNames = [];
|
|
29474
29724
|
if (!template.Outputs) return {};
|
|
29475
29725
|
const outputs = {};
|
|
29476
29726
|
const context = this.buildResolverContext({
|
|
@@ -29519,6 +29769,7 @@ var DeployEngine = class {
|
|
|
29519
29769
|
else if (isExportAliasCollision(exportName, outputKey, publishedOutputNames)) this.logger.warn(exportAliasCollisionWarning(outputKey, exportName));
|
|
29520
29770
|
else {
|
|
29521
29771
|
outputs[exportName] = value;
|
|
29772
|
+
if (!this.resolvedExportNames.includes(exportName)) this.resolvedExportNames.push(exportName);
|
|
29522
29773
|
this.outputsTemplateSource[exportName] = output.Value;
|
|
29523
29774
|
}
|
|
29524
29775
|
}
|
|
@@ -29545,5 +29796,5 @@ var DeployEngine = class {
|
|
|
29545
29796
|
};
|
|
29546
29797
|
|
|
29547
29798
|
//#endregion
|
|
29548
|
-
export { startInterruptWatch as $,
|
|
29549
|
-
//# sourceMappingURL=deploy-engine-
|
|
29799
|
+
export { startInterruptWatch as $, AwsClients as $n, shouldRetainResource as $t, renderStatefulReason as A, getLegacyStateBucketName as An, isThrottlingError as Ar, redactSecretsForState as At, exportAliasCollisionScrubWarning as B, CFN_TEMPLATE_BODY_LIMIT as Bn, DiffCalculator as Bt, isFinalSnapshotError as C, runDockerForeground as Cn, SynthesisError as Cr, TEMPLATE_SOURCED_RULES as Ct, extractDeploymentEventError as D, Synthesizer as Dn, withErrorHandling as Dr, isSingleDynamicReferenceToken as Dt, makeCanonicalizePropertiesFn as E, getDockerImageBySourceHash as En, normalizeAwsError as Er, errorCauseChain as Et, green as F, resolveStateBucketWithDefault as Fn, s3BucketDomainName as Ft, collectInlinePolicyNamesManagedBySiblings as G, expectedOwnerParam as Gn, TemplateParser as Gt, secretBearingStateKeyWarning as H, MIGRATE_TMP_PREFIX as Hn, describeTypeWithThrottleRetry as Ht, red as I, resolveStateBucketWithDefaultAndSource as In, s3BucketDualStackDomainName as It, findActionableSilentDrops as J, derivePartitionAndUrlSuffix as Jn, S3StateBackend as Jt, clearOnUpdateRemoval as K, PARTITION_TABLE as Kn, LockManager as Kt, yellow as L, resolveUseCdkBootstrapAssets as Ln, s3BucketRegionalDomainName as Lt, bold as M, resolveAutoAssetStorage as Mn, __exportAll as Mr, classifyReplaySecretRegion as Mt, cyan as N, resolveCaptureObservedState as Nn, producerRegionsFromState as Nt, MULTI_REGION_RECREATE_BLOCKED_TYPES as O, synthesisStatusMessage as On, isMarkedNonRetryable as Or, maskSecretsInError as Ot, gray as P, resolveSkipPrefix as Pn, s3BucketArn as Pt, isInterruptedWaitError as Q, resolveBucketRegion as Qn, importableOutputs as Qt, collectDeclaredOutputNames as R, stateBucketExistenceConfirmed as Rn, s3BucketWebsiteUrl as Rt, createPreDeleteFinalSnapshot as S, partitionSensitiveEnv as Sn, StateError as Sr, STATE_SOURCED_READBACK_RULES as St, unsupportedFinalSnapshotError as T, AssetManifestLoader as Tn, isCdkdError as Tr, dynamicReferenceTokens as Tt, stateKeySecretExposure as U, findLargeInlineResources as Un, withRetry as Ut, isExportAliasCollision as V, CFN_TEMPLATE_URL_LIMIT as Vn, INTRINSIC_KEYS as Vt, IAMRoleProvider as W, uploadCfnTemplate as Wn, DagBuilder as Wt, beginCommandInterruptScope as X, processStackMessages as Xn, exportNamesCarriedFrom as Xt, findSilentDropProperties as Y, AssemblyReader as Yn, rebuildClientForBucketRegion as Yt, endCommandInterruptScope as Z, clearBucketRegionCache as Zn, importableOutputKeys as Zt, computeImplicitDeleteEdges as _, buildDenyExternalAccessPolicy as _n, ProvisioningError as _r, replayWarn as _t, DeploymentEventsStore as a, loadPublishableAssetManifest as an, ConfigError as ar, carriesDynamicReference as at, buildFinalSnapshotIdentifier as b, formatDockerLoginError as bn, StackHasActiveImportsError as br, requireConfigString as bt, replayFailedOperations as c, stripControlChars as cn, DeployCancelledError as cr, refStateLookupFromResource as ct, updatePartialReason as d, ensureAssetStorage as dn, LocalMigrateError as dr, resolveExplicitPhysicalId as dt, AssetPublisher as en, getAwsClients as er, CloudControlProvider as et, UNSPECIFIED_SKIP_REASON as f, getBootstrapMarkerKey as fn, LocalStartServiceError as fr, assertRegionMatch as ft, IMPLICIT_DELETE_DEPENDENCIES as g, validateContainerRepoName as gn, PartialFailureError as gr, readConfigString as gt, maskingRetryLogger as h, validateAssetBucketName as hn, NestedStackChildDirectDestroyError as hr, configStringRefusal as ht, DeploymentEventsReader as i, createAssetRedirectResolver as in, CdkdError as ir, IntrinsicFunctionResolver as it, formatResourceLine as j, resolveApp as jn, markNonRetryable as jr, scrubResourceRecord as jt, isStatefulRecreateTargetSync as k, getDefaultStateBucketName as kn, isRetryableTransientError as kr, maskSecretsInText as kt, replayRollback as l, AssetModeResolver as ln, DynamicReferenceRegionAmbiguousError as lr, WAFv2WebACLProvider as lt, withResourceDeadline as m, readBootstrapMarkerBody as mn, MissingCdkCliError as mr, configBooleanRefusal as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, WorkGraph as nn, setAwsClients as nr, disableInstanceApiTermination as nt, planFailedOps as o, rewriteTemplateAssetReferences as on, CrossAccountSecretRefusalError as or, cfnRefValueFromPhysicalId as ot, deleteSkipReason as p, parseBootstrapMarker as pn, LockError as pr, coerceCfnBoolean as pt, ProviderRegistry as q, canonicalizeRegion as qn, displaySafe as qt, DeployEngine as r, buildAssetRedirectMap as rn, AssetError as rr, isTerminationProtectionPropagationError as rt, planRollback as s, escapeRegExp$1 as sn, DependencyError as sr, getAccountInfo as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, stringifyValue as tn, resetAwsClients as tr, slowCcOperationTimeoutMs as tt, updatePartialMessage as u, BOOTSTRAP_MARKER_PREFIX as un, LocalInvokeBuildError as ur, normalizeAwsTagsToCfn as ut, ATOMIC_FINAL_SNAPSHOT_TYPES as v, buildDockerImage as vn, ResourceTimeoutError as vr, requireConfigArray as vt, refusesFinalSnapshot as w, runDockerStreaming as wn, formatError as wr, createSecretMasker as wt, ccRoutedFinalSnapshotError as x, getDockerCmd as xn, StackTerminationProtectionError as xr, STATE_SOURCED_CROSS_GENERATION_RULES as xt, PRE_DELETE_SNAPSHOT_TYPES as y, dockerSpawnEnvWithSensitive as yn, ResourceUpdateNotSupportedError as yr, requireConfigObject as yt, collectPublishedOutputNames as z, warnDeprecatedNoPrefixCliFlag as zn, applyRoleArnIfSet as zt };
|
|
29800
|
+
//# sourceMappingURL=deploy-engine-DOP4V6eK.js.map
|