@go-to-k/cdkd 0.284.23 → 0.284.25
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-Cucl2K22.js → asg-provider-B2lPfJBN.js} +2 -2
- package/dist/{asg-provider-Cucl2K22.js.map → asg-provider-B2lPfJBN.js.map} +1 -1
- package/dist/cli.js +353 -169
- package/dist/cli.js.map +1 -1
- package/dist/{deploy-engine-HfFU96oJ.js → deploy-engine-BpZWPiaL.js} +445 -57
- package/dist/deploy-engine-BpZWPiaL.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/deploy-engine-HfFU96oJ.js.map +0 -1
|
@@ -16860,7 +16860,7 @@ var CloudControlProvider = class {
|
|
|
16860
16860
|
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);
|
|
16861
16861
|
if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
|
|
16862
16862
|
this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
|
|
16863
|
-
const { ASGProvider } = await import("./asg-provider-
|
|
16863
|
+
const { ASGProvider } = await import("./asg-provider-B2lPfJBN.js").then((n) => n.n);
|
|
16864
16864
|
return await new ASGProvider().delete(logicalId, physicalId, resourceType, _properties, context);
|
|
16865
16865
|
}
|
|
16866
16866
|
const isProtectedEc2Instance = context?.removeProtection === true && resourceType === "AWS::EC2::Instance";
|
|
@@ -17531,6 +17531,280 @@ var CloudControlProvider = class {
|
|
|
17531
17531
|
}
|
|
17532
17532
|
};
|
|
17533
17533
|
|
|
17534
|
+
//#endregion
|
|
17535
|
+
//#region src/provisioning/interrupt-watch.ts
|
|
17536
|
+
/**
|
|
17537
|
+
* The ONE interrupt watch every bounded wait under `src/provisioning/**` uses
|
|
17538
|
+
* (issues #2053 / #1952, consolidating the per-invocation shape PR #2033
|
|
17539
|
+
* introduced in `providers/custom-resource-provider.ts`).
|
|
17540
|
+
*
|
|
17541
|
+
* WHY A WAIT NEEDS ONE AT ALL
|
|
17542
|
+
* ---------------------------
|
|
17543
|
+
* `withRetry` (`src/deployment/retry.ts`) is the only wait in cdkd that
|
|
17544
|
+
* consults an interrupt DURING a backoff — it probes once a second while
|
|
17545
|
+
* sleeping. The deploy engine, `destroy-runner.ts` and `rollback-executor.ts`
|
|
17546
|
+
* all poll only BETWEEN operations. So a retry that threads nothing is dead to
|
|
17547
|
+
* Ctrl-C for its whole schedule, and on the destroy path `withResourceTimeout`
|
|
17548
|
+
* has by then abandoned the promise WITHOUT cancelling it, so the loop keeps
|
|
17549
|
+
* issuing writes behind a run the user was told had ended.
|
|
17550
|
+
* `docs/provider-development.md` states the requirement; `vp run
|
|
17551
|
+
* audit:withretry-interrupt:check` enforces it.
|
|
17552
|
+
*
|
|
17553
|
+
* WHY IT IS SHARED RATHER THAN PER MODULE
|
|
17554
|
+
* ---------------------------------------
|
|
17555
|
+
* Four modules carried a copy before issue #2104, and the copies could not
|
|
17556
|
+
* agree about the one thing that matters: a single `delete()` traverses more
|
|
17557
|
+
* than one of them, so a SIGINT marked only whichever module happened to hold a
|
|
17558
|
+
* live watch. One module means one latch, one error type, and ONE process
|
|
17559
|
+
* listener rather than four.
|
|
17560
|
+
*
|
|
17561
|
+
* FOUR PROPERTIES, EACH LOAD-BEARING
|
|
17562
|
+
* ----------------------------------
|
|
17563
|
+
*
|
|
17564
|
+
* 1. **The flag is per WAIT, never on a provider.** Providers are registered as
|
|
17565
|
+
* SINGLETONS serving concurrent resources, so provider-level state is some
|
|
17566
|
+
* other resource's.
|
|
17567
|
+
*
|
|
17568
|
+
* 2. **The latch is STICKY.** A watch STARTED after the signal begins is
|
|
17569
|
+
* already interrupted. Clearing it when the last watch is disposed — the
|
|
17570
|
+
* first cut — is wrong for exactly the case issue #1952 is about: a
|
|
17571
|
+
* `GlobalTable` delete runs the #1521 gate, then the index-busy retry loop,
|
|
17572
|
+
* then the gone-wait, each disposing before the next begins, so a SIGINT
|
|
17573
|
+
* during the gate left the two multi-minute waits after it DEAF. Only a
|
|
17574
|
+
* COMMAND clears it. The listener is likewise never torn down BETWEEN two
|
|
17575
|
+
* waits: one removed in that gap cannot record a signal landing in it, which
|
|
17576
|
+
* is the same bug one layer down. {@link endCommandInterruptScope} removes it
|
|
17577
|
+
* at command END, where there is no next wait to miss.
|
|
17578
|
+
*
|
|
17579
|
+
* 3. **It arms only inside a command that OWNS interrupt handling.** Registering
|
|
17580
|
+
* any SIGINT listener disables Node's default terminate, so a command with no
|
|
17581
|
+
* graceful shutdown of its own must not gain one here: `cdkd drift --revert`
|
|
17582
|
+
* reaches `provider.update` and installs nothing, and an armed watch there
|
|
17583
|
+
* would leave Ctrl-C setting flags nobody reads while the command carried on
|
|
17584
|
+
* writing to AWS — needing a SIGKILL.
|
|
17585
|
+
*
|
|
17586
|
+
* The gate is an explicit flag raised by
|
|
17587
|
+
* {@link beginCommandInterruptScope}, which `forwardSigtermToSigint()` calls
|
|
17588
|
+
* at command start. It is deliberately NOT
|
|
17589
|
+
* `process.listenerCount('SIGINT') > 0`, which was the first cut and is
|
|
17590
|
+
* defeated by the very case it was meant to catch: `cdkd drift` runs
|
|
17591
|
+
* `provider.update` at concurrency 4, and a concurrent CloudFront / ACM /
|
|
17592
|
+
* Route53 wait installs a TRANSIENT SIGINT listener of its own — so an ELBv2
|
|
17593
|
+
* update starting inside that window saw a non-zero count, armed, and then
|
|
17594
|
+
* kept the listener for the rest of the command after the transient one was
|
|
17595
|
+
* removed. A count answers "is anyone listening right now"; the question is
|
|
17596
|
+
* "does this COMMAND have a shutdown path", and only the command can say.
|
|
17597
|
+
* (`forwardSigtermToSigint` itself registers on SIGTERM only, so it never
|
|
17598
|
+
* satisfied the count either — a detail an earlier version of this comment
|
|
17599
|
+
* got wrong, which is how the gap survived a review.)
|
|
17600
|
+
*
|
|
17601
|
+
* Arming is re-attempted on every watch, so a wait that runs before the
|
|
17602
|
+
* command opens its scope does not poison later ones.
|
|
17603
|
+
*
|
|
17604
|
+
* 4. **The handler force-quits when it is the LAST listener.** Property 3 gets
|
|
17605
|
+
* the watch armed only under a command with a shutdown path, but that path
|
|
17606
|
+
* is not live for the command's whole duration: `destroy.ts` registers no
|
|
17607
|
+
* SIGINT handler of its own, and `destroy-runner.ts` removes its one in a
|
|
17608
|
+
* `finally` — so between two stacks of a multi-stack destroy the shared
|
|
17609
|
+
* handler is the ONLY listener. Merely latching there SWALLOWS the Ctrl-C:
|
|
17610
|
+
* the process does not exit, `draining` is never set, `result.interrupted`
|
|
17611
|
+
* stays false, and the loop proceeds to delete the NEXT stack after the user
|
|
17612
|
+
* asked to stop — this file's own headline failure, one layer out.
|
|
17613
|
+
*
|
|
17614
|
+
* So when no other listener remains, the handler restores exactly what Node
|
|
17615
|
+
* would have done with no listener at all. That is deliberately not a second
|
|
17616
|
+
* graceful path: inventing one would duplicate `destroy-runner.ts`'s drain
|
|
17617
|
+
* and have to be kept in sync with it, whereas "there is no graceful owner
|
|
17618
|
+
* right now, so terminate" is true by construction and needs no upkeep.
|
|
17619
|
+
*/
|
|
17620
|
+
/**
|
|
17621
|
+
* Thrown by {@link InterruptWatch.onInterrupted}, and the ONE type the whole
|
|
17622
|
+
* codebase uses to mean "a wait stopped because the user asked us to stop".
|
|
17623
|
+
*
|
|
17624
|
+
* It has to be a distinct class rather than a bare `Error` because
|
|
17625
|
+
* `deploy-engine.ts` decides whether to ROLL BACK by asking what the failure
|
|
17626
|
+
* was. Its own `InterruptedError` is module-private, so a provider cannot
|
|
17627
|
+
* produce one; a bare `Error` from a provider therefore read as a genuine
|
|
17628
|
+
* resource failure and triggered an automatic rollback of the whole stack on
|
|
17629
|
+
* Ctrl-C — strictly worse than the unresponsiveness the threading removes.
|
|
17630
|
+
*
|
|
17631
|
+
* The explicit `setPrototypeOf` is not decoration: without it a subclass of
|
|
17632
|
+
* `Error` loses `instanceof` under this repo's compile target, which would make
|
|
17633
|
+
* {@link isInterruptedWaitError} silently answer `false`.
|
|
17634
|
+
*/
|
|
17635
|
+
var InterruptedWaitError = class InterruptedWaitError extends Error {
|
|
17636
|
+
constructor(what) {
|
|
17637
|
+
super(`${what} interrupted by user (SIGINT)`);
|
|
17638
|
+
this.name = "InterruptedWaitError";
|
|
17639
|
+
Object.setPrototypeOf(this, InterruptedWaitError.prototype);
|
|
17640
|
+
}
|
|
17641
|
+
};
|
|
17642
|
+
/**
|
|
17643
|
+
* Whether `error` IS an interrupt, or WRAPS one.
|
|
17644
|
+
*
|
|
17645
|
+
* The wrap is the normal case, not the edge case: every provider catch under
|
|
17646
|
+
* `src/provisioning/providers/**` re-throws AWS failures as a
|
|
17647
|
+
* `ProvisioningError` threading the original as `cause` (issue #2040, enforced
|
|
17648
|
+
* by `vp run audit:provider-error-cause:check`), so by the time the engine sees
|
|
17649
|
+
* an interrupt it is one or more `cause` hops down. A plain `instanceof` check
|
|
17650
|
+
* at the engine would therefore have been a placebo.
|
|
17651
|
+
*
|
|
17652
|
+
* **The walk is bounded by a VISITED SET, not by a depth ceiling**, and the
|
|
17653
|
+
* difference decides correctness rather than style. A ceiling has to be sized
|
|
17654
|
+
* against the deepest real chain, and that chain GROWS: the flat case is 2 (the
|
|
17655
|
+
* provider's own wrap, then the command's), `DagExecutor` adds none — it
|
|
17656
|
+
* collects rather than wraps (`dag-executor.ts:178`) — but `deploy-engine.ts`
|
|
17657
|
+
* adds one `ProvisioningError` PER NESTED-STACK LEVEL (`deploy-engine.ts:2932`;
|
|
17658
|
+
* `NestedStackProvider.create` adds none of its own). A depth-5 cap therefore
|
|
17659
|
+
* missed at four levels of nesting, and missing here is not a degraded answer:
|
|
17660
|
+
* it is a full automatic rollback on Ctrl-C. The visited set gives the
|
|
17661
|
+
* termination the cap was really there for — a cyclic `cause` chain, which
|
|
17662
|
+
* would otherwise spin on the ERROR path where nothing else is watching —
|
|
17663
|
+
* without a ceiling any legitimate nest can cross.
|
|
17664
|
+
*/
|
|
17665
|
+
function isInterruptedWaitError(error) {
|
|
17666
|
+
const seen = /* @__PURE__ */ new Set();
|
|
17667
|
+
let current = error;
|
|
17668
|
+
while (current !== void 0 && current !== null) {
|
|
17669
|
+
if (current instanceof InterruptedWaitError) return true;
|
|
17670
|
+
if (!(current instanceof Error)) return false;
|
|
17671
|
+
if (seen.has(current)) return false;
|
|
17672
|
+
seen.add(current);
|
|
17673
|
+
current = current.cause;
|
|
17674
|
+
}
|
|
17675
|
+
return false;
|
|
17676
|
+
}
|
|
17677
|
+
const liveWatches = /* @__PURE__ */ new Set();
|
|
17678
|
+
let sharedSigintHandler;
|
|
17679
|
+
let sigintLatched = false;
|
|
17680
|
+
/**
|
|
17681
|
+
* Test seam for the "this command owns interrupt handling" gate and for the
|
|
17682
|
+
* force-quit in property 4.
|
|
17683
|
+
*
|
|
17684
|
+
* Production never assigns either, and neither condition may be weakened to
|
|
17685
|
+
* accommodate tests: a command without a shutdown path really must keep Node's
|
|
17686
|
+
* default terminate, and a swallowed Ctrl-C in a multi-stack destroy really is
|
|
17687
|
+
* a blocker. `cdkd drift --revert` and `cdkd destroy` are the live instances.
|
|
17688
|
+
*
|
|
17689
|
+
* `commandOwnsInterrupts` exists because a provider suite never runs a COMMAND,
|
|
17690
|
+
* so every interrupt test would otherwise exercise the UNARMED path while
|
|
17691
|
+
* appearing to test the armed one — the worst of both, since it fails for a
|
|
17692
|
+
* reason unrelated to what the test claims. `forceQuit` exists because the real
|
|
17693
|
+
* one calls `process.exit`, which would take the test runner with it.
|
|
17694
|
+
*/
|
|
17695
|
+
const interruptWatchTestSeam = {};
|
|
17696
|
+
/**
|
|
17697
|
+
* How many command scopes are currently open.
|
|
17698
|
+
*
|
|
17699
|
+
* A COUNTER rather than a boolean, because a boolean is only correct while
|
|
17700
|
+
* scopes never overlap. The CLI runs one command per process so they do not
|
|
17701
|
+
* today — but this module's own contract offers itself to "a host that runs
|
|
17702
|
+
* more than one command", and under a boolean the inner scope's `end` would
|
|
17703
|
+
* remove the shared listener and clear the OUTER command's sticky latch
|
|
17704
|
+
* mid-run, so a signal landing in the re-arm gap goes unrecorded. That is
|
|
17705
|
+
* exactly what property 2 forbids, arrived at from the other direction.
|
|
17706
|
+
*/
|
|
17707
|
+
let commandInterruptScopeDepth = 0;
|
|
17708
|
+
function commandOwnsInterrupts() {
|
|
17709
|
+
const override = interruptWatchTestSeam.commandOwnsInterrupts;
|
|
17710
|
+
if (override !== void 0) return override();
|
|
17711
|
+
return commandInterruptScopeDepth > 0;
|
|
17712
|
+
}
|
|
17713
|
+
/**
|
|
17714
|
+
* Install the ONE process listener, if and only if the running command has
|
|
17715
|
+
* declared that it owns interrupt handling. See property 3 for why the "if" is
|
|
17716
|
+
* load-bearing rather than defensive.
|
|
17717
|
+
*
|
|
17718
|
+
* Called on every `startInterruptWatch` rather than once, so a wait that runs
|
|
17719
|
+
* before the command opens its interrupt scope leaves the door open instead of
|
|
17720
|
+
* latching a permanent "unarmed".
|
|
17721
|
+
*/
|
|
17722
|
+
function armSharedSigintHandler() {
|
|
17723
|
+
if (sharedSigintHandler !== void 0) return;
|
|
17724
|
+
if (!commandOwnsInterrupts()) return;
|
|
17725
|
+
const handler = () => {
|
|
17726
|
+
sigintLatched = true;
|
|
17727
|
+
for (const live of liveWatches) live.interrupted = true;
|
|
17728
|
+
if (process.listeners("SIGINT").filter((l) => l !== handler).length === 0) {
|
|
17729
|
+
process.stderr.write("\nInterrupted.\nIf the next run reports a stack lock, release it with: cdkd force-unlock <stack-name>\n");
|
|
17730
|
+
(interruptWatchTestSeam.forceQuit ?? ((code) => process.exit(code)))(130);
|
|
17731
|
+
}
|
|
17732
|
+
};
|
|
17733
|
+
sharedSigintHandler = handler;
|
|
17734
|
+
process.on("SIGINT", handler);
|
|
17735
|
+
}
|
|
17736
|
+
/**
|
|
17737
|
+
* Start a watch for ONE wait. `what` names the wait in the thrown message.
|
|
17738
|
+
*
|
|
17739
|
+
* The caller MUST `dispose()` in a `finally`. A leaked watch is not merely
|
|
17740
|
+
* untidy: it stays in {@link liveWatches} forever, and the sticky latch means
|
|
17741
|
+
* every wait after a Ctrl-C would keep aborting instantly even if the run
|
|
17742
|
+
* somehow continued.
|
|
17743
|
+
*/
|
|
17744
|
+
function startInterruptWatch(what) {
|
|
17745
|
+
armSharedSigintHandler();
|
|
17746
|
+
const state = { interrupted: sigintLatched };
|
|
17747
|
+
liveWatches.add(state);
|
|
17748
|
+
let disposed = false;
|
|
17749
|
+
return {
|
|
17750
|
+
isInterrupted: () => state.interrupted,
|
|
17751
|
+
onInterrupted: () => new InterruptedWaitError(what),
|
|
17752
|
+
dispose: () => {
|
|
17753
|
+
if (disposed) return;
|
|
17754
|
+
disposed = true;
|
|
17755
|
+
liveWatches.delete(state);
|
|
17756
|
+
}
|
|
17757
|
+
};
|
|
17758
|
+
}
|
|
17759
|
+
/**
|
|
17760
|
+
* Clear the sticky latch.
|
|
17761
|
+
*
|
|
17762
|
+
* Called by {@link beginCommandInterruptScope} and
|
|
17763
|
+
* {@link endCommandInterruptScope}, which bracket one command. On the CLI one
|
|
17764
|
+
* process runs one command, so the latch starts false regardless and those
|
|
17765
|
+
* calls are belt-and-braces; they earn their keep for a host that runs more
|
|
17766
|
+
* than one command, and for unit suites, where every test shares one process
|
|
17767
|
+
* and a simulated Ctrl-C would otherwise leak into every test after it.
|
|
17768
|
+
*
|
|
17769
|
+
* Deliberately NOT wired into `dispose()` — see property 2. That was the first
|
|
17770
|
+
* cut and it is precisely the bug: sequential waits always empty the live set
|
|
17771
|
+
* between them, so the latch cleared in every gap that mattered.
|
|
17772
|
+
*/
|
|
17773
|
+
function resetInterruptWatchLatch() {
|
|
17774
|
+
sigintLatched = false;
|
|
17775
|
+
for (const live of liveWatches) live.interrupted = false;
|
|
17776
|
+
}
|
|
17777
|
+
/**
|
|
17778
|
+
* Declare that this command owns interrupt handling, and clear the latch.
|
|
17779
|
+
*
|
|
17780
|
+
* Called by `forwardSigtermToSigint()` (`src/utils/interrupt-signals.ts`),
|
|
17781
|
+
* which every command that reaches a provider wait through a lock invokes at
|
|
17782
|
+
* start — `deploy`, `destroy`, `rollback`, `state`. A command that does NOT
|
|
17783
|
+
* call it (`cdkd drift`) keeps Node's default terminate, which is the point.
|
|
17784
|
+
*/
|
|
17785
|
+
function beginCommandInterruptScope() {
|
|
17786
|
+
commandInterruptScopeDepth += 1;
|
|
17787
|
+
if (commandInterruptScopeDepth === 1) resetInterruptWatchLatch();
|
|
17788
|
+
}
|
|
17789
|
+
/**
|
|
17790
|
+
* Close the scope — the command is done.
|
|
17791
|
+
*
|
|
17792
|
+
* Removing the shared listener HERE does not weaken property 2: what must never
|
|
17793
|
+
* happen is a teardown between two sequential WAITS, because a signal landing
|
|
17794
|
+
* in that gap would go unrecorded. At command end there is no next wait, and
|
|
17795
|
+
* leaving the listener installed would suppress default terminate for whatever
|
|
17796
|
+
* runs after.
|
|
17797
|
+
*/
|
|
17798
|
+
function endCommandInterruptScope() {
|
|
17799
|
+
commandInterruptScopeDepth = Math.max(0, commandInterruptScopeDepth - 1);
|
|
17800
|
+
if (commandInterruptScopeDepth > 0) return;
|
|
17801
|
+
if (sharedSigintHandler !== void 0) {
|
|
17802
|
+
process.removeListener("SIGINT", sharedSigintHandler);
|
|
17803
|
+
sharedSigintHandler = void 0;
|
|
17804
|
+
}
|
|
17805
|
+
resetInterruptWatchLatch();
|
|
17806
|
+
}
|
|
17807
|
+
|
|
17534
17808
|
//#endregion
|
|
17535
17809
|
//#region src/provisioning/providers/custom-resource-provider.ts
|
|
17536
17810
|
/**
|
|
@@ -17575,6 +17849,47 @@ const CR_NO_SERVICE_TOKEN_SKIP_REASON = "no ServiceToken in state — Delete han
|
|
|
17575
17849
|
*/
|
|
17576
17850
|
const CR_DELETE_INVOKE_FAILED_SKIP_REASON = "Delete request to the handler did not complete — resource unproven";
|
|
17577
17851
|
/**
|
|
17852
|
+
* Fourth sibling of the three above, for the arm where the handler RAN, was
|
|
17853
|
+
* reached, and answered `Status: 'FAILED'` (issue
|
|
17854
|
+
* [#2054](https://github.com/go-to-k/cdkd/issues/2054)).
|
|
17855
|
+
*
|
|
17856
|
+
* The terminal FAILED arm used to warn and fall through to `return undefined`,
|
|
17857
|
+
* which `deleteSkipReason` reads as DELETED — so cdkd dropped the state
|
|
17858
|
+
* record, printed the row as deleted and exited 0 over a resource the handler
|
|
17859
|
+
* had EXPLICITLY said it did not delete. It is the same silent-orphan class
|
|
17860
|
+
* {@link CR_DELETE_INVOKE_FAILED_SKIP_REASON} removed from the throw arm,
|
|
17861
|
+
* reached through the handler's RESPONSE instead.
|
|
17862
|
+
*
|
|
17863
|
+
* **Unconditional, with no already-gone classifier.** A handler that reports
|
|
17864
|
+
* FAILED because the thing it manages was already absent is a real and common
|
|
17865
|
+
* shape, and today's leniency lets those destroys finish green. Classifying
|
|
17866
|
+
* the reason to keep them green was rejected: the reason is free text a user's
|
|
17867
|
+
* handler writes, so any classifier is a guess, and a wrong guess
|
|
17868
|
+
* re-introduces exactly the orphan this arm exists to stop.
|
|
17869
|
+
*
|
|
17870
|
+
* This is therefore a COMPATIBILITY BREAK: a destroy whose delete handler
|
|
17871
|
+
* reports FAILED now exits 2 with the record kept, where it used to exit 0
|
|
17872
|
+
* with the record dropped.
|
|
17873
|
+
*
|
|
17874
|
+
* **The two callers have DIFFERENT escape hatches, and only one of them is a
|
|
17875
|
+
* flag.** On `cdkd deploy` the skip is forced back to exit 0 by
|
|
17876
|
+
* `--allow-unaddressed` (issue #1960, the flag that settled the analogous
|
|
17877
|
+
* exit-code question). `cdkd destroy` has no such flag — a skip raises
|
|
17878
|
+
* `PartialFailureError` unconditionally (`src/cli/commands/destroy.ts`) — so
|
|
17879
|
+
* there the remedy is the one that command's own summary names: confirm the
|
|
17880
|
+
* resource is gone, then drop the record with `cdkd state orphan <stack>`.
|
|
17881
|
+
* Messages must not offer the flag on the destroy path, which is the path this
|
|
17882
|
+
* arm is mostly reached from.
|
|
17883
|
+
*
|
|
17884
|
+
* **Fixed wording, no interpolation**, for the reason spelled out on
|
|
17885
|
+
* {@link CR_DELETE_INVOKE_FAILED_SKIP_REASON}: the handler's own `Reason` is a
|
|
17886
|
+
* user-authored string, it goes out on the `logger.warn` beside this, and a
|
|
17887
|
+
* `Reason` carrying `does not exist` / `not found` would make the deploy-side
|
|
17888
|
+
* replacement sites classify the skip as "already gone" and drop the record
|
|
17889
|
+
* one layer further out.
|
|
17890
|
+
*/
|
|
17891
|
+
const CR_DELETE_HANDLER_FAILED_SKIP_REASON = "Delete handler reported FAILED — resource unproven";
|
|
17892
|
+
/**
|
|
17578
17893
|
* The deploy-side caveat both skip warnings in this file carry (issue
|
|
17579
17894
|
* [#1762](https://github.com/go-to-k/cdkd/issues/1762)).
|
|
17580
17895
|
*
|
|
@@ -17585,6 +17900,29 @@ const CR_DELETE_INVOKE_FAILED_SKIP_REASON = "Delete request to the handler did n
|
|
|
17585
17900
|
* torn down by hand. Mirrors the caveat `compositeIdFormatMessage` already
|
|
17586
17901
|
* carries for the composite-id family.
|
|
17587
17902
|
*/
|
|
17903
|
+
/**
|
|
17904
|
+
* The bound BOTH delete-path skips in this file have to state (found in review
|
|
17905
|
+
* of issue [#2054](https://github.com/go-to-k/cdkd/issues/2054)).
|
|
17906
|
+
*
|
|
17907
|
+
* A skip KEEPS the state record, and the natural thing to promise is that a
|
|
17908
|
+
* re-run retries the handler. **On `cdkd destroy` that promise is false**, and
|
|
17909
|
+
* it is false in the direction that matters. `destroy-runner.ts` walks every
|
|
17910
|
+
* reverse-DAG level regardless of skips, so the SAME run that skipped the
|
|
17911
|
+
* custom resource goes on to delete its backing Lambda. The next
|
|
17912
|
+
* `cdkd destroy` therefore reaches the issue-#804 pre-check above, finds the
|
|
17913
|
+
* function gone, and treats the resource as already deleted — dropping the
|
|
17914
|
+
* record and exiting 0 over a resource the handler explicitly refused to
|
|
17915
|
+
* remove, which is the very silent orphan #2054 removed one run earlier.
|
|
17916
|
+
*
|
|
17917
|
+
* Closing it properly means making that pre-check answer `'skipped'` when the
|
|
17918
|
+
* teardown was never PROVEN, which needs a durable "a prior run skipped this"
|
|
17919
|
+
* signal. Every candidate is outside this file: a `ResourceState` field (a
|
|
17920
|
+
* state-schema bump), or a `DeleteContext` flag threaded from
|
|
17921
|
+
* `destroy-runner.ts`. So the record is described here as what it actually is
|
|
17922
|
+
* — a POINTER to something that has to be torn down by hand — rather than as a
|
|
17923
|
+
* retry that will not happen.
|
|
17924
|
+
*/
|
|
17925
|
+
const CR_SKIP_NOT_A_RETRY_CAVEAT = "NOTE this record is a POINTER, not a retry: the same destroy run deletes the backing Lambda, so the next 'cdkd destroy' finds the handler gone and DROPS this record (issue 804 pre-check). Tear the resource down by hand, then clear the stack's records with 'cdkd state orphan <stack>' — that command drops EVERY record for the stack, not just this one.";
|
|
17588
17926
|
const DEPLOY_SKIP_CAVEAT = "NOTE this arm is ALSO reached from cdkd deploy. Since issue 1762 the DELETE of a resource removed from the template behaves like destroy — the record is KEPT and the next deploy re-attempts it — but a REPLACEMENT / rollback delete FAILS the resource instead (https://github.com/go-to-k/cdkd/issues/1762), leaving the old one untracked; there, tear the resource down by hand.";
|
|
17589
17927
|
/**
|
|
17590
17928
|
* Type guard to validate Lambda response payload structure
|
|
@@ -17898,25 +18236,50 @@ const CR_LOG_TAIL_BOILERPLATE = /^(START|END|REPORT|XRAY|INIT_START|INIT_REPORT|
|
|
|
17898
18236
|
*/
|
|
17899
18237
|
const SNS_SERVICE_TOKEN_ARN_RE = /^arn:aws[a-z0-9-]*:sns:/;
|
|
17900
18238
|
/**
|
|
18239
|
+
* Account segment {@link syntheticStackId} falls back to when STS could not
|
|
18240
|
+
* answer (`AwsAccountInfo.fabricated`, issue
|
|
18241
|
+
* [#1730](https://github.com/go-to-k/cdkd/issues/1730)).
|
|
18242
|
+
*
|
|
18243
|
+
* The Cloud Control enrichment sites answer a fabricated account by OMITTING
|
|
18244
|
+
* the value they would have built. That is not available here — `StackId` is a
|
|
18245
|
+
* REQUIRED member of the custom-resource request payload — so the choice is
|
|
18246
|
+
* between two wrong strings, and the honest one is the one a handler cannot
|
|
18247
|
+
* mistake for real. `getAccountInfo`'s own fallback id (`123456789012`) is
|
|
18248
|
+
* shaped exactly like a live account; the all-zero id is not a valid AWS
|
|
18249
|
+
* account and reads as the placeholder it is.
|
|
18250
|
+
*/
|
|
18251
|
+
const SYNTHETIC_STACK_ID_PLACEHOLDER_ACCOUNT = "000000000000";
|
|
18252
|
+
/**
|
|
17901
18253
|
* The synthetic `StackId` handed to a custom-resource handler in place of the
|
|
17902
18254
|
* CloudFormation stack ARN cdkd does not have.
|
|
17903
18255
|
*
|
|
17904
|
-
*
|
|
17905
|
-
*
|
|
17906
|
-
*
|
|
17907
|
-
*
|
|
17908
|
-
*
|
|
17909
|
-
*
|
|
17910
|
-
*
|
|
17911
|
-
*
|
|
17912
|
-
*
|
|
17913
|
-
*
|
|
18256
|
+
* Partition / region / account are synthesized TOGETHER from the real deploy
|
|
18257
|
+
* context (issue [#1866](https://github.com/go-to-k/cdkd/issues/1866)). Every
|
|
18258
|
+
* segment used to be fabricated — `arn:aws:cloudformation:us-east-1:0000...`
|
|
18259
|
+
* regardless of where the deploy actually ran — and CloudFormation-authored
|
|
18260
|
+
* handlers DO read `event.StackId`: to re-derive the region / account they are
|
|
18261
|
+
* running in, to build ARNs, to name log streams, to correlate a response.
|
|
18262
|
+
* Each of those read a coherent-looking ARN and got an answer that addresses
|
|
18263
|
+
* nothing.
|
|
18264
|
+
*
|
|
18265
|
+
* Deriving only ONE segment is worse than deriving none, which is why issue
|
|
18266
|
+
* #1815 deliberately left the hardcoded `arn:aws:` prefix alone rather than
|
|
18267
|
+
* partition-deriving it in isolation: `arn:aws-cn:cloudformation:us-east-1:…`
|
|
18268
|
+
* is a China partition carrying a commercial region, strictly LESS coherent
|
|
18269
|
+
* than a uniformly-commercial fabrication. So this takes the whole
|
|
18270
|
+
* {@link AwsAccountInfo} — where `partition` is already derived FROM `region`
|
|
18271
|
+
* — rather than any one field.
|
|
18272
|
+
*
|
|
18273
|
+
* The stack-NAME segment stays synthetic (`cdkd-<logicalId>`): cdkd has no
|
|
18274
|
+
* CloudFormation stack, so there is no real value to put there.
|
|
17914
18275
|
*
|
|
17915
18276
|
* Factored into one place so the rationale cannot go stale against two other
|
|
17916
|
-
* copies: the create / update / delete request builders all use it
|
|
18277
|
+
* copies: the create / update / delete request builders all use it, through
|
|
18278
|
+
* {@link CustomResourceProvider.resolveSyntheticStackId}.
|
|
17917
18279
|
*/
|
|
17918
|
-
function syntheticStackId(logicalId) {
|
|
17919
|
-
|
|
18280
|
+
function syntheticStackId(logicalId, accountInfo) {
|
|
18281
|
+
const account = accountInfo.fabricated ? SYNTHETIC_STACK_ID_PLACEHOLDER_ACCOUNT : accountInfo.accountId;
|
|
18282
|
+
return `arn:${accountInfo.partition}:cloudformation:${accountInfo.region}:${account}:stack/cdkd-${logicalId}/cdkd`;
|
|
17920
18283
|
}
|
|
17921
18284
|
/**
|
|
17922
18285
|
* `true` when the tail contains at least one line the HANDLER produced.
|
|
@@ -18109,11 +18472,29 @@ var CustomResourceProvider = class CustomResourceProvider {
|
|
|
18109
18472
|
* the placeholder `PutObject`'s `withRetry` takes no knob either.
|
|
18110
18473
|
*/
|
|
18111
18474
|
preDeliveryAuthzMaxRetries = 26;
|
|
18475
|
+
/**
|
|
18476
|
+
* The region the client bag this provider was built from was EXPLICITLY
|
|
18477
|
+
* configured with, or `undefined` (issue #1866).
|
|
18478
|
+
*
|
|
18479
|
+
* Captured in the constructor, beside the clients, rather than read per call:
|
|
18480
|
+
* `cdkd deploy` builds a region-configured `AwsClients` and a fresh
|
|
18481
|
+
* `ProviderRegistry` per stack, and with `--stack-concurrency` (default 4) it
|
|
18482
|
+
* swaps the process-global bag while other stacks are mid-flight — so a
|
|
18483
|
+
* call-time read can hand a SIBLING stack's region. Pairing it with the
|
|
18484
|
+
* clients keeps the two consistent by construction.
|
|
18485
|
+
*
|
|
18486
|
+
* `AwsClients.configuredRegion` is deliberately the only region a client bag
|
|
18487
|
+
* will answer (see its own note on why `client.config.region()` is unsound),
|
|
18488
|
+
* and `undefined` means no region was pinned anywhere — which
|
|
18489
|
+
* {@link getAccountInfo} then resolves from `AWS_REGION` itself.
|
|
18490
|
+
*/
|
|
18491
|
+
configuredRegion;
|
|
18112
18492
|
constructor(config) {
|
|
18113
18493
|
const awsClients = getAwsClients();
|
|
18114
18494
|
this.lambdaClient = awsClients.lambda;
|
|
18115
18495
|
this.snsClient = awsClients.sns;
|
|
18116
18496
|
this.s3Client = awsClients.s3;
|
|
18497
|
+
this.configuredRegion = awsClients.configuredRegion;
|
|
18117
18498
|
this.responseBucket = config?.responseBucket;
|
|
18118
18499
|
this.responsePrefix = config?.responsePrefix ?? "custom-resource-responses";
|
|
18119
18500
|
this.asyncResponseTimeoutMs = config?.asyncResponseTimeoutMs ?? CustomResourceProvider.DEFAULT_ASYNC_RESPONSE_TIMEOUT_MS;
|
|
@@ -18211,6 +18592,22 @@ var CustomResourceProvider = class CustomResourceProvider {
|
|
|
18211
18592
|
return this.responseClientResolveInFlight;
|
|
18212
18593
|
}
|
|
18213
18594
|
/**
|
|
18595
|
+
* Resolve {@link syntheticStackId} against this deploy's REAL account /
|
|
18596
|
+
* region / partition (issue #1866).
|
|
18597
|
+
*
|
|
18598
|
+
* `getAccountInfo` never throws — it answers a `fabricated` account when STS
|
|
18599
|
+
* cannot, which {@link SYNTHETIC_STACK_ID_PLACEHOLDER_ACCOUNT} handles — so
|
|
18600
|
+
* this cannot turn a working deploy into a failing one on the credential
|
|
18601
|
+
* path. It is resolved ONCE per `create` / `update` / `delete` rather than
|
|
18602
|
+
* per invocation attempt: the value does not vary between attempts, and the
|
|
18603
|
+
* request builder the retry loop re-runs is synchronous.
|
|
18604
|
+
*/
|
|
18605
|
+
async resolveSyntheticStackId(logicalId) {
|
|
18606
|
+
const accountInfo = await getAccountInfo(this.configuredRegion);
|
|
18607
|
+
if (accountInfo.fabricated) this.logger.warn(`Custom resource ${logicalId}: STS did not report this deploy's account id, so the synthetic StackId handed to the handler carries the placeholder account ${SYNTHETIC_STACK_ID_PLACEHOLDER_ACCOUNT}. A handler that parses StackId to re-derive the account it is running in will not get a usable one — fix the credentials (or set AWS_ACCOUNT_ID) and re-run.`);
|
|
18608
|
+
return syntheticStackId(logicalId, accountInfo);
|
|
18609
|
+
}
|
|
18610
|
+
/**
|
|
18214
18611
|
* Create a custom resource by invoking its Lambda handler
|
|
18215
18612
|
*/
|
|
18216
18613
|
async create(logicalId, resourceType, properties) {
|
|
@@ -18225,7 +18622,7 @@ var CustomResourceProvider = class CustomResourceProvider {
|
|
|
18225
18622
|
ResponseURL: invocation.responseURL,
|
|
18226
18623
|
ResourceType: resourceType,
|
|
18227
18624
|
LogicalResourceId: logicalId,
|
|
18228
|
-
StackId:
|
|
18625
|
+
StackId: invocation.stackId,
|
|
18229
18626
|
ResourceProperties: this.stringifyProperties(properties)
|
|
18230
18627
|
}));
|
|
18231
18628
|
if (cfnResponse.Status === "FAILED") throw new Error(`Custom resource handler returned FAILED: ${cfnResponse.Reason || "Unknown reason"}`);
|
|
@@ -18257,7 +18654,7 @@ var CustomResourceProvider = class CustomResourceProvider {
|
|
|
18257
18654
|
ResourceType: resourceType,
|
|
18258
18655
|
LogicalResourceId: logicalId,
|
|
18259
18656
|
PhysicalResourceId: physicalId,
|
|
18260
|
-
StackId:
|
|
18657
|
+
StackId: invocation.stackId,
|
|
18261
18658
|
ResourceProperties: this.stringifyProperties(properties),
|
|
18262
18659
|
OldResourceProperties: this.stringifyProperties(previousProperties)
|
|
18263
18660
|
}));
|
|
@@ -18298,7 +18695,7 @@ var CustomResourceProvider = class CustomResourceProvider {
|
|
|
18298
18695
|
}
|
|
18299
18696
|
if (typeof serviceToken !== "string") throw new ProvisioningError(`Custom Resource ${logicalId}: ServiceToken is not a resolved string ARN (got ${typeof serviceToken}). This usually indicates state was written by a pre-fix cdkd import; re-run \`cdkd import\` or \`cdkd state orphan <stack>\` to recover.`, resourceType, logicalId, physicalId);
|
|
18300
18697
|
if (!this.isSnsServiceToken(serviceToken) && await this.isBackingLambdaGone(serviceToken)) {
|
|
18301
|
-
this.logger.warn(`Backing Lambda for custom resource ${logicalId} no longer exists (${serviceToken}); treating the custom resource as already deleted
|
|
18698
|
+
this.logger.warn(`Backing Lambda for custom resource ${logicalId} no longer exists (${serviceToken}); treating the custom resource as already deleted and DROPPING its state record. The handler can never run again, so if its teardown was never PROVEN — e.g. an earlier run reported this resource as skipped (issue 2054) — whatever it manages is still LIVE and is now untracked by cdkd. Check for leftovers before treating the stack as gone.`);
|
|
18302
18699
|
return;
|
|
18303
18700
|
}
|
|
18304
18701
|
try {
|
|
@@ -18309,13 +18706,19 @@ var CustomResourceProvider = class CustomResourceProvider {
|
|
|
18309
18706
|
ResourceType: resourceType,
|
|
18310
18707
|
LogicalResourceId: logicalId,
|
|
18311
18708
|
PhysicalResourceId: physicalId,
|
|
18312
|
-
StackId:
|
|
18709
|
+
StackId: invocation.stackId,
|
|
18313
18710
|
ResourceProperties: this.stringifyProperties(properties)
|
|
18314
18711
|
}));
|
|
18315
|
-
if (cfnResponse.Status === "FAILED")
|
|
18316
|
-
|
|
18712
|
+
if (cfnResponse.Status === "FAILED") {
|
|
18713
|
+
this.logger.warn(`Custom resource delete handler returned FAILED for ${logicalId}: ${cfnResponse.Reason || "Unknown reason"}. The handler reported that it did NOT delete, so anything this custom resource manages is LEFT IN PLACE — cdkd is KEEPING the state record and the run exits non-zero. ${CR_SKIP_NOT_A_RETRY_CAVEAT} ('cdkd deploy' also accepts --allow-unaddressed, which forces exit 0; 'cdkd destroy' has no such flag.) ${DEPLOY_SKIP_CAVEAT}`);
|
|
18714
|
+
return {
|
|
18715
|
+
outcome: "skipped",
|
|
18716
|
+
reason: CR_DELETE_HANDLER_FAILED_SKIP_REASON
|
|
18717
|
+
};
|
|
18718
|
+
}
|
|
18719
|
+
this.logger.debug(`Successfully deleted custom resource ${logicalId}`);
|
|
18317
18720
|
} catch (error) {
|
|
18318
|
-
this.logger.warn(`Failed to delete custom resource ${logicalId}, but continuing: ${error instanceof Error ? error.message : String(error)}. The Delete handler did not complete, so anything this custom resource manages may still be LIVE — cdkd is KEEPING the state record
|
|
18721
|
+
this.logger.warn(`Failed to delete custom resource ${logicalId}, but continuing: ${error instanceof Error ? error.message : String(error)}. The Delete handler did not complete, so anything this custom resource manages may still be LIVE — cdkd is KEEPING the state record and the run exits non-zero. ${CR_SKIP_NOT_A_RETRY_CAVEAT} ${DEPLOY_SKIP_CAVEAT}`);
|
|
18319
18722
|
return {
|
|
18320
18723
|
outcome: "skipped",
|
|
18321
18724
|
reason: CR_DELETE_INVOKE_FAILED_SKIP_REASON
|
|
@@ -18391,13 +18794,22 @@ var CustomResourceProvider = class CustomResourceProvider {
|
|
|
18391
18794
|
* PRE-delivery throw is safe to replay at all.
|
|
18392
18795
|
*
|
|
18393
18796
|
* `buildRequest` is called once per attempt with the fresh invocation so the
|
|
18394
|
-
* CFn request body always carries the matching ResponseURL / RequestId.
|
|
18797
|
+
* CFn request body always carries the matching ResponseURL / RequestId. The
|
|
18798
|
+
* synthetic `StackId` rides the same bag although it is stable across
|
|
18799
|
+
* attempts (issue #1866), for an ORDERING reason rather than a freshness one:
|
|
18800
|
+
* resolving it needs an `await`, and every await before the SIGINT watch
|
|
18801
|
+
* below is installed is a window in which Ctrl-C is dead — `docs/
|
|
18802
|
+
* provider-development.md` requires a new wait site to be interruptible, and
|
|
18803
|
+
* the pre-delivery backoff this method owns is 47.75s long.
|
|
18804
|
+
*
|
|
18395
18805
|
* Returns the final response; the caller decides what a terminal FAILED means
|
|
18396
|
-
* (create/update throw
|
|
18806
|
+
* (create / update throw; delete warns and returns `'skipped'` — issue
|
|
18807
|
+
* #2054, which replaced its warn-and-continue).
|
|
18397
18808
|
*/
|
|
18398
18809
|
async invokeCustomResourceWithRetry(serviceToken, logicalId, operation, buildRequest) {
|
|
18399
|
-
const watch =
|
|
18810
|
+
const watch = startInterruptWatch(`Custom resource ${logicalId}`);
|
|
18400
18811
|
try {
|
|
18812
|
+
const stackId = await this.resolveSyntheticStackId(logicalId);
|
|
18401
18813
|
let preDeliveryRetries = 0;
|
|
18402
18814
|
let failedResponseRetries = 0;
|
|
18403
18815
|
for (let attempt = 0;; attempt++) {
|
|
@@ -18407,7 +18819,10 @@ var CustomResourceProvider = class CustomResourceProvider {
|
|
|
18407
18819
|
let invocation;
|
|
18408
18820
|
try {
|
|
18409
18821
|
invocation = await this.prepareInvocation(logicalId, watch);
|
|
18410
|
-
const request = buildRequest(
|
|
18822
|
+
const request = buildRequest({
|
|
18823
|
+
...invocation,
|
|
18824
|
+
stackId
|
|
18825
|
+
});
|
|
18411
18826
|
this.logger.debug(`Sending custom resource ${operation.toLowerCase()} request: ${serviceToken}`);
|
|
18412
18827
|
const sent = await this.sendRequest(serviceToken, request, invocation.responseKey, logicalId, operation, () => {
|
|
18413
18828
|
delivered = true;
|
|
@@ -18943,33 +19358,6 @@ var CustomResourceProvider = class CustomResourceProvider {
|
|
|
18943
19358
|
return customResourceRetryDelays.sleep(ms);
|
|
18944
19359
|
}
|
|
18945
19360
|
/**
|
|
18946
|
-
* Install a SIGINT watch for one custom-resource invocation (issue #2033).
|
|
18947
|
-
*
|
|
18948
|
-
* `docs/provider-development.md` requires a new `withRetry` to thread
|
|
18949
|
-
* `isInterrupted` / `onInterrupted`, and a hand-rolled backoff to be
|
|
18950
|
-
* interruptible for the same reason: without it Ctrl-C is dead for the whole
|
|
18951
|
-
* 47.75s schedule. The provider already had the shape — `pollS3Response`
|
|
18952
|
-
* installs its own handler — so this is that pattern, lifted so the two new
|
|
18953
|
-
* wait sites share one flag and one disposal.
|
|
18954
|
-
*
|
|
18955
|
-
* The caller MUST `dispose()` in a `finally`; a leaked listener would
|
|
18956
|
-
* accumulate one per resource across a deploy.
|
|
18957
|
-
*/
|
|
18958
|
-
startInterruptWatch(logicalId) {
|
|
18959
|
-
let interrupted = false;
|
|
18960
|
-
const handler = () => {
|
|
18961
|
-
interrupted = true;
|
|
18962
|
-
};
|
|
18963
|
-
process.on("SIGINT", handler);
|
|
18964
|
-
return {
|
|
18965
|
-
isInterrupted: () => interrupted,
|
|
18966
|
-
onInterrupted: () => /* @__PURE__ */ new Error(`Custom resource ${logicalId} interrupted by user`),
|
|
18967
|
-
dispose: () => {
|
|
18968
|
-
process.removeListener("SIGINT", handler);
|
|
18969
|
-
}
|
|
18970
|
-
};
|
|
18971
|
-
}
|
|
18972
|
-
/**
|
|
18973
19361
|
* `sleep` that checks the interrupt watch at most a second apart, mirroring
|
|
18974
19362
|
* `withRetry`'s own once-per-second probe. Throws the watch's error when the
|
|
18975
19363
|
* user has hit Ctrl-C, so the retry loop unwinds instead of sitting out the
|
|
@@ -25385,7 +25773,7 @@ const FLUSH_INTERVAL_MS = 2e3;
|
|
|
25385
25773
|
const FLUSH_EVENT_THRESHOLD = 50;
|
|
25386
25774
|
/** Build-time cdkd version, with a dev fallback for non-built contexts. */
|
|
25387
25775
|
function getCdkdVersion() {
|
|
25388
|
-
return "0.284.
|
|
25776
|
+
return "0.284.25";
|
|
25389
25777
|
}
|
|
25390
25778
|
/**
|
|
25391
25779
|
* Generate a time-sortable unique run id, e.g.
|
|
@@ -26829,7 +27217,7 @@ var DeployEngine = class {
|
|
|
26829
27217
|
this.logger.warn(`Failed to save partial state before rollback: ${saveError instanceof Error ? saveError.message : String(saveError)}`);
|
|
26830
27218
|
}
|
|
26831
27219
|
let autoRollbackClean = false;
|
|
26832
|
-
if (error instanceof InterruptedError) {
|
|
27220
|
+
if (error instanceof InterruptedError || isInterruptedWaitError(error)) {
|
|
26833
27221
|
await this.writeRollbackJournalSegment(stackName, completedOperations, failedOperations, "interrupted", initialDeploy);
|
|
26834
27222
|
this.logger.info(`Partial state saved (${Object.keys(newResources).length} resources). Run deploy again to resume, 'cdkd rollback' to revert, or destroy to clean up.`);
|
|
26835
27223
|
throw error;
|
|
@@ -27599,7 +27987,7 @@ var DeployEngine = class {
|
|
|
27599
27987
|
}), logicalId, 3, 5e3, deleteProvider);
|
|
27600
27988
|
} catch (deleteError) {
|
|
27601
27989
|
const msg = deleteError instanceof Error ? deleteError.message : String(deleteError);
|
|
27602
|
-
if (msg.includes("does not exist") || msg.includes("was not found") || msg.includes("not found") || msg.includes("No policy found") || msg.includes("NoSuchEntity") || msg.includes("NotFoundException") || msg.includes("ResourceNotFoundException")) this.logger.debug(`Resource ${logicalId} already deleted (${msg}), removing from state`);
|
|
27990
|
+
if (!isInterruptedWaitError(deleteError) && (msg.includes("does not exist") || msg.includes("was not found") || msg.includes("not found") || msg.includes("No policy found") || msg.includes("NoSuchEntity") || msg.includes("NotFoundException") || msg.includes("ResourceNotFoundException"))) this.logger.debug(`Resource ${logicalId} already deleted (${msg}), removing from state`);
|
|
27603
27991
|
else throw deleteError;
|
|
27604
27992
|
}
|
|
27605
27993
|
const deleteSkipped = deleteSkipReason(deleteResult);
|
|
@@ -28005,5 +28393,5 @@ var DeployEngine = class {
|
|
|
28005
28393
|
};
|
|
28006
28394
|
|
|
28007
28395
|
//#endregion
|
|
28008
|
-
export {
|
|
28009
|
-
//# sourceMappingURL=deploy-engine-
|
|
28396
|
+
export { isInterruptedWaitError as $, LocalMigrateError as $n, escapeRegExp$1 as $t, isStatefulRecreateTargetSync as A, CFN_TEMPLATE_BODY_LIMIT as An, s3BucketArn as At, collectPublishedOutputNames as B, processStackMessages as Bn, DagBuilder as Bt, createPreDeleteFinalSnapshot as C, resolveCaptureObservedState as Cn, TEMPLATE_SOURCED_RULES as Ct, makeCanonicalizePropertiesFn as D, resolveUseCdkBootstrapAssets as Dn, maskSecretsInText as Dt, unsupportedFinalSnapshotError as E, resolveStateBucketWithDefaultAndSource as En, isSingleDynamicReferenceToken as Et, gray as F, expectedOwnerParam as Fn, applyRoleArnIfSet as Ft, IAMRoleProvider as G, resetAwsClients as Gn, shouldRetainResource as Gt, isExportAliasCollision as H, resolveBucketRegion as Hn, LockManager as Ht, green as I, PARTITION_TABLE as In, DiffCalculator as It, ProviderRegistry as J, CdkdError as Jn, WorkGraph as Jt, collectInlinePolicyNamesManagedBySiblings as K, setAwsClients as Kn, AssetPublisher as Kt, red as L, canonicalizeRegion as Ln, INTRINSIC_KEYS as Lt, formatResourceLine as M, MIGRATE_TMP_PREFIX as Mn, s3BucketDualStackDomainName as Mt, bold as N, findLargeInlineResources as Nn, s3BucketRegionalDomainName as Nt, extractDeploymentEventError as O, stateBucketExistenceConfirmed as On, redactSecretsForState as Ot, cyan as P, uploadCfnTemplate as Pn, s3BucketWebsiteUrl as Pt, endCommandInterruptScope as Q, LocalInvokeBuildError as Qn, rewriteTemplateAssetReferences as Qt, yellow as R, derivePartitionAndUrlSuffix as Rn, describeTypeWithThrottleRetry as Rt, ccRoutedFinalSnapshotError as S, resolveAutoAssetStorage as Sn, STATE_SOURCED_READBACK_RULES as St, refusesFinalSnapshot as T, resolveStateBucketWithDefault as Tn, dynamicReferenceTokens as Tt, secretBearingStateKeyWarning as U, AwsClients as Un, S3StateBackend as Ut, exportAliasCollisionScrubWarning as V, clearBucketRegionCache as Vn, TemplateParser as Vt, stateKeySecretExposure as W, getAwsClients as Wn, rebuildClientForBucketRegion as Wt, findSilentDropProperties as X, DependencyError as Xn, createAssetRedirectResolver as Xt, findActionableSilentDrops as Y, ConfigError as Yn, buildAssetRedirectMap as Yt, beginCommandInterruptScope as Z, DeployCancelledError as Zn, loadPublishableAssetManifest as Zt, IMPLICIT_DELETE_DEPENDENCIES as _, Synthesizer as _n, isRetryableTransientError as _r, replayWarn as _t, DeploymentEventsStore as a, parseBootstrapMarker as an, ProvisioningError as ar, IntrinsicFunctionResolver as at, PRE_DELETE_SNAPSHOT_TYPES as b, getLegacyStateBucketName as bn, __exportAll as br, requireConfigString as bt, producerRegionsFromState as c, validateContainerRepoName as cn, StackHasActiveImportsError as cr, refStateLookupFromResource as ct, updatePartialMessage as d, formatDockerLoginError as dn, SynthesisError as dr, resolveExplicitPhysicalId as dt, stripControlChars as en, LocalStartServiceError as er, startInterruptWatch as et, updatePartialReason as f, getDockerCmd as fn, formatError as fr, assertRegionMatch as ft, maskingRetryLogger as g, getDockerImageBySourceHash as gn, isMarkedNonRetryable as gr, readConfigString as gt, withResourceDeadline as h, AssetManifestLoader as hn, withErrorHandling as hr, configStringRefusal as ht, DeploymentEventsReader as i, getBootstrapMarkerKey as in, PartialFailureError as ir, isTerminationProtectionPropagationError as it, renderStatefulReason as j, CFN_TEMPLATE_URL_LIMIT as jn, s3BucketDomainName as jt, MULTI_REGION_RECREATE_BLOCKED_TYPES as k, warnDeprecatedNoPrefixCliFlag as kn, scrubResourceRecord as kt, replayFailedOperations as l, buildDenyExternalAccessPolicy as ln, StackTerminationProtectionError as lr, WAFv2WebACLProvider as lt, deleteSkipReason as m, runDockerStreaming as mn, normalizeAwsError as mr, configBooleanRefusal as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, BOOTSTRAP_MARKER_PREFIX as nn, MissingCdkCliError as nr, slowCcOperationTimeoutMs as nt, planFailedOps as o, readBootstrapMarkerBody as on, ResourceTimeoutError as or, cfnRefValueFromPhysicalId as ot, UNSPECIFIED_SKIP_REASON as p, runDockerForeground as pn, isCdkdError as pr, coerceCfnBoolean as pt, clearOnUpdateRemoval as q, AssetError as qn, stringifyValue as qt, DeployEngine as r, ensureAssetStorage as rn, NestedStackChildDirectDestroyError as rr, disableInstanceApiTermination as rt, planRollback as s, validateAssetBucketName as sn, ResourceUpdateNotSupportedError as sr, getAccountInfo as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, AssetModeResolver as tn, LockError as tr, CloudControlProvider as tt, replayRollback as u, buildDockerImage as un, StateError as ur, normalizeAwsTagsToCfn as ut, computeImplicitDeleteEdges as v, synthesisStatusMessage as vn, isThrottlingError as vr, requireConfigArray as vt, isFinalSnapshotError as w, resolveSkipPrefix as wn, createSecretMasker as wt, buildFinalSnapshotIdentifier as x, resolveApp as xn, STATE_SOURCED_CROSS_GENERATION_RULES as xt, ATOMIC_FINAL_SNAPSHOT_TYPES as y, getDefaultStateBucketName as yn, markNonRetryable as yr, requireConfigObject as yt, collectDeclaredOutputNames as z, AssemblyReader as zn, withRetry as zt };
|
|
28397
|
+
//# sourceMappingURL=deploy-engine-BpZWPiaL.js.map
|