From b5e9c1a99be6898c544f91781ceb4ee1d371a03e Mon Sep 17 00:00:00 2001
From: Joshua Weber <57131123+daschaa@users.noreply.github.com>
Date: Tue, 12 Jul 2022 15:27:51 +0200
Subject: [PATCH] feat(redshift): adds classic or elastic resize type option
 (#21084)

Fixes #19430.

Adds the property `classicResizing` property to the `ClusterProps`. If not set or set to false, elastic resizing is used.

I feel like an entry in the README is not necessary. If it is ok, please add `pr-linter/exempt-readme` label to this PR.

----

### All Submissions:

* [x] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md)

### Adding new Unconventional Dependencies:

* [ ] This PR adds new unconventional dependencies following the process described [here](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md/#adding-new-unconventional-dependencies)

### New Features

* [ ] Have you added the new feature to an [integration test](https://github.com/aws/aws-cdk/blob/main/INTEGRATION_TESTS.md)?
	* [ ] Did you use `yarn integ` to deploy the infrastructure and generate the snapshot (i.e. `yarn integ` without `--dry-run`)?

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
---
 packages/@aws-cdk/aws-redshift/lib/cluster.ts | 14 ++++
 .../aws-redshift/test/cluster.test.ts         | 67 +++++++++++++++++++
 2 files changed, 81 insertions(+)

diff --git a/packages/@aws-cdk/aws-redshift/lib/cluster.ts b/packages/@aws-cdk/aws-redshift/lib/cluster.ts
index ab86540d3d7b3..3a61f3ad93afe 100644
--- a/packages/@aws-cdk/aws-redshift/lib/cluster.ts
+++ b/packages/@aws-cdk/aws-redshift/lib/cluster.ts
@@ -322,6 +322,19 @@ export interface ClusterProps {
    * @default false
    */
   readonly publiclyAccessible?: boolean
+
+  /**
+   * If this flag is set, the cluster resizing type will be set to classic.
+   * When resizing a cluster, classic resizing will always provision a new cluster and transfer the data there.
+   *
+   * Classic resize takes more time to complete, but it can be useful in cases where the change in node count or
+   * the node type to migrate to doesn't fall within the bounds for elastic resize.
+   *
+   * @see https://docs.aws.amazon.com/redshift/latest/mgmt/managing-cluster-operations.html#elastic-resize
+   *
+   * @default - Elastic resize type
+   */
+  readonly classicResizing?: boolean
 }
 
 /**
@@ -485,6 +498,7 @@ export class Cluster extends ClusterBase {
       // Encryption
       kmsKeyId: props.encryptionKey?.keyId,
       encrypted: props.encrypted ?? true,
+      classic: props.classicResizing,
     });
 
     cluster.applyRemovalPolicy(removalPolicy, {
diff --git a/packages/@aws-cdk/aws-redshift/test/cluster.test.ts b/packages/@aws-cdk/aws-redshift/test/cluster.test.ts
index 6db5f18ade684..80a03cb7ac207 100644
--- a/packages/@aws-cdk/aws-redshift/test/cluster.test.ts
+++ b/packages/@aws-cdk/aws-redshift/test/cluster.test.ts
@@ -422,6 +422,73 @@ test('default child returns a CfnCluster', () => {
   expect(cluster.node.defaultChild).toBeInstanceOf(CfnCluster);
 });
 
+test.each([
+  ['elastic', false],
+  ['classic', true],
+])('resize type (%s)', (_, classicResizing) => {
+  // WHEN
+  new Cluster(stack, 'Redshift', {
+    masterUser: {
+      masterUsername: 'admin',
+      masterPassword: cdk.SecretValue.unsafePlainText('tooshort'),
+    },
+    classicResizing,
+    vpc,
+  });
+
+  // THEN
+  Template.fromStack(stack).hasResource('AWS::Redshift::Cluster', {
+    Properties: {
+      AllowVersionUpgrade: true,
+      MasterUsername: 'admin',
+      MasterUserPassword: 'tooshort',
+      ClusterType: 'multi-node',
+      AutomatedSnapshotRetentionPeriod: 1,
+      Encrypted: true,
+      NumberOfNodes: 2,
+      NodeType: 'dc2.large',
+      DBName: 'default_db',
+      PubliclyAccessible: false,
+      ClusterSubnetGroupName: { Ref: 'RedshiftSubnetsDFE70E0A' },
+      VpcSecurityGroupIds: [{ 'Fn::GetAtt': ['RedshiftSecurityGroup796D74A7', 'GroupId'] }],
+      Classic: classicResizing,
+    },
+    DeletionPolicy: 'Retain',
+    UpdateReplacePolicy: 'Retain',
+  });
+});
+
+test('resize type not set', () => {
+  // WHEN
+  new Cluster(stack, 'Redshift', {
+    masterUser: {
+      masterUsername: 'admin',
+      masterPassword: cdk.SecretValue.unsafePlainText('tooshort'),
+    },
+    vpc,
+  });
+
+  // THEN
+  Template.fromStack(stack).hasResource('AWS::Redshift::Cluster', {
+    Properties: {
+      AllowVersionUpgrade: true,
+      MasterUsername: 'admin',
+      MasterUserPassword: 'tooshort',
+      ClusterType: 'multi-node',
+      AutomatedSnapshotRetentionPeriod: 1,
+      Encrypted: true,
+      NumberOfNodes: 2,
+      NodeType: 'dc2.large',
+      DBName: 'default_db',
+      PubliclyAccessible: false,
+      ClusterSubnetGroupName: { Ref: 'RedshiftSubnetsDFE70E0A' },
+      VpcSecurityGroupIds: [{ 'Fn::GetAtt': ['RedshiftSecurityGroup796D74A7', 'GroupId'] }],
+    },
+    DeletionPolicy: 'Retain',
+    UpdateReplacePolicy: 'Retain',
+  });
+});
+
 function testStack() {
   const newTestStack = new cdk.Stack(undefined, undefined, { env: { account: '12345', region: 'us-test-1' } });
   newTestStack.node.setContext('availability-zones:12345:us-test-1', ['us-test-1a', 'us-test-1b']);