in packages/aws-cdk-lib/aws-rds/lib/instance.ts [845:978]
constructor(scope: Construct, id: string, props: DatabaseInstanceNewProps) {
// RDS always lower-cases the ID of the database, so use that for the physical name
// (which is the name used for cross-environment access, so it needs to be correct,
// regardless of the feature flag that changes it in the template for the L1)
const instancePhysicalName = Token.isUnresolved(props.instanceIdentifier)
? props.instanceIdentifier
: props.instanceIdentifier?.toLowerCase();
super(scope, id, {
physicalName: instancePhysicalName,
});
this.vpc = props.vpc;
if (props.vpcSubnets && props.vpcPlacement) {
throw new ValidationError('Only one of `vpcSubnets` or `vpcPlacement` can be specified', this);
}
this.vpcPlacement = props.vpcSubnets ?? props.vpcPlacement;
if (props.multiAz === true && props.availabilityZone) {
throw new ValidationError('Requesting a specific availability zone is not valid for Multi-AZ instances', this);
}
const subnetGroup = props.subnetGroup ?? new SubnetGroup(this, 'SubnetGroup', {
description: `Subnet group for ${this.node.id} database`,
vpc: this.vpc,
vpcSubnets: this.vpcPlacement,
removalPolicy: renderUnless(helperRemovalPolicy(props.removalPolicy), RemovalPolicy.DESTROY),
});
const securityGroups = props.securityGroups || [new ec2.SecurityGroup(this, 'SecurityGroup', {
description: `Security group for ${this.node.id} database`,
vpc: props.vpc,
})];
this.connections = new ec2.Connections({
securityGroups,
defaultPort: ec2.Port.tcp(Lazy.number({ produce: () => this.instanceEndpoint.port })),
});
let monitoringRole;
if (props.monitoringInterval && props.monitoringInterval.toSeconds()) {
monitoringRole = props.monitoringRole || new iam.Role(this, 'MonitoringRole', {
assumedBy: new iam.ServicePrincipal('monitoring.rds.amazonaws.com'),
managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AmazonRDSEnhancedMonitoringRole')],
});
}
const storageType = props.storageType ?? StorageType.GP2;
const iops = defaultIops(storageType, props.iops);
if (props.storageThroughput && storageType !== StorageType.GP3) {
throw new ValidationError(`The storage throughput can only be specified with GP3 storage type. Got ${storageType}.`, this);
}
if (storageType === StorageType.GP3 && props.storageThroughput && iops
&& !Token.isUnresolved(props.storageThroughput) && !Token.isUnresolved(iops)
&& props.storageThroughput/iops > 0.25) {
throw new ValidationError(`The maximum ratio of storage throughput to IOPS is 0.25. Got ${props.storageThroughput/iops}.`, this);
}
this.cloudwatchLogGroups = {};
this.cloudwatchLogsExports = props.cloudwatchLogsExports;
this.cloudwatchLogsRetention = props.cloudwatchLogsRetention;
this.cloudwatchLogsRetentionRole = props.cloudwatchLogsRetentionRole;
this.enableIamAuthentication = props.iamAuthentication;
const enablePerformanceInsights = props.enablePerformanceInsights
|| props.performanceInsightRetention !== undefined || props.performanceInsightEncryptionKey !== undefined;
if (enablePerformanceInsights && props.enablePerformanceInsights === false) {
throw new ValidationError('`enablePerformanceInsights` disabled, but `performanceInsightRetention` or `performanceInsightEncryptionKey` was set', this);
}
if (props.domain) {
this.domainId = props.domain;
this.domainRole = props.domainRole || new iam.Role(this, 'RDSDirectoryServiceRole', {
assumedBy: new iam.CompositePrincipal(
new iam.ServicePrincipal('rds.amazonaws.com'),
new iam.ServicePrincipal('directoryservice.rds.amazonaws.com'),
),
managedPolicies: [
iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AmazonRDSDirectoryServiceAccess'),
],
});
}
const maybeLowercasedInstanceId = FeatureFlags.of(this).isEnabled(cxapi.RDS_LOWERCASE_DB_IDENTIFIER)
&& !Token.isUnresolved(props.instanceIdentifier)
? props.instanceIdentifier?.toLowerCase()
: props.instanceIdentifier;
const instanceParameterGroupConfig = props.parameterGroup?.bindToInstance({});
const isInPublicSubnet = this.vpcPlacement && this.vpcPlacement.subnetType === ec2.SubnetType.PUBLIC;
this.newCfnProps = {
autoMinorVersionUpgrade: props.autoMinorVersionUpgrade,
availabilityZone: props.multiAz ? undefined : props.availabilityZone,
backupRetentionPeriod: props.backupRetention?.toDays(),
copyTagsToSnapshot: props.copyTagsToSnapshot ?? true,
dbInstanceClass: Lazy.string({ produce: () => `db.${this.instanceType}` }),
dbInstanceIdentifier: Token.isUnresolved(props.instanceIdentifier)
// if the passed identifier is a Token,
// we need to use the physicalName of the database
// (we cannot change its case anyway),
// as it might be used in a cross-environment fashion
? this.physicalName
: maybeLowercasedInstanceId,
dbSubnetGroupName: subnetGroup.subnetGroupName,
deleteAutomatedBackups: props.deleteAutomatedBackups,
deletionProtection: defaultDeletionProtection(props.deletionProtection, props.removalPolicy),
enableCloudwatchLogsExports: this.cloudwatchLogsExports,
enableIamDatabaseAuthentication: Lazy.any({ produce: () => this.enableIamAuthentication }),
enablePerformanceInsights: enablePerformanceInsights || props.enablePerformanceInsights, // fall back to undefined if not set,
iops,
monitoringInterval: props.monitoringInterval?.toSeconds(),
monitoringRoleArn: monitoringRole?.roleArn,
multiAz: props.multiAz,
dbParameterGroupName: instanceParameterGroupConfig?.parameterGroupName,
optionGroupName: props.optionGroup?.optionGroupName,
performanceInsightsKmsKeyId: props.performanceInsightEncryptionKey?.keyArn,
performanceInsightsRetentionPeriod: enablePerformanceInsights
? (props.performanceInsightRetention || PerformanceInsightRetention.DEFAULT)
: undefined,
port: props.port !== undefined ? Tokenization.stringifyNumber(props.port) : undefined,
preferredBackupWindow: props.preferredBackupWindow,
preferredMaintenanceWindow: props.preferredMaintenanceWindow,
processorFeatures: props.processorFeatures && renderProcessorFeatures(props.processorFeatures),
publiclyAccessible: props.publiclyAccessible ?? isInPublicSubnet,
storageType,
storageThroughput: props.storageThroughput,
vpcSecurityGroups: securityGroups.map(s => s.securityGroupId),
maxAllocatedStorage: props.maxAllocatedStorage,
domain: this.domainId,
domainIamRoleName: this.domainRole?.roleName,
networkType: props.networkType,
caCertificateIdentifier: props.caCertificate ? props.caCertificate.toString() : undefined,
applyImmediately: props.applyImmediately,
};
}