From f0ac86a1c8063e8d6b83e36e0a5cb6cff7425dc0 Mon Sep 17 00:00:00 2001 From: corymhall <43035978+corymhall@users.noreply.github.com> Date: Thu, 4 May 2023 12:47:44 +0000 Subject: [PATCH 01/10] feat(rds): support Aurora Serverless V2 instances Starting off with just an ADR so that we can first agree on the approach we will take in this PR. Once that has been agreed upon then I will work on implementation. closes #20197 --- .../aws-rds/adr/aurora-serverless-v2.md | 233 ++++++++++++++++++ 1 file changed, 233 insertions(+) create mode 100644 packages/aws-cdk-lib/aws-rds/adr/aurora-serverless-v2.md diff --git a/packages/aws-cdk-lib/aws-rds/adr/aurora-serverless-v2.md b/packages/aws-cdk-lib/aws-rds/adr/aurora-serverless-v2.md new file mode 100644 index 0000000000000..4aae4a44f57d5 --- /dev/null +++ b/packages/aws-cdk-lib/aws-rds/adr/aurora-serverless-v2.md @@ -0,0 +1,233 @@ +# Aurora Serverless V2 + +> **Note** recommended reading https://aws.amazon.com/blogs/database/evaluate-amazon-aurora-serverless-v2-for-your-provisioned-aurora-clusters/ + +## Status + +accepted + +## Context + +Recently RDS Aurora clusters added support for [Aurora Serverless +V2](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-serverless-v2.html). +Prior to that there were two types of clusters that you could create. + +1. A Serverless v1 cluster +2. A provisioned cluster + +Each of these clusters only supported a single type of DB instance (serverless +or provisioned) and it was not possible to mix the two types of instances +together. With the addition of Serverless V2 it is now possible to create a +cluster which has _both_ provisioned instances and serverless v2 instances. + +### Current API + +With the current API you create a cluster and specify the number of instances to +create and the properties to apply to _all_ of the instances. You do not have +granular control over each individual instance. + +```ts +const cluster = new rds.DatabaseCluster(this, 'Database', { + engine: rds.DatabaseClusterEngine.auroraMysql({ version: rds.AuroraMysqlEngineVersion.VER_2_08_1 }), + instances: 3, // default is 2 + instanceProps: { + // optional , defaults to t3.medium + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, + }, +}); +``` + +### Serverless v2 + +#### Capacity & Scaling + +Some things to take into consideration with Aurora Serverless v2. + +To create a cluster that can support serverless v2 instance you configure a +minimum and maximum capacity range. This looks something like + +```json +{ + "MaxCapacity": 128, // max value + "MinCapacity": 0.5 // min value +} +``` + +The capacity is defined as a number of Aurora capacity units (ACUs). You can +specify in half-step increments (40, 40.5, 41, etc). + +The maximum capacity is mainly used for budget control since it allows you to +set a cap on how high your instance can scale. + +The minimum capacity is a little more involved. This controls a couple different +things. More complete details can be found [in the docs](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-serverless-v2.setting-capacity.html#aurora-serverless-v2-examples-setting-capacity-range-for-cluster) + +1. How low can the instance scale down. If there is no traffic to the cluster + this is the minimum capacity that is allowed. +2. How fast can the instance scale up. The scaling rate of an Aurora Serverless + v2 instance depends on its current capacity. The higher the current capacity, + the faster it can scale up. So for example, if you need to very quickly scale + up to high capacity, you might have to set the minimum higher to allow for + faster scaling. +3. If you have a higher amount of data in the buffer cache you may have to set + the minimum higher so that data is not evicted from the buffer cache when + then instances scale down. +4. Some features require certain minimums + - Performance insights - 2 ACUs + - Aurora global databases - 8 ACUs (in primary region) +5. For high write workloads with serverless v2 readers in tiers 2-15 (more on + tiers below), you may need to provision a higher minimum capacity to reduce + replica lag. + - When using a provisioned writer, you should set the minimum capacity to a + value that represents a comparable amount of memory and CPU to the + writer. (this is only if you notice replication lag) + + +Another way that you control the capacity/scaling of your serverless v2 reader +instances is based on the [promotion tier](https://aws.amazon.com/blogs/aws/additional-failover-control-for-amazon-aurora/) +which can be between 0-15. Previously with all provisioned clusters this didn't +matter too much (we set everything to 1), but with serverless v2 it starts to +matter. Any serverless v2 instance in the 0-1 tiers will scale alongside the +writer even if the current read load does not require the capacity. This is +because instances in the 0-1 tier are first priority for failover and Aurora +wants to ensure that in the event of a failover the reader that gets promoted is +scaled to handle the write load. + +- Serverless v2 readers in tier 0-1 scale with the writer +- Serverless v2 readers in tier 2-15 scale with the read load on itself. + +### Serverless v2 vs Provisioned + +Serverless v2 can go up to 256GB memory. Anything above that needs to be provisioned. + - For example, if the CPU utilization for a db.r6g.4xlarge (128 GB) + instance stays at 10% most times, then the minimum ACUs may be set + at 6.5 ACUs (10% of 128 GB) and maximum may be set at 64 ACUs (64x2GB=128GB). + - But if using a db.r6g.16xlarge (512 GB) a serverles v2 instance can't scale + to match + +Out of the 4 common usage patters (peaks & valleys, outliers, random, and +consistent), provisioned should be preferred for the consistent pattern. With +mixed use cluster you may have writers/readers that follow different patters. +For example, you may have a writer that follows the `consistent` pattern, but a +reader that follows the `outliers` pattern. In this case you may want to have a +provisioned instance as the writer along with a provisioned writer in tier 0-1 +(for failover) and then a serverless v2 reader in tier 2-15 (so it doesn't scale with the +writer). + +If you are currently using auto scaling with provisioned instances, you should +instead switch to instance scaling with serverless v2. This allows for a larger +pool of serverless readers with the appropriate cluster capacity range. Vertical +scaling at the serverless instance level is much faster compared to launching +new instances. + +## Constraints + +Some of these are discussed in more detail above, but reposting here for +clarity. + +1. Max `MaxCapacity` of 128 (256GB) +2. Min `MinCapacity` of 0.5 (1GB) (*with some exceptions) +3. Supports engine version MySQL 8+ & PostgreSQL 13+ +4. Scaling rate depends on capacity and promotion tier + +## Decision + +The major decision is whether we should update the existing +`rds.DatabaseCluster` API to take into account all these new constraints or +create an entirely new API (i.e. `rds.DatabaseClusterV2`). I am proposing that +we update the existing API since this will allow existing users to migrate. + +The changes we would need to make is to switch the `instanceProps` property from +required to optional and deprecate it. Add a new property `clusterInstances` +which would look something like: + +_updates to core_ +```ts +interface DatabaseClusterBaseProps { + ... + /** + * @deprecated - use clusterInstances instead + */ + readonly instances?: number; + /** + * @deprecated - use clusterInstances instead + */ + readonly instanceProps?: InstanceProps; + readonly clusterInstances?: ClusterInstances; +} + +interface ClusterInstances { + readonly writer: IClusterInstance; + readonly readers?: IClusterInstance[]; +} + +class ClusterInstance implements IClusterInstance { + public static provisioned(id: string, props: ProvisionedClusterInstanceProps = {}): IClusterInstance { + return new ClusterInstance(id, { + ...props, + instanceType: ClusterInstanceType.provisioned(props.instanceType), + }); + } + + public static serverlessV2(id: string, props: ServerlessV2ClusterInstanceProps = {}): IClusterInstance { + return new ClusterInstance(id, { + ...props, + instanceType: ClusterInstanceType.serverlessV2(), + }); + } + private constructor(private id: string, private readonly props: ClusterInstanceProps = {}) { } + + public bind(scope: Construct, cluster: DatabaseCluster, props: ClusterInstanceBindOptions): IAuroraClusterInstance { + // new class to represent this concept + return new AuroraClusterInstance(scope, this.id, { + cluster, + ...this.props, + ...props, + }); + } +} +``` + +_user configuration_ +```ts +new rds.DatabaseCluster(this, 'Cluster', { + engine: rds.DatabaseClusterEngine.auroraMysql({ version: rds.AuroraMysqlEngineVersion.VER_3_03_0 }), + clusterInstances: { + writer: ClusterInstance.provisioned('writer'), + readers: [ + // puts it in promition tier 0-1 + ClusterInstance.serverlessV2('reader1', { scaleWithWriter: true }), + ClusterInstance.serverlessV2('reader2'), + ClusterInstance.serverlessV2('reader3'), + ], + }, +}); +``` + +We can also provide instructions on how to migrate from `instanceProps` to +`clusterInstances` which would just entail overwriting the logicalId of the +instances. We could also add something like `ClusterInstance.fromInstanceProps(props: InstanceProps)` +that allows customers to more easily migrate their existing configuration. + +## Alternatives + +The other alternative that was considered was to create an entirely new API +(i.e. `rds.DatabaseClusterV2`). This was considered because it would allow us to +create an API that was more tailored to the new functionality. Given all the +context above, it was also originally unclear whether or not it would be possible +to update the existing API while accounting for all the nuances with Serverless +V2. + +Ultimately this was discarded because it looks like we will be able to account +for the nuances and the benefit of allowing users to continue to use the +existing API outweigh any ergonomic benefits of a completely new API. + +## Consequences + +The main consequence of this decision is maybe just some confusion on how +to use the new properties vs the old ones and changing some property validation +from linter to runtime validation (`instanceProps` was required and would show +in the IDE if not provided. Now you will get a runtime error if you don't +provide `clusterInstances` or `instanceProps`). This would essentially make the +TypeScript experience match the experience of other languages. From c85fd8960ddcbe1f96caf43260baf7a1eb775023 Mon Sep 17 00:00:00 2001 From: Cory Hall <43035978+corymhall@users.noreply.github.com> Date: Thu, 4 May 2023 10:56:23 -0400 Subject: [PATCH 02/10] Update packages/aws-cdk-lib/aws-rds/adr/aurora-serverless-v2.md Co-authored-by: Rico Hermans --- packages/aws-cdk-lib/aws-rds/adr/aurora-serverless-v2.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/aws-cdk-lib/aws-rds/adr/aurora-serverless-v2.md b/packages/aws-cdk-lib/aws-rds/adr/aurora-serverless-v2.md index 4aae4a44f57d5..2a83b8ac9875d 100644 --- a/packages/aws-cdk-lib/aws-rds/adr/aurora-serverless-v2.md +++ b/packages/aws-cdk-lib/aws-rds/adr/aurora-serverless-v2.md @@ -111,7 +111,7 @@ consistent), provisioned should be preferred for the consistent pattern. With mixed use cluster you may have writers/readers that follow different patters. For example, you may have a writer that follows the `consistent` pattern, but a reader that follows the `outliers` pattern. In this case you may want to have a -provisioned instance as the writer along with a provisioned writer in tier 0-1 +provisioned instance as the writer along with a provisioned reader in tier 0-1 (for failover) and then a serverless v2 reader in tier 2-15 (so it doesn't scale with the writer). From cd3894cd01f47310205a07bd5b4dde3e7491a4a3 Mon Sep 17 00:00:00 2001 From: Cory Hall <43035978+corymhall@users.noreply.github.com> Date: Thu, 4 May 2023 10:57:56 -0400 Subject: [PATCH 03/10] Update packages/aws-cdk-lib/aws-rds/adr/aurora-serverless-v2.md Co-authored-by: Rico Hermans --- packages/aws-cdk-lib/aws-rds/adr/aurora-serverless-v2.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/aws-cdk-lib/aws-rds/adr/aurora-serverless-v2.md b/packages/aws-cdk-lib/aws-rds/adr/aurora-serverless-v2.md index 2a83b8ac9875d..0daae3e215bb4 100644 --- a/packages/aws-cdk-lib/aws-rds/adr/aurora-serverless-v2.md +++ b/packages/aws-cdk-lib/aws-rds/adr/aurora-serverless-v2.md @@ -112,7 +112,7 @@ mixed use cluster you may have writers/readers that follow different patters. For example, you may have a writer that follows the `consistent` pattern, but a reader that follows the `outliers` pattern. In this case you may want to have a provisioned instance as the writer along with a provisioned reader in tier 0-1 -(for failover) and then a serverless v2 reader in tier 2-15 (so it doesn't scale with the +(for failover) and then a serverless v2 reader in tier 2-15 (so it scales with the spotty reader) writer). If you are currently using auto scaling with provisioned instances, you should From f95067a4ccb9daa7897ac9ba1f32f407ffa243a4 Mon Sep 17 00:00:00 2001 From: corymhall <43035978+corymhall@users.noreply.github.com> Date: Thu, 4 May 2023 15:52:05 +0000 Subject: [PATCH 04/10] updating based on comments --- .../aws-rds/adr/aurora-serverless-v2.md | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/packages/aws-cdk-lib/aws-rds/adr/aurora-serverless-v2.md b/packages/aws-cdk-lib/aws-rds/adr/aurora-serverless-v2.md index 0daae3e215bb4..a73e3ab0e5a56 100644 --- a/packages/aws-cdk-lib/aws-rds/adr/aurora-serverless-v2.md +++ b/packages/aws-cdk-lib/aws-rds/adr/aurora-serverless-v2.md @@ -119,7 +119,11 @@ If you are currently using auto scaling with provisioned instances, you should instead switch to instance scaling with serverless v2. This allows for a larger pool of serverless readers with the appropriate cluster capacity range. Vertical scaling at the serverless instance level is much faster compared to launching -new instances. +new instances. For example, using the case above, using a single `db.r6g.4xlarge` +reader instance with auto scaling configured would add new `db.r6g.4xlarge` instances +when the cluster auto scaled. Alternatively you could provision a couple serverless reader instances +with min=6.5/max=64. These serverless instances would scale up faster (with the read load split between them) +than adding new provisioned instances. ## Constraints @@ -189,18 +193,22 @@ class ClusterInstance implements IClusterInstance { } ``` -_user configuration_ +_user configuration_ (properties are not shown to focus on the API) ```ts new rds.DatabaseCluster(this, 'Cluster', { engine: rds.DatabaseClusterEngine.auroraMysql({ version: rds.AuroraMysqlEngineVersion.VER_3_03_0 }), - clusterInstances: { - writer: ClusterInstance.provisioned('writer'), - readers: [ - // puts it in promition tier 0-1 - ClusterInstance.serverlessV2('reader1', { scaleWithWriter: true }), - ClusterInstance.serverlessV2('reader2'), - ClusterInstance.serverlessV2('reader3'), - ], + // capacity applies to all serverless instances in the cluster + serverlessV2Capacity: 1, + serverlessV2MinCapacity: 0.5, + writer: ClusterInstance.provisioned('writer', { ...props }), + readers: [ + // puts it in promition tier 0-1 + ClusterInstance.serverlessV2('reader1', { scaleWithWriter: true, ...additionalProps }), + ClusterInstance.serverlessV2('reader2'), + ClusterInstance.serverlessV2('reader3'), + // illustrating how it might be possible to add support for groups in the future. + // currently not supported by CFN + ClusterInstance.fromReaderGroup('analytics', { ...readerProps }), }, }); ``` From ae00864ef6b155b9328ad9357dfd3a7b8c7b70a5 Mon Sep 17 00:00:00 2001 From: corymhall <43035978+corymhall@users.noreply.github.com> Date: Wed, 24 May 2023 18:57:15 +0000 Subject: [PATCH 05/10] started working on it --- .../cdk.out | 1 + ...eg-aurora-serverlessv2-cluster.assets.json | 19 + ...-aurora-serverlessv2-cluster.template.json | 910 ++++++++++ .../integ.json | 12 + ...efaultTestDeployAssert24D5C536.assets.json | 19 + ...aultTestDeployAssert24D5C536.template.json | 36 + .../manifest.json | 381 ++++ .../tree.json | 1607 +++++++++++++++++ .../test/integ.cluster-serverless-v2.ts | 64 + packages/aws-cdk-lib/aws-rds/README.md | 193 +- .../aws-rds/adr/aurora-serverless-v2.md | 2 +- .../aws-rds/lib/aurora-cluster-instance.ts | 444 +++++ packages/aws-cdk-lib/aws-rds/lib/cluster.ts | 380 +++- packages/aws-cdk-lib/aws-rds/lib/index.ts | 1 + .../aws-cdk-lib/aws-rds/test/cluster.test.ts | 719 +++++++- 15 files changed, 4741 insertions(+), 47 deletions(-) create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/cdk.out create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integ-aurora-serverlessv2-cluster.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integ-aurora-serverlessv2-cluster.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integ.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integtestDefaultTestDeployAssert24D5C536.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integtestDefaultTestDeployAssert24D5C536.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/manifest.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/tree.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.ts create mode 100644 packages/aws-cdk-lib/aws-rds/lib/aurora-cluster-instance.ts diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/cdk.out new file mode 100644 index 0000000000000..7925065efbcc4 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"31.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integ-aurora-serverlessv2-cluster.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integ-aurora-serverlessv2-cluster.assets.json new file mode 100644 index 0000000000000..b6d5020a23dee --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integ-aurora-serverlessv2-cluster.assets.json @@ -0,0 +1,19 @@ +{ + "version": "31.0.0", + "files": { + "c124cab7d8a98cc66aa81986e6076d47dbd4c4b9622119636b7974340cc71ca4": { + "source": { + "path": "integ-aurora-serverlessv2-cluster.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "c124cab7d8a98cc66aa81986e6076d47dbd4c4b9622119636b7974340cc71ca4.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integ-aurora-serverlessv2-cluster.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integ-aurora-serverlessv2-cluster.template.json new file mode 100644 index 0000000000000..0535c32a713ec --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integ-aurora-serverlessv2-cluster.template.json @@ -0,0 +1,910 @@ +{ + "Resources": { + "IntegVPC2FF1AB0E": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "integ-aurora-serverlessv2-cluster/Integ-VPC" + } + ] + } + }, + "IntegVPCPublicSubnet1SubnetE05F7E7D": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "VpcId": { + "Ref": "IntegVPC2FF1AB0E" + }, + "AvailabilityZone": { + "Fn::Select": [ + 0, + { + "Fn::GetAZs": "" + } + ] + }, + "CidrBlock": "10.0.0.0/18", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet1" + } + ] + } + }, + "IntegVPCPublicSubnet1RouteTable622895C7": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "IntegVPC2FF1AB0E" + }, + "Tags": [ + { + "Key": "Name", + "Value": "integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet1" + } + ] + } + }, + "IntegVPCPublicSubnet1RouteTableAssociation0E84800B": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "IntegVPCPublicSubnet1RouteTable622895C7" + }, + "SubnetId": { + "Ref": "IntegVPCPublicSubnet1SubnetE05F7E7D" + } + } + }, + "IntegVPCPublicSubnet1DefaultRouteE885D95E": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "IntegVPCPublicSubnet1RouteTable622895C7" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "IntegVPCIGW02FC78B6" + } + }, + "DependsOn": [ + "IntegVPCVPCGW4DD476C7" + ] + }, + "IntegVPCPublicSubnet1EIP1AC057E9": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet1" + } + ] + } + }, + "IntegVPCPublicSubnet1NATGateway380AC0A0": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "SubnetId": { + "Ref": "IntegVPCPublicSubnet1SubnetE05F7E7D" + }, + "AllocationId": { + "Fn::GetAtt": [ + "IntegVPCPublicSubnet1EIP1AC057E9", + "AllocationId" + ] + }, + "Tags": [ + { + "Key": "Name", + "Value": "integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet1" + } + ] + }, + "DependsOn": [ + "IntegVPCPublicSubnet1DefaultRouteE885D95E", + "IntegVPCPublicSubnet1RouteTableAssociation0E84800B" + ] + }, + "IntegVPCPublicSubnet2Subnet9648DE97": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "VpcId": { + "Ref": "IntegVPC2FF1AB0E" + }, + "AvailabilityZone": { + "Fn::Select": [ + 1, + { + "Fn::GetAZs": "" + } + ] + }, + "CidrBlock": "10.0.64.0/18", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet2" + } + ] + } + }, + "IntegVPCPublicSubnet2RouteTableB79B3910": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "IntegVPC2FF1AB0E" + }, + "Tags": [ + { + "Key": "Name", + "Value": "integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet2" + } + ] + } + }, + "IntegVPCPublicSubnet2RouteTableAssociation831EA0CC": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "IntegVPCPublicSubnet2RouteTableB79B3910" + }, + "SubnetId": { + "Ref": "IntegVPCPublicSubnet2Subnet9648DE97" + } + } + }, + "IntegVPCPublicSubnet2DefaultRoute2FC4B163": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "IntegVPCPublicSubnet2RouteTableB79B3910" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "IntegVPCIGW02FC78B6" + } + }, + "DependsOn": [ + "IntegVPCVPCGW4DD476C7" + ] + }, + "IntegVPCPublicSubnet2EIPEA07DF99": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet2" + } + ] + } + }, + "IntegVPCPublicSubnet2NATGateway912800A3": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "SubnetId": { + "Ref": "IntegVPCPublicSubnet2Subnet9648DE97" + }, + "AllocationId": { + "Fn::GetAtt": [ + "IntegVPCPublicSubnet2EIPEA07DF99", + "AllocationId" + ] + }, + "Tags": [ + { + "Key": "Name", + "Value": "integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet2" + } + ] + }, + "DependsOn": [ + "IntegVPCPublicSubnet2DefaultRoute2FC4B163", + "IntegVPCPublicSubnet2RouteTableAssociation831EA0CC" + ] + }, + "IntegVPCPrivateSubnet1SubnetD5B61223": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "VpcId": { + "Ref": "IntegVPC2FF1AB0E" + }, + "AvailabilityZone": { + "Fn::Select": [ + 0, + { + "Fn::GetAZs": "" + } + ] + }, + "CidrBlock": "10.0.128.0/18", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "integ-aurora-serverlessv2-cluster/Integ-VPC/PrivateSubnet1" + } + ] + } + }, + "IntegVPCPrivateSubnet1RouteTableF2678D77": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "IntegVPC2FF1AB0E" + }, + "Tags": [ + { + "Key": "Name", + "Value": "integ-aurora-serverlessv2-cluster/Integ-VPC/PrivateSubnet1" + } + ] + } + }, + "IntegVPCPrivateSubnet1RouteTableAssociationAD4B0EBF": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "IntegVPCPrivateSubnet1RouteTableF2678D77" + }, + "SubnetId": { + "Ref": "IntegVPCPrivateSubnet1SubnetD5B61223" + } + } + }, + "IntegVPCPrivateSubnet1DefaultRoute140D7A84": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "IntegVPCPrivateSubnet1RouteTableF2678D77" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "IntegVPCPublicSubnet1NATGateway380AC0A0" + } + } + }, + "IntegVPCPrivateSubnet2SubnetFCC4EF23": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "VpcId": { + "Ref": "IntegVPC2FF1AB0E" + }, + "AvailabilityZone": { + "Fn::Select": [ + 1, + { + "Fn::GetAZs": "" + } + ] + }, + "CidrBlock": "10.0.192.0/18", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "integ-aurora-serverlessv2-cluster/Integ-VPC/PrivateSubnet2" + } + ] + } + }, + "IntegVPCPrivateSubnet2RouteTable4132D373": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "IntegVPC2FF1AB0E" + }, + "Tags": [ + { + "Key": "Name", + "Value": "integ-aurora-serverlessv2-cluster/Integ-VPC/PrivateSubnet2" + } + ] + } + }, + "IntegVPCPrivateSubnet2RouteTableAssociation9A15DAD6": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "IntegVPCPrivateSubnet2RouteTable4132D373" + }, + "SubnetId": { + "Ref": "IntegVPCPrivateSubnet2SubnetFCC4EF23" + } + } + }, + "IntegVPCPrivateSubnet2DefaultRouteAE44E307": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "IntegVPCPrivateSubnet2RouteTable4132D373" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "IntegVPCPublicSubnet2NATGateway912800A3" + } + } + }, + "IntegVPCIGW02FC78B6": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "integ-aurora-serverlessv2-cluster/Integ-VPC" + } + ] + } + }, + "IntegVPCVPCGW4DD476C7": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "IntegVPC2FF1AB0E" + }, + "InternetGatewayId": { + "Ref": "IntegVPCIGW02FC78B6" + } + } + }, + "integauroraserverlessv20IntegClusterSubnets2462DA9D": { + "Type": "AWS::RDS::DBSubnetGroup", + "Properties": { + "DBSubnetGroupDescription": "Subnets for Integ-Cluster database", + "SubnetIds": [ + { + "Ref": "IntegVPCPrivateSubnet1SubnetD5B61223" + }, + { + "Ref": "IntegVPCPrivateSubnet2SubnetFCC4EF23" + } + ] + } + }, + "integauroraserverlessv20IntegClusterSecurityGroup0FF1F93F": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "RDS security group", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "IntegVPC2FF1AB0E" + } + } + }, + "integauroraserverlessv20IntegClusterSecretB9E432EB": { + "Type": "AWS::SecretsManager::Secret", + "Properties": { + "Description": { + "Fn::Join": [ + "", + [ + "Generated by the CDK for stack: ", + { + "Ref": "AWS::StackName" + } + ] + ] + }, + "GenerateSecretString": { + "ExcludeCharacters": " %+~`#$&*()|[]{}:;<>?!'/@\"\\", + "GenerateStringKey": "password", + "PasswordLength": 30, + "SecretStringTemplate": "{\"username\":\"admin\"}" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "integauroraserverlessv20IntegClusterSecretAttachmentABF2342B": { + "Type": "AWS::SecretsManager::SecretTargetAttachment", + "Properties": { + "SecretId": { + "Ref": "integauroraserverlessv20IntegClusterSecretB9E432EB" + }, + "TargetId": { + "Ref": "integauroraserverlessv20IntegCluster5133790E" + }, + "TargetType": "AWS::RDS::DBCluster" + } + }, + "integauroraserverlessv20IntegCluster5133790E": { + "Type": "AWS::RDS::DBCluster", + "Properties": { + "CopyTagsToSnapshot": true, + "DBClusterParameterGroupName": "default.aurora-mysql8.0", + "DBSubnetGroupName": { + "Ref": "integauroraserverlessv20IntegClusterSubnets2462DA9D" + }, + "Engine": "aurora-mysql", + "EngineVersion": "8.0.mysql_aurora.3.03.0", + "MasterUsername": { + "Fn::Join": [ + "", + [ + "{{resolve:secretsmanager:", + { + "Ref": "integauroraserverlessv20IntegClusterSecretB9E432EB" + }, + ":SecretString:username::}}" + ] + ] + }, + "MasterUserPassword": { + "Fn::Join": [ + "", + [ + "{{resolve:secretsmanager:", + { + "Ref": "integauroraserverlessv20IntegClusterSecretB9E432EB" + }, + ":SecretString:password::}}" + ] + ] + }, + "ServerlessV2ScalingConfiguration": { + "MaxCapacity": 2, + "MinCapacity": 0.5 + }, + "VpcSecurityGroupIds": [ + { + "Fn::GetAtt": [ + "integauroraserverlessv20IntegClusterSecurityGroup0FF1F93F", + "GroupId" + ] + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "integauroraserverlessv20IntegClusterwriter68858AE9": { + "Type": "AWS::RDS::DBInstance", + "Properties": { + "DBClusterIdentifier": { + "Ref": "integauroraserverlessv20IntegCluster5133790E" + }, + "DBInstanceClass": "db.serverless", + "Engine": "aurora-mysql", + "PromotionTier": 0 + }, + "DependsOn": [ + "IntegVPCPrivateSubnet1DefaultRoute140D7A84", + "IntegVPCPrivateSubnet1RouteTableAssociationAD4B0EBF", + "IntegVPCPrivateSubnet2DefaultRouteAE44E307", + "IntegVPCPrivateSubnet2RouteTableAssociation9A15DAD6" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "integauroraserverlessv21IntegClusterSubnetsAEE71920": { + "Type": "AWS::RDS::DBSubnetGroup", + "Properties": { + "DBSubnetGroupDescription": "Subnets for Integ-Cluster database", + "SubnetIds": [ + { + "Ref": "IntegVPCPrivateSubnet1SubnetD5B61223" + }, + { + "Ref": "IntegVPCPrivateSubnet2SubnetFCC4EF23" + } + ] + } + }, + "integauroraserverlessv21IntegClusterSecurityGroup483E60E7": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "RDS security group", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "IntegVPC2FF1AB0E" + } + } + }, + "integauroraserverlessv21IntegClusterSecretA8DA28CB": { + "Type": "AWS::SecretsManager::Secret", + "Properties": { + "Description": { + "Fn::Join": [ + "", + [ + "Generated by the CDK for stack: ", + { + "Ref": "AWS::StackName" + } + ] + ] + }, + "GenerateSecretString": { + "ExcludeCharacters": " %+~`#$&*()|[]{}:;<>?!'/@\"\\", + "GenerateStringKey": "password", + "PasswordLength": 30, + "SecretStringTemplate": "{\"username\":\"admin\"}" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "integauroraserverlessv21IntegClusterSecretAttachmentB7E69BEA": { + "Type": "AWS::SecretsManager::SecretTargetAttachment", + "Properties": { + "SecretId": { + "Ref": "integauroraserverlessv21IntegClusterSecretA8DA28CB" + }, + "TargetId": { + "Ref": "integauroraserverlessv21IntegClusterDFF12F00" + }, + "TargetType": "AWS::RDS::DBCluster" + } + }, + "integauroraserverlessv21IntegClusterDFF12F00": { + "Type": "AWS::RDS::DBCluster", + "Properties": { + "CopyTagsToSnapshot": true, + "DBClusterParameterGroupName": "default.aurora-mysql8.0", + "DBSubnetGroupName": { + "Ref": "integauroraserverlessv21IntegClusterSubnetsAEE71920" + }, + "Engine": "aurora-mysql", + "EngineVersion": "8.0.mysql_aurora.3.03.0", + "MasterUsername": { + "Fn::Join": [ + "", + [ + "{{resolve:secretsmanager:", + { + "Ref": "integauroraserverlessv21IntegClusterSecretA8DA28CB" + }, + ":SecretString:username::}}" + ] + ] + }, + "MasterUserPassword": { + "Fn::Join": [ + "", + [ + "{{resolve:secretsmanager:", + { + "Ref": "integauroraserverlessv21IntegClusterSecretA8DA28CB" + }, + ":SecretString:password::}}" + ] + ] + }, + "ServerlessV2ScalingConfiguration": { + "MaxCapacity": 2, + "MinCapacity": 0.5 + }, + "VpcSecurityGroupIds": [ + { + "Fn::GetAtt": [ + "integauroraserverlessv21IntegClusterSecurityGroup483E60E7", + "GroupId" + ] + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "integauroraserverlessv21IntegClusterwriterD87D3A20": { + "Type": "AWS::RDS::DBInstance", + "Properties": { + "DBClusterIdentifier": { + "Ref": "integauroraserverlessv21IntegClusterDFF12F00" + }, + "DBInstanceClass": "db.t3.medium", + "Engine": "aurora-mysql", + "PromotionTier": 0 + }, + "DependsOn": [ + "IntegVPCPrivateSubnet1DefaultRoute140D7A84", + "IntegVPCPrivateSubnet1RouteTableAssociationAD4B0EBF", + "IntegVPCPrivateSubnet2DefaultRouteAE44E307", + "IntegVPCPrivateSubnet2RouteTableAssociation9A15DAD6" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "integauroraserverlessv21IntegClusterFailoverReader595E72DE": { + "Type": "AWS::RDS::DBInstance", + "Properties": { + "DBClusterIdentifier": { + "Ref": "integauroraserverlessv21IntegClusterDFF12F00" + }, + "DBInstanceClass": "db.serverless", + "Engine": "aurora-mysql", + "PromotionTier": 1 + }, + "DependsOn": [ + "IntegVPCPrivateSubnet1DefaultRoute140D7A84", + "IntegVPCPrivateSubnet1RouteTableAssociationAD4B0EBF", + "IntegVPCPrivateSubnet2DefaultRouteAE44E307", + "IntegVPCPrivateSubnet2RouteTableAssociation9A15DAD6" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "integauroraserverlessv21IntegClusterOtherReaderBC649D9A": { + "Type": "AWS::RDS::DBInstance", + "Properties": { + "DBClusterIdentifier": { + "Ref": "integauroraserverlessv21IntegClusterDFF12F00" + }, + "DBInstanceClass": "db.serverless", + "Engine": "aurora-mysql", + "PromotionTier": 2 + }, + "DependsOn": [ + "IntegVPCPrivateSubnet1DefaultRoute140D7A84", + "IntegVPCPrivateSubnet1RouteTableAssociationAD4B0EBF", + "IntegVPCPrivateSubnet2DefaultRouteAE44E307", + "IntegVPCPrivateSubnet2RouteTableAssociation9A15DAD6" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "integauroraserverlessv22IntegClusterSubnets241DB50C": { + "Type": "AWS::RDS::DBSubnetGroup", + "Properties": { + "DBSubnetGroupDescription": "Subnets for Integ-Cluster database", + "SubnetIds": [ + { + "Ref": "IntegVPCPrivateSubnet1SubnetD5B61223" + }, + { + "Ref": "IntegVPCPrivateSubnet2SubnetFCC4EF23" + } + ] + } + }, + "integauroraserverlessv22IntegClusterSecurityGroup0EDBBE37": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "RDS security group", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "IntegVPC2FF1AB0E" + } + } + }, + "integauroraserverlessv22IntegClusterSecretBF74DBA3": { + "Type": "AWS::SecretsManager::Secret", + "Properties": { + "Description": { + "Fn::Join": [ + "", + [ + "Generated by the CDK for stack: ", + { + "Ref": "AWS::StackName" + } + ] + ] + }, + "GenerateSecretString": { + "ExcludeCharacters": " %+~`#$&*()|[]{}:;<>?!'/@\"\\", + "GenerateStringKey": "password", + "PasswordLength": 30, + "SecretStringTemplate": "{\"username\":\"admin\"}" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "integauroraserverlessv22IntegClusterSecretAttachment4864E40A": { + "Type": "AWS::SecretsManager::SecretTargetAttachment", + "Properties": { + "SecretId": { + "Ref": "integauroraserverlessv22IntegClusterSecretBF74DBA3" + }, + "TargetId": { + "Ref": "integauroraserverlessv22IntegCluster1F86F0C6" + }, + "TargetType": "AWS::RDS::DBCluster" + } + }, + "integauroraserverlessv22IntegCluster1F86F0C6": { + "Type": "AWS::RDS::DBCluster", + "Properties": { + "CopyTagsToSnapshot": true, + "DBClusterParameterGroupName": "default.aurora-mysql8.0", + "DBSubnetGroupName": { + "Ref": "integauroraserverlessv22IntegClusterSubnets241DB50C" + }, + "Engine": "aurora-mysql", + "EngineVersion": "8.0.mysql_aurora.3.03.0", + "MasterUsername": { + "Fn::Join": [ + "", + [ + "{{resolve:secretsmanager:", + { + "Ref": "integauroraserverlessv22IntegClusterSecretBF74DBA3" + }, + ":SecretString:username::}}" + ] + ] + }, + "MasterUserPassword": { + "Fn::Join": [ + "", + [ + "{{resolve:secretsmanager:", + { + "Ref": "integauroraserverlessv22IntegClusterSecretBF74DBA3" + }, + ":SecretString:password::}}" + ] + ] + }, + "ServerlessV2ScalingConfiguration": { + "MaxCapacity": 2, + "MinCapacity": 0.5 + }, + "VpcSecurityGroupIds": [ + { + "Fn::GetAtt": [ + "integauroraserverlessv22IntegClusterSecurityGroup0EDBBE37", + "GroupId" + ] + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "integauroraserverlessv22IntegClusterwriter4C20F6E7": { + "Type": "AWS::RDS::DBInstance", + "Properties": { + "DBClusterIdentifier": { + "Ref": "integauroraserverlessv22IntegCluster1F86F0C6" + }, + "DBInstanceClass": "db.serverless", + "Engine": "aurora-mysql", + "PromotionTier": 0 + }, + "DependsOn": [ + "IntegVPCPrivateSubnet1DefaultRoute140D7A84", + "IntegVPCPrivateSubnet1RouteTableAssociationAD4B0EBF", + "IntegVPCPrivateSubnet2DefaultRouteAE44E307", + "IntegVPCPrivateSubnet2RouteTableAssociation9A15DAD6" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "integauroraserverlessv22IntegClusterFailoverReaderBB40FCA6": { + "Type": "AWS::RDS::DBInstance", + "Properties": { + "DBClusterIdentifier": { + "Ref": "integauroraserverlessv22IntegCluster1F86F0C6" + }, + "DBInstanceClass": "db.t3.medium", + "Engine": "aurora-mysql", + "PromotionTier": 1 + }, + "DependsOn": [ + "IntegVPCPrivateSubnet1DefaultRoute140D7A84", + "IntegVPCPrivateSubnet1RouteTableAssociationAD4B0EBF", + "IntegVPCPrivateSubnet2DefaultRouteAE44E307", + "IntegVPCPrivateSubnet2RouteTableAssociation9A15DAD6" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "integauroraserverlessv22IntegClusterOtherReader63C2651D": { + "Type": "AWS::RDS::DBInstance", + "Properties": { + "DBClusterIdentifier": { + "Ref": "integauroraserverlessv22IntegCluster1F86F0C6" + }, + "DBInstanceClass": "db.serverless", + "Engine": "aurora-mysql", + "PromotionTier": 2 + }, + "DependsOn": [ + "IntegVPCPrivateSubnet1DefaultRoute140D7A84", + "IntegVPCPrivateSubnet1RouteTableAssociationAD4B0EBF", + "IntegVPCPrivateSubnet2DefaultRouteAE44E307", + "IntegVPCPrivateSubnet2RouteTableAssociation9A15DAD6" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integ.json new file mode 100644 index 0000000000000..cd2240681ff26 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "31.0.0", + "testCases": { + "integ-test/DefaultTest": { + "stacks": [ + "integ-aurora-serverlessv2-cluster" + ], + "assertionStack": "integ-test/DefaultTest/DeployAssert", + "assertionStackName": "integtestDefaultTestDeployAssert24D5C536" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integtestDefaultTestDeployAssert24D5C536.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integtestDefaultTestDeployAssert24D5C536.assets.json new file mode 100644 index 0000000000000..ecd9f6bd2a455 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integtestDefaultTestDeployAssert24D5C536.assets.json @@ -0,0 +1,19 @@ +{ + "version": "31.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "integtestDefaultTestDeployAssert24D5C536.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integtestDefaultTestDeployAssert24D5C536.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integtestDefaultTestDeployAssert24D5C536.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integtestDefaultTestDeployAssert24D5C536.template.json @@ -0,0 +1,36 @@ +{ + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/manifest.json new file mode 100644 index 0000000000000..5e4f9e538bb7d --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/manifest.json @@ -0,0 +1,381 @@ +{ + "version": "31.0.0", + "artifacts": { + "integ-aurora-serverlessv2-cluster.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "integ-aurora-serverlessv2-cluster.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "integ-aurora-serverlessv2-cluster": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "integ-aurora-serverlessv2-cluster.template.json", + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/c124cab7d8a98cc66aa81986e6076d47dbd4c4b9622119636b7974340cc71ca4.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "integ-aurora-serverlessv2-cluster.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "integ-aurora-serverlessv2-cluster.assets" + ], + "metadata": { + "/integ-aurora-serverlessv2-cluster/Integ-VPC/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "IntegVPC2FF1AB0E" + } + ], + "/integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet1/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "IntegVPCPublicSubnet1SubnetE05F7E7D" + } + ], + "/integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet1/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "IntegVPCPublicSubnet1RouteTable622895C7" + } + ], + "/integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet1/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "IntegVPCPublicSubnet1RouteTableAssociation0E84800B" + } + ], + "/integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet1/DefaultRoute": [ + { + "type": "aws:cdk:logicalId", + "data": "IntegVPCPublicSubnet1DefaultRouteE885D95E" + } + ], + "/integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet1/EIP": [ + { + "type": "aws:cdk:logicalId", + "data": "IntegVPCPublicSubnet1EIP1AC057E9" + } + ], + "/integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet1/NATGateway": [ + { + "type": "aws:cdk:logicalId", + "data": "IntegVPCPublicSubnet1NATGateway380AC0A0" + } + ], + "/integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet2/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "IntegVPCPublicSubnet2Subnet9648DE97" + } + ], + "/integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet2/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "IntegVPCPublicSubnet2RouteTableB79B3910" + } + ], + "/integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet2/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "IntegVPCPublicSubnet2RouteTableAssociation831EA0CC" + } + ], + "/integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet2/DefaultRoute": [ + { + "type": "aws:cdk:logicalId", + "data": "IntegVPCPublicSubnet2DefaultRoute2FC4B163" + } + ], + "/integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet2/EIP": [ + { + "type": "aws:cdk:logicalId", + "data": "IntegVPCPublicSubnet2EIPEA07DF99" + } + ], + "/integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet2/NATGateway": [ + { + "type": "aws:cdk:logicalId", + "data": "IntegVPCPublicSubnet2NATGateway912800A3" + } + ], + "/integ-aurora-serverlessv2-cluster/Integ-VPC/PrivateSubnet1/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "IntegVPCPrivateSubnet1SubnetD5B61223" + } + ], + "/integ-aurora-serverlessv2-cluster/Integ-VPC/PrivateSubnet1/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "IntegVPCPrivateSubnet1RouteTableF2678D77" + } + ], + "/integ-aurora-serverlessv2-cluster/Integ-VPC/PrivateSubnet1/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "IntegVPCPrivateSubnet1RouteTableAssociationAD4B0EBF" + } + ], + "/integ-aurora-serverlessv2-cluster/Integ-VPC/PrivateSubnet1/DefaultRoute": [ + { + "type": "aws:cdk:logicalId", + "data": "IntegVPCPrivateSubnet1DefaultRoute140D7A84" + } + ], + "/integ-aurora-serverlessv2-cluster/Integ-VPC/PrivateSubnet2/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "IntegVPCPrivateSubnet2SubnetFCC4EF23" + } + ], + "/integ-aurora-serverlessv2-cluster/Integ-VPC/PrivateSubnet2/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "IntegVPCPrivateSubnet2RouteTable4132D373" + } + ], + "/integ-aurora-serverlessv2-cluster/Integ-VPC/PrivateSubnet2/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "IntegVPCPrivateSubnet2RouteTableAssociation9A15DAD6" + } + ], + "/integ-aurora-serverlessv2-cluster/Integ-VPC/PrivateSubnet2/DefaultRoute": [ + { + "type": "aws:cdk:logicalId", + "data": "IntegVPCPrivateSubnet2DefaultRouteAE44E307" + } + ], + "/integ-aurora-serverlessv2-cluster/Integ-VPC/IGW": [ + { + "type": "aws:cdk:logicalId", + "data": "IntegVPCIGW02FC78B6" + } + ], + "/integ-aurora-serverlessv2-cluster/Integ-VPC/VPCGW": [ + { + "type": "aws:cdk:logicalId", + "data": "IntegVPCVPCGW4DD476C7" + } + ], + "/integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-0/Integ-Cluster/Subnets/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "integauroraserverlessv20IntegClusterSubnets2462DA9D" + } + ], + "/integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-0/Integ-Cluster/SecurityGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "integauroraserverlessv20IntegClusterSecurityGroup0FF1F93F" + } + ], + "/integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-0/Integ-Cluster/Secret/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "integauroraserverlessv20IntegClusterSecretB9E432EB" + } + ], + "/integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-0/Integ-Cluster/Secret/Attachment/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "integauroraserverlessv20IntegClusterSecretAttachmentABF2342B" + } + ], + "/integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-0/Integ-Cluster/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "integauroraserverlessv20IntegCluster5133790E" + } + ], + "/integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-0/Integ-Cluster/writer/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "integauroraserverlessv20IntegClusterwriter68858AE9" + } + ], + "/integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-1/Integ-Cluster/Subnets/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "integauroraserverlessv21IntegClusterSubnetsAEE71920" + } + ], + "/integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-1/Integ-Cluster/SecurityGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "integauroraserverlessv21IntegClusterSecurityGroup483E60E7" + } + ], + "/integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-1/Integ-Cluster/Secret/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "integauroraserverlessv21IntegClusterSecretA8DA28CB" + } + ], + "/integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-1/Integ-Cluster/Secret/Attachment/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "integauroraserverlessv21IntegClusterSecretAttachmentB7E69BEA" + } + ], + "/integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-1/Integ-Cluster/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "integauroraserverlessv21IntegClusterDFF12F00" + } + ], + "/integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-1/Integ-Cluster/writer/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "integauroraserverlessv21IntegClusterwriterD87D3A20" + } + ], + "/integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-1/Integ-Cluster/FailoverReader/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "integauroraserverlessv21IntegClusterFailoverReader595E72DE" + } + ], + "/integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-1/Integ-Cluster/OtherReader/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "integauroraserverlessv21IntegClusterOtherReaderBC649D9A" + } + ], + "/integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-2/Integ-Cluster": [ + { + "type": "aws:cdk:info", + "data": "..." + } + ], + "/integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-2/Integ-Cluster/Subnets/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "integauroraserverlessv22IntegClusterSubnets241DB50C" + } + ], + "/integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-2/Integ-Cluster/SecurityGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "integauroraserverlessv22IntegClusterSecurityGroup0EDBBE37" + } + ], + "/integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-2/Integ-Cluster/Secret/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "integauroraserverlessv22IntegClusterSecretBF74DBA3" + } + ], + "/integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-2/Integ-Cluster/Secret/Attachment/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "integauroraserverlessv22IntegClusterSecretAttachment4864E40A" + } + ], + "/integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-2/Integ-Cluster/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "integauroraserverlessv22IntegCluster1F86F0C6" + } + ], + "/integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-2/Integ-Cluster/writer/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "integauroraserverlessv22IntegClusterwriter4C20F6E7" + } + ], + "/integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-2/Integ-Cluster/FailoverReader/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "integauroraserverlessv22IntegClusterFailoverReaderBB40FCA6" + } + ], + "/integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-2/Integ-Cluster/OtherReader/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "integauroraserverlessv22IntegClusterOtherReader63C2651D" + } + ], + "/integ-aurora-serverlessv2-cluster/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/integ-aurora-serverlessv2-cluster/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "integ-aurora-serverlessv2-cluster" + }, + "integtestDefaultTestDeployAssert24D5C536.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "integtestDefaultTestDeployAssert24D5C536.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "integtestDefaultTestDeployAssert24D5C536": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "integtestDefaultTestDeployAssert24D5C536.template.json", + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "integtestDefaultTestDeployAssert24D5C536.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "integtestDefaultTestDeployAssert24D5C536.assets" + ], + "metadata": { + "/integ-test/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/integ-test/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "integ-test/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/tree.json new file mode 100644 index 0000000000000..e43bc7077cfc0 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/tree.json @@ -0,0 +1,1607 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "integ-aurora-serverlessv2-cluster": { + "id": "integ-aurora-serverlessv2-cluster", + "path": "integ-aurora-serverlessv2-cluster", + "children": { + "Integ-VPC": { + "id": "Integ-VPC", + "path": "integ-aurora-serverlessv2-cluster/Integ-VPC", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::VPC", + "aws:cdk:cloudformation:props": { + "cidrBlock": "10.0.0.0/16", + "enableDnsHostnames": true, + "enableDnsSupport": true, + "instanceTenancy": "default", + "tags": [ + { + "key": "Name", + "value": "integ-aurora-serverlessv2-cluster/Integ-VPC" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnVPC", + "version": "0.0.0" + } + }, + "PublicSubnet1": { + "id": "PublicSubnet1", + "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet1", + "children": { + "Subnet": { + "id": "Subnet", + "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet1/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "IntegVPC2FF1AB0E" + }, + "availabilityZone": { + "Fn::Select": [ + 0, + { + "Fn::GetAZs": "" + } + ] + }, + "cidrBlock": "10.0.0.0/18", + "mapPublicIpOnLaunch": true, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "Public" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Public" + }, + { + "key": "Name", + "value": "integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet1" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", + "version": "0.0.0" + } + }, + "Acl": { + "id": "Acl", + "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet1/Acl", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet1/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "IntegVPC2FF1AB0E" + }, + "tags": [ + { + "key": "Name", + "value": "integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet1" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", + "version": "0.0.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet1/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "IntegVPCPublicSubnet1RouteTable622895C7" + }, + "subnetId": { + "Ref": "IntegVPCPublicSubnet1SubnetE05F7E7D" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", + "version": "0.0.0" + } + }, + "DefaultRoute": { + "id": "DefaultRoute", + "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet1/DefaultRoute", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Route", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "IntegVPCPublicSubnet1RouteTable622895C7" + }, + "destinationCidrBlock": "0.0.0.0/0", + "gatewayId": { + "Ref": "IntegVPCIGW02FC78B6" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", + "version": "0.0.0" + } + }, + "EIP": { + "id": "EIP", + "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet1/EIP", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::EIP", + "aws:cdk:cloudformation:props": { + "domain": "vpc", + "tags": [ + { + "key": "Name", + "value": "integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet1" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnEIP", + "version": "0.0.0" + } + }, + "NATGateway": { + "id": "NATGateway", + "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet1/NATGateway", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", + "aws:cdk:cloudformation:props": { + "subnetId": { + "Ref": "IntegVPCPublicSubnet1SubnetE05F7E7D" + }, + "allocationId": { + "Fn::GetAtt": [ + "IntegVPCPublicSubnet1EIP1AC057E9", + "AllocationId" + ] + }, + "tags": [ + { + "key": "Name", + "value": "integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet1" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnNatGateway", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "PublicSubnet2": { + "id": "PublicSubnet2", + "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet2", + "children": { + "Subnet": { + "id": "Subnet", + "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet2/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "IntegVPC2FF1AB0E" + }, + "availabilityZone": { + "Fn::Select": [ + 1, + { + "Fn::GetAZs": "" + } + ] + }, + "cidrBlock": "10.0.64.0/18", + "mapPublicIpOnLaunch": true, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "Public" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Public" + }, + { + "key": "Name", + "value": "integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet2" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", + "version": "0.0.0" + } + }, + "Acl": { + "id": "Acl", + "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet2/Acl", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet2/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "IntegVPC2FF1AB0E" + }, + "tags": [ + { + "key": "Name", + "value": "integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet2" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", + "version": "0.0.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet2/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "IntegVPCPublicSubnet2RouteTableB79B3910" + }, + "subnetId": { + "Ref": "IntegVPCPublicSubnet2Subnet9648DE97" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", + "version": "0.0.0" + } + }, + "DefaultRoute": { + "id": "DefaultRoute", + "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet2/DefaultRoute", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Route", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "IntegVPCPublicSubnet2RouteTableB79B3910" + }, + "destinationCidrBlock": "0.0.0.0/0", + "gatewayId": { + "Ref": "IntegVPCIGW02FC78B6" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", + "version": "0.0.0" + } + }, + "EIP": { + "id": "EIP", + "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet2/EIP", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::EIP", + "aws:cdk:cloudformation:props": { + "domain": "vpc", + "tags": [ + { + "key": "Name", + "value": "integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet2" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnEIP", + "version": "0.0.0" + } + }, + "NATGateway": { + "id": "NATGateway", + "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet2/NATGateway", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", + "aws:cdk:cloudformation:props": { + "subnetId": { + "Ref": "IntegVPCPublicSubnet2Subnet9648DE97" + }, + "allocationId": { + "Fn::GetAtt": [ + "IntegVPCPublicSubnet2EIPEA07DF99", + "AllocationId" + ] + }, + "tags": [ + { + "key": "Name", + "value": "integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet2" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnNatGateway", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "PrivateSubnet1": { + "id": "PrivateSubnet1", + "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/PrivateSubnet1", + "children": { + "Subnet": { + "id": "Subnet", + "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/PrivateSubnet1/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "IntegVPC2FF1AB0E" + }, + "availabilityZone": { + "Fn::Select": [ + 0, + { + "Fn::GetAZs": "" + } + ] + }, + "cidrBlock": "10.0.128.0/18", + "mapPublicIpOnLaunch": false, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "Private" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Private" + }, + { + "key": "Name", + "value": "integ-aurora-serverlessv2-cluster/Integ-VPC/PrivateSubnet1" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", + "version": "0.0.0" + } + }, + "Acl": { + "id": "Acl", + "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/PrivateSubnet1/Acl", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/PrivateSubnet1/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "IntegVPC2FF1AB0E" + }, + "tags": [ + { + "key": "Name", + "value": "integ-aurora-serverlessv2-cluster/Integ-VPC/PrivateSubnet1" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", + "version": "0.0.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/PrivateSubnet1/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "IntegVPCPrivateSubnet1RouteTableF2678D77" + }, + "subnetId": { + "Ref": "IntegVPCPrivateSubnet1SubnetD5B61223" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", + "version": "0.0.0" + } + }, + "DefaultRoute": { + "id": "DefaultRoute", + "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/PrivateSubnet1/DefaultRoute", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Route", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "IntegVPCPrivateSubnet1RouteTableF2678D77" + }, + "destinationCidrBlock": "0.0.0.0/0", + "natGatewayId": { + "Ref": "IntegVPCPublicSubnet1NATGateway380AC0A0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "PrivateSubnet2": { + "id": "PrivateSubnet2", + "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/PrivateSubnet2", + "children": { + "Subnet": { + "id": "Subnet", + "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/PrivateSubnet2/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "IntegVPC2FF1AB0E" + }, + "availabilityZone": { + "Fn::Select": [ + 1, + { + "Fn::GetAZs": "" + } + ] + }, + "cidrBlock": "10.0.192.0/18", + "mapPublicIpOnLaunch": false, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "Private" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Private" + }, + { + "key": "Name", + "value": "integ-aurora-serverlessv2-cluster/Integ-VPC/PrivateSubnet2" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", + "version": "0.0.0" + } + }, + "Acl": { + "id": "Acl", + "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/PrivateSubnet2/Acl", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/PrivateSubnet2/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "IntegVPC2FF1AB0E" + }, + "tags": [ + { + "key": "Name", + "value": "integ-aurora-serverlessv2-cluster/Integ-VPC/PrivateSubnet2" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", + "version": "0.0.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/PrivateSubnet2/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "IntegVPCPrivateSubnet2RouteTable4132D373" + }, + "subnetId": { + "Ref": "IntegVPCPrivateSubnet2SubnetFCC4EF23" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", + "version": "0.0.0" + } + }, + "DefaultRoute": { + "id": "DefaultRoute", + "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/PrivateSubnet2/DefaultRoute", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Route", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "IntegVPCPrivateSubnet2RouteTable4132D373" + }, + "destinationCidrBlock": "0.0.0.0/0", + "natGatewayId": { + "Ref": "IntegVPCPublicSubnet2NATGateway912800A3" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "IGW": { + "id": "IGW", + "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/IGW", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::InternetGateway", + "aws:cdk:cloudformation:props": { + "tags": [ + { + "key": "Name", + "value": "integ-aurora-serverlessv2-cluster/Integ-VPC" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnInternetGateway", + "version": "0.0.0" + } + }, + "VPCGW": { + "id": "VPCGW", + "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/VPCGW", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::VPCGatewayAttachment", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "IntegVPC2FF1AB0E" + }, + "internetGatewayId": { + "Ref": "IntegVPCIGW02FC78B6" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnVPCGatewayAttachment", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "integ-aurora-serverlessv2-0": { + "id": "integ-aurora-serverlessv2-0", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-0", + "children": { + "Integ-Cluster": { + "id": "Integ-Cluster", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-0/Integ-Cluster", + "children": { + "Subnets": { + "id": "Subnets", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-0/Integ-Cluster/Subnets", + "children": { + "Default": { + "id": "Default", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-0/Integ-Cluster/Subnets/Default", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::RDS::DBSubnetGroup", + "aws:cdk:cloudformation:props": { + "dbSubnetGroupDescription": "Subnets for Integ-Cluster database", + "subnetIds": [ + { + "Ref": "IntegVPCPrivateSubnet1SubnetD5B61223" + }, + { + "Ref": "IntegVPCPrivateSubnet2SubnetFCC4EF23" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_rds.CfnDBSubnetGroup", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "SecurityGroup": { + "id": "SecurityGroup", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-0/Integ-Cluster/SecurityGroup", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-0/Integ-Cluster/SecurityGroup/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SecurityGroup", + "aws:cdk:cloudformation:props": { + "groupDescription": "RDS security group", + "securityGroupEgress": [ + { + "cidrIp": "0.0.0.0/0", + "description": "Allow all outbound traffic by default", + "ipProtocol": "-1" + } + ], + "vpcId": { + "Ref": "IntegVPC2FF1AB0E" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSecurityGroup", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "AuroraMySqlDatabaseClusterEngineDefaultParameterGroup": { + "id": "AuroraMySqlDatabaseClusterEngineDefaultParameterGroup", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-0/Integ-Cluster/AuroraMySqlDatabaseClusterEngineDefaultParameterGroup", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "Secret": { + "id": "Secret", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-0/Integ-Cluster/Secret", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-0/Integ-Cluster/Secret/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SecretsManager::Secret", + "aws:cdk:cloudformation:props": { + "description": { + "Fn::Join": [ + "", + [ + "Generated by the CDK for stack: ", + { + "Ref": "AWS::StackName" + } + ] + ] + }, + "generateSecretString": { + "passwordLength": 30, + "secretStringTemplate": "{\"username\":\"admin\"}", + "generateStringKey": "password", + "excludeCharacters": " %+~`#$&*()|[]{}:;<>?!'/@\"\\" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_secretsmanager.CfnSecret", + "version": "0.0.0" + } + }, + "Attachment": { + "id": "Attachment", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-0/Integ-Cluster/Secret/Attachment", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-0/Integ-Cluster/Secret/Attachment/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SecretsManager::SecretTargetAttachment", + "aws:cdk:cloudformation:props": { + "secretId": { + "Ref": "integauroraserverlessv20IntegClusterSecretB9E432EB" + }, + "targetId": { + "Ref": "integauroraserverlessv20IntegCluster5133790E" + }, + "targetType": "AWS::RDS::DBCluster" + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_secretsmanager.CfnSecretTargetAttachment", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "Resource": { + "id": "Resource", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-0/Integ-Cluster/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::RDS::DBCluster", + "aws:cdk:cloudformation:props": { + "copyTagsToSnapshot": true, + "dbClusterParameterGroupName": "default.aurora-mysql8.0", + "dbSubnetGroupName": { + "Ref": "integauroraserverlessv20IntegClusterSubnets2462DA9D" + }, + "engine": "aurora-mysql", + "engineVersion": "8.0.mysql_aurora.3.03.0", + "masterUsername": { + "Fn::Join": [ + "", + [ + "{{resolve:secretsmanager:", + { + "Ref": "integauroraserverlessv20IntegClusterSecretB9E432EB" + }, + ":SecretString:username::}}" + ] + ] + }, + "masterUserPassword": { + "Fn::Join": [ + "", + [ + "{{resolve:secretsmanager:", + { + "Ref": "integauroraserverlessv20IntegClusterSecretB9E432EB" + }, + ":SecretString:password::}}" + ] + ] + }, + "serverlessV2ScalingConfiguration": { + "minCapacity": 0.5, + "maxCapacity": 2 + }, + "vpcSecurityGroupIds": [ + { + "Fn::GetAtt": [ + "integauroraserverlessv20IntegClusterSecurityGroup0FF1F93F", + "GroupId" + ] + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_rds.CfnDBCluster", + "version": "0.0.0" + } + }, + "writer": { + "id": "writer", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-0/Integ-Cluster/writer", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-0/Integ-Cluster/writer/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::RDS::DBInstance", + "aws:cdk:cloudformation:props": { + "dbClusterIdentifier": { + "Ref": "integauroraserverlessv20IntegCluster5133790E" + }, + "dbInstanceClass": "db.serverless", + "engine": "aurora-mysql", + "promotionTier": 0 + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_rds.CfnDBInstance", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "integ-aurora-serverlessv2-1": { + "id": "integ-aurora-serverlessv2-1", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-1", + "children": { + "Integ-Cluster": { + "id": "Integ-Cluster", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-1/Integ-Cluster", + "children": { + "Subnets": { + "id": "Subnets", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-1/Integ-Cluster/Subnets", + "children": { + "Default": { + "id": "Default", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-1/Integ-Cluster/Subnets/Default", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::RDS::DBSubnetGroup", + "aws:cdk:cloudformation:props": { + "dbSubnetGroupDescription": "Subnets for Integ-Cluster database", + "subnetIds": [ + { + "Ref": "IntegVPCPrivateSubnet1SubnetD5B61223" + }, + { + "Ref": "IntegVPCPrivateSubnet2SubnetFCC4EF23" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_rds.CfnDBSubnetGroup", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "SecurityGroup": { + "id": "SecurityGroup", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-1/Integ-Cluster/SecurityGroup", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-1/Integ-Cluster/SecurityGroup/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SecurityGroup", + "aws:cdk:cloudformation:props": { + "groupDescription": "RDS security group", + "securityGroupEgress": [ + { + "cidrIp": "0.0.0.0/0", + "description": "Allow all outbound traffic by default", + "ipProtocol": "-1" + } + ], + "vpcId": { + "Ref": "IntegVPC2FF1AB0E" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSecurityGroup", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "AuroraMySqlDatabaseClusterEngineDefaultParameterGroup": { + "id": "AuroraMySqlDatabaseClusterEngineDefaultParameterGroup", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-1/Integ-Cluster/AuroraMySqlDatabaseClusterEngineDefaultParameterGroup", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "Secret": { + "id": "Secret", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-1/Integ-Cluster/Secret", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-1/Integ-Cluster/Secret/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SecretsManager::Secret", + "aws:cdk:cloudformation:props": { + "description": { + "Fn::Join": [ + "", + [ + "Generated by the CDK for stack: ", + { + "Ref": "AWS::StackName" + } + ] + ] + }, + "generateSecretString": { + "passwordLength": 30, + "secretStringTemplate": "{\"username\":\"admin\"}", + "generateStringKey": "password", + "excludeCharacters": " %+~`#$&*()|[]{}:;<>?!'/@\"\\" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_secretsmanager.CfnSecret", + "version": "0.0.0" + } + }, + "Attachment": { + "id": "Attachment", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-1/Integ-Cluster/Secret/Attachment", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-1/Integ-Cluster/Secret/Attachment/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SecretsManager::SecretTargetAttachment", + "aws:cdk:cloudformation:props": { + "secretId": { + "Ref": "integauroraserverlessv21IntegClusterSecretA8DA28CB" + }, + "targetId": { + "Ref": "integauroraserverlessv21IntegClusterDFF12F00" + }, + "targetType": "AWS::RDS::DBCluster" + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_secretsmanager.CfnSecretTargetAttachment", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "Resource": { + "id": "Resource", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-1/Integ-Cluster/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::RDS::DBCluster", + "aws:cdk:cloudformation:props": { + "copyTagsToSnapshot": true, + "dbClusterParameterGroupName": "default.aurora-mysql8.0", + "dbSubnetGroupName": { + "Ref": "integauroraserverlessv21IntegClusterSubnetsAEE71920" + }, + "engine": "aurora-mysql", + "engineVersion": "8.0.mysql_aurora.3.03.0", + "masterUsername": { + "Fn::Join": [ + "", + [ + "{{resolve:secretsmanager:", + { + "Ref": "integauroraserverlessv21IntegClusterSecretA8DA28CB" + }, + ":SecretString:username::}}" + ] + ] + }, + "masterUserPassword": { + "Fn::Join": [ + "", + [ + "{{resolve:secretsmanager:", + { + "Ref": "integauroraserverlessv21IntegClusterSecretA8DA28CB" + }, + ":SecretString:password::}}" + ] + ] + }, + "serverlessV2ScalingConfiguration": { + "minCapacity": 0.5, + "maxCapacity": 2 + }, + "vpcSecurityGroupIds": [ + { + "Fn::GetAtt": [ + "integauroraserverlessv21IntegClusterSecurityGroup483E60E7", + "GroupId" + ] + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_rds.CfnDBCluster", + "version": "0.0.0" + } + }, + "writer": { + "id": "writer", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-1/Integ-Cluster/writer", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-1/Integ-Cluster/writer/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::RDS::DBInstance", + "aws:cdk:cloudformation:props": { + "dbClusterIdentifier": { + "Ref": "integauroraserverlessv21IntegClusterDFF12F00" + }, + "dbInstanceClass": "db.t3.medium", + "engine": "aurora-mysql", + "promotionTier": 0 + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_rds.CfnDBInstance", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "FailoverReader": { + "id": "FailoverReader", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-1/Integ-Cluster/FailoverReader", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-1/Integ-Cluster/FailoverReader/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::RDS::DBInstance", + "aws:cdk:cloudformation:props": { + "dbClusterIdentifier": { + "Ref": "integauroraserverlessv21IntegClusterDFF12F00" + }, + "dbInstanceClass": "db.serverless", + "engine": "aurora-mysql", + "promotionTier": 1 + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_rds.CfnDBInstance", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "OtherReader": { + "id": "OtherReader", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-1/Integ-Cluster/OtherReader", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-1/Integ-Cluster/OtherReader/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::RDS::DBInstance", + "aws:cdk:cloudformation:props": { + "dbClusterIdentifier": { + "Ref": "integauroraserverlessv21IntegClusterDFF12F00" + }, + "dbInstanceClass": "db.serverless", + "engine": "aurora-mysql", + "promotionTier": 2 + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_rds.CfnDBInstance", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "integ-aurora-serverlessv2-2": { + "id": "integ-aurora-serverlessv2-2", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-2", + "children": { + "Integ-Cluster": { + "id": "Integ-Cluster", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-2/Integ-Cluster", + "children": { + "Subnets": { + "id": "Subnets", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-2/Integ-Cluster/Subnets", + "children": { + "Default": { + "id": "Default", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-2/Integ-Cluster/Subnets/Default", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::RDS::DBSubnetGroup", + "aws:cdk:cloudformation:props": { + "dbSubnetGroupDescription": "Subnets for Integ-Cluster database", + "subnetIds": [ + { + "Ref": "IntegVPCPrivateSubnet1SubnetD5B61223" + }, + { + "Ref": "IntegVPCPrivateSubnet2SubnetFCC4EF23" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_rds.CfnDBSubnetGroup", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "SecurityGroup": { + "id": "SecurityGroup", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-2/Integ-Cluster/SecurityGroup", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-2/Integ-Cluster/SecurityGroup/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SecurityGroup", + "aws:cdk:cloudformation:props": { + "groupDescription": "RDS security group", + "securityGroupEgress": [ + { + "cidrIp": "0.0.0.0/0", + "description": "Allow all outbound traffic by default", + "ipProtocol": "-1" + } + ], + "vpcId": { + "Ref": "IntegVPC2FF1AB0E" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSecurityGroup", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "AuroraMySqlDatabaseClusterEngineDefaultParameterGroup": { + "id": "AuroraMySqlDatabaseClusterEngineDefaultParameterGroup", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-2/Integ-Cluster/AuroraMySqlDatabaseClusterEngineDefaultParameterGroup", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "Secret": { + "id": "Secret", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-2/Integ-Cluster/Secret", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-2/Integ-Cluster/Secret/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SecretsManager::Secret", + "aws:cdk:cloudformation:props": { + "description": { + "Fn::Join": [ + "", + [ + "Generated by the CDK for stack: ", + { + "Ref": "AWS::StackName" + } + ] + ] + }, + "generateSecretString": { + "passwordLength": 30, + "secretStringTemplate": "{\"username\":\"admin\"}", + "generateStringKey": "password", + "excludeCharacters": " %+~`#$&*()|[]{}:;<>?!'/@\"\\" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_secretsmanager.CfnSecret", + "version": "0.0.0" + } + }, + "Attachment": { + "id": "Attachment", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-2/Integ-Cluster/Secret/Attachment", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-2/Integ-Cluster/Secret/Attachment/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SecretsManager::SecretTargetAttachment", + "aws:cdk:cloudformation:props": { + "secretId": { + "Ref": "integauroraserverlessv22IntegClusterSecretBF74DBA3" + }, + "targetId": { + "Ref": "integauroraserverlessv22IntegCluster1F86F0C6" + }, + "targetType": "AWS::RDS::DBCluster" + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_secretsmanager.CfnSecretTargetAttachment", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "Resource": { + "id": "Resource", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-2/Integ-Cluster/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::RDS::DBCluster", + "aws:cdk:cloudformation:props": { + "copyTagsToSnapshot": true, + "dbClusterParameterGroupName": "default.aurora-mysql8.0", + "dbSubnetGroupName": { + "Ref": "integauroraserverlessv22IntegClusterSubnets241DB50C" + }, + "engine": "aurora-mysql", + "engineVersion": "8.0.mysql_aurora.3.03.0", + "masterUsername": { + "Fn::Join": [ + "", + [ + "{{resolve:secretsmanager:", + { + "Ref": "integauroraserverlessv22IntegClusterSecretBF74DBA3" + }, + ":SecretString:username::}}" + ] + ] + }, + "masterUserPassword": { + "Fn::Join": [ + "", + [ + "{{resolve:secretsmanager:", + { + "Ref": "integauroraserverlessv22IntegClusterSecretBF74DBA3" + }, + ":SecretString:password::}}" + ] + ] + }, + "serverlessV2ScalingConfiguration": { + "minCapacity": 0.5, + "maxCapacity": 2 + }, + "vpcSecurityGroupIds": [ + { + "Fn::GetAtt": [ + "integauroraserverlessv22IntegClusterSecurityGroup0EDBBE37", + "GroupId" + ] + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_rds.CfnDBCluster", + "version": "0.0.0" + } + }, + "writer": { + "id": "writer", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-2/Integ-Cluster/writer", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-2/Integ-Cluster/writer/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::RDS::DBInstance", + "aws:cdk:cloudformation:props": { + "dbClusterIdentifier": { + "Ref": "integauroraserverlessv22IntegCluster1F86F0C6" + }, + "dbInstanceClass": "db.serverless", + "engine": "aurora-mysql", + "promotionTier": 0 + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_rds.CfnDBInstance", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "FailoverReader": { + "id": "FailoverReader", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-2/Integ-Cluster/FailoverReader", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-2/Integ-Cluster/FailoverReader/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::RDS::DBInstance", + "aws:cdk:cloudformation:props": { + "dbClusterIdentifier": { + "Ref": "integauroraserverlessv22IntegCluster1F86F0C6" + }, + "dbInstanceClass": "db.t3.medium", + "engine": "aurora-mysql", + "promotionTier": 1 + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_rds.CfnDBInstance", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "OtherReader": { + "id": "OtherReader", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-2/Integ-Cluster/OtherReader", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-2/Integ-Cluster/OtherReader/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::RDS::DBInstance", + "aws:cdk:cloudformation:props": { + "dbClusterIdentifier": { + "Ref": "integauroraserverlessv22IntegCluster1F86F0C6" + }, + "dbInstanceClass": "db.serverless", + "engine": "aurora-mysql", + "promotionTier": 2 + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_rds.CfnDBInstance", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "integ-aurora-serverlessv2-cluster/BootstrapVersion", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "integ-aurora-serverlessv2-cluster/CheckBootstrapVersion", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "integ-test": { + "id": "integ-test", + "path": "integ-test", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "integ-test/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "integ-test/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "integ-test/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "integ-test/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "integ-test/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTest", + "version": "0.0.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.ts new file mode 100644 index 0000000000000..664b8fbec2449 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.ts @@ -0,0 +1,64 @@ +import { IntegTest } from '@aws-cdk/integ-tests-alpha'; +import { App, RemovalPolicy, Stack, StackProps } from 'aws-cdk-lib'; +import { Vpc } from 'aws-cdk-lib/aws-ec2'; +import * as rds from 'aws-cdk-lib/aws-rds'; +import { ClusterInstance } from 'aws-cdk-lib/aws-rds'; +import { Construct } from 'constructs'; + +interface TestCaseProps extends Pick { +} + +class TestCase extends Construct { + constructor(scope: Construct, id: string, props: TestCaseProps) { + super(scope, id); + new rds.DatabaseCluster(this, 'Integ-Cluster', { + engine: rds.DatabaseClusterEngine.auroraMysql({ version: rds.AuroraMysqlEngineVersion.VER_3_03_0 }), + writer: props.writer, + readers: props.readers, + removalPolicy: RemovalPolicy.DESTROY, + vpc: props.vpc, + }); + // cluster.metricACUUtilization().createAlarm(this, 'alarm', { + // evaluationPeriods: 1, + // }); + } +} + +const testCases: TestCaseProps[] = [ + { + writer: ClusterInstance.serverlessV2('writer'), + }, + { + writer: ClusterInstance.provisioned('writer'), + readers: [ + ClusterInstance.serverlessV2('FailoverReader', { scaleWithWriter: true }), + ClusterInstance.serverlessV2('OtherReader'), + ], + }, + { + writer: ClusterInstance.serverlessV2('writer'), + readers: [ + ClusterInstance.provisioned('FailoverReader', { promotionTier: 1 }), + ClusterInstance.serverlessV2('OtherReader'), + ], + }, +]; + +export class TestStack extends Stack { + constructor(scope: Construct, id: string, props?: StackProps) { + super(scope, id, props); + const vpc = new Vpc(this, 'Integ-VPC'); + testCases.forEach((p: TestCaseProps, i) => + new TestCase(this, `integ-aurora-serverlessv2-${i}`, { + ...p, + vpc, + }), + ); + } +} + + +const app = new App(); +new IntegTest(app, 'integ-test', { + testCases: [new TestStack(app, 'integ-aurora-serverlessv2-cluster')], +}); diff --git a/packages/aws-cdk-lib/aws-rds/README.md b/packages/aws-cdk-lib/aws-rds/README.md index 8c9b01705648d..8c7f2f4d8c0cd 100644 --- a/packages/aws-cdk-lib/aws-rds/README.md +++ b/packages/aws-cdk-lib/aws-rds/README.md @@ -12,19 +12,26 @@ To set up a clustered database (like Aurora), define a `DatabaseCluster`. You mu always launch a database in a VPC. Use the `vpcSubnets` attribute to control whether your instances will be launched privately or publicly: +You must specify the instance to use as the writer, along with an optional list +of readers (up to 15). + ```ts declare const vpc: ec2.Vpc; const cluster = new rds.DatabaseCluster(this, 'Database', { engine: rds.DatabaseClusterEngine.auroraMysql({ version: rds.AuroraMysqlEngineVersion.VER_2_08_1 }), credentials: rds.Credentials.fromGeneratedSecret('clusteradmin'), // Optional - will default to 'admin' username and generated password - instanceProps: { + writer: rds.ClusterInstance.provisioned('writer', { // optional , defaults to t3.medium instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), - vpcSubnets: { - subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, - }, - vpc, + }), + readers: [ + rds.ClusterInstance.provisioned('reader1', { promotionTier: 1 }), + rds.ClusterInstance.serverlessV2('reader2'), + ] + vpcSubnets: { + subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, }, + vpc, }); ``` @@ -46,10 +53,10 @@ To use dual-stack mode, specify `NetworkType.DUAL` on the `networkType` property declare const vpc: ec2.Vpc; // VPC and subnets must have IPv6 CIDR blocks const cluster = new rds.DatabaseCluster(this, 'Database', { engine: rds.DatabaseClusterEngine.auroraMysql({ version: rds.AuroraMysqlEngineVersion.VER_3_02_1 }), - instanceProps: { - vpc, + writer: rds.ClusterInstance.provisioned('writer', { publiclyAccessible: false, - }, + }), + vpc, networkType: rds.NetworkType.DUAL, }); ``` @@ -62,9 +69,8 @@ Use `DatabaseClusterFromSnapshot` to create a cluster from a snapshot: declare const vpc: ec2.Vpc; new rds.DatabaseClusterFromSnapshot(this, 'Database', { engine: rds.DatabaseClusterEngine.aurora({ version: rds.AuroraEngineVersion.VER_1_22_2 }), - instanceProps: { - vpc, - }, + writer: rds.ClusterInstance.provisioned('writer'), + vpc, snapshotIdentifier: 'mySnapshot', }); ``` @@ -81,15 +87,159 @@ Use `InstanceUpdateBehavior.BULK` to update all instances at once. declare const vpc: ec2.Vpc; const cluster = new rds.DatabaseCluster(this, 'Database', { engine: rds.DatabaseClusterEngine.auroraMysql({ version: rds.AuroraMysqlEngineVersion.VER_3_01_0 }), - instances: 2, - instanceProps: { + writer: rds.ClusterInstance.provisioned({ instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE3, ec2.InstanceSize.SMALL), - vpc, - }, + }), + readers [rds.ClusterInstance.provisioned('reader')], instanceUpdateBehaviour: rds.InstanceUpdateBehaviour.ROLLING, // Optional - defaults to rds.InstanceUpdateBehaviour.BULK + vpc, +}); +``` + +### Serverless V2 instances in a Cluster + +It is possible to create an RDS cluster with _both_ serverlessV2 and provisioned +instances. For example, this will create a cluster with a provisioned writer and +a serverless v2 reader. + +```ts +declare const vpc: ec2.Vpc; +const cluster = new rds.DatabaseCluster(this, 'Database', { + engine: rds.DatabaseClusterEngine.auroraMysql({ version: rds.AuroraMysqlEngineVersion.VER_2_08_1 }), + writer: rds.ClusterInstance.provisioned('writer'), + readers: [ + rds.ClusterInstance.serverlessV2('reader'), + ] + vpc, +}); +``` + +#### Capacity & Scaling + +There are some things to take into consideration with Aurora Serverless v2. + +To create a cluster that can support serverless v2 instance you configure a +minimum and maximum capacity range on the cluster. This is an example showing +the default values: + +```ts +declare const vpc: ec2.Vpc; +const cluster = new rds.DatabaseCluster(this, 'Database', { + engine: rds.DatabaseClusterEngine.auroraMysql({ version: rds.AuroraMysqlEngineVersion.VER_2_08_1 }), + writer: rds.ClusterInstance.serverlessV2('writer'), + serverlessV2MinCapacity: 0.5, + serverlessV2MaxCapacity: 2, + vpc, }); ``` +The capacity is defined as a number of Aurora capacity units (ACUs). You can +specify in half-step increments (40, 40.5, 41, etc). Each serverless instance in +the cluster inherits the capacity that is defined on the cluster. It is not +possible to configure separate capacity at the instance level. + +The maximum capacity is mainly used for budget control since it allows you to +set a cap on how high your instance can scale. + +The minimum capacity is a little more involved. This controls a couple different +things. + +* The scale-up rate is proportional to the current capacity (larger instances + scale up faster) + * Adjust the minimum capacity to obtain a suitable scaling rate +* Network throughput is proportional to capacity + +More complete details can be found [in the docs](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-serverless-v2.setting-capacity.html#aurora-serverless-v2-examples-setting-capacity-range-for-cluster) + +Another way that you control the capacity/scaling of your serverless v2 reader +instances is based on the [promotion tier](https://aws.amazon.com/blogs/aws/additional-failover-control-for-amazon-aurora/) +which can be between 0-15. Any serverless v2 instance in the 0-1 tiers will scale alongside the +writer even if the current read load does not require the capacity. This is +because instances in the 0-1 tier are first priority for failover and Aurora +wants to ensure that in the event of a failover the reader that gets promoted is +scaled to handle the write load. + +```ts +declare const vpc: ec2.Vpc; +const cluster = new rds.DatabaseCluster(this, 'Database', { + engine: rds.DatabaseClusterEngine.auroraMysql({ version: rds.AuroraMysqlEngineVersion.VER_2_08_1 }), + writer: rds.ClusterInstance.serverlessV2('writer'), + readers: [ + // will be put in promotion tier 1 and will scale with the writer + rds.ClusterInstance.serverlessV2('reader1', { scaleWithWriter: true }), + // will be put in promotion tier 2 and will not scale with the writer + rds.ClusterInstance.serverlessV2('reader2'), + ] + vpc, +}); +``` + +* When the writer scales up, any readers in tier 0-1 will scale up to match +* Scaling for tier 2-15 is independent of what is happening on the writer +* Readers in tier 2-15 scale up based on read load against the individual reader + +When configuring your cluster it is important to take this into consideration +and ensure that in the event of a failover there is an instance that is scaled +up to take over. + +### Mixing Serverless v2 and Provisioned instances + +You are able to create a cluster that has both provisioned and serverless +instances. [This blog post](https://aws.amazon.com/blogs/database/evaluate-amazon-aurora-serverless-v2-for-your-provisioned-aurora-clusters/) +has an excellent guide on choosing between serverless and provisioned instances +based on use case. + +There are a couple of high level differences: + +* Engine Version (serverless only supports MySQL 8+ & PostgreSQL 13+) +* Memory up to 256GB can be replaced with serverless + +#### Provisioned writer + +With a provisioned writer and serverless v2 readers, some of the serverless +readers will need to be configured to scale with the writer so they can act as +failover targets. You will need to determine the correct capacity based on the +provisioned instance type and it's utilization. + +As an example, if the CPU utilization for a db.r6g.4xlarge (128 GB) instance +stays at 10% most times, then the minimum ACUs may be set at 6.5 ACUs +(10% of 128 GB) and maximum may be set at 64 ACUs (64x2GB=128GB). Keep in mind +that the speed at which the serverless instance can scale up is determined by +the minimum capacity so if your cluster has spiky workloads you may need to set +a higher minimum capacity. + +```ts +declare const vpc: ec2.Vpc; +const cluster = new rds.DatabaseCluster(this, 'Database', { + engine: rds.DatabaseClusterEngine.auroraMysql({ version: rds.AuroraMysqlEngineVersion.VER_2_08_1 }), + writer: rds.ClusterInstance.provisioned('writer', { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.R6G, ec2.InstanceSize.XLARGE4), + }), + serverlessV2MinCapacity: 6.5, + serverlessV2MaxCapacity: 64, + readers: [ + // will be put in promotion tier 1 and will scale with the writer + rds.ClusterInstance.serverlessV2('reader1', { scaleWithWriter: true }), + // will be put in promotion tier 2 and will not scale with the writer + rds.ClusterInstance.serverlessV2('reader2'), + ] + vpc, +}); +``` + +In the above example `reader1` will scale with the writer based on the writer's +utilization. So if the writer were to go to `50%` utilization then `reader1` +would scale up to use `32` ACUs. If the read load stayed consistent then +`reader2` may remain at `6.5` since it is not configured to scale with the +writer. + +If one of your Aurora Serverless v2 DB instances consistently reaches the +limit of its maximum capacity, Aurora indicates this condition by setting the +DB instance to a status of `incompatible-parameters`. While the DB instance has +the incompatible-parameters status, some operations are blocked. For example, +you can't upgrade the engine version. + + ## Starting an instance database To set up an instance database, define a `DatabaseInstance`. You must @@ -434,7 +584,8 @@ The following example shows granting connection access for RDS Proxy to an IAM r declare const vpc: ec2.Vpc; const cluster = new rds.DatabaseCluster(this, 'Database', { engine: rds.DatabaseClusterEngine.AURORA, - instanceProps: { vpc }, + writer: rds.ClusterInstance.provisioned('writer'), + vpc, }); const proxy = new rds.DatabaseProxy(this, 'Proxy', { @@ -526,9 +677,8 @@ const importBucket = new s3.Bucket(this, 'importbucket'); const exportBucket = new s3.Bucket(this, 'exportbucket'); new rds.DatabaseCluster(this, 'dbcluster', { engine: rds.DatabaseClusterEngine.AURORA, - instanceProps: { - vpc, - }, + writer: rds.ClusterInstance.provisioned('writer'), + vpc, s3ImportBuckets: [importBucket], s3ExportBuckets: [exportBucket], }); @@ -571,9 +721,8 @@ const cluster = new rds.DatabaseCluster(this, 'Database', { engine: rds.DatabaseClusterEngine.aurora({ version: rds.AuroraEngineVersion.VER_1_17_9, // different version class for each engine type }), - instanceProps: { - vpc, - }, + writer: rds.ClusterInstance.provisioned('writer'), + vpc, cloudwatchLogsExports: ['error', 'general', 'slowquery', 'audit'], // Export all available MySQL-based logs cloudwatchLogsRetention: logs.RetentionDays.THREE_MONTHS, // Optional - default is to never expire logs cloudwatchLogsRetentionRole: myLogsPublishingRole, // Optional - a role will be created if not provided diff --git a/packages/aws-cdk-lib/aws-rds/adr/aurora-serverless-v2.md b/packages/aws-cdk-lib/aws-rds/adr/aurora-serverless-v2.md index a73e3ab0e5a56..a4fd2de2da5ff 100644 --- a/packages/aws-cdk-lib/aws-rds/adr/aurora-serverless-v2.md +++ b/packages/aws-cdk-lib/aws-rds/adr/aurora-serverless-v2.md @@ -198,7 +198,7 @@ _user configuration_ (properties are not shown to focus on the API) new rds.DatabaseCluster(this, 'Cluster', { engine: rds.DatabaseClusterEngine.auroraMysql({ version: rds.AuroraMysqlEngineVersion.VER_3_03_0 }), // capacity applies to all serverless instances in the cluster - serverlessV2Capacity: 1, + serverlessV2MaxCapacity: 1, serverlessV2MinCapacity: 0.5, writer: ClusterInstance.provisioned('writer', { ...props }), readers: [ diff --git a/packages/aws-cdk-lib/aws-rds/lib/aurora-cluster-instance.ts b/packages/aws-cdk-lib/aws-rds/lib/aurora-cluster-instance.ts new file mode 100644 index 0000000000000..1a2ca2581cb3c --- /dev/null +++ b/packages/aws-cdk-lib/aws-rds/lib/aurora-cluster-instance.ts @@ -0,0 +1,444 @@ +import { Construct } from 'constructs'; +import { DatabaseCluster } from './cluster'; +import { IDatabaseCluster } from './cluster-ref'; +import { IParameterGroup, ParameterGroup } from './parameter-group'; +import { helperRemovalPolicy } from './private/util'; +import { InstanceProps, PerformanceInsightRetention } from './props'; +import { CfnDBInstance } from './rds.generated'; +import * as ec2 from '../../aws-ec2'; +import { IRole } from '../../aws-iam'; +import * as kms from '../../aws-kms'; +import { IResource, Resource, Duration, RemovalPolicy, ArnFormat } from '../../core'; + +export interface ClusterInstanceBindOptions { + /** + * The interval, in seconds, between points when Amazon RDS collects enhanced + * monitoring metrics for the DB instances. + * + * @default no enhanced monitoring + */ + readonly monitoringInterval?: Duration; + + /** + * Role that will be used to manage DB instances monitoring. + * + * @default - A role is automatically created for you + */ + readonly monitoringRole?: IRole; + + /** + * The removal policy on the cluster + * + * @default - RemovalPolicy.DESTROY (cluster snapshot can restore) + */ + readonly removalPolicy?: RemovalPolicy; + + /** + * The promotion tier of the cluster instance + * + * This matters more for serverlessV2 instances. If a serverless + * instance is in tier 0-1 then it will scale with the writer. + * + * For provisioned instances this just determines the failover priority. + * If multiple instances have the same priority then one will be picked at random + * + * @default 2 + */ + readonly promotionTier?: number; + +} + +/** + * The type of Aurora Cluster Instance. Can be either serverless v2 + * or provisioned + */ +export class ClusterInstanceType { + /** + * Aurora Serverless V2 instance type + * @see https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-serverless-v2.html + */ + public static serverlessV2(): ClusterInstanceType { + return new ClusterInstanceType('db.serverless', InstanceType.SERVERLESS_V2); + } + + /** + * Aurora Provisioned instance type + */ + public static provisioned(instanceType?: ec2.InstanceType): ClusterInstanceType { + return new ClusterInstanceType( + (instanceType ?? ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MEDIUM)).toString(), + InstanceType.PROVISIONED, + ); + } + + + constructor( + private readonly instanceType: string, + public readonly type: InstanceType, + ) { } + + /** + * String representation of the instance type that can be used in the CloudFormation resource + */ + public toString(): string { + return this.instanceType; + } +} + +/** + * Represents an Aurora cluster instance + * This can be either a provisioned instance or a serverless v2 instance + */ +export interface IClusterInstance { + /** + * Create the database instance within the provided cluster + */ + bind(scope: Construct, cluster: IDatabaseCluster, options: ClusterInstanceBindOptions): IAuroraClusterInstance; +} + +/** + * Options for creating a provisioned instance + */ +export interface ProvisionedClusterInstanceProps extends ClusterInstanceOptions { + /** + * The cluster instance type + * + * @default db.t3.medium + */ + readonly instanceType?: ec2.InstanceType; + + /** + * The promotion tier of the cluster instance + * + * Can be between 0-15 + * + * For provisioned instances this just determines the failover priority. + * If multiple instances have the same priority then one will be picked at random + * + * @default 2 + */ + readonly promotionTier?: number; +} + +/** + * Options for creating a serverless v2 instance + */ +export interface ServerlessV2ClusterInstanceProps extends ClusterInstanceOptions { + /** + * Only applicable to reader instances. + * + * If this is true then the instance will be placed in promotion tier 1, otherwise + * it will be placed in promotion tier 2. + * + * For serverless v2 instances this means: + * - true: The serverless v2 reader will scale to match the writer instance (provisioned or serverless) + * - false: The serverless v2 reader will scale with the read workfload on the instance + * + * @default false + */ + readonly scaleWithWriter?: boolean; +} + +/** + * Common options for creating cluster instances (both serverless and provisioned) + */ +export interface ClusterInstanceProps extends ClusterInstanceOptions{ + /** + * The type of cluster instance to create. Can be either + * provisioned or serverless v2 + */ + readonly instanceType: ClusterInstanceType; + + /** + * The promotion tier of the cluster instance + * + * This matters more for serverlessV2 instances. If a serverless + * instance is in tier 0-1 then it will scale with the writer. + * + * For provisioned instances this just determines the failover priority. + * If multiple instances have the same priority then one will be picked at random + * + * @default 2 + */ + readonly promotionTier?: number; + + /** + * @default false + */ + readonly isFromLegacyInstanceProps?: boolean; +} + +export interface ClusterInstanceOptions { + /** + * The identifier for the database instance + * + * @default - CloudFormation generated identifier + */ + readonly instanceIdentifier?: string; + + /** + * Whether to enable automatic upgrade of minor version for the DB instance. + * + * @default - true + */ + readonly autoMinorVersionUpgrade?: boolean; + + /** + * Whether to enable Performance Insights for the DB instance. + * + * @default - false, unless ``performanceInsightRentention`` or ``performanceInsightEncryptionKey`` is set. + */ + readonly enablePerformanceInsights?: boolean; + + /** + * The amount of time, in days, to retain Performance Insights data. + * + * @default 7 + */ + readonly performanceInsightRetention?: PerformanceInsightRetention; + + /** + * The AWS KMS key for encryption of Performance Insights data. + * + * @default - default master key + */ + readonly performanceInsightEncryptionKey?: kms.IKey; + + /** + * Indicates whether the DB instance is an internet-facing instance. + * + * @default - true if the instance is placed in a public subnet + */ + readonly publiclyAccessible?: boolean; + + /** + * The parameters in the DBParameterGroup to create automatically + * + * You can only specify parameterGroup or parameters but not both. + * You need to use a versioned engine to auto-generate a DBParameterGroup. + * + * @default - None + */ + readonly parameters?: { [key: string]: string }; + + /** + * Whether to allow upgrade of major version for the DB instance. + * + * @default - false + */ + readonly allowMajorVersionUpgrade?: boolean; + + /** + * The DB parameter group to associate with the instance. + * This is only needed if you need to configure different parameter + * groups for each individual instance, otherwise you should not + * provide this and just use the cluster parameter group + * + * @default the cluster parameter group is used + */ + readonly parameterGroup?: IParameterGroup; +} + +export interface LegacyInstanceProps extends InstanceProps { + /** + * How many replicas/instances to create + * + * Has to be at least 1. + * + * @default 2 + */ + readonly instances?: number; + + /** + * An optional identifier for the cluster + * + * @default - A name is automatically generated. + */ + readonly clusterIdentifier?: string; + + /** + * Base identifier for instances + * + * Every replica is named by appending the replica number to this string, 1-based. + * + * @default - clusterIdentifier is used with the word "Instance" appended. + * If clusterIdentifier is not provided, the identifier is automatically generated. + */ + readonly instanceIdentifierBase?: string; +} + +export class ClusterInstance implements IClusterInstance { + public static provisioned(id: string, props: ProvisionedClusterInstanceProps = {}): IClusterInstance { + return new ClusterInstance(id, { + ...props, + instanceType: ClusterInstanceType.provisioned(props.instanceType), + }); + } + + public static serverlessV2(id: string, props: ServerlessV2ClusterInstanceProps = {}): IClusterInstance { + return new ClusterInstance(id, { + ...props, + promotionTier: props.scaleWithWriter ? 1 : 2, + instanceType: ClusterInstanceType.serverlessV2(), + }); + } + + public static fromInstanceProps(props: LegacyInstanceProps, instances?: number): IClusterInstance[] { + const instanceCount = instances != null ? instances : 2; + if (instanceCount < 1) { + throw new Error('At least one instance is required'); + } + const clusterInstances: IClusterInstance[] = []; + for (let i = 0; i < instanceCount; i++) { + const instanceIndex = i + 1; + const instanceIdentifier = props.instanceIdentifierBase != null ? `${props.instanceIdentifierBase}${instanceIndex}` : + props.clusterIdentifier != null ? `${props.clusterIdentifier}instance${instanceIndex}` : + undefined; + clusterInstances.push( + new ClusterInstance(`Instance${instanceIndex}`, { + ...props, + isFromLegacyInstanceProps: true, + instanceType: ClusterInstanceType.provisioned(props.instanceType), + instanceIdentifier, + promotionTier: 1, + }), + ); + } + return clusterInstances; + } + + private constructor(private id: string, private readonly props: ClusterInstanceProps) { } + + public bind(scope: Construct, cluster: IDatabaseCluster, props: ClusterInstanceBindOptions): IAuroraClusterInstance { + return new AuroraClusterInstance(scope, this.id, { + cluster, + ...this.props, + ...props, + }); + } +} + +interface AuroraClusterInstanceProps extends ClusterInstanceProps, ClusterInstanceBindOptions { + readonly cluster: IDatabaseCluster; +} + +export enum InstanceType { + PROVISIONED = 'PROVISIONED', + SERVERLESS_V2 = 'SERVERLESS_V2', +} + +export interface IAuroraClusterInstance extends IResource { + readonly dbInstanceArn: string; + readonly dbiResourceId: string; + readonly dbInstanceEndpointAddress: string; + readonly instanceIdentifier: string; + readonly type: InstanceType; + readonly instanceSize?: string; + readonly tier: number; +} + +class AuroraClusterInstance extends Resource implements IAuroraClusterInstance { + public readonly dbInstanceArn: string; + public readonly dbiResourceId: string; + public readonly dbInstanceEndpointAddress: string; + public readonly instanceIdentifier: string; + public readonly type: InstanceType; + public readonly tier: number; + public readonly instanceSize?: string; + constructor(scope: Construct, id: string, props: AuroraClusterInstanceProps) { + super( + scope, + props.isFromLegacyInstanceProps ? `${id}Wrapper` : id, + { + physicalName: props.instanceIdentifier, + }); + this.tier = props.promotionTier ?? 2; + if (this.tier > 15) { + throw new Error('promotionTier must be between 0-15'); + } + + const isOwnedResource = Resource.isOwnedResource(props.cluster); + let internetConnected; + let publiclyAccessible = props.publiclyAccessible; + if (isOwnedResource) { + const ownedCluster = props.cluster as DatabaseCluster; + internetConnected = ownedCluster.vpc.selectSubnets(ownedCluster.vpcSubnets).internetConnectivityEstablished; + publiclyAccessible = ownedCluster.vpcSubnets && ownedCluster.vpcSubnets.subnetType === ec2.SubnetType.PUBLIC; + } + + // Get the actual subnet objects so we can depend on internet connectivity. + const instanceType = (props.instanceType ?? ClusterInstanceType.serverlessV2()); + this.type = instanceType.type; + this.instanceSize = this.type === InstanceType.PROVISIONED ? props.instanceType?.toString() : undefined; + + // engine is never undefined on a managed resource, i.e. DatabaseCluster + const engine = props.cluster.engine!; + const enablePerformanceInsights = props.enablePerformanceInsights + || props.performanceInsightRetention !== undefined || props.performanceInsightEncryptionKey !== undefined; + if (enablePerformanceInsights && props.enablePerformanceInsights === false) { + throw new Error('`enablePerformanceInsights` disabled, but `performanceInsightRetention` or `performanceInsightEncryptionKey` was set'); + } + + const instanceParameterGroup = props.parameterGroup ?? ( + props.parameters + ? new ParameterGroup(props.cluster, 'InstanceParameterGroup', { + engine: engine, + parameters: props.parameters, + }) + : undefined + ); + const instanceParameterGroupConfig = instanceParameterGroup?.bindToInstance({}); + const instance = new CfnDBInstance( + props.isFromLegacyInstanceProps ? scope : this, + props.isFromLegacyInstanceProps ? id : 'Resource', + { + // Link to cluster + engine: engine.engineType, + dbClusterIdentifier: props.cluster.clusterIdentifier, + promotionTier: props.isFromLegacyInstanceProps ? undefined : this.tier, + dbInstanceIdentifier: this.physicalName, + // Instance properties + dbInstanceClass: props.instanceType ? databaseInstanceType(instanceType) : undefined, + publiclyAccessible, + enablePerformanceInsights: enablePerformanceInsights || props.enablePerformanceInsights, // fall back to undefined if not set + performanceInsightsKmsKeyId: props.performanceInsightEncryptionKey?.keyArn, + performanceInsightsRetentionPeriod: enablePerformanceInsights + ? (props.performanceInsightRetention || PerformanceInsightRetention.DEFAULT) + : undefined, + dbParameterGroupName: instanceParameterGroupConfig?.parameterGroupName, + monitoringInterval: props.monitoringInterval && props.monitoringInterval.toSeconds(), + monitoringRoleArn: props.monitoringRole && props.monitoringRole.roleArn, + autoMinorVersionUpgrade: props.autoMinorVersionUpgrade, + allowMajorVersionUpgrade: props.allowMajorVersionUpgrade, + }); + // For instances that are part of a cluster: + // + // Cluster DESTROY or SNAPSHOT -> DESTROY (snapshot is good enough to recreate) + // Cluster RETAIN -> RETAIN (otherwise cluster state will disappear) + instance.applyRemovalPolicy(helperRemovalPolicy(props.removalPolicy)); + + // We must have a dependency on the NAT gateway provider here to create + // things in the right order. + if (internetConnected) { + instance.node.addDependency(internetConnected); + } + + this.dbInstanceArn = this.getResourceArnAttribute(instance.attrDbInstanceArn, { + resource: 'db', + service: 'rds', + arnFormat: ArnFormat.COLON_RESOURCE_NAME, + resourceName: this.physicalName, + }); + this.instanceIdentifier = this.getResourceNameAttribute(instance.ref); + this.dbiResourceId = instance.attrDbiResourceId; + this.dbInstanceEndpointAddress = instance.attrEndpointAddress; + } +} + +/** + * Turn a regular instance type into a database instance type + */ +function databaseInstanceType(instanceType: ClusterInstanceType) { + const type = instanceType.toString(); + return instanceType.type === InstanceType.SERVERLESS_V2 ? type : 'db.' + type; +} diff --git a/packages/aws-cdk-lib/aws-rds/lib/cluster.ts b/packages/aws-cdk-lib/aws-rds/lib/cluster.ts index 59528f6d8892b..a32245173cb8e 100644 --- a/packages/aws-cdk-lib/aws-rds/lib/cluster.ts +++ b/packages/aws-cdk-lib/aws-rds/lib/cluster.ts @@ -1,12 +1,5 @@ -import * as ec2 from '../../aws-ec2'; -import { IRole, ManagedPolicy, Role, ServicePrincipal } from '../../aws-iam'; -import * as kms from '../../aws-kms'; -import * as logs from '../../aws-logs'; -import * as s3 from '../../aws-s3'; -import * as secretsmanager from '../../aws-secretsmanager'; -import { Annotations, Duration, FeatureFlags, RemovalPolicy, Resource, Token } from '../../core'; -import * as cxapi from '../../cx-api'; import { Construct } from 'constructs'; +import { IAuroraClusterInstance, IClusterInstance, InstanceType } from './aurora-cluster-instance'; import { IClusterEngine } from './cluster-engine'; import { DatabaseClusterAttributes, IDatabaseCluster } from './cluster-ref'; import { DatabaseSecret } from './database-secret'; @@ -18,6 +11,15 @@ import { BackupProps, Credentials, InstanceProps, PerformanceInsightRetention, R import { DatabaseProxy, DatabaseProxyOptions, ProxyTarget } from './proxy'; import { CfnDBCluster, CfnDBClusterProps, CfnDBInstance } from './rds.generated'; import { ISubnetGroup, SubnetGroup } from './subnet-group'; +import * as cloudwatch from '../../aws-cloudwatch'; +import * as ec2 from '../../aws-ec2'; +import { IRole, ManagedPolicy, Role, ServicePrincipal } from '../../aws-iam'; +import * as kms from '../../aws-kms'; +import * as logs from '../../aws-logs'; +import * as s3 from '../../aws-s3'; +import * as secretsmanager from '../../aws-secretsmanager'; +import { Annotations, Duration, FeatureFlags, Lazy, RemovalPolicy, Resource, Token } from '../../core'; +import * as cxapi from '../../cx-api'; /** * Common properties for a new database cluster or cluster from snapshot. @@ -34,13 +36,74 @@ interface DatabaseClusterBaseProps { * Has to be at least 1. * * @default 2 + * @deprecated - use writer and readers instead */ readonly instances?: number; /** * Settings for the individual instances that are launched + * + * @deprecated - use writer and readers instead */ - readonly instanceProps: InstanceProps; + readonly instanceProps?: InstanceProps; + + /** + * The instance to use for the cluster writer + * + * @default required if instanceProps is not provided + */ + readonly writer?: IClusterInstance; + + /** + * A list of instances to create as cluster reader instances + * + * @default - no readers are created. The cluster will have a single writer/reader + */ + readonly readers?: IClusterInstance[]; + + /** + * The maximum number of Aurora capacity units (ACUs) for a DB instance in an Aurora Serverless v2 cluster. + * You can specify ACU values in half-step increments, such as 40, 40.5, 41, and so on. + * The largest value that you can use is 128 (256GB). + * + * The maximum capacity must be higher than 0.5 ACUs. + * @see https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-serverless-v2.setting-capacity.html#aurora-serverless-v2.max_capacity_considerations + * + * @default 2 + */ + readonly serverlessV2MaxCapacity?: number, + + /** + * The minimum number of Aurora capacity units (ACUs) for a DB instance in an Aurora Serverless v2 cluster. + * You can specify ACU values in half-step increments, such as 8, 8.5, 9, and so on. + * The smallest value that you can use is 0.5. + * + * @see https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-serverless-v2.setting-capacity.html#aurora-serverless-v2.max_capacity_considerations + * + * @default 0.5 + */ + readonly serverlessV2MinCapacity?: number; + + /** + * What subnets to run the RDS instances in. + * + * Must be at least 2 subnets in two different AZs. + */ + readonly vpc?: ec2.IVpc; + + /** + * Where to place the instances within the VPC + * + * @default - the Vpc default strategy if not specified. + */ + readonly vpcSubnets?: ec2.SubnetSelection; + + /** + * Security group. + * + * @default a new security group is created. + */ + readonly securityGroups?: ec2.ISecurityGroup[]; /** * The ordering of updates for instances @@ -354,6 +417,8 @@ export abstract class DatabaseClusterBase extends Resource implements IDatabaseC */ public abstract readonly connections: ec2.Connections; + protected hasServerlessInstance?: boolean; + /** * Add a new db proxy to this cluster. */ @@ -373,6 +438,150 @@ export abstract class DatabaseClusterBase extends Resource implements IDatabaseC targetType: secretsmanager.AttachmentTargetType.RDS_DB_CLUSTER, }; } + + + /** + * Create cluster instances + */ + protected createInstances(props: DatabaseClusterProps): InstanceConfig { + const instanceEndpoints: Endpoint[] = []; + const instanceIdentifiers: string[] = []; + const readers: IAuroraClusterInstance[] = []; + // need to create the writer first since writer is determined by what instance is first + const writer = props.writer!.bind(this, this, { + monitoringInterval: props.monitoringInterval, + monitoringRole: props.monitoringRole, + removalPolicy: props.removalPolicy ?? RemovalPolicy.SNAPSHOT, + promotionTier: 0, // override the promotion tier so that writers are always 0 + }); + (props.readers ?? []).forEach(instance => { + const clusterInstance = instance.bind(this, this, { + monitoringInterval: props.monitoringInterval, + monitoringRole: props.monitoringRole, + removalPolicy: props.removalPolicy ?? RemovalPolicy.SNAPSHOT, + }); + readers.push(clusterInstance); + + if (clusterInstance.tier < 2) { + this.validateReaderInstance(writer, clusterInstance); + } + instanceEndpoints.push(new Endpoint(clusterInstance.dbInstanceEndpointAddress, this.clusterEndpoint.port)); + instanceIdentifiers.push(clusterInstance.instanceIdentifier); + }); + this.validateClusterInstances(writer, readers); + + return { + instanceEndpoints, + instanceIdentifiers, + }; + } + + /** + * Perform validations on the cluster instances + */ + private validateClusterInstances(writer: IAuroraClusterInstance, readers: IAuroraClusterInstance[]): void { + if (writer.type === InstanceType.SERVERLESS_V2) { + this.hasServerlessInstance = true; + } + if (readers.length > 0) { + const sortedReaders = readers.sort((a, b) => a.tier - b.tier); + const highestTierReaders: IAuroraClusterInstance[] = []; + const highestTier = sortedReaders[0].tier; + let hasProvisionedReader = false; + let noFailoverTierInstances = true; + let serverlessInHighestTier = false; + let hasServerlessReader = false; + const someProvisionedReadersDontMatchWriter: IAuroraClusterInstance[] = []; + for (const reader of sortedReaders) { + if (reader.type === InstanceType.SERVERLESS_V2) { + hasServerlessReader = true; + this.hasServerlessInstance = true; + } else { + hasProvisionedReader = true; + if (reader.instanceSize !== writer.instanceSize) { + someProvisionedReadersDontMatchWriter.push(reader); + } + } + if (reader.tier === highestTier) { + if (reader.type === InstanceType.SERVERLESS_V2) { + serverlessInHighestTier = true; + } + highestTierReaders.push(reader); + } + if (reader.tier <= 1) { + noFailoverTierInstances = false; + } + } + const hasOnlyServerlessReaders = hasServerlessReader && !hasProvisionedReader; + if (hasOnlyServerlessReaders) { + if (noFailoverTierInstances) { + Annotations.of(this).addWarning( + `Cluster ${this.node.id} only has serverless readers and no reader is in promotion tier 0-1.`+ + 'Serverless readers in promotion tiers >= 2 will NOT scale with the writer, which can lead to '+ + 'availability issues if a failover event occurs. It is recommended that at least one reader '+ + 'has `scaleWithWriter` set to true', + ); + } + } else { + if (serverlessInHighestTier && highestTier > 1) { + Annotations.of(this).addWarning( + `There are serverlessV2 readers in tier ${highestTier}. Since there are no instances in a higher tier, `+ + 'any instance in this tier is a failover target. Since this tier is > 1 the serverless reader will not scale '+ + 'with the writer which could lead to availability issues during failover.', + ); + } + if (someProvisionedReadersDontMatchWriter.length > 0 && writer.type === InstanceType.PROVISIONED) { + Annotations.of(this).addWarning( + `There are provisioned readers in the highest promotion tier ${highestTier} that do not have the same `+ + 'InstanceSize as the writer. Any of these instances could be chosen as the new writer in the event '+ + 'of a failover.\n'+ + `Writer InstanceSize: ${writer.instanceSize}\n`+ + `Reader InstanceSizes: ${someProvisionedReadersDontMatchWriter.map(reader => reader.instanceSize).join(', ')}`, + ); + } + } + } + } + + /** + * Perform validations on the reader instance + */ + private validateReaderInstance(writer: IAuroraClusterInstance, reader: IAuroraClusterInstance): void { + if (writer.type === InstanceType.PROVISIONED) { + if (reader.type === InstanceType.SERVERLESS_V2) { + if (!instanceSizeSupportedByServerlessV2(writer.instanceSize!)) { + Annotations.of(this).addWarning( + 'For high availability any serverless instances in promotion tiers 0-1 '+ + 'should be able to scale to match the provisioned instance capacity.\n'+ + `Serverless instance ${reader.node.id} is in promotion tier ${reader.tier},\n`+ + `But can not scale to match the provisioned writer instance (${writer.instanceSize})`, + ); + } + } + } else { + // TODO: add some info around serverless instance tiers and matching scaling + Annotations.of(this).addInfo('...'); + } + } + + /** + * As a cluster-level metric, it represents the average of the ServerlessDatabaseCapacity + * values of all the Aurora Serverless v2 DB instances in the cluster. + */ + public metricServerlessDatabaseCapacity(props?: cloudwatch.MetricOptions) { + return this.metric('ServerlessDatabaseCapacity', { statistic: 'Average', ...props }); + } + + /** + * This value is represented as a percentage. It's calculated as the value of the + * ServerlessDatabaseCapacity metric divided by the maximum ACU value of the DB cluster. + * + * If this metric approaches a value of 100.0, the DB instance has scaled up as high as it can. + * Consider increasing the maximum ACU setting for the cluster. + */ + public metricACUUtilization(props?: cloudwatch.MetricOptions) { + return this.metric('ACUUtilization', { statistic: 'Average', ...props }); + } } /** @@ -414,16 +623,31 @@ abstract class DatabaseClusterNew extends DatabaseClusterBase { */ public readonly multiUserRotationApplication: secretsmanager.SecretRotationApplication; + protected readonly serverlessV2MinCapacity: number; + protected readonly serverlessV2MaxCapacity: number; + constructor(scope: Construct, id: string, props: DatabaseClusterBaseProps) { super(scope, id); - this.vpc = props.instanceProps.vpc; - this.vpcSubnets = props.instanceProps.vpcSubnets; + if ((props.vpc && props.instanceProps?.vpc)) { + throw new Error('Provide either vpc or instanceProps.vpc, but not both'); + } else if (!props.vpc && !props.instanceProps?.vpc) { + throw new Error('If instanceProps is not provided then `vpc` must be provided.'); + } + if ((props.vpcSubnets && props.instanceProps?.vpcSubnets)) { + throw new Error('Provide either vpcSubnets or instanceProps.vpcSubnets, but not both'); + } + this.vpc = props.instanceProps?.vpc ?? props.vpc!; + this.vpcSubnets = props.instanceProps?.vpcSubnets ?? props.vpcSubnets; this.singleUserRotationApplication = props.engine.singleUserRotationApplication; this.multiUserRotationApplication = props.engine.multiUserRotationApplication; - const { subnetIds } = props.instanceProps.vpc.selectSubnets(props.instanceProps.vpcSubnets); + this.serverlessV2MaxCapacity = props.serverlessV2MaxCapacity ?? 2; + this.serverlessV2MinCapacity = props.serverlessV2MinCapacity ?? 0.5; + this.validateServerlessScalingConfig(); + + const { subnetIds } = this.vpc.selectSubnets(this.vpcSubnets); // Cannot test whether the subnets are in different AZs, but at least we can test the amount. if (subnetIds.length < 2) { @@ -432,15 +656,15 @@ abstract class DatabaseClusterNew extends DatabaseClusterBase { this.subnetGroup = props.subnetGroup ?? new SubnetGroup(this, 'Subnets', { description: `Subnets for ${id} database`, - vpc: props.instanceProps.vpc, - vpcSubnets: props.instanceProps.vpcSubnets, + vpc: this.vpc, + vpcSubnets: this.vpcSubnets, removalPolicy: renderUnless(helperRemovalPolicy(props.removalPolicy), RemovalPolicy.DESTROY), }); - this.securityGroups = props.instanceProps.securityGroups ?? [ + this.securityGroups = props.instanceProps?.securityGroups ?? props.securityGroups ?? [ new ec2.SecurityGroup(this, 'SecurityGroup', { description: 'RDS security group', - vpc: props.instanceProps.vpc, + vpc: this.vpc, }), ]; @@ -498,6 +722,17 @@ abstract class DatabaseClusterNew extends DatabaseClusterBase { deletionProtection: defaultDeletionProtection(props.deletionProtection, props.removalPolicy), enableIamDatabaseAuthentication: props.iamAuthentication, networkType: props.networkType, + serverlessV2ScalingConfiguration: Lazy.any({ + produce: () => { + if (this.hasServerlessInstance) { + return { + minCapacity: this.serverlessV2MinCapacity, + maxCapacity: this.serverlessV2MaxCapacity, + }; + } + return undefined; + }, + }), // Admin backtrackWindow: props.backtrackWindow?.toSeconds(), backupRetentionPeriod: props.backup?.retention?.toDays(), @@ -513,6 +748,26 @@ abstract class DatabaseClusterNew extends DatabaseClusterBase { }; } + private validateServerlessScalingConfig(): void { + if (this.serverlessV2MaxCapacity > 128 || this.serverlessV2MaxCapacity < 0.5) { + throw new Error('serverlessV2MaxCapacity must be >= 0.5 & <= 128'); + } + + if (this.serverlessV2MinCapacity > 128 || this.serverlessV2MinCapacity < 0.5) { + throw new Error('serverlessV2MinCapacity must be >= 0.5 & <= 128'); + } + + if (this.serverlessV2MaxCapacity === 0.5 && this.serverlessV2MinCapacity === 0.5) { + throw new Error('If serverlessV2MinCapacity === 0.5 then serverlessV2MaxCapacity must be >=1'); + } + const regexp = new RegExp(/^[0-9]+\.?5?$/); + if (!regexp.test(this.serverlessV2MaxCapacity.toString()) || !regexp.test(this.serverlessV2MinCapacity.toString())) { + throw new Error('serverlessV2MinCapacity & serverlessV2MaxCapacity must be in 0.5 step increments, received '+ + `min: ${this.serverlessV2MaxCapacity}, max: ${this.serverlessV2MaxCapacity}`); + + } + } + /** * Adds the single user rotation of the master password to this cluster. * See [Single user rotation strategy](https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotating-secrets_strategies.html#rotating-secrets-one-user-one-password) @@ -698,10 +953,86 @@ export class DatabaseCluster extends DatabaseClusterNew { cluster.applyRemovalPolicy(props.removalPolicy ?? RemovalPolicy.SNAPSHOT); setLogRetention(this, props); - const createdInstances = createInstances(this, props, this.subnetGroup); + if ((props.writer || props.readers) && (props.instances || props.instanceProps)) { + throw new Error('Cannot provide writer or readers if instances or instanceProps are provided'); + } + + if (!props.instanceProps && !props.writer) { + throw new Error('writer must be provided'); + } + + const createdInstances = props.writer ? this.createInstances(props) : legacyCreateInstances(this, props, this.subnetGroup); this.instanceIdentifiers = createdInstances.instanceIdentifiers; this.instanceEndpoints = createdInstances.instanceEndpoints; } + +} + +/** + * RDS instances that require more memory than is supported by serverlessV2 + * + * The key is the instance type and the value is the minimum size that is NOT supported. + * Example, { m5: '24' } means that if the instance type is m5.24xlarge or above then + * it is not supported by serverless v2 because the memory requirement is > 256GB + */ +const UN_SUPPORTED_PROVISIONED_SIZES: { [type: string]: string } = { + m5: '24', + m5d: '24', + r6g: '12', + r5: '12', + r5b: '12', + r5d: '12', + r4: '16', + x2g: '4', + x1e: '4', + x1: '16', + z1d: '12', +}; + +/** + * This validates that the instance size falls within the maximum available serverless + * capacity (256GB memory). This does not validate whether the actual provided `serverlessV2MaxCapacity` + * is supported by the instance size. That would be ideal, but would also require having a mapping + * of instance size to total memory. + * + * @param instanceSize the instance size of the provisioned writer, e.g. r5.xlarge + * @returns true if the instance size is supported by serverless v2 instances + */ +function instanceSizeSupportedByServerlessV2(instanceSize: string): boolean { + + // i.e. r5.xlarge + const sizeParts = instanceSize.split('.'); + if (sizeParts.length === 2) { + const type = sizeParts[0]; + const size = sizeParts[1]; + if (size === 'xlarge') { + return true; + } else if (size.endsWith('xlarge')) { + const sizeNum = size.slice(0, -6); + if (UN_SUPPORTED_PROVISIONED_SIZES.hasOwnProperty(type)) { + const unSupported = UN_SUPPORTED_PROVISIONED_SIZES[type]; + if (sizeNum >= unSupported) { + return false; + } + } + } + } else { + // some weird non-standard instance types + // not sure how to add automation around this so for now + // just handling as one offs + const unSupportedSizes = [ + 'db.r5.2xlarge.tpc2.mem8x', + 'db.r5.4xlarge.tpc2.mem3x', + 'db.r5.4xlarge.tpc2.mem4x', + 'db.r5.6xlarge.tpc2.mem4x', + 'db.r5.8xlarge.tpc2.mem3x', + 'db.r5.12xlarge.tpc2.mem2x', + ]; + if (unSupportedSizes.includes(instanceSize)) { + return false; + } + } + return true; } /** @@ -819,7 +1150,10 @@ export class DatabaseClusterFromSnapshot extends DatabaseClusterNew { cluster.applyRemovalPolicy(props.removalPolicy ?? RemovalPolicy.SNAPSHOT); setLogRetention(this, props); - const createdInstances = createInstances(this, props, this.subnetGroup); + if ((props.writer || props.readers) && (props.instances || props.instanceProps)) { + throw new Error('Cannot provide clusterInstances if instances or instanceProps are provided'); + } + const createdInstances = props.writer ? this.createInstances(props) : legacyCreateInstances(this, props, this.subnetGroup); this.instanceIdentifiers = createdInstances.instanceIdentifiers; this.instanceEndpoints = createdInstances.instanceEndpoints; } @@ -859,7 +1193,7 @@ interface InstanceConfig { * A function rather than a protected method on ``DatabaseClusterNew`` to avoid exposing * ``DatabaseClusterNew`` and ``DatabaseClusterBaseProps`` in the API. */ -function createInstances(cluster: DatabaseClusterNew, props: DatabaseClusterBaseProps, subnetGroup: ISubnetGroup): InstanceConfig { +function legacyCreateInstances(cluster: DatabaseClusterNew, props: DatabaseClusterBaseProps, subnetGroup: ISubnetGroup): InstanceConfig { const instanceCount = props.instances != null ? props.instances : 2; const instanceUpdateBehaviour = props.instanceUpdateBehaviour ?? InstanceUpdateBehaviour.BULK; if (Token.isUnresolved(instanceCount)) { @@ -872,7 +1206,7 @@ function createInstances(cluster: DatabaseClusterNew, props: DatabaseClusterBase const instanceIdentifiers: string[] = []; const instanceEndpoints: Endpoint[] = []; const portAttribute = cluster.clusterEndpoint.port; - const instanceProps = props.instanceProps; + const instanceProps = props.instanceProps!; // Get the actual subnet objects so we can depend on internet connectivity. const internetConnected = instanceProps.vpc.selectSubnets(instanceProps.vpcSubnets).internetConnectivityEstablished; @@ -936,9 +1270,9 @@ function createInstances(cluster: DatabaseClusterNew, props: DatabaseClusterBase dbParameterGroupName: instanceParameterGroupConfig?.parameterGroupName, monitoringInterval: props.monitoringInterval && props.monitoringInterval.toSeconds(), monitoringRoleArn: monitoringRole && monitoringRole.roleArn, - autoMinorVersionUpgrade: props.instanceProps.autoMinorVersionUpgrade, - allowMajorVersionUpgrade: props.instanceProps.allowMajorVersionUpgrade, - deleteAutomatedBackups: props.instanceProps.deleteAutomatedBackups, + autoMinorVersionUpgrade: instanceProps.autoMinorVersionUpgrade, + allowMajorVersionUpgrade: instanceProps.allowMajorVersionUpgrade, + deleteAutomatedBackups: instanceProps.deleteAutomatedBackups, }); // For instances that are part of a cluster: diff --git a/packages/aws-cdk-lib/aws-rds/lib/index.ts b/packages/aws-cdk-lib/aws-rds/lib/index.ts index 0ce8e5fee4018..fd7e157de0745 100644 --- a/packages/aws-cdk-lib/aws-rds/lib/index.ts +++ b/packages/aws-cdk-lib/aws-rds/lib/index.ts @@ -13,6 +13,7 @@ export * from './instance'; export * from './proxy'; export * from './serverless-cluster'; export * from './subnet-group'; +export * from './aurora-cluster-instance'; // AWS::RDS CloudFormation Resources: export * from './rds.generated'; diff --git a/packages/aws-cdk-lib/aws-rds/test/cluster.test.ts b/packages/aws-cdk-lib/aws-rds/test/cluster.test.ts index c94632e3d23df..6643ce01add8c 100644 --- a/packages/aws-cdk-lib/aws-rds/test/cluster.test.ts +++ b/packages/aws-cdk-lib/aws-rds/test/cluster.test.ts @@ -5,12 +5,729 @@ import * as kms from '../../aws-kms'; import * as logs from '../../aws-logs'; import * as s3 from '../../aws-s3'; import * as cdk from '../../core'; +import { RemovalPolicy, Stack } from '../../core'; import { AuroraEngineVersion, AuroraMysqlEngineVersion, AuroraPostgresEngineVersion, CfnDBCluster, Credentials, DatabaseCluster, DatabaseClusterEngine, DatabaseClusterFromSnapshot, ParameterGroup, PerformanceInsightRetention, SubnetGroup, DatabaseSecret, - DatabaseInstanceEngine, SqlServerEngineVersion, SnapshotCredentials, InstanceUpdateBehaviour, NetworkType, + DatabaseInstanceEngine, SqlServerEngineVersion, SnapshotCredentials, InstanceUpdateBehaviour, NetworkType, ClusterInstance, } from '../lib'; +describe('cluster new api', () => { + describe('errors are thrown', () => { + test('when old and new props are provided', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + expect(() => { + // WHEN + new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, + }, + writer: ClusterInstance.serverlessV2('writer'), + iamAuthentication: true, + }); + // THEN + }).toThrow(/Cannot provide writer or readers if instances or instanceProps are provided/); + }); + + test('when no instances are provided', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + expect(() => { + // WHEN + new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA, + vpc, + iamAuthentication: true, + }); + // THEN + }).toThrow(/writer must be provided/); + }); + + test('when vpc prop is not provided', () => { + // GIVEN + const stack = testStack(); + + expect(() => { + // WHEN + new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA, + writer: ClusterInstance.serverlessV2('writer'), + iamAuthentication: true, + }); + // THEN + }).toThrow(/If instanceProps is not provided then `vpc` must be provided./); + }); + + test('when both vpc and instanceProps.vpc are provided', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + expect(() => { + // WHEN + new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, + }, + vpc, + iamAuthentication: true, + }); + // THEN + }).toThrow(/Provide either vpc or instanceProps.vpc, but not both/); + }); + + test('when both vpcSubnets and instanceProps.vpcSubnets are provided', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + expect(() => { + // WHEN + new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpcSubnets: vpc.selectSubnets( { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS } ), + vpc, + }, + vpcSubnets: vpc.selectSubnets( { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS } ), + iamAuthentication: true, + }); + // THEN + }).toThrow(/Provide either vpcSubnets or instanceProps.vpcSubnets, but not both/); + }); + + test.each([ + [0.5, 200, /serverlessV2MaxCapacity must be >= 0.5 & <= 128/], + [0.5, 0, /serverlessV2MaxCapacity must be >= 0.5 & <= 128/], + [0, 1, /serverlessV2MinCapacity must be >= 0.5 & <= 128/], + [200, 1, /serverlessV2MinCapacity must be >= 0.5 & <= 128/], + [0.5, 0.5, /If serverlessV2MinCapacity === 0.5 then serverlessV2MaxCapacity must be >=1/], + [10.1, 12, /serverlessV2MinCapacity & serverlessV2MaxCapacity must be in 0.5 step increments/], + [12, 12.1, /serverlessV2MinCapacity & serverlessV2MaxCapacity must be in 0.5 step increments/], + ])('when serverless capacity is incorrect', (minCapacity, maxCapacity, errorMessage) => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + expect(() => { + // WHEN + new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA, + vpc, + vpcSubnets: vpc.selectSubnets( { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS } ), + serverlessV2MaxCapacity: maxCapacity, + serverlessV2MinCapacity: minCapacity, + iamAuthentication: true, + }); + // THEN + }).toThrow(errorMessage); + }); + }); + + describe('cluster options', () => { + test('with serverless instances', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA, + vpc, + writer: ClusterInstance.serverlessV2('writer'), + iamAuthentication: true, + }); + + // THEN + const template = Template.fromStack(stack); + // serverless scaling config is set + template.hasResourceProperties('AWS::RDS::DBCluster', Match.objectLike({ + ServerlessV2ScalingConfiguration: { + MinCapacity: 0.5, + MaxCapacity: 2, + }, + })); + + // subnets are set correctly + template.hasResourceProperties('AWS::RDS::DBSubnetGroup', { + DBSubnetGroupDescription: 'Subnets for Database database', + SubnetIds: [ + { Ref: 'VPCPrivateSubnet1Subnet8BCA10E0' }, + { Ref: 'VPCPrivateSubnet2SubnetCFCDAA7A' }, + { Ref: 'VPCPrivateSubnet3Subnet3EDCD457' }, + ], + }); + }); + + test('vpcSubnets can be provided', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA, + vpc, + vpcSubnets: vpc.selectSubnets({ subnetType: ec2.SubnetType.PUBLIC }), + writer: ClusterInstance.serverlessV2('writer'), + iamAuthentication: true, + }); + + // THEN + const template = Template.fromStack(stack); + // serverless scaling config is set + template.hasResourceProperties('AWS::RDS::DBCluster', Match.objectLike({ + ServerlessV2ScalingConfiguration: { + MinCapacity: 0.5, + MaxCapacity: 2, + }, + })); + + // subnets are set correctly + template.hasResourceProperties('AWS::RDS::DBSubnetGroup', { + DBSubnetGroupDescription: 'Subnets for Database database', + SubnetIds: [ + { Ref: 'VPCPublicSubnet1SubnetB4246D30' }, + { Ref: 'VPCPublicSubnet2Subnet74179F39' }, + { Ref: 'VPCPublicSubnet3Subnet631C5E25' }, + ], + }); + }); + }); + + describe('migrate from instanceProps', () => { + test('', () => { + // GIVEN + const stack1 = testStack(); + const stack2 = testStack(); + + function createCase(stack: Stack) { + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + const pg = new ParameterGroup(stack, 'pg', { + engine: DatabaseClusterEngine.AURORA, + }); + const sg = new ec2.SecurityGroup(stack, 'sg', { + vpc, + }); + const instanceProps = { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, + allowMajorVersionUpgrade: true, + autoMinorVersionUpgrade: true, + deleteAutomatedBackups: true, + enablePerformanceInsights: true, + parameterGroup: pg, + securityGroups: [sg], + }; + return instanceProps; + } + const test1 = createCase(stack1); + const test2 = createCase(stack2); + new DatabaseCluster(stack1, 'Database', { + engine: DatabaseClusterEngine.AURORA, + instanceProps: test1, + iamAuthentication: true, + }); + + const clusterInstances = ClusterInstance.fromInstanceProps(test2); + new DatabaseCluster(stack2, 'Database', { + engine: DatabaseClusterEngine.AURORA, + vpc: test2.vpc, + securityGroups: test2.securityGroups, + writer: clusterInstances[0], + readers: [...clusterInstances.slice(1)], + iamAuthentication: true, + }); + + // THEN + const test1Template = Template.fromStack(stack1).toJSON(); + // Dbsubnetgroup is not needed on the instance, it is set on the cluster + delete test1Template.Resources.DatabaseInstance1844F58FD.Properties.DBSubnetGroupName; + // deleteAutomatedBackups is not needed on the instance, it is set on the cluster + delete test1Template.Resources.DatabaseInstance1844F58FD.Properties.DeleteAutomatedBackups; + delete test1Template.Resources.DatabaseInstance2AA380DEE.Properties.DBSubnetGroupName; + delete test1Template.Resources.DatabaseInstance2AA380DEE.Properties.DeleteAutomatedBackups; + expect( + test1Template, + ).toEqual(Template.fromStack(stack2).toJSON()); + }); + }); + + describe('creates a writer instance', () => { + test('serverlessV2 writer', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA, + vpc, + writer: ClusterInstance.serverlessV2('writer'), + iamAuthentication: true, + }); + + // THEN + const template = Template.fromStack(stack); + // only the writer gets created + template.resourceCountIs('AWS::RDS::DBInstance', 1); + template.hasResourceProperties('AWS::RDS::DBInstance', { + DBClusterIdentifier: { Ref: 'DatabaseB269D8BB' }, + DBInstanceClass: 'db.serverless', + Engine: 'aurora', + PromotionTier: 0, + }); + }); + + test('serverlessV2 writer with config', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new DatabaseCluster(stack, 'Database', { + removalPolicy: RemovalPolicy.RETAIN, + engine: DatabaseClusterEngine.AURORA, + vpc, + writer: ClusterInstance.serverlessV2('writer', { + allowMajorVersionUpgrade: true, + autoMinorVersionUpgrade: true, + enablePerformanceInsights: true, + parameterGroup: new ParameterGroup(stack, 'pg', { engine: DatabaseClusterEngine.AURORA }), + }), + }); + + // THEN + const template = Template.fromStack(stack); + // only the writer gets created + template.resourceCountIs('AWS::RDS::DBInstance', 1); + template.hasResource('AWS::RDS::DBInstance', { + Properties: { + AllowMajorVersionUpgrade: true, + AutoMinorVersionUpgrade: true, + DBClusterIdentifier: { Ref: 'DatabaseB269D8BB' }, + DBInstanceClass: 'db.serverless', + DBParameterGroupName: { Ref: 'pg749EE6ED' }, + EnablePerformanceInsights: true, + Engine: 'aurora', + PerformanceInsightsRetentionPeriod: 7, + PromotionTier: 0, + }, + UpdateReplacePolicy: 'Retain', + Type: 'AWS::RDS::DBInstance', + }); + }); + + test('provisioned writer', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA, + vpc, + writer: ClusterInstance.provisioned('writer'), + iamAuthentication: true, + }); + + // THEN + const template = Template.fromStack(stack); + // only the writer gets created + template.resourceCountIs('AWS::RDS::DBInstance', 1); + template.hasResourceProperties('AWS::RDS::DBInstance', { + DBClusterIdentifier: { Ref: 'DatabaseB269D8BB' }, + DBInstanceClass: 'db.t3.medium', + PromotionTier: 0, + }); + }); + + test('provisioned writer with config', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA, + vpc, + writer: ClusterInstance.provisioned('writer', { + allowMajorVersionUpgrade: true, + autoMinorVersionUpgrade: true, + enablePerformanceInsights: true, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.C4, ec2.InstanceSize.LARGE ), + parameterGroup: new ParameterGroup(stack, 'pg', { engine: DatabaseClusterEngine.AURORA }), + }), + iamAuthentication: true, + }); + + // THEN + const template = Template.fromStack(stack); + + // only the writer gets created + template.resourceCountIs('AWS::RDS::DBInstance', 1); + template.hasResourceProperties('AWS::RDS::DBInstance', { + AllowMajorVersionUpgrade: true, + AutoMinorVersionUpgrade: true, + DBClusterIdentifier: { Ref: 'DatabaseB269D8BB' }, + DBInstanceClass: 'db.c4.large', + DBParameterGroupName: { Ref: 'pg749EE6ED' }, + EnablePerformanceInsights: true, + Engine: 'aurora', + PerformanceInsightsRetentionPeriod: 7, + PromotionTier: 0, + }); + }); + }); + + describe('provisioned writer with serverless readers', () => { + test('serverless reader in promotion tier 2 throws warning', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + const cluster = new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA, + vpc, + writer: ClusterInstance.provisioned('writer'), + readers: [ClusterInstance.serverlessV2('reader')], + iamAuthentication: true, + }); + + // THEN + const template = Template.fromStack(stack); + template.resourceCountIs('AWS::RDS::DBInstance', 2); + template.hasResourceProperties('AWS::RDS::DBInstance', { + DBClusterIdentifier: { Ref: 'DatabaseB269D8BB' }, + DBInstanceClass: 'db.t3.medium', + PromotionTier: 0, + }); + + template.hasResourceProperties('AWS::RDS::DBInstance', { + DBClusterIdentifier: { Ref: 'DatabaseB269D8BB' }, + DBInstanceClass: 'db.serverless', + PromotionTier: 2, + }); + + Annotations.fromStack(stack).hasWarning('*', + `Cluster ${cluster.node.id} only has serverless readers and no reader is in promotion tier 0-1.`+ + 'Serverless readers in promotion tiers >= 2 will NOT scale with the writer, which can lead to '+ + 'availability issues if a failover event occurs. It is recommended that at least one reader '+ + 'has `scaleWithWriter` set to true', + ); + }); + + test('serverless reader in promotion tier 1', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA, + vpc, + writer: ClusterInstance.provisioned('writer'), + readers: [ClusterInstance.serverlessV2('reader', { scaleWithWriter: true })], + iamAuthentication: true, + }); + + // THEN + const template = Template.fromStack(stack); + template.resourceCountIs('AWS::RDS::DBInstance', 2); + template.hasResourceProperties('AWS::RDS::DBInstance', { + DBClusterIdentifier: { Ref: 'DatabaseB269D8BB' }, + DBInstanceClass: 'db.t3.medium', + PromotionTier: 0, + }); + + template.hasResourceProperties('AWS::RDS::DBInstance', { + DBClusterIdentifier: { Ref: 'DatabaseB269D8BB' }, + DBInstanceClass: 'db.serverless', + PromotionTier: 1, + }); + + Annotations.fromStack(stack).hasNoWarning('*', '*'); + }); + + test('serverless reader cannot scale with writer, throw warning', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA, + vpc, + writer: ClusterInstance.provisioned('writer', { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.M5, ec2.InstanceSize.XLARGE24 ), + }), + readers: [ClusterInstance.serverlessV2('reader', { scaleWithWriter: true })], + iamAuthentication: true, + }); + + // THEN + const template = Template.fromStack(stack); + template.resourceCountIs('AWS::RDS::DBInstance', 2); + template.hasResourceProperties('AWS::RDS::DBInstance', { + DBClusterIdentifier: { Ref: 'DatabaseB269D8BB' }, + DBInstanceClass: 'db.m5.24xlarge', + PromotionTier: 0, + }); + + template.hasResourceProperties('AWS::RDS::DBInstance', { + DBClusterIdentifier: { Ref: 'DatabaseB269D8BB' }, + DBInstanceClass: 'db.serverless', + PromotionTier: 1, + }); + + Annotations.fromStack(stack).hasWarning('*', + 'For high availability any serverless instances in promotion tiers 0-1 '+ + 'should be able to scale to match the provisioned instance capacity.\n'+ + 'Serverless instance reader is in promotion tier 1,\n'+ + 'But can not scale to match the provisioned writer instance (m5.24xlarge)', + ); + }); + }); + + describe('provisioned writer and readers', () => { + test('single reader', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA, + vpc, + writer: ClusterInstance.provisioned('writer', { + // instanceType: ec2.InstanceType.of(ec2.InstanceClass.M5, ec2.InstanceSize.XLARGE24 ), + }), + readers: [ClusterInstance.provisioned('reader')], + }); + + // THEN + const template = Template.fromStack(stack); + template.resourceCountIs('AWS::RDS::DBInstance', 2); + template.hasResourceProperties('AWS::RDS::DBInstance', { + DBClusterIdentifier: { Ref: 'DatabaseB269D8BB' }, + DBInstanceClass: 'db.t3.medium', + PromotionTier: 0, + }); + + template.hasResourceProperties('AWS::RDS::DBInstance', { + DBClusterIdentifier: { Ref: 'DatabaseB269D8BB' }, + DBInstanceClass: 'db.t3.medium', + PromotionTier: 2, + }); + + Annotations.fromStack(stack).hasNoWarning('*', '*'); + }); + + test('throws warning if instance types do not match', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA, + vpc, + writer: ClusterInstance.provisioned('writer', { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.M5, ec2.InstanceSize.XLARGE24 ), + }), + readers: [ + ClusterInstance.provisioned('reader'), + ClusterInstance.provisioned('reader2', { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.M5, ec2.InstanceSize.XLARGE ), + }), + ], + }); + + // THEN + const template = Template.fromStack(stack); + template.resourceCountIs('AWS::RDS::DBInstance', 3); + template.hasResourceProperties('AWS::RDS::DBInstance', { + DBClusterIdentifier: { Ref: 'DatabaseB269D8BB' }, + DBInstanceClass: 'db.m5.24xlarge', + PromotionTier: 0, + }); + template.hasResourceProperties('AWS::RDS::DBInstance', { + DBClusterIdentifier: { Ref: 'DatabaseB269D8BB' }, + DBInstanceClass: 'db.t3.medium', + PromotionTier: 2, + }); + template.hasResourceProperties('AWS::RDS::DBInstance', { + DBClusterIdentifier: { Ref: 'DatabaseB269D8BB' }, + DBInstanceClass: 'db.m5.xlarge', + PromotionTier: 2, + }); + + Annotations.fromStack(stack).hasWarning('*', + 'There are provisioned readers in the highest promotion tier 2 that do not have the same '+ + 'InstanceSize as the writer. Any of these instances could be chosen as the new writer in the event '+ + 'of a failover.\n'+ + 'Writer InstanceSize: m5.24xlarge\n'+ + 'Reader InstanceSizes: t3.medium, m5.xlarge', + ); + }); + + test('does not throw warning if highest tier matches', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA, + vpc, + writer: ClusterInstance.provisioned('writer', { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.M5, ec2.InstanceSize.XLARGE24 ), + }), + readers: [ + ClusterInstance.provisioned('reader'), + ClusterInstance.provisioned('reader2', { + promotionTier: 1, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.M5, ec2.InstanceSize.XLARGE24 ), + }), + ], + }); + + // THEN + const template = Template.fromStack(stack); + template.resourceCountIs('AWS::RDS::DBInstance', 3); + template.hasResourceProperties('AWS::RDS::DBInstance', { + DBClusterIdentifier: { Ref: 'DatabaseB269D8BB' }, + DBInstanceClass: 'db.m5.24xlarge', + PromotionTier: 0, + }); + template.hasResourceProperties('AWS::RDS::DBInstance', { + DBClusterIdentifier: { Ref: 'DatabaseB269D8BB' }, + DBInstanceClass: 'db.t3.medium', + PromotionTier: 2, + }); + template.hasResourceProperties('AWS::RDS::DBInstance', { + DBClusterIdentifier: { Ref: 'DatabaseB269D8BB' }, + DBInstanceClass: 'db.m5.24xlarge', + PromotionTier: 1, + }); + + Annotations.fromStack(stack).hasNoWarning('*', '*'); + }); + }); + + describe('mixed readers', () => { + test('no warnings', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA, + vpc, + writer: ClusterInstance.provisioned('writer', { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.M5, ec2.InstanceSize.XLARGE24 ), + }), + readers: [ + ClusterInstance.serverlessV2('reader'), + ClusterInstance.provisioned('reader2', { + promotionTier: 1, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.M5, ec2.InstanceSize.XLARGE24 ), + }), + ], + }); + + // THEN + const template = Template.fromStack(stack); + template.resourceCountIs('AWS::RDS::DBInstance', 3); + template.hasResourceProperties('AWS::RDS::DBInstance', { + DBClusterIdentifier: { Ref: 'DatabaseB269D8BB' }, + DBInstanceClass: 'db.m5.24xlarge', + PromotionTier: 0, + }); + template.hasResourceProperties('AWS::RDS::DBInstance', { + DBClusterIdentifier: { Ref: 'DatabaseB269D8BB' }, + DBInstanceClass: 'db.serverless', + PromotionTier: 2, + }); + template.hasResourceProperties('AWS::RDS::DBInstance', { + DBClusterIdentifier: { Ref: 'DatabaseB269D8BB' }, + DBInstanceClass: 'db.m5.24xlarge', + PromotionTier: 1, + }); + + Annotations.fromStack(stack).hasNoWarning('*', '*'); + }); + + test('throws warning if not scaling with writer', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new DatabaseCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA, + vpc, + writer: ClusterInstance.provisioned('writer', { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.M5, ec2.InstanceSize.XLARGE24 ), + }), + readers: [ + ClusterInstance.serverlessV2('reader'), + ClusterInstance.provisioned('reader2', { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.M5, ec2.InstanceSize.XLARGE ), + }), + ], + }); + + // THEN + const template = Template.fromStack(stack); + template.resourceCountIs('AWS::RDS::DBInstance', 3); + template.hasResourceProperties('AWS::RDS::DBInstance', { + DBClusterIdentifier: { Ref: 'DatabaseB269D8BB' }, + DBInstanceClass: 'db.m5.24xlarge', + PromotionTier: 0, + }); + template.hasResourceProperties('AWS::RDS::DBInstance', { + DBClusterIdentifier: { Ref: 'DatabaseB269D8BB' }, + DBInstanceClass: 'db.serverless', + PromotionTier: 2, + }); + template.hasResourceProperties('AWS::RDS::DBInstance', { + DBClusterIdentifier: { Ref: 'DatabaseB269D8BB' }, + DBInstanceClass: 'db.m5.xlarge', + PromotionTier: 2, + }); + + Annotations.fromStack(stack).hasWarning('*', + 'There are serverlessV2 readers in tier 2. Since there are no instances in a higher tier, '+ + 'any instance in this tier is a failover target. Since this tier is > 1 the serverless reader will not scale '+ + 'with the writer which could lead to availability issues during failover.', + ); + + Annotations.fromStack(stack).hasWarning('*', + 'There are provisioned readers in the highest promotion tier 2 that do not have the same '+ + 'InstanceSize as the writer. Any of these instances could be chosen as the new writer in the event '+ + 'of a failover.\n'+ + 'Writer InstanceSize: m5.24xlarge\n'+ + 'Reader InstanceSizes: m5.xlarge', + ); + }); + }); +}); + describe('cluster', () => { test('creating a Cluster also creates 2 DB Instances', () => { // GIVEN From 20f1f9b25638d084a2d7947ded582cc5f7d51e1d Mon Sep 17 00:00:00 2001 From: corymhall <43035978+corymhall@users.noreply.github.com> Date: Thu, 25 May 2023 15:50:16 +0000 Subject: [PATCH 06/10] updates --- .../test/aws-rds/test/integ.cluster-dual.ts | 34 +- .../aws-cdk-rds-cluster-rotation.assets.json | 6 +- ...aws-cdk-rds-cluster-rotation.template.json | 24 +- .../cdk.out | 2 +- .../integ.json | 2 +- .../manifest.json | 52 +-- .../tree.json | 418 ++++++++++-------- .../test/integ.cluster-rotation.lit.ts | 38 +- .../aws-cdk-rds-s3-integ.assets.json | 6 +- .../aws-cdk-rds-s3-integ.template.json | 70 +-- .../test/integ.cluster-s3.js.snapshot/cdk.out | 2 +- .../integ.cluster-s3.js.snapshot/integ.json | 2 +- .../manifest.json | 66 ++- .../integ.cluster-s3.js.snapshot/tree.json | 378 +++++++--------- .../aws-rds/test/integ.cluster-s3.mysql-8.ts | 4 +- .../test/aws-rds/test/integ.cluster-s3.ts | 25 +- ...eg-aurora-serverlessv2-cluster.assets.json | 4 +- ...-aurora-serverlessv2-cluster.template.json | 120 +++++ .../manifest.json | 38 +- .../tree.json | 408 +++++++++++++---- .../test/integ.cluster-serverless-v2.ts | 19 +- .../aws-rds/test/integ.cluster-snapshot.ts | 31 +- .../aws-cdk-rds-integ.assets.json | 6 +- .../aws-cdk-rds-integ.template.json | 13 +- .../test/integ.cluster.js.snapshot/cdk.out | 2 +- .../test/integ.cluster.js.snapshot/integ.json | 2 +- .../integ.cluster.js.snapshot/manifest.json | 4 +- .../test/integ.cluster.js.snapshot/tree.json | 247 ++++++----- .../test/aws-rds/test/integ.cluster.ts | 29 +- packages/aws-cdk-lib/aws-rds/README.md | 82 +++- .../aws-rds/lib/aurora-cluster-instance.ts | 189 +++++--- packages/aws-cdk-lib/aws-rds/lib/cluster.ts | 364 +++++++-------- .../aws-cdk-lib/aws-rds/test/cluster.test.ts | 36 +- 33 files changed, 1687 insertions(+), 1036 deletions(-) diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-dual.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-dual.ts index 930f482b7b06d..d2c7d94725317 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-dual.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-dual.ts @@ -14,14 +14,23 @@ vpc.isolatedSubnets.forEach((subnet, idx) => { cfnSubnet.addDependsOn(ipv6); }); +const instanceProps = { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE3, ec2.InstanceSize.MEDIUM), + isFromLegacyInstanceProps: true, +}; new rds.DatabaseCluster(stack, 'DualstackCluster', { engine: rds.DatabaseClusterEngine.auroraMysql({ version: rds.AuroraMysqlEngineVersion.VER_3_02_0 }), credentials: rds.Credentials.fromUsername('admin', { password: cdk.SecretValue.unsafePlainText('7959866cacc02c2d243ecfe177464fe6') }), - instanceProps: { - instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE3, ec2.InstanceSize.MEDIUM), - vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED }, - vpc, - }, + writer: rds.ClusterInstance.provisioned('Instance1', { + ...instanceProps, + }), + readers: [ + rds.ClusterInstance.provisioned('Instance2', { + ...instanceProps, + }), + ], + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED }, + vpc, networkType: rds.NetworkType.DUAL, removalPolicy: cdk.RemovalPolicy.DESTROY, }); @@ -29,11 +38,16 @@ new rds.DatabaseCluster(stack, 'DualstackCluster', { new rds.DatabaseCluster(stack, 'Ipv4Cluster', { engine: rds.DatabaseClusterEngine.auroraMysql({ version: rds.AuroraMysqlEngineVersion.VER_3_02_0 }), credentials: rds.Credentials.fromUsername('admin', { password: cdk.SecretValue.unsafePlainText('7959866cacc02c2d243ecfe177464fe6') }), - instanceProps: { - instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE3, ec2.InstanceSize.MEDIUM), - vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED }, - vpc, - }, + vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED }, + vpc, + writer: rds.ClusterInstance.provisioned('Instance1', { + ...instanceProps, + }), + readers: [ + rds.ClusterInstance.provisioned('Instance2', { + ...instanceProps, + }), + ], networkType: rds.NetworkType.IPV4, removalPolicy: cdk.RemovalPolicy.DESTROY, }); diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-rotation.lit.js.snapshot/aws-cdk-rds-cluster-rotation.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-rotation.lit.js.snapshot/aws-cdk-rds-cluster-rotation.assets.json index 6256aa3105eec..a6d7a71f73597 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-rotation.lit.js.snapshot/aws-cdk-rds-cluster-rotation.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-rotation.lit.js.snapshot/aws-cdk-rds-cluster-rotation.assets.json @@ -1,7 +1,7 @@ { - "version": "30.1.0", + "version": "31.0.0", "files": { - "f1be03db0810455e897d5600a00d7d089273d1f89b9a319be25928bf241a9490": { + "a633d33a056f9a9a775353c3902b2da4fa8318b43707e565b45a591da0888305": { "source": { "path": "aws-cdk-rds-cluster-rotation.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "f1be03db0810455e897d5600a00d7d089273d1f89b9a319be25928bf241a9490.json", + "objectKey": "a633d33a056f9a9a775353c3902b2da4fa8318b43707e565b45a591da0888305.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-rotation.lit.js.snapshot/aws-cdk-rds-cluster-rotation.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-rotation.lit.js.snapshot/aws-cdk-rds-cluster-rotation.template.json index 0252e7533406a..dcf03b6f8e08a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-rotation.lit.js.snapshot/aws-cdk-rds-cluster-rotation.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-rotation.lit.js.snapshot/aws-cdk-rds-cluster-rotation.template.json @@ -646,10 +646,12 @@ "Type": "AWS::RDS::DBCluster", "Properties": { "CopyTagsToSnapshot": true, + "DBClusterParameterGroupName": "default.aurora-mysql8.0", "DBSubnetGroupName": { "Ref": "DatabaseSubnets56F17B9A" }, - "Engine": "aurora", + "Engine": "aurora-mysql", + "EngineVersion": "8.0.mysql_aurora.3.03.0", "MasterUsername": { "Fn::Join": [ "", @@ -692,11 +694,11 @@ "DBClusterIdentifier": { "Ref": "DatabaseB269D8BB" }, - "DBInstanceClass": "db.t3.small", + "DBInstanceClass": "db.t3.medium", "DBSubnetGroupName": { "Ref": "DatabaseSubnets56F17B9A" }, - "Engine": "aurora" + "Engine": "aurora-mysql" }, "DependsOn": [ "VPCPrivateSubnet1DefaultRouteAE1D6490", @@ -713,11 +715,11 @@ "DBClusterIdentifier": { "Ref": "DatabaseB269D8BB" }, - "DBInstanceClass": "db.t3.small", + "DBInstanceClass": "db.t3.medium", "DBSubnetGroupName": { "Ref": "DatabaseSubnets56F17B9A" }, - "Engine": "aurora" + "Engine": "aurora-mysql" }, "DependsOn": [ "VPCPrivateSubnet1DefaultRouteAE1D6490", @@ -964,10 +966,12 @@ "Type": "AWS::RDS::DBCluster", "Properties": { "CopyTagsToSnapshot": true, + "DBClusterParameterGroupName": "default.aurora-mysql8.0", "DBSubnetGroupName": { "Ref": "CustomRotationOptionsSubnets52AEBCED" }, - "Engine": "aurora", + "Engine": "aurora-mysql", + "EngineVersion": "8.0.mysql_aurora.3.03.0", "MasterUsername": { "Fn::Join": [ "", @@ -1010,11 +1014,11 @@ "DBClusterIdentifier": { "Ref": "CustomRotationOptions7CA9E132" }, - "DBInstanceClass": "db.t3.small", + "DBInstanceClass": "db.t3.medium", "DBSubnetGroupName": { "Ref": "CustomRotationOptionsSubnets52AEBCED" }, - "Engine": "aurora" + "Engine": "aurora-mysql" }, "DependsOn": [ "VPCPrivateSubnet1DefaultRouteAE1D6490", @@ -1031,11 +1035,11 @@ "DBClusterIdentifier": { "Ref": "CustomRotationOptions7CA9E132" }, - "DBInstanceClass": "db.t3.small", + "DBInstanceClass": "db.t3.medium", "DBSubnetGroupName": { "Ref": "CustomRotationOptionsSubnets52AEBCED" }, - "Engine": "aurora" + "Engine": "aurora-mysql" }, "DependsOn": [ "VPCPrivateSubnet1DefaultRouteAE1D6490", diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-rotation.lit.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-rotation.lit.js.snapshot/cdk.out index b72fef144f05c..7925065efbcc4 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-rotation.lit.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-rotation.lit.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"30.1.0"} \ No newline at end of file +{"version":"31.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-rotation.lit.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-rotation.lit.js.snapshot/integ.json index 5bbe8121413b0..6bb0c26d856fa 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-rotation.lit.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-rotation.lit.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "30.1.0", + "version": "31.0.0", "testCases": { "integ.cluster-rotation.lit": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-rotation.lit.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-rotation.lit.js.snapshot/manifest.json index 0da5ccc5e746a..e7c77a659a445 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-rotation.lit.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-rotation.lit.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "30.1.0", + "version": "31.0.0", "artifacts": { "aws-cdk-rds-cluster-rotation.assets": { "type": "cdk:asset-manifest", @@ -17,7 +17,7 @@ "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/f1be03db0810455e897d5600a00d7d089273d1f89b9a319be25928bf241a9490.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/a633d33a056f9a9a775353c3902b2da4fa8318b43707e565b45a591da0888305.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -234,19 +234,28 @@ "/aws-cdk-rds-cluster-rotation/Database/Resource": [ { "type": "aws:cdk:logicalId", - "data": "DatabaseB269D8BB" + "data": "DatabaseB269D8BB", + "trace": [ + "!!DESTRUCTIVE_CHANGES: MAY_REPLACE" + ] } ], "/aws-cdk-rds-cluster-rotation/Database/Instance1": [ { "type": "aws:cdk:logicalId", - "data": "DatabaseInstance1844F58FD" + "data": "DatabaseInstance1844F58FD", + "trace": [ + "!!DESTRUCTIVE_CHANGES: MAY_REPLACE" + ] } ], "/aws-cdk-rds-cluster-rotation/Database/Instance2": [ { "type": "aws:cdk:logicalId", - "data": "DatabaseInstance2AA380DEE" + "data": "DatabaseInstance2AA380DEE", + "trace": [ + "!!DESTRUCTIVE_CHANGES: MAY_REPLACE" + ] } ], "/aws-cdk-rds-cluster-rotation/Database/RotationSingleUser/SecurityGroup/Resource": [ @@ -312,19 +321,28 @@ "/aws-cdk-rds-cluster-rotation/CustomRotationOptions/Resource": [ { "type": "aws:cdk:logicalId", - "data": "CustomRotationOptions7CA9E132" + "data": "CustomRotationOptions7CA9E132", + "trace": [ + "!!DESTRUCTIVE_CHANGES: MAY_REPLACE" + ] } ], "/aws-cdk-rds-cluster-rotation/CustomRotationOptions/Instance1": [ { "type": "aws:cdk:logicalId", - "data": "CustomRotationOptionsInstance1D693E87C" + "data": "CustomRotationOptionsInstance1D693E87C", + "trace": [ + "!!DESTRUCTIVE_CHANGES: MAY_REPLACE" + ] } ], "/aws-cdk-rds-cluster-rotation/CustomRotationOptions/Instance2": [ { "type": "aws:cdk:logicalId", - "data": "CustomRotationOptionsInstance2A21FADD8" + "data": "CustomRotationOptionsInstance2A21FADD8", + "trace": [ + "!!DESTRUCTIVE_CHANGES: MAY_REPLACE" + ] } ], "/aws-cdk-rds-cluster-rotation/CustomRotationOptions/RotationSingleUser/SARMapping": [ @@ -350,24 +368,6 @@ "type": "aws:cdk:logicalId", "data": "CheckBootstrapVersion" } - ], - "DatabaseSecretAttachmentPolicy5ACFE6CA": [ - { - "type": "aws:cdk:logicalId", - "data": "DatabaseSecretAttachmentPolicy5ACFE6CA", - "trace": [ - "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" - ] - } - ], - "CustomRotationOptionsSecretAttachmentPolicyAB818C64": [ - { - "type": "aws:cdk:logicalId", - "data": "CustomRotationOptionsSecretAttachmentPolicyAB818C64", - "trace": [ - "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" - ] - } ] }, "displayName": "aws-cdk-rds-cluster-rotation" diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-rotation.lit.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-rotation.lit.js.snapshot/tree.json index 5eefe4ba0e14b..49635bd17853e 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-rotation.lit.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-rotation.lit.js.snapshot/tree.json @@ -31,8 +31,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnVPC", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "PublicSubnet1": { @@ -75,16 +75,16 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSubnet", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Acl": { "id": "Acl", "path": "aws-cdk-rds-cluster-rotation/VPC/PublicSubnet1/Acl", "constructInfo": { - "fqn": "@aws-cdk/core.Resource", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "RouteTable": { @@ -105,8 +105,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnRouteTable", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "RouteTableAssociation": { @@ -124,8 +124,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSubnetRouteTableAssociation", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "DefaultRoute": { @@ -144,8 +144,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnRoute", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "EIP": { @@ -164,8 +164,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnEIP", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "NATGateway": { @@ -192,14 +192,14 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnNatGateway", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.PublicSubnet", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "PublicSubnet2": { @@ -242,16 +242,16 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSubnet", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Acl": { "id": "Acl", "path": "aws-cdk-rds-cluster-rotation/VPC/PublicSubnet2/Acl", "constructInfo": { - "fqn": "@aws-cdk/core.Resource", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "RouteTable": { @@ -272,8 +272,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnRouteTable", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "RouteTableAssociation": { @@ -291,8 +291,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSubnetRouteTableAssociation", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "DefaultRoute": { @@ -311,8 +311,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnRoute", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "EIP": { @@ -331,8 +331,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnEIP", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "NATGateway": { @@ -359,14 +359,14 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnNatGateway", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.PublicSubnet", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "PrivateSubnet1": { @@ -409,16 +409,16 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSubnet", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Acl": { "id": "Acl", "path": "aws-cdk-rds-cluster-rotation/VPC/PrivateSubnet1/Acl", "constructInfo": { - "fqn": "@aws-cdk/core.Resource", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "RouteTable": { @@ -439,8 +439,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnRouteTable", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "RouteTableAssociation": { @@ -458,8 +458,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSubnetRouteTableAssociation", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "DefaultRoute": { @@ -478,14 +478,14 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnRoute", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.PrivateSubnet", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "PrivateSubnet2": { @@ -528,16 +528,16 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSubnet", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Acl": { "id": "Acl", "path": "aws-cdk-rds-cluster-rotation/VPC/PrivateSubnet2/Acl", "constructInfo": { - "fqn": "@aws-cdk/core.Resource", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "RouteTable": { @@ -558,8 +558,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnRouteTable", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "RouteTableAssociation": { @@ -577,8 +577,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSubnetRouteTableAssociation", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "DefaultRoute": { @@ -597,14 +597,14 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnRoute", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.PrivateSubnet", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "IGW": { @@ -622,8 +622,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnInternetGateway", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "VPCGW": { @@ -641,14 +641,14 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnVPCGatewayAttachment", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.Vpc", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "SecurityGroup": { @@ -675,14 +675,14 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSecurityGroup", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.SecurityGroup", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Endpoint": { @@ -741,14 +741,14 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSecurityGroup", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.SecurityGroup", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Resource": { @@ -793,14 +793,14 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnVPCEndpoint", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.InterfaceVpcEndpoint", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Database": { @@ -829,14 +829,14 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-rds.CfnDBSubnetGroup", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-rds.SubnetGroup", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "SecurityGroup": { @@ -863,8 +863,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSecurityGroup", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "from awscdkrdsclusterrotationDatabaseRotationSingleUserSecurityGroup0FFF34B1:{IndirectPort}": { @@ -902,14 +902,22 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSecurityGroupIngress", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.SecurityGroup", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "AuroraMySqlDatabaseClusterEngineDefaultParameterGroup": { + "id": "AuroraMySqlDatabaseClusterEngineDefaultParameterGroup", + "path": "aws-cdk-rds-cluster-rotation/Database/AuroraMySqlDatabaseClusterEngineDefaultParameterGroup", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Secret": { @@ -942,8 +950,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-secretsmanager.CfnSecret", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Attachment": { @@ -966,8 +974,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-secretsmanager.CfnSecretTargetAttachment", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "RotationSchedule": { @@ -995,20 +1003,20 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-secretsmanager.CfnRotationSchedule", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-secretsmanager.RotationSchedule", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-secretsmanager.SecretTargetAttachment", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Policy": { @@ -1055,20 +1063,20 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-secretsmanager.CfnResourcePolicy", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-secretsmanager.ResourcePolicy", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-rds.DatabaseSecret", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Resource": { @@ -1078,10 +1086,12 @@ "aws:cdk:cloudformation:type": "AWS::RDS::DBCluster", "aws:cdk:cloudformation:props": { "copyTagsToSnapshot": true, + "dbClusterParameterGroupName": "default.aurora-mysql8.0", "dbSubnetGroupName": { "Ref": "DatabaseSubnets56F17B9A" }, - "engine": "aurora", + "engine": "aurora-mysql", + "engineVersion": "8.0.mysql_aurora.3.03.0", "masterUsername": { "Fn::Join": [ "", @@ -1117,8 +1127,16 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-rds.CfnDBCluster", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "Instance1Wrapper": { + "id": "Instance1Wrapper", + "path": "aws-cdk-rds-cluster-rotation/Database/Instance1Wrapper", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Instance1": { @@ -1130,16 +1148,24 @@ "dbClusterIdentifier": { "Ref": "DatabaseB269D8BB" }, - "dbInstanceClass": "db.t3.small", + "dbInstanceClass": "db.t3.medium", "dbSubnetGroupName": { "Ref": "DatabaseSubnets56F17B9A" }, - "engine": "aurora" + "engine": "aurora-mysql" } }, "constructInfo": { - "fqn": "@aws-cdk/aws-rds.CfnDBInstance", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "Instance2Wrapper": { + "id": "Instance2Wrapper", + "path": "aws-cdk-rds-cluster-rotation/Database/Instance2Wrapper", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Instance2": { @@ -1151,16 +1177,16 @@ "dbClusterIdentifier": { "Ref": "DatabaseB269D8BB" }, - "dbInstanceClass": "db.t3.small", + "dbInstanceClass": "db.t3.medium", "dbSubnetGroupName": { "Ref": "DatabaseSubnets56F17B9A" }, - "engine": "aurora" + "engine": "aurora-mysql" } }, "constructInfo": { - "fqn": "@aws-cdk/aws-rds.CfnDBInstance", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "RotationSingleUser": { @@ -1191,22 +1217,22 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSecurityGroup", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.SecurityGroup", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "SARMapping": { "id": "SARMapping", "path": "aws-cdk-rds-cluster-rotation/Database/RotationSingleUser/SARMapping", "constructInfo": { - "fqn": "@aws-cdk/core.CfnMapping", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Resource": { @@ -1277,28 +1303,28 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-sam.CfnApplication", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "RotationLambda": { "id": "RotationLambda", "path": "aws-cdk-rds-cluster-rotation/Database/RotationSingleUser/RotationLambda", "constructInfo": { - "fqn": "@aws-cdk/aws-lambda.FunctionBase", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-secretsmanager.SecretRotation", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-rds.DatabaseCluster", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "CustomRotationOptions": { @@ -1327,14 +1353,14 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-rds.CfnDBSubnetGroup", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-rds.SubnetGroup", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "SecurityGroup": { @@ -1361,8 +1387,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSecurityGroup", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "from awscdkrdsclusterrotationSecurityGroupB986D266:{IndirectPort}": { @@ -1400,14 +1426,22 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSecurityGroupIngress", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.SecurityGroup", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "AuroraMySqlDatabaseClusterEngineDefaultParameterGroup": { + "id": "AuroraMySqlDatabaseClusterEngineDefaultParameterGroup", + "path": "aws-cdk-rds-cluster-rotation/CustomRotationOptions/AuroraMySqlDatabaseClusterEngineDefaultParameterGroup", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Secret": { @@ -1440,8 +1474,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-secretsmanager.CfnSecret", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Attachment": { @@ -1464,8 +1498,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-secretsmanager.CfnSecretTargetAttachment", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "RotationSchedule": { @@ -1493,20 +1527,20 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-secretsmanager.CfnRotationSchedule", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-secretsmanager.RotationSchedule", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-secretsmanager.SecretTargetAttachment", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Policy": { @@ -1553,20 +1587,20 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-secretsmanager.CfnResourcePolicy", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-secretsmanager.ResourcePolicy", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-rds.DatabaseSecret", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Resource": { @@ -1576,10 +1610,12 @@ "aws:cdk:cloudformation:type": "AWS::RDS::DBCluster", "aws:cdk:cloudformation:props": { "copyTagsToSnapshot": true, + "dbClusterParameterGroupName": "default.aurora-mysql8.0", "dbSubnetGroupName": { "Ref": "CustomRotationOptionsSubnets52AEBCED" }, - "engine": "aurora", + "engine": "aurora-mysql", + "engineVersion": "8.0.mysql_aurora.3.03.0", "masterUsername": { "Fn::Join": [ "", @@ -1615,8 +1651,16 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-rds.CfnDBCluster", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "Instance1Wrapper": { + "id": "Instance1Wrapper", + "path": "aws-cdk-rds-cluster-rotation/CustomRotationOptions/Instance1Wrapper", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Instance1": { @@ -1628,16 +1672,24 @@ "dbClusterIdentifier": { "Ref": "CustomRotationOptions7CA9E132" }, - "dbInstanceClass": "db.t3.small", + "dbInstanceClass": "db.t3.medium", "dbSubnetGroupName": { "Ref": "CustomRotationOptionsSubnets52AEBCED" }, - "engine": "aurora" + "engine": "aurora-mysql" } }, "constructInfo": { - "fqn": "@aws-cdk/aws-rds.CfnDBInstance", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "Instance2Wrapper": { + "id": "Instance2Wrapper", + "path": "aws-cdk-rds-cluster-rotation/CustomRotationOptions/Instance2Wrapper", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Instance2": { @@ -1649,16 +1701,16 @@ "dbClusterIdentifier": { "Ref": "CustomRotationOptions7CA9E132" }, - "dbInstanceClass": "db.t3.small", + "dbInstanceClass": "db.t3.medium", "dbSubnetGroupName": { "Ref": "CustomRotationOptionsSubnets52AEBCED" }, - "engine": "aurora" + "engine": "aurora-mysql" } }, "constructInfo": { - "fqn": "@aws-cdk/aws-rds.CfnDBInstance", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "RotationSingleUser": { @@ -1669,8 +1721,8 @@ "id": "SARMapping", "path": "aws-cdk-rds-cluster-rotation/CustomRotationOptions/RotationSingleUser/SARMapping", "constructInfo": { - "fqn": "@aws-cdk/core.CfnMapping", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Resource": { @@ -1745,50 +1797,50 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-sam.CfnApplication", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "RotationLambda": { "id": "RotationLambda", "path": "aws-cdk-rds-cluster-rotation/CustomRotationOptions/RotationSingleUser/RotationLambda", "constructInfo": { - "fqn": "@aws-cdk/aws-lambda.FunctionBase", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-secretsmanager.SecretRotation", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-rds.DatabaseCluster", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "BootstrapVersion": { "id": "BootstrapVersion", "path": "aws-cdk-rds-cluster-rotation/BootstrapVersion", "constructInfo": { - "fqn": "@aws-cdk/core.CfnParameter", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "CheckBootstrapVersion": { "id": "CheckBootstrapVersion", "path": "aws-cdk-rds-cluster-rotation/CheckBootstrapVersion", "constructInfo": { - "fqn": "@aws-cdk/core.CfnRule", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/core.Stack", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Tree": { @@ -1796,13 +1848,13 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.252" + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/core.App", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } } \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-rotation.lit.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-rotation.lit.ts index cb946fa6cc1e6..8d19ec6a1446c 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-rotation.lit.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-rotation.lit.ts @@ -13,22 +13,40 @@ const endpoint = new ec2.InterfaceVpcEndpoint(stack, 'Endpoint', { }); /// !show +const instanceProps = { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE3, ec2.InstanceSize.MEDIUM), + isFromLegacyInstanceProps: true, +}; const cluster = new rds.DatabaseCluster(stack, 'Database', { - engine: rds.DatabaseClusterEngine.AURORA, - instanceProps: { - instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE3, ec2.InstanceSize.SMALL), - vpc, - }, + engine: rds.DatabaseClusterEngine.auroraMysql({ + version: rds.AuroraMysqlEngineVersion.VER_3_03_0, + }), + vpc, + writer: rds.ClusterInstance.provisioned('Instance1', { + ...instanceProps, + }), + readers: [ + rds.ClusterInstance.provisioned('Instance2', { + ...instanceProps, + }), + ], }); cluster.addRotationSingleUser(); const clusterWithCustomRotationOptions = new rds.DatabaseCluster(stack, 'CustomRotationOptions', { - engine: rds.DatabaseClusterEngine.AURORA, - instanceProps: { - instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE3, ec2.InstanceSize.SMALL), - vpc, - }, + engine: rds.DatabaseClusterEngine.auroraMysql({ + version: rds.AuroraMysqlEngineVersion.VER_3_03_0, + }), + vpc, + writer: rds.ClusterInstance.provisioned('Instance1', { + ...instanceProps, + }), + readers: [ + rds.ClusterInstance.provisioned('Instance2', { + ...instanceProps, + }), + ], }); clusterWithCustomRotationOptions.addRotationSingleUser({ automaticallyAfter: cdk.Duration.days(7), diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-s3.js.snapshot/aws-cdk-rds-s3-integ.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-s3.js.snapshot/aws-cdk-rds-s3-integ.assets.json index 49bd5c22f83d4..5118531d2bf72 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-s3.js.snapshot/aws-cdk-rds-s3-integ.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-s3.js.snapshot/aws-cdk-rds-s3-integ.assets.json @@ -1,7 +1,7 @@ { - "version": "20.0.0", + "version": "31.0.0", "files": { - "8182c8bf4e17962cb28aa684c91f0d422b58d2f454a7088dc2ceebd8f32e89d7": { + "847a7253a365d747181fde2a1ce016fb160617357972f277a1dc32b6a4e60587": { "source": { "path": "aws-cdk-rds-s3-integ.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "8182c8bf4e17962cb28aa684c91f0d422b58d2f454a7088dc2ceebd8f32e89d7.json", + "objectKey": "847a7253a365d747181fde2a1ce016fb160617357972f277a1dc32b6a4e60587.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-s3.js.snapshot/aws-cdk-rds-s3-integ.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-s3.js.snapshot/aws-cdk-rds-s3-integ.template.json index 38bd36b82fa75..4e07f44f347c8 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-s3.js.snapshot/aws-cdk-rds-s3-integ.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-s3.js.snapshot/aws-cdk-rds-s3-integ.template.json @@ -543,40 +543,7 @@ ] } ] - } - ], - "Version": "2012-10-17" - }, - "PolicyName": "DatabaseS3ImportRoleDefaultPolicyA60A7342", - "Roles": [ - { - "Ref": "DatabaseS3ImportRole377BC9C0" - } - ] - } - }, - "DatabaseS3ExportRole9E328562": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "rds.amazonaws.com" - } - } - ], - "Version": "2012-10-17" - } - } - }, - "DatabaseS3ExportRoleDefaultPolicy8FEADB68": { - "Type": "AWS::IAM::Policy", - "Properties": { - "PolicyDocument": { - "Statement": [ + }, { "Action": [ "s3:Abort*", @@ -617,10 +584,10 @@ ], "Version": "2012-10-17" }, - "PolicyName": "DatabaseS3ExportRoleDefaultPolicy8FEADB68", + "PolicyName": "DatabaseS3ImportRoleDefaultPolicyA60A7342", "Roles": [ { - "Ref": "DatabaseS3ExportRole9E328562" + "Ref": "DatabaseS3ImportRole377BC9C0" } ] } @@ -628,20 +595,14 @@ "DatabaseClusterParameterGroupF2A52087": { "Type": "AWS::RDS::DBClusterParameterGroup", "Properties": { - "Description": "Cluster parameter group for aurora5.6", - "Family": "aurora5.6", + "Description": "Cluster parameter group for aurora-mysql8.0", + "Family": "aurora-mysql8.0", "Parameters": { - "aurora_load_from_s3_role": { + "aws_default_s3_role": { "Fn::GetAtt": [ "DatabaseS3ImportRole377BC9C0", "Arn" ] - }, - "aurora_select_into_s3_role": { - "Fn::GetAtt": [ - "DatabaseS3ExportRole9E328562", - "Arn" - ] } } } @@ -649,7 +610,6 @@ "DatabaseB269D8BB": { "Type": "AWS::RDS::DBCluster", "Properties": { - "Engine": "aurora", "AssociatedRoles": [ { "RoleArn": { @@ -658,14 +618,6 @@ "Arn" ] } - }, - { - "RoleArn": { - "Fn::GetAtt": [ - "DatabaseS3ExportRole9E328562", - "Arn" - ] - } } ], "CopyTagsToSnapshot": true, @@ -675,6 +627,8 @@ "DBSubnetGroupName": { "Ref": "DatabaseSubnets56F17B9A" }, + "Engine": "aurora-mysql", + "EngineVersion": "8.0.mysql_aurora.3.03.0", "KmsKeyId": { "Fn::GetAtt": [ "DbSecurity381C2C15", @@ -702,11 +656,11 @@ "DBClusterIdentifier": { "Ref": "DatabaseB269D8BB" }, - "DBInstanceClass": "db.t3.small", + "DBInstanceClass": "db.t3.medium", "DBSubnetGroupName": { "Ref": "DatabaseSubnets56F17B9A" }, - "Engine": "aurora", + "Engine": "aurora-mysql", "PubliclyAccessible": true }, "DependsOn": [ @@ -724,11 +678,11 @@ "DBClusterIdentifier": { "Ref": "DatabaseB269D8BB" }, - "DBInstanceClass": "db.t3.small", + "DBInstanceClass": "db.t3.medium", "DBSubnetGroupName": { "Ref": "DatabaseSubnets56F17B9A" }, - "Engine": "aurora", + "Engine": "aurora-mysql", "PubliclyAccessible": true }, "DependsOn": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-s3.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-s3.js.snapshot/cdk.out index 588d7b269d34f..7925065efbcc4 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-s3.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-s3.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"20.0.0"} \ No newline at end of file +{"version":"31.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-s3.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-s3.js.snapshot/integ.json index ea9819fe78ff3..66199c33ae19e 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-s3.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-s3.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "20.0.0", + "version": "31.0.0", "testCases": { "integ.cluster-s3": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-s3.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-s3.js.snapshot/manifest.json index caab81f394ff5..924980aa659b2 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-s3.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-s3.js.snapshot/manifest.json @@ -1,12 +1,6 @@ { - "version": "20.0.0", + "version": "31.0.0", "artifacts": { - "Tree": { - "type": "cdk:tree", - "properties": { - "file": "tree.json" - } - }, "aws-cdk-rds-s3-integ.assets": { "type": "cdk:asset-manifest", "properties": { @@ -23,7 +17,7 @@ "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/8182c8bf4e17962cb28aa684c91f0d422b58d2f454a7088dc2ceebd8f32e89d7.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/847a7253a365d747181fde2a1ce016fb160617357972f277a1dc32b6a4e60587.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -225,40 +219,40 @@ "data": "DatabaseS3ImportRoleDefaultPolicyA60A7342" } ], - "/aws-cdk-rds-s3-integ/Database/S3ExportRole/Resource": [ - { - "type": "aws:cdk:logicalId", - "data": "DatabaseS3ExportRole9E328562" - } - ], - "/aws-cdk-rds-s3-integ/Database/S3ExportRole/DefaultPolicy/Resource": [ - { - "type": "aws:cdk:logicalId", - "data": "DatabaseS3ExportRoleDefaultPolicy8FEADB68" - } - ], "/aws-cdk-rds-s3-integ/Database/ClusterParameterGroup/Resource": [ { "type": "aws:cdk:logicalId", - "data": "DatabaseClusterParameterGroupF2A52087" + "data": "DatabaseClusterParameterGroupF2A52087", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_REPLACE" + ] } ], "/aws-cdk-rds-s3-integ/Database/Resource": [ { "type": "aws:cdk:logicalId", - "data": "DatabaseB269D8BB" + "data": "DatabaseB269D8BB", + "trace": [ + "!!DESTRUCTIVE_CHANGES: MAY_REPLACE" + ] } ], "/aws-cdk-rds-s3-integ/Database/Instance1": [ { "type": "aws:cdk:logicalId", - "data": "DatabaseInstance1844F58FD" + "data": "DatabaseInstance1844F58FD", + "trace": [ + "!!DESTRUCTIVE_CHANGES: MAY_REPLACE" + ] } ], "/aws-cdk-rds-s3-integ/Database/Instance2": [ { "type": "aws:cdk:logicalId", - "data": "DatabaseInstance2AA380DEE" + "data": "DatabaseInstance2AA380DEE", + "trace": [ + "!!DESTRUCTIVE_CHANGES: MAY_REPLACE" + ] } ], "/aws-cdk-rds-s3-integ/BootstrapVersion": [ @@ -272,9 +266,33 @@ "type": "aws:cdk:logicalId", "data": "CheckBootstrapVersion" } + ], + "DatabaseS3ExportRole9E328562": [ + { + "type": "aws:cdk:logicalId", + "data": "DatabaseS3ExportRole9E328562", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "DatabaseS3ExportRoleDefaultPolicy8FEADB68": [ + { + "type": "aws:cdk:logicalId", + "data": "DatabaseS3ExportRoleDefaultPolicy8FEADB68", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } ] }, "displayName": "aws-cdk-rds-s3-integ" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } } } } \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-s3.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-s3.js.snapshot/tree.json index 729fe5d691188..01f4dd8f3a06b 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-s3.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-s3.js.snapshot/tree.json @@ -4,14 +4,6 @@ "id": "App", "path": "", "children": { - "Tree": { - "id": "Tree", - "path": "Tree", - "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.85" - } - }, "aws-cdk-rds-s3-integ": { "id": "aws-cdk-rds-s3-integ", "path": "aws-cdk-rds-s3-integ", @@ -39,8 +31,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnVPC", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "PublicSubnet1": { @@ -83,8 +75,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSubnet", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Acl": { @@ -92,7 +84,7 @@ "path": "aws-cdk-rds-s3-integ/VPC/PublicSubnet1/Acl", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.85" + "version": "10.1.270" } }, "RouteTable": { @@ -113,8 +105,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnRouteTable", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "RouteTableAssociation": { @@ -132,8 +124,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSubnetRouteTableAssociation", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "DefaultRoute": { @@ -152,8 +144,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnRoute", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "EIP": { @@ -172,8 +164,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnEIP", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "NATGateway": { @@ -200,14 +192,14 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnNatGateway", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.PublicSubnet", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "PublicSubnet2": { @@ -250,8 +242,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSubnet", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Acl": { @@ -259,7 +251,7 @@ "path": "aws-cdk-rds-s3-integ/VPC/PublicSubnet2/Acl", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.85" + "version": "10.1.270" } }, "RouteTable": { @@ -280,8 +272,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnRouteTable", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "RouteTableAssociation": { @@ -299,8 +291,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSubnetRouteTableAssociation", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "DefaultRoute": { @@ -319,8 +311,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnRoute", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "EIP": { @@ -339,8 +331,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnEIP", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "NATGateway": { @@ -367,14 +359,14 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnNatGateway", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.PublicSubnet", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "PrivateSubnet1": { @@ -417,8 +409,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSubnet", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Acl": { @@ -426,7 +418,7 @@ "path": "aws-cdk-rds-s3-integ/VPC/PrivateSubnet1/Acl", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.85" + "version": "10.1.270" } }, "RouteTable": { @@ -447,8 +439,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnRouteTable", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "RouteTableAssociation": { @@ -466,8 +458,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSubnetRouteTableAssociation", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "DefaultRoute": { @@ -486,14 +478,14 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnRoute", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.PrivateSubnet", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "PrivateSubnet2": { @@ -536,8 +528,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSubnet", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Acl": { @@ -545,7 +537,7 @@ "path": "aws-cdk-rds-s3-integ/VPC/PrivateSubnet2/Acl", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.85" + "version": "10.1.270" } }, "RouteTable": { @@ -566,8 +558,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnRouteTable", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "RouteTableAssociation": { @@ -585,8 +577,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSubnetRouteTableAssociation", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "DefaultRoute": { @@ -605,14 +597,14 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnRoute", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.PrivateSubnet", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "IGW": { @@ -630,8 +622,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnInternetGateway", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "VPCGW": { @@ -649,14 +641,14 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnVPCGatewayAttachment", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.Vpc", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "DbSecurity": { @@ -700,14 +692,14 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-kms.CfnKey", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-kms.Key", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "ImportBucket": { @@ -722,14 +714,14 @@ "aws:cdk:cloudformation:props": {} }, "constructInfo": { - "fqn": "@aws-cdk/aws-s3.CfnBucket", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-s3.Bucket", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "ExportBucket": { @@ -744,14 +736,14 @@ "aws:cdk:cloudformation:props": {} }, "constructInfo": { - "fqn": "@aws-cdk/aws-s3.CfnBucket", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-s3.Bucket", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Database": { @@ -780,14 +772,14 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-rds.CfnDBSubnetGroup", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-rds.SubnetGroup", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "SecurityGroup": { @@ -814,8 +806,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSecurityGroup", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "from 0.0.0.0_0:{IndirectPort}": { @@ -848,20 +840,28 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.CfnSecurityGroupIngress", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-ec2.SecurityGroup", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "S3ImportRole": { "id": "S3ImportRole", "path": "aws-cdk-rds-s3-integ/Database/S3ImportRole", "children": { + "ImportS3ImportRole": { + "id": "ImportS3ImportRole", + "path": "aws-cdk-rds-s3-integ/Database/S3ImportRole/ImportS3ImportRole", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, "Resource": { "id": "Resource", "path": "aws-cdk-rds-s3-integ/Database/S3ImportRole/Resource", @@ -883,8 +883,8 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.CfnRole", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "DefaultPolicy": { @@ -928,76 +928,7 @@ ] } ] - } - ], - "Version": "2012-10-17" - }, - "policyName": "DatabaseS3ImportRoleDefaultPolicyA60A7342", - "roles": [ - { - "Ref": "DatabaseS3ImportRole377BC9C0" - } - ] - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-iam.CfnPolicy", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-iam.Policy", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-iam.Role", - "version": "0.0.0" - } - }, - "S3ExportRole": { - "id": "S3ExportRole", - "path": "aws-cdk-rds-s3-integ/Database/S3ExportRole", - "children": { - "Resource": { - "id": "Resource", - "path": "aws-cdk-rds-s3-integ/Database/S3ExportRole/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::IAM::Role", - "aws:cdk:cloudformation:props": { - "assumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "rds.amazonaws.com" - } - } - ], - "Version": "2012-10-17" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-iam.CfnRole", - "version": "0.0.0" - } - }, - "DefaultPolicy": { - "id": "DefaultPolicy", - "path": "aws-cdk-rds-s3-integ/Database/S3ExportRole/DefaultPolicy", - "children": { - "Resource": { - "id": "Resource", - "path": "aws-cdk-rds-s3-integ/Database/S3ExportRole/DefaultPolicy/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::IAM::Policy", - "aws:cdk:cloudformation:props": { - "policyDocument": { - "Statement": [ + }, { "Action": [ "s3:Abort*", @@ -1038,29 +969,37 @@ ], "Version": "2012-10-17" }, - "policyName": "DatabaseS3ExportRoleDefaultPolicy8FEADB68", + "policyName": "DatabaseS3ImportRoleDefaultPolicyA60A7342", "roles": [ { - "Ref": "DatabaseS3ExportRole9E328562" + "Ref": "DatabaseS3ImportRole377BC9C0" } ] } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.CfnPolicy", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.Policy", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.Role", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "AuroraMySqlDatabaseClusterEngineDefaultParameterGroup": { + "id": "AuroraMySqlDatabaseClusterEngineDefaultParameterGroup", + "path": "aws-cdk-rds-s3-integ/Database/AuroraMySqlDatabaseClusterEngineDefaultParameterGroup", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "ClusterParameterGroup": { @@ -1073,33 +1012,27 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::RDS::DBClusterParameterGroup", "aws:cdk:cloudformation:props": { - "description": "Cluster parameter group for aurora5.6", - "family": "aurora5.6", + "description": "Cluster parameter group for aurora-mysql8.0", + "family": "aurora-mysql8.0", "parameters": { - "aurora_load_from_s3_role": { + "aws_default_s3_role": { "Fn::GetAtt": [ "DatabaseS3ImportRole377BC9C0", "Arn" ] - }, - "aurora_select_into_s3_role": { - "Fn::GetAtt": [ - "DatabaseS3ExportRole9E328562", - "Arn" - ] } } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-rds.CfnDBClusterParameterGroup", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-rds.ParameterGroup", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Resource": { @@ -1108,7 +1041,6 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::RDS::DBCluster", "aws:cdk:cloudformation:props": { - "engine": "aurora", "associatedRoles": [ { "roleArn": { @@ -1117,14 +1049,6 @@ "Arn" ] } - }, - { - "roleArn": { - "Fn::GetAtt": [ - "DatabaseS3ExportRole9E328562", - "Arn" - ] - } } ], "copyTagsToSnapshot": true, @@ -1134,6 +1058,8 @@ "dbSubnetGroupName": { "Ref": "DatabaseSubnets56F17B9A" }, + "engine": "aurora-mysql", + "engineVersion": "8.0.mysql_aurora.3.03.0", "kmsKeyId": { "Fn::GetAtt": [ "DbSecurity381C2C15", @@ -1154,8 +1080,16 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-rds.CfnDBCluster", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "Instance1Wrapper": { + "id": "Instance1Wrapper", + "path": "aws-cdk-rds-s3-integ/Database/Instance1Wrapper", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Instance1": { @@ -1167,17 +1101,25 @@ "dbClusterIdentifier": { "Ref": "DatabaseB269D8BB" }, - "dbInstanceClass": "db.t3.small", + "dbInstanceClass": "db.t3.medium", "dbSubnetGroupName": { "Ref": "DatabaseSubnets56F17B9A" }, - "engine": "aurora", + "engine": "aurora-mysql", "publiclyAccessible": true } }, "constructInfo": { - "fqn": "@aws-cdk/aws-rds.CfnDBInstance", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "Instance2Wrapper": { + "id": "Instance2Wrapper", + "path": "aws-cdk-rds-s3-integ/Database/Instance2Wrapper", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Instance2": { @@ -1189,35 +1131,59 @@ "dbClusterIdentifier": { "Ref": "DatabaseB269D8BB" }, - "dbInstanceClass": "db.t3.small", + "dbInstanceClass": "db.t3.medium", "dbSubnetGroupName": { "Ref": "DatabaseSubnets56F17B9A" }, - "engine": "aurora", + "engine": "aurora-mysql", "publiclyAccessible": true } }, "constructInfo": { - "fqn": "@aws-cdk/aws-rds.CfnDBInstance", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-rds.DatabaseCluster", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "aws-cdk-rds-s3-integ/BootstrapVersion", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "aws-cdk-rds-s3-integ/CheckBootstrapVersion", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.85" + "version": "10.1.270" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.85" + "version": "10.1.270" } } } \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-s3.mysql-8.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-s3.mysql-8.ts index 03e3f25981ff5..109e6030b8b1f 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-s3.mysql-8.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-s3.mysql-8.ts @@ -18,8 +18,8 @@ new rds.DatabaseCluster(stack, 'Database', { credentials: rds.Credentials.fromUsername('admin', { password: cdk.SecretValue.plainText('7959866cacc02c2d243ecfe177464fe6'), }), - instances: 1, - instanceProps: { vpc }, + writer: rds.ClusterInstance.provisioned('Instance1', { isFromLegacyInstanceProps: true }), + vpc, s3ImportBuckets: [importExportBucket], s3ExportBuckets: [importExportBucket], }); diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-s3.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-s3.ts index fe427b9a9723d..0cf4a8bd8834c 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-s3.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-s3.ts @@ -2,7 +2,7 @@ import * as ec2 from 'aws-cdk-lib/aws-ec2'; import * as kms from 'aws-cdk-lib/aws-kms'; import * as s3 from 'aws-cdk-lib/aws-s3'; import * as cdk from 'aws-cdk-lib'; -import { Credentials, DatabaseCluster, DatabaseClusterEngine } from 'aws-cdk-lib/aws-rds'; +import { AuroraMysqlEngineVersion, ClusterInstance, Credentials, DatabaseCluster, DatabaseClusterEngine } from 'aws-cdk-lib/aws-rds'; const app = new cdk.App(); const stack = new cdk.Stack(app, 'aws-cdk-rds-s3-integ'); @@ -14,14 +14,25 @@ const kmsKey = new kms.Key(stack, 'DbSecurity'); const importBucket = new s3.Bucket(stack, 'ImportBucket'); const exportBucket = new s3.Bucket(stack, 'ExportBucket'); +const instanceProps = { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE3, ec2.InstanceSize.MEDIUM), + isFromLegacyInstanceProps: true, +}; const cluster = new DatabaseCluster(stack, 'Database', { - engine: DatabaseClusterEngine.AURORA, credentials: Credentials.fromUsername('admin', { password: cdk.SecretValue.unsafePlainText('7959866cacc02c2d243ecfe177464fe6') }), - instanceProps: { - instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE3, ec2.InstanceSize.SMALL), - vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC }, - vpc, - }, + engine: DatabaseClusterEngine.auroraMysql({ + version: AuroraMysqlEngineVersion.VER_3_03_0, + }), + vpc, + writer: ClusterInstance.provisioned('Instance1', { + ...instanceProps, + }), + readers: [ + ClusterInstance.provisioned('Instance2', { + ...instanceProps, + }), + ], + vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC }, storageEncryptionKey: kmsKey, s3ImportBuckets: [importBucket], s3ExportBuckets: [exportBucket], diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integ-aurora-serverlessv2-cluster.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integ-aurora-serverlessv2-cluster.assets.json index b6d5020a23dee..583dec2965545 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integ-aurora-serverlessv2-cluster.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integ-aurora-serverlessv2-cluster.assets.json @@ -1,7 +1,7 @@ { "version": "31.0.0", "files": { - "c124cab7d8a98cc66aa81986e6076d47dbd4c4b9622119636b7974340cc71ca4": { + "5ec15cecd9b8441a50d23535be26d2c68417eac2f5ddaf3d86e820b5d95a5ea9": { "source": { "path": "integ-aurora-serverlessv2-cluster.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "c124cab7d8a98cc66aa81986e6076d47dbd4c4b9622119636b7974340cc71ca4.json", + "objectKey": "5ec15cecd9b8441a50d23535be26d2c68417eac2f5ddaf3d86e820b5d95a5ea9.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integ-aurora-serverlessv2-cluster.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integ-aurora-serverlessv2-cluster.template.json index 0535c32a713ec..60af981d3a7b8 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integ-aurora-serverlessv2-cluster.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integ-aurora-serverlessv2-cluster.template.json @@ -526,6 +526,46 @@ "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, + "integauroraserverlessv20capacity09BB04C7": { + "Type": "AWS::CloudWatch::Alarm", + "Properties": { + "ComparisonOperator": "GreaterThanOrEqualToThreshold", + "EvaluationPeriods": 3, + "Dimensions": [ + { + "Name": "DBClusterIdentifier", + "Value": { + "Ref": "integauroraserverlessv20IntegCluster5133790E" + } + } + ], + "MetricName": "ServerlessDatabaseCapacity", + "Namespace": "AWS/RDS", + "Period": 600, + "Statistic": "Average", + "Threshold": 1.5 + } + }, + "integauroraserverlessv20alarmA67BFE09": { + "Type": "AWS::CloudWatch::Alarm", + "Properties": { + "ComparisonOperator": "GreaterThanOrEqualToThreshold", + "EvaluationPeriods": 3, + "Dimensions": [ + { + "Name": "DBClusterIdentifier", + "Value": { + "Ref": "integauroraserverlessv20IntegCluster5133790E" + } + } + ], + "MetricName": "ACUUtilization", + "Namespace": "AWS/RDS", + "Period": 600, + "Statistic": "Average", + "Threshold": 90 + } + }, "integauroraserverlessv21IntegClusterSubnetsAEE71920": { "Type": "AWS::RDS::DBSubnetGroup", "Properties": { @@ -699,6 +739,46 @@ "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, + "integauroraserverlessv21capacityAFD8D6D1": { + "Type": "AWS::CloudWatch::Alarm", + "Properties": { + "ComparisonOperator": "GreaterThanOrEqualToThreshold", + "EvaluationPeriods": 3, + "Dimensions": [ + { + "Name": "DBClusterIdentifier", + "Value": { + "Ref": "integauroraserverlessv21IntegClusterDFF12F00" + } + } + ], + "MetricName": "ServerlessDatabaseCapacity", + "Namespace": "AWS/RDS", + "Period": 600, + "Statistic": "Average", + "Threshold": 1.5 + } + }, + "integauroraserverlessv21alarmE70B8A00": { + "Type": "AWS::CloudWatch::Alarm", + "Properties": { + "ComparisonOperator": "GreaterThanOrEqualToThreshold", + "EvaluationPeriods": 3, + "Dimensions": [ + { + "Name": "DBClusterIdentifier", + "Value": { + "Ref": "integauroraserverlessv21IntegClusterDFF12F00" + } + } + ], + "MetricName": "ACUUtilization", + "Namespace": "AWS/RDS", + "Period": 600, + "Statistic": "Average", + "Threshold": 90 + } + }, "integauroraserverlessv22IntegClusterSubnets241DB50C": { "Type": "AWS::RDS::DBSubnetGroup", "Properties": { @@ -871,6 +951,46 @@ ], "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" + }, + "integauroraserverlessv22capacityCC6A400C": { + "Type": "AWS::CloudWatch::Alarm", + "Properties": { + "ComparisonOperator": "GreaterThanOrEqualToThreshold", + "EvaluationPeriods": 3, + "Dimensions": [ + { + "Name": "DBClusterIdentifier", + "Value": { + "Ref": "integauroraserverlessv22IntegCluster1F86F0C6" + } + } + ], + "MetricName": "ServerlessDatabaseCapacity", + "Namespace": "AWS/RDS", + "Period": 600, + "Statistic": "Average", + "Threshold": 1.5 + } + }, + "integauroraserverlessv22alarmA8DB3F10": { + "Type": "AWS::CloudWatch::Alarm", + "Properties": { + "ComparisonOperator": "GreaterThanOrEqualToThreshold", + "EvaluationPeriods": 3, + "Dimensions": [ + { + "Name": "DBClusterIdentifier", + "Value": { + "Ref": "integauroraserverlessv22IntegCluster1F86F0C6" + } + } + ], + "MetricName": "ACUUtilization", + "Namespace": "AWS/RDS", + "Period": 600, + "Statistic": "Average", + "Threshold": 90 + } } }, "Parameters": { diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/manifest.json index 5e4f9e538bb7d..efb5c19624fc1 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/manifest.json @@ -17,7 +17,7 @@ "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/c124cab7d8a98cc66aa81986e6076d47dbd4c4b9622119636b7974340cc71ca4.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/5ec15cecd9b8441a50d23535be26d2c68417eac2f5ddaf3d86e820b5d95a5ea9.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -207,6 +207,18 @@ "data": "integauroraserverlessv20IntegClusterwriter68858AE9" } ], + "/integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-0/capacity/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "integauroraserverlessv20capacity09BB04C7" + } + ], + "/integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-0/alarm/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "integauroraserverlessv20alarmA67BFE09" + } + ], "/integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-1/Integ-Cluster/Subnets/Default": [ { "type": "aws:cdk:logicalId", @@ -255,6 +267,18 @@ "data": "integauroraserverlessv21IntegClusterOtherReaderBC649D9A" } ], + "/integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-1/capacity/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "integauroraserverlessv21capacityAFD8D6D1" + } + ], + "/integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-1/alarm/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "integauroraserverlessv21alarmE70B8A00" + } + ], "/integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-2/Integ-Cluster": [ { "type": "aws:cdk:info", @@ -309,6 +333,18 @@ "data": "integauroraserverlessv22IntegClusterOtherReader63C2651D" } ], + "/integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-2/capacity/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "integauroraserverlessv22capacityCC6A400C" + } + ], + "/integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-2/alarm/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "integauroraserverlessv22alarmA8DB3F10" + } + ], "/integ-aurora-serverlessv2-cluster/BootstrapVersion": [ { "type": "aws:cdk:logicalId", diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/tree.json index e43bc7077cfc0..e46e5ea3ced0e 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/tree.json @@ -31,8 +31,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnVPC", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "PublicSubnet1": { @@ -75,8 +75,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Acl": { @@ -105,8 +105,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "RouteTableAssociation": { @@ -124,8 +124,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "DefaultRoute": { @@ -144,8 +144,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "EIP": { @@ -164,8 +164,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnEIP", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "NATGateway": { @@ -192,8 +192,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnNatGateway", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, @@ -242,8 +242,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Acl": { @@ -272,8 +272,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "RouteTableAssociation": { @@ -291,8 +291,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "DefaultRoute": { @@ -311,8 +311,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "EIP": { @@ -331,8 +331,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnEIP", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "NATGateway": { @@ -359,8 +359,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnNatGateway", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, @@ -409,8 +409,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Acl": { @@ -439,8 +439,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "RouteTableAssociation": { @@ -458,8 +458,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "DefaultRoute": { @@ -478,8 +478,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, @@ -528,8 +528,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Acl": { @@ -558,8 +558,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "RouteTableAssociation": { @@ -577,8 +577,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "DefaultRoute": { @@ -597,8 +597,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, @@ -622,8 +622,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnInternetGateway", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "VPCGW": { @@ -641,8 +641,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnVPCGatewayAttachment", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, @@ -681,8 +681,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_rds.CfnDBSubnetGroup", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, @@ -715,8 +715,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnSecurityGroup", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, @@ -763,8 +763,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_secretsmanager.CfnSecret", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Attachment": { @@ -787,8 +787,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_secretsmanager.CfnSecretTargetAttachment", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, @@ -855,8 +855,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_rds.CfnDBCluster", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "writer": { @@ -878,8 +878,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_rds.CfnDBInstance", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, @@ -893,6 +893,82 @@ "fqn": "constructs.Construct", "version": "10.1.270" } + }, + "capacity": { + "id": "capacity", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-0/capacity", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-0/capacity/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CloudWatch::Alarm", + "aws:cdk:cloudformation:props": { + "comparisonOperator": "GreaterThanOrEqualToThreshold", + "evaluationPeriods": 3, + "dimensions": [ + { + "name": "DBClusterIdentifier", + "value": { + "Ref": "integauroraserverlessv20IntegCluster5133790E" + } + } + ], + "metricName": "ServerlessDatabaseCapacity", + "namespace": "AWS/RDS", + "period": 600, + "statistic": "Average", + "threshold": 1.5 + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "alarm": { + "id": "alarm", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-0/alarm", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-0/alarm/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CloudWatch::Alarm", + "aws:cdk:cloudformation:props": { + "comparisonOperator": "GreaterThanOrEqualToThreshold", + "evaluationPeriods": 3, + "dimensions": [ + { + "name": "DBClusterIdentifier", + "value": { + "Ref": "integauroraserverlessv20IntegCluster5133790E" + } + } + ], + "metricName": "ACUUtilization", + "namespace": "AWS/RDS", + "period": 600, + "statistic": "Average", + "threshold": 90 + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } } }, "constructInfo": { @@ -930,8 +1006,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_rds.CfnDBSubnetGroup", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, @@ -964,8 +1040,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnSecurityGroup", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, @@ -1012,8 +1088,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_secretsmanager.CfnSecret", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Attachment": { @@ -1036,8 +1112,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_secretsmanager.CfnSecretTargetAttachment", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, @@ -1104,8 +1180,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_rds.CfnDBCluster", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "writer": { @@ -1127,8 +1203,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_rds.CfnDBInstance", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, @@ -1156,8 +1232,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_rds.CfnDBInstance", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, @@ -1185,8 +1261,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_rds.CfnDBInstance", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, @@ -1200,6 +1276,82 @@ "fqn": "constructs.Construct", "version": "10.1.270" } + }, + "capacity": { + "id": "capacity", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-1/capacity", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-1/capacity/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CloudWatch::Alarm", + "aws:cdk:cloudformation:props": { + "comparisonOperator": "GreaterThanOrEqualToThreshold", + "evaluationPeriods": 3, + "dimensions": [ + { + "name": "DBClusterIdentifier", + "value": { + "Ref": "integauroraserverlessv21IntegClusterDFF12F00" + } + } + ], + "metricName": "ServerlessDatabaseCapacity", + "namespace": "AWS/RDS", + "period": 600, + "statistic": "Average", + "threshold": 1.5 + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "alarm": { + "id": "alarm", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-1/alarm", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-1/alarm/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CloudWatch::Alarm", + "aws:cdk:cloudformation:props": { + "comparisonOperator": "GreaterThanOrEqualToThreshold", + "evaluationPeriods": 3, + "dimensions": [ + { + "name": "DBClusterIdentifier", + "value": { + "Ref": "integauroraserverlessv21IntegClusterDFF12F00" + } + } + ], + "metricName": "ACUUtilization", + "namespace": "AWS/RDS", + "period": 600, + "statistic": "Average", + "threshold": 90 + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } } }, "constructInfo": { @@ -1237,8 +1389,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_rds.CfnDBSubnetGroup", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, @@ -1271,8 +1423,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnSecurityGroup", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, @@ -1319,8 +1471,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_secretsmanager.CfnSecret", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "Attachment": { @@ -1343,8 +1495,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_secretsmanager.CfnSecretTargetAttachment", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, @@ -1411,8 +1563,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_rds.CfnDBCluster", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } }, "writer": { @@ -1434,8 +1586,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_rds.CfnDBInstance", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, @@ -1463,8 +1615,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_rds.CfnDBInstance", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, @@ -1492,8 +1644,8 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_rds.CfnDBInstance", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.1.270" } } }, @@ -1507,6 +1659,82 @@ "fqn": "constructs.Construct", "version": "10.1.270" } + }, + "capacity": { + "id": "capacity", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-2/capacity", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-2/capacity/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CloudWatch::Alarm", + "aws:cdk:cloudformation:props": { + "comparisonOperator": "GreaterThanOrEqualToThreshold", + "evaluationPeriods": 3, + "dimensions": [ + { + "name": "DBClusterIdentifier", + "value": { + "Ref": "integauroraserverlessv22IntegCluster1F86F0C6" + } + } + ], + "metricName": "ServerlessDatabaseCapacity", + "namespace": "AWS/RDS", + "period": 600, + "statistic": "Average", + "threshold": 1.5 + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "alarm": { + "id": "alarm", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-2/alarm", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-2/alarm/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CloudWatch::Alarm", + "aws:cdk:cloudformation:props": { + "comparisonOperator": "GreaterThanOrEqualToThreshold", + "evaluationPeriods": 3, + "dimensions": [ + { + "name": "DBClusterIdentifier", + "value": { + "Ref": "integauroraserverlessv22IntegCluster1F86F0C6" + } + } + ], + "metricName": "ACUUtilization", + "namespace": "AWS/RDS", + "period": 600, + "statistic": "Average", + "threshold": 90 + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } } }, "constructInfo": { diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.ts index 664b8fbec2449..bbfdb4c6219ab 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.ts @@ -1,5 +1,5 @@ import { IntegTest } from '@aws-cdk/integ-tests-alpha'; -import { App, RemovalPolicy, Stack, StackProps } from 'aws-cdk-lib'; +import { App, Duration, RemovalPolicy, Stack, StackProps } from 'aws-cdk-lib'; import { Vpc } from 'aws-cdk-lib/aws-ec2'; import * as rds from 'aws-cdk-lib/aws-rds'; import { ClusterInstance } from 'aws-cdk-lib/aws-rds'; @@ -11,16 +11,25 @@ interface TestCaseProps extends Pick *Note* Before getting starting with this type of cluster it is +> highly recommended that you read through the [Developer Guide](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-serverless-v2.setting-capacity.html) +> which goes into much more detail on the things you need to take into +> consideration. + ```ts declare const vpc: ec2.Vpc; const cluster = new rds.DatabaseCluster(this, 'Database', { - engine: rds.DatabaseClusterEngine.auroraMysql({ version: rds.AuroraMysqlEngineVersion.VER_2_08_1 }), + engine: rds.DatabaseClusterEngine.auroraMysql({ version: rds.AuroraMysqlEngineVersion.VER_3_01_0 }), writer: rds.ClusterInstance.provisioned('writer'), readers: [ rds.ClusterInstance.serverlessV2('reader'), @@ -118,14 +123,14 @@ const cluster = new rds.DatabaseCluster(this, 'Database', { There are some things to take into consideration with Aurora Serverless v2. -To create a cluster that can support serverless v2 instance you configure a +To create a cluster that can support serverless v2 instances you configure a minimum and maximum capacity range on the cluster. This is an example showing the default values: ```ts declare const vpc: ec2.Vpc; const cluster = new rds.DatabaseCluster(this, 'Database', { - engine: rds.DatabaseClusterEngine.auroraMysql({ version: rds.AuroraMysqlEngineVersion.VER_2_08_1 }), + engine: rds.DatabaseClusterEngine.auroraMysql({ version: rds.AuroraMysqlEngineVersion.VER_3_01_0 }), writer: rds.ClusterInstance.serverlessV2('writer'), serverlessV2MinCapacity: 0.5, serverlessV2MaxCapacity: 2, @@ -149,7 +154,7 @@ things. * Adjust the minimum capacity to obtain a suitable scaling rate * Network throughput is proportional to capacity -More complete details can be found [in the docs](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-serverless-v2.setting-capacity.html#aurora-serverless-v2-examples-setting-capacity-range-for-cluster) +> *Info* More complete details can be found [in the docs](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-serverless-v2.setting-capacity.html#aurora-serverless-v2-examples-setting-capacity-range-for-cluster) Another way that you control the capacity/scaling of your serverless v2 reader instances is based on the [promotion tier](https://aws.amazon.com/blogs/aws/additional-failover-control-for-amazon-aurora/) @@ -192,7 +197,7 @@ based on use case. There are a couple of high level differences: * Engine Version (serverless only supports MySQL 8+ & PostgreSQL 13+) -* Memory up to 256GB can be replaced with serverless +* Memory up to 256GB can be supported by serverless #### Provisioned writer @@ -239,6 +244,61 @@ DB instance to a status of `incompatible-parameters`. While the DB instance has the incompatible-parameters status, some operations are blocked. For example, you can't upgrade the engine version. +### Migrating from instanceProps + +Creating instances in a `DatabaseCluster` using `instanceProps` & `instances` is +deprecated. To migrate to the new properties you can provide the +`isFromLegacyInstanceProps` property. + +For example, in order to migrate from this deprecated config: + +```ts +declare const vpc: ec2.Vpc; +const cluster = new rds.DatabaseCluster(stack, 'Database', { + engine: rds.DatabaseClusterEngine.auroraMysql({ + version: rds.AuroraMysqlEngineVersion.VER_3_03_0, + }), + instances: 2, + instanceProps: { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE3, ec2.InstanceSize.SMALL), + vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC }, + vpc, + }, +}); +``` + +You would need to migrate to this. The old method of providing `instanceProps` +and `instances` will create the number of `instances` that you provide. The +first instance will be the writer and the rest will be the readers. It's +important that the `id` that you provide is `Instance{NUMBER}`. The writer +should always be `Instance1` and the readers will increment from there. + +Make sure to run a `cdk diff` before deploying to make sure that all changes are +expected. **Always test the migration in a non-production environment first.** + +```ts +const instanceProps = { + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE3, ec2.InstanceSize.SMALL), + isFromLegacyInstanceProps: true, +}; + +declare const vpc: ec2.Vpc; +const cluster = new rds.DatabaseCluster(stack, 'Database', { + engine: rds.DatabaseClusterEngine.auroraMysql({ + version: rds.AuroraMysqlEngineVersion.VER_3_03_0, + }), + vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC }, + vpc, + writer: ClusterInstance.provisioned('Instance1', { + ...instanceProps, + }), + readers: [ + ClusterInstance.provisioned('Instance2', { + ...instanceProps, + }), + ], +}); +``` ## Starting an instance database @@ -374,7 +434,9 @@ new rds.DatabaseInstance(this, 'Instance', { // Setting public accessibility for DB cluster new rds.DatabaseCluster(this, 'DatabaseCluster', { - engine: rds.DatabaseClusterEngine.AURORA, + engine: rds.DatabaseClusterEngine.auroraMysql({ + version: rds.AuroraMysqlEngineVersion.VER_3_03_0, + }), instanceProps: { vpc, vpcSubnets: { @@ -583,7 +645,9 @@ The following example shows granting connection access for RDS Proxy to an IAM r ```ts declare const vpc: ec2.Vpc; const cluster = new rds.DatabaseCluster(this, 'Database', { - engine: rds.DatabaseClusterEngine.AURORA, + engine: rds.DatabaseClusterEngine.auroraMysql({ + version: rds.AuroraMysqlEngineVersion.VER_3_03_0, + }), writer: rds.ClusterInstance.provisioned('writer'), vpc, }); @@ -676,7 +740,9 @@ declare const vpc: ec2.Vpc; const importBucket = new s3.Bucket(this, 'importbucket'); const exportBucket = new s3.Bucket(this, 'exportbucket'); new rds.DatabaseCluster(this, 'dbcluster', { - engine: rds.DatabaseClusterEngine.AURORA, + engine: rds.DatabaseClusterEngine.auroraMysql({ + version: rds.AuroraMysqlEngineVersion.VER_3_03_0, + }), writer: rds.ClusterInstance.provisioned('writer'), vpc, s3ImportBuckets: [importBucket], diff --git a/packages/aws-cdk-lib/aws-rds/lib/aurora-cluster-instance.ts b/packages/aws-cdk-lib/aws-rds/lib/aurora-cluster-instance.ts index 1a2ca2581cb3c..3b5a5ef8f2afc 100644 --- a/packages/aws-cdk-lib/aws-rds/lib/aurora-cluster-instance.ts +++ b/packages/aws-cdk-lib/aws-rds/lib/aurora-cluster-instance.ts @@ -3,13 +3,17 @@ import { DatabaseCluster } from './cluster'; import { IDatabaseCluster } from './cluster-ref'; import { IParameterGroup, ParameterGroup } from './parameter-group'; import { helperRemovalPolicy } from './private/util'; -import { InstanceProps, PerformanceInsightRetention } from './props'; +import { PerformanceInsightRetention } from './props'; import { CfnDBInstance } from './rds.generated'; +import { ISubnetGroup } from './subnet-group'; import * as ec2 from '../../aws-ec2'; import { IRole } from '../../aws-iam'; import * as kms from '../../aws-kms'; import { IResource, Resource, Duration, RemovalPolicy, ArnFormat } from '../../core'; +/** + * Options for binding the instance to the cluster + */ export interface ClusterInstanceBindOptions { /** * The interval, in seconds, between points when Amazon RDS collects enhanced @@ -46,6 +50,13 @@ export interface ClusterInstanceBindOptions { */ readonly promotionTier?: number; + /** + * Existing subnet group for the cluster. + * This is only needed when using the isFromLegacyInstanceProps + * + * @default - cluster subnet group is used + */ + readonly subnetGroup?: ISubnetGroup; } /** @@ -71,7 +82,6 @@ export class ClusterInstanceType { ); } - constructor( private readonly instanceType: string, public readonly type: InstanceType, @@ -118,6 +128,52 @@ export interface ProvisionedClusterInstanceProps extends ClusterInstanceOptions * @default 2 */ readonly promotionTier?: number; + + /** + * Only used for migrating existing clusters from using `instanceProps` to `writer` and `readers` + * + * @example + * // existing cluster + * declare const vpc: ec2.Vpc; + * const cluster = new rds.DatabaseCluster(stack, 'Database', { + * engine: rds.DatabaseClusterEngine.auroraMysql({ + * version: rds.AuroraMysqlEngineVersion.VER_3_03_0, + * }), + * instances: 2, + * instanceProps: { + * instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE3, ec2.InstanceSize.SMALL), + * vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC }, + * vpc, + * }, + * }); + * + * // migration + * + * const instanceProps = { + * instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE3, ec2.InstanceSize.SMALL), + * isFromLegacyInstanceProps: true, + * }; + * + * declare const vpc: ec2.Vpc; + * const cluster = new rds.DatabaseCluster(stack, 'Database', { + * engine: rds.DatabaseClusterEngine.auroraMysql({ + * version: rds.AuroraMysqlEngineVersion.VER_3_03_0, + * }), + * vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC }, + * vpc, + * writer: ClusterInstance.provisioned('Instance1', { + * ...instanceProps, + * }), + * readers: [ + * ClusterInstance.provisioned('Instance2', { + * ...instanceProps, + * }), + * ], + * }); + * + * @default false + */ + readonly isFromLegacyInstanceProps?: boolean; } /** @@ -163,11 +219,16 @@ export interface ClusterInstanceProps extends ClusterInstanceOptions{ readonly promotionTier?: number; /** + * Only used for migrating existing clusters from using `instanceProps` to `writer` and `readers` + * * @default false */ readonly isFromLegacyInstanceProps?: boolean; } +/** + * Common options for creating a cluster instance + */ export interface ClusterInstanceOptions { /** * The identifier for the database instance @@ -239,35 +300,38 @@ export interface ClusterInstanceOptions { readonly parameterGroup?: IParameterGroup; } -export interface LegacyInstanceProps extends InstanceProps { - /** - * How many replicas/instances to create - * - * Has to be at least 1. - * - * @default 2 - */ - readonly instances?: number; - - /** - * An optional identifier for the cluster - * - * @default - A name is automatically generated. - */ - readonly clusterIdentifier?: string; - +/** + * Create an RDS Aurora Cluster Instance. You can create either provisioned or + * serverless v2 instances. + * + * @example + * + * declare const vpc: ec2.Vpc; + * const cluster = new rds.DatabaseCluster(this, 'Database', { + * engine: rds.DatabaseClusterEngine.auroraMysql({ version: rds.AuroraMysqlEngineVersion.VER_2_08_1 }), + * writer: rds.ClusterInstance.provisioned('writer', { + * instanceType: ec2.InstanceType.of(ec2.InstanceClass.R6G, ec2.InstanceSize.XLARGE4), + * }), + * serverlessV2MinCapacity: 6.5, + * serverlessV2MaxCapacity: 64, + * readers: [ + * // will be put in promotion tier 1 and will scale with the writer + * rds.ClusterInstance.serverlessV2('reader1', { scaleWithWriter: true }), + * // will be put in promotion tier 2 and will not scale with the writer + * rds.ClusterInstance.serverlessV2('reader2'), + * ] + * vpc, + * }); + */ +export class ClusterInstance implements IClusterInstance { /** - * Base identifier for instances + * Add a provisioned instance to the cluster * - * Every replica is named by appending the replica number to this string, 1-based. - * - * @default - clusterIdentifier is used with the word "Instance" appended. - * If clusterIdentifier is not provided, the identifier is automatically generated. + * @example + * ClusterInstance.provisioned('ClusterInstance', { + * instanceType: ec2.InstanceType.of(ec2.InstanceClass.R6G, ec2.InstanceSize.XLARGE4), + * }); */ - readonly instanceIdentifierBase?: string; -} - -export class ClusterInstance implements IClusterInstance { public static provisioned(id: string, props: ProvisionedClusterInstanceProps = {}): IClusterInstance { return new ClusterInstance(id, { ...props, @@ -275,6 +339,14 @@ export class ClusterInstance implements IClusterInstance { }); } + /** + * Add a serverless v2 instance to the cluster + * + * @example + * ClusterInstance.serverlessV2('ClusterInstance', { + * scaleWithWriter: true, + * }); + */ public static serverlessV2(id: string, props: ServerlessV2ClusterInstanceProps = {}): IClusterInstance { return new ClusterInstance(id, { ...props, @@ -283,32 +355,11 @@ export class ClusterInstance implements IClusterInstance { }); } - public static fromInstanceProps(props: LegacyInstanceProps, instances?: number): IClusterInstance[] { - const instanceCount = instances != null ? instances : 2; - if (instanceCount < 1) { - throw new Error('At least one instance is required'); - } - const clusterInstances: IClusterInstance[] = []; - for (let i = 0; i < instanceCount; i++) { - const instanceIndex = i + 1; - const instanceIdentifier = props.instanceIdentifierBase != null ? `${props.instanceIdentifierBase}${instanceIndex}` : - props.clusterIdentifier != null ? `${props.clusterIdentifier}instance${instanceIndex}` : - undefined; - clusterInstances.push( - new ClusterInstance(`Instance${instanceIndex}`, { - ...props, - isFromLegacyInstanceProps: true, - instanceType: ClusterInstanceType.provisioned(props.instanceType), - instanceIdentifier, - promotionTier: 1, - }), - ); - } - return clusterInstances; - } - private constructor(private id: string, private readonly props: ClusterInstanceProps) { } + /** + * Add the ClusterInstance to the cluster + */ public bind(scope: Construct, cluster: IDatabaseCluster, props: ClusterInstanceBindOptions): IAuroraClusterInstance { return new AuroraClusterInstance(scope, this.id, { cluster, @@ -327,13 +378,43 @@ export enum InstanceType { SERVERLESS_V2 = 'SERVERLESS_V2', } +/** + * An Aurora Cluster Instance + */ export interface IAuroraClusterInstance extends IResource { + /** + * The instance ARN + */ readonly dbInstanceArn: string; + + /** + * The instance resource ID + */ readonly dbiResourceId: string; + + /** + * The instance endpoint address + */ readonly dbInstanceEndpointAddress: string; + + /** + * The instance identifier + */ readonly instanceIdentifier: string; + + /** + * The instance type (provisioned vs serverless v2) + */ readonly type: InstanceType; + + /** + * The instance size if the instance is a provisioned type + */ readonly instanceSize?: string; + + /** + * Te promotion tier the instance was created in + */ readonly tier: number; } @@ -405,6 +486,10 @@ class AuroraClusterInstance extends Resource implements IAuroraClusterInstance { performanceInsightsRetentionPeriod: enablePerformanceInsights ? (props.performanceInsightRetention || PerformanceInsightRetention.DEFAULT) : undefined, + // only need to supply this when migrating from legacy method. + // this is not applicable for aurora instances, but if you do provide it and then + // change it it will cause an instance replacement + dbSubnetGroupName: props.isFromLegacyInstanceProps ? props.subnetGroup?.subnetGroupName : undefined, dbParameterGroupName: instanceParameterGroupConfig?.parameterGroupName, monitoringInterval: props.monitoringInterval && props.monitoringInterval.toSeconds(), monitoringRoleArn: props.monitoringRole && props.monitoringRole.roleArn, diff --git a/packages/aws-cdk-lib/aws-rds/lib/cluster.ts b/packages/aws-cdk-lib/aws-rds/lib/cluster.ts index a32245173cb8e..f58cb8d57fc5f 100644 --- a/packages/aws-cdk-lib/aws-rds/lib/cluster.ts +++ b/packages/aws-cdk-lib/aws-rds/lib/cluster.ts @@ -417,8 +417,6 @@ export abstract class DatabaseClusterBase extends Resource implements IDatabaseC */ public abstract readonly connections: ec2.Connections; - protected hasServerlessInstance?: boolean; - /** * Add a new db proxy to this cluster. */ @@ -440,148 +438,6 @@ export abstract class DatabaseClusterBase extends Resource implements IDatabaseC } - /** - * Create cluster instances - */ - protected createInstances(props: DatabaseClusterProps): InstanceConfig { - const instanceEndpoints: Endpoint[] = []; - const instanceIdentifiers: string[] = []; - const readers: IAuroraClusterInstance[] = []; - // need to create the writer first since writer is determined by what instance is first - const writer = props.writer!.bind(this, this, { - monitoringInterval: props.monitoringInterval, - monitoringRole: props.monitoringRole, - removalPolicy: props.removalPolicy ?? RemovalPolicy.SNAPSHOT, - promotionTier: 0, // override the promotion tier so that writers are always 0 - }); - (props.readers ?? []).forEach(instance => { - const clusterInstance = instance.bind(this, this, { - monitoringInterval: props.monitoringInterval, - monitoringRole: props.monitoringRole, - removalPolicy: props.removalPolicy ?? RemovalPolicy.SNAPSHOT, - }); - readers.push(clusterInstance); - - if (clusterInstance.tier < 2) { - this.validateReaderInstance(writer, clusterInstance); - } - instanceEndpoints.push(new Endpoint(clusterInstance.dbInstanceEndpointAddress, this.clusterEndpoint.port)); - instanceIdentifiers.push(clusterInstance.instanceIdentifier); - }); - this.validateClusterInstances(writer, readers); - - return { - instanceEndpoints, - instanceIdentifiers, - }; - } - - /** - * Perform validations on the cluster instances - */ - private validateClusterInstances(writer: IAuroraClusterInstance, readers: IAuroraClusterInstance[]): void { - if (writer.type === InstanceType.SERVERLESS_V2) { - this.hasServerlessInstance = true; - } - if (readers.length > 0) { - const sortedReaders = readers.sort((a, b) => a.tier - b.tier); - const highestTierReaders: IAuroraClusterInstance[] = []; - const highestTier = sortedReaders[0].tier; - let hasProvisionedReader = false; - let noFailoverTierInstances = true; - let serverlessInHighestTier = false; - let hasServerlessReader = false; - const someProvisionedReadersDontMatchWriter: IAuroraClusterInstance[] = []; - for (const reader of sortedReaders) { - if (reader.type === InstanceType.SERVERLESS_V2) { - hasServerlessReader = true; - this.hasServerlessInstance = true; - } else { - hasProvisionedReader = true; - if (reader.instanceSize !== writer.instanceSize) { - someProvisionedReadersDontMatchWriter.push(reader); - } - } - if (reader.tier === highestTier) { - if (reader.type === InstanceType.SERVERLESS_V2) { - serverlessInHighestTier = true; - } - highestTierReaders.push(reader); - } - if (reader.tier <= 1) { - noFailoverTierInstances = false; - } - } - const hasOnlyServerlessReaders = hasServerlessReader && !hasProvisionedReader; - if (hasOnlyServerlessReaders) { - if (noFailoverTierInstances) { - Annotations.of(this).addWarning( - `Cluster ${this.node.id} only has serverless readers and no reader is in promotion tier 0-1.`+ - 'Serverless readers in promotion tiers >= 2 will NOT scale with the writer, which can lead to '+ - 'availability issues if a failover event occurs. It is recommended that at least one reader '+ - 'has `scaleWithWriter` set to true', - ); - } - } else { - if (serverlessInHighestTier && highestTier > 1) { - Annotations.of(this).addWarning( - `There are serverlessV2 readers in tier ${highestTier}. Since there are no instances in a higher tier, `+ - 'any instance in this tier is a failover target. Since this tier is > 1 the serverless reader will not scale '+ - 'with the writer which could lead to availability issues during failover.', - ); - } - if (someProvisionedReadersDontMatchWriter.length > 0 && writer.type === InstanceType.PROVISIONED) { - Annotations.of(this).addWarning( - `There are provisioned readers in the highest promotion tier ${highestTier} that do not have the same `+ - 'InstanceSize as the writer. Any of these instances could be chosen as the new writer in the event '+ - 'of a failover.\n'+ - `Writer InstanceSize: ${writer.instanceSize}\n`+ - `Reader InstanceSizes: ${someProvisionedReadersDontMatchWriter.map(reader => reader.instanceSize).join(', ')}`, - ); - } - } - } - } - - /** - * Perform validations on the reader instance - */ - private validateReaderInstance(writer: IAuroraClusterInstance, reader: IAuroraClusterInstance): void { - if (writer.type === InstanceType.PROVISIONED) { - if (reader.type === InstanceType.SERVERLESS_V2) { - if (!instanceSizeSupportedByServerlessV2(writer.instanceSize!)) { - Annotations.of(this).addWarning( - 'For high availability any serverless instances in promotion tiers 0-1 '+ - 'should be able to scale to match the provisioned instance capacity.\n'+ - `Serverless instance ${reader.node.id} is in promotion tier ${reader.tier},\n`+ - `But can not scale to match the provisioned writer instance (${writer.instanceSize})`, - ); - } - } - } else { - // TODO: add some info around serverless instance tiers and matching scaling - Annotations.of(this).addInfo('...'); - } - } - - /** - * As a cluster-level metric, it represents the average of the ServerlessDatabaseCapacity - * values of all the Aurora Serverless v2 DB instances in the cluster. - */ - public metricServerlessDatabaseCapacity(props?: cloudwatch.MetricOptions) { - return this.metric('ServerlessDatabaseCapacity', { statistic: 'Average', ...props }); - } - - /** - * This value is represented as a percentage. It's calculated as the value of the - * ServerlessDatabaseCapacity metric divided by the maximum ACU value of the DB cluster. - * - * If this metric approaches a value of 100.0, the DB instance has scaled up as high as it can. - * Consider increasing the maximum ACU setting for the cluster. - */ - public metricACUUtilization(props?: cloudwatch.MetricOptions) { - return this.metric('ACUUtilization', { statistic: 'Average', ...props }); - } } /** @@ -626,6 +482,8 @@ abstract class DatabaseClusterNew extends DatabaseClusterBase { protected readonly serverlessV2MinCapacity: number; protected readonly serverlessV2MaxCapacity: number; + protected hasServerlessInstance?: boolean; + constructor(scope: Construct, id: string, props: DatabaseClusterBaseProps) { super(scope, id); @@ -748,6 +606,153 @@ abstract class DatabaseClusterNew extends DatabaseClusterBase { }; } + /** + * Create cluster instances + * + * @internal + */ + protected _createInstances(props: DatabaseClusterProps): InstanceConfig { + const instanceEndpoints: Endpoint[] = []; + const instanceIdentifiers: string[] = []; + const readers: IAuroraClusterInstance[] = []; + // need to create the writer first since writer is determined by what instance is first + const writer = props.writer!.bind(this, this, { + monitoringInterval: props.monitoringInterval, + monitoringRole: props.monitoringRole, + removalPolicy: props.removalPolicy ?? RemovalPolicy.SNAPSHOT, + subnetGroup: this.subnetGroup, + promotionTier: 0, // override the promotion tier so that writers are always 0 + }); + (props.readers ?? []).forEach(instance => { + const clusterInstance = instance.bind(this, this, { + monitoringInterval: props.monitoringInterval, + monitoringRole: props.monitoringRole, + removalPolicy: props.removalPolicy ?? RemovalPolicy.SNAPSHOT, + subnetGroup: this.subnetGroup, + }); + readers.push(clusterInstance); + + if (clusterInstance.tier < 2) { + this.validateReaderInstance(writer, clusterInstance); + } + instanceEndpoints.push(new Endpoint(clusterInstance.dbInstanceEndpointAddress, this.clusterEndpoint.port)); + instanceIdentifiers.push(clusterInstance.instanceIdentifier); + }); + this.validateClusterInstances(writer, readers); + + return { + instanceEndpoints, + instanceIdentifiers, + }; + } + + /** + * Perform validations on the cluster instances + */ + private validateClusterInstances(writer: IAuroraClusterInstance, readers: IAuroraClusterInstance[]): void { + if (writer.type === InstanceType.SERVERLESS_V2) { + this.hasServerlessInstance = true; + } + if (readers.length > 0) { + const sortedReaders = readers.sort((a, b) => a.tier - b.tier); + const highestTierReaders: IAuroraClusterInstance[] = []; + const highestTier = sortedReaders[0].tier; + let hasProvisionedReader = false; + let noFailoverTierInstances = true; + let serverlessInHighestTier = false; + let hasServerlessReader = false; + const someProvisionedReadersDontMatchWriter: IAuroraClusterInstance[] = []; + for (const reader of sortedReaders) { + if (reader.type === InstanceType.SERVERLESS_V2) { + hasServerlessReader = true; + this.hasServerlessInstance = true; + } else { + hasProvisionedReader = true; + if (reader.instanceSize !== writer.instanceSize) { + someProvisionedReadersDontMatchWriter.push(reader); + } + } + if (reader.tier === highestTier) { + if (reader.type === InstanceType.SERVERLESS_V2) { + serverlessInHighestTier = true; + } + highestTierReaders.push(reader); + } + if (reader.tier <= 1) { + noFailoverTierInstances = false; + } + } + const hasOnlyServerlessReaders = hasServerlessReader && !hasProvisionedReader; + if (hasOnlyServerlessReaders) { + if (noFailoverTierInstances) { + Annotations.of(this).addWarning( + `Cluster ${this.node.id} only has serverless readers and no reader is in promotion tier 0-1.`+ + 'Serverless readers in promotion tiers >= 2 will NOT scale with the writer, which can lead to '+ + 'availability issues if a failover event occurs. It is recommended that at least one reader '+ + 'has `scaleWithWriter` set to true', + ); + } + } else { + if (serverlessInHighestTier && highestTier > 1) { + Annotations.of(this).addWarning( + `There are serverlessV2 readers in tier ${highestTier}. Since there are no instances in a higher tier, `+ + 'any instance in this tier is a failover target. Since this tier is > 1 the serverless reader will not scale '+ + 'with the writer which could lead to availability issues during failover.', + ); + } + if (someProvisionedReadersDontMatchWriter.length > 0 && writer.type === InstanceType.PROVISIONED) { + Annotations.of(this).addWarning( + `There are provisioned readers in the highest promotion tier ${highestTier} that do not have the same `+ + 'InstanceSize as the writer. Any of these instances could be chosen as the new writer in the event '+ + 'of a failover.\n'+ + `Writer InstanceSize: ${writer.instanceSize}\n`+ + `Reader InstanceSizes: ${someProvisionedReadersDontMatchWriter.map(reader => reader.instanceSize).join(', ')}`, + ); + } + } + } + } + + /** + * Perform validations on the reader instance + */ + private validateReaderInstance(writer: IAuroraClusterInstance, reader: IAuroraClusterInstance): void { + if (writer.type === InstanceType.PROVISIONED) { + if (reader.type === InstanceType.SERVERLESS_V2) { + if (!instanceSizeSupportedByServerlessV2(writer.instanceSize!, this.serverlessV2MaxCapacity)) { + Annotations.of(this).addWarning( + 'For high availability any serverless instances in promotion tiers 0-1 '+ + 'should be able to scale to match the provisioned instance capacity.\n'+ + `Serverless instance ${reader.node.id} is in promotion tier ${reader.tier},\n`+ + `But can not scale to match the provisioned writer instance (${writer.instanceSize})`, + ); + } + } + } else { + // TODO: add some info around serverless instance tiers and matching scaling + Annotations.of(this).addInfo('...'); + } + } + + /** + * As a cluster-level metric, it represents the average of the ServerlessDatabaseCapacity + * values of all the Aurora Serverless v2 DB instances in the cluster. + */ + public metricServerlessDatabaseCapacity(props?: cloudwatch.MetricOptions) { + return this.metric('ServerlessDatabaseCapacity', { statistic: 'Average', ...props }); + } + + /** + * This value is represented as a percentage. It's calculated as the value of the + * ServerlessDatabaseCapacity metric divided by the maximum ACU value of the DB cluster. + * + * If this metric approaches a value of 100.0, the DB instance has scaled up as high as it can. + * Consider increasing the maximum ACU setting for the cluster. + */ + public metricACUUtilization(props?: cloudwatch.MetricOptions) { + return this.metric('ACUUtilization', { statistic: 'Average', ...props }); + } + private validateServerlessScalingConfig(): void { if (this.serverlessV2MaxCapacity > 128 || this.serverlessV2MaxCapacity < 0.5) { throw new Error('serverlessV2MaxCapacity must be >= 0.5 & <= 128'); @@ -961,7 +966,7 @@ export class DatabaseCluster extends DatabaseClusterNew { throw new Error('writer must be provided'); } - const createdInstances = props.writer ? this.createInstances(props) : legacyCreateInstances(this, props, this.subnetGroup); + const createdInstances = props.writer ? this._createInstances(props) : legacyCreateInstances(this, props, this.subnetGroup); this.instanceIdentifiers = createdInstances.instanceIdentifiers; this.instanceEndpoints = createdInstances.instanceEndpoints; } @@ -969,52 +974,57 @@ export class DatabaseCluster extends DatabaseClusterNew { } /** - * RDS instances that require more memory than is supported by serverlessV2 - * - * The key is the instance type and the value is the minimum size that is NOT supported. - * Example, { m5: '24' } means that if the instance type is m5.24xlarge or above then - * it is not supported by serverless v2 because the memory requirement is > 256GB + * Mapping of instance type to memory setting on the xlarge size + * The memory is predictable based on the xlarge size. For example + * if m5.xlarge has 16GB memory then + * - m5.2xlarge will have 32 (16*2) + * - m5.4xlarge will have 62 (16*4) + * - m5.24xlarge will have 384 (16*24) */ -const UN_SUPPORTED_PROVISIONED_SIZES: { [type: string]: string } = { - m5: '24', - m5d: '24', - r6g: '12', - r5: '12', - r5b: '12', - r5d: '12', - r4: '16', - x2g: '4', - x1e: '4', - x1: '16', - z1d: '12', +const INSTANCE_TYPE_XLARGE_MEMORY_MAPPING: { [instanceType: string]: number } = { + m5: 16, + m5d: 16, + m6g: 16, + t4g: 16, + t3: 16, + m4: 16, + r6g: 32, + r5: 32, + r5b: 32, + r5d: 32, + r4: 30.5, + x2g: 64, + x1e: 122, + x1: 61, + z1d: 32, }; /** - * This validates that the instance size falls within the maximum available serverless - * capacity (256GB memory). This does not validate whether the actual provided `serverlessV2MaxCapacity` - * is supported by the instance size. That would be ideal, but would also require having a mapping - * of instance size to total memory. + * This validates that the instance size falls within the maximum configured serverless capacity. * * @param instanceSize the instance size of the provisioned writer, e.g. r5.xlarge + * @param serverlessV2MaxCapacity the maxCapacity configured on the cluster * @returns true if the instance size is supported by serverless v2 instances */ -function instanceSizeSupportedByServerlessV2(instanceSize: string): boolean { +function instanceSizeSupportedByServerlessV2(instanceSize: string, serverlessV2MaxCapacity: number): boolean { + const serverlessMaxMem = serverlessV2MaxCapacity*2; // i.e. r5.xlarge const sizeParts = instanceSize.split('.'); if (sizeParts.length === 2) { const type = sizeParts[0]; const size = sizeParts[1]; - if (size === 'xlarge') { - return true; - } else if (size.endsWith('xlarge')) { - const sizeNum = size.slice(0, -6); - if (UN_SUPPORTED_PROVISIONED_SIZES.hasOwnProperty(type)) { - const unSupported = UN_SUPPORTED_PROVISIONED_SIZES[type]; - if (sizeNum >= unSupported) { - return false; - } + const xlargeMem = INSTANCE_TYPE_XLARGE_MEMORY_MAPPING[type]; + if (size.endsWith('xlarge')) { + const instanceMem = size === 'xlarge' + ? xlargeMem + : Number(size.slice(0, -6))*xlargeMem; + if (instanceMem > serverlessMaxMem) { + return false; } + // smaller than xlarge + } else { + return true; } } else { // some weird non-standard instance types @@ -1153,7 +1163,7 @@ export class DatabaseClusterFromSnapshot extends DatabaseClusterNew { if ((props.writer || props.readers) && (props.instances || props.instanceProps)) { throw new Error('Cannot provide clusterInstances if instances or instanceProps are provided'); } - const createdInstances = props.writer ? this.createInstances(props) : legacyCreateInstances(this, props, this.subnetGroup); + const createdInstances = props.writer ? this._createInstances(props) : legacyCreateInstances(this, props, this.subnetGroup); this.instanceIdentifiers = createdInstances.instanceIdentifiers; this.instanceEndpoints = createdInstances.instanceEndpoints; } diff --git a/packages/aws-cdk-lib/aws-rds/test/cluster.test.ts b/packages/aws-cdk-lib/aws-rds/test/cluster.test.ts index 6643ce01add8c..d602d5972a102 100644 --- a/packages/aws-cdk-lib/aws-rds/test/cluster.test.ts +++ b/packages/aws-cdk-lib/aws-rds/test/cluster.test.ts @@ -206,7 +206,7 @@ describe('cluster new api', () => { }); describe('migrate from instanceProps', () => { - test('', () => { + test('template contains no changes', () => { // GIVEN const stack1 = testStack(); const stack2 = testStack(); @@ -241,23 +241,27 @@ describe('cluster new api', () => { iamAuthentication: true, }); - const clusterInstances = ClusterInstance.fromInstanceProps(test2); new DatabaseCluster(stack2, 'Database', { engine: DatabaseClusterEngine.AURORA, vpc: test2.vpc, securityGroups: test2.securityGroups, - writer: clusterInstances[0], - readers: [...clusterInstances.slice(1)], + writer: ClusterInstance.provisioned('Instance1', { + ...test2, + isFromLegacyInstanceProps: true, + }), + readers: [ + ClusterInstance.provisioned('Instance2', { + ...test2, + isFromLegacyInstanceProps: true, + }), + ], iamAuthentication: true, }); // THEN const test1Template = Template.fromStack(stack1).toJSON(); - // Dbsubnetgroup is not needed on the instance, it is set on the cluster - delete test1Template.Resources.DatabaseInstance1844F58FD.Properties.DBSubnetGroupName; // deleteAutomatedBackups is not needed on the instance, it is set on the cluster delete test1Template.Resources.DatabaseInstance1844F58FD.Properties.DeleteAutomatedBackups; - delete test1Template.Resources.DatabaseInstance2AA380DEE.Properties.DBSubnetGroupName; delete test1Template.Resources.DatabaseInstance2AA380DEE.Properties.DeleteAutomatedBackups; expect( test1Template, @@ -462,7 +466,16 @@ describe('cluster new api', () => { Annotations.fromStack(stack).hasNoWarning('*', '*'); }); - test('serverless reader cannot scale with writer, throw warning', () => { + test.each([ + [ + ec2.InstanceType.of(ec2.InstanceClass.M5, ec2.InstanceSize.XLARGE24 ), + undefined, + ], + [ + ec2.InstanceType.of(ec2.InstanceClass.M5, ec2.InstanceSize.XLARGE ), + 4, + ], + ])('serverless reader cannot scale with writer, throw warning', (instanceType: ec2.InstanceType, maxCapacity?: number) => { // GIVEN const stack = testStack(); const vpc = new ec2.Vpc(stack, 'VPC'); @@ -472,8 +485,9 @@ describe('cluster new api', () => { engine: DatabaseClusterEngine.AURORA, vpc, writer: ClusterInstance.provisioned('writer', { - instanceType: ec2.InstanceType.of(ec2.InstanceClass.M5, ec2.InstanceSize.XLARGE24 ), + instanceType, }), + serverlessV2MaxCapacity: maxCapacity, readers: [ClusterInstance.serverlessV2('reader', { scaleWithWriter: true })], iamAuthentication: true, }); @@ -483,7 +497,7 @@ describe('cluster new api', () => { template.resourceCountIs('AWS::RDS::DBInstance', 2); template.hasResourceProperties('AWS::RDS::DBInstance', { DBClusterIdentifier: { Ref: 'DatabaseB269D8BB' }, - DBInstanceClass: 'db.m5.24xlarge', + DBInstanceClass: `db.${instanceType.toString()}`, PromotionTier: 0, }); @@ -497,7 +511,7 @@ describe('cluster new api', () => { 'For high availability any serverless instances in promotion tiers 0-1 '+ 'should be able to scale to match the provisioned instance capacity.\n'+ 'Serverless instance reader is in promotion tier 1,\n'+ - 'But can not scale to match the provisioned writer instance (m5.24xlarge)', + `But can not scale to match the provisioned writer instance (${instanceType.toString()})`, ); }); }); From 414ef4e0c37d53ec20efa9dbb9131b906e85dd70 Mon Sep 17 00:00:00 2001 From: corymhall <43035978+corymhall@users.noreply.github.com> Date: Thu, 25 May 2023 18:38:50 +0000 Subject: [PATCH 07/10] adding section on metrics --- packages/aws-cdk-lib/aws-rds/README.md | 36 ++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/packages/aws-cdk-lib/aws-rds/README.md b/packages/aws-cdk-lib/aws-rds/README.md index d2dab0244da93..1ae139d5321c3 100644 --- a/packages/aws-cdk-lib/aws-rds/README.md +++ b/packages/aws-cdk-lib/aws-rds/README.md @@ -119,6 +119,42 @@ const cluster = new rds.DatabaseCluster(this, 'Database', { }); ``` +### Monitoring + +There are some CloudWatch metrics that are [important for Aurora Serverless +v2](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-serverless-v2.setting-capacity.html#aurora-serverless-v2.viewing.monitoring). + +- `ServerlessDatabaseCapacity`: An instance-level metric that can also be + evaluated at the cluster level. At the cluster-level it represents the average + capacity of all the instances in the cluster. +- `ACUUtilization`: Value of the `ServerlessDatabaseCapacity`/ max ACU of the + cluster. + +```ts +declare const vpc: ec2.Vpc; +const cluster = new rds.DatabaseCluster(this, 'Database', { + engine: rds.DatabaseClusterEngine.auroraMysql({ version: rds.AuroraMysqlEngineVersion.VER_3_01_0 }), + writer: rds.ClusterInstance.provisioned('writer'), + readers: [ + rds.ClusterInstance.serverlessV2('reader'), + ] + vpc, +}); + +cluster.metricServerlessDatabaseCapacity({ + period: Duration.minutes(10), +}).createAlarm(this, 'capacity', { + threshold: 1.5, + evaluationPeriods: 3, +}); +cluster.metricACUUtilization({ + period: Duration.minutes(10), +}).createAlarm(this, 'alarm', { + evaluationPeriods: 3, + threshold: 90, +}); +``` + #### Capacity & Scaling There are some things to take into consideration with Aurora Serverless v2. From 0cf77ed8b2e989a63ab439f3bf41869e3c7d7997 Mon Sep 17 00:00:00 2001 From: corymhall <43035978+corymhall@users.noreply.github.com> Date: Fri, 26 May 2023 16:46:11 +0000 Subject: [PATCH 08/10] fixing linting errors --- .../test/aws-rds/test/integ.cluster-serverless-v2.ts | 1 - packages/aws-cdk-lib/aws-rds/lib/cluster.ts | 2 -- 2 files changed, 3 deletions(-) diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.ts index bbfdb4c6219ab..6c1b87fc101f9 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.ts @@ -66,7 +66,6 @@ export class TestStack extends Stack { } } - const app = new App(); new IntegTest(app, 'integ-test', { testCases: [new TestStack(app, 'integ-aurora-serverlessv2-cluster')], diff --git a/packages/aws-cdk-lib/aws-rds/lib/cluster.ts b/packages/aws-cdk-lib/aws-rds/lib/cluster.ts index f58cb8d57fc5f..22fe8f1c369f1 100644 --- a/packages/aws-cdk-lib/aws-rds/lib/cluster.ts +++ b/packages/aws-cdk-lib/aws-rds/lib/cluster.ts @@ -436,8 +436,6 @@ export abstract class DatabaseClusterBase extends Resource implements IDatabaseC targetType: secretsmanager.AttachmentTargetType.RDS_DB_CLUSTER, }; } - - } /** From e98a724a9d73e4879ce672089dfb943c16fab644 Mon Sep 17 00:00:00 2001 From: corymhall <43035978+corymhall@users.noreply.github.com> Date: Fri, 26 May 2023 17:18:54 +0000 Subject: [PATCH 09/10] re-run integ test due to upstream changes --- .../__entrypoint__.js | 147 ++++++ .../index.js | 81 ++++ .../cdk.out | 2 +- ...eg-aurora-serverlessv2-cluster.assets.json | 19 +- ...-aurora-serverlessv2-cluster.template.json | 116 +++++ .../integ.json | 2 +- ...efaultTestDeployAssert24D5C536.assets.json | 2 +- .../manifest.json | 22 +- .../tree.json | 454 ++++++++++-------- 9 files changed, 636 insertions(+), 209 deletions(-) create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/asset.ba598c1f1d84f7077ea9c16a6b921e4f8acf18e996100e72a8f17da980e64fdd/__entrypoint__.js create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/asset.ba598c1f1d84f7077ea9c16a6b921e4f8acf18e996100e72a8f17da980e64fdd/index.js diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/asset.ba598c1f1d84f7077ea9c16a6b921e4f8acf18e996100e72a8f17da980e64fdd/__entrypoint__.js b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/asset.ba598c1f1d84f7077ea9c16a6b921e4f8acf18e996100e72a8f17da980e64fdd/__entrypoint__.js new file mode 100644 index 0000000000000..c83ecebaaadac --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/asset.ba598c1f1d84f7077ea9c16a6b921e4f8acf18e996100e72a8f17da980e64fdd/__entrypoint__.js @@ -0,0 +1,147 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.withRetries = exports.handler = exports.external = void 0; +const https = require("https"); +const url = require("url"); +// for unit tests +exports.external = { + sendHttpRequest: defaultSendHttpRequest, + log: defaultLog, + includeStackTraces: true, + userHandlerIndex: './index', +}; +const CREATE_FAILED_PHYSICAL_ID_MARKER = 'AWSCDK::CustomResourceProviderFramework::CREATE_FAILED'; +const MISSING_PHYSICAL_ID_MARKER = 'AWSCDK::CustomResourceProviderFramework::MISSING_PHYSICAL_ID'; +async function handler(event, context) { + const sanitizedEvent = { ...event, ResponseURL: '...' }; + exports.external.log(JSON.stringify(sanitizedEvent, undefined, 2)); + // ignore DELETE event when the physical resource ID is the marker that + // indicates that this DELETE is a subsequent DELETE to a failed CREATE + // operation. + if (event.RequestType === 'Delete' && event.PhysicalResourceId === CREATE_FAILED_PHYSICAL_ID_MARKER) { + exports.external.log('ignoring DELETE event caused by a failed CREATE event'); + await submitResponse('SUCCESS', event); + return; + } + try { + // invoke the user handler. this is intentionally inside the try-catch to + // ensure that if there is an error it's reported as a failure to + // cloudformation (otherwise cfn waits). + // eslint-disable-next-line @typescript-eslint/no-require-imports + const userHandler = require(exports.external.userHandlerIndex).handler; + const result = await userHandler(sanitizedEvent, context); + // validate user response and create the combined event + const responseEvent = renderResponse(event, result); + // submit to cfn as success + await submitResponse('SUCCESS', responseEvent); + } + catch (e) { + const resp = { + ...event, + Reason: exports.external.includeStackTraces ? e.stack : e.message, + }; + if (!resp.PhysicalResourceId) { + // special case: if CREATE fails, which usually implies, we usually don't + // have a physical resource id. in this case, the subsequent DELETE + // operation does not have any meaning, and will likely fail as well. to + // address this, we use a marker so the provider framework can simply + // ignore the subsequent DELETE. + if (event.RequestType === 'Create') { + exports.external.log('CREATE failed, responding with a marker physical resource id so that the subsequent DELETE will be ignored'); + resp.PhysicalResourceId = CREATE_FAILED_PHYSICAL_ID_MARKER; + } + else { + // otherwise, if PhysicalResourceId is not specified, something is + // terribly wrong because all other events should have an ID. + exports.external.log(`ERROR: Malformed event. "PhysicalResourceId" is required: ${JSON.stringify(event)}`); + } + } + // this is an actual error, fail the activity altogether and exist. + await submitResponse('FAILED', resp); + } +} +exports.handler = handler; +function renderResponse(cfnRequest, handlerResponse = {}) { + // if physical ID is not returned, we have some defaults for you based + // on the request type. + const physicalResourceId = handlerResponse.PhysicalResourceId ?? cfnRequest.PhysicalResourceId ?? cfnRequest.RequestId; + // if we are in DELETE and physical ID was changed, it's an error. + if (cfnRequest.RequestType === 'Delete' && physicalResourceId !== cfnRequest.PhysicalResourceId) { + throw new Error(`DELETE: cannot change the physical resource ID from "${cfnRequest.PhysicalResourceId}" to "${handlerResponse.PhysicalResourceId}" during deletion`); + } + // merge request event and result event (result prevails). + return { + ...cfnRequest, + ...handlerResponse, + PhysicalResourceId: physicalResourceId, + }; +} +async function submitResponse(status, event) { + const json = { + Status: status, + Reason: event.Reason ?? status, + StackId: event.StackId, + RequestId: event.RequestId, + PhysicalResourceId: event.PhysicalResourceId || MISSING_PHYSICAL_ID_MARKER, + LogicalResourceId: event.LogicalResourceId, + NoEcho: event.NoEcho, + Data: event.Data, + }; + exports.external.log('submit response to cloudformation', json); + const responseBody = JSON.stringify(json); + const parsedUrl = url.parse(event.ResponseURL); + const req = { + hostname: parsedUrl.hostname, + path: parsedUrl.path, + method: 'PUT', + headers: { + 'content-type': '', + 'content-length': Buffer.byteLength(responseBody, 'utf8'), + }, + }; + const retryOptions = { + attempts: 5, + sleep: 1000, + }; + await withRetries(retryOptions, exports.external.sendHttpRequest)(req, responseBody); +} +async function defaultSendHttpRequest(options, responseBody) { + return new Promise((resolve, reject) => { + try { + const request = https.request(options, _ => resolve()); + request.on('error', reject); + request.write(responseBody); + request.end(); + } + catch (e) { + reject(e); + } + }); +} +function defaultLog(fmt, ...params) { + // eslint-disable-next-line no-console + console.log(fmt, ...params); +} +function withRetries(options, fn) { + return async (...xs) => { + let attempts = options.attempts; + let ms = options.sleep; + while (true) { + try { + return await fn(...xs); + } + catch (e) { + if (attempts-- <= 0) { + throw e; + } + await sleep(Math.floor(Math.random() * ms)); + ms *= 2; + } + } + }; +} +exports.withRetries = withRetries; +async function sleep(ms) { + return new Promise((ok) => setTimeout(ok, ms)); +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZWpzLWVudHJ5cG9pbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJub2RlanMtZW50cnlwb2ludC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSwrQkFBK0I7QUFDL0IsMkJBQTJCO0FBRTNCLGlCQUFpQjtBQUNKLFFBQUEsUUFBUSxHQUFHO0lBQ3RCLGVBQWUsRUFBRSxzQkFBc0I7SUFDdkMsR0FBRyxFQUFFLFVBQVU7SUFDZixrQkFBa0IsRUFBRSxJQUFJO0lBQ3hCLGdCQUFnQixFQUFFLFNBQVM7Q0FDNUIsQ0FBQztBQUVGLE1BQU0sZ0NBQWdDLEdBQUcsd0RBQXdELENBQUM7QUFDbEcsTUFBTSwwQkFBMEIsR0FBRyw4REFBOEQsQ0FBQztBQVczRixLQUFLLFVBQVUsT0FBTyxDQUFDLEtBQWtELEVBQUUsT0FBMEI7SUFDMUcsTUFBTSxjQUFjLEdBQUcsRUFBRSxHQUFHLEtBQUssRUFBRSxXQUFXLEVBQUUsS0FBSyxFQUFFLENBQUM7SUFDeEQsZ0JBQVEsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxjQUFjLEVBQUUsU0FBUyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFFM0QsdUVBQXVFO0lBQ3ZFLHVFQUF1RTtJQUN2RSxhQUFhO0lBQ2IsSUFBSSxLQUFLLENBQUMsV0FBVyxLQUFLLFFBQVEsSUFBSSxLQUFLLENBQUMsa0JBQWtCLEtBQUssZ0NBQWdDLEVBQUU7UUFDbkcsZ0JBQVEsQ0FBQyxHQUFHLENBQUMsdURBQXVELENBQUMsQ0FBQztRQUN0RSxNQUFNLGNBQWMsQ0FBQyxTQUFTLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDdkMsT0FBTztLQUNSO0lBRUQsSUFBSTtRQUNGLHlFQUF5RTtRQUN6RSxpRUFBaUU7UUFDakUsd0NBQXdDO1FBQ3hDLGlFQUFpRTtRQUNqRSxNQUFNLFdBQVcsR0FBWSxPQUFPLENBQUMsZ0JBQVEsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLE9BQU8sQ0FBQztRQUN4RSxNQUFNLE1BQU0sR0FBRyxNQUFNLFdBQVcsQ0FBQyxjQUFjLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFFMUQsdURBQXVEO1FBQ3ZELE1BQU0sYUFBYSxHQUFHLGNBQWMsQ0FBQyxLQUFLLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFFcEQsMkJBQTJCO1FBQzNCLE1BQU0sY0FBYyxDQUFDLFNBQVMsRUFBRSxhQUFhLENBQUMsQ0FBQztLQUNoRDtJQUFDLE9BQU8sQ0FBTSxFQUFFO1FBQ2YsTUFBTSxJQUFJLEdBQWE7WUFDckIsR0FBRyxLQUFLO1lBQ1IsTUFBTSxFQUFFLGdCQUFRLENBQUMsa0JBQWtCLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPO1NBQzFELENBQUM7UUFFRixJQUFJLENBQUMsSUFBSSxDQUFDLGtCQUFrQixFQUFFO1lBQzVCLHlFQUF5RTtZQUN6RSxtRUFBbUU7WUFDbkUsd0VBQXdFO1lBQ3hFLHFFQUFxRTtZQUNyRSxnQ0FBZ0M7WUFDaEMsSUFBSSxLQUFLLENBQUMsV0FBVyxLQUFLLFFBQVEsRUFBRTtnQkFDbEMsZ0JBQVEsQ0FBQyxHQUFHLENBQUMsNEdBQTRHLENBQUMsQ0FBQztnQkFDM0gsSUFBSSxDQUFDLGtCQUFrQixHQUFHLGdDQUFnQyxDQUFDO2FBQzVEO2lCQUFNO2dCQUNMLGtFQUFrRTtnQkFDbEUsNkRBQTZEO2dCQUM3RCxnQkFBUSxDQUFDLEdBQUcsQ0FBQyw2REFBNkQsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUM7YUFDcEc7U0FDRjtRQUVELG1FQUFtRTtRQUNuRSxNQUFNLGNBQWMsQ0FBQyxRQUFRLEVBQUUsSUFBSSxDQUFDLENBQUM7S0FDdEM7QUFDSCxDQUFDO0FBbkRELDBCQW1EQztBQUVELFNBQVMsY0FBYyxDQUNyQixVQUF5RixFQUN6RixrQkFBMEMsRUFBRztJQUU3QyxzRUFBc0U7SUFDdEUsdUJBQXVCO0lBQ3ZCLE1BQU0sa0JBQWtCLEdBQUcsZUFBZSxDQUFDLGtCQUFrQixJQUFJLFVBQVUsQ0FBQyxrQkFBa0IsSUFBSSxVQUFVLENBQUMsU0FBUyxDQUFDO0lBRXZILGtFQUFrRTtJQUNsRSxJQUFJLFVBQVUsQ0FBQyxXQUFXLEtBQUssUUFBUSxJQUFJLGtCQUFrQixLQUFLLFVBQVUsQ0FBQyxrQkFBa0IsRUFBRTtRQUMvRixNQUFNLElBQUksS0FBSyxDQUFDLHdEQUF3RCxVQUFVLENBQUMsa0JBQWtCLFNBQVMsZUFBZSxDQUFDLGtCQUFrQixtQkFBbUIsQ0FBQyxDQUFDO0tBQ3RLO0lBRUQsMERBQTBEO0lBQzFELE9BQU87UUFDTCxHQUFHLFVBQVU7UUFDYixHQUFHLGVBQWU7UUFDbEIsa0JBQWtCLEVBQUUsa0JBQWtCO0tBQ3ZDLENBQUM7QUFDSixDQUFDO0FBRUQsS0FBSyxVQUFVLGNBQWMsQ0FBQyxNQUE0QixFQUFFLEtBQWU7SUFDekUsTUFBTSxJQUFJLEdBQW1EO1FBQzNELE1BQU0sRUFBRSxNQUFNO1FBQ2QsTUFBTSxFQUFFLEtBQUssQ0FBQyxNQUFNLElBQUksTUFBTTtRQUM5QixPQUFPLEVBQUUsS0FBSyxDQUFDLE9BQU87UUFDdEIsU0FBUyxFQUFFLEtBQUssQ0FBQyxTQUFTO1FBQzFCLGtCQUFrQixFQUFFLEtBQUssQ0FBQyxrQkFBa0IsSUFBSSwwQkFBMEI7UUFDMUUsaUJBQWlCLEVBQUUsS0FBSyxDQUFDLGlCQUFpQjtRQUMxQyxNQUFNLEVBQUUsS0FBSyxDQUFDLE1BQU07UUFDcEIsSUFBSSxFQUFFLEtBQUssQ0FBQyxJQUFJO0tBQ2pCLENBQUM7SUFFRixnQkFBUSxDQUFDLEdBQUcsQ0FBQyxtQ0FBbUMsRUFBRSxJQUFJLENBQUMsQ0FBQztJQUV4RCxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzFDLE1BQU0sU0FBUyxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQy9DLE1BQU0sR0FBRyxHQUFHO1FBQ1YsUUFBUSxFQUFFLFNBQVMsQ0FBQyxRQUFRO1FBQzVCLElBQUksRUFBRSxTQUFTLENBQUMsSUFBSTtRQUNwQixNQUFNLEVBQUUsS0FBSztRQUNiLE9BQU8sRUFBRTtZQUNQLGNBQWMsRUFBRSxFQUFFO1lBQ2xCLGdCQUFnQixFQUFFLE1BQU0sQ0FBQyxVQUFVLENBQUMsWUFBWSxFQUFFLE1BQU0sQ0FBQztTQUMxRDtLQUNGLENBQUM7SUFFRixNQUFNLFlBQVksR0FBRztRQUNuQixRQUFRLEVBQUUsQ0FBQztRQUNYLEtBQUssRUFBRSxJQUFJO0tBQ1osQ0FBQztJQUNGLE1BQU0sV0FBVyxDQUFDLFlBQVksRUFBRSxnQkFBUSxDQUFDLGVBQWUsQ0FBQyxDQUFDLEdBQUcsRUFBRSxZQUFZLENBQUMsQ0FBQztBQUMvRSxDQUFDO0FBRUQsS0FBSyxVQUFVLHNCQUFzQixDQUFDLE9BQTZCLEVBQUUsWUFBb0I7SUFDdkYsT0FBTyxJQUFJLE9BQU8sQ0FBQyxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRTtRQUNyQyxJQUFJO1lBQ0YsTUFBTSxPQUFPLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1lBQ3ZELE9BQU8sQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1lBQzVCLE9BQU8sQ0FBQyxLQUFLLENBQUMsWUFBWSxDQUFDLENBQUM7WUFDNUIsT0FBTyxDQUFDLEdBQUcsRUFBRSxDQUFDO1NBQ2Y7UUFBQyxPQUFPLENBQUMsRUFBRTtZQUNWLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztTQUNYO0lBQ0gsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDO0FBRUQsU0FBUyxVQUFVLENBQUMsR0FBVyxFQUFFLEdBQUcsTUFBYTtJQUMvQyxzQ0FBc0M7SUFDdEMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxNQUFNLENBQUMsQ0FBQztBQUM5QixDQUFDO0FBU0QsU0FBZ0IsV0FBVyxDQUEwQixPQUFxQixFQUFFLEVBQTRCO0lBQ3RHLE9BQU8sS0FBSyxFQUFFLEdBQUcsRUFBSyxFQUFFLEVBQUU7UUFDeEIsSUFBSSxRQUFRLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQztRQUNoQyxJQUFJLEVBQUUsR0FBRyxPQUFPLENBQUMsS0FBSyxDQUFDO1FBQ3ZCLE9BQU8sSUFBSSxFQUFFO1lBQ1gsSUFBSTtnQkFDRixPQUFPLE1BQU0sRUFBRSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUM7YUFDeEI7WUFBQyxPQUFPLENBQUMsRUFBRTtnQkFDVixJQUFJLFFBQVEsRUFBRSxJQUFJLENBQUMsRUFBRTtvQkFDbkIsTUFBTSxDQUFDLENBQUM7aUJBQ1Q7Z0JBQ0QsTUFBTSxLQUFLLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQztnQkFDNUMsRUFBRSxJQUFJLENBQUMsQ0FBQzthQUNUO1NBQ0Y7SUFDSCxDQUFDLENBQUM7QUFDSixDQUFDO0FBaEJELGtDQWdCQztBQUVELEtBQUssVUFBVSxLQUFLLENBQUMsRUFBVTtJQUM3QixPQUFPLElBQUksT0FBTyxDQUFDLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxVQUFVLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUM7QUFDakQsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIGh0dHBzIGZyb20gJ2h0dHBzJztcbmltcG9ydCAqIGFzIHVybCBmcm9tICd1cmwnO1xuXG4vLyBmb3IgdW5pdCB0ZXN0c1xuZXhwb3J0IGNvbnN0IGV4dGVybmFsID0ge1xuICBzZW5kSHR0cFJlcXVlc3Q6IGRlZmF1bHRTZW5kSHR0cFJlcXVlc3QsXG4gIGxvZzogZGVmYXVsdExvZyxcbiAgaW5jbHVkZVN0YWNrVHJhY2VzOiB0cnVlLFxuICB1c2VySGFuZGxlckluZGV4OiAnLi9pbmRleCcsXG59O1xuXG5jb25zdCBDUkVBVEVfRkFJTEVEX1BIWVNJQ0FMX0lEX01BUktFUiA9ICdBV1NDREs6OkN1c3RvbVJlc291cmNlUHJvdmlkZXJGcmFtZXdvcms6OkNSRUFURV9GQUlMRUQnO1xuY29uc3QgTUlTU0lOR19QSFlTSUNBTF9JRF9NQVJLRVIgPSAnQVdTQ0RLOjpDdXN0b21SZXNvdXJjZVByb3ZpZGVyRnJhbWV3b3JrOjpNSVNTSU5HX1BIWVNJQ0FMX0lEJztcblxuZXhwb3J0IHR5cGUgUmVzcG9uc2UgPSBBV1NMYW1iZGEuQ2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZUV2ZW50ICYgSGFuZGxlclJlc3BvbnNlO1xuZXhwb3J0IHR5cGUgSGFuZGxlciA9IChldmVudDogQVdTTGFtYmRhLkNsb3VkRm9ybWF0aW9uQ3VzdG9tUmVzb3VyY2VFdmVudCwgY29udGV4dDogQVdTTGFtYmRhLkNvbnRleHQpID0+IFByb21pc2U8SGFuZGxlclJlc3BvbnNlIHwgdm9pZD47XG5leHBvcnQgdHlwZSBIYW5kbGVyUmVzcG9uc2UgPSB1bmRlZmluZWQgfCB7XG4gIERhdGE/OiBhbnk7XG4gIFBoeXNpY2FsUmVzb3VyY2VJZD86IHN0cmluZztcbiAgUmVhc29uPzogc3RyaW5nO1xuICBOb0VjaG8/OiBib29sZWFuO1xufTtcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGhhbmRsZXIoZXZlbnQ6IEFXU0xhbWJkYS5DbG91ZEZvcm1hdGlvbkN1c3RvbVJlc291cmNlRXZlbnQsIGNvbnRleHQ6IEFXU0xhbWJkYS5Db250ZXh0KSB7XG4gIGNvbnN0IHNhbml0aXplZEV2ZW50ID0geyAuLi5ldmVudCwgUmVzcG9uc2VVUkw6ICcuLi4nIH07XG4gIGV4dGVybmFsLmxvZyhKU09OLnN0cmluZ2lmeShzYW5pdGl6ZWRFdmVudCwgdW5kZWZpbmVkLCAyKSk7XG5cbiAgLy8gaWdub3JlIERFTEVURSBldmVudCB3aGVuIHRoZSBwaHlzaWNhbCByZXNvdXJjZSBJRCBpcyB0aGUgbWFya2VyIHRoYXRcbiAgLy8gaW5kaWNhdGVzIHRoYXQgdGhpcyBERUxFVEUgaXMgYSBzdWJzZXF1ZW50IERFTEVURSB0byBhIGZhaWxlZCBDUkVBVEVcbiAgLy8gb3BlcmF0aW9uLlxuICBpZiAoZXZlbnQuUmVxdWVzdFR5cGUgPT09ICdEZWxldGUnICYmIGV2ZW50LlBoeXNpY2FsUmVzb3VyY2VJZCA9PT0gQ1JFQVRFX0ZBSUxFRF9QSFlTSUNBTF9JRF9NQVJLRVIpIHtcbiAgICBleHRlcm5hbC5sb2coJ2lnbm9yaW5nIERFTEVURSBldmVudCBjYXVzZWQgYnkgYSBmYWlsZWQgQ1JFQVRFIGV2ZW50Jyk7XG4gICAgYXdhaXQgc3VibWl0UmVzcG9uc2UoJ1NVQ0NFU1MnLCBldmVudCk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgdHJ5IHtcbiAgICAvLyBpbnZva2UgdGhlIHVzZXIgaGFuZGxlci4gdGhpcyBpcyBpbnRlbnRpb25hbGx5IGluc2lkZSB0aGUgdHJ5LWNhdGNoIHRvXG4gICAgLy8gZW5zdXJlIHRoYXQgaWYgdGhlcmUgaXMgYW4gZXJyb3IgaXQncyByZXBvcnRlZCBhcyBhIGZhaWx1cmUgdG9cbiAgICAvLyBjbG91ZGZvcm1hdGlvbiAob3RoZXJ3aXNlIGNmbiB3YWl0cykuXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1yZXF1aXJlLWltcG9ydHNcbiAgICBjb25zdCB1c2VySGFuZGxlcjogSGFuZGxlciA9IHJlcXVpcmUoZXh0ZXJuYWwudXNlckhhbmRsZXJJbmRleCkuaGFuZGxlcjtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB1c2VySGFuZGxlcihzYW5pdGl6ZWRFdmVudCwgY29udGV4dCk7XG5cbiAgICAvLyB2YWxpZGF0ZSB1c2VyIHJlc3BvbnNlIGFuZCBjcmVhdGUgdGhlIGNvbWJpbmVkIGV2ZW50XG4gICAgY29uc3QgcmVzcG9uc2VFdmVudCA9IHJlbmRlclJlc3BvbnNlKGV2ZW50LCByZXN1bHQpO1xuXG4gICAgLy8gc3VibWl0IHRvIGNmbiBhcyBzdWNjZXNzXG4gICAgYXdhaXQgc3VibWl0UmVzcG9uc2UoJ1NVQ0NFU1MnLCByZXNwb25zZUV2ZW50KTtcbiAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgY29uc3QgcmVzcDogUmVzcG9uc2UgPSB7XG4gICAgICAuLi5ldmVudCxcbiAgICAgIFJlYXNvbjogZXh0ZXJuYWwuaW5jbHVkZVN0YWNrVHJhY2VzID8gZS5zdGFjayA6IGUubWVzc2FnZSxcbiAgICB9O1xuXG4gICAgaWYgKCFyZXNwLlBoeXNpY2FsUmVzb3VyY2VJZCkge1xuICAgICAgLy8gc3BlY2lhbCBjYXNlOiBpZiBDUkVBVEUgZmFpbHMsIHdoaWNoIHVzdWFsbHkgaW1wbGllcywgd2UgdXN1YWxseSBkb24ndFxuICAgICAgLy8gaGF2ZSBhIHBoeXNpY2FsIHJlc291cmNlIGlkLiBpbiB0aGlzIGNhc2UsIHRoZSBzdWJzZXF1ZW50IERFTEVURVxuICAgICAgLy8gb3BlcmF0aW9uIGRvZXMgbm90IGhhdmUgYW55IG1lYW5pbmcsIGFuZCB3aWxsIGxpa2VseSBmYWlsIGFzIHdlbGwuIHRvXG4gICAgICAvLyBhZGRyZXNzIHRoaXMsIHdlIHVzZSBhIG1hcmtlciBzbyB0aGUgcHJvdmlkZXIgZnJhbWV3b3JrIGNhbiBzaW1wbHlcbiAgICAgIC8vIGlnbm9yZSB0aGUgc3Vic2VxdWVudCBERUxFVEUuXG4gICAgICBpZiAoZXZlbnQuUmVxdWVzdFR5cGUgPT09ICdDcmVhdGUnKSB7XG4gICAgICAgIGV4dGVybmFsLmxvZygnQ1JFQVRFIGZhaWxlZCwgcmVzcG9uZGluZyB3aXRoIGEgbWFya2VyIHBoeXNpY2FsIHJlc291cmNlIGlkIHNvIHRoYXQgdGhlIHN1YnNlcXVlbnQgREVMRVRFIHdpbGwgYmUgaWdub3JlZCcpO1xuICAgICAgICByZXNwLlBoeXNpY2FsUmVzb3VyY2VJZCA9IENSRUFURV9GQUlMRURfUEhZU0lDQUxfSURfTUFSS0VSO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gb3RoZXJ3aXNlLCBpZiBQaHlzaWNhbFJlc291cmNlSWQgaXMgbm90IHNwZWNpZmllZCwgc29tZXRoaW5nIGlzXG4gICAgICAgIC8vIHRlcnJpYmx5IHdyb25nIGJlY2F1c2UgYWxsIG90aGVyIGV2ZW50cyBzaG91bGQgaGF2ZSBhbiBJRC5cbiAgICAgICAgZXh0ZXJuYWwubG9nKGBFUlJPUjogTWFsZm9ybWVkIGV2ZW50LiBcIlBoeXNpY2FsUmVzb3VyY2VJZFwiIGlzIHJlcXVpcmVkOiAke0pTT04uc3RyaW5naWZ5KGV2ZW50KX1gKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyB0aGlzIGlzIGFuIGFjdHVhbCBlcnJvciwgZmFpbCB0aGUgYWN0aXZpdHkgYWx0b2dldGhlciBhbmQgZXhpc3QuXG4gICAgYXdhaXQgc3VibWl0UmVzcG9uc2UoJ0ZBSUxFRCcsIHJlc3ApO1xuICB9XG59XG5cbmZ1bmN0aW9uIHJlbmRlclJlc3BvbnNlKFxuICBjZm5SZXF1ZXN0OiBBV1NMYW1iZGEuQ2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZUV2ZW50ICYgeyBQaHlzaWNhbFJlc291cmNlSWQ/OiBzdHJpbmcgfSxcbiAgaGFuZGxlclJlc3BvbnNlOiB2b2lkIHwgSGFuZGxlclJlc3BvbnNlID0geyB9KTogUmVzcG9uc2Uge1xuXG4gIC8vIGlmIHBoeXNpY2FsIElEIGlzIG5vdCByZXR1cm5lZCwgd2UgaGF2ZSBzb21lIGRlZmF1bHRzIGZvciB5b3UgYmFzZWRcbiAgLy8gb24gdGhlIHJlcXVlc3QgdHlwZS5cbiAgY29uc3QgcGh5c2ljYWxSZXNvdXJjZUlkID0gaGFuZGxlclJlc3BvbnNlLlBoeXNpY2FsUmVzb3VyY2VJZCA/PyBjZm5SZXF1ZXN0LlBoeXNpY2FsUmVzb3VyY2VJZCA/PyBjZm5SZXF1ZXN0LlJlcXVlc3RJZDtcblxuICAvLyBpZiB3ZSBhcmUgaW4gREVMRVRFIGFuZCBwaHlzaWNhbCBJRCB3YXMgY2hhbmdlZCwgaXQncyBhbiBlcnJvci5cbiAgaWYgKGNmblJlcXVlc3QuUmVxdWVzdFR5cGUgPT09ICdEZWxldGUnICYmIHBoeXNpY2FsUmVzb3VyY2VJZCAhPT0gY2ZuUmVxdWVzdC5QaHlzaWNhbFJlc291cmNlSWQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYERFTEVURTogY2Fubm90IGNoYW5nZSB0aGUgcGh5c2ljYWwgcmVzb3VyY2UgSUQgZnJvbSBcIiR7Y2ZuUmVxdWVzdC5QaHlzaWNhbFJlc291cmNlSWR9XCIgdG8gXCIke2hhbmRsZXJSZXNwb25zZS5QaHlzaWNhbFJlc291cmNlSWR9XCIgZHVyaW5nIGRlbGV0aW9uYCk7XG4gIH1cblxuICAvLyBtZXJnZSByZXF1ZXN0IGV2ZW50IGFuZCByZXN1bHQgZXZlbnQgKHJlc3VsdCBwcmV2YWlscykuXG4gIHJldHVybiB7XG4gICAgLi4uY2ZuUmVxdWVzdCxcbiAgICAuLi5oYW5kbGVyUmVzcG9uc2UsXG4gICAgUGh5c2ljYWxSZXNvdXJjZUlkOiBwaHlzaWNhbFJlc291cmNlSWQsXG4gIH07XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHN1Ym1pdFJlc3BvbnNlKHN0YXR1czogJ1NVQ0NFU1MnIHwgJ0ZBSUxFRCcsIGV2ZW50OiBSZXNwb25zZSkge1xuICBjb25zdCBqc29uOiBBV1NMYW1iZGEuQ2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZVJlc3BvbnNlID0ge1xuICAgIFN0YXR1czogc3RhdHVzLFxuICAgIFJlYXNvbjogZXZlbnQuUmVhc29uID8/IHN0YXR1cyxcbiAgICBTdGFja0lkOiBldmVudC5TdGFja0lkLFxuICAgIFJlcXVlc3RJZDogZXZlbnQuUmVxdWVzdElkLFxuICAgIFBoeXNpY2FsUmVzb3VyY2VJZDogZXZlbnQuUGh5c2ljYWxSZXNvdXJjZUlkIHx8IE1JU1NJTkdfUEhZU0lDQUxfSURfTUFSS0VSLFxuICAgIExvZ2ljYWxSZXNvdXJjZUlkOiBldmVudC5Mb2dpY2FsUmVzb3VyY2VJZCxcbiAgICBOb0VjaG86IGV2ZW50Lk5vRWNobyxcbiAgICBEYXRhOiBldmVudC5EYXRhLFxuICB9O1xuXG4gIGV4dGVybmFsLmxvZygnc3VibWl0IHJlc3BvbnNlIHRvIGNsb3VkZm9ybWF0aW9uJywganNvbik7XG5cbiAgY29uc3QgcmVzcG9uc2VCb2R5ID0gSlNPTi5zdHJpbmdpZnkoanNvbik7XG4gIGNvbnN0IHBhcnNlZFVybCA9IHVybC5wYXJzZShldmVudC5SZXNwb25zZVVSTCk7XG4gIGNvbnN0IHJlcSA9IHtcbiAgICBob3N0bmFtZTogcGFyc2VkVXJsLmhvc3RuYW1lLFxuICAgIHBhdGg6IHBhcnNlZFVybC5wYXRoLFxuICAgIG1ldGhvZDogJ1BVVCcsXG4gICAgaGVhZGVyczoge1xuICAgICAgJ2NvbnRlbnQtdHlwZSc6ICcnLFxuICAgICAgJ2NvbnRlbnQtbGVuZ3RoJzogQnVmZmVyLmJ5dGVMZW5ndGgocmVzcG9uc2VCb2R5LCAndXRmOCcpLFxuICAgIH0sXG4gIH07XG5cbiAgY29uc3QgcmV0cnlPcHRpb25zID0ge1xuICAgIGF0dGVtcHRzOiA1LFxuICAgIHNsZWVwOiAxMDAwLFxuICB9O1xuICBhd2FpdCB3aXRoUmV0cmllcyhyZXRyeU9wdGlvbnMsIGV4dGVybmFsLnNlbmRIdHRwUmVxdWVzdCkocmVxLCByZXNwb25zZUJvZHkpO1xufVxuXG5hc3luYyBmdW5jdGlvbiBkZWZhdWx0U2VuZEh0dHBSZXF1ZXN0KG9wdGlvbnM6IGh0dHBzLlJlcXVlc3RPcHRpb25zLCByZXNwb25zZUJvZHk6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXF1ZXN0ID0gaHR0cHMucmVxdWVzdChvcHRpb25zLCBfID0+IHJlc29sdmUoKSk7XG4gICAgICByZXF1ZXN0Lm9uKCdlcnJvcicsIHJlamVjdCk7XG4gICAgICByZXF1ZXN0LndyaXRlKHJlc3BvbnNlQm9keSk7XG4gICAgICByZXF1ZXN0LmVuZCgpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHJlamVjdChlKTtcbiAgICB9XG4gIH0pO1xufVxuXG5mdW5jdGlvbiBkZWZhdWx0TG9nKGZtdDogc3RyaW5nLCAuLi5wYXJhbXM6IGFueVtdKSB7XG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1jb25zb2xlXG4gIGNvbnNvbGUubG9nKGZtdCwgLi4ucGFyYW1zKTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBSZXRyeU9wdGlvbnMge1xuICAvKiogSG93IG1hbnkgcmV0cmllcyAod2lsbCBhdCBsZWFzdCB0cnkgb25jZSkgKi9cbiAgcmVhZG9ubHkgYXR0ZW1wdHM6IG51bWJlcjtcbiAgLyoqIFNsZWVwIGJhc2UsIGluIG1zICovXG4gIHJlYWRvbmx5IHNsZWVwOiBudW1iZXI7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiB3aXRoUmV0cmllczxBIGV4dGVuZHMgQXJyYXk8YW55PiwgQj4ob3B0aW9uczogUmV0cnlPcHRpb25zLCBmbjogKC4uLnhzOiBBKSA9PiBQcm9taXNlPEI+KTogKC4uLnhzOiBBKSA9PiBQcm9taXNlPEI+IHtcbiAgcmV0dXJuIGFzeW5jICguLi54czogQSkgPT4ge1xuICAgIGxldCBhdHRlbXB0cyA9IG9wdGlvbnMuYXR0ZW1wdHM7XG4gICAgbGV0IG1zID0gb3B0aW9ucy5zbGVlcDtcbiAgICB3aGlsZSAodHJ1ZSkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IGZuKC4uLnhzKTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgaWYgKGF0dGVtcHRzLS0gPD0gMCkge1xuICAgICAgICAgIHRocm93IGU7XG4gICAgICAgIH1cbiAgICAgICAgYXdhaXQgc2xlZXAoTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogbXMpKTtcbiAgICAgICAgbXMgKj0gMjtcbiAgICAgIH1cbiAgICB9XG4gIH07XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHNsZWVwKG1zOiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChvaykgPT4gc2V0VGltZW91dChvaywgbXMpKTtcbn1cbiJdfQ== \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/asset.ba598c1f1d84f7077ea9c16a6b921e4f8acf18e996100e72a8f17da980e64fdd/index.js b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/asset.ba598c1f1d84f7077ea9c16a6b921e4f8acf18e996100e72a8f17da980e64fdd/index.js new file mode 100644 index 0000000000000..cf597f535efd3 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/asset.ba598c1f1d84f7077ea9c16a6b921e4f8acf18e996100e72a8f17da980e64fdd/index.js @@ -0,0 +1,81 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.handler = void 0; +// eslint-disable-next-line import/no-extraneous-dependencies +const aws_sdk_1 = require("aws-sdk"); +const ec2 = new aws_sdk_1.EC2(); +/** + * The default security group ingress rule. This can be used to both revoke and authorize the rules + */ +function ingressRuleParams(groupId, account) { + return { + GroupId: groupId, + IpPermissions: [{ + UserIdGroupPairs: [{ + GroupId: groupId, + UserId: account, + }], + IpProtocol: '-1', + }], + }; +} +/** + * The default security group egress rule. This can be used to both revoke and authorize the rules + */ +function egressRuleParams(groupId) { + return { + GroupId: groupId, + IpPermissions: [{ + IpRanges: [{ + CidrIp: '0.0.0.0/0', + }], + IpProtocol: '-1', + }], + }; +} +/** + * Process a custom resource request to restrict the default security group + * ingress & egress rules. + * + * When someone turns off the property then this custom resource will be deleted in which + * case we should add back the rules that were removed. + */ +async function handler(event) { + const securityGroupId = event.ResourceProperties.DefaultSecurityGroupId; + const account = event.ResourceProperties.Account; + switch (event.RequestType) { + case 'Create': + return revokeRules(securityGroupId, account); + case 'Update': + return onUpdate(event); + case 'Delete': + return authorizeRules(securityGroupId, account); + } +} +exports.handler = handler; +async function onUpdate(event) { + const oldSg = event.OldResourceProperties.DefaultSecurityGroupId; + const newSg = event.ResourceProperties.DefaultSecurityGroupId; + if (oldSg !== newSg) { + await authorizeRules(oldSg, event.ResourceProperties.Account); + await revokeRules(newSg, event.ResourceProperties.Account); + } + return; +} +/** + * Revoke both ingress and egress rules + */ +async function revokeRules(groupId, account) { + await ec2.revokeSecurityGroupEgress(egressRuleParams(groupId)).promise(); + await ec2.revokeSecurityGroupIngress(ingressRuleParams(groupId, account)).promise(); + return; +} +/** + * Authorize both ingress and egress rules + */ +async function authorizeRules(groupId, account) { + await ec2.authorizeSecurityGroupIngress(ingressRuleParams(groupId, account)).promise(); + await ec2.authorizeSecurityGroupEgress(egressRuleParams(groupId)).promise(); + return; +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSw2REFBNkQ7QUFDN0QscUNBQThCO0FBRTlCLE1BQU0sR0FBRyxHQUFHLElBQUksYUFBRyxFQUFFLENBQUM7QUFFdEI7O0dBRUc7QUFDSCxTQUFTLGlCQUFpQixDQUFDLE9BQWUsRUFBRSxPQUFlO0lBQ3pELE9BQU87UUFDTCxPQUFPLEVBQUUsT0FBTztRQUNoQixhQUFhLEVBQUUsQ0FBQztnQkFDZCxnQkFBZ0IsRUFBRSxDQUFDO3dCQUNqQixPQUFPLEVBQUUsT0FBTzt3QkFDaEIsTUFBTSxFQUFFLE9BQU87cUJBQ2hCLENBQUM7Z0JBQ0YsVUFBVSxFQUFFLElBQUk7YUFDakIsQ0FBQztLQUNILENBQUM7QUFDSixDQUFDO0FBRUQ7O0dBRUc7QUFDSCxTQUFTLGdCQUFnQixDQUFDLE9BQWU7SUFDdkMsT0FBTztRQUNMLE9BQU8sRUFBRSxPQUFPO1FBQ2hCLGFBQWEsRUFBRSxDQUFDO2dCQUNkLFFBQVEsRUFBRSxDQUFDO3dCQUNULE1BQU0sRUFBRSxXQUFXO3FCQUNwQixDQUFDO2dCQUNGLFVBQVUsRUFBRSxJQUFJO2FBQ2pCLENBQUM7S0FDSCxDQUFDO0FBQ0osQ0FBQztBQUVEOzs7Ozs7R0FNRztBQUNJLEtBQUssVUFBVSxPQUFPLENBQUMsS0FBa0Q7SUFDOUUsTUFBTSxlQUFlLEdBQUcsS0FBSyxDQUFDLGtCQUFrQixDQUFDLHNCQUFzQixDQUFDO0lBQ3hFLE1BQU0sT0FBTyxHQUFHLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQyxPQUFPLENBQUM7SUFDakQsUUFBUSxLQUFLLENBQUMsV0FBVyxFQUFFO1FBQ3pCLEtBQUssUUFBUTtZQUNYLE9BQU8sV0FBVyxDQUFDLGVBQWUsRUFBRSxPQUFPLENBQUMsQ0FBQztRQUMvQyxLQUFLLFFBQVE7WUFDWCxPQUFPLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUN6QixLQUFLLFFBQVE7WUFDWCxPQUFPLGNBQWMsQ0FBQyxlQUFlLEVBQUUsT0FBTyxDQUFDLENBQUM7S0FDbkQ7QUFDSCxDQUFDO0FBWEQsMEJBV0M7QUFDRCxLQUFLLFVBQVUsUUFBUSxDQUFDLEtBQXdEO0lBQzlFLE1BQU0sS0FBSyxHQUFHLEtBQUssQ0FBQyxxQkFBcUIsQ0FBQyxzQkFBc0IsQ0FBQztJQUNqRSxNQUFNLEtBQUssR0FBRyxLQUFLLENBQUMsa0JBQWtCLENBQUMsc0JBQXNCLENBQUM7SUFDOUQsSUFBSSxLQUFLLEtBQUssS0FBSyxFQUFFO1FBQ25CLE1BQU0sY0FBYyxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsa0JBQWtCLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDOUQsTUFBTSxXQUFXLENBQUMsS0FBSyxFQUFFLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQyxPQUFPLENBQUMsQ0FBQztLQUM1RDtJQUNELE9BQU87QUFDVCxDQUFDO0FBRUQ7O0dBRUc7QUFDSCxLQUFLLFVBQVUsV0FBVyxDQUFDLE9BQWUsRUFBRSxPQUFlO0lBQ3pELE1BQU0sR0FBRyxDQUFDLHlCQUF5QixDQUFDLGdCQUFnQixDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUM7SUFDekUsTUFBTSxHQUFHLENBQUMsMEJBQTBCLENBQUMsaUJBQWlCLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUM7SUFDcEYsT0FBTztBQUNULENBQUM7QUFFRDs7R0FFRztBQUNILEtBQUssVUFBVSxjQUFjLENBQUMsT0FBZSxFQUFFLE9BQWU7SUFDNUQsTUFBTSxHQUFHLENBQUMsNkJBQTZCLENBQUMsaUJBQWlCLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUM7SUFDdkYsTUFBTSxHQUFHLENBQUMsNEJBQTRCLENBQUMsZ0JBQWdCLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQztJQUM1RSxPQUFPO0FBQ1QsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBpbXBvcnQvbm8tZXh0cmFuZW91cy1kZXBlbmRlbmNpZXNcbmltcG9ydCB7IEVDMiB9IGZyb20gJ2F3cy1zZGsnO1xuXG5jb25zdCBlYzIgPSBuZXcgRUMyKCk7XG5cbi8qKlxuICogVGhlIGRlZmF1bHQgc2VjdXJpdHkgZ3JvdXAgaW5ncmVzcyBydWxlLiBUaGlzIGNhbiBiZSB1c2VkIHRvIGJvdGggcmV2b2tlIGFuZCBhdXRob3JpemUgdGhlIHJ1bGVzXG4gKi9cbmZ1bmN0aW9uIGluZ3Jlc3NSdWxlUGFyYW1zKGdyb3VwSWQ6IHN0cmluZywgYWNjb3VudDogc3RyaW5nKTogRUMyLlJldm9rZVNlY3VyaXR5R3JvdXBJbmdyZXNzUmVxdWVzdCB8IEVDMi5BdXRob3JpemVTZWN1cml0eUdyb3VwSW5ncmVzc1JlcXVlc3Qge1xuICByZXR1cm4ge1xuICAgIEdyb3VwSWQ6IGdyb3VwSWQsXG4gICAgSXBQZXJtaXNzaW9uczogW3tcbiAgICAgIFVzZXJJZEdyb3VwUGFpcnM6IFt7XG4gICAgICAgIEdyb3VwSWQ6IGdyb3VwSWQsXG4gICAgICAgIFVzZXJJZDogYWNjb3VudCxcbiAgICAgIH1dLFxuICAgICAgSXBQcm90b2NvbDogJy0xJyxcbiAgICB9XSxcbiAgfTtcbn1cblxuLyoqXG4gKiBUaGUgZGVmYXVsdCBzZWN1cml0eSBncm91cCBlZ3Jlc3MgcnVsZS4gVGhpcyBjYW4gYmUgdXNlZCB0byBib3RoIHJldm9rZSBhbmQgYXV0aG9yaXplIHRoZSBydWxlc1xuICovXG5mdW5jdGlvbiBlZ3Jlc3NSdWxlUGFyYW1zKGdyb3VwSWQ6IHN0cmluZyk6IEVDMi5SZXZva2VTZWN1cml0eUdyb3VwRWdyZXNzUmVxdWVzdCB8IEVDMi5BdXRob3JpemVTZWN1cml0eUdyb3VwRWdyZXNzUmVxdWVzdCB7XG4gIHJldHVybiB7XG4gICAgR3JvdXBJZDogZ3JvdXBJZCxcbiAgICBJcFBlcm1pc3Npb25zOiBbe1xuICAgICAgSXBSYW5nZXM6IFt7XG4gICAgICAgIENpZHJJcDogJzAuMC4wLjAvMCcsXG4gICAgICB9XSxcbiAgICAgIElwUHJvdG9jb2w6ICctMScsXG4gICAgfV0sXG4gIH07XG59XG5cbi8qKlxuICogUHJvY2VzcyBhIGN1c3RvbSByZXNvdXJjZSByZXF1ZXN0IHRvIHJlc3RyaWN0IHRoZSBkZWZhdWx0IHNlY3VyaXR5IGdyb3VwXG4gKiBpbmdyZXNzICYgZWdyZXNzIHJ1bGVzLlxuICpcbiAqIFdoZW4gc29tZW9uZSB0dXJucyBvZmYgdGhlIHByb3BlcnR5IHRoZW4gdGhpcyBjdXN0b20gcmVzb3VyY2Ugd2lsbCBiZSBkZWxldGVkIGluIHdoaWNoXG4gKiBjYXNlIHdlIHNob3VsZCBhZGQgYmFjayB0aGUgcnVsZXMgdGhhdCB3ZXJlIHJlbW92ZWQuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBoYW5kbGVyKGV2ZW50OiBBV1NMYW1iZGEuQ2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZUV2ZW50KTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IHNlY3VyaXR5R3JvdXBJZCA9IGV2ZW50LlJlc291cmNlUHJvcGVydGllcy5EZWZhdWx0U2VjdXJpdHlHcm91cElkO1xuICBjb25zdCBhY2NvdW50ID0gZXZlbnQuUmVzb3VyY2VQcm9wZXJ0aWVzLkFjY291bnQ7XG4gIHN3aXRjaCAoZXZlbnQuUmVxdWVzdFR5cGUpIHtcbiAgICBjYXNlICdDcmVhdGUnOlxuICAgICAgcmV0dXJuIHJldm9rZVJ1bGVzKHNlY3VyaXR5R3JvdXBJZCwgYWNjb3VudCk7XG4gICAgY2FzZSAnVXBkYXRlJzpcbiAgICAgIHJldHVybiBvblVwZGF0ZShldmVudCk7XG4gICAgY2FzZSAnRGVsZXRlJzpcbiAgICAgIHJldHVybiBhdXRob3JpemVSdWxlcyhzZWN1cml0eUdyb3VwSWQsIGFjY291bnQpO1xuICB9XG59XG5hc3luYyBmdW5jdGlvbiBvblVwZGF0ZShldmVudDogQVdTTGFtYmRhLkNsb3VkRm9ybWF0aW9uQ3VzdG9tUmVzb3VyY2VVcGRhdGVFdmVudCk6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBvbGRTZyA9IGV2ZW50Lk9sZFJlc291cmNlUHJvcGVydGllcy5EZWZhdWx0U2VjdXJpdHlHcm91cElkO1xuICBjb25zdCBuZXdTZyA9IGV2ZW50LlJlc291cmNlUHJvcGVydGllcy5EZWZhdWx0U2VjdXJpdHlHcm91cElkO1xuICBpZiAob2xkU2cgIT09IG5ld1NnKSB7XG4gICAgYXdhaXQgYXV0aG9yaXplUnVsZXMob2xkU2csIGV2ZW50LlJlc291cmNlUHJvcGVydGllcy5BY2NvdW50KTtcbiAgICBhd2FpdCByZXZva2VSdWxlcyhuZXdTZywgZXZlbnQuUmVzb3VyY2VQcm9wZXJ0aWVzLkFjY291bnQpO1xuICB9XG4gIHJldHVybjtcbn1cblxuLyoqXG4gKiBSZXZva2UgYm90aCBpbmdyZXNzIGFuZCBlZ3Jlc3MgcnVsZXNcbiAqL1xuYXN5bmMgZnVuY3Rpb24gcmV2b2tlUnVsZXMoZ3JvdXBJZDogc3RyaW5nLCBhY2NvdW50OiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgYXdhaXQgZWMyLnJldm9rZVNlY3VyaXR5R3JvdXBFZ3Jlc3MoZWdyZXNzUnVsZVBhcmFtcyhncm91cElkKSkucHJvbWlzZSgpO1xuICBhd2FpdCBlYzIucmV2b2tlU2VjdXJpdHlHcm91cEluZ3Jlc3MoaW5ncmVzc1J1bGVQYXJhbXMoZ3JvdXBJZCwgYWNjb3VudCkpLnByb21pc2UoKTtcbiAgcmV0dXJuO1xufVxuXG4vKipcbiAqIEF1dGhvcml6ZSBib3RoIGluZ3Jlc3MgYW5kIGVncmVzcyBydWxlc1xuICovXG5hc3luYyBmdW5jdGlvbiBhdXRob3JpemVSdWxlcyhncm91cElkOiBzdHJpbmcsIGFjY291bnQ6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICBhd2FpdCBlYzIuYXV0aG9yaXplU2VjdXJpdHlHcm91cEluZ3Jlc3MoaW5ncmVzc1J1bGVQYXJhbXMoZ3JvdXBJZCwgYWNjb3VudCkpLnByb21pc2UoKTtcbiAgYXdhaXQgZWMyLmF1dGhvcml6ZVNlY3VyaXR5R3JvdXBFZ3Jlc3MoZWdyZXNzUnVsZVBhcmFtcyhncm91cElkKSkucHJvbWlzZSgpO1xuICByZXR1cm47XG59XG4iXX0= \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/cdk.out index 7925065efbcc4..f0b901e7c06e5 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"31.0.0"} \ No newline at end of file +{"version":"32.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integ-aurora-serverlessv2-cluster.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integ-aurora-serverlessv2-cluster.assets.json index 583dec2965545..433c4a35e9762 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integ-aurora-serverlessv2-cluster.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integ-aurora-serverlessv2-cluster.assets.json @@ -1,7 +1,20 @@ { - "version": "31.0.0", + "version": "32.0.0", "files": { - "5ec15cecd9b8441a50d23535be26d2c68417eac2f5ddaf3d86e820b5d95a5ea9": { + "ba598c1f1d84f7077ea9c16a6b921e4f8acf18e996100e72a8f17da980e64fdd": { + "source": { + "path": "asset.ba598c1f1d84f7077ea9c16a6b921e4f8acf18e996100e72a8f17da980e64fdd", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "ba598c1f1d84f7077ea9c16a6b921e4f8acf18e996100e72a8f17da980e64fdd.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "bffc468fc464208b727e3300214b3102d30e6f4d749531331ef45d2da89cae51": { "source": { "path": "integ-aurora-serverlessv2-cluster.template.json", "packaging": "file" @@ -9,7 +22,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "5ec15cecd9b8441a50d23535be26d2c68417eac2f5ddaf3d86e820b5d95a5ea9.json", + "objectKey": "bffc468fc464208b727e3300214b3102d30e6f4d749531331ef45d2da89cae51.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integ-aurora-serverlessv2-cluster.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integ-aurora-serverlessv2-cluster.template.json index 60af981d3a7b8..251ce03637f86 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integ-aurora-serverlessv2-cluster.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integ-aurora-serverlessv2-cluster.template.json @@ -391,6 +391,122 @@ } } }, + "IntegVPCRestrictDefaultSecurityGroupCustomResource42DF8AB1": { + "Type": "Custom::VpcRestrictDefaultSG", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "CustomVpcRestrictDefaultSGCustomResourceProviderHandlerDC833E5E", + "Arn" + ] + }, + "DefaultSecurityGroupId": { + "Fn::GetAtt": [ + "IntegVPC2FF1AB0E", + "DefaultSecurityGroup" + ] + }, + "Account": { + "Ref": "AWS::AccountId" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "CustomVpcRestrictDefaultSGCustomResourceProviderRole26592FE0": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ] + }, + "ManagedPolicyArns": [ + { + "Fn::Sub": "arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + } + ], + "Policies": [ + { + "PolicyName": "Inline", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "ec2:AuthorizeSecurityGroupIngress", + "ec2:AuthorizeSecurityGroupEgress", + "ec2:RevokeSecurityGroupIngress", + "ec2:RevokeSecurityGroupEgress" + ], + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":ec2:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":security-group/", + { + "Fn::GetAtt": [ + "IntegVPC2FF1AB0E", + "DefaultSecurityGroup" + ] + } + ] + ] + } + ] + } + ] + } + } + ] + } + }, + "CustomVpcRestrictDefaultSGCustomResourceProviderHandlerDC833E5E": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "ba598c1f1d84f7077ea9c16a6b921e4f8acf18e996100e72a8f17da980e64fdd.zip" + }, + "Timeout": 900, + "MemorySize": 128, + "Handler": "__entrypoint__.handler", + "Role": { + "Fn::GetAtt": [ + "CustomVpcRestrictDefaultSGCustomResourceProviderRole26592FE0", + "Arn" + ] + }, + "Runtime": "nodejs16.x", + "Description": "Lambda function for removing all inbound/outbound rules from the VPC default security group" + }, + "DependsOn": [ + "CustomVpcRestrictDefaultSGCustomResourceProviderRole26592FE0" + ] + }, "integauroraserverlessv20IntegClusterSubnets2462DA9D": { "Type": "AWS::RDS::DBSubnetGroup", "Properties": { diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integ.json index cd2240681ff26..fcf69e229cfef 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "31.0.0", + "version": "32.0.0", "testCases": { "integ-test/DefaultTest": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integtestDefaultTestDeployAssert24D5C536.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integtestDefaultTestDeployAssert24D5C536.assets.json index ecd9f6bd2a455..4b008a0cae838 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integtestDefaultTestDeployAssert24D5C536.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/integtestDefaultTestDeployAssert24D5C536.assets.json @@ -1,5 +1,5 @@ { - "version": "31.0.0", + "version": "32.0.0", "files": { "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { "source": { diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/manifest.json index efb5c19624fc1..3f10d394ec9e0 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "31.0.0", + "version": "32.0.0", "artifacts": { "integ-aurora-serverlessv2-cluster.assets": { "type": "cdk:asset-manifest", @@ -17,7 +17,7 @@ "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/5ec15cecd9b8441a50d23535be26d2c68417eac2f5ddaf3d86e820b5d95a5ea9.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/bffc468fc464208b727e3300214b3102d30e6f4d749531331ef45d2da89cae51.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -171,6 +171,24 @@ "data": "IntegVPCVPCGW4DD476C7" } ], + "/integ-aurora-serverlessv2-cluster/Integ-VPC/RestrictDefaultSecurityGroupCustomResource/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "IntegVPCRestrictDefaultSecurityGroupCustomResource42DF8AB1" + } + ], + "/integ-aurora-serverlessv2-cluster/Custom::VpcRestrictDefaultSGCustomResourceProvider/Role": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomVpcRestrictDefaultSGCustomResourceProviderRole26592FE0" + } + ], + "/integ-aurora-serverlessv2-cluster/Custom::VpcRestrictDefaultSGCustomResourceProvider/Handler": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomVpcRestrictDefaultSGCustomResourceProviderHandlerDC833E5E" + } + ], "/integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-0/Integ-Cluster/Subnets/Default": [ { "type": "aws:cdk:logicalId", diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/tree.json index e46e5ea3ced0e..2cb417f6456a3 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.cluster-serverless-v2.js.snapshot/tree.json @@ -31,8 +31,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_ec2.CfnVPC", + "version": "0.0.0" } }, "PublicSubnet1": { @@ -75,16 +75,16 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", + "version": "0.0.0" } }, "Acl": { "id": "Acl", "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet1/Acl", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" } }, "RouteTable": { @@ -105,8 +105,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", + "version": "0.0.0" } }, "RouteTableAssociation": { @@ -124,8 +124,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", + "version": "0.0.0" } }, "DefaultRoute": { @@ -144,8 +144,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", + "version": "0.0.0" } }, "EIP": { @@ -164,8 +164,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_ec2.CfnEIP", + "version": "0.0.0" } }, "NATGateway": { @@ -192,14 +192,14 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_ec2.CfnNatGateway", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_ec2.PublicSubnet", + "version": "0.0.0" } }, "PublicSubnet2": { @@ -242,16 +242,16 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", + "version": "0.0.0" } }, "Acl": { "id": "Acl", "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/PublicSubnet2/Acl", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" } }, "RouteTable": { @@ -272,8 +272,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", + "version": "0.0.0" } }, "RouteTableAssociation": { @@ -291,8 +291,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", + "version": "0.0.0" } }, "DefaultRoute": { @@ -311,8 +311,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", + "version": "0.0.0" } }, "EIP": { @@ -331,8 +331,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_ec2.CfnEIP", + "version": "0.0.0" } }, "NATGateway": { @@ -359,14 +359,14 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_ec2.CfnNatGateway", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_ec2.PublicSubnet", + "version": "0.0.0" } }, "PrivateSubnet1": { @@ -409,16 +409,16 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", + "version": "0.0.0" } }, "Acl": { "id": "Acl", "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/PrivateSubnet1/Acl", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" } }, "RouteTable": { @@ -439,8 +439,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", + "version": "0.0.0" } }, "RouteTableAssociation": { @@ -458,8 +458,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", + "version": "0.0.0" } }, "DefaultRoute": { @@ -478,14 +478,14 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_ec2.PrivateSubnet", + "version": "0.0.0" } }, "PrivateSubnet2": { @@ -528,16 +528,16 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", + "version": "0.0.0" } }, "Acl": { "id": "Acl", "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/PrivateSubnet2/Acl", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" } }, "RouteTable": { @@ -558,8 +558,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", + "version": "0.0.0" } }, "RouteTableAssociation": { @@ -577,8 +577,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", + "version": "0.0.0" } }, "DefaultRoute": { @@ -597,14 +597,14 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_ec2.PrivateSubnet", + "version": "0.0.0" } }, "IGW": { @@ -622,8 +622,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_ec2.CfnInternetGateway", + "version": "0.0.0" } }, "VPCGW": { @@ -641,14 +641,66 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_ec2.CfnVPCGatewayAttachment", + "version": "0.0.0" + } + }, + "RestrictDefaultSecurityGroupCustomResource": { + "id": "RestrictDefaultSecurityGroupCustomResource", + "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/RestrictDefaultSecurityGroupCustomResource", + "children": { + "Default": { + "id": "Default", + "path": "integ-aurora-serverlessv2-cluster/Integ-VPC/RestrictDefaultSecurityGroupCustomResource/Default", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.CustomResource", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_ec2.Vpc", + "version": "0.0.0" + } + }, + "Custom::VpcRestrictDefaultSGCustomResourceProvider": { + "id": "Custom::VpcRestrictDefaultSGCustomResourceProvider", + "path": "integ-aurora-serverlessv2-cluster/Custom::VpcRestrictDefaultSGCustomResourceProvider", + "children": { + "Staging": { + "id": "Staging", + "path": "integ-aurora-serverlessv2-cluster/Custom::VpcRestrictDefaultSGCustomResourceProvider/Staging", + "constructInfo": { + "fqn": "aws-cdk-lib.AssetStaging", + "version": "0.0.0" + } + }, + "Role": { + "id": "Role", + "path": "integ-aurora-serverlessv2-cluster/Custom::VpcRestrictDefaultSGCustomResourceProvider/Role", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "0.0.0" + } + }, + "Handler": { + "id": "Handler", + "path": "integ-aurora-serverlessv2-cluster/Custom::VpcRestrictDefaultSGCustomResourceProvider/Handler", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.CustomResourceProvider", + "version": "0.0.0" } }, "integ-aurora-serverlessv2-0": { @@ -681,14 +733,14 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_rds.CfnDBSubnetGroup", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_rds.SubnetGroup", + "version": "0.0.0" } }, "SecurityGroup": { @@ -715,22 +767,22 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_ec2.CfnSecurityGroup", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_ec2.SecurityGroup", + "version": "0.0.0" } }, "AuroraMySqlDatabaseClusterEngineDefaultParameterGroup": { "id": "AuroraMySqlDatabaseClusterEngineDefaultParameterGroup", "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-0/Integ-Cluster/AuroraMySqlDatabaseClusterEngineDefaultParameterGroup", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" } }, "Secret": { @@ -763,8 +815,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_secretsmanager.CfnSecret", + "version": "0.0.0" } }, "Attachment": { @@ -787,20 +839,20 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_secretsmanager.CfnSecretTargetAttachment", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_secretsmanager.SecretTargetAttachment", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_rds.DatabaseSecret", + "version": "0.0.0" } }, "Resource": { @@ -855,8 +907,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_rds.CfnDBCluster", + "version": "0.0.0" } }, "writer": { @@ -878,20 +930,20 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_rds.CfnDBInstance", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_rds.DatabaseCluster", + "version": "0.0.0" } }, "capacity": { @@ -922,14 +974,14 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_cloudwatch.CfnAlarm", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_cloudwatch.Alarm", + "version": "0.0.0" } }, "alarm": { @@ -960,20 +1012,20 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_cloudwatch.CfnAlarm", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_cloudwatch.Alarm", + "version": "0.0.0" } } }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.270" + "version": "10.2.26" } }, "integ-aurora-serverlessv2-1": { @@ -1006,14 +1058,14 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_rds.CfnDBSubnetGroup", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_rds.SubnetGroup", + "version": "0.0.0" } }, "SecurityGroup": { @@ -1040,22 +1092,22 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_ec2.CfnSecurityGroup", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_ec2.SecurityGroup", + "version": "0.0.0" } }, "AuroraMySqlDatabaseClusterEngineDefaultParameterGroup": { "id": "AuroraMySqlDatabaseClusterEngineDefaultParameterGroup", "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-1/Integ-Cluster/AuroraMySqlDatabaseClusterEngineDefaultParameterGroup", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" } }, "Secret": { @@ -1088,8 +1140,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_secretsmanager.CfnSecret", + "version": "0.0.0" } }, "Attachment": { @@ -1112,20 +1164,20 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_secretsmanager.CfnSecretTargetAttachment", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_secretsmanager.SecretTargetAttachment", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_rds.DatabaseSecret", + "version": "0.0.0" } }, "Resource": { @@ -1180,8 +1232,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_rds.CfnDBCluster", + "version": "0.0.0" } }, "writer": { @@ -1203,14 +1255,14 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_rds.CfnDBInstance", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" } }, "FailoverReader": { @@ -1232,14 +1284,14 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_rds.CfnDBInstance", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" } }, "OtherReader": { @@ -1261,20 +1313,20 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_rds.CfnDBInstance", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_rds.DatabaseCluster", + "version": "0.0.0" } }, "capacity": { @@ -1305,14 +1357,14 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_cloudwatch.CfnAlarm", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_cloudwatch.Alarm", + "version": "0.0.0" } }, "alarm": { @@ -1343,20 +1395,20 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_cloudwatch.CfnAlarm", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_cloudwatch.Alarm", + "version": "0.0.0" } } }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.270" + "version": "10.2.26" } }, "integ-aurora-serverlessv2-2": { @@ -1389,14 +1441,14 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_rds.CfnDBSubnetGroup", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_rds.SubnetGroup", + "version": "0.0.0" } }, "SecurityGroup": { @@ -1423,22 +1475,22 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_ec2.CfnSecurityGroup", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_ec2.SecurityGroup", + "version": "0.0.0" } }, "AuroraMySqlDatabaseClusterEngineDefaultParameterGroup": { "id": "AuroraMySqlDatabaseClusterEngineDefaultParameterGroup", "path": "integ-aurora-serverlessv2-cluster/integ-aurora-serverlessv2-2/Integ-Cluster/AuroraMySqlDatabaseClusterEngineDefaultParameterGroup", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" } }, "Secret": { @@ -1471,8 +1523,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_secretsmanager.CfnSecret", + "version": "0.0.0" } }, "Attachment": { @@ -1495,20 +1547,20 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_secretsmanager.CfnSecretTargetAttachment", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_secretsmanager.SecretTargetAttachment", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_rds.DatabaseSecret", + "version": "0.0.0" } }, "Resource": { @@ -1563,8 +1615,8 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_rds.CfnDBCluster", + "version": "0.0.0" } }, "writer": { @@ -1586,14 +1638,14 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_rds.CfnDBInstance", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" } }, "FailoverReader": { @@ -1615,14 +1667,14 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_rds.CfnDBInstance", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" } }, "OtherReader": { @@ -1644,20 +1696,20 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_rds.CfnDBInstance", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_rds.DatabaseCluster", + "version": "0.0.0" } }, "capacity": { @@ -1688,14 +1740,14 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_cloudwatch.CfnAlarm", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_cloudwatch.Alarm", + "version": "0.0.0" } }, "alarm": { @@ -1726,42 +1778,42 @@ } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_cloudwatch.CfnAlarm", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.aws_cloudwatch.Alarm", + "version": "0.0.0" } } }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.270" + "version": "10.2.26" } }, "BootstrapVersion": { "id": "BootstrapVersion", "path": "integ-aurora-serverlessv2-cluster/BootstrapVersion", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" } }, "CheckBootstrapVersion": { "id": "CheckBootstrapVersion", "path": "integ-aurora-serverlessv2-cluster/CheckBootstrapVersion", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" } }, "integ-test": { @@ -1777,7 +1829,7 @@ "path": "integ-test/DefaultTest/Default", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.270" + "version": "10.2.26" } }, "DeployAssert": { @@ -1788,22 +1840,22 @@ "id": "BootstrapVersion", "path": "integ-test/DefaultTest/DeployAssert/BootstrapVersion", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" } }, "CheckBootstrapVersion": { "id": "CheckBootstrapVersion", "path": "integ-test/DefaultTest/DeployAssert/CheckBootstrapVersion", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" } } }, @@ -1823,13 +1875,13 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.270" + "version": "10.2.26" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.270" + "fqn": "aws-cdk-lib.App", + "version": "0.0.0" } } } \ No newline at end of file From 056d2a398fd4ac3ad1f9732fe4f4b5d1ff7e3dbb Mon Sep 17 00:00:00 2001 From: corymhall <43035978+corymhall@users.noreply.github.com> Date: Wed, 31 May 2023 10:22:39 +0000 Subject: [PATCH 10/10] fixing review comments --- packages/aws-cdk-lib/aws-rds/lib/cluster.ts | 7 ++++--- packages/aws-cdk-lib/aws-rds/test/cluster.test.ts | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/aws-cdk-lib/aws-rds/lib/cluster.ts b/packages/aws-cdk-lib/aws-rds/lib/cluster.ts index 3c25b454ef1e2..1f7acddde80ae 100644 --- a/packages/aws-cdk-lib/aws-rds/lib/cluster.ts +++ b/packages/aws-cdk-lib/aws-rds/lib/cluster.ts @@ -749,9 +749,6 @@ abstract class DatabaseClusterNew extends DatabaseClusterBase { ); } } - } else { - // TODO: add some info around serverless instance tiers and matching scaling - Annotations.of(this).addInfo('...'); } } @@ -783,6 +780,10 @@ abstract class DatabaseClusterNew extends DatabaseClusterBase { throw new Error('serverlessV2MinCapacity must be >= 0.5 & <= 128'); } + if (this.serverlessV2MaxCapacity < this.serverlessV2MinCapacity) { + throw new Error('serverlessV2MaxCapacity must be greater than serverlessV2MinCapacity'); + } + if (this.serverlessV2MaxCapacity === 0.5 && this.serverlessV2MinCapacity === 0.5) { throw new Error('If serverlessV2MinCapacity === 0.5 then serverlessV2MaxCapacity must be >=1'); } diff --git a/packages/aws-cdk-lib/aws-rds/test/cluster.test.ts b/packages/aws-cdk-lib/aws-rds/test/cluster.test.ts index d602d5972a102..298dfec3352e0 100644 --- a/packages/aws-cdk-lib/aws-rds/test/cluster.test.ts +++ b/packages/aws-cdk-lib/aws-rds/test/cluster.test.ts @@ -114,6 +114,7 @@ describe('cluster new api', () => { [0.5, 0.5, /If serverlessV2MinCapacity === 0.5 then serverlessV2MaxCapacity must be >=1/], [10.1, 12, /serverlessV2MinCapacity & serverlessV2MaxCapacity must be in 0.5 step increments/], [12, 12.1, /serverlessV2MinCapacity & serverlessV2MaxCapacity must be in 0.5 step increments/], + [5, 1, /serverlessV2MaxCapacity must be greater than serverlessV2MinCapacity/], ])('when serverless capacity is incorrect', (minCapacity, maxCapacity, errorMessage) => { // GIVEN const stack = testStack();