@go-to-k/cdkd 0.281.21 → 0.281.23
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/README.md +7 -1
- package/dist/{asg-provider-CH0YfbOn.js → asg-provider-CCSQkGwO.js} +2 -2
- package/dist/{asg-provider-CH0YfbOn.js.map → asg-provider-CCSQkGwO.js.map} +1 -1
- package/dist/cli.js +203 -69
- package/dist/cli.js.map +1 -1
- package/dist/{deploy-engine-Cx48pqGQ.js → deploy-engine-uxo_FCje.js} +62 -52
- package/dist/deploy-engine-uxo_FCje.js.map +1 -0
- package/dist/index.d.ts +11 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/deploy-engine-Cx48pqGQ.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { $ as configStringRefusal, $t as
|
|
2
|
+
import { $ as configStringRefusal, $t as MIGRATE_TMP_PREFIX, A as green, At as validateContainerRepoName, B as slowCcOperationTimeoutMs, Bt as getDefaultStateBucketName, C as MULTI_REGION_RECREATE_BLOCKED_TYPES, Cn as PartialFailureError, Ct as rewriteTemplateAssetReferences, D as bold, Dn as StackHasActiveImportsError, Dt as getBootstrapMarkerKey, E as formatResourceLine, En as ResourceUpdateNotSupportedError, Et as ensureAssetStorage, F as clearOnUpdateRemoval, Ft as runDockerStreaming, G as getAccountInfo, Gt as resolveSkipPrefix, H as isTerminationProtectionPropagationError, Ht as resolveApp, I as ProviderRegistry, It as AssetManifestLoader, J as normalizeAwsTagsToCfn, Jt as resolveUseCdkBootstrapAssets, K as refStateLookupFromResource, Kt as resolveStateBucketWithDefault, L as findActionableSilentDrops, Lt as getDockerImageBySourceHash, M as yellow, Mt as formatDockerLoginError, N as IAMRoleProvider, Nn as normalizeAwsError, Nt as getDockerCmd, O as cyan, On as StackTerminationProtectionError, Ot as parseBootstrapMarker, P as collectInlinePolicyNamesManagedBySiblings, Pn as withErrorHandling, Pt as runDockerForeground, Q as configBooleanRefusal, Qt as CFN_TEMPLATE_URL_LIMIT, R as findSilentDropProperties, Rt as Synthesizer, S as extractDeploymentEventError, Sn as NestedStackChildDirectDestroyError, St as loadPublishableAssetManifest, T as renderStatefulReason, Tn as ResourceTimeoutError, Tt as BOOTSTRAP_MARKER_PREFIX, U as IntrinsicFunctionResolver, Ut as resolveAutoAssetStorage, V as disableInstanceApiTermination, Vt as getLegacyStateBucketName, W as cfnRefValueFromPhysicalId, Wt as resolveCaptureObservedState, X as assertRegionMatch, Xt as warnDeprecatedNoPrefixCliFlag, Y as resolveExplicitPhysicalId, Yt as stateBucketExistenceConfirmed, Z as coerceCfnBoolean, Zt as CFN_TEMPLATE_BODY_LIMIT, _ as createPreDeleteFinalSnapshot, _n as LocalInvokeBuildError$1, _t as AssetPublisher, a as DeploymentEventsStore, an as processStackMessages, at as applyRoleArnIfSet, b as unsupportedFinalSnapshotError, bt as buildAssetRedirectMap, c as replayFailedOperations, cn as AwsClients, ct as withRetry, d as IMPLICIT_DELETE_DEPENDENCIES, dn as setAwsClients, dt as DagBuilder, en as findLargeInlineResources, et as readConfigString, f as computeImplicitDeleteEdges, ft as TemplateParser, g as ccRoutedFinalSnapshotError, gn as DeployCancelledError, gt as shouldRetainResource, h as buildFinalSnapshotIdentifier, ht as rebuildClientForBucketRegion, i as DeploymentEventsReader, in as AssemblyReader, it as requireConfigString, j as red, jt as buildDockerImage, k as gray, kt as validateAssetBucketName, l as replayRollback, ln as getAwsClients, lt as isRetryableTransientError, m as PRE_DELETE_SNAPSHOT_TYPES, mt as S3StateBackend, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as expectedOwnerParam, nt as requireConfigArray, o as planFailedOps, ot as DiffCalculator, p as ATOMIC_FINAL_SNAPSHOT_TYPES, pn as CdkdError, pt as LockManager, q as WAFv2WebACLProvider, qt as resolveStateBucketWithDefaultAndSource, r as DeployEngine, rn as derivePartitionAndUrlSuffix, rt as requireConfigObject, s as planRollback, sn as resolveBucketRegion, st as describeTypeWithThrottleRetry, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as uploadCfnTemplate, tt as replayWarn, u as withResourceDeadline, un as resetAwsClients, ut as isThrottlingError, v as isFinalSnapshotError, vn as LocalMigrateError, vt as stringifyValue, w as isStatefulRecreateTargetSync, wn as ProvisioningError, wt as AssetModeResolver, x as makeCanonicalizePropertiesFn, xn as MissingCdkCliError, xt as createAssetRedirectResolver, y as refusesFinalSnapshot, yn as LocalStartServiceError, yt as WorkGraph, z as CloudControlProvider, zt as synthesisStatusMessage } from "./deploy-engine-uxo_FCje.js";
|
|
3
3
|
import { a as getLiveRenderer, c as PATTERN_B_RESOURCE_TYPES, d as generateResourceNameWithFallback, h as withStackName, i as runStackBuffered, m as withSkipPrefix, n as getLogger, o as PATTERN_B_NAME_OPTIONS, s as PATTERN_B_NAME_PROPERTIES, u as generateResourceName } from "./logger-zRrlbaQt.js";
|
|
4
|
-
import { t as ASGProvider } from "./asg-provider-
|
|
4
|
+
import { t as ASGProvider } from "./asg-provider-CCSQkGwO.js";
|
|
5
5
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
6
6
|
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
7
7
|
import { CopyObjectCommand, CreateBucketCommand, DeleteBucketAnalyticsConfigurationCommand, DeleteBucketCommand, DeleteBucketCorsCommand, DeleteBucketEncryptionCommand, DeleteBucketIntelligentTieringConfigurationCommand, DeleteBucketInventoryConfigurationCommand, DeleteBucketLifecycleCommand, DeleteBucketMetricsConfigurationCommand, DeleteBucketOwnershipControlsCommand, DeleteBucketPolicyCommand, DeleteBucketReplicationCommand, DeleteBucketTaggingCommand, DeleteBucketWebsiteCommand, DeleteObjectsCommand, GetBucketAccelerateConfigurationCommand, GetBucketCorsCommand, GetBucketEncryptionCommand, GetBucketLifecycleConfigurationCommand, GetBucketLocationCommand, GetBucketLoggingCommand, GetBucketNotificationConfigurationCommand, GetBucketOwnershipControlsCommand, GetBucketPolicyCommand, GetBucketReplicationCommand, GetBucketTaggingCommand, GetBucketVersioningCommand, GetBucketWebsiteCommand, GetObjectCommand, GetObjectLockConfigurationCommand, GetPublicAccessBlockCommand, HeadBucketCommand, ListBucketAnalyticsConfigurationsCommand, ListBucketIntelligentTieringConfigurationsCommand, ListBucketInventoryConfigurationsCommand, ListBucketMetricsConfigurationsCommand, ListObjectVersionsCommand, ListObjectsV2Command, NoSuchBucket, PutBucketAccelerateConfigurationCommand, PutBucketAnalyticsConfigurationCommand, PutBucketCorsCommand, PutBucketEncryptionCommand, PutBucketIntelligentTieringConfigurationCommand, PutBucketInventoryConfigurationCommand, PutBucketLifecycleConfigurationCommand, PutBucketLoggingCommand, PutBucketMetricsConfigurationCommand, PutBucketNotificationConfigurationCommand, PutBucketOwnershipControlsCommand, PutBucketPolicyCommand, PutBucketReplicationCommand, PutBucketTaggingCommand, PutBucketVersioningCommand, PutBucketWebsiteCommand, PutObjectCommand, PutObjectLockConfigurationCommand, PutPublicAccessBlockCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
|
|
@@ -12455,16 +12455,57 @@ function formatShape(segments) {
|
|
|
12455
12455
|
* ## The `skipping` variant
|
|
12456
12456
|
*
|
|
12457
12457
|
* On the DELETE path the established policy is warn-and-continue, so a
|
|
12458
|
-
* malformed record leaves the AWS resource ALIVE
|
|
12459
|
-
*
|
|
12460
|
-
*
|
|
12461
|
-
*
|
|
12458
|
+
* malformed record leaves the AWS resource ALIVE. That policy is unchanged —
|
|
12459
|
+
* the warning says what the skip costs, because an orphan the user is never
|
|
12460
|
+
* told about is one they cannot go and delete.
|
|
12461
|
+
*
|
|
12462
|
+
* Since issue [#1752](https://github.com/go-to-k/cdkd/issues/1752) the ACCOUNTING
|
|
12463
|
+
* around it is no longer a lie: an arm emitting this message must also return
|
|
12464
|
+
* `{ outcome: 'skipped', reason: COMPOSITE_ID_SKIP_REASON }` so `cdkd destroy`
|
|
12465
|
+
* prints a `⚠ … skipped` line instead of `✓ … deleted`, reports
|
|
12466
|
+
* `N deleted, 1 skipped`, KEEPS the state record, and exits non-zero. The
|
|
12467
|
+
* wording here changed accordingly — it used to promise unconditionally that
|
|
12468
|
+
* cdkd "will report this delete as successful", which is no longer true on the
|
|
12469
|
+
* destroy path. It is STILL true for the deploy engine's replacement / rollback
|
|
12470
|
+
* deletes, which discard the return value (issue
|
|
12471
|
+
* [#1762](https://github.com/go-to-k/cdkd/issues/1762)), so the message names
|
|
12472
|
+
* both callers rather than describing only the fixed one — a remedy of
|
|
12473
|
+
* "drop the record with 'cdkd state orphan'" is impossible on a path that has
|
|
12474
|
+
* already dropped it.
|
|
12462
12475
|
*/
|
|
12463
12476
|
function compositeIdFormatMessage(format, logicalId, physicalId, options) {
|
|
12464
12477
|
const accepted = format.alsoAccepts ? `"${formatShape(format.segments)}" or ${format.alsoAccepts}` : `"${formatShape(format.segments)}"`;
|
|
12465
12478
|
const head = `Invalid physicalId format for ${format.label} ${logicalId}: expected ${accepted}, got "${physicalId}"`;
|
|
12466
12479
|
if (!options?.skipping) return head;
|
|
12467
|
-
return `${head}. Skipping the delete —
|
|
12480
|
+
return `${head}. Skipping the delete — no AWS call is issued, so the resource is LEFT IN PLACE. On 'cdkd destroy' / 'cdkd state destroy' the state record is KEPT and the run exits non-zero, so repair the id in state.json and re-run (or delete the resource by hand and drop the record with 'cdkd state orphan'). NOTE this arm is ALSO reached from cdkd deploy — the plain DELETE of a resource removed from the template (the most common one), plus the replacement and rollback deletes — all of which still DROP the record and report success (https://github.com/go-to-k/cdkd/issues/1762) — there, delete it by hand.`;
|
|
12481
|
+
}
|
|
12482
|
+
/**
|
|
12483
|
+
* The short `ResourceDeleteResult.reason` every malformed-composite-id DELETE
|
|
12484
|
+
* skip reports (issue [#1752](https://github.com/go-to-k/cdkd/issues/1752)).
|
|
12485
|
+
*
|
|
12486
|
+
* Deliberately short and IDENTICAL across the five arms: it is rendered inline
|
|
12487
|
+
* on the per-resource status line (`⚠ MyTable (AWS::Glue::Table) skipped
|
|
12488
|
+
* (malformed physicalId in state — no delete issued)`), where the full
|
|
12489
|
+
* remediation sentence built by {@link compositeIdFormatMessage} would not fit.
|
|
12490
|
+
* The full text is still emitted, as the `logger.warn` right beside it.
|
|
12491
|
+
*
|
|
12492
|
+
* A shared constant rather than five literals so the five arms cannot drift and
|
|
12493
|
+
* a grep for the wording finds all of them.
|
|
12494
|
+
*/
|
|
12495
|
+
const COMPOSITE_ID_SKIP_REASON = "malformed physicalId in state — no delete issued";
|
|
12496
|
+
/**
|
|
12497
|
+
* The `ResourceDeleteResult` a malformed-composite-id DELETE arm returns.
|
|
12498
|
+
*
|
|
12499
|
+
* Pairs with the `{ skipping: true }` warning: emit the warning, return this.
|
|
12500
|
+
* Providers call it as `return compositeIdSkipResult();` so the arm reads as
|
|
12501
|
+
* the deliberate skip it is rather than as the bare `return;` that made issue
|
|
12502
|
+
* #1752's mis-accounting possible.
|
|
12503
|
+
*/
|
|
12504
|
+
function compositeIdSkipResult() {
|
|
12505
|
+
return {
|
|
12506
|
+
outcome: "skipped",
|
|
12507
|
+
reason: COMPOSITE_ID_SKIP_REASON
|
|
12508
|
+
};
|
|
12468
12509
|
}
|
|
12469
12510
|
|
|
12470
12511
|
//#endregion
|
|
@@ -21890,7 +21931,7 @@ var EC2Provider = class {
|
|
|
21890
21931
|
const parts = physicalId.split("|");
|
|
21891
21932
|
if (parts.length < 3) {
|
|
21892
21933
|
this.logger.warn(compositeIdFormatMessage(EC2_NETWORK_ACL_ENTRY_ID_FORMAT, logicalId, physicalId, { skipping: true }));
|
|
21893
|
-
return;
|
|
21934
|
+
return compositeIdSkipResult();
|
|
21894
21935
|
}
|
|
21895
21936
|
const networkAclId = parts[0];
|
|
21896
21937
|
const ruleNumber = parseInt(parts[1], 10);
|
|
@@ -39028,7 +39069,7 @@ var AppSyncProvider = class {
|
|
|
39028
39069
|
const [apiId, name] = physicalId.split("|");
|
|
39029
39070
|
if (!apiId || !name) {
|
|
39030
39071
|
this.logger.warn(compositeIdFormatMessage(APPSYNC_DATASOURCE_ID_FORMAT, logicalId, physicalId, { skipping: true }));
|
|
39031
|
-
return;
|
|
39072
|
+
return compositeIdSkipResult();
|
|
39032
39073
|
}
|
|
39033
39074
|
try {
|
|
39034
39075
|
await this.getClient().send(new DeleteDataSourceCommand({
|
|
@@ -39091,7 +39132,7 @@ var AppSyncProvider = class {
|
|
|
39091
39132
|
const parts = physicalId.split("|");
|
|
39092
39133
|
if (parts.length < 3) {
|
|
39093
39134
|
this.logger.warn(compositeIdFormatMessage(APPSYNC_RESOLVER_ID_FORMAT, logicalId, physicalId, { skipping: true }));
|
|
39094
|
-
return;
|
|
39135
|
+
return compositeIdSkipResult();
|
|
39095
39136
|
}
|
|
39096
39137
|
const [apiId, typeName, fieldName] = parts;
|
|
39097
39138
|
try {
|
|
@@ -39147,7 +39188,7 @@ var AppSyncProvider = class {
|
|
|
39147
39188
|
const [apiId, apiKeyId] = physicalId.split("|");
|
|
39148
39189
|
if (!apiId || !apiKeyId) {
|
|
39149
39190
|
this.logger.warn(compositeIdFormatMessage(APPSYNC_APIKEY_ID_FORMAT, logicalId, physicalId, { skipping: true }));
|
|
39150
|
-
return;
|
|
39191
|
+
return compositeIdSkipResult();
|
|
39151
39192
|
}
|
|
39152
39193
|
try {
|
|
39153
39194
|
await this.getClient().send(new DeleteApiKeyCommand({
|
|
@@ -39873,7 +39914,7 @@ var GlueProvider = class {
|
|
|
39873
39914
|
const [databaseName, tableName] = physicalId.split("|");
|
|
39874
39915
|
if (!databaseName || !tableName) {
|
|
39875
39916
|
this.logger.warn(compositeIdFormatMessage(GLUE_TABLE_ID_FORMAT, logicalId, physicalId, { skipping: true }));
|
|
39876
|
-
return;
|
|
39917
|
+
return compositeIdSkipResult();
|
|
39877
39918
|
}
|
|
39878
39919
|
const target = deleteCatalogId(properties);
|
|
39879
39920
|
if (target.declaredButUnusable) this.logger.debug(`Glue Table ${logicalId}: CatalogId is not a usable value (likely an unresolved intrinsic), so DeleteTable targets ${describeCatalog(target.catalogId)}.`);
|
|
@@ -52076,6 +52117,12 @@ var ECRProvider = class {
|
|
|
52076
52117
|
*
|
|
52077
52118
|
* Exported for unit-test coverage of `countProtectedResources`.
|
|
52078
52119
|
*/
|
|
52120
|
+
/**
|
|
52121
|
+
* The nested-stack resource type. A skipped row of this type means the CHILD
|
|
52122
|
+
* stack was not destroyed, and the record a user must repair lives in the
|
|
52123
|
+
* child's own state file (`<parent>~<logicalId>`) — see `skippedStateTargets`.
|
|
52124
|
+
*/
|
|
52125
|
+
const NESTED_STACK_TYPE = "AWS::CloudFormation::Stack";
|
|
52079
52126
|
const PROTECTION_PROPERTY_BY_TYPE = {
|
|
52080
52127
|
"AWS::Logs::LogGroup": "DeletionProtectionEnabled",
|
|
52081
52128
|
"AWS::RDS::DBInstance": "DeletionProtection",
|
|
@@ -52179,6 +52226,7 @@ async function runDestroyForStack(stackName, state, ctx) {
|
|
|
52179
52226
|
skippedEmpty: false,
|
|
52180
52227
|
deletedCount: 0,
|
|
52181
52228
|
retainedCount: 0,
|
|
52229
|
+
skippedCount: 0,
|
|
52182
52230
|
errorCount: 0,
|
|
52183
52231
|
interrupted: false
|
|
52184
52232
|
};
|
|
@@ -52285,6 +52333,7 @@ async function runDestroyForStack(stackName, state, ctx) {
|
|
|
52285
52333
|
}
|
|
52286
52334
|
}
|
|
52287
52335
|
const remainingResources = { ...state.resources };
|
|
52336
|
+
const skippedStateTargets = /* @__PURE__ */ new Set();
|
|
52288
52337
|
const buildDestroySnapshot = () => {
|
|
52289
52338
|
const { imports: _imports, outputReads: _outputReads, ...rest } = state;
|
|
52290
52339
|
return {
|
|
@@ -52412,15 +52461,16 @@ async function runDestroyForStack(stackName, state, ctx) {
|
|
|
52412
52461
|
const globalTimeoutMs = ctx.resourceTimeoutMs ?? 18e5;
|
|
52413
52462
|
const slowTypeMinTimeoutMs = slowCcOperationTimeoutMs(resource.resourceType, "DELETE");
|
|
52414
52463
|
const timeoutMs = ctx.resourceTimeoutByType?.[resource.resourceType] ?? Math.max(providerMinTimeoutMs, slowTypeMinTimeoutMs, globalTimeoutMs);
|
|
52464
|
+
let deleteResult;
|
|
52415
52465
|
await withResourceDeadline(async () => {
|
|
52416
52466
|
const maxAttempts = provider.disableOuterRetry ? 0 : 3;
|
|
52417
52467
|
let lastDeleteError;
|
|
52418
52468
|
for (let attempt = 0; attempt <= maxAttempts; attempt++) try {
|
|
52419
|
-
await provider.delete(logicalId, resource.physicalId, resource.resourceType, resource.properties, {
|
|
52469
|
+
deleteResult = await provider.delete(logicalId, resource.physicalId, resource.resourceType, resource.properties, {
|
|
52420
52470
|
...state.region !== void 0 && { expectedRegion: state.region },
|
|
52421
52471
|
...ctx.removeProtection === true && { removeProtection: true },
|
|
52422
52472
|
...finalSnapshotIdentifier !== void 0 && { finalSnapshotIdentifier }
|
|
52423
|
-
});
|
|
52473
|
+
}) ?? void 0;
|
|
52424
52474
|
lastDeleteError = null;
|
|
52425
52475
|
break;
|
|
52426
52476
|
} catch (retryError) {
|
|
@@ -52445,6 +52495,23 @@ async function runDestroyForStack(stackName, state, ctx) {
|
|
|
52445
52495
|
onTimeout: (elapsedMs) => new ResourceTimeoutError(logicalId, resource.resourceType, stackRegion, elapsedMs, "DELETE", timeoutMs)
|
|
52446
52496
|
});
|
|
52447
52497
|
renderer.removeTask(logicalId);
|
|
52498
|
+
if (deleteResult?.outcome === "skipped") {
|
|
52499
|
+
logger.info(` ${formatResourceLine("skipped", logicalId, resource.resourceType, `skipped (${deleteResult.reason})`)}`);
|
|
52500
|
+
result.skippedCount++;
|
|
52501
|
+
skippedStateTargets.add(resource.resourceType === NESTED_STACK_TYPE ? `${stackName}~${logicalId}` : stackName);
|
|
52502
|
+
ctx.eventRecorder?.record({
|
|
52503
|
+
eventType: "RESOURCE_SKIPPED",
|
|
52504
|
+
stackName,
|
|
52505
|
+
operation: "DELETE",
|
|
52506
|
+
logicalId,
|
|
52507
|
+
resourceType: resource.resourceType,
|
|
52508
|
+
...resource.provisionedBy && { provisionedBy: resource.provisionedBy },
|
|
52509
|
+
...resource.physicalId && { physicalId: resource.physicalId },
|
|
52510
|
+
reason: deleteResult.reason,
|
|
52511
|
+
durationMs: Date.now() - resourceStartedAt
|
|
52512
|
+
});
|
|
52513
|
+
return;
|
|
52514
|
+
}
|
|
52448
52515
|
logger.info(` ${formatResourceLine("deleted", logicalId, resource.resourceType)}`);
|
|
52449
52516
|
result.deletedCount++;
|
|
52450
52517
|
ctx.eventRecorder?.record({
|
|
@@ -52513,7 +52580,7 @@ async function runDestroyForStack(stackName, state, ctx) {
|
|
|
52513
52580
|
}
|
|
52514
52581
|
result.interrupted = draining;
|
|
52515
52582
|
await saveChain;
|
|
52516
|
-
const preserveState = result.errorCount > 0 || result.interrupted;
|
|
52583
|
+
const preserveState = result.errorCount > 0 || result.interrupted || result.skippedCount > 0;
|
|
52517
52584
|
if (!preserveState) {
|
|
52518
52585
|
await ctx.stateBackend.deleteState(stackName, regionForState);
|
|
52519
52586
|
logger.debug("State deleted");
|
|
@@ -52525,12 +52592,19 @@ async function runDestroyForStack(stackName, state, ctx) {
|
|
|
52525
52592
|
logger.warn(`Failed to persist remaining state after partial destroy: ${error instanceof Error ? error.message : String(error)}. The state file may still list already-deleted resources; a re-run resolves them idempotently.`);
|
|
52526
52593
|
}
|
|
52527
52594
|
if (result.interrupted) logger.warn(`Destroy interrupted — ${Object.keys(remainingResources).length} resource(s) not deleted. State preserved.`);
|
|
52528
|
-
else logger.warn(`${result.errorCount} resource(s) failed to delete. State preserved.`);
|
|
52595
|
+
else if (result.errorCount > 0) logger.warn(`${result.errorCount} resource(s) failed to delete. State preserved.`);
|
|
52596
|
+
else logger.warn(`${result.skippedCount} resource(s) skipped — cdkd could not address them, so no delete was issued and they may still exist in AWS. State preserved (the records are kept so the resources stay traceable).`);
|
|
52529
52597
|
}
|
|
52530
52598
|
const retainedSuffix = result.retainedCount > 0 ? `, ${result.retainedCount} retained` : "";
|
|
52599
|
+
const skippedSuffix = result.skippedCount > 0 ? `, ${yellow(result.skippedCount)} skipped` : "";
|
|
52531
52600
|
if (!preserveState) logger.info(`\n${green("✓")} ${bold(`Stack ${stackName} destroyed`)} (${green(result.deletedCount)} deleted${retainedSuffix}, ${result.errorCount} errors)`);
|
|
52532
|
-
else if (result.interrupted && result.errorCount === 0) logger.warn(`\n${yellow("⚠")} ${bold(`Stack ${stackName} destroy interrupted`)} (${green(result.deletedCount)} deleted${retainedSuffix}, ${result.errorCount} errors). State preserved — re-run 'cdkd destroy' / 'cdkd state destroy' to finish.`);
|
|
52533
|
-
else
|
|
52601
|
+
else if (result.interrupted && result.errorCount === 0) logger.warn(`\n${yellow("⚠")} ${bold(`Stack ${stackName} destroy interrupted`)} (${green(result.deletedCount)} deleted${retainedSuffix}${skippedSuffix}, ${result.errorCount} errors). State preserved — re-run 'cdkd destroy' / 'cdkd state destroy' to finish.`);
|
|
52602
|
+
else if (result.errorCount === 0) {
|
|
52603
|
+
const targets = [...skippedStateTargets];
|
|
52604
|
+
const showHint = targets.map((t) => `'cdkd state show ${t}'`).join(" / ");
|
|
52605
|
+
const orphanHint = targets.map((t) => `'cdkd state orphan ${t}'`).join(" / ");
|
|
52606
|
+
logger.warn(`\n${yellow("⚠")} ${bold(`Stack ${stackName} partially destroyed`)} (${green(result.deletedCount)} deleted${retainedSuffix}${skippedSuffix}, ${result.errorCount} errors). cdkd could not address the skipped resource(s), so they may still exist in AWS. Fix the physicalId in state.json (${showHint}) and re-run, or delete them by hand and drop the records with ${orphanHint}.`);
|
|
52607
|
+
} else logger.warn(`\n${yellow("⚠")} ${bold(`Stack ${stackName} partially destroyed`)} (${green(result.deletedCount)} deleted${retainedSuffix}${skippedSuffix}, ${red(result.errorCount)} errors). State preserved — re-run 'cdkd destroy' / 'cdkd state destroy' to clean up. If the same resource keeps failing, 'cdkd state orphan ${stackName}' is the last resort: it removes the state record without deleting AWS resources.`);
|
|
52534
52608
|
} finally {
|
|
52535
52609
|
process.removeListener("SIGINT", sigintHandler);
|
|
52536
52610
|
renderer.stop();
|
|
@@ -52749,7 +52823,7 @@ var NestedStackProvider = class {
|
|
|
52749
52823
|
}
|
|
52750
52824
|
const resourceCount = Object.keys(childStateData.state.resources).length;
|
|
52751
52825
|
this.logger.info(`Destroying nested stack ${childStackName} (logicalId=${logicalId}, ${resourceCount} resource(s))`);
|
|
52752
|
-
await withNestedStackContext({
|
|
52826
|
+
const childResult = await withNestedStackContext({
|
|
52753
52827
|
...ctx,
|
|
52754
52828
|
parentStackName: childStackName,
|
|
52755
52829
|
parentRegion: childRegion,
|
|
@@ -52771,6 +52845,15 @@ var NestedStackProvider = class {
|
|
|
52771
52845
|
...ctx.destroyOptions?.resourceWarnAfterByType && { resourceWarnAfterByType: ctx.destroyOptions.resourceWarnAfterByType },
|
|
52772
52846
|
...ctx.destroyOptions?.resourceTimeoutByType && { resourceTimeoutByType: ctx.destroyOptions.resourceTimeoutByType }
|
|
52773
52847
|
}));
|
|
52848
|
+
if (childResult.skippedCount > 0 || childResult.interrupted) {
|
|
52849
|
+
const causes = [];
|
|
52850
|
+
if (childResult.skippedCount > 0) causes.push(`skipped ${childResult.skippedCount} resource(s)`);
|
|
52851
|
+
if (childResult.interrupted) causes.push("was interrupted");
|
|
52852
|
+
return {
|
|
52853
|
+
outcome: "skipped",
|
|
52854
|
+
reason: `nested stack ${childStackName} ${causes.join(" and ")}`
|
|
52855
|
+
};
|
|
52856
|
+
}
|
|
52774
52857
|
}
|
|
52775
52858
|
async getAttribute(_physicalId, _resourceType, attributeName) {
|
|
52776
52859
|
throw new Error(`AWS::CloudFormation::Stack: attribute '${attributeName}' is not in the recorded Outputs map. Only 'Outputs.<Key>' references to declared Output names on the child template are supported.`);
|
|
@@ -57689,6 +57772,7 @@ async function destroyCommand(stackArgs, options) {
|
|
|
57689
57772
|
} else throw new Error("Could not determine which stacks belong to this app. Specify stack names explicitly, use --all, or ensure --app / cdk.json is configured.");
|
|
57690
57773
|
const stackPatterns = stackArgs.length > 0 ? stackArgs : options.stack ? [options.stack] : [];
|
|
57691
57774
|
let totalErrors = 0;
|
|
57775
|
+
let totalSkipped = 0;
|
|
57692
57776
|
let interrupted = false;
|
|
57693
57777
|
let stackNames;
|
|
57694
57778
|
if (options.all) stackNames = candidateStacks.map((s) => s.stackName);
|
|
@@ -57813,8 +57897,9 @@ async function destroyCommand(stackArgs, options) {
|
|
|
57813
57897
|
eventRecorder
|
|
57814
57898
|
}));
|
|
57815
57899
|
totalErrors += result.errorCount;
|
|
57900
|
+
totalSkipped += result.skippedCount;
|
|
57816
57901
|
if (result.interrupted) interrupted = true;
|
|
57817
|
-
destroyRunResult = result.errorCount > 0 ? "FAILED" : "SUCCEEDED";
|
|
57902
|
+
destroyRunResult = result.errorCount > 0 || result.skippedCount > 0 ? "FAILED" : "SUCCEEDED";
|
|
57818
57903
|
eventRecorder.record({
|
|
57819
57904
|
eventType: "RUN_FINISHED",
|
|
57820
57905
|
stackName,
|
|
@@ -57823,7 +57908,8 @@ async function destroyCommand(stackArgs, options) {
|
|
|
57823
57908
|
created: 0,
|
|
57824
57909
|
updated: 0,
|
|
57825
57910
|
deleted: result.deletedCount,
|
|
57826
|
-
...result.errorCount > 0 && { failed: result.errorCount }
|
|
57911
|
+
...result.errorCount > 0 && { failed: result.errorCount },
|
|
57912
|
+
...result.skippedCount > 0 && { skipped: result.skippedCount }
|
|
57827
57913
|
}
|
|
57828
57914
|
});
|
|
57829
57915
|
} catch (destroyError) {
|
|
@@ -57842,6 +57928,7 @@ async function destroyCommand(stackArgs, options) {
|
|
|
57842
57928
|
}
|
|
57843
57929
|
if (totalErrors > 0) throw new PartialFailureError(`Destroy completed with ${totalErrors} resource error(s). State preserved — inspect 'cdkd state show <stack>' and re-run 'cdkd destroy' to retry. If the same resource keeps failing, 'cdkd state orphan <stack>' removes the state record without deleting AWS resources.`);
|
|
57844
57930
|
if (interrupted) throw new PartialFailureError(`Destroy interrupted by Ctrl-C. State preserved — re-run 'cdkd destroy' to finish.`);
|
|
57931
|
+
if (totalSkipped > 0) throw new PartialFailureError(`Destroy skipped ${totalSkipped} entr${totalSkipped === 1 ? "y" : "ies"} cdkd could not address, so the underlying resources may still exist in AWS. A skipped nested stack counts as ONE entry and may cover several of its own resources — the per-stack summaries above give the exact breakdown. State preserved (the records are kept). Repair the physicalId in state.json and re-run 'cdkd destroy', or delete the resources by hand and drop the records with 'cdkd state orphan <stack>'.`);
|
|
57845
57932
|
} finally {
|
|
57846
57933
|
unforwardSigterm();
|
|
57847
57934
|
awsClients.destroy();
|
|
@@ -61356,6 +61443,7 @@ async function stateDestroyCommand(stackArgs, options) {
|
|
|
61356
61443
|
}
|
|
61357
61444
|
logger.info(`Found ${stackNames.length} stack(s) to destroy: ${stackNames.join(", ")}`);
|
|
61358
61445
|
let totalErrors = 0;
|
|
61446
|
+
let totalSkipped = 0;
|
|
61359
61447
|
let interrupted = false;
|
|
61360
61448
|
for (const stackName of stackNames) {
|
|
61361
61449
|
const refs = stateRefs.filter((r) => r.stackName === stackName);
|
|
@@ -61416,6 +61504,7 @@ async function stateDestroyCommand(stackArgs, options) {
|
|
|
61416
61504
|
...options.resourceTimeout?.perTypeMs && { resourceTimeoutByType: options.resourceTimeout.perTypeMs }
|
|
61417
61505
|
}));
|
|
61418
61506
|
totalErrors += result.errorCount;
|
|
61507
|
+
totalSkipped += result.skippedCount;
|
|
61419
61508
|
if (result.interrupted) interrupted = true;
|
|
61420
61509
|
if (interrupted) break;
|
|
61421
61510
|
}
|
|
@@ -61423,6 +61512,7 @@ async function stateDestroyCommand(stackArgs, options) {
|
|
|
61423
61512
|
}
|
|
61424
61513
|
if (totalErrors > 0) throw new PartialFailureError(`Destroy completed with ${totalErrors} resource error(s). State preserved — inspect 'cdkd state show <stack>' and re-run 'cdkd state destroy' to retry. If the same resource keeps failing, 'cdkd state orphan <stack>' removes the state record without deleting AWS resources.`);
|
|
61425
61514
|
if (interrupted) throw new PartialFailureError(`Destroy interrupted by Ctrl-C. State preserved — re-run 'cdkd state destroy' to finish.`);
|
|
61515
|
+
if (totalSkipped > 0) throw new PartialFailureError(`Destroy skipped ${totalSkipped} entr${totalSkipped === 1 ? "y" : "ies"} cdkd could not address, so the underlying resources may still exist in AWS. A skipped nested stack counts as ONE entry and may cover several of its own resources — the per-stack summaries above give the exact breakdown. State preserved (the records are kept). Repair the physicalId in state.json and re-run 'cdkd state destroy', or delete the resources by hand and drop the records with 'cdkd state orphan <stack>'.`);
|
|
61426
61516
|
} finally {
|
|
61427
61517
|
unforwardSigterm();
|
|
61428
61518
|
setup.dispose();
|
|
@@ -62492,6 +62582,11 @@ function printRunList(stackName, region, runs) {
|
|
|
62492
62582
|
logger.info(gray(`\nUse 'cdkd events ${stackName} --run <runId>' to read one run's events.`));
|
|
62493
62583
|
}
|
|
62494
62584
|
/** Human-readable single-run event stream (in recorded order). */
|
|
62585
|
+
/**
|
|
62586
|
+
* Render one run's event stream. Exported for unit-test coverage — the
|
|
62587
|
+
* `counts.skipped` / `reason` rendering is the whole value of those fields
|
|
62588
|
+
* (issue #1752), so it needs a direct fence rather than only `--json` coverage.
|
|
62589
|
+
*/
|
|
62495
62590
|
function printRunEvents(stackName, region, runId, events) {
|
|
62496
62591
|
const logger = getLogger();
|
|
62497
62592
|
logger.info(`${bold("Events for run")} ${cyan(runId)} ${gray(`(${stackName}, ${region})`)}`);
|
|
@@ -62509,8 +62604,9 @@ function printRunEvents(stackName, region, runId, events) {
|
|
|
62509
62604
|
if (e.cdkdVersion) parts.push(gray(`cdkd ${e.cdkdVersion}`));
|
|
62510
62605
|
if (e.result) parts.push(e.result === "SUCCEEDED" ? green(e.result) : red(e.result));
|
|
62511
62606
|
if (typeof e.durationMs === "number") parts.push(gray(`${e.durationMs}ms`));
|
|
62512
|
-
if (e.counts) parts.push(gray(`+${e.counts.created}/~${e.counts.updated}/-${e.counts.deleted}` + (e.counts.failed ? ` !${e.counts.failed}` : "")));
|
|
62607
|
+
if (e.counts) parts.push(gray(`+${e.counts.created}/~${e.counts.updated}/-${e.counts.deleted}` + (e.counts.failed ? ` !${e.counts.failed}` : "") + (e.counts.skipped ? ` ⚠${e.counts.skipped}` : "")));
|
|
62513
62608
|
logger.info(` ${parts.join(" ")}`);
|
|
62609
|
+
if (e.reason) logger.info(` ${yellow(e.reason)}`);
|
|
62514
62610
|
if (e.error) {
|
|
62515
62611
|
const code = e.error.awsErrorCode ? ` (${e.error.awsErrorCode})` : "";
|
|
62516
62612
|
const reqId = e.error.requestId ? gray(` requestId=${e.error.requestId}`) : "";
|
|
@@ -62518,10 +62614,17 @@ function printRunEvents(stackName, region, runId, events) {
|
|
|
62518
62614
|
}
|
|
62519
62615
|
}
|
|
62520
62616
|
}
|
|
62521
|
-
/**
|
|
62617
|
+
/**
|
|
62618
|
+
* Color the event-type token by its lifecycle phase.
|
|
62619
|
+
*
|
|
62620
|
+
* Exported for unit-test coverage (matching `destroy-runner.ts`'s
|
|
62621
|
+
* `PROTECTION_PROPERTY_BY_TYPE` convention) — it is pure, so testing it
|
|
62622
|
+
* directly beats driving it through the renderer's log output.
|
|
62623
|
+
*/
|
|
62522
62624
|
function colorizeEventType(eventType) {
|
|
62523
62625
|
if (eventType.endsWith("FAILED")) return red(eventType);
|
|
62524
62626
|
if (eventType.endsWith("SUCCEEDED") || eventType === "RUN_FINISHED") return green(eventType);
|
|
62627
|
+
if (eventType === "RESOURCE_SKIPPED") return yellow(eventType);
|
|
62525
62628
|
if (eventType.startsWith("ROLLBACK")) return yellow(eventType);
|
|
62526
62629
|
return cyan(eventType);
|
|
62527
62630
|
}
|
|
@@ -65827,6 +65930,61 @@ function notFoundError$1(target, stack, resources) {
|
|
|
65827
65930
|
return new LocalInvokeResolutionError(msg.trimEnd());
|
|
65828
65931
|
}
|
|
65829
65932
|
|
|
65933
|
+
//#endregion
|
|
65934
|
+
//#region src/utils/ecr-uri.ts
|
|
65935
|
+
/**
|
|
65936
|
+
* Matching the HOST half of an ECR image URI:
|
|
65937
|
+
* `<acct>.dkr.ecr.<region>.<urlSuffix>/`.
|
|
65938
|
+
*
|
|
65939
|
+
* The suffix is CAPTURED rather than spelled out (issue #1758): the previous
|
|
65940
|
+
* pattern hardcoded `amazonaws.com` with an optional `.cn` tail, so a `us-iso*`
|
|
65941
|
+
* registry (`c2s.ic.gov` / `sc2s.sgov.gov`) never matched and the caller
|
|
65942
|
+
* silently classified a real ECR image as a user-managed one — skipping the
|
|
65943
|
+
* `docker login` it needs.
|
|
65944
|
+
*/
|
|
65945
|
+
const ECR_URI_HOST_REGEX = /^(\d{12})\.dkr\.ecr\.([^.]+)\.([^/]+)\//;
|
|
65946
|
+
/**
|
|
65947
|
+
* The account + region of an ECR image URI, or `undefined` when the URI is not
|
|
65948
|
+
* an ECR registry host for the region it names.
|
|
65949
|
+
*
|
|
65950
|
+
* Lives in `src/utils/` rather than beside its first caller because it has TWO
|
|
65951
|
+
* consumers in different layers — `src/local/ecr-puller.ts` (which needs the
|
|
65952
|
+
* `:tag` tail too) and `src/local/ecs-task-resolver.ts` (which classifies an
|
|
65953
|
+
* image that may carry a digest or no tag at all). Before issue #1758 they each
|
|
65954
|
+
* carried their own copy of the hardcoded commercial pattern, and fixing only
|
|
65955
|
+
* the pull path left `cdkd local run-task` broken outside the commercial
|
|
65956
|
+
* partition; ONE definition is what stops them drifting apart again.
|
|
65957
|
+
*
|
|
65958
|
+
* The module is deliberately free of AWS SDK imports, which is what lets
|
|
65959
|
+
* `ecs-task-resolver.ts` consume it without breaking the invariant that module
|
|
65960
|
+
* documents about itself (it resolves secrets through a separate module for
|
|
65961
|
+
* exactly that reason).
|
|
65962
|
+
*/
|
|
65963
|
+
function parseEcrRegistryHost(imageUri) {
|
|
65964
|
+
const m = ECR_URI_HOST_REGEX.exec(imageUri);
|
|
65965
|
+
if (!m) return void 0;
|
|
65966
|
+
const region = m[2];
|
|
65967
|
+
if (m[3] !== derivePartitionAndUrlSuffix(region).urlSuffix) return void 0;
|
|
65968
|
+
return {
|
|
65969
|
+
accountId: m[1],
|
|
65970
|
+
region
|
|
65971
|
+
};
|
|
65972
|
+
}
|
|
65973
|
+
/**
|
|
65974
|
+
* True when the URI has the ECR HOST SHAPE but its suffix does not belong to
|
|
65975
|
+
* the region it names — i.e. exactly the case {@link parseEcrRegistryHost}
|
|
65976
|
+
* rejects for a reason the caller may want to report.
|
|
65977
|
+
*
|
|
65978
|
+
* The two rejections are worth telling apart at a call site that degrades
|
|
65979
|
+
* silently: a genuinely public image and a registry in a partition
|
|
65980
|
+
* `derivePartitionAndUrlSuffix` does not know yet (issue #1764) both come back
|
|
65981
|
+
* `undefined`, and only the second is a cdkd gap rather than a user choice.
|
|
65982
|
+
*/
|
|
65983
|
+
function looksLikeEcrHostWithForeignSuffix(imageUri) {
|
|
65984
|
+
const m = ECR_URI_HOST_REGEX.exec(imageUri);
|
|
65985
|
+
return m !== null && m[3] !== derivePartitionAndUrlSuffix(m[2]).urlSuffix;
|
|
65986
|
+
}
|
|
65987
|
+
|
|
65830
65988
|
//#endregion
|
|
65831
65989
|
//#region src/local/ecs-task-resolver.ts
|
|
65832
65990
|
function detectEcsImageResolutionNeeds(stack) {
|
|
@@ -66446,13 +66604,14 @@ function parseContainerImage(raw, containerName, taskLogicalId, resources, _stac
|
|
|
66446
66604
|
if (substituted.includes("AWS::")) throw new EcsTaskResolutionError(`Container '${containerName}' in task '${taskLogicalId}' has an Image that references AWS pseudo parameters (${substituted}). cdkd could not resolve them: confirm AWS credentials are configured so STS GetCallerIdentity succeeds, and that --region / AWS_REGION names the target region. Workaround: build the image locally (ContainerImage.fromAsset) or pin a public image.`);
|
|
66447
66605
|
throw new EcsTaskResolutionError(`Container '${containerName}' in task '${taskLogicalId}' has an Image with unresolved \${...} placeholders (${substituted}). cdkd local run-task v1 only resolves AWS pseudo parameters and same-stack AWS::ECR::Repository refs.`);
|
|
66448
66606
|
}
|
|
66449
|
-
const
|
|
66450
|
-
if (
|
|
66607
|
+
const ecrHost = parseEcrRegistryHost(substituted);
|
|
66608
|
+
if (ecrHost) return {
|
|
66451
66609
|
kind: "ecr",
|
|
66452
66610
|
uri: substituted,
|
|
66453
|
-
account:
|
|
66454
|
-
region:
|
|
66611
|
+
account: ecrHost.accountId,
|
|
66612
|
+
region: ecrHost.region
|
|
66455
66613
|
};
|
|
66614
|
+
if (looksLikeEcrHostWithForeignSuffix(substituted)) getLogger().child("ecs-task-resolver").debug(`Image '${substituted}' has an ECR host shape but a URL suffix that does not belong to its region's partition; treating it as a public image (no docker login).`);
|
|
66456
66615
|
return {
|
|
66457
66616
|
kind: "public",
|
|
66458
66617
|
uri: substituted
|
|
@@ -66489,12 +66648,12 @@ function classifyResolvedImage(uri, cdkAssetContainerRepo) {
|
|
|
66489
66648
|
if (hashMatch) out.assetHash = hashMatch[1];
|
|
66490
66649
|
return out;
|
|
66491
66650
|
}
|
|
66492
|
-
const
|
|
66493
|
-
if (
|
|
66651
|
+
const ecrHost = parseEcrRegistryHost(uri);
|
|
66652
|
+
if (ecrHost) return {
|
|
66494
66653
|
kind: "ecr",
|
|
66495
66654
|
uri,
|
|
66496
|
-
account:
|
|
66497
|
-
region:
|
|
66655
|
+
account: ecrHost.accountId,
|
|
66656
|
+
region: ecrHost.region
|
|
66498
66657
|
};
|
|
66499
66658
|
return {
|
|
66500
66659
|
kind: "public",
|
|
@@ -67080,50 +67239,25 @@ async function buildContainerImage$1(...args) {
|
|
|
67080
67239
|
|
|
67081
67240
|
//#endregion
|
|
67082
67241
|
//#region src/local/ecr-puller.ts
|
|
67083
|
-
/**
|
|
67084
|
-
|
|
67085
|
-
|
|
67086
|
-
|
|
67087
|
-
* deployed elsewhere or sharing a centralized registry), cdkd
|
|
67088
|
-
* authenticates against the target registry and runs `docker pull`.
|
|
67089
|
-
*
|
|
67090
|
-
* **Cross-account / cross-region** (#455):
|
|
67091
|
-
* - Same-account, same-region: fast path. No STS hop. The default
|
|
67092
|
-
* credential chain is used directly for `ecr:GetAuthorizationToken`.
|
|
67093
|
-
* - `ecrRoleArn` is provided: `sts:AssumeRole` is issued via the
|
|
67094
|
-
* default credential chain to obtain temporary credentials for the
|
|
67095
|
-
* target account. The resulting credentials authenticate the ECR
|
|
67096
|
-
* client (regardless of region — the ECR client is built for the
|
|
67097
|
-
* URI's region, which can differ from the caller's profile region).
|
|
67098
|
-
* - Cross-account, NO `ecrRoleArn`: cdkd falls through to the
|
|
67099
|
-
* default credential chain. This works when the caller has been
|
|
67100
|
-
* granted cross-account `ecr:GetAuthorizationToken` +
|
|
67101
|
-
* `ecr:BatchGetImage` permissions on the target repository via an
|
|
67102
|
-
* IAM policy; otherwise AWS rejects the call with `AccessDenied`
|
|
67103
|
-
* and the user is pointed at `--ecr-role-arn`.
|
|
67104
|
-
*
|
|
67105
|
-
* The `--no-pull` semantics (C3 in the design doc):
|
|
67106
|
-
* - When NOT set: `ecrLogin` + `docker pull <uri>`.
|
|
67107
|
-
* - When set: skip `docker pull`. If the image isn't in the local
|
|
67108
|
-
* cache, the subsequent `docker run` will fail; we surface a clearer
|
|
67109
|
-
* "image not in local cache" error here so the user knows to drop
|
|
67110
|
-
* `--no-pull` or pre-pull manually.
|
|
67111
|
-
*/
|
|
67112
|
-
/** Regex matching the `<acct>.dkr.ecr.<region>.amazonaws.com/<repo>:<tag>` shape. */
|
|
67113
|
-
const ECR_URI_REGEX = /^(\d{12})\.dkr\.ecr\.([^.]+)\.amazonaws\.com(?:\.cn)?\/([^:]+):(.+)$/;
|
|
67242
|
+
/** The URL suffix an ECR registry host uses in `region`'s partition (issue #1758). */
|
|
67243
|
+
function ecrUrlSuffix(region) {
|
|
67244
|
+
return derivePartitionAndUrlSuffix(region).urlSuffix;
|
|
67245
|
+
}
|
|
67114
67246
|
/**
|
|
67115
67247
|
* Parse an ECR image URI. Returns `undefined` for non-ECR URIs (typically:
|
|
67116
67248
|
* Docker Hub, public.ecr.aws, gcr.io, ...) — those are user-managed
|
|
67117
67249
|
* images we don't try to authenticate against.
|
|
67118
67250
|
*/
|
|
67119
67251
|
function parseEcrUri(imageUri) {
|
|
67120
|
-
const
|
|
67252
|
+
const host = parseEcrRegistryHost(imageUri);
|
|
67253
|
+
if (!host) return void 0;
|
|
67254
|
+
const m = /^([^:]+):(.+)$/.exec(imageUri.slice(imageUri.indexOf("/") + 1));
|
|
67121
67255
|
if (!m) return void 0;
|
|
67122
67256
|
return {
|
|
67123
|
-
accountId:
|
|
67124
|
-
region:
|
|
67125
|
-
repository: m[
|
|
67126
|
-
tag: m[
|
|
67257
|
+
accountId: host.accountId,
|
|
67258
|
+
region: host.region,
|
|
67259
|
+
repository: m[1],
|
|
67260
|
+
tag: m[2]
|
|
67127
67261
|
};
|
|
67128
67262
|
}
|
|
67129
67263
|
/**
|
|
@@ -67262,7 +67396,7 @@ async function ecrLogin(client, accountId, region) {
|
|
|
67262
67396
|
if (!authData?.authorizationToken) throw new LocalInvokeBuildError$1("Failed to get ECR authorization token");
|
|
67263
67397
|
const [username, password] = Buffer.from(authData.authorizationToken, "base64").toString().split(":");
|
|
67264
67398
|
if (!username || password === void 0) throw new LocalInvokeBuildError$1("ECR authorization token has unexpected shape (missing username/password)");
|
|
67265
|
-
const endpoint = authData.proxyEndpoint || `https://${accountId}.dkr.ecr.${region}
|
|
67399
|
+
const endpoint = authData.proxyEndpoint || `https://${accountId}.dkr.ecr.${region}.${ecrUrlSuffix(region)}`;
|
|
67266
67400
|
try {
|
|
67267
67401
|
await runDockerStreaming([
|
|
67268
67402
|
"login",
|
|
@@ -74474,7 +74608,7 @@ function createMigrateCommand() {
|
|
|
74474
74608
|
*/
|
|
74475
74609
|
function buildProgram() {
|
|
74476
74610
|
const program = new Command();
|
|
74477
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.281.
|
|
74611
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.281.23");
|
|
74478
74612
|
program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
74479
74613
|
const { profile } = actionCommand.optsWithGlobals();
|
|
74480
74614
|
if (profile !== void 0) process.env["AWS_PROFILE"] = profile;
|