@go-to-k/cdkd 0.14.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/dist/cli.js +1066 -17
- package/dist/cli.js.map +4 -4
- package/dist/go-to-k-cdkd-0.16.0.tgz +0 -0
- package/dist/index.js +134 -0
- package/dist/index.js.map +3 -3
- package/package.json +1 -1
- package/dist/go-to-k-cdkd-0.14.0.tgz +0 -0
package/dist/cli.js
CHANGED
|
@@ -447,7 +447,7 @@ var init_aws_clients = __esm({
|
|
|
447
447
|
});
|
|
448
448
|
|
|
449
449
|
// src/cli/index.ts
|
|
450
|
-
import { Command as
|
|
450
|
+
import { Command as Command12 } from "commander";
|
|
451
451
|
|
|
452
452
|
// src/cli/commands/bootstrap.ts
|
|
453
453
|
import { Command, Option as Option2 } from "commander";
|
|
@@ -1016,7 +1016,7 @@ async function resolveStateBucketWithDefaultAndSource(cliBucket, region) {
|
|
|
1016
1016
|
logger.warn(
|
|
1017
1017
|
`Using legacy state bucket name '${legacyName}'. The default has changed to '${newName}'. To migrate, run:
|
|
1018
1018
|
|
|
1019
|
-
cdkd state migrate
|
|
1019
|
+
cdkd state migrate --region ${region}
|
|
1020
1020
|
|
|
1021
1021
|
(add --remove-legacy to delete the legacy bucket after a successful copy; legacy support will be dropped in a future release.)`
|
|
1022
1022
|
);
|
|
@@ -1030,9 +1030,9 @@ async function resolveStateBucketWithDefaultAndSource(cliBucket, region) {
|
|
|
1030
1030
|
}
|
|
1031
1031
|
}
|
|
1032
1032
|
async function bucketExists(client, bucketName) {
|
|
1033
|
-
const { HeadBucketCommand:
|
|
1033
|
+
const { HeadBucketCommand: HeadBucketCommand5 } = await import("@aws-sdk/client-s3");
|
|
1034
1034
|
try {
|
|
1035
|
-
await client.send(new
|
|
1035
|
+
await client.send(new HeadBucketCommand5({ Bucket: bucketName }));
|
|
1036
1036
|
return true;
|
|
1037
1037
|
} catch (error) {
|
|
1038
1038
|
const err = error;
|
|
@@ -7010,6 +7010,60 @@ Error: ${err.message || "Unknown error"}`,
|
|
|
7010
7010
|
}
|
|
7011
7011
|
return resourceType.startsWith("AWS::");
|
|
7012
7012
|
}
|
|
7013
|
+
/**
|
|
7014
|
+
* Adopt an already-deployed resource into cdkd state via Cloud Control API.
|
|
7015
|
+
*
|
|
7016
|
+
* Strategy: explicit-override only.
|
|
7017
|
+
* - With `knownPhysicalId` (from `--resource <id>=<physicalId>` or
|
|
7018
|
+
* `--resource-mapping`): call `GetResource(TypeName, Identifier)`,
|
|
7019
|
+
* parse `ResourceModel` (returned as a JSON string by CC API), and
|
|
7020
|
+
* return its keys as `attributes`.
|
|
7021
|
+
* - Without `knownPhysicalId`: return `null`. CC API has no efficient
|
|
7022
|
+
* `aws:cdk:path`-tag lookup — `ListResources` returns identifiers
|
|
7023
|
+
* only, so tag lookup would require one `GetResource` per resource
|
|
7024
|
+
* in the account, plus per-service tag-API calls (which CC API
|
|
7025
|
+
* doesn't expose uniformly). Cost vs. value isn't worth it; users
|
|
7026
|
+
* who need adoption for CC-API-only resource types should pass
|
|
7027
|
+
* `--resource <id>=<physicalId>` for those resources.
|
|
7028
|
+
*
|
|
7029
|
+
* SDK providers (S3, Lambda, IAM Role, etc.) implement their own
|
|
7030
|
+
* `import` with tag-based auto-lookup; this fallback only kicks in for
|
|
7031
|
+
* resource types that don't have a dedicated SDK provider.
|
|
7032
|
+
*/
|
|
7033
|
+
async import(input) {
|
|
7034
|
+
if (!input.knownPhysicalId) {
|
|
7035
|
+
return null;
|
|
7036
|
+
}
|
|
7037
|
+
try {
|
|
7038
|
+
const resp = await this.cloudControlClient.send(
|
|
7039
|
+
new GetResourceCommand2({
|
|
7040
|
+
TypeName: input.resourceType,
|
|
7041
|
+
Identifier: input.knownPhysicalId
|
|
7042
|
+
})
|
|
7043
|
+
);
|
|
7044
|
+
let attributes = {};
|
|
7045
|
+
const raw = resp.ResourceDescription?.Properties;
|
|
7046
|
+
if (typeof raw === "string" && raw.length > 0) {
|
|
7047
|
+
try {
|
|
7048
|
+
const parsed = JSON.parse(raw);
|
|
7049
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
7050
|
+
attributes = parsed;
|
|
7051
|
+
}
|
|
7052
|
+
} catch (parseErr) {
|
|
7053
|
+
this.logger.debug(
|
|
7054
|
+
`Failed to parse CC API ResourceModel for ${input.resourceType}/${input.knownPhysicalId}: ${parseErr instanceof Error ? parseErr.message : String(parseErr)}`
|
|
7055
|
+
);
|
|
7056
|
+
}
|
|
7057
|
+
}
|
|
7058
|
+
return { physicalId: input.knownPhysicalId, attributes };
|
|
7059
|
+
} catch (error) {
|
|
7060
|
+
const err = error;
|
|
7061
|
+
if (err.name === "ResourceNotFoundException") {
|
|
7062
|
+
return null;
|
|
7063
|
+
}
|
|
7064
|
+
throw error;
|
|
7065
|
+
}
|
|
7066
|
+
}
|
|
7013
7067
|
};
|
|
7014
7068
|
|
|
7015
7069
|
// src/provisioning/providers/custom-resource-provider.ts
|
|
@@ -7674,6 +7728,8 @@ import {
|
|
|
7674
7728
|
UntagRoleCommand,
|
|
7675
7729
|
PutRolePermissionsBoundaryCommand,
|
|
7676
7730
|
DeleteRolePermissionsBoundaryCommand,
|
|
7731
|
+
ListRolesCommand,
|
|
7732
|
+
ListRoleTagsCommand,
|
|
7677
7733
|
NoSuchEntityException
|
|
7678
7734
|
} from "@aws-sdk/client-iam";
|
|
7679
7735
|
init_aws_clients();
|
|
@@ -7782,6 +7838,32 @@ function applyDefaultNameForFallback(logicalId, resourceType, properties) {
|
|
|
7782
7838
|
};
|
|
7783
7839
|
}
|
|
7784
7840
|
|
|
7841
|
+
// src/provisioning/import-helpers.ts
|
|
7842
|
+
function readNameProperty(input, propertyName) {
|
|
7843
|
+
const value = input.properties?.[propertyName];
|
|
7844
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
7845
|
+
}
|
|
7846
|
+
function resolveExplicitPhysicalId(input, nameProperty) {
|
|
7847
|
+
if (input.knownPhysicalId)
|
|
7848
|
+
return input.knownPhysicalId;
|
|
7849
|
+
if (nameProperty) {
|
|
7850
|
+
const name = readNameProperty(input, nameProperty);
|
|
7851
|
+
if (name)
|
|
7852
|
+
return name;
|
|
7853
|
+
}
|
|
7854
|
+
return void 0;
|
|
7855
|
+
}
|
|
7856
|
+
var CDK_PATH_TAG = "aws:cdk:path";
|
|
7857
|
+
function matchesCdkPath(tags, cdkPath) {
|
|
7858
|
+
if (!tags || !cdkPath)
|
|
7859
|
+
return false;
|
|
7860
|
+
for (const t of tags) {
|
|
7861
|
+
if (t.Key === CDK_PATH_TAG && t.Value === cdkPath)
|
|
7862
|
+
return true;
|
|
7863
|
+
}
|
|
7864
|
+
return false;
|
|
7865
|
+
}
|
|
7866
|
+
|
|
7785
7867
|
// src/provisioning/providers/iam-role-provider.ts
|
|
7786
7868
|
var IAMRoleProvider = class {
|
|
7787
7869
|
iamClient;
|
|
@@ -8288,6 +8370,58 @@ var IAMRoleProvider = class {
|
|
|
8288
8370
|
this.logger.debug(`Added/updated ${tagsToAdd.length} tags on role ${roleName}`);
|
|
8289
8371
|
}
|
|
8290
8372
|
}
|
|
8373
|
+
/**
|
|
8374
|
+
* Adopt an existing IAM role into cdkd state.
|
|
8375
|
+
*
|
|
8376
|
+
* Lookup order:
|
|
8377
|
+
* 1. `--resource` override or `Properties.RoleName` → use directly,
|
|
8378
|
+
* verify via `GetRole`.
|
|
8379
|
+
* 2. `ListRoles` + `ListRoleTags`, match `aws:cdk:path` tag.
|
|
8380
|
+
*
|
|
8381
|
+
* `ListRoles` is paginated and IAM is global (no region scoping), so this
|
|
8382
|
+
* walks every role in the account once. Acceptable for the cardinalities
|
|
8383
|
+
* we expect (typically <100 roles per account); larger accounts may want
|
|
8384
|
+
* to provide `--resource` overrides instead.
|
|
8385
|
+
*/
|
|
8386
|
+
async import(input) {
|
|
8387
|
+
const explicit = resolveExplicitPhysicalId(input, "RoleName");
|
|
8388
|
+
if (explicit) {
|
|
8389
|
+
try {
|
|
8390
|
+
await this.iamClient.send(new GetRoleCommand({ RoleName: explicit }));
|
|
8391
|
+
return { physicalId: explicit, attributes: {} };
|
|
8392
|
+
} catch (err) {
|
|
8393
|
+
if (err instanceof NoSuchEntityException)
|
|
8394
|
+
return null;
|
|
8395
|
+
throw err;
|
|
8396
|
+
}
|
|
8397
|
+
}
|
|
8398
|
+
if (!input.cdkPath)
|
|
8399
|
+
return null;
|
|
8400
|
+
let marker;
|
|
8401
|
+
do {
|
|
8402
|
+
const list = await this.iamClient.send(
|
|
8403
|
+
new ListRolesCommand({ ...marker && { Marker: marker } })
|
|
8404
|
+
);
|
|
8405
|
+
for (const role of list.Roles ?? []) {
|
|
8406
|
+
if (!role.RoleName)
|
|
8407
|
+
continue;
|
|
8408
|
+
try {
|
|
8409
|
+
const tags = await this.iamClient.send(
|
|
8410
|
+
new ListRoleTagsCommand({ RoleName: role.RoleName })
|
|
8411
|
+
);
|
|
8412
|
+
if (matchesCdkPath(tags.Tags, input.cdkPath)) {
|
|
8413
|
+
return { physicalId: role.RoleName, attributes: {} };
|
|
8414
|
+
}
|
|
8415
|
+
} catch (err) {
|
|
8416
|
+
if (err instanceof NoSuchEntityException)
|
|
8417
|
+
continue;
|
|
8418
|
+
throw err;
|
|
8419
|
+
}
|
|
8420
|
+
}
|
|
8421
|
+
marker = list.IsTruncated ? list.Marker : void 0;
|
|
8422
|
+
} while (marker);
|
|
8423
|
+
return null;
|
|
8424
|
+
}
|
|
8291
8425
|
};
|
|
8292
8426
|
|
|
8293
8427
|
// src/provisioning/providers/iam-policy-provider.ts
|
|
@@ -9868,6 +10002,8 @@ var IAMUserGroupProvider = class {
|
|
|
9868
10002
|
import {
|
|
9869
10003
|
CreateBucketCommand as CreateBucketCommand2,
|
|
9870
10004
|
DeleteBucketCommand,
|
|
10005
|
+
HeadBucketCommand as HeadBucketCommand3,
|
|
10006
|
+
ListBucketsCommand,
|
|
9871
10007
|
PutBucketVersioningCommand as PutBucketVersioningCommand2,
|
|
9872
10008
|
PutBucketTaggingCommand,
|
|
9873
10009
|
PutBucketOwnershipControlsCommand,
|
|
@@ -9885,6 +10021,7 @@ import {
|
|
|
9885
10021
|
PutBucketInventoryConfigurationCommand,
|
|
9886
10022
|
PutBucketReplicationCommand,
|
|
9887
10023
|
PutObjectLockConfigurationCommand,
|
|
10024
|
+
GetBucketTaggingCommand,
|
|
9888
10025
|
NoSuchBucket,
|
|
9889
10026
|
ListObjectVersionsCommand,
|
|
9890
10027
|
DeleteObjectsCommand
|
|
@@ -10723,6 +10860,53 @@ var S3BucketProvider = class {
|
|
|
10723
10860
|
);
|
|
10724
10861
|
}
|
|
10725
10862
|
}
|
|
10863
|
+
/**
|
|
10864
|
+
* Adopt an existing S3 bucket into cdkd state.
|
|
10865
|
+
*
|
|
10866
|
+
* Lookup order:
|
|
10867
|
+
* 1. `--resource <id>=<name>` override or `Properties.BucketName` → use directly,
|
|
10868
|
+
* verify with `HeadBucket`.
|
|
10869
|
+
* 2. `ListBuckets` + `GetBucketTagging`, match `aws:cdk:path` against the
|
|
10870
|
+
* CDK construct path.
|
|
10871
|
+
*
|
|
10872
|
+
* Returns `null` when nothing matches — caller treats this as
|
|
10873
|
+
* "not deployed yet" rather than a failure.
|
|
10874
|
+
*/
|
|
10875
|
+
async import(input) {
|
|
10876
|
+
const explicit = resolveExplicitPhysicalId(input, "BucketName");
|
|
10877
|
+
if (explicit) {
|
|
10878
|
+
try {
|
|
10879
|
+
await this.s3Client.send(new HeadBucketCommand3({ Bucket: explicit }));
|
|
10880
|
+
return { physicalId: explicit, attributes: {} };
|
|
10881
|
+
} catch (err) {
|
|
10882
|
+
const e = err;
|
|
10883
|
+
if (e.name === "NotFound" || e.name === "NoSuchBucket") {
|
|
10884
|
+
return null;
|
|
10885
|
+
}
|
|
10886
|
+
throw err;
|
|
10887
|
+
}
|
|
10888
|
+
}
|
|
10889
|
+
if (!input.cdkPath)
|
|
10890
|
+
return null;
|
|
10891
|
+
const list = await this.s3Client.send(new ListBucketsCommand({}));
|
|
10892
|
+
for (const b of list.Buckets ?? []) {
|
|
10893
|
+
if (!b.Name)
|
|
10894
|
+
continue;
|
|
10895
|
+
try {
|
|
10896
|
+
const tagging = await this.s3Client.send(new GetBucketTaggingCommand({ Bucket: b.Name }));
|
|
10897
|
+
if (matchesCdkPath(tagging.TagSet, input.cdkPath)) {
|
|
10898
|
+
return { physicalId: b.Name, attributes: {} };
|
|
10899
|
+
}
|
|
10900
|
+
} catch (err) {
|
|
10901
|
+
const e = err;
|
|
10902
|
+
if (e.name === "NoSuchTagSet" || e.name === "AccessDenied" || e.$metadata?.httpStatusCode === 301) {
|
|
10903
|
+
continue;
|
|
10904
|
+
}
|
|
10905
|
+
throw err;
|
|
10906
|
+
}
|
|
10907
|
+
}
|
|
10908
|
+
return null;
|
|
10909
|
+
}
|
|
10726
10910
|
/**
|
|
10727
10911
|
* Delete a bucket, emptying it first if not empty.
|
|
10728
10912
|
* Handles the race condition where objects (e.g., ALB logs) are written
|
|
@@ -10959,6 +11143,9 @@ import {
|
|
|
10959
11143
|
CreateQueueCommand,
|
|
10960
11144
|
DeleteQueueCommand,
|
|
10961
11145
|
GetQueueAttributesCommand,
|
|
11146
|
+
GetQueueUrlCommand,
|
|
11147
|
+
ListQueuesCommand,
|
|
11148
|
+
ListQueueTagsCommand,
|
|
10962
11149
|
SetQueueAttributesCommand,
|
|
10963
11150
|
QueueDoesNotExist
|
|
10964
11151
|
} from "@aws-sdk/client-sqs";
|
|
@@ -11167,6 +11354,68 @@ var SQSQueueProvider = class {
|
|
|
11167
11354
|
return `arn:aws:sqs:unknown:unknown:${queueName}`;
|
|
11168
11355
|
}
|
|
11169
11356
|
}
|
|
11357
|
+
/**
|
|
11358
|
+
* Adopt an existing SQS queue into cdkd state.
|
|
11359
|
+
*
|
|
11360
|
+
* SQS physical IDs are queue URLs (`https://sqs.us-east-1.amazonaws.com/<account>/<name>`).
|
|
11361
|
+
*
|
|
11362
|
+
* Lookup order:
|
|
11363
|
+
* 1. `--resource` override (URL) → verify via `GetQueueAttributes`.
|
|
11364
|
+
* 2. `Properties.QueueName` → `GetQueueUrl` for direct lookup.
|
|
11365
|
+
* 3. `aws:cdk:path` tag match via `ListQueues` + `ListQueueTags`.
|
|
11366
|
+
*/
|
|
11367
|
+
async import(input) {
|
|
11368
|
+
if (input.knownPhysicalId) {
|
|
11369
|
+
try {
|
|
11370
|
+
await this.sqsClient.send(
|
|
11371
|
+
new GetQueueAttributesCommand({
|
|
11372
|
+
QueueUrl: input.knownPhysicalId,
|
|
11373
|
+
AttributeNames: ["QueueArn"]
|
|
11374
|
+
})
|
|
11375
|
+
);
|
|
11376
|
+
return { physicalId: input.knownPhysicalId, attributes: {} };
|
|
11377
|
+
} catch (err) {
|
|
11378
|
+
if (err instanceof QueueDoesNotExist)
|
|
11379
|
+
return null;
|
|
11380
|
+
throw err;
|
|
11381
|
+
}
|
|
11382
|
+
}
|
|
11383
|
+
const explicitName = resolveExplicitPhysicalId(input, "QueueName");
|
|
11384
|
+
if (explicitName && !input.knownPhysicalId) {
|
|
11385
|
+
try {
|
|
11386
|
+
const resp = await this.sqsClient.send(new GetQueueUrlCommand({ QueueName: explicitName }));
|
|
11387
|
+
if (resp.QueueUrl)
|
|
11388
|
+
return { physicalId: resp.QueueUrl, attributes: {} };
|
|
11389
|
+
return null;
|
|
11390
|
+
} catch (err) {
|
|
11391
|
+
if (err instanceof QueueDoesNotExist)
|
|
11392
|
+
return null;
|
|
11393
|
+
throw err;
|
|
11394
|
+
}
|
|
11395
|
+
}
|
|
11396
|
+
if (!input.cdkPath)
|
|
11397
|
+
return null;
|
|
11398
|
+
let nextToken;
|
|
11399
|
+
do {
|
|
11400
|
+
const list = await this.sqsClient.send(
|
|
11401
|
+
new ListQueuesCommand({ ...nextToken && { NextToken: nextToken } })
|
|
11402
|
+
);
|
|
11403
|
+
for (const url of list.QueueUrls ?? []) {
|
|
11404
|
+
try {
|
|
11405
|
+
const tagsResp = await this.sqsClient.send(new ListQueueTagsCommand({ QueueUrl: url }));
|
|
11406
|
+
if (tagsResp.Tags?.[CDK_PATH_TAG] === input.cdkPath) {
|
|
11407
|
+
return { physicalId: url, attributes: {} };
|
|
11408
|
+
}
|
|
11409
|
+
} catch (err) {
|
|
11410
|
+
if (err instanceof QueueDoesNotExist)
|
|
11411
|
+
continue;
|
|
11412
|
+
throw err;
|
|
11413
|
+
}
|
|
11414
|
+
}
|
|
11415
|
+
nextToken = list.NextToken;
|
|
11416
|
+
} while (nextToken);
|
|
11417
|
+
return null;
|
|
11418
|
+
}
|
|
11170
11419
|
};
|
|
11171
11420
|
|
|
11172
11421
|
// src/provisioning/providers/sqs-queue-policy-provider.ts
|
|
@@ -11329,6 +11578,9 @@ var SQSQueuePolicyProvider = class {
|
|
|
11329
11578
|
import {
|
|
11330
11579
|
CreateTopicCommand,
|
|
11331
11580
|
DeleteTopicCommand,
|
|
11581
|
+
GetTopicAttributesCommand,
|
|
11582
|
+
ListTopicsCommand,
|
|
11583
|
+
ListTagsForResourceCommand,
|
|
11332
11584
|
SetTopicAttributesCommand,
|
|
11333
11585
|
TagResourceCommand,
|
|
11334
11586
|
UntagResourceCommand,
|
|
@@ -11618,6 +11870,63 @@ var SNSTopicProvider = class {
|
|
|
11618
11870
|
);
|
|
11619
11871
|
}
|
|
11620
11872
|
}
|
|
11873
|
+
/**
|
|
11874
|
+
* Adopt an existing SNS topic into cdkd state.
|
|
11875
|
+
*
|
|
11876
|
+
* SNS physical IDs are full ARNs (`arn:aws:sns:...:TopicName`). The
|
|
11877
|
+
* `--resource` override is expected to receive an ARN; bare topic names
|
|
11878
|
+
* trigger a `ListTopics` walk that resolves to the ARN.
|
|
11879
|
+
*
|
|
11880
|
+
* Lookup order:
|
|
11881
|
+
* 1. `--resource` override → trust as ARN, verify via `GetTopicAttributes`.
|
|
11882
|
+
* 2. `Properties.TopicName` → `ListTopics` to find matching ARN.
|
|
11883
|
+
* 3. `aws:cdk:path` tag match via `ListTopics` + `ListTagsForResource`.
|
|
11884
|
+
*/
|
|
11885
|
+
async import(input) {
|
|
11886
|
+
if (input.knownPhysicalId) {
|
|
11887
|
+
try {
|
|
11888
|
+
await this.snsClient.send(
|
|
11889
|
+
new GetTopicAttributesCommand({ TopicArn: input.knownPhysicalId })
|
|
11890
|
+
);
|
|
11891
|
+
return { physicalId: input.knownPhysicalId, attributes: {} };
|
|
11892
|
+
} catch (err) {
|
|
11893
|
+
if (err instanceof NotFoundException)
|
|
11894
|
+
return null;
|
|
11895
|
+
throw err;
|
|
11896
|
+
}
|
|
11897
|
+
}
|
|
11898
|
+
const desiredName = typeof input.properties?.["TopicName"] === "string" ? input.properties["TopicName"] : void 0;
|
|
11899
|
+
let nextToken;
|
|
11900
|
+
do {
|
|
11901
|
+
const list = await this.snsClient.send(
|
|
11902
|
+
new ListTopicsCommand({ ...nextToken && { NextToken: nextToken } })
|
|
11903
|
+
);
|
|
11904
|
+
for (const t of list.Topics ?? []) {
|
|
11905
|
+
if (!t.TopicArn)
|
|
11906
|
+
continue;
|
|
11907
|
+
const arnTail = t.TopicArn.substring(t.TopicArn.lastIndexOf(":") + 1);
|
|
11908
|
+
if (desiredName && arnTail === desiredName) {
|
|
11909
|
+
return { physicalId: t.TopicArn, attributes: {} };
|
|
11910
|
+
}
|
|
11911
|
+
if (input.cdkPath) {
|
|
11912
|
+
try {
|
|
11913
|
+
const tagsResp = await this.snsClient.send(
|
|
11914
|
+
new ListTagsForResourceCommand({ ResourceArn: t.TopicArn })
|
|
11915
|
+
);
|
|
11916
|
+
if (matchesCdkPath(tagsResp.Tags, input.cdkPath)) {
|
|
11917
|
+
return { physicalId: t.TopicArn, attributes: {} };
|
|
11918
|
+
}
|
|
11919
|
+
} catch (err) {
|
|
11920
|
+
if (err instanceof NotFoundException)
|
|
11921
|
+
continue;
|
|
11922
|
+
throw err;
|
|
11923
|
+
}
|
|
11924
|
+
}
|
|
11925
|
+
}
|
|
11926
|
+
nextToken = list.NextToken;
|
|
11927
|
+
} while (nextToken);
|
|
11928
|
+
return null;
|
|
11929
|
+
}
|
|
11621
11930
|
};
|
|
11622
11931
|
|
|
11623
11932
|
// src/provisioning/providers/sns-subscription-provider.ts
|
|
@@ -11917,6 +12226,8 @@ import {
|
|
|
11917
12226
|
UpdateFunctionCodeCommand,
|
|
11918
12227
|
DeleteFunctionCommand,
|
|
11919
12228
|
GetFunctionCommand,
|
|
12229
|
+
ListFunctionsCommand,
|
|
12230
|
+
ListTagsCommand,
|
|
11920
12231
|
ResourceNotFoundException
|
|
11921
12232
|
} from "@aws-sdk/client-lambda";
|
|
11922
12233
|
import {
|
|
@@ -12501,6 +12812,57 @@ var LambdaFunctionProvider = class {
|
|
|
12501
12812
|
}
|
|
12502
12813
|
return (crc ^ 4294967295) >>> 0;
|
|
12503
12814
|
}
|
|
12815
|
+
/**
|
|
12816
|
+
* Adopt an existing Lambda function into cdkd state.
|
|
12817
|
+
*
|
|
12818
|
+
* Lookup order:
|
|
12819
|
+
* 1. `--resource` override or `Properties.FunctionName` → use directly,
|
|
12820
|
+
* verify via `GetFunction`.
|
|
12821
|
+
* 2. `ListFunctions` + `ListTags`, match `aws:cdk:path` tag.
|
|
12822
|
+
*
|
|
12823
|
+
* Lambda's `ListTags` returns a `Tags` map keyed by tag name (unlike
|
|
12824
|
+
* EC2/S3 which return an array of `{Key, Value}`), so we read it directly
|
|
12825
|
+
* instead of going through the shared `matchesCdkPath` helper.
|
|
12826
|
+
*/
|
|
12827
|
+
async import(input) {
|
|
12828
|
+
const explicit = resolveExplicitPhysicalId(input, "FunctionName");
|
|
12829
|
+
if (explicit) {
|
|
12830
|
+
try {
|
|
12831
|
+
await this.lambdaClient.send(new GetFunctionCommand({ FunctionName: explicit }));
|
|
12832
|
+
return { physicalId: explicit, attributes: {} };
|
|
12833
|
+
} catch (err) {
|
|
12834
|
+
if (err instanceof ResourceNotFoundException)
|
|
12835
|
+
return null;
|
|
12836
|
+
throw err;
|
|
12837
|
+
}
|
|
12838
|
+
}
|
|
12839
|
+
if (!input.cdkPath)
|
|
12840
|
+
return null;
|
|
12841
|
+
let marker;
|
|
12842
|
+
do {
|
|
12843
|
+
const list = await this.lambdaClient.send(
|
|
12844
|
+
new ListFunctionsCommand({ ...marker && { Marker: marker } })
|
|
12845
|
+
);
|
|
12846
|
+
for (const fn of list.Functions ?? []) {
|
|
12847
|
+
if (!fn.FunctionArn || !fn.FunctionName)
|
|
12848
|
+
continue;
|
|
12849
|
+
try {
|
|
12850
|
+
const tagsResp = await this.lambdaClient.send(
|
|
12851
|
+
new ListTagsCommand({ Resource: fn.FunctionArn })
|
|
12852
|
+
);
|
|
12853
|
+
if (tagsResp.Tags?.[CDK_PATH_TAG] === input.cdkPath) {
|
|
12854
|
+
return { physicalId: fn.FunctionName, attributes: {} };
|
|
12855
|
+
}
|
|
12856
|
+
} catch (err) {
|
|
12857
|
+
if (err instanceof ResourceNotFoundException)
|
|
12858
|
+
continue;
|
|
12859
|
+
throw err;
|
|
12860
|
+
}
|
|
12861
|
+
}
|
|
12862
|
+
marker = list.NextMarker;
|
|
12863
|
+
} while (marker);
|
|
12864
|
+
return null;
|
|
12865
|
+
}
|
|
12504
12866
|
};
|
|
12505
12867
|
|
|
12506
12868
|
// src/provisioning/providers/lambda-permission-provider.ts
|
|
@@ -13222,6 +13584,8 @@ import {
|
|
|
13222
13584
|
CreateTableCommand,
|
|
13223
13585
|
DeleteTableCommand,
|
|
13224
13586
|
DescribeTableCommand as DescribeTableCommand2,
|
|
13587
|
+
ListTablesCommand,
|
|
13588
|
+
ListTagsOfResourceCommand,
|
|
13225
13589
|
ResourceNotFoundException as ResourceNotFoundException6
|
|
13226
13590
|
} from "@aws-sdk/client-dynamodb";
|
|
13227
13591
|
init_aws_clients();
|
|
@@ -13433,12 +13797,70 @@ var DynamoDBTableProvider = class {
|
|
|
13433
13797
|
}
|
|
13434
13798
|
throw new Error(`Table ${tableName} did not reach ACTIVE status within ${maxAttempts} seconds`);
|
|
13435
13799
|
}
|
|
13800
|
+
/**
|
|
13801
|
+
* Adopt an existing DynamoDB table into cdkd state.
|
|
13802
|
+
*
|
|
13803
|
+
* Lookup order:
|
|
13804
|
+
* 1. `--resource` override or `Properties.TableName` → verify via `DescribeTable`.
|
|
13805
|
+
* 2. `ListTables` + `ListTagsOfResource`, match `aws:cdk:path` tag.
|
|
13806
|
+
*
|
|
13807
|
+
* Tags require the table ARN, which `DescribeTable` provides; the loop
|
|
13808
|
+
* therefore costs one `DescribeTable` per table just to read the ARN.
|
|
13809
|
+
* Acceptable for typical DynamoDB cardinalities.
|
|
13810
|
+
*/
|
|
13811
|
+
async import(input) {
|
|
13812
|
+
const explicit = resolveExplicitPhysicalId(input, "TableName");
|
|
13813
|
+
if (explicit) {
|
|
13814
|
+
try {
|
|
13815
|
+
await this.dynamoDBClient.send(new DescribeTableCommand2({ TableName: explicit }));
|
|
13816
|
+
return { physicalId: explicit, attributes: {} };
|
|
13817
|
+
} catch (err) {
|
|
13818
|
+
if (err instanceof ResourceNotFoundException6)
|
|
13819
|
+
return null;
|
|
13820
|
+
throw err;
|
|
13821
|
+
}
|
|
13822
|
+
}
|
|
13823
|
+
if (!input.cdkPath)
|
|
13824
|
+
return null;
|
|
13825
|
+
let exclusiveStartTableName;
|
|
13826
|
+
do {
|
|
13827
|
+
const list = await this.dynamoDBClient.send(
|
|
13828
|
+
new ListTablesCommand({
|
|
13829
|
+
...exclusiveStartTableName && { ExclusiveStartTableName: exclusiveStartTableName }
|
|
13830
|
+
})
|
|
13831
|
+
);
|
|
13832
|
+
for (const name of list.TableNames ?? []) {
|
|
13833
|
+
try {
|
|
13834
|
+
const desc = await this.dynamoDBClient.send(
|
|
13835
|
+
new DescribeTableCommand2({ TableName: name })
|
|
13836
|
+
);
|
|
13837
|
+
const arn = desc.Table?.TableArn;
|
|
13838
|
+
if (!arn)
|
|
13839
|
+
continue;
|
|
13840
|
+
const tagsResp = await this.dynamoDBClient.send(
|
|
13841
|
+
new ListTagsOfResourceCommand({ ResourceArn: arn })
|
|
13842
|
+
);
|
|
13843
|
+
if (matchesCdkPath(tagsResp.Tags, input.cdkPath)) {
|
|
13844
|
+
return { physicalId: name, attributes: {} };
|
|
13845
|
+
}
|
|
13846
|
+
} catch (err) {
|
|
13847
|
+
if (err instanceof ResourceNotFoundException6)
|
|
13848
|
+
continue;
|
|
13849
|
+
throw err;
|
|
13850
|
+
}
|
|
13851
|
+
}
|
|
13852
|
+
exclusiveStartTableName = list.LastEvaluatedTableName;
|
|
13853
|
+
} while (exclusiveStartTableName);
|
|
13854
|
+
return null;
|
|
13855
|
+
}
|
|
13436
13856
|
};
|
|
13437
13857
|
|
|
13438
13858
|
// src/provisioning/providers/logs-loggroup-provider.ts
|
|
13439
13859
|
import {
|
|
13440
13860
|
CreateLogGroupCommand,
|
|
13441
13861
|
DeleteLogGroupCommand,
|
|
13862
|
+
DescribeLogGroupsCommand,
|
|
13863
|
+
ListTagsForResourceCommand as ListTagsForResourceCommand2,
|
|
13442
13864
|
PutRetentionPolicyCommand,
|
|
13443
13865
|
DeleteRetentionPolicyCommand,
|
|
13444
13866
|
TagResourceCommand as TagResourceCommand2,
|
|
@@ -13662,6 +14084,61 @@ var LogsLogGroupProvider = class {
|
|
|
13662
14084
|
return `arn:aws:logs:unknown:unknown:log-group:${logGroupName}:*`;
|
|
13663
14085
|
}
|
|
13664
14086
|
}
|
|
14087
|
+
/**
|
|
14088
|
+
* Adopt an existing CloudWatch Logs log group into cdkd state.
|
|
14089
|
+
*
|
|
14090
|
+
* Lookup order:
|
|
14091
|
+
* 1. `--resource` override or `Properties.LogGroupName` → verify via
|
|
14092
|
+
* `DescribeLogGroups` (filtered by name prefix).
|
|
14093
|
+
* 2. `aws:cdk:path` tag match via `DescribeLogGroups` + `ListTagsForResource`.
|
|
14094
|
+
*
|
|
14095
|
+
* `ListTagsForResource` for log groups uses the log-group ARN. The
|
|
14096
|
+
* `DescribeLogGroups` response includes the ARN, so no extra round-trip
|
|
14097
|
+
* is needed beyond the per-group tag lookup.
|
|
14098
|
+
*/
|
|
14099
|
+
async import(input) {
|
|
14100
|
+
const explicit = resolveExplicitPhysicalId(input, "LogGroupName");
|
|
14101
|
+
if (explicit) {
|
|
14102
|
+
try {
|
|
14103
|
+
const resp = await this.logsClient.send(
|
|
14104
|
+
new DescribeLogGroupsCommand({ logGroupNamePrefix: explicit })
|
|
14105
|
+
);
|
|
14106
|
+
const found = resp.logGroups?.find((g) => g.logGroupName === explicit);
|
|
14107
|
+
return found ? { physicalId: explicit, attributes: {} } : null;
|
|
14108
|
+
} catch (err) {
|
|
14109
|
+
if (err instanceof ResourceNotFoundException7)
|
|
14110
|
+
return null;
|
|
14111
|
+
throw err;
|
|
14112
|
+
}
|
|
14113
|
+
}
|
|
14114
|
+
if (!input.cdkPath)
|
|
14115
|
+
return null;
|
|
14116
|
+
let nextToken;
|
|
14117
|
+
do {
|
|
14118
|
+
const list = await this.logsClient.send(
|
|
14119
|
+
new DescribeLogGroupsCommand({ ...nextToken && { nextToken } })
|
|
14120
|
+
);
|
|
14121
|
+
for (const g of list.logGroups ?? []) {
|
|
14122
|
+
if (!g.logGroupName || !g.arn)
|
|
14123
|
+
continue;
|
|
14124
|
+
const arnForTags = g.arn.replace(/:\*$/, "");
|
|
14125
|
+
try {
|
|
14126
|
+
const tagsResp = await this.logsClient.send(
|
|
14127
|
+
new ListTagsForResourceCommand2({ resourceArn: arnForTags })
|
|
14128
|
+
);
|
|
14129
|
+
if (tagsResp.tags?.["aws:cdk:path"] === input.cdkPath) {
|
|
14130
|
+
return { physicalId: g.logGroupName, attributes: {} };
|
|
14131
|
+
}
|
|
14132
|
+
} catch (err) {
|
|
14133
|
+
if (err instanceof ResourceNotFoundException7)
|
|
14134
|
+
continue;
|
|
14135
|
+
throw err;
|
|
14136
|
+
}
|
|
14137
|
+
}
|
|
14138
|
+
nextToken = list.nextToken;
|
|
14139
|
+
} while (nextToken);
|
|
14140
|
+
return null;
|
|
14141
|
+
}
|
|
13665
14142
|
};
|
|
13666
14143
|
|
|
13667
14144
|
// src/provisioning/providers/cloudwatch-alarm-provider.ts
|
|
@@ -13892,6 +14369,8 @@ var CloudWatchAlarmProvider = class {
|
|
|
13892
14369
|
import {
|
|
13893
14370
|
CreateSecretCommand,
|
|
13894
14371
|
DeleteSecretCommand,
|
|
14372
|
+
DescribeSecretCommand,
|
|
14373
|
+
ListSecretsCommand,
|
|
13895
14374
|
UpdateSecretCommand,
|
|
13896
14375
|
TagResourceCommand as TagResourceCommand3,
|
|
13897
14376
|
UntagResourceCommand as UntagResourceCommand3,
|
|
@@ -14159,10 +14638,65 @@ var SecretsManagerSecretProvider = class {
|
|
|
14159
14638
|
}
|
|
14160
14639
|
return password;
|
|
14161
14640
|
}
|
|
14641
|
+
/**
|
|
14642
|
+
* Adopt an existing Secrets Manager secret into cdkd state.
|
|
14643
|
+
*
|
|
14644
|
+
* Secrets Manager physical IDs are full secret ARNs. The CDK template's
|
|
14645
|
+
* `Properties.Name` (secret name) is enough to fetch the ARN via
|
|
14646
|
+
* `DescribeSecret`.
|
|
14647
|
+
*
|
|
14648
|
+
* Lookup order:
|
|
14649
|
+
* 1. `--resource` override (ARN) → verify via `DescribeSecret`.
|
|
14650
|
+
* 2. `Properties.Name` → `DescribeSecret` (accepts name).
|
|
14651
|
+
* 3. `aws:cdk:path` tag match via `ListSecrets` (which already returns Tags).
|
|
14652
|
+
*/
|
|
14653
|
+
async import(input) {
|
|
14654
|
+
if (input.knownPhysicalId) {
|
|
14655
|
+
try {
|
|
14656
|
+
const resp = await this.smClient.send(
|
|
14657
|
+
new DescribeSecretCommand({ SecretId: input.knownPhysicalId })
|
|
14658
|
+
);
|
|
14659
|
+
return resp.ARN ? { physicalId: resp.ARN, attributes: {} } : null;
|
|
14660
|
+
} catch (err) {
|
|
14661
|
+
if (err instanceof ResourceNotFoundException8)
|
|
14662
|
+
return null;
|
|
14663
|
+
throw err;
|
|
14664
|
+
}
|
|
14665
|
+
}
|
|
14666
|
+
const name = typeof input.properties?.["Name"] === "string" ? input.properties["Name"] : void 0;
|
|
14667
|
+
if (name) {
|
|
14668
|
+
try {
|
|
14669
|
+
const resp = await this.smClient.send(new DescribeSecretCommand({ SecretId: name }));
|
|
14670
|
+
return resp.ARN ? { physicalId: resp.ARN, attributes: {} } : null;
|
|
14671
|
+
} catch (err) {
|
|
14672
|
+
if (err instanceof ResourceNotFoundException8)
|
|
14673
|
+
return null;
|
|
14674
|
+
throw err;
|
|
14675
|
+
}
|
|
14676
|
+
}
|
|
14677
|
+
if (!input.cdkPath)
|
|
14678
|
+
return null;
|
|
14679
|
+
let nextToken;
|
|
14680
|
+
do {
|
|
14681
|
+
const list = await this.smClient.send(
|
|
14682
|
+
new ListSecretsCommand({ ...nextToken && { NextToken: nextToken } })
|
|
14683
|
+
);
|
|
14684
|
+
for (const s of list.SecretList ?? []) {
|
|
14685
|
+
if (s.ARN && matchesCdkPath(s.Tags, input.cdkPath)) {
|
|
14686
|
+
return { physicalId: s.ARN, attributes: {} };
|
|
14687
|
+
}
|
|
14688
|
+
}
|
|
14689
|
+
nextToken = list.NextToken;
|
|
14690
|
+
} while (nextToken);
|
|
14691
|
+
return null;
|
|
14692
|
+
}
|
|
14162
14693
|
};
|
|
14163
14694
|
|
|
14164
14695
|
// src/provisioning/providers/ssm-parameter-provider.ts
|
|
14165
14696
|
import {
|
|
14697
|
+
DescribeParametersCommand,
|
|
14698
|
+
GetParameterCommand as GetParameterCommand3,
|
|
14699
|
+
ListTagsForResourceCommand as ListTagsForResourceCommand3,
|
|
14166
14700
|
PutParameterCommand,
|
|
14167
14701
|
DeleteParameterCommand,
|
|
14168
14702
|
AddTagsToResourceCommand,
|
|
@@ -14374,6 +14908,57 @@ var SSMParameterProvider = class {
|
|
|
14374
14908
|
);
|
|
14375
14909
|
}
|
|
14376
14910
|
}
|
|
14911
|
+
/**
|
|
14912
|
+
* Adopt an existing SSM parameter into cdkd state.
|
|
14913
|
+
*
|
|
14914
|
+
* SSM physical IDs ARE the parameter names (`/foo/bar`). The CDK template
|
|
14915
|
+
* usually carries `Properties.Name` explicitly, so the explicit-name path
|
|
14916
|
+
* covers most cases. The tag-based fallback is rarely needed.
|
|
14917
|
+
*
|
|
14918
|
+
* Lookup order:
|
|
14919
|
+
* 1. `--resource` override or `Properties.Name` → verify via `GetParameter`.
|
|
14920
|
+
* 2. `aws:cdk:path` tag match via `DescribeParameters` + `ListTagsForResource`
|
|
14921
|
+
* (`ResourceType: 'Parameter'`, `ResourceId: <name>`).
|
|
14922
|
+
*/
|
|
14923
|
+
async import(input) {
|
|
14924
|
+
const explicit = resolveExplicitPhysicalId(input, "Name");
|
|
14925
|
+
if (explicit) {
|
|
14926
|
+
try {
|
|
14927
|
+
await this.ssmClient.send(new GetParameterCommand3({ Name: explicit }));
|
|
14928
|
+
return { physicalId: explicit, attributes: {} };
|
|
14929
|
+
} catch (err) {
|
|
14930
|
+
if (err instanceof ParameterNotFound)
|
|
14931
|
+
return null;
|
|
14932
|
+
throw err;
|
|
14933
|
+
}
|
|
14934
|
+
}
|
|
14935
|
+
if (!input.cdkPath)
|
|
14936
|
+
return null;
|
|
14937
|
+
let nextToken;
|
|
14938
|
+
do {
|
|
14939
|
+
const list = await this.ssmClient.send(
|
|
14940
|
+
new DescribeParametersCommand({ ...nextToken && { NextToken: nextToken } })
|
|
14941
|
+
);
|
|
14942
|
+
for (const p of list.Parameters ?? []) {
|
|
14943
|
+
if (!p.Name)
|
|
14944
|
+
continue;
|
|
14945
|
+
try {
|
|
14946
|
+
const tagsResp = await this.ssmClient.send(
|
|
14947
|
+
new ListTagsForResourceCommand3({ ResourceType: "Parameter", ResourceId: p.Name })
|
|
14948
|
+
);
|
|
14949
|
+
if (matchesCdkPath(tagsResp.TagList, input.cdkPath)) {
|
|
14950
|
+
return { physicalId: p.Name, attributes: {} };
|
|
14951
|
+
}
|
|
14952
|
+
} catch (err) {
|
|
14953
|
+
if (err instanceof ParameterNotFound)
|
|
14954
|
+
continue;
|
|
14955
|
+
throw err;
|
|
14956
|
+
}
|
|
14957
|
+
}
|
|
14958
|
+
nextToken = list.NextToken;
|
|
14959
|
+
} while (nextToken);
|
|
14960
|
+
return null;
|
|
14961
|
+
}
|
|
14377
14962
|
};
|
|
14378
14963
|
|
|
14379
14964
|
// src/provisioning/providers/eventbridge-rule-provider.ts
|
|
@@ -14672,7 +15257,9 @@ import {
|
|
|
14672
15257
|
DeleteEventBusCommand,
|
|
14673
15258
|
UpdateEventBusCommand,
|
|
14674
15259
|
DescribeEventBusCommand,
|
|
15260
|
+
ListEventBusesCommand,
|
|
14675
15261
|
ListRulesCommand,
|
|
15262
|
+
ListTagsForResourceCommand as ListTagsForResourceCommand4,
|
|
14676
15263
|
RemoveTargetsCommand as RemoveTargetsCommand2,
|
|
14677
15264
|
DeleteRuleCommand as DeleteRuleCommand2,
|
|
14678
15265
|
ListTargetsByRuleCommand as ListTargetsByRuleCommand2,
|
|
@@ -14913,6 +15500,52 @@ var EventBridgeBusProvider = class {
|
|
|
14913
15500
|
);
|
|
14914
15501
|
}
|
|
14915
15502
|
}
|
|
15503
|
+
/**
|
|
15504
|
+
* Adopt an existing EventBridge event bus into cdkd state.
|
|
15505
|
+
*
|
|
15506
|
+
* Lookup order:
|
|
15507
|
+
* 1. `--resource` override or `Properties.Name` → verify via `DescribeEventBus`.
|
|
15508
|
+
* 2. `aws:cdk:path` tag match via `ListEventBuses` + `ListTagsForResource`.
|
|
15509
|
+
*/
|
|
15510
|
+
async import(input) {
|
|
15511
|
+
const explicit = resolveExplicitPhysicalId(input, "Name");
|
|
15512
|
+
if (explicit) {
|
|
15513
|
+
try {
|
|
15514
|
+
await this.eventBridgeClient.send(new DescribeEventBusCommand({ Name: explicit }));
|
|
15515
|
+
return { physicalId: explicit, attributes: {} };
|
|
15516
|
+
} catch (err) {
|
|
15517
|
+
if (err instanceof ResourceNotFoundException10)
|
|
15518
|
+
return null;
|
|
15519
|
+
throw err;
|
|
15520
|
+
}
|
|
15521
|
+
}
|
|
15522
|
+
if (!input.cdkPath)
|
|
15523
|
+
return null;
|
|
15524
|
+
let nextToken;
|
|
15525
|
+
do {
|
|
15526
|
+
const list = await this.eventBridgeClient.send(
|
|
15527
|
+
new ListEventBusesCommand({ ...nextToken && { NextToken: nextToken } })
|
|
15528
|
+
);
|
|
15529
|
+
for (const bus of list.EventBuses ?? []) {
|
|
15530
|
+
if (!bus.Name || !bus.Arn)
|
|
15531
|
+
continue;
|
|
15532
|
+
try {
|
|
15533
|
+
const tagsResp = await this.eventBridgeClient.send(
|
|
15534
|
+
new ListTagsForResourceCommand4({ ResourceARN: bus.Arn })
|
|
15535
|
+
);
|
|
15536
|
+
if (matchesCdkPath(tagsResp.Tags, input.cdkPath)) {
|
|
15537
|
+
return { physicalId: bus.Name, attributes: {} };
|
|
15538
|
+
}
|
|
15539
|
+
} catch (err) {
|
|
15540
|
+
if (err instanceof ResourceNotFoundException10)
|
|
15541
|
+
continue;
|
|
15542
|
+
throw err;
|
|
15543
|
+
}
|
|
15544
|
+
}
|
|
15545
|
+
nextToken = list.NextToken;
|
|
15546
|
+
} while (nextToken);
|
|
15547
|
+
return null;
|
|
15548
|
+
}
|
|
14916
15549
|
};
|
|
14917
15550
|
|
|
14918
15551
|
// src/provisioning/providers/ec2-provider.ts
|
|
@@ -24219,6 +24852,10 @@ var GlueProvider = class {
|
|
|
24219
24852
|
import {
|
|
24220
24853
|
KMSClient as KMSClient2,
|
|
24221
24854
|
CreateKeyCommand,
|
|
24855
|
+
DescribeKeyCommand,
|
|
24856
|
+
ListAliasesCommand as ListAliasesCommand2,
|
|
24857
|
+
ListKeysCommand,
|
|
24858
|
+
ListResourceTagsCommand,
|
|
24222
24859
|
ScheduleKeyDeletionCommand,
|
|
24223
24860
|
CreateAliasCommand,
|
|
24224
24861
|
DeleteAliasCommand,
|
|
@@ -24601,6 +25238,81 @@ var KMSProvider = class {
|
|
|
24601
25238
|
);
|
|
24602
25239
|
}
|
|
24603
25240
|
}
|
|
25241
|
+
/**
|
|
25242
|
+
* Adopt an existing KMS key or alias into cdkd state.
|
|
25243
|
+
*
|
|
25244
|
+
* KMS keys have no `Properties.KeyName` field — physical IDs are
|
|
25245
|
+
* AWS-generated UUIDs. So:
|
|
25246
|
+
* - For `AWS::KMS::Key`: `--resource MyKey=<keyId>` is the only explicit
|
|
25247
|
+
* path; auto-lookup walks `ListKeys` + `ListResourceTags` matching
|
|
25248
|
+
* `aws:cdk:path`.
|
|
25249
|
+
* - For `AWS::KMS::Alias`: `Properties.AliasName` is explicit and reliable.
|
|
25250
|
+
*/
|
|
25251
|
+
async import(input) {
|
|
25252
|
+
if (input.resourceType === "AWS::KMS::Alias") {
|
|
25253
|
+
const aliasName = input.knownPhysicalId ?? (typeof input.properties?.["AliasName"] === "string" ? input.properties["AliasName"] : void 0);
|
|
25254
|
+
if (!aliasName)
|
|
25255
|
+
return null;
|
|
25256
|
+
try {
|
|
25257
|
+
let marker2;
|
|
25258
|
+
do {
|
|
25259
|
+
const list = await this.getClient().send(
|
|
25260
|
+
new ListAliasesCommand2({ ...marker2 && { Marker: marker2 } })
|
|
25261
|
+
);
|
|
25262
|
+
const found = list.Aliases?.find(
|
|
25263
|
+
(a) => a.AliasName === aliasName
|
|
25264
|
+
);
|
|
25265
|
+
if (found)
|
|
25266
|
+
return { physicalId: aliasName, attributes: {} };
|
|
25267
|
+
marker2 = list.NextMarker;
|
|
25268
|
+
} while (marker2);
|
|
25269
|
+
return null;
|
|
25270
|
+
} catch (err) {
|
|
25271
|
+
if (err instanceof NotFoundException5)
|
|
25272
|
+
return null;
|
|
25273
|
+
throw err;
|
|
25274
|
+
}
|
|
25275
|
+
}
|
|
25276
|
+
if (input.knownPhysicalId) {
|
|
25277
|
+
try {
|
|
25278
|
+
await this.getClient().send(new DescribeKeyCommand({ KeyId: input.knownPhysicalId }));
|
|
25279
|
+
return { physicalId: input.knownPhysicalId, attributes: {} };
|
|
25280
|
+
} catch (err) {
|
|
25281
|
+
if (err instanceof NotFoundException5)
|
|
25282
|
+
return null;
|
|
25283
|
+
throw err;
|
|
25284
|
+
}
|
|
25285
|
+
}
|
|
25286
|
+
if (!input.cdkPath)
|
|
25287
|
+
return null;
|
|
25288
|
+
let marker;
|
|
25289
|
+
do {
|
|
25290
|
+
const list = await this.getClient().send(
|
|
25291
|
+
new ListKeysCommand({ ...marker && { Marker: marker } })
|
|
25292
|
+
);
|
|
25293
|
+
for (const key of list.Keys ?? []) {
|
|
25294
|
+
if (!key.KeyId)
|
|
25295
|
+
continue;
|
|
25296
|
+
try {
|
|
25297
|
+
const tagsResp = await this.getClient().send(
|
|
25298
|
+
new ListResourceTagsCommand({ KeyId: key.KeyId })
|
|
25299
|
+
);
|
|
25300
|
+
for (const tag of tagsResp.Tags ?? []) {
|
|
25301
|
+
if (tag.TagKey === CDK_PATH_TAG && tag.TagValue === input.cdkPath) {
|
|
25302
|
+
return { physicalId: key.KeyId, attributes: {} };
|
|
25303
|
+
}
|
|
25304
|
+
}
|
|
25305
|
+
} catch (err) {
|
|
25306
|
+
const name = err.name;
|
|
25307
|
+
if (name === "AccessDeniedException" || err instanceof NotFoundException5)
|
|
25308
|
+
continue;
|
|
25309
|
+
throw err;
|
|
25310
|
+
}
|
|
25311
|
+
}
|
|
25312
|
+
marker = list.NextMarker;
|
|
25313
|
+
} while (marker);
|
|
25314
|
+
return null;
|
|
25315
|
+
}
|
|
24604
25316
|
};
|
|
24605
25317
|
|
|
24606
25318
|
// src/provisioning/providers/kinesis-provider.ts
|
|
@@ -26579,7 +27291,7 @@ import {
|
|
|
26579
27291
|
CreateTableCommand as CreateTableCommand3,
|
|
26580
27292
|
DeleteTableCommand as DeleteTableCommand3,
|
|
26581
27293
|
ListNamespacesCommand,
|
|
26582
|
-
ListTablesCommand,
|
|
27294
|
+
ListTablesCommand as ListTablesCommand2,
|
|
26583
27295
|
NotFoundException as NotFoundException6
|
|
26584
27296
|
} from "@aws-sdk/client-s3tables";
|
|
26585
27297
|
var S3TablesProvider = class {
|
|
@@ -26725,7 +27437,7 @@ var S3TablesProvider = class {
|
|
|
26725
27437
|
let tableContinuationToken;
|
|
26726
27438
|
do {
|
|
26727
27439
|
const tablesResult = await this.getClient().send(
|
|
26728
|
-
new
|
|
27440
|
+
new ListTablesCommand2({
|
|
26729
27441
|
tableBucketARN,
|
|
26730
27442
|
namespace: namespaceName,
|
|
26731
27443
|
continuationToken: tableContinuationToken
|
|
@@ -29564,7 +30276,7 @@ import {
|
|
|
29564
30276
|
} from "@aws-sdk/client-s3";
|
|
29565
30277
|
init_aws_clients();
|
|
29566
30278
|
|
|
29567
|
-
// src/cli/commands/state-migrate
|
|
30279
|
+
// src/cli/commands/state-migrate.ts
|
|
29568
30280
|
import * as readline2 from "node:readline/promises";
|
|
29569
30281
|
import { Command as Command9 } from "commander";
|
|
29570
30282
|
import {
|
|
@@ -29572,7 +30284,7 @@ import {
|
|
|
29572
30284
|
CreateBucketCommand as CreateBucketCommand4,
|
|
29573
30285
|
DeleteBucketCommand as DeleteBucketCommand3,
|
|
29574
30286
|
DeleteObjectsCommand as DeleteObjectsCommand3,
|
|
29575
|
-
HeadBucketCommand as
|
|
30287
|
+
HeadBucketCommand as HeadBucketCommand4,
|
|
29576
30288
|
ListObjectVersionsCommand as ListObjectVersionsCommand2,
|
|
29577
30289
|
ListObjectsV2Command as ListObjectsV2Command3,
|
|
29578
30290
|
PutBucketEncryptionCommand as PutBucketEncryptionCommand3,
|
|
@@ -29582,7 +30294,7 @@ import {
|
|
|
29582
30294
|
} from "@aws-sdk/client-s3";
|
|
29583
30295
|
import { GetCallerIdentityCommand as GetCallerIdentityCommand8 } from "@aws-sdk/client-sts";
|
|
29584
30296
|
init_aws_clients();
|
|
29585
|
-
async function
|
|
30297
|
+
async function stateMigrateCommand(options) {
|
|
29586
30298
|
const logger = getLogger();
|
|
29587
30299
|
if (options.verbose)
|
|
29588
30300
|
logger.setLevel("debug");
|
|
@@ -29695,7 +30407,7 @@ async function stateMigrateBucketCommand(options) {
|
|
|
29695
30407
|
}
|
|
29696
30408
|
async function bucketExists2(s3, bucketName) {
|
|
29697
30409
|
try {
|
|
29698
|
-
await s3.send(new
|
|
30410
|
+
await s3.send(new HeadBucketCommand4({ Bucket: bucketName }));
|
|
29699
30411
|
return true;
|
|
29700
30412
|
} catch (error) {
|
|
29701
30413
|
const err = error;
|
|
@@ -29848,8 +30560,8 @@ async function confirmPrompt(prompt) {
|
|
|
29848
30560
|
rl.close();
|
|
29849
30561
|
}
|
|
29850
30562
|
}
|
|
29851
|
-
function
|
|
29852
|
-
const cmd = new Command9("migrate
|
|
30563
|
+
function createStateMigrateCommand() {
|
|
30564
|
+
const cmd = new Command9("migrate").description(
|
|
29853
30565
|
"Migrate state from the legacy region-suffixed bucket (cdkd-state-{account}-{region}) to the new region-free default (cdkd-state-{account}). Source bucket is kept by default; pass --remove-legacy to delete it after a successful migration."
|
|
29854
30566
|
).option(
|
|
29855
30567
|
"--region <region>",
|
|
@@ -29864,7 +30576,7 @@ function createStateMigrateBucketCommand() {
|
|
|
29864
30576
|
"--remove-legacy",
|
|
29865
30577
|
"Delete the source bucket after successful migration. Default: keep it.",
|
|
29866
30578
|
false
|
|
29867
|
-
).action(withErrorHandling(
|
|
30579
|
+
).action(withErrorHandling(stateMigrateCommand));
|
|
29868
30580
|
commonOptions.forEach((o) => cmd.addOption(o));
|
|
29869
30581
|
return cmd;
|
|
29870
30582
|
}
|
|
@@ -30438,7 +31150,7 @@ function formatBucketSource(source) {
|
|
|
30438
31150
|
case "default":
|
|
30439
31151
|
return "default (account ID from STS)";
|
|
30440
31152
|
case "default-legacy":
|
|
30441
|
-
return "default (legacy region-suffixed name; cdkd state migrate
|
|
31153
|
+
return "default (legacy region-suffixed name; cdkd state migrate recommended)";
|
|
30442
31154
|
}
|
|
30443
31155
|
}
|
|
30444
31156
|
async function detectBucketRegion(awsClients, bucket) {
|
|
@@ -30553,9 +31265,344 @@ function createStateCommand() {
|
|
|
30553
31265
|
cmd.addCommand(createStateShowCommand());
|
|
30554
31266
|
cmd.addCommand(createStateRmCommand());
|
|
30555
31267
|
cmd.addCommand(createStateDestroyCommand());
|
|
30556
|
-
cmd.addCommand(
|
|
31268
|
+
cmd.addCommand(createStateMigrateCommand());
|
|
31269
|
+
return cmd;
|
|
31270
|
+
}
|
|
31271
|
+
|
|
31272
|
+
// src/cli/commands/import.ts
|
|
31273
|
+
import { readFileSync as readFileSync5 } from "node:fs";
|
|
31274
|
+
import * as readline4 from "node:readline/promises";
|
|
31275
|
+
import { Command as Command11 } from "commander";
|
|
31276
|
+
init_aws_clients();
|
|
31277
|
+
async function importCommand(stackArg, options) {
|
|
31278
|
+
const logger = getLogger();
|
|
31279
|
+
if (options.verbose) {
|
|
31280
|
+
logger.setLevel("debug");
|
|
31281
|
+
process.env["CDKD_NO_LIVE"] = "1";
|
|
31282
|
+
}
|
|
31283
|
+
const region = options.region || process.env["AWS_REGION"] || "us-east-1";
|
|
31284
|
+
const stateBucket = await resolveStateBucketWithDefault(options.stateBucket, region);
|
|
31285
|
+
if (options.region) {
|
|
31286
|
+
process.env["AWS_REGION"] = options.region;
|
|
31287
|
+
process.env["AWS_DEFAULT_REGION"] = options.region;
|
|
31288
|
+
}
|
|
31289
|
+
const awsClients = new AwsClients({
|
|
31290
|
+
...options.region && { region: options.region },
|
|
31291
|
+
...options.profile && { profile: options.profile }
|
|
31292
|
+
});
|
|
31293
|
+
setAwsClients(awsClients);
|
|
31294
|
+
try {
|
|
31295
|
+
const stateConfig = { bucket: stateBucket, prefix: options.statePrefix };
|
|
31296
|
+
const stateBackend = new S3StateBackend(awsClients.s3, stateConfig, {
|
|
31297
|
+
...options.region && { region: options.region },
|
|
31298
|
+
...options.profile && { profile: options.profile }
|
|
31299
|
+
});
|
|
31300
|
+
await stateBackend.verifyBucketExists();
|
|
31301
|
+
const lockManager = new LockManager(awsClients.s3, stateConfig);
|
|
31302
|
+
const providerRegistry = new ProviderRegistry();
|
|
31303
|
+
registerAllProviders(providerRegistry);
|
|
31304
|
+
const appCmd = options.app || resolveApp();
|
|
31305
|
+
if (!appCmd) {
|
|
31306
|
+
throw new Error(
|
|
31307
|
+
"`cdkd state import` requires a CDK app: pass --app or set it in cdk.json. The template is read to find logical IDs, resource types, and dependencies."
|
|
31308
|
+
);
|
|
31309
|
+
}
|
|
31310
|
+
logger.info("Synthesizing CDK app to read template...");
|
|
31311
|
+
const synthesizer = new Synthesizer();
|
|
31312
|
+
const context = parseContextOptions(options.context);
|
|
31313
|
+
const result = await synthesizer.synthesize({
|
|
31314
|
+
app: appCmd,
|
|
31315
|
+
output: options.output || "cdk.out",
|
|
31316
|
+
...Object.keys(context).length > 0 && { context }
|
|
31317
|
+
});
|
|
31318
|
+
let stackInfo;
|
|
31319
|
+
if (stackArg) {
|
|
31320
|
+
stackInfo = result.stacks.find((s) => s.stackName === stackArg || s.displayName === stackArg);
|
|
31321
|
+
if (!stackInfo) {
|
|
31322
|
+
throw new Error(
|
|
31323
|
+
`Stack '${stackArg}' not found in synthesized app. Available: ${result.stacks.map((s) => s.stackName).join(", ")}`
|
|
31324
|
+
);
|
|
31325
|
+
}
|
|
31326
|
+
} else if (result.stacks.length === 1) {
|
|
31327
|
+
stackInfo = result.stacks[0];
|
|
31328
|
+
} else {
|
|
31329
|
+
throw new Error(
|
|
31330
|
+
`Multiple stacks found: ${result.stacks.map((s) => s.stackName).join(", ")}. Specify the stack name as a positional argument.`
|
|
31331
|
+
);
|
|
31332
|
+
}
|
|
31333
|
+
const targetRegion = stackInfo.region || region;
|
|
31334
|
+
logger.info(`Target stack: ${stackInfo.stackName} (${targetRegion})`);
|
|
31335
|
+
const existing = await stateBackend.stateExists(stackInfo.stackName, targetRegion);
|
|
31336
|
+
if (existing && !options.force) {
|
|
31337
|
+
throw new Error(
|
|
31338
|
+
`State already exists for stack '${stackInfo.stackName}' (${targetRegion}). Pass --force to overwrite. (cdkd state import rebuilds the resource map from AWS, so the existing state \u2014 including any drift you've manually edited \u2014 will be lost.)`
|
|
31339
|
+
);
|
|
31340
|
+
}
|
|
31341
|
+
const overrides = parseResourceOverrides(options.resource, options.resourceMapping);
|
|
31342
|
+
if (overrides.size > 0) {
|
|
31343
|
+
logger.debug(`User-supplied physical IDs: ${[...overrides.keys()].join(", ")}`);
|
|
31344
|
+
}
|
|
31345
|
+
const template = stackInfo.template;
|
|
31346
|
+
const templateParser = new TemplateParser();
|
|
31347
|
+
const resources = collectImportableResources(template);
|
|
31348
|
+
logger.info(`Found ${resources.length} resource(s) in template`);
|
|
31349
|
+
const owner = `${process.env["USER"] || "unknown"}@${process.env["HOSTNAME"] || "host"}:${process.pid}`;
|
|
31350
|
+
await lockManager.acquireLock(stackInfo.stackName, targetRegion, owner, "import");
|
|
31351
|
+
try {
|
|
31352
|
+
const rows = [];
|
|
31353
|
+
for (const { logicalId, resource } of resources) {
|
|
31354
|
+
const outcome = await importOne({
|
|
31355
|
+
logicalId,
|
|
31356
|
+
resource,
|
|
31357
|
+
stackName: stackInfo.stackName,
|
|
31358
|
+
region: targetRegion,
|
|
31359
|
+
providerRegistry,
|
|
31360
|
+
override: overrides.get(logicalId)
|
|
31361
|
+
});
|
|
31362
|
+
rows.push(outcome);
|
|
31363
|
+
}
|
|
31364
|
+
printSummary(rows);
|
|
31365
|
+
if (options.dryRun) {
|
|
31366
|
+
logger.info("--dry-run: state will NOT be written. Re-run without --dry-run to apply.");
|
|
31367
|
+
return;
|
|
31368
|
+
}
|
|
31369
|
+
const importedRows = rows.filter((r) => r.outcome === "imported");
|
|
31370
|
+
if (importedRows.length === 0) {
|
|
31371
|
+
logger.warn("No resources were successfully imported. State will not be written.");
|
|
31372
|
+
return;
|
|
31373
|
+
}
|
|
31374
|
+
if (!options.yes) {
|
|
31375
|
+
const ok = await confirmPrompt2(
|
|
31376
|
+
`Write state for ${stackInfo.stackName} (${targetRegion}) with ${importedRows.length} resource(s)?`
|
|
31377
|
+
);
|
|
31378
|
+
if (!ok) {
|
|
31379
|
+
logger.info("Import cancelled.");
|
|
31380
|
+
return;
|
|
31381
|
+
}
|
|
31382
|
+
}
|
|
31383
|
+
const stackState = buildStackState(
|
|
31384
|
+
stackInfo.stackName,
|
|
31385
|
+
targetRegion,
|
|
31386
|
+
rows,
|
|
31387
|
+
templateParser,
|
|
31388
|
+
template
|
|
31389
|
+
);
|
|
31390
|
+
await stateBackend.saveState(stackInfo.stackName, targetRegion, stackState);
|
|
31391
|
+
logger.info(`\u2713 State written: ${stackInfo.stackName} (${targetRegion})`);
|
|
31392
|
+
logger.info(
|
|
31393
|
+
` ${importedRows.length} resource(s) imported. Run 'cdkd diff' to see how the imported state lines up with the template.`
|
|
31394
|
+
);
|
|
31395
|
+
} finally {
|
|
31396
|
+
await lockManager.releaseLock(stackInfo.stackName, targetRegion).catch((err) => {
|
|
31397
|
+
logger.warn(`Failed to release lock: ${err instanceof Error ? err.message : String(err)}`);
|
|
31398
|
+
});
|
|
31399
|
+
}
|
|
31400
|
+
} finally {
|
|
31401
|
+
awsClients.destroy();
|
|
31402
|
+
}
|
|
31403
|
+
}
|
|
31404
|
+
async function importOne(task) {
|
|
31405
|
+
const logger = getLogger();
|
|
31406
|
+
const { logicalId, resource, stackName, region, providerRegistry, override } = task;
|
|
31407
|
+
if (!providerRegistry.hasProvider(resource.Type)) {
|
|
31408
|
+
return {
|
|
31409
|
+
logicalId,
|
|
31410
|
+
resourceType: resource.Type,
|
|
31411
|
+
outcome: "skipped-no-impl",
|
|
31412
|
+
reason: "no provider registered"
|
|
31413
|
+
};
|
|
31414
|
+
}
|
|
31415
|
+
const provider = providerRegistry.getProvider(resource.Type);
|
|
31416
|
+
if (!provider.import) {
|
|
31417
|
+
return {
|
|
31418
|
+
logicalId,
|
|
31419
|
+
resourceType: resource.Type,
|
|
31420
|
+
outcome: "skipped-no-impl",
|
|
31421
|
+
reason: `provider does not implement import (yet)`
|
|
31422
|
+
};
|
|
31423
|
+
}
|
|
31424
|
+
const cdkPath = readCdkPath(resource);
|
|
31425
|
+
const input = {
|
|
31426
|
+
logicalId,
|
|
31427
|
+
resourceType: resource.Type,
|
|
31428
|
+
cdkPath,
|
|
31429
|
+
stackName,
|
|
31430
|
+
region,
|
|
31431
|
+
properties: resource.Properties ?? {},
|
|
31432
|
+
...override !== void 0 && { knownPhysicalId: override }
|
|
31433
|
+
};
|
|
31434
|
+
try {
|
|
31435
|
+
const result = await provider.import(input);
|
|
31436
|
+
if (!result) {
|
|
31437
|
+
return {
|
|
31438
|
+
logicalId,
|
|
31439
|
+
resourceType: resource.Type,
|
|
31440
|
+
outcome: "skipped-not-found",
|
|
31441
|
+
reason: "no matching AWS resource"
|
|
31442
|
+
};
|
|
31443
|
+
}
|
|
31444
|
+
return {
|
|
31445
|
+
logicalId,
|
|
31446
|
+
resourceType: resource.Type,
|
|
31447
|
+
outcome: "imported",
|
|
31448
|
+
physicalId: result.physicalId
|
|
31449
|
+
};
|
|
31450
|
+
} catch (error) {
|
|
31451
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
31452
|
+
logger.error(`Failed to import ${logicalId} (${resource.Type}): ${msg}`);
|
|
31453
|
+
return {
|
|
31454
|
+
logicalId,
|
|
31455
|
+
resourceType: resource.Type,
|
|
31456
|
+
outcome: "failed",
|
|
31457
|
+
reason: msg
|
|
31458
|
+
};
|
|
31459
|
+
}
|
|
31460
|
+
}
|
|
31461
|
+
function parseResourceOverrides(flags, mappingFile) {
|
|
31462
|
+
const map = /* @__PURE__ */ new Map();
|
|
31463
|
+
if (mappingFile) {
|
|
31464
|
+
let parsed;
|
|
31465
|
+
try {
|
|
31466
|
+
parsed = JSON.parse(readFileSync5(mappingFile, "utf-8"));
|
|
31467
|
+
} catch (err) {
|
|
31468
|
+
throw new Error(
|
|
31469
|
+
`Failed to read --resource-mapping file '${mappingFile}': ` + (err instanceof Error ? err.message : String(err))
|
|
31470
|
+
);
|
|
31471
|
+
}
|
|
31472
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
31473
|
+
throw new Error(
|
|
31474
|
+
`--resource-mapping file '${mappingFile}' must be a JSON object {logicalId: physicalId}`
|
|
31475
|
+
);
|
|
31476
|
+
}
|
|
31477
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
31478
|
+
if (typeof value !== "string") {
|
|
31479
|
+
throw new Error(
|
|
31480
|
+
`--resource-mapping: value for '${key}' must be a string, got ${typeof value}`
|
|
31481
|
+
);
|
|
31482
|
+
}
|
|
31483
|
+
map.set(key, value);
|
|
31484
|
+
}
|
|
31485
|
+
}
|
|
31486
|
+
for (const entry of flags ?? []) {
|
|
31487
|
+
const eq = entry.indexOf("=");
|
|
31488
|
+
if (eq <= 0 || eq === entry.length - 1) {
|
|
31489
|
+
throw new Error(`--resource expects 'logicalId=physicalId', got '${entry}'`);
|
|
31490
|
+
}
|
|
31491
|
+
map.set(entry.slice(0, eq), entry.slice(eq + 1));
|
|
31492
|
+
}
|
|
31493
|
+
return map;
|
|
31494
|
+
}
|
|
31495
|
+
function readCdkPath(resource) {
|
|
31496
|
+
const meta = resource.Metadata;
|
|
31497
|
+
if (!meta)
|
|
31498
|
+
return "";
|
|
31499
|
+
const v = meta["aws:cdk:path"];
|
|
31500
|
+
return typeof v === "string" ? v : "";
|
|
31501
|
+
}
|
|
31502
|
+
function collectImportableResources(template) {
|
|
31503
|
+
const out = [];
|
|
31504
|
+
for (const [logicalId, resource] of Object.entries(template.Resources)) {
|
|
31505
|
+
if (resource.Type === "AWS::CDK::Metadata")
|
|
31506
|
+
continue;
|
|
31507
|
+
out.push({ logicalId, resource });
|
|
31508
|
+
}
|
|
31509
|
+
return out;
|
|
31510
|
+
}
|
|
31511
|
+
function buildStackState(stackName, region, rows, templateParser, template) {
|
|
31512
|
+
const resources = {};
|
|
31513
|
+
for (const row of rows) {
|
|
31514
|
+
if (row.outcome !== "imported" || !row.physicalId)
|
|
31515
|
+
continue;
|
|
31516
|
+
const tmplResource = template.Resources[row.logicalId];
|
|
31517
|
+
if (!tmplResource)
|
|
31518
|
+
continue;
|
|
31519
|
+
const deps = templateParser.extractDependencies(tmplResource);
|
|
31520
|
+
resources[row.logicalId] = {
|
|
31521
|
+
physicalId: row.physicalId,
|
|
31522
|
+
resourceType: row.resourceType,
|
|
31523
|
+
properties: tmplResource.Properties ?? {},
|
|
31524
|
+
attributes: {},
|
|
31525
|
+
dependencies: [...deps]
|
|
31526
|
+
};
|
|
31527
|
+
}
|
|
31528
|
+
return {
|
|
31529
|
+
version: 2,
|
|
31530
|
+
stackName,
|
|
31531
|
+
region,
|
|
31532
|
+
resources,
|
|
31533
|
+
outputs: {},
|
|
31534
|
+
lastModified: Date.now()
|
|
31535
|
+
};
|
|
31536
|
+
}
|
|
31537
|
+
function printSummary(rows) {
|
|
31538
|
+
const logger = getLogger();
|
|
31539
|
+
const counts = {
|
|
31540
|
+
imported: 0,
|
|
31541
|
+
"skipped-no-impl": 0,
|
|
31542
|
+
"skipped-not-found": 0,
|
|
31543
|
+
failed: 0
|
|
31544
|
+
};
|
|
31545
|
+
logger.info("");
|
|
31546
|
+
logger.info("Import plan:");
|
|
31547
|
+
for (const r of rows) {
|
|
31548
|
+
counts[r.outcome]++;
|
|
31549
|
+
const tag = formatOutcome(r.outcome);
|
|
31550
|
+
const detail = r.outcome === "imported" ? ` (${r.physicalId})` : r.reason ? ` \u2014 ${r.reason}` : "";
|
|
31551
|
+
logger.info(` ${tag} ${r.logicalId} (${r.resourceType})${detail}`);
|
|
31552
|
+
}
|
|
31553
|
+
logger.info("");
|
|
31554
|
+
logger.info(
|
|
31555
|
+
`Summary: ${counts.imported} imported, ${counts["skipped-not-found"]} not found, ${counts["skipped-no-impl"]} unsupported, ${counts.failed} failed`
|
|
31556
|
+
);
|
|
31557
|
+
}
|
|
31558
|
+
function formatOutcome(outcome) {
|
|
31559
|
+
switch (outcome) {
|
|
31560
|
+
case "imported":
|
|
31561
|
+
return "\u2713";
|
|
31562
|
+
case "skipped-not-found":
|
|
31563
|
+
return "\xB7";
|
|
31564
|
+
case "skipped-no-impl":
|
|
31565
|
+
return "?";
|
|
31566
|
+
case "failed":
|
|
31567
|
+
return "\u2717";
|
|
31568
|
+
}
|
|
31569
|
+
}
|
|
31570
|
+
async function confirmPrompt2(prompt) {
|
|
31571
|
+
const rl = readline4.createInterface({ input: process.stdin, output: process.stdout });
|
|
31572
|
+
try {
|
|
31573
|
+
const ans = await rl.question(`${prompt} [y/N] `);
|
|
31574
|
+
return /^y(es)?$/i.test(ans.trim());
|
|
31575
|
+
} finally {
|
|
31576
|
+
rl.close();
|
|
31577
|
+
}
|
|
31578
|
+
}
|
|
31579
|
+
function createImportCommand() {
|
|
31580
|
+
const cmd = new Command11("import").description(
|
|
31581
|
+
"Adopt already-deployed AWS resources into cdkd state. Reads the CDK app to find logical IDs, resource types, and dependencies; uses the aws:cdk:path tag (or explicit --resource overrides) to find each resource in AWS."
|
|
31582
|
+
).argument(
|
|
31583
|
+
"[stack]",
|
|
31584
|
+
"Stack to import. Optional when the synthesized app contains exactly one stack."
|
|
31585
|
+
).option(
|
|
31586
|
+
"--resource <id=physical>",
|
|
31587
|
+
"Explicit physical-id override for one logical ID. Repeatable. Bypasses tag-based auto-lookup for that resource only.",
|
|
31588
|
+
collectMultiple,
|
|
31589
|
+
[]
|
|
31590
|
+
).option(
|
|
31591
|
+
"--resource-mapping <file>",
|
|
31592
|
+
"Path to a JSON file of {logicalId: physicalId} overrides (CDK CLI `cdk import --resource-mapping` compatible)."
|
|
31593
|
+
).option("--dry-run", "Show planned imports without writing state", false).option(
|
|
31594
|
+
"--force",
|
|
31595
|
+
"Overwrite an existing state record. Without this, an existing state file aborts the import.",
|
|
31596
|
+
false
|
|
31597
|
+
).action(withErrorHandling(importCommand));
|
|
31598
|
+
[...commonOptions, ...appOptions, ...stateOptions, ...contextOptions].forEach(
|
|
31599
|
+
(o) => cmd.addOption(o)
|
|
31600
|
+
);
|
|
30557
31601
|
return cmd;
|
|
30558
31602
|
}
|
|
31603
|
+
function collectMultiple(value, previous) {
|
|
31604
|
+
return [...previous ?? [], value];
|
|
31605
|
+
}
|
|
30559
31606
|
|
|
30560
31607
|
// src/cli/index.ts
|
|
30561
31608
|
var SUBCOMMANDS = /* @__PURE__ */ new Set([
|
|
@@ -30566,6 +31613,7 @@ var SUBCOMMANDS = /* @__PURE__ */ new Set([
|
|
|
30566
31613
|
"deploy",
|
|
30567
31614
|
"diff",
|
|
30568
31615
|
"destroy",
|
|
31616
|
+
"import",
|
|
30569
31617
|
"publish-assets",
|
|
30570
31618
|
"force-unlock",
|
|
30571
31619
|
"state"
|
|
@@ -30581,14 +31629,15 @@ function reorderArgs(argv) {
|
|
|
30581
31629
|
return [...prefix, ...cmdAndAfter, ...beforeCmd];
|
|
30582
31630
|
}
|
|
30583
31631
|
async function main() {
|
|
30584
|
-
const program = new
|
|
30585
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.
|
|
31632
|
+
const program = new Command12();
|
|
31633
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.16.0");
|
|
30586
31634
|
program.addCommand(createBootstrapCommand());
|
|
30587
31635
|
program.addCommand(createSynthCommand());
|
|
30588
31636
|
program.addCommand(createListCommand());
|
|
30589
31637
|
program.addCommand(createDeployCommand());
|
|
30590
31638
|
program.addCommand(createDiffCommand());
|
|
30591
31639
|
program.addCommand(createDestroyCommand());
|
|
31640
|
+
program.addCommand(createImportCommand());
|
|
30592
31641
|
program.addCommand(createPublishAssetsCommand());
|
|
30593
31642
|
program.addCommand(createForceUnlockCommand());
|
|
30594
31643
|
program.addCommand(createStateCommand());
|