@go-to-k/cdkd 0.221.8 → 0.221.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +14 -3
- package/dist/cli.js.map +1 -1
- package/dist/{deploy-engine-DCkhw7i7.js → deploy-engine-U63EpLKn.js} +167 -6
- package/dist/deploy-engine-U63EpLKn.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/deploy-engine-DCkhw7i7.js.map +0 -1
|
@@ -7,7 +7,7 @@ import { AttachRolePolicyCommand, CreateRoleCommand, DeleteRoleCommand, DeleteRo
|
|
|
7
7
|
import { PublishCommand, SNSClient } from "@aws-sdk/client-sns";
|
|
8
8
|
import { GetFunctionCommand, GetFunctionUrlConfigCommand, InvokeCommand, LambdaClient, UpdateFunctionConfigurationCommand, waitUntilFunctionActiveV2, waitUntilFunctionUpdatedV2 } from "@aws-sdk/client-lambda";
|
|
9
9
|
import { AssumeRoleCommand, GetCallerIdentityCommand, STSClient } from "@aws-sdk/client-sts";
|
|
10
|
-
import { DescribeAvailabilityZonesCommand, DescribeImagesCommand, DescribeLaunchTemplatesCommand, DescribeRouteTablesCommand, DescribeSecurityGroupsCommand, DescribeSubnetsCommand, DescribeVpcsCommand, DescribeVpnGatewaysCommand, EC2Client } from "@aws-sdk/client-ec2";
|
|
10
|
+
import { DescribeAvailabilityZonesCommand, DescribeImagesCommand, DescribeInstancesCommand, DescribeLaunchTemplatesCommand, DescribeRouteTablesCommand, DescribeSecurityGroupsCommand, DescribeSubnetsCommand, DescribeVpcsCommand, DescribeVpnGatewaysCommand, EC2Client } from "@aws-sdk/client-ec2";
|
|
11
11
|
import { DescribeTableCommand } from "@aws-sdk/client-dynamodb";
|
|
12
12
|
import { CloudFormationClient, CreateChangeSetCommand, DeleteStackCommand, DescribeChangeSetCommand, DescribeTypeCommand, GetTemplateCommand, waitUntilChangeSetCreateComplete } from "@aws-sdk/client-cloudformation";
|
|
13
13
|
import { GetRestApiCommand } from "@aws-sdk/client-api-gateway";
|
|
@@ -5463,6 +5463,15 @@ const cachedAvailabilityZones = {};
|
|
|
5463
5463
|
*/
|
|
5464
5464
|
const cachedDynamicReferences = {};
|
|
5465
5465
|
/**
|
|
5466
|
+
* Cache for EC2 instance attributes that require a live DescribeInstances
|
|
5467
|
+
* lookup (PrivateIp / PublicIp / PrivateDnsName / PublicDnsName /
|
|
5468
|
+
* AvailabilityZone). Keyed by `${physicalId}#${attributeName}`. The IP /
|
|
5469
|
+
* DNS attributes are not derivable from the instance id, so they are read
|
|
5470
|
+
* back from AWS once per (instance, attribute) and memoized for the deploy
|
|
5471
|
+
* lifetime.
|
|
5472
|
+
*/
|
|
5473
|
+
const cachedEc2InstanceAttributes = {};
|
|
5474
|
+
/**
|
|
5466
5475
|
* Get AWS account information from STS
|
|
5467
5476
|
*/
|
|
5468
5477
|
async function getAccountInfo(overrideRegion) {
|
|
@@ -5859,6 +5868,10 @@ var IntrinsicFunctionResolver = class {
|
|
|
5859
5868
|
case "Arn": return `arn:${partition}:cloudwatch:${region}:${accountId}:alarm:${physicalId}`;
|
|
5860
5869
|
default: return physicalId;
|
|
5861
5870
|
}
|
|
5871
|
+
if (resourceType === "AWS::CloudWatch::CompositeAlarm") switch (attributeName) {
|
|
5872
|
+
case "Arn": return `arn:${partition}:cloudwatch:${region}:${accountId}:alarm:${physicalId}`;
|
|
5873
|
+
default: return physicalId;
|
|
5874
|
+
}
|
|
5862
5875
|
if (resourceType === "AWS::RDS::DBInstance" || resourceType === "AWS::DocDB::DBInstance" || resourceType === "AWS::Neptune::DBInstance") switch (attributeName) {
|
|
5863
5876
|
case "DBInstanceArn":
|
|
5864
5877
|
case "Arn": return `arn:${partition}:rds:${region}:${accountId}:db:${physicalId}`;
|
|
@@ -5929,6 +5942,47 @@ var IntrinsicFunctionResolver = class {
|
|
|
5929
5942
|
case "SubnetId": return physicalId;
|
|
5930
5943
|
default: return physicalId;
|
|
5931
5944
|
}
|
|
5945
|
+
if (resourceType === "AWS::EC2::Instance") switch (attributeName) {
|
|
5946
|
+
case "PrivateIp":
|
|
5947
|
+
case "PublicIp":
|
|
5948
|
+
case "PrivateDnsName":
|
|
5949
|
+
case "PublicDnsName":
|
|
5950
|
+
case "AvailabilityZone": {
|
|
5951
|
+
const cacheKey = `${physicalId}#${attributeName}`;
|
|
5952
|
+
const cached = cachedEc2InstanceAttributes[cacheKey];
|
|
5953
|
+
if (cached !== void 0) return cached;
|
|
5954
|
+
try {
|
|
5955
|
+
const instance = (await getAwsClients().ec2.send(new DescribeInstancesCommand({ InstanceIds: [physicalId] }))).Reservations?.[0]?.Instances?.[0];
|
|
5956
|
+
let value;
|
|
5957
|
+
switch (attributeName) {
|
|
5958
|
+
case "PrivateIp":
|
|
5959
|
+
value = instance?.PrivateIpAddress;
|
|
5960
|
+
break;
|
|
5961
|
+
case "PublicIp":
|
|
5962
|
+
value = instance?.PublicIpAddress;
|
|
5963
|
+
break;
|
|
5964
|
+
case "PrivateDnsName":
|
|
5965
|
+
value = instance?.PrivateDnsName;
|
|
5966
|
+
break;
|
|
5967
|
+
case "PublicDnsName":
|
|
5968
|
+
value = instance?.PublicDnsName;
|
|
5969
|
+
break;
|
|
5970
|
+
case "AvailabilityZone":
|
|
5971
|
+
value = instance?.Placement?.AvailabilityZone;
|
|
5972
|
+
break;
|
|
5973
|
+
}
|
|
5974
|
+
if (value !== void 0 && value !== null && value !== "") {
|
|
5975
|
+
cachedEc2InstanceAttributes[cacheKey] = value;
|
|
5976
|
+
return value;
|
|
5977
|
+
}
|
|
5978
|
+
this.logger.warn(`DescribeInstances(${physicalId}) returned no ${attributeName}; returning physical ID`);
|
|
5979
|
+
} catch (err) {
|
|
5980
|
+
this.logger.warn(`DescribeInstances(${physicalId}) failed for ${attributeName}: ${err instanceof Error ? err.message : String(err)}`);
|
|
5981
|
+
}
|
|
5982
|
+
return physicalId;
|
|
5983
|
+
}
|
|
5984
|
+
default: return physicalId;
|
|
5985
|
+
}
|
|
5932
5986
|
if (resourceType === "AWS::EC2::LaunchTemplate") {
|
|
5933
5987
|
if (attributeName === "LatestVersionNumber" || attributeName === "DefaultVersionNumber") {
|
|
5934
5988
|
try {
|
|
@@ -6555,6 +6609,13 @@ var IntrinsicFunctionResolver = class {
|
|
|
6555
6609
|
* SECRET_ID can be a simple name or an ARN (arn:aws:secretsmanager:REGION:ACCOUNT:secret:NAME)
|
|
6556
6610
|
* which contains colons, so we cannot simply split on ':'.
|
|
6557
6611
|
* Instead, we find ':SecretString:' or ':SecretBinary:' as the delimiter.
|
|
6612
|
+
*
|
|
6613
|
+
* The whole-secret form omits everything after the type segment and carries no trailing
|
|
6614
|
+
* colon: "secretsmanager:SECRET_ID:SecretString" (returns the full secret string). We detect
|
|
6615
|
+
* it with an end-anchored check so that, for the whole-secret form, a SECRET_ID that merely
|
|
6616
|
+
* contains ":SecretString" mid-name is not split incorrectly. (The end-anchored fallback only
|
|
6617
|
+
* runs when no mid-string ":SecretString:" delimiter is present, so the json-key / version
|
|
6618
|
+
* forms are unaffected.)
|
|
6558
6619
|
*/
|
|
6559
6620
|
async resolveSecretsManagerReference(inner) {
|
|
6560
6621
|
const afterService = inner.substring(15);
|
|
@@ -6562,10 +6623,20 @@ var IntrinsicFunctionResolver = class {
|
|
|
6562
6623
|
let jsonKey = "";
|
|
6563
6624
|
let versionStage = "";
|
|
6564
6625
|
let versionId = "";
|
|
6565
|
-
|
|
6566
|
-
|
|
6626
|
+
let secretStringIdx = afterService.indexOf(":SecretString:");
|
|
6627
|
+
let secretBinaryIdx = afterService.indexOf(":SecretBinary:");
|
|
6628
|
+
let delimiterLenAtBinary = 14;
|
|
6629
|
+
let delimiterLenAtString = 14;
|
|
6630
|
+
if (secretStringIdx < 0 && afterService.endsWith(":SecretString")) {
|
|
6631
|
+
secretStringIdx = afterService.length - 13;
|
|
6632
|
+
delimiterLenAtString = 13;
|
|
6633
|
+
}
|
|
6634
|
+
if (secretBinaryIdx < 0 && afterService.endsWith(":SecretBinary")) {
|
|
6635
|
+
secretBinaryIdx = afterService.length - 13;
|
|
6636
|
+
delimiterLenAtBinary = 13;
|
|
6637
|
+
}
|
|
6567
6638
|
const delimiterIdx = secretStringIdx >= 0 && secretBinaryIdx >= 0 ? Math.min(secretStringIdx, secretBinaryIdx) : secretStringIdx >= 0 ? secretStringIdx : secretBinaryIdx;
|
|
6568
|
-
const delimiterLen = delimiterIdx >= 0 && delimiterIdx === secretBinaryIdx ?
|
|
6639
|
+
const delimiterLen = delimiterIdx >= 0 && delimiterIdx === secretBinaryIdx ? delimiterLenAtBinary : delimiterLenAtString;
|
|
6569
6640
|
if (delimiterIdx >= 0) {
|
|
6570
6641
|
secretId = afterService.substring(0, delimiterIdx);
|
|
6571
6642
|
const remainingParts = afterService.substring(delimiterIdx + delimiterLen).split(":");
|
|
@@ -11435,6 +11506,84 @@ const IMPLICIT_DELETE_DEPENDENCIES = {
|
|
|
11435
11506
|
"AWS::Lambda::Function"
|
|
11436
11507
|
]
|
|
11437
11508
|
};
|
|
11509
|
+
/**
|
|
11510
|
+
* Matches one alarm-state function token in a CompositeAlarm `AlarmRule`:
|
|
11511
|
+
* ALARM("name") | OK('name') | INSUFFICIENT_DATA(name)
|
|
11512
|
+
* The argument is captured raw (with any surrounding quotes) and trimmed /
|
|
11513
|
+
* unquoted by {@link extractReferencedAlarmNames}. CloudWatch also accepts the
|
|
11514
|
+
* boolean literals TRUE / FALSE which carry no argument, so they never match.
|
|
11515
|
+
*/
|
|
11516
|
+
const ALARM_RULE_FUNCTION_REGEX = /\b(?:ALARM|OK|INSUFFICIENT_DATA)\s*\(\s*([^)]*?)\s*\)/gi;
|
|
11517
|
+
/**
|
|
11518
|
+
* Extract every alarm NAME (or ARN) referenced by a CompositeAlarm `AlarmRule`
|
|
11519
|
+
* string. The rule references its child alarms by NAME (or ARN) as a plain
|
|
11520
|
+
* string — there is no `Ref` / `Fn::GetAtt`, so cdkd's DAG sees no dependency
|
|
11521
|
+
* edge from these references. We parse them out so a delete-ordering edge can be
|
|
11522
|
+
* synthesized (CloudWatch refuses to delete a metric alarm while a composite
|
|
11523
|
+
* alarm still references it).
|
|
11524
|
+
*
|
|
11525
|
+
* Handles the three alarm-state functions (`ALARM` / `OK` / `INSUFFICIENT_DATA`)
|
|
11526
|
+
* and both the bare-name and quoted-name forms. An ARN argument
|
|
11527
|
+
* (`arn:aws:cloudwatch:...:alarm:<name>`) is reduced to its trailing `<name>`
|
|
11528
|
+
* so it can be matched against a referenced alarm's `AlarmName` / physical id
|
|
11529
|
+
* the same way a bare name is.
|
|
11530
|
+
*/
|
|
11531
|
+
function extractReferencedAlarmNames(alarmRule) {
|
|
11532
|
+
const names = /* @__PURE__ */ new Set();
|
|
11533
|
+
for (const match of alarmRule.matchAll(ALARM_RULE_FUNCTION_REGEX)) {
|
|
11534
|
+
let arg = (match[1] ?? "").trim();
|
|
11535
|
+
if (arg.length === 0) continue;
|
|
11536
|
+
if (arg.startsWith("\"") && arg.endsWith("\"") || arg.startsWith("'") && arg.endsWith("'")) arg = arg.slice(1, -1);
|
|
11537
|
+
if (arg.length === 0) continue;
|
|
11538
|
+
const arnAlarmMatch = /:alarm:(.+)$/.exec(arg);
|
|
11539
|
+
if (arnAlarmMatch?.[1]) names.add(arnAlarmMatch[1]);
|
|
11540
|
+
else names.add(arg);
|
|
11541
|
+
}
|
|
11542
|
+
return [...names];
|
|
11543
|
+
}
|
|
11544
|
+
/**
|
|
11545
|
+
* Compute per-resource delete-ordering edges that cannot be inferred from
|
|
11546
|
+
* Ref / Fn::GetAtt edges or from the type-pair {@link IMPLICIT_DELETE_DEPENDENCIES}
|
|
11547
|
+
* table.
|
|
11548
|
+
*
|
|
11549
|
+
* Currently this synthesizes edges for `AWS::CloudWatch::CompositeAlarm`: a
|
|
11550
|
+
* composite alarm references its child alarms (metric `AWS::CloudWatch::Alarm`
|
|
11551
|
+
* or other composite alarms) by NAME inside its `AlarmRule` string. Because the
|
|
11552
|
+
* reference is a plain string (no `Ref` / `Fn::GetAtt`), cdkd's DAG sees no
|
|
11553
|
+
* dependency edge, so without this the metric alarm can be scheduled for
|
|
11554
|
+
* deletion while the composite still exists — and CloudWatch rejects that with
|
|
11555
|
+
* `Cannot delete <alarm> as there are composite alarm(s) depending on it.`
|
|
11556
|
+
* We therefore emit an edge making the composite alarm delete BEFORE every
|
|
11557
|
+
* alarm its `AlarmRule` references (handling composite-of-composite too).
|
|
11558
|
+
*
|
|
11559
|
+
* @param resources logical id -> resource (the subset of resources participating
|
|
11560
|
+
* in the delete). Only entries whose logical id is a key in this record are
|
|
11561
|
+
* considered as edge endpoints.
|
|
11562
|
+
*/
|
|
11563
|
+
function computeImplicitDeleteEdges(resources) {
|
|
11564
|
+
const edges = [];
|
|
11565
|
+
const alarmTypes = new Set(["AWS::CloudWatch::Alarm", "AWS::CloudWatch::CompositeAlarm"]);
|
|
11566
|
+
const nameToLogicalId = /* @__PURE__ */ new Map();
|
|
11567
|
+
for (const [logicalId, resource] of Object.entries(resources)) {
|
|
11568
|
+
if (!alarmTypes.has(resource.resourceType)) continue;
|
|
11569
|
+
const alarmName = typeof resource.properties?.["AlarmName"] === "string" ? resource.properties["AlarmName"] : resource.physicalId;
|
|
11570
|
+
if (alarmName) nameToLogicalId.set(alarmName, logicalId);
|
|
11571
|
+
}
|
|
11572
|
+
for (const [logicalId, resource] of Object.entries(resources)) {
|
|
11573
|
+
if (resource.resourceType !== "AWS::CloudWatch::CompositeAlarm") continue;
|
|
11574
|
+
const alarmRule = resource.properties?.["AlarmRule"];
|
|
11575
|
+
if (typeof alarmRule !== "string") continue;
|
|
11576
|
+
for (const referencedName of extractReferencedAlarmNames(alarmRule)) {
|
|
11577
|
+
const referencedLogicalId = nameToLogicalId.get(referencedName);
|
|
11578
|
+
if (!referencedLogicalId || referencedLogicalId === logicalId) continue;
|
|
11579
|
+
edges.push({
|
|
11580
|
+
before: logicalId,
|
|
11581
|
+
after: referencedLogicalId
|
|
11582
|
+
});
|
|
11583
|
+
}
|
|
11584
|
+
}
|
|
11585
|
+
return edges;
|
|
11586
|
+
}
|
|
11438
11587
|
|
|
11439
11588
|
//#endregion
|
|
11440
11589
|
//#region src/deployment/retryable-errors.ts
|
|
@@ -12850,6 +12999,18 @@ var DeployEngine = class {
|
|
|
12850
12999
|
}
|
|
12851
13000
|
}
|
|
12852
13001
|
}
|
|
13002
|
+
const scoped = {};
|
|
13003
|
+
for (const id of deleteIds) {
|
|
13004
|
+
const resource = state.resources[id];
|
|
13005
|
+
if (resource) scoped[id] = resource;
|
|
13006
|
+
}
|
|
13007
|
+
for (const { before, after } of computeImplicitDeleteEdges(scoped)) {
|
|
13008
|
+
if (!dependedBy.has(after)) dependedBy.set(after, /* @__PURE__ */ new Set());
|
|
13009
|
+
if (!dependedBy.get(after).has(before)) {
|
|
13010
|
+
dependedBy.get(after).add(before);
|
|
13011
|
+
this.logger.debug(`Implicit delete dependency: ${before} (${scoped[before]?.resourceType}) must be deleted before ${after} (${scoped[after]?.resourceType})`);
|
|
13012
|
+
}
|
|
13013
|
+
}
|
|
12853
13014
|
}
|
|
12854
13015
|
/**
|
|
12855
13016
|
* Prepare a property map for a Cloud Control API call. When a Tier 1
|
|
@@ -12933,5 +13094,5 @@ var DeployEngine = class {
|
|
|
12933
13094
|
};
|
|
12934
13095
|
|
|
12935
13096
|
//#endregion
|
|
12936
|
-
export {
|
|
12937
|
-
//# sourceMappingURL=deploy-engine-
|
|
13097
|
+
export { AssemblyReader as $, shouldRetainResource as A, getDefaultStateBucketName as B, applyRoleArnIfSet as C, LockManager as D, TemplateParser as E, formatDockerLoginError as F, resolveStateBucketWithDefault as G, resolveApp as H, getDockerCmd as I, CFN_TEMPLATE_BODY_LIMIT as J, resolveStateBucketWithDefaultAndSource as K, runDockerForeground as L, stringifyValue as M, WorkGraph as N, S3StateBackend as O, buildDockerImage as P, uploadCfnTemplate as Q, runDockerStreaming as R, IntrinsicFunctionResolver as S, DagBuilder as T, resolveCaptureObservedState as U, getLegacyStateBucketName as V, resolveSkipPrefix as W, MIGRATE_TMP_PREFIX as X, CFN_TEMPLATE_URL_LIMIT as Y, findLargeInlineResources as Z, IAMRoleProvider as _, withRetry as a, findActionableSilentDrops as b, computeImplicitDeleteEdges as c, bold as d, clearBucketRegionCache as et, cyan as f, yellow as g, red as h, withResourceDeadline as i, AssetPublisher as j, rebuildClientForBucketRegion as k, extractDeploymentEventError as l, green as m, DEFAULT_RESOURCE_WARN_AFTER_MS as n, isRetryableTransientError as o, gray as p, warnDeprecatedNoPrefixCliFlag as q, DeployEngine as r, IMPLICIT_DELETE_DEPENDENCIES as s, DEFAULT_RESOURCE_TIMEOUT_MS as t, resolveBucketRegion as tt, formatResourceLine as u, collectInlinePolicyNamesManagedBySiblings as v, DiffCalculator as w, CloudControlProvider as x, ProviderRegistry as y, Synthesizer as z };
|
|
13098
|
+
//# sourceMappingURL=deploy-engine-U63EpLKn.js.map
|