@go-to-k/cdkd 0.59.1 → 0.60.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 +3 -0
- package/dist/cli.js +2330 -329
- package/dist/cli.js.map +4 -4
- package/dist/go-to-k-cdkd-0.60.0.tgz +0 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +2 -2
- package/package.json +3 -1
- package/dist/go-to-k-cdkd-0.59.1.tgz +0 -0
package/dist/cli.js
CHANGED
|
@@ -653,7 +653,7 @@ var destroyOptions = [
|
|
|
653
653
|
),
|
|
654
654
|
new Option(
|
|
655
655
|
"--remove-protection",
|
|
656
|
-
"Bypass deletion protection on protected resources by flipping the per-resource protection flag off in-place before delete. Covers stack-level terminationProtection (CDK property) and resource-level protection on AWS::Logs::LogGroup, AWS::RDS::DBInstance, AWS::RDS::DBCluster, AWS::DynamoDB::Table, AWS::EC2::Instance, and AWS::ElasticLoadBalancingV2::LoadBalancer."
|
|
656
|
+
"Bypass deletion protection on protected resources by flipping the per-resource protection flag off in-place before delete. Covers stack-level terminationProtection (CDK property) and resource-level protection on AWS::Logs::LogGroup, AWS::RDS::DBInstance, AWS::RDS::DBCluster, AWS::DocDB::DBCluster, AWS::Neptune::DBCluster, AWS::Neptune::DBInstance, AWS::DynamoDB::Table, AWS::EC2::Instance, AWS::Cognito::UserPool, AWS::AutoScaling::AutoScalingGroup, and AWS::ElasticLoadBalancingV2::LoadBalancer."
|
|
657
657
|
).default(false)
|
|
658
658
|
];
|
|
659
659
|
|
|
@@ -738,6 +738,32 @@ var FALLBACK_NAME_RULES = {
|
|
|
738
738
|
nameProperty: "DBInstanceIdentifier",
|
|
739
739
|
options: { maxLength: 63, lowercase: true }
|
|
740
740
|
},
|
|
741
|
+
// DocumentDB — RDS-shaped API; same name constraints.
|
|
742
|
+
"AWS::DocDB::DBSubnetGroup": {
|
|
743
|
+
nameProperty: "DBSubnetGroupName",
|
|
744
|
+
options: { maxLength: 255, lowercase: true }
|
|
745
|
+
},
|
|
746
|
+
"AWS::DocDB::DBCluster": {
|
|
747
|
+
nameProperty: "DBClusterIdentifier",
|
|
748
|
+
options: { maxLength: 63, lowercase: true }
|
|
749
|
+
},
|
|
750
|
+
"AWS::DocDB::DBInstance": {
|
|
751
|
+
nameProperty: "DBInstanceIdentifier",
|
|
752
|
+
options: { maxLength: 63, lowercase: true }
|
|
753
|
+
},
|
|
754
|
+
// Neptune — RDS-shaped API; same name constraints.
|
|
755
|
+
"AWS::Neptune::DBSubnetGroup": {
|
|
756
|
+
nameProperty: "DBSubnetGroupName",
|
|
757
|
+
options: { maxLength: 255, lowercase: true }
|
|
758
|
+
},
|
|
759
|
+
"AWS::Neptune::DBCluster": {
|
|
760
|
+
nameProperty: "DBClusterIdentifier",
|
|
761
|
+
options: { maxLength: 63, lowercase: true }
|
|
762
|
+
},
|
|
763
|
+
"AWS::Neptune::DBInstance": {
|
|
764
|
+
nameProperty: "DBInstanceIdentifier",
|
|
765
|
+
options: { maxLength: 63, lowercase: true }
|
|
766
|
+
},
|
|
741
767
|
"AWS::ElasticLoadBalancingV2::LoadBalancer": {
|
|
742
768
|
nameProperty: "Name",
|
|
743
769
|
options: { maxLength: 32 }
|
|
@@ -30019,70 +30045,89 @@ var RDSProvider = class {
|
|
|
30019
30045
|
}
|
|
30020
30046
|
};
|
|
30021
30047
|
|
|
30022
|
-
// src/provisioning/providers/
|
|
30048
|
+
// src/provisioning/providers/docdb-provider.ts
|
|
30023
30049
|
import {
|
|
30024
|
-
|
|
30025
|
-
|
|
30026
|
-
|
|
30027
|
-
|
|
30028
|
-
|
|
30029
|
-
|
|
30030
|
-
|
|
30031
|
-
|
|
30032
|
-
|
|
30033
|
-
|
|
30034
|
-
|
|
30035
|
-
|
|
30036
|
-
|
|
30037
|
-
|
|
30038
|
-
|
|
30039
|
-
|
|
30040
|
-
} from "@aws-sdk/client-
|
|
30041
|
-
var
|
|
30042
|
-
|
|
30050
|
+
DocDBClient,
|
|
30051
|
+
CreateDBClusterCommand as CreateDBClusterCommand2,
|
|
30052
|
+
DeleteDBClusterCommand as DeleteDBClusterCommand2,
|
|
30053
|
+
ModifyDBClusterCommand as ModifyDBClusterCommand2,
|
|
30054
|
+
DescribeDBClustersCommand as DescribeDBClustersCommand2,
|
|
30055
|
+
CreateDBInstanceCommand as CreateDBInstanceCommand2,
|
|
30056
|
+
DeleteDBInstanceCommand as DeleteDBInstanceCommand2,
|
|
30057
|
+
ModifyDBInstanceCommand as ModifyDBInstanceCommand2,
|
|
30058
|
+
DescribeDBInstancesCommand as DescribeDBInstancesCommand2,
|
|
30059
|
+
CreateDBSubnetGroupCommand as CreateDBSubnetGroupCommand2,
|
|
30060
|
+
DeleteDBSubnetGroupCommand as DeleteDBSubnetGroupCommand2,
|
|
30061
|
+
DescribeDBSubnetGroupsCommand as DescribeDBSubnetGroupsCommand2,
|
|
30062
|
+
ModifyDBSubnetGroupCommand as ModifyDBSubnetGroupCommand2,
|
|
30063
|
+
ListTagsForResourceCommand as ListTagsForResourceCommand11,
|
|
30064
|
+
AddTagsToResourceCommand as AddTagsToResourceCommand3,
|
|
30065
|
+
RemoveTagsFromResourceCommand as RemoveTagsFromResourceCommand3
|
|
30066
|
+
} from "@aws-sdk/client-docdb";
|
|
30067
|
+
var DocDBProvider = class {
|
|
30068
|
+
docdbClient;
|
|
30043
30069
|
providerRegion = process.env["AWS_REGION"];
|
|
30044
|
-
logger = getLogger().child("
|
|
30070
|
+
logger = getLogger().child("DocDBProvider");
|
|
30045
30071
|
handledProperties = /* @__PURE__ */ new Map([
|
|
30046
30072
|
[
|
|
30047
|
-
"AWS::
|
|
30048
|
-
/* @__PURE__ */ new Set(["
|
|
30073
|
+
"AWS::DocDB::DBSubnetGroup",
|
|
30074
|
+
/* @__PURE__ */ new Set(["DBSubnetGroupName", "DBSubnetGroupDescription", "SubnetIds", "Tags"])
|
|
30049
30075
|
],
|
|
30050
30076
|
[
|
|
30051
|
-
"AWS::
|
|
30077
|
+
"AWS::DocDB::DBCluster",
|
|
30052
30078
|
/* @__PURE__ */ new Set([
|
|
30053
|
-
"
|
|
30054
|
-
"
|
|
30055
|
-
"
|
|
30056
|
-
"
|
|
30057
|
-
"
|
|
30058
|
-
"
|
|
30059
|
-
"
|
|
30060
|
-
"
|
|
30061
|
-
"
|
|
30062
|
-
"
|
|
30063
|
-
"
|
|
30064
|
-
"
|
|
30065
|
-
"
|
|
30066
|
-
"
|
|
30067
|
-
"
|
|
30079
|
+
"DBClusterIdentifier",
|
|
30080
|
+
"EngineVersion",
|
|
30081
|
+
"MasterUsername",
|
|
30082
|
+
"MasterUserPassword",
|
|
30083
|
+
"Port",
|
|
30084
|
+
"VpcSecurityGroupIds",
|
|
30085
|
+
"DBSubnetGroupName",
|
|
30086
|
+
"StorageEncrypted",
|
|
30087
|
+
"KmsKeyId",
|
|
30088
|
+
"BackupRetentionPeriod",
|
|
30089
|
+
"PreferredBackupWindow",
|
|
30090
|
+
"PreferredMaintenanceWindow",
|
|
30091
|
+
"DBClusterParameterGroupName",
|
|
30092
|
+
"DeletionProtection",
|
|
30093
|
+
"Tags"
|
|
30094
|
+
])
|
|
30095
|
+
],
|
|
30096
|
+
[
|
|
30097
|
+
"AWS::DocDB::DBInstance",
|
|
30098
|
+
// DocDB DBInstance does NOT support DeletionProtection (verified
|
|
30099
|
+
// against the @aws-sdk/client-docdb CreateDBInstanceMessage type —
|
|
30100
|
+
// the field is absent). Cluster-level DeletionProtection covers the
|
|
30101
|
+
// common case anyway; instance deletes are gated by the cluster's
|
|
30102
|
+
// protection flag in normal use.
|
|
30103
|
+
/* @__PURE__ */ new Set([
|
|
30104
|
+
"DBInstanceIdentifier",
|
|
30105
|
+
"DBInstanceClass",
|
|
30106
|
+
"DBClusterIdentifier",
|
|
30107
|
+
"AvailabilityZone",
|
|
30108
|
+
"PreferredMaintenanceWindow",
|
|
30109
|
+
"AutoMinorVersionUpgrade",
|
|
30110
|
+
"Tags"
|
|
30068
30111
|
])
|
|
30069
30112
|
]
|
|
30070
30113
|
]);
|
|
30071
30114
|
getClient() {
|
|
30072
|
-
if (!this.
|
|
30073
|
-
this.
|
|
30115
|
+
if (!this.docdbClient) {
|
|
30116
|
+
this.docdbClient = new DocDBClient(
|
|
30074
30117
|
this.providerRegion ? { region: this.providerRegion } : {}
|
|
30075
30118
|
);
|
|
30076
30119
|
}
|
|
30077
|
-
return this.
|
|
30120
|
+
return this.docdbClient;
|
|
30078
30121
|
}
|
|
30079
30122
|
// ─── Dispatch ─────────────────────────────────────────────────────
|
|
30080
30123
|
async create(logicalId, resourceType, properties) {
|
|
30081
30124
|
switch (resourceType) {
|
|
30082
|
-
case "AWS::
|
|
30083
|
-
return this.
|
|
30084
|
-
case "AWS::
|
|
30085
|
-
return this.
|
|
30125
|
+
case "AWS::DocDB::DBSubnetGroup":
|
|
30126
|
+
return this.createDBSubnetGroup(logicalId, resourceType, properties);
|
|
30127
|
+
case "AWS::DocDB::DBCluster":
|
|
30128
|
+
return this.createDBCluster(logicalId, resourceType, properties);
|
|
30129
|
+
case "AWS::DocDB::DBInstance":
|
|
30130
|
+
return this.createDBInstance(logicalId, resourceType, properties);
|
|
30086
30131
|
default:
|
|
30087
30132
|
throw new ProvisioningError(
|
|
30088
30133
|
`Unsupported resource type: ${resourceType}`,
|
|
@@ -30091,12 +30136,32 @@ var Route53Provider = class {
|
|
|
30091
30136
|
);
|
|
30092
30137
|
}
|
|
30093
30138
|
}
|
|
30094
|
-
async update(logicalId, physicalId, resourceType, properties,
|
|
30139
|
+
async update(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
30095
30140
|
switch (resourceType) {
|
|
30096
|
-
case "AWS::
|
|
30097
|
-
return this.
|
|
30098
|
-
|
|
30099
|
-
|
|
30141
|
+
case "AWS::DocDB::DBSubnetGroup":
|
|
30142
|
+
return this.updateDBSubnetGroup(
|
|
30143
|
+
logicalId,
|
|
30144
|
+
physicalId,
|
|
30145
|
+
resourceType,
|
|
30146
|
+
properties,
|
|
30147
|
+
previousProperties
|
|
30148
|
+
);
|
|
30149
|
+
case "AWS::DocDB::DBCluster":
|
|
30150
|
+
return this.updateDBCluster(
|
|
30151
|
+
logicalId,
|
|
30152
|
+
physicalId,
|
|
30153
|
+
resourceType,
|
|
30154
|
+
properties,
|
|
30155
|
+
previousProperties
|
|
30156
|
+
);
|
|
30157
|
+
case "AWS::DocDB::DBInstance":
|
|
30158
|
+
return this.updateDBInstance(
|
|
30159
|
+
logicalId,
|
|
30160
|
+
physicalId,
|
|
30161
|
+
resourceType,
|
|
30162
|
+
properties,
|
|
30163
|
+
previousProperties
|
|
30164
|
+
);
|
|
30100
30165
|
default:
|
|
30101
30166
|
throw new ProvisioningError(
|
|
30102
30167
|
`Unsupported resource type: ${resourceType}`,
|
|
@@ -30106,12 +30171,14 @@ var Route53Provider = class {
|
|
|
30106
30171
|
);
|
|
30107
30172
|
}
|
|
30108
30173
|
}
|
|
30109
|
-
async delete(logicalId, physicalId, resourceType,
|
|
30174
|
+
async delete(logicalId, physicalId, resourceType, _properties, context) {
|
|
30110
30175
|
switch (resourceType) {
|
|
30111
|
-
case "AWS::
|
|
30112
|
-
return this.
|
|
30113
|
-
case "AWS::
|
|
30114
|
-
return this.
|
|
30176
|
+
case "AWS::DocDB::DBSubnetGroup":
|
|
30177
|
+
return this.deleteDBSubnetGroup(logicalId, physicalId, resourceType, context);
|
|
30178
|
+
case "AWS::DocDB::DBCluster":
|
|
30179
|
+
return this.deleteDBCluster(logicalId, physicalId, resourceType, context);
|
|
30180
|
+
case "AWS::DocDB::DBInstance":
|
|
30181
|
+
return this.deleteDBInstance(logicalId, physicalId, resourceType, context);
|
|
30115
30182
|
default:
|
|
30116
30183
|
throw new ProvisioningError(
|
|
30117
30184
|
`Unsupported resource type: ${resourceType}`,
|
|
@@ -30121,123 +30188,74 @@ var Route53Provider = class {
|
|
|
30121
30188
|
);
|
|
30122
30189
|
}
|
|
30123
30190
|
}
|
|
30124
|
-
|
|
30125
|
-
|
|
30126
|
-
|
|
30127
|
-
|
|
30128
|
-
default:
|
|
30129
|
-
return void 0;
|
|
30130
|
-
}
|
|
30131
|
-
}
|
|
30132
|
-
// ─── AWS::Route53::HostedZone ──────────────────────────────────────
|
|
30133
|
-
async createHostedZone(logicalId, resourceType, properties) {
|
|
30134
|
-
this.logger.debug(`Creating Route 53 hosted zone ${logicalId}`);
|
|
30135
|
-
const name = properties["Name"];
|
|
30136
|
-
if (!name) {
|
|
30137
|
-
throw new ProvisioningError(
|
|
30138
|
-
`Name is required for hosted zone ${logicalId}`,
|
|
30139
|
-
resourceType,
|
|
30140
|
-
logicalId
|
|
30141
|
-
);
|
|
30142
|
-
}
|
|
30191
|
+
// ─── DBSubnetGroup ────────────────────────────────────────────────
|
|
30192
|
+
async createDBSubnetGroup(logicalId, resourceType, properties) {
|
|
30193
|
+
this.logger.debug(`Creating DocDB DBSubnetGroup ${logicalId}`);
|
|
30194
|
+
const dbSubnetGroupName = properties["DBSubnetGroupName"] || generateResourceName(logicalId, { maxLength: 255, lowercase: true });
|
|
30143
30195
|
try {
|
|
30144
|
-
const
|
|
30145
|
-
|
|
30146
|
-
|
|
30147
|
-
|
|
30148
|
-
|
|
30149
|
-
|
|
30150
|
-
|
|
30151
|
-
...hostedZoneConfig && hostedZoneConfig["Comment"] ? {
|
|
30152
|
-
HostedZoneConfig: {
|
|
30153
|
-
Comment: hostedZoneConfig["Comment"],
|
|
30154
|
-
// When VPCs are specified, this is a private hosted zone
|
|
30155
|
-
...firstVpc ? { PrivateZone: true } : {}
|
|
30156
|
-
}
|
|
30157
|
-
} : firstVpc ? { HostedZoneConfig: { PrivateZone: true } } : {},
|
|
30158
|
-
...firstVpc ? {
|
|
30159
|
-
VPC: {
|
|
30160
|
-
VPCId: firstVpc["VPCId"],
|
|
30161
|
-
VPCRegion: firstVpc["VPCRegion"]
|
|
30162
|
-
}
|
|
30163
|
-
} : {}
|
|
30196
|
+
const tags = this.buildTags(properties);
|
|
30197
|
+
await this.getClient().send(
|
|
30198
|
+
new CreateDBSubnetGroupCommand2({
|
|
30199
|
+
DBSubnetGroupName: dbSubnetGroupName,
|
|
30200
|
+
DBSubnetGroupDescription: properties["DBSubnetGroupDescription"] || `Subnet group for ${logicalId}`,
|
|
30201
|
+
SubnetIds: properties["SubnetIds"],
|
|
30202
|
+
...tags.length > 0 && { Tags: tags }
|
|
30164
30203
|
})
|
|
30165
30204
|
);
|
|
30166
|
-
|
|
30167
|
-
|
|
30168
|
-
|
|
30169
|
-
}
|
|
30170
|
-
const zoneId = hostedZone.Id.replace("/hostedzone/", "");
|
|
30171
|
-
if (vpcs && vpcs.length > 1) {
|
|
30172
|
-
for (let i = 1; i < vpcs.length; i++) {
|
|
30173
|
-
const additionalVpc = vpcs[i];
|
|
30174
|
-
this.logger.debug(
|
|
30175
|
-
`Associating additional VPC ${String(additionalVpc["VPCId"])} with hosted zone ${zoneId}`
|
|
30176
|
-
);
|
|
30177
|
-
await this.getClient().send(
|
|
30178
|
-
new AssociateVPCWithHostedZoneCommand({
|
|
30179
|
-
HostedZoneId: zoneId,
|
|
30180
|
-
VPC: {
|
|
30181
|
-
VPCId: additionalVpc["VPCId"],
|
|
30182
|
-
VPCRegion: additionalVpc["VPCRegion"]
|
|
30183
|
-
}
|
|
30184
|
-
})
|
|
30185
|
-
);
|
|
30186
|
-
}
|
|
30187
|
-
}
|
|
30188
|
-
await this.applyHostedZoneTags(zoneId, properties, logicalId);
|
|
30189
|
-
await this.applyQueryLoggingConfig(zoneId, properties, logicalId);
|
|
30190
|
-
const nameServers = response.DelegationSet?.NameServers ?? [];
|
|
30191
|
-
this.logger.debug(`Successfully created hosted zone ${logicalId}: ${zoneId}`);
|
|
30205
|
+
this.logger.debug(
|
|
30206
|
+
`Successfully created DocDB DBSubnetGroup ${logicalId}: ${dbSubnetGroupName}`
|
|
30207
|
+
);
|
|
30192
30208
|
return {
|
|
30193
|
-
physicalId:
|
|
30209
|
+
physicalId: dbSubnetGroupName,
|
|
30194
30210
|
attributes: {
|
|
30195
|
-
|
|
30196
|
-
NameServers: nameServers.join(",")
|
|
30211
|
+
DBSubnetGroupName: dbSubnetGroupName
|
|
30197
30212
|
}
|
|
30198
30213
|
};
|
|
30199
30214
|
} catch (error) {
|
|
30200
|
-
if (error instanceof ProvisioningError)
|
|
30201
|
-
throw error;
|
|
30202
30215
|
const cause = error instanceof Error ? error : void 0;
|
|
30203
30216
|
throw new ProvisioningError(
|
|
30204
|
-
`Failed to create
|
|
30217
|
+
`Failed to create DocDB DBSubnetGroup ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
30205
30218
|
resourceType,
|
|
30206
30219
|
logicalId,
|
|
30207
|
-
|
|
30220
|
+
dbSubnetGroupName,
|
|
30208
30221
|
cause
|
|
30209
30222
|
);
|
|
30210
30223
|
}
|
|
30211
30224
|
}
|
|
30212
|
-
async
|
|
30213
|
-
this.logger.debug(`Updating
|
|
30225
|
+
async updateDBSubnetGroup(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
30226
|
+
this.logger.debug(`Updating DocDB DBSubnetGroup ${logicalId}: ${physicalId}`);
|
|
30214
30227
|
try {
|
|
30215
|
-
const
|
|
30216
|
-
const
|
|
30217
|
-
|
|
30218
|
-
|
|
30219
|
-
|
|
30220
|
-
|
|
30221
|
-
|
|
30228
|
+
const subnetIds = properties["SubnetIds"];
|
|
30229
|
+
const sendSubnetIds = subnetIds !== void 0 && subnetIds.length > 0;
|
|
30230
|
+
const modifyInput = {
|
|
30231
|
+
DBSubnetGroupName: physicalId,
|
|
30232
|
+
DBSubnetGroupDescription: properties["DBSubnetGroupDescription"],
|
|
30233
|
+
...sendSubnetIds && { SubnetIds: subnetIds }
|
|
30234
|
+
};
|
|
30235
|
+
await this.getClient().send(new ModifyDBSubnetGroupCommand2(modifyInput));
|
|
30236
|
+
const desc = await this.getClient().send(
|
|
30237
|
+
new DescribeDBSubnetGroupsCommand2({ DBSubnetGroupName: physicalId })
|
|
30222
30238
|
);
|
|
30223
|
-
|
|
30224
|
-
|
|
30225
|
-
|
|
30226
|
-
|
|
30227
|
-
|
|
30228
|
-
|
|
30239
|
+
const arn = desc.DBSubnetGroups?.[0]?.DBSubnetGroupArn;
|
|
30240
|
+
if (arn) {
|
|
30241
|
+
await this.applyTagDiff(
|
|
30242
|
+
arn,
|
|
30243
|
+
previousProperties["Tags"],
|
|
30244
|
+
properties["Tags"]
|
|
30245
|
+
);
|
|
30246
|
+
}
|
|
30247
|
+
this.logger.debug(`Successfully updated DocDB DBSubnetGroup ${logicalId}`);
|
|
30229
30248
|
return {
|
|
30230
30249
|
physicalId,
|
|
30231
30250
|
wasReplaced: false,
|
|
30232
30251
|
attributes: {
|
|
30233
|
-
|
|
30234
|
-
NameServers: nameServers.join(",")
|
|
30252
|
+
DBSubnetGroupName: physicalId
|
|
30235
30253
|
}
|
|
30236
30254
|
};
|
|
30237
30255
|
} catch (error) {
|
|
30238
30256
|
const cause = error instanceof Error ? error : void 0;
|
|
30239
30257
|
throw new ProvisioningError(
|
|
30240
|
-
`Failed to update
|
|
30258
|
+
`Failed to update DocDB DBSubnetGroup ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
30241
30259
|
resourceType,
|
|
30242
30260
|
logicalId,
|
|
30243
30261
|
physicalId,
|
|
@@ -30245,14 +30263,17 @@ var Route53Provider = class {
|
|
|
30245
30263
|
);
|
|
30246
30264
|
}
|
|
30247
30265
|
}
|
|
30248
|
-
async
|
|
30249
|
-
this.logger.debug(`Deleting
|
|
30266
|
+
async deleteDBSubnetGroup(logicalId, physicalId, resourceType, context) {
|
|
30267
|
+
this.logger.debug(`Deleting DocDB DBSubnetGroup ${logicalId}: ${physicalId}`);
|
|
30250
30268
|
try {
|
|
30251
|
-
await this.
|
|
30252
|
-
|
|
30253
|
-
|
|
30269
|
+
await this.getClient().send(
|
|
30270
|
+
new DeleteDBSubnetGroupCommand2({
|
|
30271
|
+
DBSubnetGroupName: physicalId
|
|
30272
|
+
})
|
|
30273
|
+
);
|
|
30274
|
+
this.logger.debug(`Successfully deleted DocDB DBSubnetGroup ${logicalId}`);
|
|
30254
30275
|
} catch (error) {
|
|
30255
|
-
if (error
|
|
30276
|
+
if (this.isNotFoundError(error, "DBSubnetGroupNotFoundFault")) {
|
|
30256
30277
|
const clientRegion = await this.getClient().config.region();
|
|
30257
30278
|
assertRegionMatch(
|
|
30258
30279
|
clientRegion,
|
|
@@ -30261,12 +30282,12 @@ var Route53Provider = class {
|
|
|
30261
30282
|
logicalId,
|
|
30262
30283
|
physicalId
|
|
30263
30284
|
);
|
|
30264
|
-
this.logger.debug(`
|
|
30285
|
+
this.logger.debug(`DocDB DBSubnetGroup ${physicalId} does not exist, skipping deletion`);
|
|
30265
30286
|
return;
|
|
30266
30287
|
}
|
|
30267
30288
|
const cause = error instanceof Error ? error : void 0;
|
|
30268
30289
|
throw new ProvisioningError(
|
|
30269
|
-
`Failed to delete
|
|
30290
|
+
`Failed to delete DocDB DBSubnetGroup ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
30270
30291
|
resourceType,
|
|
30271
30292
|
logicalId,
|
|
30272
30293
|
physicalId,
|
|
@@ -30274,98 +30295,111 @@ var Route53Provider = class {
|
|
|
30274
30295
|
);
|
|
30275
30296
|
}
|
|
30276
30297
|
}
|
|
30277
|
-
|
|
30278
|
-
|
|
30279
|
-
|
|
30280
|
-
|
|
30281
|
-
case "NameServers": {
|
|
30282
|
-
const response = await this.getClient().send(new GetHostedZoneCommand2({ Id: physicalId }));
|
|
30283
|
-
return (response.DelegationSet?.NameServers ?? []).join(",");
|
|
30284
|
-
}
|
|
30285
|
-
default:
|
|
30286
|
-
return void 0;
|
|
30287
|
-
}
|
|
30288
|
-
}
|
|
30289
|
-
// ─── AWS::Route53::RecordSet ───────────────────────────────────────
|
|
30290
|
-
async createRecordSet(logicalId, resourceType, properties) {
|
|
30291
|
-
this.logger.debug(`Creating Route 53 record set ${logicalId}`);
|
|
30292
|
-
const hostedZoneId = await this.resolveHostedZoneId(properties, logicalId, resourceType);
|
|
30293
|
-
const recordName = properties["Name"];
|
|
30294
|
-
const recordType = properties["Type"];
|
|
30298
|
+
// ─── DBCluster ────────────────────────────────────────────────────
|
|
30299
|
+
async createDBCluster(logicalId, resourceType, properties) {
|
|
30300
|
+
this.logger.debug(`Creating DocDB DBCluster ${logicalId}`);
|
|
30301
|
+
const dbClusterIdentifier = properties["DBClusterIdentifier"] || generateResourceName(logicalId, { maxLength: 63, lowercase: true });
|
|
30295
30302
|
try {
|
|
30296
|
-
const
|
|
30297
|
-
const
|
|
30298
|
-
|
|
30299
|
-
|
|
30300
|
-
|
|
30301
|
-
|
|
30302
|
-
|
|
30303
|
-
|
|
30304
|
-
|
|
30305
|
-
|
|
30306
|
-
|
|
30307
|
-
|
|
30308
|
-
|
|
30309
|
-
|
|
30303
|
+
const tags = this.buildTags(properties);
|
|
30304
|
+
const response = await this.getClient().send(
|
|
30305
|
+
new CreateDBClusterCommand2({
|
|
30306
|
+
DBClusterIdentifier: dbClusterIdentifier,
|
|
30307
|
+
// DocDB engine value is fixed: only `docdb` is accepted.
|
|
30308
|
+
Engine: "docdb",
|
|
30309
|
+
EngineVersion: properties["EngineVersion"],
|
|
30310
|
+
MasterUsername: properties["MasterUsername"],
|
|
30311
|
+
MasterUserPassword: properties["MasterUserPassword"],
|
|
30312
|
+
Port: properties["Port"] != null ? Number(properties["Port"]) : void 0,
|
|
30313
|
+
VpcSecurityGroupIds: properties["VpcSecurityGroupIds"],
|
|
30314
|
+
DBSubnetGroupName: properties["DBSubnetGroupName"],
|
|
30315
|
+
StorageEncrypted: properties["StorageEncrypted"],
|
|
30316
|
+
KmsKeyId: properties["KmsKeyId"],
|
|
30317
|
+
BackupRetentionPeriod: properties["BackupRetentionPeriod"] != null ? Number(properties["BackupRetentionPeriod"]) : void 0,
|
|
30318
|
+
PreferredBackupWindow: properties["PreferredBackupWindow"],
|
|
30319
|
+
PreferredMaintenanceWindow: properties["PreferredMaintenanceWindow"],
|
|
30320
|
+
DBClusterParameterGroupName: properties["DBClusterParameterGroupName"],
|
|
30321
|
+
DeletionProtection: properties["DeletionProtection"],
|
|
30322
|
+
...tags.length > 0 && { Tags: tags }
|
|
30310
30323
|
})
|
|
30311
30324
|
);
|
|
30312
|
-
const
|
|
30313
|
-
|
|
30325
|
+
const cluster = response.DBCluster;
|
|
30326
|
+
if (!cluster) {
|
|
30327
|
+
throw new Error("CreateDBCluster did not return DBCluster");
|
|
30328
|
+
}
|
|
30329
|
+
this.logger.debug(
|
|
30330
|
+
`Successfully created DocDB DBCluster ${logicalId}: ${dbClusterIdentifier}`
|
|
30331
|
+
);
|
|
30332
|
+
if (process.env["CDKD_NO_WAIT"] !== "true") {
|
|
30333
|
+
await this.waitForClusterAvailable(dbClusterIdentifier);
|
|
30334
|
+
}
|
|
30335
|
+
const described = await this.describeDBCluster(dbClusterIdentifier);
|
|
30314
30336
|
return {
|
|
30315
|
-
physicalId:
|
|
30316
|
-
attributes: {
|
|
30337
|
+
physicalId: dbClusterIdentifier,
|
|
30338
|
+
attributes: {
|
|
30339
|
+
"Endpoint.Address": described?.Endpoint ?? "",
|
|
30340
|
+
"Endpoint.Port": String(described?.Port ?? ""),
|
|
30341
|
+
"ReadEndpoint.Address": described?.ReaderEndpoint ?? "",
|
|
30342
|
+
Arn: described?.DBClusterArn ?? "",
|
|
30343
|
+
ClusterResourceId: described?.DbClusterResourceId ?? ""
|
|
30344
|
+
}
|
|
30317
30345
|
};
|
|
30318
30346
|
} catch (error) {
|
|
30319
30347
|
if (error instanceof ProvisioningError)
|
|
30320
30348
|
throw error;
|
|
30321
30349
|
const cause = error instanceof Error ? error : void 0;
|
|
30322
30350
|
throw new ProvisioningError(
|
|
30323
|
-
`Failed to create
|
|
30351
|
+
`Failed to create DocDB DBCluster ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
30324
30352
|
resourceType,
|
|
30325
30353
|
logicalId,
|
|
30326
|
-
|
|
30354
|
+
dbClusterIdentifier,
|
|
30327
30355
|
cause
|
|
30328
30356
|
);
|
|
30329
30357
|
}
|
|
30330
30358
|
}
|
|
30331
|
-
async
|
|
30332
|
-
this.logger.debug(`Updating
|
|
30333
|
-
const hostedZoneId = await this.resolveHostedZoneId(
|
|
30334
|
-
properties,
|
|
30335
|
-
logicalId,
|
|
30336
|
-
resourceType,
|
|
30337
|
-
physicalId
|
|
30338
|
-
);
|
|
30339
|
-
const recordName = properties["Name"];
|
|
30340
|
-
const recordType = properties["Type"];
|
|
30359
|
+
async updateDBCluster(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
30360
|
+
this.logger.debug(`Updating DocDB DBCluster ${logicalId}: ${physicalId}`);
|
|
30341
30361
|
try {
|
|
30342
|
-
const
|
|
30343
|
-
const
|
|
30362
|
+
const vpcSgIds = properties["VpcSecurityGroupIds"];
|
|
30363
|
+
const sendVpcSgIds = vpcSgIds !== void 0 && vpcSgIds.length > 0;
|
|
30344
30364
|
await this.getClient().send(
|
|
30345
|
-
new
|
|
30346
|
-
|
|
30347
|
-
|
|
30348
|
-
|
|
30349
|
-
|
|
30350
|
-
|
|
30351
|
-
|
|
30352
|
-
|
|
30353
|
-
|
|
30354
|
-
|
|
30355
|
-
|
|
30365
|
+
new ModifyDBClusterCommand2({
|
|
30366
|
+
DBClusterIdentifier: physicalId,
|
|
30367
|
+
EngineVersion: properties["EngineVersion"],
|
|
30368
|
+
DeletionProtection: properties["DeletionProtection"],
|
|
30369
|
+
BackupRetentionPeriod: properties["BackupRetentionPeriod"] != null ? Number(properties["BackupRetentionPeriod"]) : void 0,
|
|
30370
|
+
PreferredBackupWindow: properties["PreferredBackupWindow"],
|
|
30371
|
+
PreferredMaintenanceWindow: properties["PreferredMaintenanceWindow"],
|
|
30372
|
+
DBClusterParameterGroupName: properties["DBClusterParameterGroupName"],
|
|
30373
|
+
...sendVpcSgIds && { VpcSecurityGroupIds: vpcSgIds },
|
|
30374
|
+
MasterUserPassword: properties["MasterUserPassword"],
|
|
30375
|
+
Port: properties["Port"] != null ? Number(properties["Port"]) : void 0,
|
|
30376
|
+
ApplyImmediately: true
|
|
30356
30377
|
})
|
|
30357
30378
|
);
|
|
30358
|
-
|
|
30359
|
-
|
|
30379
|
+
this.logger.debug(`Successfully updated DocDB DBCluster ${logicalId}`);
|
|
30380
|
+
const described = await this.describeDBCluster(physicalId);
|
|
30381
|
+
if (described?.DBClusterArn) {
|
|
30382
|
+
await this.applyTagDiff(
|
|
30383
|
+
described.DBClusterArn,
|
|
30384
|
+
previousProperties["Tags"],
|
|
30385
|
+
properties["Tags"]
|
|
30386
|
+
);
|
|
30387
|
+
}
|
|
30360
30388
|
return {
|
|
30361
|
-
physicalId
|
|
30389
|
+
physicalId,
|
|
30362
30390
|
wasReplaced: false,
|
|
30363
|
-
attributes: {
|
|
30391
|
+
attributes: {
|
|
30392
|
+
"Endpoint.Address": described?.Endpoint ?? "",
|
|
30393
|
+
"Endpoint.Port": String(described?.Port ?? ""),
|
|
30394
|
+
"ReadEndpoint.Address": described?.ReaderEndpoint ?? "",
|
|
30395
|
+
Arn: described?.DBClusterArn ?? "",
|
|
30396
|
+
ClusterResourceId: described?.DbClusterResourceId ?? ""
|
|
30397
|
+
}
|
|
30364
30398
|
};
|
|
30365
30399
|
} catch (error) {
|
|
30366
30400
|
const cause = error instanceof Error ? error : void 0;
|
|
30367
30401
|
throw new ProvisioningError(
|
|
30368
|
-
`Failed to update
|
|
30402
|
+
`Failed to update DocDB DBCluster ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
30369
30403
|
resourceType,
|
|
30370
30404
|
logicalId,
|
|
30371
30405
|
physicalId,
|
|
@@ -30373,44 +30407,39 @@ var Route53Provider = class {
|
|
|
30373
30407
|
);
|
|
30374
30408
|
}
|
|
30375
30409
|
}
|
|
30376
|
-
async
|
|
30377
|
-
this.logger.debug(`Deleting
|
|
30378
|
-
const parts = physicalId.split("|");
|
|
30379
|
-
if (parts.length !== 3) {
|
|
30380
|
-
throw new ProvisioningError(
|
|
30381
|
-
`Invalid record set physical ID format: ${physicalId}`,
|
|
30382
|
-
resourceType,
|
|
30383
|
-
logicalId,
|
|
30384
|
-
physicalId
|
|
30385
|
-
);
|
|
30386
|
-
}
|
|
30387
|
-
const [hostedZoneId] = parts;
|
|
30388
|
-
if (!properties) {
|
|
30389
|
-
throw new ProvisioningError(
|
|
30390
|
-
`Properties required to delete record set ${logicalId}`,
|
|
30391
|
-
resourceType,
|
|
30392
|
-
logicalId,
|
|
30393
|
-
physicalId
|
|
30394
|
-
);
|
|
30395
|
-
}
|
|
30410
|
+
async deleteDBCluster(logicalId, physicalId, resourceType, context) {
|
|
30411
|
+
this.logger.debug(`Deleting DocDB DBCluster ${logicalId}: ${physicalId}`);
|
|
30396
30412
|
try {
|
|
30397
|
-
|
|
30398
|
-
|
|
30399
|
-
|
|
30400
|
-
|
|
30401
|
-
|
|
30402
|
-
|
|
30403
|
-
|
|
30404
|
-
|
|
30405
|
-
|
|
30406
|
-
|
|
30407
|
-
|
|
30413
|
+
if (context?.removeProtection === true) {
|
|
30414
|
+
try {
|
|
30415
|
+
await this.getClient().send(
|
|
30416
|
+
new ModifyDBClusterCommand2({
|
|
30417
|
+
DBClusterIdentifier: physicalId,
|
|
30418
|
+
DeletionProtection: false,
|
|
30419
|
+
ApplyImmediately: true
|
|
30420
|
+
})
|
|
30421
|
+
);
|
|
30422
|
+
this.logger.debug(
|
|
30423
|
+
`Disabled DeletionProtection on DocDB DBCluster ${logicalId} before delete`
|
|
30424
|
+
);
|
|
30425
|
+
} catch (disableError) {
|
|
30426
|
+
if (!this.isNotFoundError(disableError, "DBClusterNotFoundFault")) {
|
|
30427
|
+
this.logger.debug(
|
|
30428
|
+
`Could not disable deletion protection for ${physicalId}: ${disableError instanceof Error ? disableError.message : String(disableError)}`
|
|
30429
|
+
);
|
|
30408
30430
|
}
|
|
30431
|
+
}
|
|
30432
|
+
}
|
|
30433
|
+
await this.getClient().send(
|
|
30434
|
+
new DeleteDBClusterCommand2({
|
|
30435
|
+
DBClusterIdentifier: physicalId,
|
|
30436
|
+
SkipFinalSnapshot: true
|
|
30409
30437
|
})
|
|
30410
30438
|
);
|
|
30411
|
-
this.logger.debug(`Successfully
|
|
30439
|
+
this.logger.debug(`Successfully initiated deletion of DocDB DBCluster ${logicalId}`);
|
|
30440
|
+
await this.waitForClusterDeleted(physicalId);
|
|
30412
30441
|
} catch (error) {
|
|
30413
|
-
if (
|
|
30442
|
+
if (this.isNotFoundError(error, "DBClusterNotFoundFault")) {
|
|
30414
30443
|
const clientRegion = await this.getClient().config.region();
|
|
30415
30444
|
assertRegionMatch(
|
|
30416
30445
|
clientRegion,
|
|
@@ -30419,18 +30448,12 @@ var Route53Provider = class {
|
|
|
30419
30448
|
logicalId,
|
|
30420
30449
|
physicalId
|
|
30421
30450
|
);
|
|
30422
|
-
this.logger.debug(`
|
|
30423
|
-
return;
|
|
30424
|
-
}
|
|
30425
|
-
if (error instanceof Error && error.name === "NoSuchHostedZone") {
|
|
30426
|
-
this.logger.debug(
|
|
30427
|
-
`Hosted zone for record set ${physicalId} does not exist, skipping deletion`
|
|
30428
|
-
);
|
|
30451
|
+
this.logger.debug(`DocDB DBCluster ${physicalId} does not exist, skipping deletion`);
|
|
30429
30452
|
return;
|
|
30430
30453
|
}
|
|
30431
30454
|
const cause = error instanceof Error ? error : void 0;
|
|
30432
30455
|
throw new ProvisioningError(
|
|
30433
|
-
`Failed to delete
|
|
30456
|
+
`Failed to delete DocDB DBCluster ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
30434
30457
|
resourceType,
|
|
30435
30458
|
logicalId,
|
|
30436
30459
|
physicalId,
|
|
@@ -30438,45 +30461,2007 @@ var Route53Provider = class {
|
|
|
30438
30461
|
);
|
|
30439
30462
|
}
|
|
30440
30463
|
}
|
|
30441
|
-
// ───
|
|
30442
|
-
|
|
30443
|
-
|
|
30444
|
-
|
|
30445
|
-
|
|
30446
|
-
|
|
30447
|
-
|
|
30448
|
-
|
|
30449
|
-
|
|
30450
|
-
|
|
30451
|
-
|
|
30452
|
-
|
|
30453
|
-
|
|
30454
|
-
|
|
30455
|
-
|
|
30456
|
-
|
|
30457
|
-
|
|
30458
|
-
|
|
30459
|
-
|
|
30460
|
-
|
|
30461
|
-
|
|
30462
|
-
|
|
30463
|
-
DNSName: aliasTarget["DNSName"],
|
|
30464
|
-
EvaluateTargetHealth: aliasTarget["EvaluateTargetHealth"] ?? false
|
|
30465
|
-
};
|
|
30466
|
-
} else {
|
|
30467
|
-
if (ttl !== void 0) {
|
|
30468
|
-
recordSet.TTL = Number(ttl);
|
|
30469
|
-
}
|
|
30470
|
-
if (resourceRecords) {
|
|
30471
|
-
recordSet.ResourceRecords = resourceRecords.map((record) => {
|
|
30472
|
-
if (typeof record === "string") {
|
|
30473
|
-
return { Value: record };
|
|
30474
|
-
}
|
|
30475
|
-
return record;
|
|
30476
|
-
});
|
|
30464
|
+
// ─── DBInstance ───────────────────────────────────────────────────
|
|
30465
|
+
async createDBInstance(logicalId, resourceType, properties) {
|
|
30466
|
+
this.logger.debug(`Creating DocDB DBInstance ${logicalId}`);
|
|
30467
|
+
const dbInstanceIdentifier = properties["DBInstanceIdentifier"] || generateResourceName(logicalId, { maxLength: 63, lowercase: true });
|
|
30468
|
+
try {
|
|
30469
|
+
const tags = this.buildTags(properties);
|
|
30470
|
+
const response = await this.getClient().send(
|
|
30471
|
+
new CreateDBInstanceCommand2({
|
|
30472
|
+
DBInstanceIdentifier: dbInstanceIdentifier,
|
|
30473
|
+
DBInstanceClass: properties["DBInstanceClass"],
|
|
30474
|
+
// DocDB engine value is fixed: only `docdb` is accepted.
|
|
30475
|
+
Engine: "docdb",
|
|
30476
|
+
DBClusterIdentifier: properties["DBClusterIdentifier"],
|
|
30477
|
+
AvailabilityZone: properties["AvailabilityZone"],
|
|
30478
|
+
PreferredMaintenanceWindow: properties["PreferredMaintenanceWindow"],
|
|
30479
|
+
AutoMinorVersionUpgrade: properties["AutoMinorVersionUpgrade"],
|
|
30480
|
+
...tags.length > 0 && { Tags: tags }
|
|
30481
|
+
})
|
|
30482
|
+
);
|
|
30483
|
+
const instance = response.DBInstance;
|
|
30484
|
+
if (!instance) {
|
|
30485
|
+
throw new Error("CreateDBInstance did not return DBInstance");
|
|
30477
30486
|
}
|
|
30478
|
-
|
|
30479
|
-
|
|
30487
|
+
this.logger.debug(
|
|
30488
|
+
`Successfully created DocDB DBInstance ${logicalId}: ${dbInstanceIdentifier}`
|
|
30489
|
+
);
|
|
30490
|
+
if (process.env["CDKD_NO_WAIT"] !== "true") {
|
|
30491
|
+
await this.waitForInstanceAvailable(dbInstanceIdentifier);
|
|
30492
|
+
}
|
|
30493
|
+
const described = await this.describeDBInstance(dbInstanceIdentifier);
|
|
30494
|
+
return {
|
|
30495
|
+
physicalId: dbInstanceIdentifier,
|
|
30496
|
+
attributes: {
|
|
30497
|
+
"Endpoint.Address": described?.Endpoint?.Address ?? "",
|
|
30498
|
+
"Endpoint.Port": String(described?.Endpoint?.Port ?? ""),
|
|
30499
|
+
Arn: described?.DBInstanceArn ?? ""
|
|
30500
|
+
}
|
|
30501
|
+
};
|
|
30502
|
+
} catch (error) {
|
|
30503
|
+
if (error instanceof ProvisioningError)
|
|
30504
|
+
throw error;
|
|
30505
|
+
const cause = error instanceof Error ? error : void 0;
|
|
30506
|
+
throw new ProvisioningError(
|
|
30507
|
+
`Failed to create DocDB DBInstance ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
30508
|
+
resourceType,
|
|
30509
|
+
logicalId,
|
|
30510
|
+
dbInstanceIdentifier,
|
|
30511
|
+
cause
|
|
30512
|
+
);
|
|
30513
|
+
}
|
|
30514
|
+
}
|
|
30515
|
+
async updateDBInstance(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
30516
|
+
this.logger.debug(`Updating DocDB DBInstance ${logicalId}: ${physicalId}`);
|
|
30517
|
+
try {
|
|
30518
|
+
await this.getClient().send(
|
|
30519
|
+
new ModifyDBInstanceCommand2({
|
|
30520
|
+
DBInstanceIdentifier: physicalId,
|
|
30521
|
+
DBInstanceClass: properties["DBInstanceClass"],
|
|
30522
|
+
PreferredMaintenanceWindow: properties["PreferredMaintenanceWindow"],
|
|
30523
|
+
AutoMinorVersionUpgrade: properties["AutoMinorVersionUpgrade"],
|
|
30524
|
+
ApplyImmediately: true
|
|
30525
|
+
})
|
|
30526
|
+
);
|
|
30527
|
+
this.logger.debug(`Successfully updated DocDB DBInstance ${logicalId}`);
|
|
30528
|
+
const described = await this.describeDBInstance(physicalId);
|
|
30529
|
+
if (described?.DBInstanceArn) {
|
|
30530
|
+
await this.applyTagDiff(
|
|
30531
|
+
described.DBInstanceArn,
|
|
30532
|
+
previousProperties["Tags"],
|
|
30533
|
+
properties["Tags"]
|
|
30534
|
+
);
|
|
30535
|
+
}
|
|
30536
|
+
return {
|
|
30537
|
+
physicalId,
|
|
30538
|
+
wasReplaced: false,
|
|
30539
|
+
attributes: {
|
|
30540
|
+
"Endpoint.Address": described?.Endpoint?.Address ?? "",
|
|
30541
|
+
"Endpoint.Port": String(described?.Endpoint?.Port ?? ""),
|
|
30542
|
+
Arn: described?.DBInstanceArn ?? ""
|
|
30543
|
+
}
|
|
30544
|
+
};
|
|
30545
|
+
} catch (error) {
|
|
30546
|
+
const cause = error instanceof Error ? error : void 0;
|
|
30547
|
+
throw new ProvisioningError(
|
|
30548
|
+
`Failed to update DocDB DBInstance ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
30549
|
+
resourceType,
|
|
30550
|
+
logicalId,
|
|
30551
|
+
physicalId,
|
|
30552
|
+
cause
|
|
30553
|
+
);
|
|
30554
|
+
}
|
|
30555
|
+
}
|
|
30556
|
+
async deleteDBInstance(logicalId, physicalId, resourceType, context) {
|
|
30557
|
+
this.logger.debug(`Deleting DocDB DBInstance ${logicalId}: ${physicalId}`);
|
|
30558
|
+
try {
|
|
30559
|
+
await this.getClient().send(
|
|
30560
|
+
new DeleteDBInstanceCommand2({
|
|
30561
|
+
DBInstanceIdentifier: physicalId
|
|
30562
|
+
})
|
|
30563
|
+
);
|
|
30564
|
+
this.logger.debug(`Successfully initiated deletion of DocDB DBInstance ${logicalId}`);
|
|
30565
|
+
await this.waitForInstanceDeleted(physicalId);
|
|
30566
|
+
} catch (error) {
|
|
30567
|
+
if (this.isNotFoundError(error, "DBInstanceNotFoundFault")) {
|
|
30568
|
+
const clientRegion = await this.getClient().config.region();
|
|
30569
|
+
assertRegionMatch(
|
|
30570
|
+
clientRegion,
|
|
30571
|
+
context?.expectedRegion,
|
|
30572
|
+
resourceType,
|
|
30573
|
+
logicalId,
|
|
30574
|
+
physicalId
|
|
30575
|
+
);
|
|
30576
|
+
this.logger.debug(`DocDB DBInstance ${physicalId} does not exist, skipping deletion`);
|
|
30577
|
+
return;
|
|
30578
|
+
}
|
|
30579
|
+
const cause = error instanceof Error ? error : void 0;
|
|
30580
|
+
throw new ProvisioningError(
|
|
30581
|
+
`Failed to delete DocDB DBInstance ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
30582
|
+
resourceType,
|
|
30583
|
+
logicalId,
|
|
30584
|
+
physicalId,
|
|
30585
|
+
cause
|
|
30586
|
+
);
|
|
30587
|
+
}
|
|
30588
|
+
}
|
|
30589
|
+
// ─── Helpers ──────────────────────────────────────────────────────
|
|
30590
|
+
/**
|
|
30591
|
+
* Apply a diff between old and new CFn-shape Tags arrays via DocDB's
|
|
30592
|
+
* `AddTagsToResource` / `RemoveTagsFromResource` APIs (keyed by
|
|
30593
|
+
* `ResourceName=arn`).
|
|
30594
|
+
*/
|
|
30595
|
+
async applyTagDiff(arn, oldTagsRaw, newTagsRaw) {
|
|
30596
|
+
const toMap = (tags) => {
|
|
30597
|
+
const m = /* @__PURE__ */ new Map();
|
|
30598
|
+
for (const t of tags ?? []) {
|
|
30599
|
+
if (t.Key !== void 0 && t.Value !== void 0)
|
|
30600
|
+
m.set(t.Key, t.Value);
|
|
30601
|
+
}
|
|
30602
|
+
return m;
|
|
30603
|
+
};
|
|
30604
|
+
const oldMap = toMap(oldTagsRaw);
|
|
30605
|
+
const newMap = toMap(newTagsRaw);
|
|
30606
|
+
const tagsToAdd = [];
|
|
30607
|
+
for (const [k, v] of newMap) {
|
|
30608
|
+
if (oldMap.get(k) !== v)
|
|
30609
|
+
tagsToAdd.push({ Key: k, Value: v });
|
|
30610
|
+
}
|
|
30611
|
+
const tagsToRemove = [];
|
|
30612
|
+
for (const k of oldMap.keys()) {
|
|
30613
|
+
if (!newMap.has(k))
|
|
30614
|
+
tagsToRemove.push(k);
|
|
30615
|
+
}
|
|
30616
|
+
if (tagsToRemove.length > 0) {
|
|
30617
|
+
await this.getClient().send(
|
|
30618
|
+
new RemoveTagsFromResourceCommand3({ ResourceName: arn, TagKeys: tagsToRemove })
|
|
30619
|
+
);
|
|
30620
|
+
this.logger.debug(`Removed ${tagsToRemove.length} tag(s) from DocDB resource ${arn}`);
|
|
30621
|
+
}
|
|
30622
|
+
if (tagsToAdd.length > 0) {
|
|
30623
|
+
await this.getClient().send(
|
|
30624
|
+
new AddTagsToResourceCommand3({ ResourceName: arn, Tags: tagsToAdd })
|
|
30625
|
+
);
|
|
30626
|
+
this.logger.debug(`Added/updated ${tagsToAdd.length} tag(s) on DocDB resource ${arn}`);
|
|
30627
|
+
}
|
|
30628
|
+
}
|
|
30629
|
+
buildTags(properties) {
|
|
30630
|
+
if (!properties["Tags"])
|
|
30631
|
+
return [];
|
|
30632
|
+
return properties["Tags"];
|
|
30633
|
+
}
|
|
30634
|
+
isNotFoundError(error, faultName) {
|
|
30635
|
+
if (!(error instanceof Error))
|
|
30636
|
+
return false;
|
|
30637
|
+
const name = error.name ?? "";
|
|
30638
|
+
const message = error.message.toLowerCase();
|
|
30639
|
+
return name === faultName || message.includes("not found") || message.includes("does not exist");
|
|
30640
|
+
}
|
|
30641
|
+
async describeDBCluster(dbClusterIdentifier) {
|
|
30642
|
+
const response = await this.getClient().send(
|
|
30643
|
+
new DescribeDBClustersCommand2({
|
|
30644
|
+
DBClusterIdentifier: dbClusterIdentifier
|
|
30645
|
+
})
|
|
30646
|
+
);
|
|
30647
|
+
return response.DBClusters?.[0];
|
|
30648
|
+
}
|
|
30649
|
+
async describeDBInstance(dbInstanceIdentifier) {
|
|
30650
|
+
const response = await this.getClient().send(
|
|
30651
|
+
new DescribeDBInstancesCommand2({
|
|
30652
|
+
DBInstanceIdentifier: dbInstanceIdentifier
|
|
30653
|
+
})
|
|
30654
|
+
);
|
|
30655
|
+
return response.DBInstances?.[0];
|
|
30656
|
+
}
|
|
30657
|
+
/**
|
|
30658
|
+
* Wait for a DBCluster to become available. DocDB's SDK does not ship a
|
|
30659
|
+
* `waitUntilDBClusterAvailable` waiter (only DBInstance has waiters),
|
|
30660
|
+
* so we poll Status manually with exponential backoff.
|
|
30661
|
+
*/
|
|
30662
|
+
async waitForClusterAvailable(dbClusterIdentifier, maxWaitMs = 18e5) {
|
|
30663
|
+
const startTime = Date.now();
|
|
30664
|
+
let delay = 5e3;
|
|
30665
|
+
while (Date.now() - startTime < maxWaitMs) {
|
|
30666
|
+
const cluster = await this.describeDBCluster(dbClusterIdentifier);
|
|
30667
|
+
const status = cluster?.Status;
|
|
30668
|
+
this.logger.debug(`DocDB DBCluster ${dbClusterIdentifier} status: ${status}`);
|
|
30669
|
+
if (status === "available")
|
|
30670
|
+
return;
|
|
30671
|
+
await this.sleep(delay);
|
|
30672
|
+
delay = Math.min(delay * 2, 3e4);
|
|
30673
|
+
}
|
|
30674
|
+
throw new Error(
|
|
30675
|
+
`Timed out waiting for DocDB DBCluster ${dbClusterIdentifier} to become available`
|
|
30676
|
+
);
|
|
30677
|
+
}
|
|
30678
|
+
/**
|
|
30679
|
+
* Wait for a DBCluster to be deleted (no SDK waiter — manual poll).
|
|
30680
|
+
*/
|
|
30681
|
+
async waitForClusterDeleted(dbClusterIdentifier, maxWaitMs = 18e5) {
|
|
30682
|
+
const startTime = Date.now();
|
|
30683
|
+
let delay = 5e3;
|
|
30684
|
+
while (Date.now() - startTime < maxWaitMs) {
|
|
30685
|
+
try {
|
|
30686
|
+
const cluster = await this.describeDBCluster(dbClusterIdentifier);
|
|
30687
|
+
const status = cluster?.Status;
|
|
30688
|
+
this.logger.debug(`DocDB DBCluster ${dbClusterIdentifier} status: ${status}`);
|
|
30689
|
+
if (!cluster)
|
|
30690
|
+
return;
|
|
30691
|
+
} catch (error) {
|
|
30692
|
+
if (this.isNotFoundError(error, "DBClusterNotFoundFault")) {
|
|
30693
|
+
return;
|
|
30694
|
+
}
|
|
30695
|
+
throw error;
|
|
30696
|
+
}
|
|
30697
|
+
await this.sleep(delay);
|
|
30698
|
+
delay = Math.min(delay * 2, 3e4);
|
|
30699
|
+
}
|
|
30700
|
+
throw new Error(`Timed out waiting for DocDB DBCluster ${dbClusterIdentifier} to be deleted`);
|
|
30701
|
+
}
|
|
30702
|
+
/**
|
|
30703
|
+
* Wait for a DBInstance to become available (manual poll — matches RDS).
|
|
30704
|
+
*/
|
|
30705
|
+
async waitForInstanceAvailable(dbInstanceIdentifier, maxWaitMs = 18e5) {
|
|
30706
|
+
const startTime = Date.now();
|
|
30707
|
+
let delay = 1e4;
|
|
30708
|
+
while (Date.now() - startTime < maxWaitMs) {
|
|
30709
|
+
const instance = await this.describeDBInstance(dbInstanceIdentifier);
|
|
30710
|
+
const status = instance?.DBInstanceStatus;
|
|
30711
|
+
this.logger.debug(`DocDB DBInstance ${dbInstanceIdentifier} status: ${status}`);
|
|
30712
|
+
if (status === "available")
|
|
30713
|
+
return;
|
|
30714
|
+
await this.sleep(delay);
|
|
30715
|
+
delay = Math.min(delay * 2, 3e4);
|
|
30716
|
+
}
|
|
30717
|
+
throw new Error(
|
|
30718
|
+
`Timed out waiting for DocDB DBInstance ${dbInstanceIdentifier} to become available`
|
|
30719
|
+
);
|
|
30720
|
+
}
|
|
30721
|
+
async waitForInstanceDeleted(dbInstanceIdentifier, maxWaitMs = 18e5) {
|
|
30722
|
+
const startTime = Date.now();
|
|
30723
|
+
let delay = 1e4;
|
|
30724
|
+
while (Date.now() - startTime < maxWaitMs) {
|
|
30725
|
+
try {
|
|
30726
|
+
const instance = await this.describeDBInstance(dbInstanceIdentifier);
|
|
30727
|
+
const status = instance?.DBInstanceStatus;
|
|
30728
|
+
this.logger.debug(`DocDB DBInstance ${dbInstanceIdentifier} status: ${status}`);
|
|
30729
|
+
if (!instance)
|
|
30730
|
+
return;
|
|
30731
|
+
} catch (error) {
|
|
30732
|
+
if (this.isNotFoundError(error, "DBInstanceNotFoundFault")) {
|
|
30733
|
+
return;
|
|
30734
|
+
}
|
|
30735
|
+
throw error;
|
|
30736
|
+
}
|
|
30737
|
+
await this.sleep(delay);
|
|
30738
|
+
delay = Math.min(delay * 2, 3e4);
|
|
30739
|
+
}
|
|
30740
|
+
throw new Error(`Timed out waiting for DocDB DBInstance ${dbInstanceIdentifier} to be deleted`);
|
|
30741
|
+
}
|
|
30742
|
+
sleep(ms) {
|
|
30743
|
+
return new Promise((resolve4) => setTimeout(resolve4, ms));
|
|
30744
|
+
}
|
|
30745
|
+
/**
|
|
30746
|
+
* Adopt an existing DocDB resource into cdkd state.
|
|
30747
|
+
*
|
|
30748
|
+
* Supported types: `AWS::DocDB::DBInstance`, `AWS::DocDB::DBCluster`,
|
|
30749
|
+
* `AWS::DocDB::DBSubnetGroup`. Identifier name properties (`DBInstance
|
|
30750
|
+
* Identifier` / `DBClusterIdentifier` / `DBSubnetGroupName`) are usually
|
|
30751
|
+
* present in CDK templates; fall back to `aws:cdk:path` tag lookup via
|
|
30752
|
+
* the corresponding `Describe*` + `ListTagsForResource` pair otherwise.
|
|
30753
|
+
*/
|
|
30754
|
+
async import(input) {
|
|
30755
|
+
switch (input.resourceType) {
|
|
30756
|
+
case "AWS::DocDB::DBInstance":
|
|
30757
|
+
return this.importDBInstance(input);
|
|
30758
|
+
case "AWS::DocDB::DBCluster":
|
|
30759
|
+
return this.importDBCluster(input);
|
|
30760
|
+
case "AWS::DocDB::DBSubnetGroup":
|
|
30761
|
+
return this.importDBSubnetGroup(input);
|
|
30762
|
+
default:
|
|
30763
|
+
return null;
|
|
30764
|
+
}
|
|
30765
|
+
}
|
|
30766
|
+
/**
|
|
30767
|
+
* Read the AWS-current DocDB resource configuration in CFn-property shape.
|
|
30768
|
+
*
|
|
30769
|
+
* Each branch surfaces only the keys cdkd's `create()` accepts. Sensitive
|
|
30770
|
+
* fields like `MasterUserPassword` are NEVER surfaced (DocDB does not
|
|
30771
|
+
* return them in the Describe responses). `Tags` are surfaced via a
|
|
30772
|
+
* follow-up `ListTagsForResource(ResourceName=arn)` call.
|
|
30773
|
+
*
|
|
30774
|
+
* Returns `undefined` when the resource is gone (`*NotFoundFault`).
|
|
30775
|
+
*/
|
|
30776
|
+
async readCurrentState(physicalId, _logicalId, resourceType) {
|
|
30777
|
+
switch (resourceType) {
|
|
30778
|
+
case "AWS::DocDB::DBInstance":
|
|
30779
|
+
return this.readCurrentStateDBInstance(physicalId);
|
|
30780
|
+
case "AWS::DocDB::DBCluster":
|
|
30781
|
+
return this.readCurrentStateDBCluster(physicalId);
|
|
30782
|
+
case "AWS::DocDB::DBSubnetGroup":
|
|
30783
|
+
return this.readCurrentStateDBSubnetGroup(physicalId);
|
|
30784
|
+
default:
|
|
30785
|
+
return void 0;
|
|
30786
|
+
}
|
|
30787
|
+
}
|
|
30788
|
+
async readCurrentStateDBInstance(physicalId) {
|
|
30789
|
+
let inst;
|
|
30790
|
+
try {
|
|
30791
|
+
inst = await this.describeDBInstance(physicalId);
|
|
30792
|
+
} catch (err) {
|
|
30793
|
+
if (this.isNotFoundError(err, "DBInstanceNotFoundFault"))
|
|
30794
|
+
return void 0;
|
|
30795
|
+
throw err;
|
|
30796
|
+
}
|
|
30797
|
+
if (!inst)
|
|
30798
|
+
return void 0;
|
|
30799
|
+
const result = {};
|
|
30800
|
+
if (inst.DBInstanceIdentifier !== void 0) {
|
|
30801
|
+
result["DBInstanceIdentifier"] = inst.DBInstanceIdentifier;
|
|
30802
|
+
}
|
|
30803
|
+
if (inst.DBInstanceClass !== void 0)
|
|
30804
|
+
result["DBInstanceClass"] = inst.DBInstanceClass;
|
|
30805
|
+
if (inst.DBClusterIdentifier !== void 0) {
|
|
30806
|
+
result["DBClusterIdentifier"] = inst.DBClusterIdentifier;
|
|
30807
|
+
}
|
|
30808
|
+
if (inst.AvailabilityZone !== void 0)
|
|
30809
|
+
result["AvailabilityZone"] = inst.AvailabilityZone;
|
|
30810
|
+
if (inst.PreferredMaintenanceWindow !== void 0) {
|
|
30811
|
+
result["PreferredMaintenanceWindow"] = inst.PreferredMaintenanceWindow;
|
|
30812
|
+
}
|
|
30813
|
+
if (inst.AutoMinorVersionUpgrade !== void 0) {
|
|
30814
|
+
result["AutoMinorVersionUpgrade"] = inst.AutoMinorVersionUpgrade;
|
|
30815
|
+
}
|
|
30816
|
+
if (inst.DBInstanceArn)
|
|
30817
|
+
await this.attachTags(result, inst.DBInstanceArn);
|
|
30818
|
+
return result;
|
|
30819
|
+
}
|
|
30820
|
+
async readCurrentStateDBCluster(physicalId) {
|
|
30821
|
+
let cluster;
|
|
30822
|
+
try {
|
|
30823
|
+
cluster = await this.describeDBCluster(physicalId);
|
|
30824
|
+
} catch (err) {
|
|
30825
|
+
if (this.isNotFoundError(err, "DBClusterNotFoundFault"))
|
|
30826
|
+
return void 0;
|
|
30827
|
+
throw err;
|
|
30828
|
+
}
|
|
30829
|
+
if (!cluster)
|
|
30830
|
+
return void 0;
|
|
30831
|
+
const result = {};
|
|
30832
|
+
if (cluster.DBClusterIdentifier !== void 0) {
|
|
30833
|
+
result["DBClusterIdentifier"] = cluster.DBClusterIdentifier;
|
|
30834
|
+
}
|
|
30835
|
+
if (cluster.EngineVersion !== void 0)
|
|
30836
|
+
result["EngineVersion"] = cluster.EngineVersion;
|
|
30837
|
+
if (cluster.MasterUsername !== void 0)
|
|
30838
|
+
result["MasterUsername"] = cluster.MasterUsername;
|
|
30839
|
+
if (cluster.Port !== void 0)
|
|
30840
|
+
result["Port"] = cluster.Port;
|
|
30841
|
+
result["VpcSecurityGroupIds"] = (cluster.VpcSecurityGroups ?? []).map((sg) => sg.VpcSecurityGroupId).filter((id) => !!id);
|
|
30842
|
+
if (cluster.DBSubnetGroup !== void 0)
|
|
30843
|
+
result["DBSubnetGroupName"] = cluster.DBSubnetGroup;
|
|
30844
|
+
if (cluster.StorageEncrypted !== void 0) {
|
|
30845
|
+
result["StorageEncrypted"] = cluster.StorageEncrypted;
|
|
30846
|
+
}
|
|
30847
|
+
if (cluster.KmsKeyId !== void 0)
|
|
30848
|
+
result["KmsKeyId"] = cluster.KmsKeyId;
|
|
30849
|
+
if (cluster.BackupRetentionPeriod !== void 0) {
|
|
30850
|
+
result["BackupRetentionPeriod"] = cluster.BackupRetentionPeriod;
|
|
30851
|
+
}
|
|
30852
|
+
if (cluster.PreferredBackupWindow !== void 0) {
|
|
30853
|
+
result["PreferredBackupWindow"] = cluster.PreferredBackupWindow;
|
|
30854
|
+
}
|
|
30855
|
+
if (cluster.PreferredMaintenanceWindow !== void 0) {
|
|
30856
|
+
result["PreferredMaintenanceWindow"] = cluster.PreferredMaintenanceWindow;
|
|
30857
|
+
}
|
|
30858
|
+
if (cluster.DBClusterParameterGroup !== void 0) {
|
|
30859
|
+
result["DBClusterParameterGroupName"] = cluster.DBClusterParameterGroup;
|
|
30860
|
+
}
|
|
30861
|
+
if (cluster.DeletionProtection !== void 0) {
|
|
30862
|
+
result["DeletionProtection"] = cluster.DeletionProtection;
|
|
30863
|
+
}
|
|
30864
|
+
if (cluster.DBClusterArn)
|
|
30865
|
+
await this.attachTags(result, cluster.DBClusterArn);
|
|
30866
|
+
return result;
|
|
30867
|
+
}
|
|
30868
|
+
async readCurrentStateDBSubnetGroup(physicalId) {
|
|
30869
|
+
let resp;
|
|
30870
|
+
try {
|
|
30871
|
+
resp = await this.getClient().send(
|
|
30872
|
+
new DescribeDBSubnetGroupsCommand2({ DBSubnetGroupName: physicalId })
|
|
30873
|
+
);
|
|
30874
|
+
} catch (err) {
|
|
30875
|
+
if (this.isNotFoundError(err, "DBSubnetGroupNotFoundFault"))
|
|
30876
|
+
return void 0;
|
|
30877
|
+
throw err;
|
|
30878
|
+
}
|
|
30879
|
+
const sg = resp.DBSubnetGroups?.[0];
|
|
30880
|
+
if (!sg)
|
|
30881
|
+
return void 0;
|
|
30882
|
+
const result = {};
|
|
30883
|
+
if (sg.DBSubnetGroupName !== void 0)
|
|
30884
|
+
result["DBSubnetGroupName"] = sg.DBSubnetGroupName;
|
|
30885
|
+
if (sg.DBSubnetGroupDescription !== void 0) {
|
|
30886
|
+
result["DBSubnetGroupDescription"] = sg.DBSubnetGroupDescription;
|
|
30887
|
+
}
|
|
30888
|
+
result["SubnetIds"] = (sg.Subnets ?? []).map((s) => s.SubnetIdentifier).filter((id) => !!id);
|
|
30889
|
+
if (sg.DBSubnetGroupArn)
|
|
30890
|
+
await this.attachTags(result, sg.DBSubnetGroupArn);
|
|
30891
|
+
return result;
|
|
30892
|
+
}
|
|
30893
|
+
/**
|
|
30894
|
+
* Fetch tags via `ListTagsForResource(ResourceName=arn)` and merge them
|
|
30895
|
+
* into the result under `Tags` (CFn shape, `aws:*` filtered out, omitted
|
|
30896
|
+
* when empty). Best-effort: tag-fetch failures are logged at debug and
|
|
30897
|
+
* the key is simply left out — drift detection on configuration is more
|
|
30898
|
+
* important than fail-closing on a missing tag permission.
|
|
30899
|
+
*/
|
|
30900
|
+
async attachTags(result, arn) {
|
|
30901
|
+
try {
|
|
30902
|
+
const tagsResp = await this.getClient().send(
|
|
30903
|
+
new ListTagsForResourceCommand11({ ResourceName: arn })
|
|
30904
|
+
);
|
|
30905
|
+
const tags = normalizeAwsTagsToCfn(tagsResp.TagList);
|
|
30906
|
+
result["Tags"] = tags;
|
|
30907
|
+
} catch (err) {
|
|
30908
|
+
this.logger.debug(
|
|
30909
|
+
`DocDB ListTagsForResource(${arn}) failed: ${err instanceof Error ? err.message : String(err)}`
|
|
30910
|
+
);
|
|
30911
|
+
}
|
|
30912
|
+
}
|
|
30913
|
+
async importDBInstance(input) {
|
|
30914
|
+
const explicit = resolveExplicitPhysicalId(input, "DBInstanceIdentifier");
|
|
30915
|
+
if (explicit) {
|
|
30916
|
+
try {
|
|
30917
|
+
await this.getClient().send(
|
|
30918
|
+
new DescribeDBInstancesCommand2({ DBInstanceIdentifier: explicit })
|
|
30919
|
+
);
|
|
30920
|
+
return { physicalId: explicit, attributes: {} };
|
|
30921
|
+
} catch (err) {
|
|
30922
|
+
if (err.name === "DBInstanceNotFoundFault")
|
|
30923
|
+
return null;
|
|
30924
|
+
throw err;
|
|
30925
|
+
}
|
|
30926
|
+
}
|
|
30927
|
+
if (!input.cdkPath)
|
|
30928
|
+
return null;
|
|
30929
|
+
let marker;
|
|
30930
|
+
do {
|
|
30931
|
+
const list = await this.getClient().send(
|
|
30932
|
+
new DescribeDBInstancesCommand2({ ...marker && { Marker: marker } })
|
|
30933
|
+
);
|
|
30934
|
+
for (const inst of list.DBInstances ?? []) {
|
|
30935
|
+
if (!inst.DBInstanceIdentifier || !inst.DBInstanceArn)
|
|
30936
|
+
continue;
|
|
30937
|
+
const tagsResp = await this.getClient().send(
|
|
30938
|
+
new ListTagsForResourceCommand11({ ResourceName: inst.DBInstanceArn })
|
|
30939
|
+
);
|
|
30940
|
+
if (matchesCdkPath(tagsResp.TagList, input.cdkPath)) {
|
|
30941
|
+
return { physicalId: inst.DBInstanceIdentifier, attributes: {} };
|
|
30942
|
+
}
|
|
30943
|
+
}
|
|
30944
|
+
marker = list.Marker;
|
|
30945
|
+
} while (marker);
|
|
30946
|
+
return null;
|
|
30947
|
+
}
|
|
30948
|
+
async importDBCluster(input) {
|
|
30949
|
+
const explicit = resolveExplicitPhysicalId(input, "DBClusterIdentifier");
|
|
30950
|
+
if (explicit) {
|
|
30951
|
+
try {
|
|
30952
|
+
await this.getClient().send(
|
|
30953
|
+
new DescribeDBClustersCommand2({ DBClusterIdentifier: explicit })
|
|
30954
|
+
);
|
|
30955
|
+
return { physicalId: explicit, attributes: {} };
|
|
30956
|
+
} catch (err) {
|
|
30957
|
+
if (err.name === "DBClusterNotFoundFault")
|
|
30958
|
+
return null;
|
|
30959
|
+
throw err;
|
|
30960
|
+
}
|
|
30961
|
+
}
|
|
30962
|
+
if (!input.cdkPath)
|
|
30963
|
+
return null;
|
|
30964
|
+
let marker;
|
|
30965
|
+
do {
|
|
30966
|
+
const list = await this.getClient().send(
|
|
30967
|
+
new DescribeDBClustersCommand2({ ...marker && { Marker: marker } })
|
|
30968
|
+
);
|
|
30969
|
+
for (const c of list.DBClusters ?? []) {
|
|
30970
|
+
if (!c.DBClusterIdentifier || !c.DBClusterArn)
|
|
30971
|
+
continue;
|
|
30972
|
+
const tagsResp = await this.getClient().send(
|
|
30973
|
+
new ListTagsForResourceCommand11({ ResourceName: c.DBClusterArn })
|
|
30974
|
+
);
|
|
30975
|
+
if (matchesCdkPath(tagsResp.TagList, input.cdkPath)) {
|
|
30976
|
+
return { physicalId: c.DBClusterIdentifier, attributes: {} };
|
|
30977
|
+
}
|
|
30978
|
+
}
|
|
30979
|
+
marker = list.Marker;
|
|
30980
|
+
} while (marker);
|
|
30981
|
+
return null;
|
|
30982
|
+
}
|
|
30983
|
+
async importDBSubnetGroup(input) {
|
|
30984
|
+
const explicit = resolveExplicitPhysicalId(input, "DBSubnetGroupName");
|
|
30985
|
+
if (explicit) {
|
|
30986
|
+
try {
|
|
30987
|
+
await this.getClient().send(
|
|
30988
|
+
new DescribeDBSubnetGroupsCommand2({ DBSubnetGroupName: explicit })
|
|
30989
|
+
);
|
|
30990
|
+
return { physicalId: explicit, attributes: {} };
|
|
30991
|
+
} catch (err) {
|
|
30992
|
+
if (err.name === "DBSubnetGroupNotFoundFault")
|
|
30993
|
+
return null;
|
|
30994
|
+
throw err;
|
|
30995
|
+
}
|
|
30996
|
+
}
|
|
30997
|
+
if (!input.cdkPath)
|
|
30998
|
+
return null;
|
|
30999
|
+
let marker;
|
|
31000
|
+
do {
|
|
31001
|
+
const list = await this.getClient().send(
|
|
31002
|
+
new DescribeDBSubnetGroupsCommand2({ ...marker && { Marker: marker } })
|
|
31003
|
+
);
|
|
31004
|
+
for (const sg of list.DBSubnetGroups ?? []) {
|
|
31005
|
+
if (!sg.DBSubnetGroupName || !sg.DBSubnetGroupArn)
|
|
31006
|
+
continue;
|
|
31007
|
+
const tagsResp = await this.getClient().send(
|
|
31008
|
+
new ListTagsForResourceCommand11({ ResourceName: sg.DBSubnetGroupArn })
|
|
31009
|
+
);
|
|
31010
|
+
if (matchesCdkPath(tagsResp.TagList, input.cdkPath)) {
|
|
31011
|
+
return { physicalId: sg.DBSubnetGroupName, attributes: {} };
|
|
31012
|
+
}
|
|
31013
|
+
}
|
|
31014
|
+
marker = list.Marker;
|
|
31015
|
+
} while (marker);
|
|
31016
|
+
return null;
|
|
31017
|
+
}
|
|
31018
|
+
};
|
|
31019
|
+
|
|
31020
|
+
// src/provisioning/providers/neptune-provider.ts
|
|
31021
|
+
import {
|
|
31022
|
+
NeptuneClient,
|
|
31023
|
+
CreateDBClusterCommand as CreateDBClusterCommand3,
|
|
31024
|
+
DeleteDBClusterCommand as DeleteDBClusterCommand3,
|
|
31025
|
+
ModifyDBClusterCommand as ModifyDBClusterCommand3,
|
|
31026
|
+
DescribeDBClustersCommand as DescribeDBClustersCommand3,
|
|
31027
|
+
CreateDBInstanceCommand as CreateDBInstanceCommand3,
|
|
31028
|
+
DeleteDBInstanceCommand as DeleteDBInstanceCommand3,
|
|
31029
|
+
ModifyDBInstanceCommand as ModifyDBInstanceCommand3,
|
|
31030
|
+
DescribeDBInstancesCommand as DescribeDBInstancesCommand3,
|
|
31031
|
+
CreateDBSubnetGroupCommand as CreateDBSubnetGroupCommand3,
|
|
31032
|
+
DeleteDBSubnetGroupCommand as DeleteDBSubnetGroupCommand3,
|
|
31033
|
+
DescribeDBSubnetGroupsCommand as DescribeDBSubnetGroupsCommand3,
|
|
31034
|
+
ModifyDBSubnetGroupCommand as ModifyDBSubnetGroupCommand3,
|
|
31035
|
+
ListTagsForResourceCommand as ListTagsForResourceCommand12,
|
|
31036
|
+
AddTagsToResourceCommand as AddTagsToResourceCommand4,
|
|
31037
|
+
RemoveTagsFromResourceCommand as RemoveTagsFromResourceCommand4
|
|
31038
|
+
} from "@aws-sdk/client-neptune";
|
|
31039
|
+
var NeptuneProvider = class {
|
|
31040
|
+
neptuneClient;
|
|
31041
|
+
providerRegion = process.env["AWS_REGION"];
|
|
31042
|
+
logger = getLogger().child("NeptuneProvider");
|
|
31043
|
+
handledProperties = /* @__PURE__ */ new Map([
|
|
31044
|
+
[
|
|
31045
|
+
"AWS::Neptune::DBSubnetGroup",
|
|
31046
|
+
/* @__PURE__ */ new Set(["DBSubnetGroupName", "DBSubnetGroupDescription", "SubnetIds", "Tags"])
|
|
31047
|
+
],
|
|
31048
|
+
[
|
|
31049
|
+
"AWS::Neptune::DBCluster",
|
|
31050
|
+
/* @__PURE__ */ new Set([
|
|
31051
|
+
"DBClusterIdentifier",
|
|
31052
|
+
"EngineVersion",
|
|
31053
|
+
"Port",
|
|
31054
|
+
"VpcSecurityGroupIds",
|
|
31055
|
+
"DBSubnetGroupName",
|
|
31056
|
+
"StorageEncrypted",
|
|
31057
|
+
"KmsKeyId",
|
|
31058
|
+
"BackupRetentionPeriod",
|
|
31059
|
+
"PreferredBackupWindow",
|
|
31060
|
+
"PreferredMaintenanceWindow",
|
|
31061
|
+
"DBClusterParameterGroupName",
|
|
31062
|
+
"IamAuthEnabled",
|
|
31063
|
+
"DeletionProtection",
|
|
31064
|
+
"Tags"
|
|
31065
|
+
])
|
|
31066
|
+
],
|
|
31067
|
+
[
|
|
31068
|
+
"AWS::Neptune::DBInstance",
|
|
31069
|
+
/* @__PURE__ */ new Set([
|
|
31070
|
+
"DBInstanceIdentifier",
|
|
31071
|
+
"DBInstanceClass",
|
|
31072
|
+
"DBClusterIdentifier",
|
|
31073
|
+
"DBSubnetGroupName",
|
|
31074
|
+
"DBParameterGroupName",
|
|
31075
|
+
"AvailabilityZone",
|
|
31076
|
+
"PreferredMaintenanceWindow",
|
|
31077
|
+
"AutoMinorVersionUpgrade",
|
|
31078
|
+
"DeletionProtection",
|
|
31079
|
+
"Tags"
|
|
31080
|
+
])
|
|
31081
|
+
]
|
|
31082
|
+
]);
|
|
31083
|
+
getClient() {
|
|
31084
|
+
if (!this.neptuneClient) {
|
|
31085
|
+
this.neptuneClient = new NeptuneClient(
|
|
31086
|
+
this.providerRegion ? { region: this.providerRegion } : {}
|
|
31087
|
+
);
|
|
31088
|
+
}
|
|
31089
|
+
return this.neptuneClient;
|
|
31090
|
+
}
|
|
31091
|
+
// ─── Dispatch ─────────────────────────────────────────────────────
|
|
31092
|
+
async create(logicalId, resourceType, properties) {
|
|
31093
|
+
switch (resourceType) {
|
|
31094
|
+
case "AWS::Neptune::DBSubnetGroup":
|
|
31095
|
+
return this.createDBSubnetGroup(logicalId, resourceType, properties);
|
|
31096
|
+
case "AWS::Neptune::DBCluster":
|
|
31097
|
+
return this.createDBCluster(logicalId, resourceType, properties);
|
|
31098
|
+
case "AWS::Neptune::DBInstance":
|
|
31099
|
+
return this.createDBInstance(logicalId, resourceType, properties);
|
|
31100
|
+
default:
|
|
31101
|
+
throw new ProvisioningError(
|
|
31102
|
+
`Unsupported resource type: ${resourceType}`,
|
|
31103
|
+
resourceType,
|
|
31104
|
+
logicalId
|
|
31105
|
+
);
|
|
31106
|
+
}
|
|
31107
|
+
}
|
|
31108
|
+
async update(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
31109
|
+
switch (resourceType) {
|
|
31110
|
+
case "AWS::Neptune::DBSubnetGroup":
|
|
31111
|
+
return this.updateDBSubnetGroup(
|
|
31112
|
+
logicalId,
|
|
31113
|
+
physicalId,
|
|
31114
|
+
resourceType,
|
|
31115
|
+
properties,
|
|
31116
|
+
previousProperties
|
|
31117
|
+
);
|
|
31118
|
+
case "AWS::Neptune::DBCluster":
|
|
31119
|
+
return this.updateDBCluster(
|
|
31120
|
+
logicalId,
|
|
31121
|
+
physicalId,
|
|
31122
|
+
resourceType,
|
|
31123
|
+
properties,
|
|
31124
|
+
previousProperties
|
|
31125
|
+
);
|
|
31126
|
+
case "AWS::Neptune::DBInstance":
|
|
31127
|
+
return this.updateDBInstance(
|
|
31128
|
+
logicalId,
|
|
31129
|
+
physicalId,
|
|
31130
|
+
resourceType,
|
|
31131
|
+
properties,
|
|
31132
|
+
previousProperties
|
|
31133
|
+
);
|
|
31134
|
+
default:
|
|
31135
|
+
throw new ProvisioningError(
|
|
31136
|
+
`Unsupported resource type: ${resourceType}`,
|
|
31137
|
+
resourceType,
|
|
31138
|
+
logicalId,
|
|
31139
|
+
physicalId
|
|
31140
|
+
);
|
|
31141
|
+
}
|
|
31142
|
+
}
|
|
31143
|
+
async delete(logicalId, physicalId, resourceType, _properties, context) {
|
|
31144
|
+
switch (resourceType) {
|
|
31145
|
+
case "AWS::Neptune::DBSubnetGroup":
|
|
31146
|
+
return this.deleteDBSubnetGroup(logicalId, physicalId, resourceType, context);
|
|
31147
|
+
case "AWS::Neptune::DBCluster":
|
|
31148
|
+
return this.deleteDBCluster(logicalId, physicalId, resourceType, context);
|
|
31149
|
+
case "AWS::Neptune::DBInstance":
|
|
31150
|
+
return this.deleteDBInstance(logicalId, physicalId, resourceType, context);
|
|
31151
|
+
default:
|
|
31152
|
+
throw new ProvisioningError(
|
|
31153
|
+
`Unsupported resource type: ${resourceType}`,
|
|
31154
|
+
resourceType,
|
|
31155
|
+
logicalId,
|
|
31156
|
+
physicalId
|
|
31157
|
+
);
|
|
31158
|
+
}
|
|
31159
|
+
}
|
|
31160
|
+
// ─── DBSubnetGroup ────────────────────────────────────────────────
|
|
31161
|
+
async createDBSubnetGroup(logicalId, resourceType, properties) {
|
|
31162
|
+
this.logger.debug(`Creating Neptune DBSubnetGroup ${logicalId}`);
|
|
31163
|
+
const dbSubnetGroupName = properties["DBSubnetGroupName"] || generateResourceName(logicalId, { maxLength: 255, lowercase: true });
|
|
31164
|
+
try {
|
|
31165
|
+
const tags = this.buildTags(properties);
|
|
31166
|
+
await this.getClient().send(
|
|
31167
|
+
new CreateDBSubnetGroupCommand3({
|
|
31168
|
+
DBSubnetGroupName: dbSubnetGroupName,
|
|
31169
|
+
DBSubnetGroupDescription: properties["DBSubnetGroupDescription"] || `Subnet group for ${logicalId}`,
|
|
31170
|
+
SubnetIds: properties["SubnetIds"],
|
|
31171
|
+
...tags.length > 0 && { Tags: tags }
|
|
31172
|
+
})
|
|
31173
|
+
);
|
|
31174
|
+
this.logger.debug(
|
|
31175
|
+
`Successfully created Neptune DBSubnetGroup ${logicalId}: ${dbSubnetGroupName}`
|
|
31176
|
+
);
|
|
31177
|
+
return {
|
|
31178
|
+
physicalId: dbSubnetGroupName,
|
|
31179
|
+
attributes: {
|
|
31180
|
+
DBSubnetGroupName: dbSubnetGroupName
|
|
31181
|
+
}
|
|
31182
|
+
};
|
|
31183
|
+
} catch (error) {
|
|
31184
|
+
const cause = error instanceof Error ? error : void 0;
|
|
31185
|
+
throw new ProvisioningError(
|
|
31186
|
+
`Failed to create Neptune DBSubnetGroup ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
31187
|
+
resourceType,
|
|
31188
|
+
logicalId,
|
|
31189
|
+
dbSubnetGroupName,
|
|
31190
|
+
cause
|
|
31191
|
+
);
|
|
31192
|
+
}
|
|
31193
|
+
}
|
|
31194
|
+
async updateDBSubnetGroup(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
31195
|
+
this.logger.debug(`Updating Neptune DBSubnetGroup ${logicalId}: ${physicalId}`);
|
|
31196
|
+
try {
|
|
31197
|
+
const subnetIds = properties["SubnetIds"];
|
|
31198
|
+
const sendSubnetIds = subnetIds !== void 0 && subnetIds.length > 0;
|
|
31199
|
+
const modifyInput = {
|
|
31200
|
+
DBSubnetGroupName: physicalId,
|
|
31201
|
+
DBSubnetGroupDescription: properties["DBSubnetGroupDescription"],
|
|
31202
|
+
...sendSubnetIds && { SubnetIds: subnetIds }
|
|
31203
|
+
};
|
|
31204
|
+
await this.getClient().send(new ModifyDBSubnetGroupCommand3(modifyInput));
|
|
31205
|
+
const desc = await this.getClient().send(
|
|
31206
|
+
new DescribeDBSubnetGroupsCommand3({ DBSubnetGroupName: physicalId })
|
|
31207
|
+
);
|
|
31208
|
+
const arn = desc.DBSubnetGroups?.[0]?.DBSubnetGroupArn;
|
|
31209
|
+
if (arn) {
|
|
31210
|
+
await this.applyTagDiff(
|
|
31211
|
+
arn,
|
|
31212
|
+
previousProperties["Tags"],
|
|
31213
|
+
properties["Tags"]
|
|
31214
|
+
);
|
|
31215
|
+
}
|
|
31216
|
+
this.logger.debug(`Successfully updated Neptune DBSubnetGroup ${logicalId}`);
|
|
31217
|
+
return {
|
|
31218
|
+
physicalId,
|
|
31219
|
+
wasReplaced: false,
|
|
31220
|
+
attributes: {
|
|
31221
|
+
DBSubnetGroupName: physicalId
|
|
31222
|
+
}
|
|
31223
|
+
};
|
|
31224
|
+
} catch (error) {
|
|
31225
|
+
const cause = error instanceof Error ? error : void 0;
|
|
31226
|
+
throw new ProvisioningError(
|
|
31227
|
+
`Failed to update Neptune DBSubnetGroup ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
31228
|
+
resourceType,
|
|
31229
|
+
logicalId,
|
|
31230
|
+
physicalId,
|
|
31231
|
+
cause
|
|
31232
|
+
);
|
|
31233
|
+
}
|
|
31234
|
+
}
|
|
31235
|
+
async deleteDBSubnetGroup(logicalId, physicalId, resourceType, context) {
|
|
31236
|
+
this.logger.debug(`Deleting Neptune DBSubnetGroup ${logicalId}: ${physicalId}`);
|
|
31237
|
+
try {
|
|
31238
|
+
await this.getClient().send(
|
|
31239
|
+
new DeleteDBSubnetGroupCommand3({
|
|
31240
|
+
DBSubnetGroupName: physicalId
|
|
31241
|
+
})
|
|
31242
|
+
);
|
|
31243
|
+
this.logger.debug(`Successfully deleted Neptune DBSubnetGroup ${logicalId}`);
|
|
31244
|
+
} catch (error) {
|
|
31245
|
+
if (this.isNotFoundError(error, "DBSubnetGroupNotFoundFault")) {
|
|
31246
|
+
const clientRegion = await this.getClient().config.region();
|
|
31247
|
+
assertRegionMatch(
|
|
31248
|
+
clientRegion,
|
|
31249
|
+
context?.expectedRegion,
|
|
31250
|
+
resourceType,
|
|
31251
|
+
logicalId,
|
|
31252
|
+
physicalId
|
|
31253
|
+
);
|
|
31254
|
+
this.logger.debug(`Neptune DBSubnetGroup ${physicalId} does not exist, skipping deletion`);
|
|
31255
|
+
return;
|
|
31256
|
+
}
|
|
31257
|
+
const cause = error instanceof Error ? error : void 0;
|
|
31258
|
+
throw new ProvisioningError(
|
|
31259
|
+
`Failed to delete Neptune DBSubnetGroup ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
31260
|
+
resourceType,
|
|
31261
|
+
logicalId,
|
|
31262
|
+
physicalId,
|
|
31263
|
+
cause
|
|
31264
|
+
);
|
|
31265
|
+
}
|
|
31266
|
+
}
|
|
31267
|
+
// ─── DBCluster ────────────────────────────────────────────────────
|
|
31268
|
+
async createDBCluster(logicalId, resourceType, properties) {
|
|
31269
|
+
this.logger.debug(`Creating Neptune DBCluster ${logicalId}`);
|
|
31270
|
+
const dbClusterIdentifier = properties["DBClusterIdentifier"] || generateResourceName(logicalId, { maxLength: 63, lowercase: true });
|
|
31271
|
+
try {
|
|
31272
|
+
const tags = this.buildTags(properties);
|
|
31273
|
+
const response = await this.getClient().send(
|
|
31274
|
+
new CreateDBClusterCommand3({
|
|
31275
|
+
DBClusterIdentifier: dbClusterIdentifier,
|
|
31276
|
+
// Neptune engine value is fixed: only `neptune` is accepted.
|
|
31277
|
+
Engine: "neptune",
|
|
31278
|
+
EngineVersion: properties["EngineVersion"],
|
|
31279
|
+
Port: properties["Port"] != null ? Number(properties["Port"]) : void 0,
|
|
31280
|
+
VpcSecurityGroupIds: properties["VpcSecurityGroupIds"],
|
|
31281
|
+
DBSubnetGroupName: properties["DBSubnetGroupName"],
|
|
31282
|
+
StorageEncrypted: properties["StorageEncrypted"],
|
|
31283
|
+
KmsKeyId: properties["KmsKeyId"],
|
|
31284
|
+
BackupRetentionPeriod: properties["BackupRetentionPeriod"] != null ? Number(properties["BackupRetentionPeriod"]) : void 0,
|
|
31285
|
+
PreferredBackupWindow: properties["PreferredBackupWindow"],
|
|
31286
|
+
PreferredMaintenanceWindow: properties["PreferredMaintenanceWindow"],
|
|
31287
|
+
DBClusterParameterGroupName: properties["DBClusterParameterGroupName"],
|
|
31288
|
+
EnableIAMDatabaseAuthentication: properties["IamAuthEnabled"],
|
|
31289
|
+
DeletionProtection: properties["DeletionProtection"],
|
|
31290
|
+
...tags.length > 0 && { Tags: tags }
|
|
31291
|
+
})
|
|
31292
|
+
);
|
|
31293
|
+
const cluster = response.DBCluster;
|
|
31294
|
+
if (!cluster) {
|
|
31295
|
+
throw new Error("CreateDBCluster did not return DBCluster");
|
|
31296
|
+
}
|
|
31297
|
+
this.logger.debug(
|
|
31298
|
+
`Successfully created Neptune DBCluster ${logicalId}: ${dbClusterIdentifier}`
|
|
31299
|
+
);
|
|
31300
|
+
if (process.env["CDKD_NO_WAIT"] !== "true") {
|
|
31301
|
+
await this.waitForClusterAvailable(dbClusterIdentifier);
|
|
31302
|
+
}
|
|
31303
|
+
const described = await this.describeDBCluster(dbClusterIdentifier);
|
|
31304
|
+
return {
|
|
31305
|
+
physicalId: dbClusterIdentifier,
|
|
31306
|
+
attributes: {
|
|
31307
|
+
"Endpoint.Address": described?.Endpoint ?? "",
|
|
31308
|
+
"Endpoint.Port": String(described?.Port ?? ""),
|
|
31309
|
+
"ReadEndpoint.Address": described?.ReaderEndpoint ?? "",
|
|
31310
|
+
ClusterResourceId: described?.DbClusterResourceId ?? ""
|
|
31311
|
+
}
|
|
31312
|
+
};
|
|
31313
|
+
} catch (error) {
|
|
31314
|
+
if (error instanceof ProvisioningError)
|
|
31315
|
+
throw error;
|
|
31316
|
+
const cause = error instanceof Error ? error : void 0;
|
|
31317
|
+
throw new ProvisioningError(
|
|
31318
|
+
`Failed to create Neptune DBCluster ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
31319
|
+
resourceType,
|
|
31320
|
+
logicalId,
|
|
31321
|
+
dbClusterIdentifier,
|
|
31322
|
+
cause
|
|
31323
|
+
);
|
|
31324
|
+
}
|
|
31325
|
+
}
|
|
31326
|
+
async updateDBCluster(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
31327
|
+
this.logger.debug(`Updating Neptune DBCluster ${logicalId}: ${physicalId}`);
|
|
31328
|
+
try {
|
|
31329
|
+
const vpcSgIds = properties["VpcSecurityGroupIds"];
|
|
31330
|
+
const sendVpcSgIds = vpcSgIds !== void 0 && vpcSgIds.length > 0;
|
|
31331
|
+
await this.getClient().send(
|
|
31332
|
+
new ModifyDBClusterCommand3({
|
|
31333
|
+
DBClusterIdentifier: physicalId,
|
|
31334
|
+
EngineVersion: properties["EngineVersion"],
|
|
31335
|
+
DeletionProtection: properties["DeletionProtection"],
|
|
31336
|
+
BackupRetentionPeriod: properties["BackupRetentionPeriod"] != null ? Number(properties["BackupRetentionPeriod"]) : void 0,
|
|
31337
|
+
PreferredBackupWindow: properties["PreferredBackupWindow"],
|
|
31338
|
+
PreferredMaintenanceWindow: properties["PreferredMaintenanceWindow"],
|
|
31339
|
+
DBClusterParameterGroupName: properties["DBClusterParameterGroupName"],
|
|
31340
|
+
EnableIAMDatabaseAuthentication: properties["IamAuthEnabled"],
|
|
31341
|
+
...sendVpcSgIds && { VpcSecurityGroupIds: vpcSgIds },
|
|
31342
|
+
Port: properties["Port"] != null ? Number(properties["Port"]) : void 0,
|
|
31343
|
+
ApplyImmediately: true
|
|
31344
|
+
})
|
|
31345
|
+
);
|
|
31346
|
+
this.logger.debug(`Successfully updated Neptune DBCluster ${logicalId}`);
|
|
31347
|
+
const described = await this.describeDBCluster(physicalId);
|
|
31348
|
+
if (described?.DBClusterArn) {
|
|
31349
|
+
await this.applyTagDiff(
|
|
31350
|
+
described.DBClusterArn,
|
|
31351
|
+
previousProperties["Tags"],
|
|
31352
|
+
properties["Tags"]
|
|
31353
|
+
);
|
|
31354
|
+
}
|
|
31355
|
+
return {
|
|
31356
|
+
physicalId,
|
|
31357
|
+
wasReplaced: false,
|
|
31358
|
+
attributes: {
|
|
31359
|
+
"Endpoint.Address": described?.Endpoint ?? "",
|
|
31360
|
+
"Endpoint.Port": String(described?.Port ?? ""),
|
|
31361
|
+
"ReadEndpoint.Address": described?.ReaderEndpoint ?? "",
|
|
31362
|
+
ClusterResourceId: described?.DbClusterResourceId ?? ""
|
|
31363
|
+
}
|
|
31364
|
+
};
|
|
31365
|
+
} catch (error) {
|
|
31366
|
+
const cause = error instanceof Error ? error : void 0;
|
|
31367
|
+
throw new ProvisioningError(
|
|
31368
|
+
`Failed to update Neptune DBCluster ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
31369
|
+
resourceType,
|
|
31370
|
+
logicalId,
|
|
31371
|
+
physicalId,
|
|
31372
|
+
cause
|
|
31373
|
+
);
|
|
31374
|
+
}
|
|
31375
|
+
}
|
|
31376
|
+
async deleteDBCluster(logicalId, physicalId, resourceType, context) {
|
|
31377
|
+
this.logger.debug(`Deleting Neptune DBCluster ${logicalId}: ${physicalId}`);
|
|
31378
|
+
try {
|
|
31379
|
+
if (context?.removeProtection === true) {
|
|
31380
|
+
try {
|
|
31381
|
+
await this.getClient().send(
|
|
31382
|
+
new ModifyDBClusterCommand3({
|
|
31383
|
+
DBClusterIdentifier: physicalId,
|
|
31384
|
+
DeletionProtection: false,
|
|
31385
|
+
ApplyImmediately: true
|
|
31386
|
+
})
|
|
31387
|
+
);
|
|
31388
|
+
this.logger.debug(
|
|
31389
|
+
`Disabled DeletionProtection on Neptune DBCluster ${logicalId} before delete`
|
|
31390
|
+
);
|
|
31391
|
+
} catch (disableError) {
|
|
31392
|
+
if (!this.isNotFoundError(disableError, "DBClusterNotFoundFault")) {
|
|
31393
|
+
this.logger.debug(
|
|
31394
|
+
`Could not disable deletion protection for ${physicalId}: ${disableError instanceof Error ? disableError.message : String(disableError)}`
|
|
31395
|
+
);
|
|
31396
|
+
}
|
|
31397
|
+
}
|
|
31398
|
+
}
|
|
31399
|
+
await this.getClient().send(
|
|
31400
|
+
new DeleteDBClusterCommand3({
|
|
31401
|
+
DBClusterIdentifier: physicalId,
|
|
31402
|
+
SkipFinalSnapshot: true
|
|
31403
|
+
})
|
|
31404
|
+
);
|
|
31405
|
+
this.logger.debug(`Successfully initiated deletion of Neptune DBCluster ${logicalId}`);
|
|
31406
|
+
await this.waitForClusterDeleted(physicalId);
|
|
31407
|
+
} catch (error) {
|
|
31408
|
+
if (this.isNotFoundError(error, "DBClusterNotFoundFault")) {
|
|
31409
|
+
const clientRegion = await this.getClient().config.region();
|
|
31410
|
+
assertRegionMatch(
|
|
31411
|
+
clientRegion,
|
|
31412
|
+
context?.expectedRegion,
|
|
31413
|
+
resourceType,
|
|
31414
|
+
logicalId,
|
|
31415
|
+
physicalId
|
|
31416
|
+
);
|
|
31417
|
+
this.logger.debug(`Neptune DBCluster ${physicalId} does not exist, skipping deletion`);
|
|
31418
|
+
return;
|
|
31419
|
+
}
|
|
31420
|
+
const cause = error instanceof Error ? error : void 0;
|
|
31421
|
+
throw new ProvisioningError(
|
|
31422
|
+
`Failed to delete Neptune DBCluster ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
31423
|
+
resourceType,
|
|
31424
|
+
logicalId,
|
|
31425
|
+
physicalId,
|
|
31426
|
+
cause
|
|
31427
|
+
);
|
|
31428
|
+
}
|
|
31429
|
+
}
|
|
31430
|
+
// ─── DBInstance ───────────────────────────────────────────────────
|
|
31431
|
+
async createDBInstance(logicalId, resourceType, properties) {
|
|
31432
|
+
this.logger.debug(`Creating Neptune DBInstance ${logicalId}`);
|
|
31433
|
+
const dbInstanceIdentifier = properties["DBInstanceIdentifier"] || generateResourceName(logicalId, { maxLength: 63, lowercase: true });
|
|
31434
|
+
try {
|
|
31435
|
+
const tags = this.buildTags(properties);
|
|
31436
|
+
const response = await this.getClient().send(
|
|
31437
|
+
new CreateDBInstanceCommand3({
|
|
31438
|
+
DBInstanceIdentifier: dbInstanceIdentifier,
|
|
31439
|
+
DBInstanceClass: properties["DBInstanceClass"],
|
|
31440
|
+
// Neptune engine value is fixed: only `neptune` is accepted.
|
|
31441
|
+
Engine: "neptune",
|
|
31442
|
+
DBClusterIdentifier: properties["DBClusterIdentifier"],
|
|
31443
|
+
DBSubnetGroupName: properties["DBSubnetGroupName"],
|
|
31444
|
+
DBParameterGroupName: properties["DBParameterGroupName"],
|
|
31445
|
+
AvailabilityZone: properties["AvailabilityZone"],
|
|
31446
|
+
PreferredMaintenanceWindow: properties["PreferredMaintenanceWindow"],
|
|
31447
|
+
AutoMinorVersionUpgrade: properties["AutoMinorVersionUpgrade"],
|
|
31448
|
+
DeletionProtection: properties["DeletionProtection"],
|
|
31449
|
+
...tags.length > 0 && { Tags: tags }
|
|
31450
|
+
})
|
|
31451
|
+
);
|
|
31452
|
+
const instance = response.DBInstance;
|
|
31453
|
+
if (!instance) {
|
|
31454
|
+
throw new Error("CreateDBInstance did not return DBInstance");
|
|
31455
|
+
}
|
|
31456
|
+
this.logger.debug(
|
|
31457
|
+
`Successfully created Neptune DBInstance ${logicalId}: ${dbInstanceIdentifier}`
|
|
31458
|
+
);
|
|
31459
|
+
if (process.env["CDKD_NO_WAIT"] !== "true") {
|
|
31460
|
+
await this.waitForInstanceAvailable(dbInstanceIdentifier);
|
|
31461
|
+
}
|
|
31462
|
+
const described = await this.describeDBInstance(dbInstanceIdentifier);
|
|
31463
|
+
return {
|
|
31464
|
+
physicalId: dbInstanceIdentifier,
|
|
31465
|
+
attributes: {
|
|
31466
|
+
"Endpoint.Address": described?.Endpoint?.Address ?? "",
|
|
31467
|
+
"Endpoint.Port": String(described?.Endpoint?.Port ?? "")
|
|
31468
|
+
}
|
|
31469
|
+
};
|
|
31470
|
+
} catch (error) {
|
|
31471
|
+
if (error instanceof ProvisioningError)
|
|
31472
|
+
throw error;
|
|
31473
|
+
const cause = error instanceof Error ? error : void 0;
|
|
31474
|
+
throw new ProvisioningError(
|
|
31475
|
+
`Failed to create Neptune DBInstance ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
31476
|
+
resourceType,
|
|
31477
|
+
logicalId,
|
|
31478
|
+
dbInstanceIdentifier,
|
|
31479
|
+
cause
|
|
31480
|
+
);
|
|
31481
|
+
}
|
|
31482
|
+
}
|
|
31483
|
+
async updateDBInstance(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
31484
|
+
this.logger.debug(`Updating Neptune DBInstance ${logicalId}: ${physicalId}`);
|
|
31485
|
+
try {
|
|
31486
|
+
await this.getClient().send(
|
|
31487
|
+
new ModifyDBInstanceCommand3({
|
|
31488
|
+
DBInstanceIdentifier: physicalId,
|
|
31489
|
+
DBInstanceClass: properties["DBInstanceClass"],
|
|
31490
|
+
DBParameterGroupName: properties["DBParameterGroupName"],
|
|
31491
|
+
PreferredMaintenanceWindow: properties["PreferredMaintenanceWindow"],
|
|
31492
|
+
AutoMinorVersionUpgrade: properties["AutoMinorVersionUpgrade"],
|
|
31493
|
+
DeletionProtection: properties["DeletionProtection"],
|
|
31494
|
+
ApplyImmediately: true
|
|
31495
|
+
})
|
|
31496
|
+
);
|
|
31497
|
+
this.logger.debug(`Successfully updated Neptune DBInstance ${logicalId}`);
|
|
31498
|
+
const described = await this.describeDBInstance(physicalId);
|
|
31499
|
+
if (described?.DBInstanceArn) {
|
|
31500
|
+
await this.applyTagDiff(
|
|
31501
|
+
described.DBInstanceArn,
|
|
31502
|
+
previousProperties["Tags"],
|
|
31503
|
+
properties["Tags"]
|
|
31504
|
+
);
|
|
31505
|
+
}
|
|
31506
|
+
return {
|
|
31507
|
+
physicalId,
|
|
31508
|
+
wasReplaced: false,
|
|
31509
|
+
attributes: {
|
|
31510
|
+
"Endpoint.Address": described?.Endpoint?.Address ?? "",
|
|
31511
|
+
"Endpoint.Port": String(described?.Endpoint?.Port ?? "")
|
|
31512
|
+
}
|
|
31513
|
+
};
|
|
31514
|
+
} catch (error) {
|
|
31515
|
+
const cause = error instanceof Error ? error : void 0;
|
|
31516
|
+
throw new ProvisioningError(
|
|
31517
|
+
`Failed to update Neptune DBInstance ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
31518
|
+
resourceType,
|
|
31519
|
+
logicalId,
|
|
31520
|
+
physicalId,
|
|
31521
|
+
cause
|
|
31522
|
+
);
|
|
31523
|
+
}
|
|
31524
|
+
}
|
|
31525
|
+
async deleteDBInstance(logicalId, physicalId, resourceType, context) {
|
|
31526
|
+
this.logger.debug(`Deleting Neptune DBInstance ${logicalId}: ${physicalId}`);
|
|
31527
|
+
try {
|
|
31528
|
+
if (context?.removeProtection === true) {
|
|
31529
|
+
try {
|
|
31530
|
+
await this.getClient().send(
|
|
31531
|
+
new ModifyDBInstanceCommand3({
|
|
31532
|
+
DBInstanceIdentifier: physicalId,
|
|
31533
|
+
DeletionProtection: false,
|
|
31534
|
+
ApplyImmediately: true
|
|
31535
|
+
})
|
|
31536
|
+
);
|
|
31537
|
+
this.logger.debug(
|
|
31538
|
+
`Disabled DeletionProtection on Neptune DBInstance ${logicalId} before delete`
|
|
31539
|
+
);
|
|
31540
|
+
} catch (disableError) {
|
|
31541
|
+
if (!this.isNotFoundError(disableError, "DBInstanceNotFoundFault")) {
|
|
31542
|
+
this.logger.debug(
|
|
31543
|
+
`Could not disable deletion protection for ${physicalId}: ${disableError instanceof Error ? disableError.message : String(disableError)}`
|
|
31544
|
+
);
|
|
31545
|
+
}
|
|
31546
|
+
}
|
|
31547
|
+
}
|
|
31548
|
+
await this.getClient().send(
|
|
31549
|
+
new DeleteDBInstanceCommand3({
|
|
31550
|
+
DBInstanceIdentifier: physicalId,
|
|
31551
|
+
SkipFinalSnapshot: true
|
|
31552
|
+
})
|
|
31553
|
+
);
|
|
31554
|
+
this.logger.debug(`Successfully initiated deletion of Neptune DBInstance ${logicalId}`);
|
|
31555
|
+
await this.waitForInstanceDeleted(physicalId);
|
|
31556
|
+
} catch (error) {
|
|
31557
|
+
if (this.isNotFoundError(error, "DBInstanceNotFoundFault")) {
|
|
31558
|
+
const clientRegion = await this.getClient().config.region();
|
|
31559
|
+
assertRegionMatch(
|
|
31560
|
+
clientRegion,
|
|
31561
|
+
context?.expectedRegion,
|
|
31562
|
+
resourceType,
|
|
31563
|
+
logicalId,
|
|
31564
|
+
physicalId
|
|
31565
|
+
);
|
|
31566
|
+
this.logger.debug(`Neptune DBInstance ${physicalId} does not exist, skipping deletion`);
|
|
31567
|
+
return;
|
|
31568
|
+
}
|
|
31569
|
+
const cause = error instanceof Error ? error : void 0;
|
|
31570
|
+
throw new ProvisioningError(
|
|
31571
|
+
`Failed to delete Neptune DBInstance ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
31572
|
+
resourceType,
|
|
31573
|
+
logicalId,
|
|
31574
|
+
physicalId,
|
|
31575
|
+
cause
|
|
31576
|
+
);
|
|
31577
|
+
}
|
|
31578
|
+
}
|
|
31579
|
+
// ─── Helpers ──────────────────────────────────────────────────────
|
|
31580
|
+
/**
|
|
31581
|
+
* Apply a diff between old and new CFn-shape Tags arrays via Neptune's
|
|
31582
|
+
* `AddTagsToResource` / `RemoveTagsFromResource` APIs (keyed by
|
|
31583
|
+
* `ResourceName=arn`).
|
|
31584
|
+
*/
|
|
31585
|
+
async applyTagDiff(arn, oldTagsRaw, newTagsRaw) {
|
|
31586
|
+
const toMap = (tags) => {
|
|
31587
|
+
const m = /* @__PURE__ */ new Map();
|
|
31588
|
+
for (const t of tags ?? []) {
|
|
31589
|
+
if (t.Key !== void 0 && t.Value !== void 0)
|
|
31590
|
+
m.set(t.Key, t.Value);
|
|
31591
|
+
}
|
|
31592
|
+
return m;
|
|
31593
|
+
};
|
|
31594
|
+
const oldMap = toMap(oldTagsRaw);
|
|
31595
|
+
const newMap = toMap(newTagsRaw);
|
|
31596
|
+
const tagsToAdd = [];
|
|
31597
|
+
for (const [k, v] of newMap) {
|
|
31598
|
+
if (oldMap.get(k) !== v)
|
|
31599
|
+
tagsToAdd.push({ Key: k, Value: v });
|
|
31600
|
+
}
|
|
31601
|
+
const tagsToRemove = [];
|
|
31602
|
+
for (const k of oldMap.keys()) {
|
|
31603
|
+
if (!newMap.has(k))
|
|
31604
|
+
tagsToRemove.push(k);
|
|
31605
|
+
}
|
|
31606
|
+
if (tagsToRemove.length > 0) {
|
|
31607
|
+
await this.getClient().send(
|
|
31608
|
+
new RemoveTagsFromResourceCommand4({ ResourceName: arn, TagKeys: tagsToRemove })
|
|
31609
|
+
);
|
|
31610
|
+
this.logger.debug(`Removed ${tagsToRemove.length} tag(s) from Neptune resource ${arn}`);
|
|
31611
|
+
}
|
|
31612
|
+
if (tagsToAdd.length > 0) {
|
|
31613
|
+
await this.getClient().send(
|
|
31614
|
+
new AddTagsToResourceCommand4({ ResourceName: arn, Tags: tagsToAdd })
|
|
31615
|
+
);
|
|
31616
|
+
this.logger.debug(`Added/updated ${tagsToAdd.length} tag(s) on Neptune resource ${arn}`);
|
|
31617
|
+
}
|
|
31618
|
+
}
|
|
31619
|
+
buildTags(properties) {
|
|
31620
|
+
if (!properties["Tags"])
|
|
31621
|
+
return [];
|
|
31622
|
+
return properties["Tags"];
|
|
31623
|
+
}
|
|
31624
|
+
isNotFoundError(error, faultName) {
|
|
31625
|
+
if (!(error instanceof Error))
|
|
31626
|
+
return false;
|
|
31627
|
+
const name = error.name ?? "";
|
|
31628
|
+
const message = error.message.toLowerCase();
|
|
31629
|
+
return name === faultName || message.includes("not found") || message.includes("does not exist");
|
|
31630
|
+
}
|
|
31631
|
+
async describeDBCluster(dbClusterIdentifier) {
|
|
31632
|
+
const response = await this.getClient().send(
|
|
31633
|
+
new DescribeDBClustersCommand3({
|
|
31634
|
+
DBClusterIdentifier: dbClusterIdentifier
|
|
31635
|
+
})
|
|
31636
|
+
);
|
|
31637
|
+
return response.DBClusters?.[0];
|
|
31638
|
+
}
|
|
31639
|
+
async describeDBInstance(dbInstanceIdentifier) {
|
|
31640
|
+
const response = await this.getClient().send(
|
|
31641
|
+
new DescribeDBInstancesCommand3({
|
|
31642
|
+
DBInstanceIdentifier: dbInstanceIdentifier
|
|
31643
|
+
})
|
|
31644
|
+
);
|
|
31645
|
+
return response.DBInstances?.[0];
|
|
31646
|
+
}
|
|
31647
|
+
/**
|
|
31648
|
+
* Wait for a DBCluster to become available (no SDK waiter — manual poll).
|
|
31649
|
+
*/
|
|
31650
|
+
async waitForClusterAvailable(dbClusterIdentifier, maxWaitMs = 18e5) {
|
|
31651
|
+
const startTime = Date.now();
|
|
31652
|
+
let delay = 5e3;
|
|
31653
|
+
while (Date.now() - startTime < maxWaitMs) {
|
|
31654
|
+
const cluster = await this.describeDBCluster(dbClusterIdentifier);
|
|
31655
|
+
const status = cluster?.Status;
|
|
31656
|
+
this.logger.debug(`Neptune DBCluster ${dbClusterIdentifier} status: ${status}`);
|
|
31657
|
+
if (status === "available")
|
|
31658
|
+
return;
|
|
31659
|
+
await this.sleep(delay);
|
|
31660
|
+
delay = Math.min(delay * 2, 3e4);
|
|
31661
|
+
}
|
|
31662
|
+
throw new Error(
|
|
31663
|
+
`Timed out waiting for Neptune DBCluster ${dbClusterIdentifier} to become available`
|
|
31664
|
+
);
|
|
31665
|
+
}
|
|
31666
|
+
/**
|
|
31667
|
+
* Wait for a DBCluster to be deleted (no SDK waiter — manual poll).
|
|
31668
|
+
*/
|
|
31669
|
+
async waitForClusterDeleted(dbClusterIdentifier, maxWaitMs = 18e5) {
|
|
31670
|
+
const startTime = Date.now();
|
|
31671
|
+
let delay = 5e3;
|
|
31672
|
+
while (Date.now() - startTime < maxWaitMs) {
|
|
31673
|
+
try {
|
|
31674
|
+
const cluster = await this.describeDBCluster(dbClusterIdentifier);
|
|
31675
|
+
const status = cluster?.Status;
|
|
31676
|
+
this.logger.debug(`Neptune DBCluster ${dbClusterIdentifier} status: ${status}`);
|
|
31677
|
+
if (!cluster)
|
|
31678
|
+
return;
|
|
31679
|
+
} catch (error) {
|
|
31680
|
+
if (this.isNotFoundError(error, "DBClusterNotFoundFault")) {
|
|
31681
|
+
return;
|
|
31682
|
+
}
|
|
31683
|
+
throw error;
|
|
31684
|
+
}
|
|
31685
|
+
await this.sleep(delay);
|
|
31686
|
+
delay = Math.min(delay * 2, 3e4);
|
|
31687
|
+
}
|
|
31688
|
+
throw new Error(`Timed out waiting for Neptune DBCluster ${dbClusterIdentifier} to be deleted`);
|
|
31689
|
+
}
|
|
31690
|
+
/**
|
|
31691
|
+
* Wait for a DBInstance to become available (manual poll).
|
|
31692
|
+
*/
|
|
31693
|
+
async waitForInstanceAvailable(dbInstanceIdentifier, maxWaitMs = 18e5) {
|
|
31694
|
+
const startTime = Date.now();
|
|
31695
|
+
let delay = 1e4;
|
|
31696
|
+
while (Date.now() - startTime < maxWaitMs) {
|
|
31697
|
+
const instance = await this.describeDBInstance(dbInstanceIdentifier);
|
|
31698
|
+
const status = instance?.DBInstanceStatus;
|
|
31699
|
+
this.logger.debug(`Neptune DBInstance ${dbInstanceIdentifier} status: ${status}`);
|
|
31700
|
+
if (status === "available")
|
|
31701
|
+
return;
|
|
31702
|
+
await this.sleep(delay);
|
|
31703
|
+
delay = Math.min(delay * 2, 3e4);
|
|
31704
|
+
}
|
|
31705
|
+
throw new Error(
|
|
31706
|
+
`Timed out waiting for Neptune DBInstance ${dbInstanceIdentifier} to become available`
|
|
31707
|
+
);
|
|
31708
|
+
}
|
|
31709
|
+
async waitForInstanceDeleted(dbInstanceIdentifier, maxWaitMs = 18e5) {
|
|
31710
|
+
const startTime = Date.now();
|
|
31711
|
+
let delay = 1e4;
|
|
31712
|
+
while (Date.now() - startTime < maxWaitMs) {
|
|
31713
|
+
try {
|
|
31714
|
+
const instance = await this.describeDBInstance(dbInstanceIdentifier);
|
|
31715
|
+
const status = instance?.DBInstanceStatus;
|
|
31716
|
+
this.logger.debug(`Neptune DBInstance ${dbInstanceIdentifier} status: ${status}`);
|
|
31717
|
+
if (!instance)
|
|
31718
|
+
return;
|
|
31719
|
+
} catch (error) {
|
|
31720
|
+
if (this.isNotFoundError(error, "DBInstanceNotFoundFault")) {
|
|
31721
|
+
return;
|
|
31722
|
+
}
|
|
31723
|
+
throw error;
|
|
31724
|
+
}
|
|
31725
|
+
await this.sleep(delay);
|
|
31726
|
+
delay = Math.min(delay * 2, 3e4);
|
|
31727
|
+
}
|
|
31728
|
+
throw new Error(
|
|
31729
|
+
`Timed out waiting for Neptune DBInstance ${dbInstanceIdentifier} to be deleted`
|
|
31730
|
+
);
|
|
31731
|
+
}
|
|
31732
|
+
sleep(ms) {
|
|
31733
|
+
return new Promise((resolve4) => setTimeout(resolve4, ms));
|
|
31734
|
+
}
|
|
31735
|
+
/**
|
|
31736
|
+
* Adopt an existing Neptune resource into cdkd state.
|
|
31737
|
+
*/
|
|
31738
|
+
async import(input) {
|
|
31739
|
+
switch (input.resourceType) {
|
|
31740
|
+
case "AWS::Neptune::DBInstance":
|
|
31741
|
+
return this.importDBInstance(input);
|
|
31742
|
+
case "AWS::Neptune::DBCluster":
|
|
31743
|
+
return this.importDBCluster(input);
|
|
31744
|
+
case "AWS::Neptune::DBSubnetGroup":
|
|
31745
|
+
return this.importDBSubnetGroup(input);
|
|
31746
|
+
default:
|
|
31747
|
+
return null;
|
|
31748
|
+
}
|
|
31749
|
+
}
|
|
31750
|
+
/**
|
|
31751
|
+
* Read the AWS-current Neptune resource configuration in CFn-property
|
|
31752
|
+
* shape. Each branch surfaces only the keys cdkd's `create()` accepts.
|
|
31753
|
+
* Sensitive fields are NEVER surfaced. `Tags` are surfaced via a
|
|
31754
|
+
* follow-up `ListTagsForResource(ResourceName=arn)` call.
|
|
31755
|
+
*/
|
|
31756
|
+
async readCurrentState(physicalId, _logicalId, resourceType) {
|
|
31757
|
+
switch (resourceType) {
|
|
31758
|
+
case "AWS::Neptune::DBInstance":
|
|
31759
|
+
return this.readCurrentStateDBInstance(physicalId);
|
|
31760
|
+
case "AWS::Neptune::DBCluster":
|
|
31761
|
+
return this.readCurrentStateDBCluster(physicalId);
|
|
31762
|
+
case "AWS::Neptune::DBSubnetGroup":
|
|
31763
|
+
return this.readCurrentStateDBSubnetGroup(physicalId);
|
|
31764
|
+
default:
|
|
31765
|
+
return void 0;
|
|
31766
|
+
}
|
|
31767
|
+
}
|
|
31768
|
+
async readCurrentStateDBInstance(physicalId) {
|
|
31769
|
+
let inst;
|
|
31770
|
+
try {
|
|
31771
|
+
inst = await this.describeDBInstance(physicalId);
|
|
31772
|
+
} catch (err) {
|
|
31773
|
+
if (this.isNotFoundError(err, "DBInstanceNotFoundFault"))
|
|
31774
|
+
return void 0;
|
|
31775
|
+
throw err;
|
|
31776
|
+
}
|
|
31777
|
+
if (!inst)
|
|
31778
|
+
return void 0;
|
|
31779
|
+
const result = {};
|
|
31780
|
+
if (inst.DBInstanceIdentifier !== void 0) {
|
|
31781
|
+
result["DBInstanceIdentifier"] = inst.DBInstanceIdentifier;
|
|
31782
|
+
}
|
|
31783
|
+
if (inst.DBInstanceClass !== void 0)
|
|
31784
|
+
result["DBInstanceClass"] = inst.DBInstanceClass;
|
|
31785
|
+
if (inst.DBClusterIdentifier !== void 0) {
|
|
31786
|
+
result["DBClusterIdentifier"] = inst.DBClusterIdentifier;
|
|
31787
|
+
}
|
|
31788
|
+
if (inst.DBSubnetGroup?.DBSubnetGroupName !== void 0) {
|
|
31789
|
+
result["DBSubnetGroupName"] = inst.DBSubnetGroup.DBSubnetGroupName;
|
|
31790
|
+
}
|
|
31791
|
+
if (inst.AvailabilityZone !== void 0)
|
|
31792
|
+
result["AvailabilityZone"] = inst.AvailabilityZone;
|
|
31793
|
+
if (inst.PreferredMaintenanceWindow !== void 0) {
|
|
31794
|
+
result["PreferredMaintenanceWindow"] = inst.PreferredMaintenanceWindow;
|
|
31795
|
+
}
|
|
31796
|
+
if (inst.AutoMinorVersionUpgrade !== void 0) {
|
|
31797
|
+
result["AutoMinorVersionUpgrade"] = inst.AutoMinorVersionUpgrade;
|
|
31798
|
+
}
|
|
31799
|
+
if (inst.DeletionProtection !== void 0) {
|
|
31800
|
+
result["DeletionProtection"] = inst.DeletionProtection;
|
|
31801
|
+
}
|
|
31802
|
+
const pg = inst.DBParameterGroups?.[0]?.DBParameterGroupName;
|
|
31803
|
+
if (pg !== void 0)
|
|
31804
|
+
result["DBParameterGroupName"] = pg;
|
|
31805
|
+
if (inst.DBInstanceArn)
|
|
31806
|
+
await this.attachTags(result, inst.DBInstanceArn);
|
|
31807
|
+
return result;
|
|
31808
|
+
}
|
|
31809
|
+
async readCurrentStateDBCluster(physicalId) {
|
|
31810
|
+
let cluster;
|
|
31811
|
+
try {
|
|
31812
|
+
cluster = await this.describeDBCluster(physicalId);
|
|
31813
|
+
} catch (err) {
|
|
31814
|
+
if (this.isNotFoundError(err, "DBClusterNotFoundFault"))
|
|
31815
|
+
return void 0;
|
|
31816
|
+
throw err;
|
|
31817
|
+
}
|
|
31818
|
+
if (!cluster)
|
|
31819
|
+
return void 0;
|
|
31820
|
+
const result = {};
|
|
31821
|
+
if (cluster.DBClusterIdentifier !== void 0) {
|
|
31822
|
+
result["DBClusterIdentifier"] = cluster.DBClusterIdentifier;
|
|
31823
|
+
}
|
|
31824
|
+
if (cluster.EngineVersion !== void 0)
|
|
31825
|
+
result["EngineVersion"] = cluster.EngineVersion;
|
|
31826
|
+
if (cluster.Port !== void 0)
|
|
31827
|
+
result["Port"] = cluster.Port;
|
|
31828
|
+
result["VpcSecurityGroupIds"] = (cluster.VpcSecurityGroups ?? []).map((sg) => sg.VpcSecurityGroupId).filter((id) => !!id);
|
|
31829
|
+
if (cluster.DBSubnetGroup !== void 0)
|
|
31830
|
+
result["DBSubnetGroupName"] = cluster.DBSubnetGroup;
|
|
31831
|
+
if (cluster.StorageEncrypted !== void 0) {
|
|
31832
|
+
result["StorageEncrypted"] = cluster.StorageEncrypted;
|
|
31833
|
+
}
|
|
31834
|
+
if (cluster.KmsKeyId !== void 0)
|
|
31835
|
+
result["KmsKeyId"] = cluster.KmsKeyId;
|
|
31836
|
+
if (cluster.BackupRetentionPeriod !== void 0) {
|
|
31837
|
+
result["BackupRetentionPeriod"] = cluster.BackupRetentionPeriod;
|
|
31838
|
+
}
|
|
31839
|
+
if (cluster.PreferredBackupWindow !== void 0) {
|
|
31840
|
+
result["PreferredBackupWindow"] = cluster.PreferredBackupWindow;
|
|
31841
|
+
}
|
|
31842
|
+
if (cluster.PreferredMaintenanceWindow !== void 0) {
|
|
31843
|
+
result["PreferredMaintenanceWindow"] = cluster.PreferredMaintenanceWindow;
|
|
31844
|
+
}
|
|
31845
|
+
if (cluster.DBClusterParameterGroup !== void 0) {
|
|
31846
|
+
result["DBClusterParameterGroupName"] = cluster.DBClusterParameterGroup;
|
|
31847
|
+
}
|
|
31848
|
+
if (cluster.IAMDatabaseAuthenticationEnabled !== void 0) {
|
|
31849
|
+
result["IamAuthEnabled"] = cluster.IAMDatabaseAuthenticationEnabled;
|
|
31850
|
+
}
|
|
31851
|
+
if (cluster.DeletionProtection !== void 0) {
|
|
31852
|
+
result["DeletionProtection"] = cluster.DeletionProtection;
|
|
31853
|
+
}
|
|
31854
|
+
if (cluster.DBClusterArn)
|
|
31855
|
+
await this.attachTags(result, cluster.DBClusterArn);
|
|
31856
|
+
return result;
|
|
31857
|
+
}
|
|
31858
|
+
async readCurrentStateDBSubnetGroup(physicalId) {
|
|
31859
|
+
let resp;
|
|
31860
|
+
try {
|
|
31861
|
+
resp = await this.getClient().send(
|
|
31862
|
+
new DescribeDBSubnetGroupsCommand3({ DBSubnetGroupName: physicalId })
|
|
31863
|
+
);
|
|
31864
|
+
} catch (err) {
|
|
31865
|
+
if (this.isNotFoundError(err, "DBSubnetGroupNotFoundFault"))
|
|
31866
|
+
return void 0;
|
|
31867
|
+
throw err;
|
|
31868
|
+
}
|
|
31869
|
+
const sg = resp.DBSubnetGroups?.[0];
|
|
31870
|
+
if (!sg)
|
|
31871
|
+
return void 0;
|
|
31872
|
+
const result = {};
|
|
31873
|
+
if (sg.DBSubnetGroupName !== void 0)
|
|
31874
|
+
result["DBSubnetGroupName"] = sg.DBSubnetGroupName;
|
|
31875
|
+
if (sg.DBSubnetGroupDescription !== void 0) {
|
|
31876
|
+
result["DBSubnetGroupDescription"] = sg.DBSubnetGroupDescription;
|
|
31877
|
+
}
|
|
31878
|
+
result["SubnetIds"] = (sg.Subnets ?? []).map((s) => s.SubnetIdentifier).filter((id) => !!id);
|
|
31879
|
+
if (sg.DBSubnetGroupArn)
|
|
31880
|
+
await this.attachTags(result, sg.DBSubnetGroupArn);
|
|
31881
|
+
return result;
|
|
31882
|
+
}
|
|
31883
|
+
/**
|
|
31884
|
+
* Fetch tags via `ListTagsForResource` and merge them into the result
|
|
31885
|
+
* under `Tags` (CFn shape). Best-effort.
|
|
31886
|
+
*/
|
|
31887
|
+
async attachTags(result, arn) {
|
|
31888
|
+
try {
|
|
31889
|
+
const tagsResp = await this.getClient().send(
|
|
31890
|
+
new ListTagsForResourceCommand12({ ResourceName: arn })
|
|
31891
|
+
);
|
|
31892
|
+
const tags = normalizeAwsTagsToCfn(tagsResp.TagList);
|
|
31893
|
+
result["Tags"] = tags;
|
|
31894
|
+
} catch (err) {
|
|
31895
|
+
this.logger.debug(
|
|
31896
|
+
`Neptune ListTagsForResource(${arn}) failed: ${err instanceof Error ? err.message : String(err)}`
|
|
31897
|
+
);
|
|
31898
|
+
}
|
|
31899
|
+
}
|
|
31900
|
+
async importDBInstance(input) {
|
|
31901
|
+
const explicit = resolveExplicitPhysicalId(input, "DBInstanceIdentifier");
|
|
31902
|
+
if (explicit) {
|
|
31903
|
+
try {
|
|
31904
|
+
await this.getClient().send(
|
|
31905
|
+
new DescribeDBInstancesCommand3({ DBInstanceIdentifier: explicit })
|
|
31906
|
+
);
|
|
31907
|
+
return { physicalId: explicit, attributes: {} };
|
|
31908
|
+
} catch (err) {
|
|
31909
|
+
if (err.name === "DBInstanceNotFoundFault")
|
|
31910
|
+
return null;
|
|
31911
|
+
throw err;
|
|
31912
|
+
}
|
|
31913
|
+
}
|
|
31914
|
+
if (!input.cdkPath)
|
|
31915
|
+
return null;
|
|
31916
|
+
let marker;
|
|
31917
|
+
do {
|
|
31918
|
+
const list = await this.getClient().send(
|
|
31919
|
+
new DescribeDBInstancesCommand3({ ...marker && { Marker: marker } })
|
|
31920
|
+
);
|
|
31921
|
+
for (const inst of list.DBInstances ?? []) {
|
|
31922
|
+
if (!inst.DBInstanceIdentifier || !inst.DBInstanceArn)
|
|
31923
|
+
continue;
|
|
31924
|
+
const tagsResp = await this.getClient().send(
|
|
31925
|
+
new ListTagsForResourceCommand12({ ResourceName: inst.DBInstanceArn })
|
|
31926
|
+
);
|
|
31927
|
+
if (matchesCdkPath(tagsResp.TagList, input.cdkPath)) {
|
|
31928
|
+
return { physicalId: inst.DBInstanceIdentifier, attributes: {} };
|
|
31929
|
+
}
|
|
31930
|
+
}
|
|
31931
|
+
marker = list.Marker;
|
|
31932
|
+
} while (marker);
|
|
31933
|
+
return null;
|
|
31934
|
+
}
|
|
31935
|
+
async importDBCluster(input) {
|
|
31936
|
+
const explicit = resolveExplicitPhysicalId(input, "DBClusterIdentifier");
|
|
31937
|
+
if (explicit) {
|
|
31938
|
+
try {
|
|
31939
|
+
await this.getClient().send(
|
|
31940
|
+
new DescribeDBClustersCommand3({ DBClusterIdentifier: explicit })
|
|
31941
|
+
);
|
|
31942
|
+
return { physicalId: explicit, attributes: {} };
|
|
31943
|
+
} catch (err) {
|
|
31944
|
+
if (err.name === "DBClusterNotFoundFault")
|
|
31945
|
+
return null;
|
|
31946
|
+
throw err;
|
|
31947
|
+
}
|
|
31948
|
+
}
|
|
31949
|
+
if (!input.cdkPath)
|
|
31950
|
+
return null;
|
|
31951
|
+
let marker;
|
|
31952
|
+
do {
|
|
31953
|
+
const list = await this.getClient().send(
|
|
31954
|
+
new DescribeDBClustersCommand3({ ...marker && { Marker: marker } })
|
|
31955
|
+
);
|
|
31956
|
+
for (const c of list.DBClusters ?? []) {
|
|
31957
|
+
if (!c.DBClusterIdentifier || !c.DBClusterArn)
|
|
31958
|
+
continue;
|
|
31959
|
+
const tagsResp = await this.getClient().send(
|
|
31960
|
+
new ListTagsForResourceCommand12({ ResourceName: c.DBClusterArn })
|
|
31961
|
+
);
|
|
31962
|
+
if (matchesCdkPath(tagsResp.TagList, input.cdkPath)) {
|
|
31963
|
+
return { physicalId: c.DBClusterIdentifier, attributes: {} };
|
|
31964
|
+
}
|
|
31965
|
+
}
|
|
31966
|
+
marker = list.Marker;
|
|
31967
|
+
} while (marker);
|
|
31968
|
+
return null;
|
|
31969
|
+
}
|
|
31970
|
+
async importDBSubnetGroup(input) {
|
|
31971
|
+
const explicit = resolveExplicitPhysicalId(input, "DBSubnetGroupName");
|
|
31972
|
+
if (explicit) {
|
|
31973
|
+
try {
|
|
31974
|
+
await this.getClient().send(
|
|
31975
|
+
new DescribeDBSubnetGroupsCommand3({ DBSubnetGroupName: explicit })
|
|
31976
|
+
);
|
|
31977
|
+
return { physicalId: explicit, attributes: {} };
|
|
31978
|
+
} catch (err) {
|
|
31979
|
+
if (err.name === "DBSubnetGroupNotFoundFault")
|
|
31980
|
+
return null;
|
|
31981
|
+
throw err;
|
|
31982
|
+
}
|
|
31983
|
+
}
|
|
31984
|
+
if (!input.cdkPath)
|
|
31985
|
+
return null;
|
|
31986
|
+
let marker;
|
|
31987
|
+
do {
|
|
31988
|
+
const list = await this.getClient().send(
|
|
31989
|
+
new DescribeDBSubnetGroupsCommand3({ ...marker && { Marker: marker } })
|
|
31990
|
+
);
|
|
31991
|
+
for (const sg of list.DBSubnetGroups ?? []) {
|
|
31992
|
+
if (!sg.DBSubnetGroupName || !sg.DBSubnetGroupArn)
|
|
31993
|
+
continue;
|
|
31994
|
+
const tagsResp = await this.getClient().send(
|
|
31995
|
+
new ListTagsForResourceCommand12({ ResourceName: sg.DBSubnetGroupArn })
|
|
31996
|
+
);
|
|
31997
|
+
if (matchesCdkPath(tagsResp.TagList, input.cdkPath)) {
|
|
31998
|
+
return { physicalId: sg.DBSubnetGroupName, attributes: {} };
|
|
31999
|
+
}
|
|
32000
|
+
}
|
|
32001
|
+
marker = list.Marker;
|
|
32002
|
+
} while (marker);
|
|
32003
|
+
return null;
|
|
32004
|
+
}
|
|
32005
|
+
};
|
|
32006
|
+
|
|
32007
|
+
// src/provisioning/providers/route53-provider.ts
|
|
32008
|
+
import {
|
|
32009
|
+
Route53Client as Route53Client2,
|
|
32010
|
+
CreateHostedZoneCommand,
|
|
32011
|
+
DeleteHostedZoneCommand,
|
|
32012
|
+
GetHostedZoneCommand as GetHostedZoneCommand2,
|
|
32013
|
+
ChangeResourceRecordSetsCommand,
|
|
32014
|
+
UpdateHostedZoneCommentCommand,
|
|
32015
|
+
ChangeTagsForResourceCommand,
|
|
32016
|
+
AssociateVPCWithHostedZoneCommand,
|
|
32017
|
+
DisassociateVPCFromHostedZoneCommand,
|
|
32018
|
+
CreateQueryLoggingConfigCommand,
|
|
32019
|
+
DeleteQueryLoggingConfigCommand,
|
|
32020
|
+
ListQueryLoggingConfigsCommand,
|
|
32021
|
+
ListHostedZonesByNameCommand as ListHostedZonesByNameCommand2,
|
|
32022
|
+
ListHostedZonesCommand,
|
|
32023
|
+
ListResourceRecordSetsCommand,
|
|
32024
|
+
ListTagsForResourceCommand as ListTagsForResourceCommand13
|
|
32025
|
+
} from "@aws-sdk/client-route-53";
|
|
32026
|
+
var Route53Provider = class {
|
|
32027
|
+
route53Client;
|
|
32028
|
+
providerRegion = process.env["AWS_REGION"];
|
|
32029
|
+
logger = getLogger().child("Route53Provider");
|
|
32030
|
+
handledProperties = /* @__PURE__ */ new Map([
|
|
32031
|
+
[
|
|
32032
|
+
"AWS::Route53::HostedZone",
|
|
32033
|
+
/* @__PURE__ */ new Set(["Name", "HostedZoneConfig", "HostedZoneTags", "VPCs", "QueryLoggingConfig"])
|
|
32034
|
+
],
|
|
32035
|
+
[
|
|
32036
|
+
"AWS::Route53::RecordSet",
|
|
32037
|
+
/* @__PURE__ */ new Set([
|
|
32038
|
+
"HostedZoneId",
|
|
32039
|
+
"HostedZoneName",
|
|
32040
|
+
"Name",
|
|
32041
|
+
"Type",
|
|
32042
|
+
"TTL",
|
|
32043
|
+
"ResourceRecords",
|
|
32044
|
+
"AliasTarget",
|
|
32045
|
+
"SetIdentifier",
|
|
32046
|
+
"Weight",
|
|
32047
|
+
"Region",
|
|
32048
|
+
"Failover",
|
|
32049
|
+
"MultiValueAnswer",
|
|
32050
|
+
"HealthCheckId",
|
|
32051
|
+
"Comment",
|
|
32052
|
+
"GeoLocation"
|
|
32053
|
+
])
|
|
32054
|
+
]
|
|
32055
|
+
]);
|
|
32056
|
+
getClient() {
|
|
32057
|
+
if (!this.route53Client) {
|
|
32058
|
+
this.route53Client = new Route53Client2(
|
|
32059
|
+
this.providerRegion ? { region: this.providerRegion } : {}
|
|
32060
|
+
);
|
|
32061
|
+
}
|
|
32062
|
+
return this.route53Client;
|
|
32063
|
+
}
|
|
32064
|
+
// ─── Dispatch ─────────────────────────────────────────────────────
|
|
32065
|
+
async create(logicalId, resourceType, properties) {
|
|
32066
|
+
switch (resourceType) {
|
|
32067
|
+
case "AWS::Route53::HostedZone":
|
|
32068
|
+
return this.createHostedZone(logicalId, resourceType, properties);
|
|
32069
|
+
case "AWS::Route53::RecordSet":
|
|
32070
|
+
return this.createRecordSet(logicalId, resourceType, properties);
|
|
32071
|
+
default:
|
|
32072
|
+
throw new ProvisioningError(
|
|
32073
|
+
`Unsupported resource type: ${resourceType}`,
|
|
32074
|
+
resourceType,
|
|
32075
|
+
logicalId
|
|
32076
|
+
);
|
|
32077
|
+
}
|
|
32078
|
+
}
|
|
32079
|
+
async update(logicalId, physicalId, resourceType, properties, _previousProperties) {
|
|
32080
|
+
switch (resourceType) {
|
|
32081
|
+
case "AWS::Route53::HostedZone":
|
|
32082
|
+
return this.updateHostedZone(logicalId, physicalId, resourceType, properties);
|
|
32083
|
+
case "AWS::Route53::RecordSet":
|
|
32084
|
+
return this.updateRecordSet(logicalId, physicalId, resourceType, properties);
|
|
32085
|
+
default:
|
|
32086
|
+
throw new ProvisioningError(
|
|
32087
|
+
`Unsupported resource type: ${resourceType}`,
|
|
32088
|
+
resourceType,
|
|
32089
|
+
logicalId,
|
|
32090
|
+
physicalId
|
|
32091
|
+
);
|
|
32092
|
+
}
|
|
32093
|
+
}
|
|
32094
|
+
async delete(logicalId, physicalId, resourceType, properties, context) {
|
|
32095
|
+
switch (resourceType) {
|
|
32096
|
+
case "AWS::Route53::HostedZone":
|
|
32097
|
+
return this.deleteHostedZone(logicalId, physicalId, resourceType, context);
|
|
32098
|
+
case "AWS::Route53::RecordSet":
|
|
32099
|
+
return this.deleteRecordSet(logicalId, physicalId, resourceType, properties, context);
|
|
32100
|
+
default:
|
|
32101
|
+
throw new ProvisioningError(
|
|
32102
|
+
`Unsupported resource type: ${resourceType}`,
|
|
32103
|
+
resourceType,
|
|
32104
|
+
logicalId,
|
|
32105
|
+
physicalId
|
|
32106
|
+
);
|
|
32107
|
+
}
|
|
32108
|
+
}
|
|
32109
|
+
async getAttribute(physicalId, resourceType, attributeName) {
|
|
32110
|
+
switch (resourceType) {
|
|
32111
|
+
case "AWS::Route53::HostedZone":
|
|
32112
|
+
return this.getHostedZoneAttribute(physicalId, attributeName);
|
|
32113
|
+
default:
|
|
32114
|
+
return void 0;
|
|
32115
|
+
}
|
|
32116
|
+
}
|
|
32117
|
+
// ─── AWS::Route53::HostedZone ──────────────────────────────────────
|
|
32118
|
+
async createHostedZone(logicalId, resourceType, properties) {
|
|
32119
|
+
this.logger.debug(`Creating Route 53 hosted zone ${logicalId}`);
|
|
32120
|
+
const name = properties["Name"];
|
|
32121
|
+
if (!name) {
|
|
32122
|
+
throw new ProvisioningError(
|
|
32123
|
+
`Name is required for hosted zone ${logicalId}`,
|
|
32124
|
+
resourceType,
|
|
32125
|
+
logicalId
|
|
32126
|
+
);
|
|
32127
|
+
}
|
|
32128
|
+
try {
|
|
32129
|
+
const hostedZoneConfig = properties["HostedZoneConfig"];
|
|
32130
|
+
const vpcs = properties["VPCs"];
|
|
32131
|
+
const firstVpc = vpcs && vpcs.length > 0 ? vpcs[0] : void 0;
|
|
32132
|
+
const response = await this.getClient().send(
|
|
32133
|
+
new CreateHostedZoneCommand({
|
|
32134
|
+
Name: name,
|
|
32135
|
+
CallerReference: `${logicalId}-${Date.now()}`,
|
|
32136
|
+
...hostedZoneConfig && hostedZoneConfig["Comment"] ? {
|
|
32137
|
+
HostedZoneConfig: {
|
|
32138
|
+
Comment: hostedZoneConfig["Comment"],
|
|
32139
|
+
// When VPCs are specified, this is a private hosted zone
|
|
32140
|
+
...firstVpc ? { PrivateZone: true } : {}
|
|
32141
|
+
}
|
|
32142
|
+
} : firstVpc ? { HostedZoneConfig: { PrivateZone: true } } : {},
|
|
32143
|
+
...firstVpc ? {
|
|
32144
|
+
VPC: {
|
|
32145
|
+
VPCId: firstVpc["VPCId"],
|
|
32146
|
+
VPCRegion: firstVpc["VPCRegion"]
|
|
32147
|
+
}
|
|
32148
|
+
} : {}
|
|
32149
|
+
})
|
|
32150
|
+
);
|
|
32151
|
+
const hostedZone = response.HostedZone;
|
|
32152
|
+
if (!hostedZone?.Id) {
|
|
32153
|
+
throw new Error("CreateHostedZone did not return HostedZone.Id");
|
|
32154
|
+
}
|
|
32155
|
+
const zoneId = hostedZone.Id.replace("/hostedzone/", "");
|
|
32156
|
+
if (vpcs && vpcs.length > 1) {
|
|
32157
|
+
for (let i = 1; i < vpcs.length; i++) {
|
|
32158
|
+
const additionalVpc = vpcs[i];
|
|
32159
|
+
this.logger.debug(
|
|
32160
|
+
`Associating additional VPC ${String(additionalVpc["VPCId"])} with hosted zone ${zoneId}`
|
|
32161
|
+
);
|
|
32162
|
+
await this.getClient().send(
|
|
32163
|
+
new AssociateVPCWithHostedZoneCommand({
|
|
32164
|
+
HostedZoneId: zoneId,
|
|
32165
|
+
VPC: {
|
|
32166
|
+
VPCId: additionalVpc["VPCId"],
|
|
32167
|
+
VPCRegion: additionalVpc["VPCRegion"]
|
|
32168
|
+
}
|
|
32169
|
+
})
|
|
32170
|
+
);
|
|
32171
|
+
}
|
|
32172
|
+
}
|
|
32173
|
+
await this.applyHostedZoneTags(zoneId, properties, logicalId);
|
|
32174
|
+
await this.applyQueryLoggingConfig(zoneId, properties, logicalId);
|
|
32175
|
+
const nameServers = response.DelegationSet?.NameServers ?? [];
|
|
32176
|
+
this.logger.debug(`Successfully created hosted zone ${logicalId}: ${zoneId}`);
|
|
32177
|
+
return {
|
|
32178
|
+
physicalId: zoneId,
|
|
32179
|
+
attributes: {
|
|
32180
|
+
Id: zoneId,
|
|
32181
|
+
NameServers: nameServers.join(",")
|
|
32182
|
+
}
|
|
32183
|
+
};
|
|
32184
|
+
} catch (error) {
|
|
32185
|
+
if (error instanceof ProvisioningError)
|
|
32186
|
+
throw error;
|
|
32187
|
+
const cause = error instanceof Error ? error : void 0;
|
|
32188
|
+
throw new ProvisioningError(
|
|
32189
|
+
`Failed to create hosted zone ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
32190
|
+
resourceType,
|
|
32191
|
+
logicalId,
|
|
32192
|
+
void 0,
|
|
32193
|
+
cause
|
|
32194
|
+
);
|
|
32195
|
+
}
|
|
32196
|
+
}
|
|
32197
|
+
async updateHostedZone(logicalId, physicalId, resourceType, properties) {
|
|
32198
|
+
this.logger.debug(`Updating Route 53 hosted zone ${logicalId}: ${physicalId}`);
|
|
32199
|
+
try {
|
|
32200
|
+
const hostedZoneConfig = properties["HostedZoneConfig"];
|
|
32201
|
+
const comment = hostedZoneConfig?.["Comment"] ?? "";
|
|
32202
|
+
await this.getClient().send(
|
|
32203
|
+
new UpdateHostedZoneCommentCommand({
|
|
32204
|
+
Id: physicalId,
|
|
32205
|
+
Comment: comment
|
|
32206
|
+
})
|
|
32207
|
+
);
|
|
32208
|
+
await this.applyHostedZoneTags(physicalId, properties, logicalId);
|
|
32209
|
+
await this.applyQueryLoggingConfig(physicalId, properties, logicalId);
|
|
32210
|
+
await this.syncVPCAssociations(physicalId, properties, logicalId);
|
|
32211
|
+
const getResponse = await this.getClient().send(new GetHostedZoneCommand2({ Id: physicalId }));
|
|
32212
|
+
const nameServers = getResponse.DelegationSet?.NameServers ?? [];
|
|
32213
|
+
this.logger.debug(`Successfully updated hosted zone ${logicalId}`);
|
|
32214
|
+
return {
|
|
32215
|
+
physicalId,
|
|
32216
|
+
wasReplaced: false,
|
|
32217
|
+
attributes: {
|
|
32218
|
+
Id: physicalId,
|
|
32219
|
+
NameServers: nameServers.join(",")
|
|
32220
|
+
}
|
|
32221
|
+
};
|
|
32222
|
+
} catch (error) {
|
|
32223
|
+
const cause = error instanceof Error ? error : void 0;
|
|
32224
|
+
throw new ProvisioningError(
|
|
32225
|
+
`Failed to update hosted zone ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
32226
|
+
resourceType,
|
|
32227
|
+
logicalId,
|
|
32228
|
+
physicalId,
|
|
32229
|
+
cause
|
|
32230
|
+
);
|
|
32231
|
+
}
|
|
32232
|
+
}
|
|
32233
|
+
async deleteHostedZone(logicalId, physicalId, resourceType, context) {
|
|
32234
|
+
this.logger.debug(`Deleting Route 53 hosted zone ${logicalId}: ${physicalId}`);
|
|
32235
|
+
try {
|
|
32236
|
+
await this.deleteQueryLoggingConfigForZone(physicalId, logicalId);
|
|
32237
|
+
await this.getClient().send(new DeleteHostedZoneCommand({ Id: physicalId }));
|
|
32238
|
+
this.logger.debug(`Successfully deleted hosted zone ${logicalId}`);
|
|
32239
|
+
} catch (error) {
|
|
32240
|
+
if (error instanceof Error && error.name === "NoSuchHostedZone") {
|
|
32241
|
+
const clientRegion = await this.getClient().config.region();
|
|
32242
|
+
assertRegionMatch(
|
|
32243
|
+
clientRegion,
|
|
32244
|
+
context?.expectedRegion,
|
|
32245
|
+
resourceType,
|
|
32246
|
+
logicalId,
|
|
32247
|
+
physicalId
|
|
32248
|
+
);
|
|
32249
|
+
this.logger.debug(`Hosted zone ${physicalId} does not exist, skipping deletion`);
|
|
32250
|
+
return;
|
|
32251
|
+
}
|
|
32252
|
+
const cause = error instanceof Error ? error : void 0;
|
|
32253
|
+
throw new ProvisioningError(
|
|
32254
|
+
`Failed to delete hosted zone ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
32255
|
+
resourceType,
|
|
32256
|
+
logicalId,
|
|
32257
|
+
physicalId,
|
|
32258
|
+
cause
|
|
32259
|
+
);
|
|
32260
|
+
}
|
|
32261
|
+
}
|
|
32262
|
+
async getHostedZoneAttribute(physicalId, attributeName) {
|
|
32263
|
+
switch (attributeName) {
|
|
32264
|
+
case "Id":
|
|
32265
|
+
return physicalId;
|
|
32266
|
+
case "NameServers": {
|
|
32267
|
+
const response = await this.getClient().send(new GetHostedZoneCommand2({ Id: physicalId }));
|
|
32268
|
+
return (response.DelegationSet?.NameServers ?? []).join(",");
|
|
32269
|
+
}
|
|
32270
|
+
default:
|
|
32271
|
+
return void 0;
|
|
32272
|
+
}
|
|
32273
|
+
}
|
|
32274
|
+
// ─── AWS::Route53::RecordSet ───────────────────────────────────────
|
|
32275
|
+
async createRecordSet(logicalId, resourceType, properties) {
|
|
32276
|
+
this.logger.debug(`Creating Route 53 record set ${logicalId}`);
|
|
32277
|
+
const hostedZoneId = await this.resolveHostedZoneId(properties, logicalId, resourceType);
|
|
32278
|
+
const recordName = properties["Name"];
|
|
32279
|
+
const recordType = properties["Type"];
|
|
32280
|
+
try {
|
|
32281
|
+
const resourceRecordSet = this.buildResourceRecordSet(properties);
|
|
32282
|
+
const comment = properties["Comment"];
|
|
32283
|
+
await this.getClient().send(
|
|
32284
|
+
new ChangeResourceRecordSetsCommand({
|
|
32285
|
+
HostedZoneId: hostedZoneId,
|
|
32286
|
+
ChangeBatch: {
|
|
32287
|
+
...comment ? { Comment: comment } : {},
|
|
32288
|
+
Changes: [
|
|
32289
|
+
{
|
|
32290
|
+
Action: "CREATE",
|
|
32291
|
+
ResourceRecordSet: resourceRecordSet
|
|
32292
|
+
}
|
|
32293
|
+
]
|
|
32294
|
+
}
|
|
32295
|
+
})
|
|
32296
|
+
);
|
|
32297
|
+
const compositeId = `${hostedZoneId}|${recordName}|${recordType}`;
|
|
32298
|
+
this.logger.debug(`Successfully created record set ${logicalId}: ${compositeId}`);
|
|
32299
|
+
return {
|
|
32300
|
+
physicalId: compositeId,
|
|
32301
|
+
attributes: {}
|
|
32302
|
+
};
|
|
32303
|
+
} catch (error) {
|
|
32304
|
+
if (error instanceof ProvisioningError)
|
|
32305
|
+
throw error;
|
|
32306
|
+
const cause = error instanceof Error ? error : void 0;
|
|
32307
|
+
throw new ProvisioningError(
|
|
32308
|
+
`Failed to create record set ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
32309
|
+
resourceType,
|
|
32310
|
+
logicalId,
|
|
32311
|
+
void 0,
|
|
32312
|
+
cause
|
|
32313
|
+
);
|
|
32314
|
+
}
|
|
32315
|
+
}
|
|
32316
|
+
async updateRecordSet(logicalId, physicalId, resourceType, properties) {
|
|
32317
|
+
this.logger.debug(`Updating Route 53 record set ${logicalId}: ${physicalId}`);
|
|
32318
|
+
const hostedZoneId = await this.resolveHostedZoneId(
|
|
32319
|
+
properties,
|
|
32320
|
+
logicalId,
|
|
32321
|
+
resourceType,
|
|
32322
|
+
physicalId
|
|
32323
|
+
);
|
|
32324
|
+
const recordName = properties["Name"];
|
|
32325
|
+
const recordType = properties["Type"];
|
|
32326
|
+
try {
|
|
32327
|
+
const resourceRecordSet = this.buildResourceRecordSet(properties);
|
|
32328
|
+
const comment = properties["Comment"];
|
|
32329
|
+
await this.getClient().send(
|
|
32330
|
+
new ChangeResourceRecordSetsCommand({
|
|
32331
|
+
HostedZoneId: hostedZoneId,
|
|
32332
|
+
ChangeBatch: {
|
|
32333
|
+
...comment ? { Comment: comment } : {},
|
|
32334
|
+
Changes: [
|
|
32335
|
+
{
|
|
32336
|
+
Action: "UPSERT",
|
|
32337
|
+
ResourceRecordSet: resourceRecordSet
|
|
32338
|
+
}
|
|
32339
|
+
]
|
|
32340
|
+
}
|
|
32341
|
+
})
|
|
32342
|
+
);
|
|
32343
|
+
const compositeId = `${hostedZoneId}|${recordName}|${recordType}`;
|
|
32344
|
+
this.logger.debug(`Successfully updated record set ${logicalId}`);
|
|
32345
|
+
return {
|
|
32346
|
+
physicalId: compositeId,
|
|
32347
|
+
wasReplaced: false,
|
|
32348
|
+
attributes: {}
|
|
32349
|
+
};
|
|
32350
|
+
} catch (error) {
|
|
32351
|
+
const cause = error instanceof Error ? error : void 0;
|
|
32352
|
+
throw new ProvisioningError(
|
|
32353
|
+
`Failed to update record set ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
32354
|
+
resourceType,
|
|
32355
|
+
logicalId,
|
|
32356
|
+
physicalId,
|
|
32357
|
+
cause
|
|
32358
|
+
);
|
|
32359
|
+
}
|
|
32360
|
+
}
|
|
32361
|
+
async deleteRecordSet(logicalId, physicalId, resourceType, properties, context) {
|
|
32362
|
+
this.logger.debug(`Deleting Route 53 record set ${logicalId}: ${physicalId}`);
|
|
32363
|
+
const parts = physicalId.split("|");
|
|
32364
|
+
if (parts.length !== 3) {
|
|
32365
|
+
throw new ProvisioningError(
|
|
32366
|
+
`Invalid record set physical ID format: ${physicalId}`,
|
|
32367
|
+
resourceType,
|
|
32368
|
+
logicalId,
|
|
32369
|
+
physicalId
|
|
32370
|
+
);
|
|
32371
|
+
}
|
|
32372
|
+
const [hostedZoneId] = parts;
|
|
32373
|
+
if (!properties) {
|
|
32374
|
+
throw new ProvisioningError(
|
|
32375
|
+
`Properties required to delete record set ${logicalId}`,
|
|
32376
|
+
resourceType,
|
|
32377
|
+
logicalId,
|
|
32378
|
+
physicalId
|
|
32379
|
+
);
|
|
32380
|
+
}
|
|
32381
|
+
try {
|
|
32382
|
+
const resourceRecordSet = this.buildResourceRecordSet(properties);
|
|
32383
|
+
await this.getClient().send(
|
|
32384
|
+
new ChangeResourceRecordSetsCommand({
|
|
32385
|
+
HostedZoneId: hostedZoneId,
|
|
32386
|
+
ChangeBatch: {
|
|
32387
|
+
Changes: [
|
|
32388
|
+
{
|
|
32389
|
+
Action: "DELETE",
|
|
32390
|
+
ResourceRecordSet: resourceRecordSet
|
|
32391
|
+
}
|
|
32392
|
+
]
|
|
32393
|
+
}
|
|
32394
|
+
})
|
|
32395
|
+
);
|
|
32396
|
+
this.logger.debug(`Successfully deleted record set ${logicalId}`);
|
|
32397
|
+
} catch (error) {
|
|
32398
|
+
if (error instanceof Error && (error.name === "InvalidChangeBatch" || error.message.includes("it was not found"))) {
|
|
32399
|
+
const clientRegion = await this.getClient().config.region();
|
|
32400
|
+
assertRegionMatch(
|
|
32401
|
+
clientRegion,
|
|
32402
|
+
context?.expectedRegion,
|
|
32403
|
+
resourceType,
|
|
32404
|
+
logicalId,
|
|
32405
|
+
physicalId
|
|
32406
|
+
);
|
|
32407
|
+
this.logger.debug(`Record set ${physicalId} does not exist, skipping deletion`);
|
|
32408
|
+
return;
|
|
32409
|
+
}
|
|
32410
|
+
if (error instanceof Error && error.name === "NoSuchHostedZone") {
|
|
32411
|
+
this.logger.debug(
|
|
32412
|
+
`Hosted zone for record set ${physicalId} does not exist, skipping deletion`
|
|
32413
|
+
);
|
|
32414
|
+
return;
|
|
32415
|
+
}
|
|
32416
|
+
const cause = error instanceof Error ? error : void 0;
|
|
32417
|
+
throw new ProvisioningError(
|
|
32418
|
+
`Failed to delete record set ${logicalId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
32419
|
+
resourceType,
|
|
32420
|
+
logicalId,
|
|
32421
|
+
physicalId,
|
|
32422
|
+
cause
|
|
32423
|
+
);
|
|
32424
|
+
}
|
|
32425
|
+
}
|
|
32426
|
+
// ─── Helpers ───────────────────────────────────────────────────────
|
|
32427
|
+
/**
|
|
32428
|
+
* Build a ResourceRecordSet object from CDK properties.
|
|
32429
|
+
*
|
|
32430
|
+
* Handles conversion of CDK-style ResourceRecords (array of strings)
|
|
32431
|
+
* to SDK-style ResourceRecords (array of {Value}).
|
|
32432
|
+
* Also handles routing policy properties: Weight, Region, Failover,
|
|
32433
|
+
* MultiValueAnswer, GeoLocation, SetIdentifier, and HealthCheckId.
|
|
32434
|
+
*/
|
|
32435
|
+
buildResourceRecordSet(properties) {
|
|
32436
|
+
const name = properties["Name"];
|
|
32437
|
+
const type = properties["Type"];
|
|
32438
|
+
const ttl = properties["TTL"];
|
|
32439
|
+
const resourceRecords = properties["ResourceRecords"];
|
|
32440
|
+
const aliasTarget = properties["AliasTarget"];
|
|
32441
|
+
const recordSet = {
|
|
32442
|
+
Name: name,
|
|
32443
|
+
Type: type
|
|
32444
|
+
};
|
|
32445
|
+
if (aliasTarget) {
|
|
32446
|
+
recordSet.AliasTarget = {
|
|
32447
|
+
HostedZoneId: aliasTarget["HostedZoneId"],
|
|
32448
|
+
DNSName: aliasTarget["DNSName"],
|
|
32449
|
+
EvaluateTargetHealth: aliasTarget["EvaluateTargetHealth"] ?? false
|
|
32450
|
+
};
|
|
32451
|
+
} else {
|
|
32452
|
+
if (ttl !== void 0) {
|
|
32453
|
+
recordSet.TTL = Number(ttl);
|
|
32454
|
+
}
|
|
32455
|
+
if (resourceRecords) {
|
|
32456
|
+
recordSet.ResourceRecords = resourceRecords.map((record) => {
|
|
32457
|
+
if (typeof record === "string") {
|
|
32458
|
+
return { Value: record };
|
|
32459
|
+
}
|
|
32460
|
+
return record;
|
|
32461
|
+
});
|
|
32462
|
+
}
|
|
32463
|
+
}
|
|
32464
|
+
const setIdentifier = properties["SetIdentifier"];
|
|
30480
32465
|
if (setIdentifier !== void 0) {
|
|
30481
32466
|
recordSet.SetIdentifier = setIdentifier;
|
|
30482
32467
|
}
|
|
@@ -30750,7 +32735,7 @@ var Route53Provider = class {
|
|
|
30750
32735
|
const idTail = physicalId.replace(/^\/hostedzone\//, "");
|
|
30751
32736
|
try {
|
|
30752
32737
|
const tagsResp = await this.getClient().send(
|
|
30753
|
-
new
|
|
32738
|
+
new ListTagsForResourceCommand13({ ResourceType: "hostedzone", ResourceId: idTail })
|
|
30754
32739
|
);
|
|
30755
32740
|
const tags = normalizeAwsTagsToCfn(tagsResp.ResourceTagSet?.Tags);
|
|
30756
32741
|
result["HostedZoneTags"] = tags;
|
|
@@ -30900,7 +32885,7 @@ var Route53Provider = class {
|
|
|
30900
32885
|
const zoneId = zone.Id.replace("/hostedzone/", "");
|
|
30901
32886
|
try {
|
|
30902
32887
|
const tagsResp = await this.getClient().send(
|
|
30903
|
-
new
|
|
32888
|
+
new ListTagsForResourceCommand13({
|
|
30904
32889
|
ResourceType: "hostedzone",
|
|
30905
32890
|
ResourceId: zoneId
|
|
30906
32891
|
})
|
|
@@ -30928,7 +32913,7 @@ import {
|
|
|
30928
32913
|
DeleteWebACLCommand,
|
|
30929
32914
|
GetWebACLCommand,
|
|
30930
32915
|
ListWebACLsCommand,
|
|
30931
|
-
ListTagsForResourceCommand as
|
|
32916
|
+
ListTagsForResourceCommand as ListTagsForResourceCommand14,
|
|
30932
32917
|
TagResourceCommand as TagResourceCommand13,
|
|
30933
32918
|
UntagResourceCommand as UntagResourceCommand13,
|
|
30934
32919
|
WAFNonexistentItemException
|
|
@@ -31256,7 +33241,7 @@ var WAFv2WebACLProvider = class {
|
|
|
31256
33241
|
}
|
|
31257
33242
|
try {
|
|
31258
33243
|
const tagsResp = await this.getClient().send(
|
|
31259
|
-
new
|
|
33244
|
+
new ListTagsForResourceCommand14({ ResourceARN: physicalId })
|
|
31260
33245
|
);
|
|
31261
33246
|
const tags = normalizeAwsTagsToCfn(tagsResp.TagInfoForResource?.TagList);
|
|
31262
33247
|
result["Tags"] = tags;
|
|
@@ -31304,7 +33289,7 @@ var WAFv2WebACLProvider = class {
|
|
|
31304
33289
|
if (!item.ARN)
|
|
31305
33290
|
continue;
|
|
31306
33291
|
const tagsResp = await this.getClient().send(
|
|
31307
|
-
new
|
|
33292
|
+
new ListTagsForResourceCommand14({ ResourceARN: item.ARN })
|
|
31308
33293
|
);
|
|
31309
33294
|
const tagList = tagsResp.TagInfoForResource?.TagList;
|
|
31310
33295
|
if (matchesCdkPath(tagList, input.cdkPath)) {
|
|
@@ -31325,7 +33310,7 @@ import {
|
|
|
31325
33310
|
UpdateUserPoolCommand,
|
|
31326
33311
|
DescribeUserPoolCommand,
|
|
31327
33312
|
ListUserPoolsCommand,
|
|
31328
|
-
ListTagsForResourceCommand as
|
|
33313
|
+
ListTagsForResourceCommand as ListTagsForResourceCommand15,
|
|
31329
33314
|
ResourceNotFoundException as ResourceNotFoundException12
|
|
31330
33315
|
} from "@aws-sdk/client-cognito-identity-provider";
|
|
31331
33316
|
function isEmptyObjectPlaceholder(value) {
|
|
@@ -31794,7 +33779,7 @@ var CognitoUserPoolProvider = class {
|
|
|
31794
33779
|
if (!arn)
|
|
31795
33780
|
continue;
|
|
31796
33781
|
const tagsResp = await this.getClient().send(
|
|
31797
|
-
new
|
|
33782
|
+
new ListTagsForResourceCommand15({ ResourceArn: arn })
|
|
31798
33783
|
);
|
|
31799
33784
|
if (tagsResp.Tags?.[CDK_PATH_TAG] === input.cdkPath) {
|
|
31800
33785
|
return { physicalId: pool.Id, attributes: {} };
|
|
@@ -31823,9 +33808,9 @@ import {
|
|
|
31823
33808
|
DeleteCacheSubnetGroupCommand,
|
|
31824
33809
|
ModifyCacheSubnetGroupCommand,
|
|
31825
33810
|
ModifyCacheClusterCommand,
|
|
31826
|
-
ListTagsForResourceCommand as
|
|
31827
|
-
AddTagsToResourceCommand as
|
|
31828
|
-
RemoveTagsFromResourceCommand as
|
|
33811
|
+
ListTagsForResourceCommand as ListTagsForResourceCommand16,
|
|
33812
|
+
AddTagsToResourceCommand as AddTagsToResourceCommand5,
|
|
33813
|
+
RemoveTagsFromResourceCommand as RemoveTagsFromResourceCommand5
|
|
31829
33814
|
} from "@aws-sdk/client-elasticache";
|
|
31830
33815
|
import { STSClient as STSClient6, GetCallerIdentityCommand as GetCallerIdentityCommand6 } from "@aws-sdk/client-sts";
|
|
31831
33816
|
var ElastiCacheProvider = class {
|
|
@@ -32211,13 +34196,13 @@ var ElastiCacheProvider = class {
|
|
|
32211
34196
|
}
|
|
32212
34197
|
if (tagsToRemove.length > 0) {
|
|
32213
34198
|
await this.getClient().send(
|
|
32214
|
-
new
|
|
34199
|
+
new RemoveTagsFromResourceCommand5({ ResourceName: arn, TagKeys: tagsToRemove })
|
|
32215
34200
|
);
|
|
32216
34201
|
this.logger.debug(`Removed ${tagsToRemove.length} tag(s) from ElastiCache resource ${arn}`);
|
|
32217
34202
|
}
|
|
32218
34203
|
if (tagsToAdd.length > 0) {
|
|
32219
34204
|
await this.getClient().send(
|
|
32220
|
-
new
|
|
34205
|
+
new AddTagsToResourceCommand5({ ResourceName: arn, Tags: tagsToAdd })
|
|
32221
34206
|
);
|
|
32222
34207
|
this.logger.debug(`Added/updated ${tagsToAdd.length} tag(s) on ElastiCache resource ${arn}`);
|
|
32223
34208
|
}
|
|
@@ -32417,7 +34402,7 @@ var ElastiCacheProvider = class {
|
|
|
32417
34402
|
async attachTags(result, arn) {
|
|
32418
34403
|
try {
|
|
32419
34404
|
const tagsResp = await this.getClient().send(
|
|
32420
|
-
new
|
|
34405
|
+
new ListTagsForResourceCommand16({ ResourceName: arn })
|
|
32421
34406
|
);
|
|
32422
34407
|
const tags = normalizeAwsTagsToCfn(tagsResp.TagList);
|
|
32423
34408
|
result["Tags"] = tags;
|
|
@@ -32479,7 +34464,7 @@ var ElastiCacheProvider = class {
|
|
|
32479
34464
|
continue;
|
|
32480
34465
|
const arn = c.ARN ?? await this.buildClusterArn(c.CacheClusterId);
|
|
32481
34466
|
const tagsResp = await this.getClient().send(
|
|
32482
|
-
new
|
|
34467
|
+
new ListTagsForResourceCommand16({ ResourceName: arn })
|
|
32483
34468
|
);
|
|
32484
34469
|
if (matchesCdkPath(tagsResp.TagList, input.cdkPath)) {
|
|
32485
34470
|
return { physicalId: c.CacheClusterId, attributes: {} };
|
|
@@ -32516,7 +34501,7 @@ var ElastiCacheProvider = class {
|
|
|
32516
34501
|
continue;
|
|
32517
34502
|
const arn = g.ARN ?? await this.buildSubnetGroupArn(g.CacheSubnetGroupName);
|
|
32518
34503
|
const tagsResp = await this.getClient().send(
|
|
32519
|
-
new
|
|
34504
|
+
new ListTagsForResourceCommand16({ ResourceName: arn })
|
|
32520
34505
|
);
|
|
32521
34506
|
if (matchesCdkPath(tagsResp.TagList, input.cdkPath)) {
|
|
32522
34507
|
return { physicalId: g.CacheSubnetGroupName, attributes: {} };
|
|
@@ -32569,7 +34554,7 @@ import {
|
|
|
32569
34554
|
GetServiceCommand,
|
|
32570
34555
|
ListNamespacesCommand,
|
|
32571
34556
|
ListServicesCommand as ListServicesCommand2,
|
|
32572
|
-
ListTagsForResourceCommand as
|
|
34557
|
+
ListTagsForResourceCommand as ListTagsForResourceCommand17,
|
|
32573
34558
|
NamespaceNotFound,
|
|
32574
34559
|
ServiceNotFound
|
|
32575
34560
|
} from "@aws-sdk/client-servicediscovery";
|
|
@@ -33133,7 +35118,7 @@ var ServiceDiscoveryProvider = class {
|
|
|
33133
35118
|
async attachTags(result, arn) {
|
|
33134
35119
|
try {
|
|
33135
35120
|
const tagsResp = await this.getClient().send(
|
|
33136
|
-
new
|
|
35121
|
+
new ListTagsForResourceCommand17({ ResourceARN: arn })
|
|
33137
35122
|
);
|
|
33138
35123
|
const tags = normalizeAwsTagsToCfn(tagsResp.Tags);
|
|
33139
35124
|
result["Tags"] = tags;
|
|
@@ -33179,7 +35164,7 @@ var ServiceDiscoveryProvider = class {
|
|
|
33179
35164
|
if (input.cdkPath) {
|
|
33180
35165
|
try {
|
|
33181
35166
|
const tagsResp = await this.getClient().send(
|
|
33182
|
-
new
|
|
35167
|
+
new ListTagsForResourceCommand17({ ResourceARN: ns.Arn })
|
|
33183
35168
|
);
|
|
33184
35169
|
if (matchesCdkPath(tagsResp.Tags, input.cdkPath)) {
|
|
33185
35170
|
return { physicalId: ns.Id, attributes: {} };
|
|
@@ -33218,7 +35203,7 @@ var ServiceDiscoveryProvider = class {
|
|
|
33218
35203
|
continue;
|
|
33219
35204
|
try {
|
|
33220
35205
|
const tagsResp = await this.getClient().send(
|
|
33221
|
-
new
|
|
35206
|
+
new ListTagsForResourceCommand17({ ResourceARN: svc.Arn })
|
|
33222
35207
|
);
|
|
33223
35208
|
if (matchesCdkPath(tagsResp.Tags, input.cdkPath)) {
|
|
33224
35209
|
return { physicalId: svc.Id, attributes: {} };
|
|
@@ -38416,7 +40401,7 @@ import {
|
|
|
38416
40401
|
GetVectorBucketCommand,
|
|
38417
40402
|
ListIndexesCommand,
|
|
38418
40403
|
ListVectorBucketsCommand,
|
|
38419
|
-
ListTagsForResourceCommand as
|
|
40404
|
+
ListTagsForResourceCommand as ListTagsForResourceCommand18,
|
|
38420
40405
|
DeleteIndexCommand
|
|
38421
40406
|
} from "@aws-sdk/client-s3vectors";
|
|
38422
40407
|
var S3VectorsProvider = class {
|
|
@@ -38650,7 +40635,7 @@ var S3VectorsProvider = class {
|
|
|
38650
40635
|
continue;
|
|
38651
40636
|
try {
|
|
38652
40637
|
const tagsResp = await this.getClient().send(
|
|
38653
|
-
new
|
|
40638
|
+
new ListTagsForResourceCommand18({ resourceArn: bucket.vectorBucketArn })
|
|
38654
40639
|
);
|
|
38655
40640
|
if (tagsResp.tags?.[CDK_PATH_TAG] === input.cdkPath) {
|
|
38656
40641
|
return { physicalId: bucket.vectorBucketName, attributes: {} };
|
|
@@ -38994,7 +40979,7 @@ import {
|
|
|
38994
40979
|
ListNamespacesCommand as ListNamespacesCommand2,
|
|
38995
40980
|
ListTablesCommand as ListTablesCommand2,
|
|
38996
40981
|
ListTableBucketsCommand,
|
|
38997
|
-
ListTagsForResourceCommand as
|
|
40982
|
+
ListTagsForResourceCommand as ListTagsForResourceCommand19,
|
|
38998
40983
|
NotFoundException as NotFoundException6
|
|
38999
40984
|
} from "@aws-sdk/client-s3tables";
|
|
39000
40985
|
var S3TablesProvider = class {
|
|
@@ -39478,7 +41463,7 @@ var S3TablesProvider = class {
|
|
|
39478
41463
|
if (input.cdkPath) {
|
|
39479
41464
|
try {
|
|
39480
41465
|
const tagsResp = await this.getClient().send(
|
|
39481
|
-
new
|
|
41466
|
+
new ListTagsForResourceCommand19({ resourceArn: bucket.arn })
|
|
39482
41467
|
);
|
|
39483
41468
|
if (tagsResp.tags?.[CDK_PATH_TAG] === input.cdkPath) {
|
|
39484
41469
|
return { physicalId: bucket.arn, attributes: {} };
|
|
@@ -39558,7 +41543,7 @@ var S3TablesProvider = class {
|
|
|
39558
41543
|
continue;
|
|
39559
41544
|
try {
|
|
39560
41545
|
const tagsResp = await this.getClient().send(
|
|
39561
|
-
new
|
|
41546
|
+
new ListTagsForResourceCommand19({ resourceArn: table.tableARN })
|
|
39562
41547
|
);
|
|
39563
41548
|
if (tagsResp.tags?.[CDK_PATH_TAG] === input.cdkPath) {
|
|
39564
41549
|
return {
|
|
@@ -39644,7 +41629,7 @@ import {
|
|
|
39644
41629
|
PutImageScanningConfigurationCommand,
|
|
39645
41630
|
PutImageTagMutabilityCommand,
|
|
39646
41631
|
TagResourceCommand as TagResourceCommand15,
|
|
39647
|
-
ListTagsForResourceCommand as
|
|
41632
|
+
ListTagsForResourceCommand as ListTagsForResourceCommand20,
|
|
39648
41633
|
LifecyclePolicyNotFoundException,
|
|
39649
41634
|
RepositoryNotFoundException
|
|
39650
41635
|
} from "@aws-sdk/client-ecr";
|
|
@@ -39974,7 +41959,7 @@ var ECRProvider = class {
|
|
|
39974
41959
|
if (r.repositoryArn) {
|
|
39975
41960
|
try {
|
|
39976
41961
|
const tagsResp = await this.getClient().send(
|
|
39977
|
-
new
|
|
41962
|
+
new ListTagsForResourceCommand20({ resourceArn: r.repositoryArn })
|
|
39978
41963
|
);
|
|
39979
41964
|
const tags = normalizeAwsTagsToCfn(tagsResp.tags);
|
|
39980
41965
|
result["Tags"] = tags;
|
|
@@ -40020,7 +42005,7 @@ var ECRProvider = class {
|
|
|
40020
42005
|
continue;
|
|
40021
42006
|
try {
|
|
40022
42007
|
const tagsResp = await this.getClient().send(
|
|
40023
|
-
new
|
|
42008
|
+
new ListTagsForResourceCommand20({ resourceArn: repo.repositoryArn })
|
|
40024
42009
|
);
|
|
40025
42010
|
if (matchesCdkPath(tagsResp.tags, input.cdkPath)) {
|
|
40026
42011
|
return { physicalId: repo.repositoryName, attributes: {} };
|
|
@@ -40749,6 +42734,14 @@ function registerAllProviders(registry) {
|
|
|
40749
42734
|
registry.register("AWS::RDS::DBSubnetGroup", rdsProvider);
|
|
40750
42735
|
registry.register("AWS::RDS::DBCluster", rdsProvider);
|
|
40751
42736
|
registry.register("AWS::RDS::DBInstance", rdsProvider);
|
|
42737
|
+
const docdbProvider = new DocDBProvider();
|
|
42738
|
+
registry.register("AWS::DocDB::DBSubnetGroup", docdbProvider);
|
|
42739
|
+
registry.register("AWS::DocDB::DBCluster", docdbProvider);
|
|
42740
|
+
registry.register("AWS::DocDB::DBInstance", docdbProvider);
|
|
42741
|
+
const neptuneProvider = new NeptuneProvider();
|
|
42742
|
+
registry.register("AWS::Neptune::DBSubnetGroup", neptuneProvider);
|
|
42743
|
+
registry.register("AWS::Neptune::DBCluster", neptuneProvider);
|
|
42744
|
+
registry.register("AWS::Neptune::DBInstance", neptuneProvider);
|
|
40752
42745
|
const route53Provider = new Route53Provider();
|
|
40753
42746
|
registry.register("AWS::Route53::HostedZone", route53Provider);
|
|
40754
42747
|
registry.register("AWS::Route53::RecordSet", route53Provider);
|
|
@@ -43750,6 +45743,14 @@ var PROTECTION_PROPERTY_BY_TYPE = {
|
|
|
43750
45743
|
"AWS::Logs::LogGroup": "DeletionProtectionEnabled",
|
|
43751
45744
|
"AWS::RDS::DBInstance": "DeletionProtection",
|
|
43752
45745
|
"AWS::RDS::DBCluster": "DeletionProtection",
|
|
45746
|
+
// DocDB: cluster-level only. The DocDB DBInstance shape does NOT
|
|
45747
|
+
// expose a DeletionProtection field (verified against the
|
|
45748
|
+
// @aws-sdk/client-docdb CreateDBInstanceMessage type — the field is
|
|
45749
|
+
// absent), so there is nothing to flip on destroy of an instance.
|
|
45750
|
+
"AWS::DocDB::DBCluster": "DeletionProtection",
|
|
45751
|
+
// Neptune: both cluster and instance expose DeletionProtection.
|
|
45752
|
+
"AWS::Neptune::DBCluster": "DeletionProtection",
|
|
45753
|
+
"AWS::Neptune::DBInstance": "DeletionProtection",
|
|
43753
45754
|
"AWS::DynamoDB::Table": "DeletionProtectionEnabled",
|
|
43754
45755
|
"AWS::EC2::Instance": "DisableApiTermination",
|
|
43755
45756
|
"AWS::Cognito::UserPool": "DeletionProtection",
|
|
@@ -46070,7 +48071,7 @@ function createStateDestroyCommand() {
|
|
|
46070
48071
|
"Destroy a stack's AWS resources and remove its state record without requiring the CDK app. For removing only the state record (keeping AWS resources intact), use 'cdkd state orphan'."
|
|
46071
48072
|
).argument("[stacks...]", "Stack name(s) to destroy (physical CloudFormation names)").option("--all", "Destroy every stack in the state bucket", false).option(
|
|
46072
48073
|
"--remove-protection",
|
|
46073
|
-
"Bypass deletion protection on protected resources by flipping the per-resource protection flag off in-place before delete. Covers AWS::Logs::LogGroup, AWS::RDS::DBInstance, AWS::RDS::DBCluster, AWS::DynamoDB::Table, AWS::EC2::Instance, and AWS::ElasticLoadBalancingV2::LoadBalancer.",
|
|
48074
|
+
"Bypass deletion protection on protected resources by flipping the per-resource protection flag off in-place before delete. Covers AWS::Logs::LogGroup, AWS::RDS::DBInstance, AWS::RDS::DBCluster, AWS::DocDB::DBCluster, AWS::Neptune::DBCluster, AWS::Neptune::DBInstance, AWS::DynamoDB::Table, AWS::EC2::Instance, AWS::Cognito::UserPool, AWS::AutoScaling::AutoScalingGroup, and AWS::ElasticLoadBalancingV2::LoadBalancer.",
|
|
46074
48075
|
false
|
|
46075
48076
|
).addOption(stackRegionOption2()).addHelpText(
|
|
46076
48077
|
"after",
|
|
@@ -47212,7 +49213,7 @@ function reorderArgs(argv) {
|
|
|
47212
49213
|
}
|
|
47213
49214
|
async function main() {
|
|
47214
49215
|
const program = new Command14();
|
|
47215
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.
|
|
49216
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.60.0");
|
|
47216
49217
|
program.addCommand(createBootstrapCommand());
|
|
47217
49218
|
program.addCommand(createSynthCommand());
|
|
47218
49219
|
program.addCommand(createListCommand());
|