From 35629f659d0c76ce41f5d16f35e92d7dd21a27dc Mon Sep 17 00:00:00 2001 From: maz Date: Wed, 11 Sep 2024 09:54:23 +0900 Subject: [PATCH 01/29] feat: add Redshift Serverless Namespace and Workgroup construct --- API.md | 1462 ++++++++++++++++- src/aws-redshiftserverless/README.md | 5 + src/aws-redshiftserverless/index.ts | 2 + src/aws-redshiftserverless/namespace.ts | 203 +++ src/aws-redshiftserverless/workgroup.ts | 260 +++ src/index.ts | 1 + .../integ.redshift-serverless.ts | 61 + ...efaultTestDeployAssertC5CDACEC.assets.json | 19 + ...aultTestDeployAssertC5CDACEC.template.json | 36 + .../RedshiftServerlessStack.assets.json | 34 + .../RedshiftServerlessStack.template.json | 796 +++++++++ .../cdk.out | 1 + .../integ.json | 14 + .../manifest.json | 359 ++++ .../tree.json | 1272 ++++++++++++++ test/aws-redshiftserverless/namespace.test.ts | 23 + test/aws-redshiftserverless/workgroup.test.ts | 39 + 17 files changed, 4503 insertions(+), 84 deletions(-) create mode 100644 src/aws-redshiftserverless/README.md create mode 100644 src/aws-redshiftserverless/index.ts create mode 100644 src/aws-redshiftserverless/namespace.ts create mode 100644 src/aws-redshiftserverless/workgroup.ts create mode 100644 test/aws-redshiftserverless/integ.redshift-serverless.ts create mode 100644 test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessDefaultTestDeployAssertC5CDACEC.assets.json create mode 100644 test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessDefaultTestDeployAssertC5CDACEC.template.json create mode 100644 test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.assets.json create mode 100644 test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.template.json create mode 100644 test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/cdk.out create mode 100644 test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/integ.json create mode 100644 test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/manifest.json create mode 100644 test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/tree.json create mode 100644 test/aws-redshiftserverless/namespace.test.ts create mode 100644 test/aws-redshiftserverless/workgroup.test.ts diff --git a/API.md b/API.md index 84af487..a1407f3 100644 --- a/API.md +++ b/API.md @@ -424,204 +424,1247 @@ The ID of the EC2 Instance Connect Endpoint. --- +### Namespace + +- *Implements:* @open-constructs/aws-cdk.aws_redshiftserverless.INamespace + +Represents a Redshift Serverless Namespace construct in AWS CDK. + +*Example* + +```typescript +const nameSpace = new Namespace( + stack, + 'Namespace', + { + namespaceName: 'my-namespace', + }, +); +``` + + +#### Initializers + +```typescript +import { aws_redshiftserverless } from '@open-constructs/aws-cdk' + +new aws_redshiftserverless.Namespace(scope: Construct, id: string, props: NamespaceProps) +``` + +| **Name** | **Type** | **Description** | +| --- | --- | --- | +| scope | constructs.Construct | *No description.* | +| id | string | *No description.* | +| props | @open-constructs/aws-cdk.aws_redshiftserverless.NamespaceProps | *No description.* | + +--- + +##### `scope`Required + +- *Type:* constructs.Construct + +--- + +##### `id`Required + +- *Type:* string + +--- + +##### `props`Required + +- *Type:* @open-constructs/aws-cdk.aws_redshiftserverless.NamespaceProps + +--- + +#### Methods + +| **Name** | **Description** | +| --- | --- | +| toString | Returns a string representation of this construct. | +| applyRemovalPolicy | Apply the given removal policy to this resource. | + +--- + +##### `toString` + +```typescript +public toString(): string +``` + +Returns a string representation of this construct. + +##### `applyRemovalPolicy` + +```typescript +public applyRemovalPolicy(policy: RemovalPolicy): void +``` + +Apply the given removal policy to this resource. + +The Removal Policy controls what happens to this resource when it stops +being managed by CloudFormation, either because you've removed it from the +CDK application or because you've made a change that requires the resource +to be replaced. + +The resource can be deleted (`RemovalPolicy.DESTROY`), or left in your AWS +account for data recovery and cleanup later (`RemovalPolicy.RETAIN`). + +###### `policy`Required + +- *Type:* aws-cdk-lib.RemovalPolicy + +--- + +#### Static Functions + +| **Name** | **Description** | +| --- | --- | +| isConstruct | Checks if `x` is a construct. | +| isOwnedResource | Returns true if the construct was created by CDK, and false otherwise. | +| isResource | Check whether the given construct is a Resource. | +| fromNamespaceAttributes | Import an existing namspace to the stack from its attributes. | + +--- + +##### `isConstruct` + +```typescript +import { aws_redshiftserverless } from '@open-constructs/aws-cdk' + +aws_redshiftserverless.Namespace.isConstruct(x: any) +``` + +Checks if `x` is a construct. + +Use this method instead of `instanceof` to properly detect `Construct` +instances, even when the construct library is symlinked. + +Explanation: in JavaScript, multiple copies of the `constructs` library on +disk are seen as independent, completely different libraries. As a +consequence, the class `Construct` in each copy of the `constructs` library +is seen as a different class, and an instance of one class will not test as +`instanceof` the other class. `npm install` will not create installations +like this, but users may manually symlink construct libraries together or +use a monorepo tool: in those cases, multiple copies of the `constructs` +library can be accidentally installed, and `instanceof` will behave +unpredictably. It is safest to avoid using `instanceof`, and using +this type-testing method instead. + +###### `x`Required + +- *Type:* any + +Any object. + +--- + +##### `isOwnedResource` + +```typescript +import { aws_redshiftserverless } from '@open-constructs/aws-cdk' + +aws_redshiftserverless.Namespace.isOwnedResource(construct: IConstruct) +``` + +Returns true if the construct was created by CDK, and false otherwise. + +###### `construct`Required + +- *Type:* constructs.IConstruct + +--- + +##### `isResource` + +```typescript +import { aws_redshiftserverless } from '@open-constructs/aws-cdk' + +aws_redshiftserverless.Namespace.isResource(construct: IConstruct) +``` + +Check whether the given construct is a Resource. + +###### `construct`Required + +- *Type:* constructs.IConstruct + +--- + +##### `fromNamespaceAttributes` + +```typescript +import { aws_redshiftserverless } from '@open-constructs/aws-cdk' + +aws_redshiftserverless.Namespace.fromNamespaceAttributes(scope: Construct, id: string, attrs: NamespaceAttributes) +``` + +Import an existing namspace to the stack from its attributes. + +###### `scope`Required + +- *Type:* constructs.Construct + +--- + +###### `id`Required + +- *Type:* string + +--- + +###### `attrs`Required + +- *Type:* @open-constructs/aws-cdk.aws_redshiftserverless.NamespaceAttributes + +--- + +#### Properties + +| **Name** | **Type** | **Description** | +| --- | --- | --- | +| node | constructs.Node | The tree node. | +| env | aws-cdk-lib.ResourceEnvironment | The environment this resource belongs to. | +| stack | aws-cdk-lib.Stack | The stack in which this resource is defined. | +| namespaceArn | string | The namespace Arn. | +| namespaceName | string | The namespace name. | + +--- + +##### `node`Required + +```typescript +public readonly node: Node; +``` + +- *Type:* constructs.Node + +The tree node. + +--- + +##### `env`Required + +```typescript +public readonly env: ResourceEnvironment; +``` + +- *Type:* aws-cdk-lib.ResourceEnvironment + +The environment this resource belongs to. + +For resources that are created and managed by the CDK +(generally, those created by creating new class instances like Role, Bucket, etc.), +this is always the same as the environment of the stack they belong to; +however, for imported resources +(those obtained from static methods like fromRoleArn, fromBucketName, etc.), +that might be different than the stack they were imported into. + +--- + +##### `stack`Required + +```typescript +public readonly stack: Stack; +``` + +- *Type:* aws-cdk-lib.Stack + +The stack in which this resource is defined. + +--- + +##### `namespaceArn`Required + +```typescript +public readonly namespaceArn: string; +``` + +- *Type:* string + +The namespace Arn. + +--- + +##### `namespaceName`Required + +```typescript +public readonly namespaceName: string; +``` + +- *Type:* string + +The namespace name. + +--- + + +### Workgroup + +- *Implements:* @open-constructs/aws-cdk.aws_redshiftserverless.IWorkgroup + +Represents a Redshift Serverless Workgroup construct in AWS CDK. + +*Example* + +```typescript +declare const namespace: Namespace; +declare const vpc: aws_ec2.IVpc; + +const nameSpace = new Workgroup( + stack, + 'Workgroup', + { + workgroupName: 'my-workgroup', + namespace: namespace, + vpc, + }, +); +``` + + +#### Initializers + +```typescript +import { aws_redshiftserverless } from '@open-constructs/aws-cdk' + +new aws_redshiftserverless.Workgroup(scope: Construct, id: string, props: WorkgroupProps) +``` + +| **Name** | **Type** | **Description** | +| --- | --- | --- | +| scope | constructs.Construct | *No description.* | +| id | string | *No description.* | +| props | @open-constructs/aws-cdk.aws_redshiftserverless.WorkgroupProps | *No description.* | + +--- + +##### `scope`Required + +- *Type:* constructs.Construct + +--- + +##### `id`Required + +- *Type:* string + +--- + +##### `props`Required + +- *Type:* @open-constructs/aws-cdk.aws_redshiftserverless.WorkgroupProps + +--- + +#### Methods + +| **Name** | **Description** | +| --- | --- | +| toString | Returns a string representation of this construct. | +| applyRemovalPolicy | Apply the given removal policy to this resource. | + +--- + +##### `toString` + +```typescript +public toString(): string +``` + +Returns a string representation of this construct. + +##### `applyRemovalPolicy` + +```typescript +public applyRemovalPolicy(policy: RemovalPolicy): void +``` + +Apply the given removal policy to this resource. + +The Removal Policy controls what happens to this resource when it stops +being managed by CloudFormation, either because you've removed it from the +CDK application or because you've made a change that requires the resource +to be replaced. + +The resource can be deleted (`RemovalPolicy.DESTROY`), or left in your AWS +account for data recovery and cleanup later (`RemovalPolicy.RETAIN`). + +###### `policy`Required + +- *Type:* aws-cdk-lib.RemovalPolicy + +--- + +#### Static Functions + +| **Name** | **Description** | +| --- | --- | +| isConstruct | Checks if `x` is a construct. | +| isOwnedResource | Returns true if the construct was created by CDK, and false otherwise. | +| isResource | Check whether the given construct is a Resource. | +| fromWorkgroupAttributes | Import an existing workgroup to the stack from its attributes. | + +--- + +##### `isConstruct` + +```typescript +import { aws_redshiftserverless } from '@open-constructs/aws-cdk' + +aws_redshiftserverless.Workgroup.isConstruct(x: any) +``` + +Checks if `x` is a construct. + +Use this method instead of `instanceof` to properly detect `Construct` +instances, even when the construct library is symlinked. + +Explanation: in JavaScript, multiple copies of the `constructs` library on +disk are seen as independent, completely different libraries. As a +consequence, the class `Construct` in each copy of the `constructs` library +is seen as a different class, and an instance of one class will not test as +`instanceof` the other class. `npm install` will not create installations +like this, but users may manually symlink construct libraries together or +use a monorepo tool: in those cases, multiple copies of the `constructs` +library can be accidentally installed, and `instanceof` will behave +unpredictably. It is safest to avoid using `instanceof`, and using +this type-testing method instead. + +###### `x`Required + +- *Type:* any + +Any object. + +--- + +##### `isOwnedResource` + +```typescript +import { aws_redshiftserverless } from '@open-constructs/aws-cdk' + +aws_redshiftserverless.Workgroup.isOwnedResource(construct: IConstruct) +``` + +Returns true if the construct was created by CDK, and false otherwise. + +###### `construct`Required + +- *Type:* constructs.IConstruct + +--- + +##### `isResource` + +```typescript +import { aws_redshiftserverless } from '@open-constructs/aws-cdk' + +aws_redshiftserverless.Workgroup.isResource(construct: IConstruct) +``` + +Check whether the given construct is a Resource. + +###### `construct`Required + +- *Type:* constructs.IConstruct + +--- + +##### `fromWorkgroupAttributes` + +```typescript +import { aws_redshiftserverless } from '@open-constructs/aws-cdk' + +aws_redshiftserverless.Workgroup.fromWorkgroupAttributes(scope: Construct, id: string, attrs: WorkgroupAttributes) +``` + +Import an existing workgroup to the stack from its attributes. + +###### `scope`Required + +- *Type:* constructs.Construct + +--- + +###### `id`Required + +- *Type:* string + +--- + +###### `attrs`Required + +- *Type:* @open-constructs/aws-cdk.aws_redshiftserverless.WorkgroupAttributes + +--- + +#### Properties + +| **Name** | **Type** | **Description** | +| --- | --- | --- | +| node | constructs.Node | The tree node. | +| env | aws-cdk-lib.ResourceEnvironment | The environment this resource belongs to. | +| stack | aws-cdk-lib.Stack | The stack in which this resource is defined. | +| connections | aws-cdk-lib.aws_ec2.Connections | The connection object associated with the EC2 Instance Connect Endpoint. | +| endpointAddress | string | The workgroup endpoint address. | +| port | number | The workgroup port. | +| workgroupArn | string | The workgroup Arn. | +| workgroupName | string | The workgroup name. | + +--- + +##### `node`Required + +```typescript +public readonly node: Node; +``` + +- *Type:* constructs.Node + +The tree node. + +--- + +##### `env`Required + +```typescript +public readonly env: ResourceEnvironment; +``` + +- *Type:* aws-cdk-lib.ResourceEnvironment + +The environment this resource belongs to. + +For resources that are created and managed by the CDK +(generally, those created by creating new class instances like Role, Bucket, etc.), +this is always the same as the environment of the stack they belong to; +however, for imported resources +(those obtained from static methods like fromRoleArn, fromBucketName, etc.), +that might be different than the stack they were imported into. + +--- + +##### `stack`Required + +```typescript +public readonly stack: Stack; +``` + +- *Type:* aws-cdk-lib.Stack + +The stack in which this resource is defined. + +--- + +##### `connections`Required + +```typescript +public readonly connections: Connections; +``` + +- *Type:* aws-cdk-lib.aws_ec2.Connections + +The connection object associated with the EC2 Instance Connect Endpoint. + +--- + +##### `endpointAddress`Required + +```typescript +public readonly endpointAddress: string; +``` + +- *Type:* string + +The workgroup endpoint address. + +--- + +##### `port`Required + +```typescript +public readonly port: number; +``` + +- *Type:* number + +The workgroup port. + +--- + +##### `workgroupArn`Required + +```typescript +public readonly workgroupArn: string; +``` + +- *Type:* string + +The workgroup Arn. + +--- + +##### `workgroupName`Required + +```typescript +public readonly workgroupName: string; +``` + +- *Type:* string + +The workgroup name. + +--- + + ## Structs -### CostReportProps +### CostReportProps + +Properties for defining a Cost and Usage Report. + +#### Initializer + +```typescript +import { aws_cur } from '@open-constructs/aws-cdk' + +const costReportProps: aws_cur.CostReportProps = { ... } +``` + +#### Properties + +| **Name** | **Type** | **Description** | +| --- | --- | --- | +| bucket | aws-cdk-lib.aws_s3.IBucket | The bucket to place the cost report into. | +| costReportName | string | The name of the cost report. | +| format | @open-constructs/aws-cdk.aws_cur.CurFormat | The format to use for the cost and usage report. | +| reportGranularity | @open-constructs/aws-cdk.aws_cur.ReportGranularity | The granularity of the line items in the report. | + +--- + +##### `bucket`Optional + +```typescript +public readonly bucket: IBucket; +``` + +- *Type:* aws-cdk-lib.aws_s3.IBucket +- *Default:* a new bucket will be created. + +The bucket to place the cost report into. + +If non is provided, a new bucket will be created. + +--- + +##### `costReportName`Optional + +```typescript +public readonly costReportName: string; +``` + +- *Type:* string +- *Default:* 'default-cur' + +The name of the cost report. + +--- + +##### `format`Optional + +```typescript +public readonly format: CurFormat; +``` + +- *Type:* @open-constructs/aws-cdk.aws_cur.CurFormat +- *Default:* TEXT_OR_CSV + +The format to use for the cost and usage report. + +--- + +##### `reportGranularity`Optional + +```typescript +public readonly reportGranularity: ReportGranularity; +``` + +- *Type:* @open-constructs/aws-cdk.aws_cur.ReportGranularity +- *Default:* HOURLY + +The granularity of the line items in the report. + +--- + +### InstanceConnectEndpointAttributes + +Attributes for importing an EC2 Instance Connect Endpoint. + +#### Initializer + +```typescript +import { aws_ec2 } from '@open-constructs/aws-cdk' + +const instanceConnectEndpointAttributes: aws_ec2.InstanceConnectEndpointAttributes = { ... } +``` + +#### Properties + +| **Name** | **Type** | **Description** | +| --- | --- | --- | +| instanceConnectEndpointId | string | The ID of the EC2 Instance Connect Endpoint. | +| securityGroups | aws-cdk-lib.aws_ec2.ISecurityGroup[] | The security groups associated with the EC2 Instance Connect Endpoint. | + +--- + +##### `instanceConnectEndpointId`Required + +```typescript +public readonly instanceConnectEndpointId: string; +``` + +- *Type:* string + +The ID of the EC2 Instance Connect Endpoint. + +--- + +##### `securityGroups`Required + +```typescript +public readonly securityGroups: ISecurityGroup[]; +``` + +- *Type:* aws-cdk-lib.aws_ec2.ISecurityGroup[] + +The security groups associated with the EC2 Instance Connect Endpoint. + +--- + +### InstanceConnectEndpointProps + +Properties for defining an EC2 Instance Connect Endpoint. + +#### Initializer + +```typescript +import { aws_ec2 } from '@open-constructs/aws-cdk' + +const instanceConnectEndpointProps: aws_ec2.InstanceConnectEndpointProps = { ... } +``` + +#### Properties + +| **Name** | **Type** | **Description** | +| --- | --- | --- | +| vpc | aws-cdk-lib.aws_ec2.IVpc | The VPC in which the EC2 Instance Connect Endpoint is created. | +| clientToken | string | Unique, case-sensitive identifier that you provide to ensure the idempotency of the request. | +| preserveClientIp | boolean | Indicates whether your client's IP address is preserved as the source. | +| securityGroups | aws-cdk-lib.aws_ec2.ISecurityGroup[] | The security groups to associate with the EC2 Instance Connect Endpoint. | + +--- -Properties for defining a Cost and Usage Report. +##### `vpc`Required -#### Initializer +```typescript +public readonly vpc: IVpc; +``` + +- *Type:* aws-cdk-lib.aws_ec2.IVpc + +The VPC in which the EC2 Instance Connect Endpoint is created. + +--- + +##### `clientToken`Optional ```typescript -import { aws_cur } from '@open-constructs/aws-cdk' +public readonly clientToken: string; +``` -const costReportProps: aws_cur.CostReportProps = { ... } +- *Type:* string + +Unique, case-sensitive identifier that you provide to ensure the idempotency of the request. + +> [https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-instanceconnectendpoint.html#cfn-ec2-instanceconnectendpoint-clienttoken](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-instanceconnectendpoint.html#cfn-ec2-instanceconnectendpoint-clienttoken) + +--- + +##### `preserveClientIp`Optional + +```typescript +public readonly preserveClientIp: boolean; +``` + +- *Type:* boolean +- *Default:* true + +Indicates whether your client's IP address is preserved as the source. + +> [https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-instanceconnectendpoint.html#cfn-ec2-instanceconnectendpoint-preserveclientip](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-instanceconnectendpoint.html#cfn-ec2-instanceconnectendpoint-preserveclientip) + +--- + +##### `securityGroups`Optional + +```typescript +public readonly securityGroups: ISecurityGroup[]; +``` + +- *Type:* aws-cdk-lib.aws_ec2.ISecurityGroup[] +- *Default:* a new security group is created + +The security groups to associate with the EC2 Instance Connect Endpoint. + +--- + +### NamespaceAttributes + +Attributes for importing a Redshift Serverless Namespace. + +#### Initializer + +```typescript +import { aws_redshiftserverless } from '@open-constructs/aws-cdk' + +const namespaceAttributes: aws_redshiftserverless.NamespaceAttributes = { ... } ``` #### Properties | **Name** | **Type** | **Description** | | --- | --- | --- | -| bucket | aws-cdk-lib.aws_s3.IBucket | The bucket to place the cost report into. | -| costReportName | string | The name of the cost report. | -| format | @open-constructs/aws-cdk.aws_cur.CurFormat | The format to use for the cost and usage report. | -| reportGranularity | @open-constructs/aws-cdk.aws_cur.ReportGranularity | The granularity of the line items in the report. | +| namespaceArn | string | The namespace Arn. | +| namespaceName | string | The namespace name. | --- -##### `bucket`Optional +##### `namespaceArn`Required ```typescript -public readonly bucket: IBucket; +public readonly namespaceArn: string; ``` -- *Type:* aws-cdk-lib.aws_s3.IBucket -- *Default:* a new bucket will be created. +- *Type:* string -The bucket to place the cost report into. +The namespace Arn. -If non is provided, a new bucket will be created. +--- + +##### `namespaceName`Required + +```typescript +public readonly namespaceName: string; +``` + +- *Type:* string + +The namespace name. --- -##### `costReportName`Optional +### NamespaceProps + +Properties for defining a Redshift Serverless Namespace. + +#### Initializer ```typescript -public readonly costReportName: string; +import { aws_redshiftserverless } from '@open-constructs/aws-cdk' + +const namespaceProps: aws_redshiftserverless.NamespaceProps = { ... } +``` + +#### Properties + +| **Name** | **Type** | **Description** | +| --- | --- | --- | +| adminUsername | string | The username of the administrator for the primary database created in the namespace. | +| adminUserPassword | aws-cdk-lib.SecretValue | The password of the administrator for the primary database created in the namespace. | +| dbName | string | The name of the primary database created in the namespace. | +| defaultIamRole | aws-cdk-lib.aws_iam.IRole | The IAM role to set as a default in the namespace. | +| finalSnapshotName | string | The name of the snapshot to be created before the namespace is deleted. | +| finalSnapshotRetentionPeriod | number | How long to retain the final snapshot. | +| iamRoles | aws-cdk-lib.aws_iam.IRole[] | A list of IAM roles to associate with the namespace. | +| kmsKey | aws-cdk-lib.aws_kms.IKey | A Customer Managed Key used to encrypt your data. | +| logExports | @open-constructs/aws-cdk.aws_redshiftserverless.LogExport[] | The types of logs the namespace can export. | +| namespaceName | string | The name of the cost report. | + +--- + +##### `adminUsername`Optional + +```typescript +public readonly adminUsername: string; +``` + +- *Type:* string +- *Default:* no admin user + +The username of the administrator for the primary database created in the namespace. + +--- + +##### `adminUserPassword`Optional + +```typescript +public readonly adminUserPassword: SecretValue; +``` + +- *Type:* aws-cdk-lib.SecretValue +- *Default:* no admin user + +The password of the administrator for the primary database created in the namespace. + +--- + +##### `dbName`Optional + +```typescript +public readonly dbName: string; +``` + +- *Type:* string +- *Default:* dev + +The name of the primary database created in the namespace. + +--- + +##### `defaultIamRole`Optional + +```typescript +public readonly defaultIamRole: IRole; +``` + +- *Type:* aws-cdk-lib.aws_iam.IRole +- *Default:* no default IAM role + +The IAM role to set as a default in the namespace. + +--- + +##### `finalSnapshotName`Optional + +```typescript +public readonly finalSnapshotName: string; +``` + +- *Type:* string +- *Default:* no final snapshot + +The name of the snapshot to be created before the namespace is deleted. + +--- + +##### `finalSnapshotRetentionPeriod`Optional + +```typescript +public readonly finalSnapshotRetentionPeriod: number; +``` + +- *Type:* number +- *Default:* Retained indefinitely if finalSnapshotName is specified, otherwise no final snapshot + +How long to retain the final snapshot. + +--- + +##### `iamRoles`Optional + +```typescript +public readonly iamRoles: IRole[]; +``` + +- *Type:* aws-cdk-lib.aws_iam.IRole[] +- *Default:* no IAM role associated + +A list of IAM roles to associate with the namespace. + +--- + +##### `kmsKey`Optional + +```typescript +public readonly kmsKey: IKey; +``` + +- *Type:* aws-cdk-lib.aws_kms.IKey +- *Default:* use AWS managed key + +A Customer Managed Key used to encrypt your data. + +--- + +##### `logExports`Optional + +```typescript +public readonly logExports: LogExport[]; +``` + +- *Type:* @open-constructs/aws-cdk.aws_redshiftserverless.LogExport[] +- *Default:* no logs export + +The types of logs the namespace can export. + +--- + +##### `namespaceName`Optional + +```typescript +public readonly namespaceName: string; ``` - *Type:* string -- *Default:* 'default-cur' The name of the cost report. --- -##### `format`Optional +### WorkgroupAttributes + +Attributes for importing a Redshift Serverless Workgroup. + +#### Initializer ```typescript -public readonly format: CurFormat; +import { aws_redshiftserverless } from '@open-constructs/aws-cdk' + +const workgroupAttributes: aws_redshiftserverless.WorkgroupAttributes = { ... } ``` -- *Type:* @open-constructs/aws-cdk.aws_cur.CurFormat -- *Default:* TEXT_OR_CSV +#### Properties -The format to use for the cost and usage report. +| **Name** | **Type** | **Description** | +| --- | --- | --- | +| endpointAddress | string | The workgroup endpoint address. | +| port | number | The workgroup port. | +| securityGroups | aws-cdk-lib.aws_ec2.ISecurityGroup[] | The security groups associated with the Redshift Serverless Workgroup. | +| workgroupArn | string | The workgroup Arn. | +| workgroupName | string | The workgroup name. | --- -##### `reportGranularity`Optional +##### `endpointAddress`Required ```typescript -public readonly reportGranularity: ReportGranularity; +public readonly endpointAddress: string; ``` -- *Type:* @open-constructs/aws-cdk.aws_cur.ReportGranularity -- *Default:* HOURLY +- *Type:* string -The granularity of the line items in the report. +The workgroup endpoint address. + +--- + +##### `port`Required + +```typescript +public readonly port: number; +``` + +- *Type:* number + +The workgroup port. + +--- + +##### `securityGroups`Required + +```typescript +public readonly securityGroups: ISecurityGroup[]; +``` + +- *Type:* aws-cdk-lib.aws_ec2.ISecurityGroup[] + +The security groups associated with the Redshift Serverless Workgroup. + +--- + +##### `workgroupArn`Required + +```typescript +public readonly workgroupArn: string; +``` + +- *Type:* string + +The workgroup Arn. + +--- + +##### `workgroupName`Required + +```typescript +public readonly workgroupName: string; +``` + +- *Type:* string + +The workgroup name. + +--- + +### WorkgroupProps + +Properties for defining a Redshift Serverless Workgroup. + +#### Initializer + +```typescript +import { aws_redshiftserverless } from '@open-constructs/aws-cdk' + +const workgroupProps: aws_redshiftserverless.WorkgroupProps = { ... } +``` + +#### Properties + +| **Name** | **Type** | **Description** | +| --- | --- | --- | +| vpc | aws-cdk-lib.aws_ec2.IVpc | The VPC to place the workgroup in. | +| baseCapacity | number | The base compute capacity of the workgroup in Redshift Processing Units (RPUs). | +| configParameters | {[ key: string ]: string} | A list of parameters to set for finer control over a database. | +| enhancedVpcRouting | boolean | The value that specifies whether to enable enhanced virtual private cloud (VPC) routing, which forces Amazon Redshift Serverless to route traffic through your VPC. | +| namespace | @open-constructs/aws-cdk.aws_redshiftserverless.INamespace | The namespace the workgroup is associated with. | +| port | number | The custom port to use when connecting to a workgroup. | +| publiclyAccessible | boolean | A value that specifies whether the workgroup can be accessible from a public network. | +| securityGroups | aws-cdk-lib.aws_ec2.ISecurityGroup[] | The name of the primary database created in the workgroup. | +| vpcSubnets | aws-cdk-lib.aws_ec2.SubnetSelection | Where to place the workgroup within the VPC. | +| workgroupName | string | The name of the cost report. | + +--- + +##### `vpc`Required + +```typescript +public readonly vpc: IVpc; +``` + +- *Type:* aws-cdk-lib.aws_ec2.IVpc + +The VPC to place the workgroup in. --- -### InstanceConnectEndpointAttributes +##### `baseCapacity`Optional + +```typescript +public readonly baseCapacity: number; +``` + +- *Type:* number +- *Default:* 8 + +The base compute capacity of the workgroup in Redshift Processing Units (RPUs). -Attributes for importing an EC2 Instance Connect Endpoint. +--- -#### Initializer +##### `configParameters`Optional ```typescript -import { aws_ec2 } from '@open-constructs/aws-cdk' - -const instanceConnectEndpointAttributes: aws_ec2.InstanceConnectEndpointAttributes = { ... } +public readonly configParameters: {[ key: string ]: string}; ``` -#### Properties +- *Type:* {[ key: string ]: string} +- *Default:* no config parameters -| **Name** | **Type** | **Description** | -| --- | --- | --- | -| instanceConnectEndpointId | string | The ID of the EC2 Instance Connect Endpoint. | -| securityGroups | aws-cdk-lib.aws_ec2.ISecurityGroup[] | The security groups associated with the EC2 Instance Connect Endpoint. | +A list of parameters to set for finer control over a database. + +> [https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-redshiftserverless-workgroup.html#cfn-redshiftserverless-workgroup-configparameters](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-redshiftserverless-workgroup.html#cfn-redshiftserverless-workgroup-configparameters) --- -##### `instanceConnectEndpointId`Required +##### `enhancedVpcRouting`Optional ```typescript -public readonly instanceConnectEndpointId: string; +public readonly enhancedVpcRouting: boolean; ``` -- *Type:* string +- *Type:* boolean +- *Default:* false -The ID of the EC2 Instance Connect Endpoint. +The value that specifies whether to enable enhanced virtual private cloud (VPC) routing, which forces Amazon Redshift Serverless to route traffic through your VPC. --- -##### `securityGroups`Required +##### `namespace`Optional ```typescript -public readonly securityGroups: ISecurityGroup[]; +public readonly namespace: INamespace; ``` -- *Type:* aws-cdk-lib.aws_ec2.ISecurityGroup[] +- *Type:* @open-constructs/aws-cdk.aws_redshiftserverless.INamespace +- *Default:* the workgroup is not associated with any namespace -The security groups associated with the EC2 Instance Connect Endpoint. +The namespace the workgroup is associated with. --- -### InstanceConnectEndpointProps - -Properties for defining an EC2 Instance Connect Endpoint. - -#### Initializer +##### `port`Optional ```typescript -import { aws_ec2 } from '@open-constructs/aws-cdk' - -const instanceConnectEndpointProps: aws_ec2.InstanceConnectEndpointProps = { ... } +public readonly port: number; ``` -#### Properties +- *Type:* number +- *Default:* 5439 -| **Name** | **Type** | **Description** | -| --- | --- | --- | -| vpc | aws-cdk-lib.aws_ec2.IVpc | The VPC in which the EC2 Instance Connect Endpoint is created. | -| clientToken | string | Unique, case-sensitive identifier that you provide to ensure the idempotency of the request. | -| preserveClientIp | boolean | Indicates whether your client's IP address is preserved as the source. | -| securityGroups | aws-cdk-lib.aws_ec2.ISecurityGroup[] | The security groups to associate with the EC2 Instance Connect Endpoint. | +The custom port to use when connecting to a workgroup. + +Valid port ranges are 5431-5455 and 8191-8215. --- -##### `vpc`Required +##### `publiclyAccessible`Optional ```typescript -public readonly vpc: IVpc; +public readonly publiclyAccessible: boolean; ``` -- *Type:* aws-cdk-lib.aws_ec2.IVpc +- *Type:* boolean +- *Default:* false -The VPC in which the EC2 Instance Connect Endpoint is created. +A value that specifies whether the workgroup can be accessible from a public network. --- -##### `clientToken`Optional +##### `securityGroups`Optional ```typescript -public readonly clientToken: string; +public readonly securityGroups: ISecurityGroup[]; ``` -- *Type:* string - -Unique, case-sensitive identifier that you provide to ensure the idempotency of the request. +- *Type:* aws-cdk-lib.aws_ec2.ISecurityGroup[] +- *Default:* no database created -> [https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-instanceconnectendpoint.html#cfn-ec2-instanceconnectendpoint-clienttoken](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-instanceconnectendpoint.html#cfn-ec2-instanceconnectendpoint-clienttoken) +The name of the primary database created in the workgroup. --- -##### `preserveClientIp`Optional +##### `vpcSubnets`Optional ```typescript -public readonly preserveClientIp: boolean; +public readonly vpcSubnets: SubnetSelection; ``` -- *Type:* boolean -- *Default:* true - -Indicates whether your client's IP address is preserved as the source. +- *Type:* aws-cdk-lib.aws_ec2.SubnetSelection +- *Default:* private subnets -> [https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-instanceconnectendpoint.html#cfn-ec2-instanceconnectendpoint-preserveclientip](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-instanceconnectendpoint.html#cfn-ec2-instanceconnectendpoint-preserveclientip) +Where to place the workgroup within the VPC. --- -##### `securityGroups`Optional +##### `workgroupName`Optional ```typescript -public readonly securityGroups: ISecurityGroup[]; +public readonly workgroupName: string; ``` -- *Type:* aws-cdk-lib.aws_ec2.ISecurityGroup[] -- *Default:* a new security group is created +- *Type:* string +- *Default:* auto generate -The security groups to associate with the EC2 Instance Connect Endpoint. +The name of the cost report. --- @@ -960,3 +2003,254 @@ The ID of the EC2 Instance Connect Endpoint. --- +### INamespace + +- *Extends:* aws-cdk-lib.IResource + +- *Implemented By:* @open-constructs/aws-cdk.aws_redshiftserverless.Namespace, @open-constructs/aws-cdk.aws_redshiftserverless.INamespace + +A Redshift Serverless Namespace. + + +#### Properties + +| **Name** | **Type** | **Description** | +| --- | --- | --- | +| node | constructs.Node | The tree node. | +| env | aws-cdk-lib.ResourceEnvironment | The environment this resource belongs to. | +| stack | aws-cdk-lib.Stack | The stack in which this resource is defined. | +| namespaceArn | string | The namespace Arn. | +| namespaceName | string | The namespace name. | + +--- + +##### `node`Required + +```typescript +public readonly node: Node; +``` + +- *Type:* constructs.Node + +The tree node. + +--- + +##### `env`Required + +```typescript +public readonly env: ResourceEnvironment; +``` + +- *Type:* aws-cdk-lib.ResourceEnvironment + +The environment this resource belongs to. + +For resources that are created and managed by the CDK +(generally, those created by creating new class instances like Role, Bucket, etc.), +this is always the same as the environment of the stack they belong to; +however, for imported resources +(those obtained from static methods like fromRoleArn, fromBucketName, etc.), +that might be different than the stack they were imported into. + +--- + +##### `stack`Required + +```typescript +public readonly stack: Stack; +``` + +- *Type:* aws-cdk-lib.Stack + +The stack in which this resource is defined. + +--- + +##### `namespaceArn`Required + +```typescript +public readonly namespaceArn: string; +``` + +- *Type:* string + +The namespace Arn. + +--- + +##### `namespaceName`Required + +```typescript +public readonly namespaceName: string; +``` + +- *Type:* string + +The namespace name. + +--- + +### IWorkgroup + +- *Extends:* aws-cdk-lib.IResource, aws-cdk-lib.aws_ec2.IConnectable + +- *Implemented By:* @open-constructs/aws-cdk.aws_redshiftserverless.Workgroup, @open-constructs/aws-cdk.aws_redshiftserverless.IWorkgroup + +A Redshift Serverless Workgroup. + + +#### Properties + +| **Name** | **Type** | **Description** | +| --- | --- | --- | +| node | constructs.Node | The tree node. | +| env | aws-cdk-lib.ResourceEnvironment | The environment this resource belongs to. | +| stack | aws-cdk-lib.Stack | The stack in which this resource is defined. | +| connections | aws-cdk-lib.aws_ec2.Connections | The network connections associated with this resource. | +| endpointAddress | string | The workgroup endpoint address. | +| port | number | The workgroup port. | +| workgroupArn | string | The workgroup Arn. | +| workgroupName | string | The workgroup name. | + +--- + +##### `node`Required + +```typescript +public readonly node: Node; +``` + +- *Type:* constructs.Node + +The tree node. + +--- + +##### `env`Required + +```typescript +public readonly env: ResourceEnvironment; +``` + +- *Type:* aws-cdk-lib.ResourceEnvironment + +The environment this resource belongs to. + +For resources that are created and managed by the CDK +(generally, those created by creating new class instances like Role, Bucket, etc.), +this is always the same as the environment of the stack they belong to; +however, for imported resources +(those obtained from static methods like fromRoleArn, fromBucketName, etc.), +that might be different than the stack they were imported into. + +--- + +##### `stack`Required + +```typescript +public readonly stack: Stack; +``` + +- *Type:* aws-cdk-lib.Stack + +The stack in which this resource is defined. + +--- + +##### `connections`Required + +```typescript +public readonly connections: Connections; +``` + +- *Type:* aws-cdk-lib.aws_ec2.Connections + +The network connections associated with this resource. + +--- + +##### `endpointAddress`Required + +```typescript +public readonly endpointAddress: string; +``` + +- *Type:* string + +The workgroup endpoint address. + +--- + +##### `port`Required + +```typescript +public readonly port: number; +``` + +- *Type:* number + +The workgroup port. + +--- + +##### `workgroupArn`Required + +```typescript +public readonly workgroupArn: string; +``` + +- *Type:* string + +The workgroup Arn. + +--- + +##### `workgroupName`Required + +```typescript +public readonly workgroupName: string; +``` + +- *Type:* string + +The workgroup name. + +--- + +## Enums + +### LogExport + +The types of logs the namespace can export. + +#### Members + +| **Name** | **Description** | +| --- | --- | +| USER_LOG | User log. | +| CONNECTION_LOG | Connection log. | +| USER_ACTIVITY_LOG | User activity log. | + +--- + +##### `USER_LOG` + +User log. + +--- + + +##### `CONNECTION_LOG` + +Connection log. + +--- + + +##### `USER_ACTIVITY_LOG` + +User activity log. + +--- + diff --git a/src/aws-redshiftserverless/README.md b/src/aws-redshiftserverless/README.md new file mode 100644 index 0000000..6e155c8 --- /dev/null +++ b/src/aws-redshiftserverless/README.md @@ -0,0 +1,5 @@ +Constructs for thw Amazon Redshift Serverlss + +# Redshift Serverless CDK Construct + +WIP \ No newline at end of file diff --git a/src/aws-redshiftserverless/index.ts b/src/aws-redshiftserverless/index.ts new file mode 100644 index 0000000..f2c6b65 --- /dev/null +++ b/src/aws-redshiftserverless/index.ts @@ -0,0 +1,2 @@ +export * from './namespace'; +export * from './workgroup'; \ No newline at end of file diff --git a/src/aws-redshiftserverless/namespace.ts b/src/aws-redshiftserverless/namespace.ts new file mode 100644 index 0000000..0a0a742 --- /dev/null +++ b/src/aws-redshiftserverless/namespace.ts @@ -0,0 +1,203 @@ +import { IResource, Lazy, Names, Resource, SecretValue, aws_redshiftserverless } from 'aws-cdk-lib'; +import { IRole } from 'aws-cdk-lib/aws-iam'; +import { IKey } from 'aws-cdk-lib/aws-kms'; +import { Construct } from 'constructs'; + +/** + * A Redshift Serverless Namespace + */ +export interface INamespace extends IResource { + /** + * The namespace Arn + * + * @attribute + */ + readonly namespaceArn: string; + /** + * The namespace name + * + * @attribute + */ + readonly namespaceName: string; +} + +/** + * Properties for defining a Redshift Serverless Namespace. + */ +export interface NamespaceProps { + /** + * The username of the administrator for the primary database created in the namespace. + * + * @default - no admin user + */ + readonly adminUsername?: string; + + /** + * The password of the administrator for the primary database created in the namespace. + * + * @default - no admin user + */ + readonly adminUserPassword?: SecretValue; + + /** + * The name of the primary database created in the namespace. + * + * @default - dev + */ + readonly dbName?: string; + + /** + * The IAM role to set as a default in the namespace. + * + * @default - no default IAM role + */ + readonly defaultIamRole?: IRole; + + /** + * The name of the snapshot to be created before the namespace is deleted. + * + * @default - no final snapshot + */ + readonly finalSnapshotName?: string; + + /** + * How long to retain the final snapshot. + * + * @default - Retained indefinitely if finalSnapshotName is specified, otherwise no final snapshot + */ + readonly finalSnapshotRetentionPeriod?: number; + + /** + * A list of IAM roles to associate with the namespace. + * + * @default - no IAM role associated + */ + readonly iamRoles?: IRole[]; + + /** + * A Customer Managed Key used to encrypt your data. + * + * @default - use AWS managed key + */ + readonly kmsKey?: IKey; + + /** + * The types of logs the namespace can export. + * + * @default - no logs export + */ + readonly logExports?: LogExport[]; + + /** + * The name of the cost report. + */ + readonly namespaceName?: string; +} + +/** + * The types of logs the namespace can export. + */ +export enum LogExport { + /** + * User log + */ + USER_LOG = 'userlog', + + /** + * Connection log + */ + CONNECTION_LOG = 'connectionlog', + + /** + * User activity log + */ + USER_ACTIVITY_LOG = 'useractivitylog' +} + +/** + * Attributes for importing a Redshift Serverless Namespace. + */ +export interface NamespaceAttributes { + /** + * The namespace Arn + */ + readonly namespaceArn: string; + /** + * The namespace name + */ + readonly namespaceName: string; + +} + +/** + * Represents a Redshift Serverless Namespace construct in AWS CDK. + * + * @example + * + * const nameSpace = new Namespace( + * stack, + * 'Namespace', + * { + * namespaceName: 'my-namespace', + * }, + * ); + */ +export class Namespace extends Resource implements INamespace { + + /** + * Import an existing namspace to the stack from its attributes. + */ + public static fromNamespaceAttributes( + scope: Construct, + id: string, + attrs: NamespaceAttributes, + ): INamespace { + class Import extends Resource implements INamespace { + public readonly namespaceArn = attrs.namespaceArn; + public readonly namespaceName = attrs.namespaceName; + } + + return new Import(scope, id); + } + + /** + * The namespace Arn + */ + readonly namespaceArn: string; + /** + * The namespace name + */ + readonly namespaceName: string; + + private readonly props: NamespaceProps; + + constructor(scope: Construct, id: string, props: NamespaceProps) { + super(scope, id, { + physicalName: props.namespaceName ?? Lazy.string({ + produce: () => Names.uniqueResourceName(this, { maxLength: 64, allowedSpecialCharacters: '-' }).toLowerCase(), + }), + }); + this.props = props; + + const namespace = this.createNamespace(); + + this.namespaceArn = namespace.attrNamespaceNamespaceArn; + this.namespaceName = namespace.attrNamespaceNamespaceName; + + } + + protected createNamespace(): aws_redshiftserverless.CfnNamespace { + return new aws_redshiftserverless.CfnNamespace(this, 'Resource', { + adminUsername: this.props.adminUsername, + adminUserPassword: this.props.adminUserPassword?.unsafeUnwrap(), + dbName: this.props.dbName, + defaultIamRoleArn: this.props.defaultIamRole?.roleArn, + finalSnapshotName: this.props.finalSnapshotName, + finalSnapshotRetentionPeriod: this.props.finalSnapshotRetentionPeriod, + iamRoles: Lazy.list({ produce: () => this.props.iamRoles?.map(role => role.roleArn) }, { omitEmpty: true }), + kmsKeyId: this.props.kmsKey?.keyId, + logExports: this.props.logExports, + namespaceName: this.physicalName, + }); + } +} diff --git a/src/aws-redshiftserverless/workgroup.ts b/src/aws-redshiftserverless/workgroup.ts new file mode 100644 index 0000000..1ca878b --- /dev/null +++ b/src/aws-redshiftserverless/workgroup.ts @@ -0,0 +1,260 @@ +import { IResource, Lazy, Names, Resource, aws_redshiftserverless, aws_ec2 } from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import { INamespace } from './namespace'; + +/** + * A Redshift Serverless Workgroup + */ +export interface IWorkgroup extends IResource, aws_ec2.IConnectable { + /** + * The workgroup Arn + * + * @attribute + */ + readonly workgroupArn: string; + /** + * The workgroup name + * + * @attribute + */ + readonly workgroupName: string; + /** + * The workgroup endpoint address + * + * @attribute + */ + readonly endpointAddress: string; + /** + * The workgroup port + * + * @attribute + */ + readonly port: number; +} + +/** + * Properties for defining a Redshift Serverless Workgroup. + */ +export interface WorkgroupProps { + /** + * The base compute capacity of the workgroup in Redshift Processing Units (RPUs). + * + * @default 8 + */ + readonly baseCapacity?: number; + + /** + * A list of parameters to set for finer control over a database. + * + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-redshiftserverless-workgroup.html#cfn-redshiftserverless-workgroup-configparameters + * @default - no config parameters + */ + readonly configParameters?: { [key: string]: string }; + + /** + * The value that specifies whether to enable enhanced virtual private cloud (VPC) routing, + * which forces Amazon Redshift Serverless to route traffic through your VPC. + * + * @default - false + */ + readonly enhancedVpcRouting?: boolean; + + /** + * The namespace the workgroup is associated with. + * + * @default - the workgroup is not associated with any namespace + */ + readonly namespace?: INamespace; + + /** + * The custom port to use when connecting to a workgroup. Valid port ranges are 5431-5455 and 8191-8215. + * + * @default - 5439 + */ + readonly port?: number; + + /** + * A value that specifies whether the workgroup can be accessible from a public network. + * + * @default - false + */ + readonly publiclyAccessible?: boolean; + + /** + * The name of the primary database created in the workgroup. + * + * @default - no database created + */ + readonly securityGroups?: aws_ec2.ISecurityGroup[]; + + /** + * The VPC to place the workgroup in. + */ + readonly vpc: aws_ec2.IVpc; + + /** + * Where to place the workgroup within the VPC + * + * @default - private subnets + */ + readonly vpcSubnets?: aws_ec2.SubnetSelection; + + /** + * The name of the cost report. + * + * @default - auto generate + */ + readonly workgroupName?: string; +} + +/** + * Attributes for importing a Redshift Serverless Workgroup. + */ +export interface WorkgroupAttributes { + /** + * The workgroup Arn + */ + readonly workgroupArn: string; + /** + * The workgroup name + */ + readonly workgroupName: string; + /** + * The workgroup endpoint address + */ + readonly endpointAddress: string; + /** + * The workgroup port + */ + readonly port: number; + /** + * The security groups associated with the Redshift Serverless Workgroup. + */ + readonly securityGroups: aws_ec2.ISecurityGroup[]; +} + +/** + * Represents a Redshift Serverless Workgroup construct in AWS CDK. + * + * @example + * declare const namespace: Namespace; + * declare const vpc: aws_ec2.IVpc; + * +* const nameSpace = new Workgroup( + * stack, + * 'Workgroup', + * { + * workgroupName: 'my-workgroup', + * namespace: namespace, + * vpc, + * }, + * ); + */ +export class Workgroup extends Resource implements IWorkgroup { + + /** + * Import an existing workgroup to the stack from its attributes. + */ + public static fromWorkgroupAttributes( + scope: Construct, + id: string, + attrs: WorkgroupAttributes, + ): IWorkgroup { + class Import extends Resource implements IWorkgroup { + public readonly workgroupArn = attrs.workgroupArn; + public readonly workgroupName = attrs.workgroupName; + public readonly endpointAddress = attrs.endpointAddress; + public readonly port = attrs.port; + public readonly connections = new aws_ec2.Connections({ + securityGroups: attrs.securityGroups, + defaultPort: aws_ec2.Port.tcp(attrs.port), + }); + } + + return new Import(scope, id); + } + + /** + * The workgroup Arn + */ + readonly workgroupArn: string; + /** + * The workgroup name + */ + readonly workgroupName: string; + + /** + * The workgroup endpoint address + */ + readonly endpointAddress: string; + + /** + * The workgroup port + */ + readonly port: number; + + /** + * The connection object associated with the Redshift Serverless Workgroup. + */ + public readonly connections: aws_ec2.Connections; + + private readonly props: WorkgroupProps; + private readonly securityGroups: aws_ec2.ISecurityGroup[]; + private readonly vpcSubnets: aws_ec2.SubnetSelection; + + constructor(scope: Construct, id: string, props: WorkgroupProps) { + super(scope, id, { + physicalName: props.workgroupName ?? Lazy.string({ + produce: () => Names.uniqueResourceName(this, { maxLength: 64, allowedSpecialCharacters: '-' }).toLowerCase(), + }), + }); + this.props = props; + + this.securityGroups = props.securityGroups ?? [this.createSecurityGroup()]; + + this.connections = this.createConnections(); + + this.vpcSubnets = props.vpcSubnets ?? { + subnetType: aws_ec2.SubnetType.PRIVATE_WITH_EGRESS, + }; + + const workgroup = this.createWorkgroup(); + + this.workgroupArn = workgroup.attrWorkgroupWorkgroupArn; + this.workgroupName = workgroup.attrWorkgroupWorkgroupName; + this.endpointAddress = workgroup.attrWorkgroupEndpointAddress; + this.port = workgroup.attrWorkgroupEndpointPort; + } + + protected createWorkgroup(): aws_redshiftserverless.CfnWorkgroup { + return new aws_redshiftserverless.CfnWorkgroup(this, 'Resource', { + baseCapacity: this.props.baseCapacity, + configParameters: this.props.configParameters + ? Object.entries(this.props.configParameters).map(([key, value]) => ({ + parameterKey: key, + parameterValue: value, + })) + : undefined, + enhancedVpcRouting: this.props.enhancedVpcRouting, + namespaceName: this.props.namespace?.namespaceName, + publiclyAccessible: this.props.publiclyAccessible, + port: this.props.port, + securityGroupIds: Lazy.list({ produce: () => this.securityGroups.map(sg => sg.securityGroupId) }), + subnetIds: Lazy.list({ produce: () => this.props.vpc.selectSubnets(this.vpcSubnets).subnetIds }), + workgroupName: this.physicalName, + }); + } + + protected createSecurityGroup(): aws_ec2.SecurityGroup { + return new aws_ec2.SecurityGroup(this, 'SecurityGroup', { + vpc: this.props.vpc, + description: 'Automatic generated security group for Redshift Serverless Security Group', + }); + } + + protected createConnections(): aws_ec2.Connections { + return new aws_ec2.Connections({ + securityGroups: this.securityGroups, + }); + } +} diff --git a/src/index.ts b/src/index.ts index 163304a..a0ed7a7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,4 @@ // Export constructs here export * as aws_cur from './aws-cur'; export * as aws_ec2 from './aws-ec2'; +export * as aws_redshiftserverless from './aws-redshiftserverless'; \ No newline at end of file diff --git a/test/aws-redshiftserverless/integ.redshift-serverless.ts b/test/aws-redshiftserverless/integ.redshift-serverless.ts new file mode 100644 index 0000000..23d5167 --- /dev/null +++ b/test/aws-redshiftserverless/integ.redshift-serverless.ts @@ -0,0 +1,61 @@ +import { IntegTest } from '@aws-cdk/integ-tests-alpha'; +import * as cdk from 'aws-cdk-lib'; +import { Role, ServicePrincipal } from 'aws-cdk-lib/aws-iam'; +import { Construct } from 'constructs'; +import * as ocf from '../../src'; + +class RedshiftServerlessStack extends cdk.Stack { + public readonly workgroup: ocf.aws_redshiftserverless.Workgroup; + constructor(scope: Construct, id: string, props?: cdk.StackProps) { + super(scope, id, props); + + const vpc = new cdk.aws_ec2.Vpc(this, 'VPC', {}); + + const defaultRole = new Role(this, 'DefaultRole', { + assumedBy: new ServicePrincipal('redshift.amazonaws.com'), + }); + + const anotherRole = new Role(this, 'AnotherRole', { + assumedBy: new ServicePrincipal('redshift.amazonaws.com'), + }); + + const namespace = new ocf.aws_redshiftserverless.Namespace(this, 'Namespace', { + adminUsername: 'adminuser', + adminUserPassword: cdk.SecretValue.unsafePlainText('adminUserPassword123'), + defaultIamRole: defaultRole, + iamRoles: [defaultRole, anotherRole], + dbName: 'mydatabase', + logExports: [ + ocf.aws_redshiftserverless.LogExport.USER_LOG, + ocf.aws_redshiftserverless.LogExport.CONNECTION_LOG, + ocf.aws_redshiftserverless.LogExport.USER_ACTIVITY_LOG, + ], + }); + + const workgroup = new ocf.aws_redshiftserverless.Workgroup(this, 'WorkGroup', { + namespace, + vpc, + enhancedVpcRouting: true, + publiclyAccessible: true, + port: 5432, + }); + this.workgroup = workgroup; + } +} + +const app = new cdk.App(); +const env = { + account: process.env.CDK_INTEG_ACCOUNT || process.env.CDK_DEFAULT_ACCOUNT, + region: process.env.CDK_INTEG_REGION || process.env.CDK_DEFAULT_REGION, +}; + +const testCase = new RedshiftServerlessStack(app, 'RedshiftServerlessStack', { env }); + +new IntegTest(app, 'RedshiftServerless', { + testCases: [testCase], + enableLookups: true, + stackUpdateWorkflow: false, +}); + +new cdk.CfnOutput(testCase, 'endpointAddress', { value: testCase.workgroup.endpointAddress }); +// new cdk.CfnOutput(testCase, 'port', { value: testCase.workgroup.port.toString() }); diff --git a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessDefaultTestDeployAssertC5CDACEC.assets.json b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessDefaultTestDeployAssertC5CDACEC.assets.json new file mode 100644 index 0000000..8b20e2f --- /dev/null +++ b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessDefaultTestDeployAssertC5CDACEC.assets.json @@ -0,0 +1,19 @@ +{ + "version": "36.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "RedshiftServerlessDefaultTestDeployAssertC5CDACEC.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/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessDefaultTestDeployAssertC5CDACEC.template.json b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessDefaultTestDeployAssertC5CDACEC.template.json new file mode 100644 index 0000000..ad9d0fb --- /dev/null +++ b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessDefaultTestDeployAssertC5CDACEC.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/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.assets.json b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.assets.json new file mode 100644 index 0000000..cd544fd --- /dev/null +++ b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.assets.json @@ -0,0 +1,34 @@ +{ + "version": "36.0.0", + "files": { + "dd5711540f04e06aa955d7f4862fc04e8cdea464cb590dae91ed2976bb78098e": { + "source": { + "path": "asset.dd5711540f04e06aa955d7f4862fc04e8cdea464cb590dae91ed2976bb78098e", + "packaging": "zip" + }, + "destinations": { + "12345678-test-region": { + "bucketName": "cdk-hnb659fds-assets-12345678-test-region", + "objectKey": "dd5711540f04e06aa955d7f4862fc04e8cdea464cb590dae91ed2976bb78098e.zip", + "region": "test-region", + "assumeRoleArn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-file-publishing-role-12345678-test-region" + } + } + }, + "955942d6d7acb0180fe558fcc96546f4ec10dfe38b83a6d5baeacd5698d96fa0": { + "source": { + "path": "RedshiftServerlessStack.template.json", + "packaging": "file" + }, + "destinations": { + "12345678-test-region": { + "bucketName": "cdk-hnb659fds-assets-12345678-test-region", + "objectKey": "955942d6d7acb0180fe558fcc96546f4ec10dfe38b83a6d5baeacd5698d96fa0.json", + "region": "test-region", + "assumeRoleArn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-file-publishing-role-12345678-test-region" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.template.json b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.template.json new file mode 100644 index 0000000..d0f9c70 --- /dev/null +++ b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.template.json @@ -0,0 +1,796 @@ +{ + "Resources": { + "VPCB9E5F0B4": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC" + } + ] + } + }, + "VPCPublicSubnet1SubnetB4246D30": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "AvailabilityZone": "test-region-1a", + "CidrBlock": "10.0.0.0/19", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC/PublicSubnet1" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCPublicSubnet1RouteTableFEE4B781": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC/PublicSubnet1" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCPublicSubnet1RouteTableAssociation0B0896DC": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + } + } + }, + "VPCPublicSubnet1DefaultRoute91CEF279": { + "Type": "AWS::EC2::Route", + "Properties": { + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + }, + "RouteTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + } + }, + "DependsOn": [ + "VPCVPCGW99B986DC" + ] + }, + "VPCPublicSubnet1EIP6AD938E8": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1NATGatewayE0556630": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet1EIP6AD938E8", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, + "Tags": [ + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC/PublicSubnet1" + } + ] + }, + "DependsOn": [ + "VPCPublicSubnet1DefaultRoute91CEF279", + "VPCPublicSubnet1RouteTableAssociation0B0896DC" + ] + }, + "VPCPublicSubnet2Subnet74179F39": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "AvailabilityZone": "test-region-1b", + "CidrBlock": "10.0.32.0/19", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC/PublicSubnet2" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCPublicSubnet2RouteTable6F1A15F1": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC/PublicSubnet2" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCPublicSubnet2RouteTableAssociation5A808732": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + } + } + }, + "VPCPublicSubnet2DefaultRouteB7481BBA": { + "Type": "AWS::EC2::Route", + "Properties": { + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + }, + "RouteTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + } + }, + "DependsOn": [ + "VPCVPCGW99B986DC" + ] + }, + "VPCPublicSubnet2EIP4947BC00": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2NATGateway3C070193": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet2EIP4947BC00", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, + "Tags": [ + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC/PublicSubnet2" + } + ] + }, + "DependsOn": [ + "VPCPublicSubnet2DefaultRouteB7481BBA", + "VPCPublicSubnet2RouteTableAssociation5A808732" + ] + }, + "VPCPublicSubnet3Subnet631C5E25": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "AvailabilityZone": "test-region-1c", + "CidrBlock": "10.0.64.0/19", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC/PublicSubnet3" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCPublicSubnet3RouteTable98AE0E14": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC/PublicSubnet3" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCPublicSubnet3RouteTableAssociation427FE0C6": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet3RouteTable98AE0E14" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet3Subnet631C5E25" + } + } + }, + "VPCPublicSubnet3DefaultRouteA0D29D46": { + "Type": "AWS::EC2::Route", + "Properties": { + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + }, + "RouteTableId": { + "Ref": "VPCPublicSubnet3RouteTable98AE0E14" + } + }, + "DependsOn": [ + "VPCVPCGW99B986DC" + ] + }, + "VPCPublicSubnet3EIPAD4BC883": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC/PublicSubnet3" + } + ] + } + }, + "VPCPublicSubnet3NATGatewayD3048F5C": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet3EIPAD4BC883", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VPCPublicSubnet3Subnet631C5E25" + }, + "Tags": [ + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC/PublicSubnet3" + } + ] + }, + "DependsOn": [ + "VPCPublicSubnet3DefaultRouteA0D29D46", + "VPCPublicSubnet3RouteTableAssociation427FE0C6" + ] + }, + "VPCPrivateSubnet1Subnet8BCA10E0": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "AvailabilityZone": "test-region-1a", + "CidrBlock": "10.0.96.0/19", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC/PrivateSubnet1" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCPrivateSubnet1RouteTableBE8A6027": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC/PrivateSubnet1" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCPrivateSubnet1RouteTableAssociation347902D1": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" + }, + "SubnetId": { + "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + } + } + }, + "VPCPrivateSubnet1DefaultRouteAE1D6490": { + "Type": "AWS::EC2::Route", + "Properties": { + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VPCPublicSubnet1NATGatewayE0556630" + }, + "RouteTableId": { + "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" + } + } + }, + "VPCPrivateSubnet2SubnetCFCDAA7A": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "AvailabilityZone": "test-region-1b", + "CidrBlock": "10.0.128.0/19", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC/PrivateSubnet2" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCPrivateSubnet2RouteTable0A19E10E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC/PrivateSubnet2" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCPrivateSubnet2RouteTableAssociation0C73D413": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" + }, + "SubnetId": { + "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" + } + } + }, + "VPCPrivateSubnet2DefaultRouteF4F5CFD2": { + "Type": "AWS::EC2::Route", + "Properties": { + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VPCPublicSubnet2NATGateway3C070193" + }, + "RouteTableId": { + "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" + } + } + }, + "VPCPrivateSubnet3Subnet3EDCD457": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "AvailabilityZone": "test-region-1c", + "CidrBlock": "10.0.160.0/19", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC/PrivateSubnet3" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCPrivateSubnet3RouteTable192186F8": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC/PrivateSubnet3" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCPrivateSubnet3RouteTableAssociationC28D144E": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet3RouteTable192186F8" + }, + "SubnetId": { + "Ref": "VPCPrivateSubnet3Subnet3EDCD457" + } + } + }, + "VPCPrivateSubnet3DefaultRoute27F311AE": { + "Type": "AWS::EC2::Route", + "Properties": { + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VPCPublicSubnet3NATGatewayD3048F5C" + }, + "RouteTableId": { + "Ref": "VPCPrivateSubnet3RouteTable192186F8" + } + } + }, + "VPCIGWB7E252D3": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC" + } + ] + } + }, + "VPCVPCGW99B986DC": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "InternetGatewayId": { + "Ref": "VPCIGWB7E252D3" + }, + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCRestrictDefaultSecurityGroupCustomResource59474679": { + "Type": "Custom::VpcRestrictDefaultSG", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "CustomVpcRestrictDefaultSGCustomResourceProviderHandlerDC833E5E", + "Arn" + ] + }, + "DefaultSecurityGroupId": { + "Fn::GetAtt": [ + "VPCB9E5F0B4", + "DefaultSecurityGroup" + ] + }, + "Account": "12345678" + }, + "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:test-region:12345678:security-group/", + { + "Fn::GetAtt": [ + "VPCB9E5F0B4", + "DefaultSecurityGroup" + ] + } + ] + ] + } + ] + } + ] + } + } + ] + } + }, + "CustomVpcRestrictDefaultSGCustomResourceProviderHandlerDC833E5E": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "cdk-hnb659fds-assets-12345678-test-region", + "S3Key": "dd5711540f04e06aa955d7f4862fc04e8cdea464cb590dae91ed2976bb78098e.zip" + }, + "Timeout": 900, + "MemorySize": 128, + "Handler": "__entrypoint__.handler", + "Role": { + "Fn::GetAtt": [ + "CustomVpcRestrictDefaultSGCustomResourceProviderRole26592FE0", + "Arn" + ] + }, + "Runtime": "nodejs18.x", + "Description": "Lambda function for removing all inbound/outbound rules from the VPC default security group" + }, + "DependsOn": [ + "CustomVpcRestrictDefaultSGCustomResourceProviderRole26592FE0" + ] + }, + "DefaultRoleEFEF8FA6": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "redshift.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "AnotherRoleE13C44E8": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "redshift.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "Namespace9B63B8C8": { + "Type": "AWS::RedshiftServerless::Namespace", + "Properties": { + "AdminUserPassword": "adminUserPassword123", + "AdminUsername": "adminuser", + "DbName": "mydatabase", + "DefaultIamRoleArn": { + "Fn::GetAtt": [ + "DefaultRoleEFEF8FA6", + "Arn" + ] + }, + "IamRoles": [ + { + "Fn::GetAtt": [ + "DefaultRoleEFEF8FA6", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "AnotherRoleE13C44E8", + "Arn" + ] + } + ], + "LogExports": [ + "userlog", + "connectionlog", + "useractivitylog" + ], + "NamespaceName": "redshiftserverlessstacknamespace96a02cb7" + } + }, + "WorkGroupSecurityGroup82E81D37": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "Automatic generated security group for Redshift Serverless Security Group", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "WorkGroup9BE20B7A": { + "Type": "AWS::RedshiftServerless::Workgroup", + "Properties": { + "EnhancedVpcRouting": true, + "NamespaceName": { + "Fn::GetAtt": [ + "Namespace9B63B8C8", + "Namespace.NamespaceName" + ] + }, + "Port": 5432, + "PubliclyAccessible": true, + "SecurityGroupIds": [ + { + "Fn::GetAtt": [ + "WorkGroupSecurityGroup82E81D37", + "GroupId" + ] + } + ], + "SubnetIds": [ + { + "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + }, + { + "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" + }, + { + "Ref": "VPCPrivateSubnet3Subnet3EDCD457" + } + ], + "WorkgroupName": "redshiftserverlessstackworkgroupcfbe5e7c" + } + } + }, + "Outputs": { + "endpointAddress": { + "Value": { + "Fn::GetAtt": [ + "WorkGroup9BE20B7A", + "Workgroup.Endpoint.Address" + ] + } + } + }, + "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/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/cdk.out b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/cdk.out new file mode 100644 index 0000000..1f0068d --- /dev/null +++ b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"36.0.0"} \ No newline at end of file diff --git a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/integ.json b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/integ.json new file mode 100644 index 0000000..baea88a --- /dev/null +++ b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/integ.json @@ -0,0 +1,14 @@ +{ + "enableLookups": true, + "version": "36.0.0", + "testCases": { + "RedshiftServerless/DefaultTest": { + "stacks": [ + "RedshiftServerlessStack" + ], + "stackUpdateWorkflow": false, + "assertionStack": "RedshiftServerless/DefaultTest/DeployAssert", + "assertionStackName": "RedshiftServerlessDefaultTestDeployAssertC5CDACEC" + } + } +} \ No newline at end of file diff --git a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/manifest.json b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/manifest.json new file mode 100644 index 0000000..b7cb6a1 --- /dev/null +++ b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/manifest.json @@ -0,0 +1,359 @@ +{ + "version": "36.0.0", + "artifacts": { + "RedshiftServerlessStack.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "RedshiftServerlessStack.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "RedshiftServerlessStack": { + "type": "aws:cloudformation:stack", + "environment": "aws://12345678/test-region", + "properties": { + "templateFile": "RedshiftServerlessStack.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-deploy-role-12345678-test-region", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-cfn-exec-role-12345678-test-region", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-12345678-test-region/955942d6d7acb0180fe558fcc96546f4ec10dfe38b83a6d5baeacd5698d96fa0.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "RedshiftServerlessStack.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-lookup-role-12345678-test-region", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "RedshiftServerlessStack.assets" + ], + "metadata": { + "/RedshiftServerlessStack/VPC/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCB9E5F0B4" + } + ], + "/RedshiftServerlessStack/VPC/PublicSubnet1/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet1SubnetB4246D30" + } + ], + "/RedshiftServerlessStack/VPC/PublicSubnet1/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet1RouteTableFEE4B781" + } + ], + "/RedshiftServerlessStack/VPC/PublicSubnet1/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet1RouteTableAssociation0B0896DC" + } + ], + "/RedshiftServerlessStack/VPC/PublicSubnet1/DefaultRoute": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet1DefaultRoute91CEF279" + } + ], + "/RedshiftServerlessStack/VPC/PublicSubnet1/EIP": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet1EIP6AD938E8" + } + ], + "/RedshiftServerlessStack/VPC/PublicSubnet1/NATGateway": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet1NATGatewayE0556630" + } + ], + "/RedshiftServerlessStack/VPC/PublicSubnet2/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet2Subnet74179F39" + } + ], + "/RedshiftServerlessStack/VPC/PublicSubnet2/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet2RouteTable6F1A15F1" + } + ], + "/RedshiftServerlessStack/VPC/PublicSubnet2/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet2RouteTableAssociation5A808732" + } + ], + "/RedshiftServerlessStack/VPC/PublicSubnet2/DefaultRoute": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet2DefaultRouteB7481BBA" + } + ], + "/RedshiftServerlessStack/VPC/PublicSubnet2/EIP": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet2EIP4947BC00" + } + ], + "/RedshiftServerlessStack/VPC/PublicSubnet2/NATGateway": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet2NATGateway3C070193" + } + ], + "/RedshiftServerlessStack/VPC/PublicSubnet3/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet3Subnet631C5E25" + } + ], + "/RedshiftServerlessStack/VPC/PublicSubnet3/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet3RouteTable98AE0E14" + } + ], + "/RedshiftServerlessStack/VPC/PublicSubnet3/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet3RouteTableAssociation427FE0C6" + } + ], + "/RedshiftServerlessStack/VPC/PublicSubnet3/DefaultRoute": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet3DefaultRouteA0D29D46" + } + ], + "/RedshiftServerlessStack/VPC/PublicSubnet3/EIP": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet3EIPAD4BC883" + } + ], + "/RedshiftServerlessStack/VPC/PublicSubnet3/NATGateway": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet3NATGatewayD3048F5C" + } + ], + "/RedshiftServerlessStack/VPC/PrivateSubnet1/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPrivateSubnet1Subnet8BCA10E0" + } + ], + "/RedshiftServerlessStack/VPC/PrivateSubnet1/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPrivateSubnet1RouteTableBE8A6027" + } + ], + "/RedshiftServerlessStack/VPC/PrivateSubnet1/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPrivateSubnet1RouteTableAssociation347902D1" + } + ], + "/RedshiftServerlessStack/VPC/PrivateSubnet1/DefaultRoute": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPrivateSubnet1DefaultRouteAE1D6490" + } + ], + "/RedshiftServerlessStack/VPC/PrivateSubnet2/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPrivateSubnet2SubnetCFCDAA7A" + } + ], + "/RedshiftServerlessStack/VPC/PrivateSubnet2/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPrivateSubnet2RouteTable0A19E10E" + } + ], + "/RedshiftServerlessStack/VPC/PrivateSubnet2/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPrivateSubnet2RouteTableAssociation0C73D413" + } + ], + "/RedshiftServerlessStack/VPC/PrivateSubnet2/DefaultRoute": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPrivateSubnet2DefaultRouteF4F5CFD2" + } + ], + "/RedshiftServerlessStack/VPC/PrivateSubnet3/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPrivateSubnet3Subnet3EDCD457" + } + ], + "/RedshiftServerlessStack/VPC/PrivateSubnet3/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPrivateSubnet3RouteTable192186F8" + } + ], + "/RedshiftServerlessStack/VPC/PrivateSubnet3/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPrivateSubnet3RouteTableAssociationC28D144E" + } + ], + "/RedshiftServerlessStack/VPC/PrivateSubnet3/DefaultRoute": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPrivateSubnet3DefaultRoute27F311AE" + } + ], + "/RedshiftServerlessStack/VPC/IGW": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCIGWB7E252D3" + } + ], + "/RedshiftServerlessStack/VPC/VPCGW": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCVPCGW99B986DC" + } + ], + "/RedshiftServerlessStack/VPC/RestrictDefaultSecurityGroupCustomResource/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCRestrictDefaultSecurityGroupCustomResource59474679" + } + ], + "/RedshiftServerlessStack/Custom::VpcRestrictDefaultSGCustomResourceProvider/Role": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomVpcRestrictDefaultSGCustomResourceProviderRole26592FE0" + } + ], + "/RedshiftServerlessStack/Custom::VpcRestrictDefaultSGCustomResourceProvider/Handler": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomVpcRestrictDefaultSGCustomResourceProviderHandlerDC833E5E" + } + ], + "/RedshiftServerlessStack/DefaultRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "DefaultRoleEFEF8FA6" + } + ], + "/RedshiftServerlessStack/AnotherRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "AnotherRoleE13C44E8" + } + ], + "/RedshiftServerlessStack/Namespace/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Namespace9B63B8C8" + } + ], + "/RedshiftServerlessStack/WorkGroup/SecurityGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "WorkGroupSecurityGroup82E81D37" + } + ], + "/RedshiftServerlessStack/WorkGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "WorkGroup9BE20B7A" + } + ], + "/RedshiftServerlessStack/endpointAddress": [ + { + "type": "aws:cdk:logicalId", + "data": "endpointAddress" + } + ], + "/RedshiftServerlessStack/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/RedshiftServerlessStack/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "RedshiftServerlessStack" + }, + "RedshiftServerlessDefaultTestDeployAssertC5CDACEC.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "RedshiftServerlessDefaultTestDeployAssertC5CDACEC.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "RedshiftServerlessDefaultTestDeployAssertC5CDACEC": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "RedshiftServerlessDefaultTestDeployAssertC5CDACEC.template.json", + "terminationProtection": false, + "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": [ + "RedshiftServerlessDefaultTestDeployAssertC5CDACEC.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": [ + "RedshiftServerlessDefaultTestDeployAssertC5CDACEC.assets" + ], + "metadata": { + "/RedshiftServerless/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/RedshiftServerless/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "RedshiftServerless/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + } +} \ No newline at end of file diff --git a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/tree.json b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/tree.json new file mode 100644 index 0000000..b0bd76c --- /dev/null +++ b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/tree.json @@ -0,0 +1,1272 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "RedshiftServerlessStack": { + "id": "RedshiftServerlessStack", + "path": "RedshiftServerlessStack", + "children": { + "VPC": { + "id": "VPC", + "path": "RedshiftServerlessStack/VPC", + "children": { + "Resource": { + "id": "Resource", + "path": "RedshiftServerlessStack/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": "RedshiftServerlessStack/VPC" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnVPC", + "version": "2.120.0" + } + }, + "PublicSubnet1": { + "id": "PublicSubnet1", + "path": "RedshiftServerlessStack/VPC/PublicSubnet1", + "children": { + "Subnet": { + "id": "Subnet", + "path": "RedshiftServerlessStack/VPC/PublicSubnet1/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "availabilityZone": "test-region-1a", + "cidrBlock": "10.0.0.0/19", + "mapPublicIpOnLaunch": true, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "Public" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Public" + }, + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC/PublicSubnet1" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", + "version": "2.120.0" + } + }, + "Acl": { + "id": "Acl", + "path": "RedshiftServerlessStack/VPC/PublicSubnet1/Acl", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "2.120.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "RedshiftServerlessStack/VPC/PublicSubnet1/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "tags": [ + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC/PublicSubnet1" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", + "version": "2.120.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "RedshiftServerlessStack/VPC/PublicSubnet1/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + }, + "subnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", + "version": "2.120.0" + } + }, + "DefaultRoute": { + "id": "DefaultRoute", + "path": "RedshiftServerlessStack/VPC/PublicSubnet1/DefaultRoute", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Route", + "aws:cdk:cloudformation:props": { + "destinationCidrBlock": "0.0.0.0/0", + "gatewayId": { + "Ref": "VPCIGWB7E252D3" + }, + "routeTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", + "version": "2.120.0" + } + }, + "EIP": { + "id": "EIP", + "path": "RedshiftServerlessStack/VPC/PublicSubnet1/EIP", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::EIP", + "aws:cdk:cloudformation:props": { + "domain": "vpc", + "tags": [ + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC/PublicSubnet1" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnEIP", + "version": "2.120.0" + } + }, + "NATGateway": { + "id": "NATGateway", + "path": "RedshiftServerlessStack/VPC/PublicSubnet1/NATGateway", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", + "aws:cdk:cloudformation:props": { + "allocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet1EIP6AD938E8", + "AllocationId" + ] + }, + "subnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, + "tags": [ + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC/PublicSubnet1" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnNatGateway", + "version": "2.120.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.PublicSubnet", + "version": "2.120.0" + } + }, + "PublicSubnet2": { + "id": "PublicSubnet2", + "path": "RedshiftServerlessStack/VPC/PublicSubnet2", + "children": { + "Subnet": { + "id": "Subnet", + "path": "RedshiftServerlessStack/VPC/PublicSubnet2/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "availabilityZone": "test-region-1b", + "cidrBlock": "10.0.32.0/19", + "mapPublicIpOnLaunch": true, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "Public" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Public" + }, + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC/PublicSubnet2" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", + "version": "2.120.0" + } + }, + "Acl": { + "id": "Acl", + "path": "RedshiftServerlessStack/VPC/PublicSubnet2/Acl", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "2.120.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "RedshiftServerlessStack/VPC/PublicSubnet2/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "tags": [ + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC/PublicSubnet2" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", + "version": "2.120.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "RedshiftServerlessStack/VPC/PublicSubnet2/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + }, + "subnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", + "version": "2.120.0" + } + }, + "DefaultRoute": { + "id": "DefaultRoute", + "path": "RedshiftServerlessStack/VPC/PublicSubnet2/DefaultRoute", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Route", + "aws:cdk:cloudformation:props": { + "destinationCidrBlock": "0.0.0.0/0", + "gatewayId": { + "Ref": "VPCIGWB7E252D3" + }, + "routeTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", + "version": "2.120.0" + } + }, + "EIP": { + "id": "EIP", + "path": "RedshiftServerlessStack/VPC/PublicSubnet2/EIP", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::EIP", + "aws:cdk:cloudformation:props": { + "domain": "vpc", + "tags": [ + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC/PublicSubnet2" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnEIP", + "version": "2.120.0" + } + }, + "NATGateway": { + "id": "NATGateway", + "path": "RedshiftServerlessStack/VPC/PublicSubnet2/NATGateway", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", + "aws:cdk:cloudformation:props": { + "allocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet2EIP4947BC00", + "AllocationId" + ] + }, + "subnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, + "tags": [ + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC/PublicSubnet2" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnNatGateway", + "version": "2.120.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.PublicSubnet", + "version": "2.120.0" + } + }, + "PublicSubnet3": { + "id": "PublicSubnet3", + "path": "RedshiftServerlessStack/VPC/PublicSubnet3", + "children": { + "Subnet": { + "id": "Subnet", + "path": "RedshiftServerlessStack/VPC/PublicSubnet3/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "availabilityZone": "test-region-1c", + "cidrBlock": "10.0.64.0/19", + "mapPublicIpOnLaunch": true, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "Public" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Public" + }, + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC/PublicSubnet3" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", + "version": "2.120.0" + } + }, + "Acl": { + "id": "Acl", + "path": "RedshiftServerlessStack/VPC/PublicSubnet3/Acl", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "2.120.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "RedshiftServerlessStack/VPC/PublicSubnet3/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "tags": [ + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC/PublicSubnet3" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", + "version": "2.120.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "RedshiftServerlessStack/VPC/PublicSubnet3/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "VPCPublicSubnet3RouteTable98AE0E14" + }, + "subnetId": { + "Ref": "VPCPublicSubnet3Subnet631C5E25" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", + "version": "2.120.0" + } + }, + "DefaultRoute": { + "id": "DefaultRoute", + "path": "RedshiftServerlessStack/VPC/PublicSubnet3/DefaultRoute", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Route", + "aws:cdk:cloudformation:props": { + "destinationCidrBlock": "0.0.0.0/0", + "gatewayId": { + "Ref": "VPCIGWB7E252D3" + }, + "routeTableId": { + "Ref": "VPCPublicSubnet3RouteTable98AE0E14" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", + "version": "2.120.0" + } + }, + "EIP": { + "id": "EIP", + "path": "RedshiftServerlessStack/VPC/PublicSubnet3/EIP", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::EIP", + "aws:cdk:cloudformation:props": { + "domain": "vpc", + "tags": [ + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC/PublicSubnet3" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnEIP", + "version": "2.120.0" + } + }, + "NATGateway": { + "id": "NATGateway", + "path": "RedshiftServerlessStack/VPC/PublicSubnet3/NATGateway", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", + "aws:cdk:cloudformation:props": { + "allocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet3EIPAD4BC883", + "AllocationId" + ] + }, + "subnetId": { + "Ref": "VPCPublicSubnet3Subnet631C5E25" + }, + "tags": [ + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC/PublicSubnet3" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnNatGateway", + "version": "2.120.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.PublicSubnet", + "version": "2.120.0" + } + }, + "PrivateSubnet1": { + "id": "PrivateSubnet1", + "path": "RedshiftServerlessStack/VPC/PrivateSubnet1", + "children": { + "Subnet": { + "id": "Subnet", + "path": "RedshiftServerlessStack/VPC/PrivateSubnet1/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "availabilityZone": "test-region-1a", + "cidrBlock": "10.0.96.0/19", + "mapPublicIpOnLaunch": false, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "Private" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Private" + }, + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC/PrivateSubnet1" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", + "version": "2.120.0" + } + }, + "Acl": { + "id": "Acl", + "path": "RedshiftServerlessStack/VPC/PrivateSubnet1/Acl", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "2.120.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "RedshiftServerlessStack/VPC/PrivateSubnet1/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "tags": [ + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC/PrivateSubnet1" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", + "version": "2.120.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "RedshiftServerlessStack/VPC/PrivateSubnet1/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" + }, + "subnetId": { + "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", + "version": "2.120.0" + } + }, + "DefaultRoute": { + "id": "DefaultRoute", + "path": "RedshiftServerlessStack/VPC/PrivateSubnet1/DefaultRoute", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Route", + "aws:cdk:cloudformation:props": { + "destinationCidrBlock": "0.0.0.0/0", + "natGatewayId": { + "Ref": "VPCPublicSubnet1NATGatewayE0556630" + }, + "routeTableId": { + "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", + "version": "2.120.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.PrivateSubnet", + "version": "2.120.0" + } + }, + "PrivateSubnet2": { + "id": "PrivateSubnet2", + "path": "RedshiftServerlessStack/VPC/PrivateSubnet2", + "children": { + "Subnet": { + "id": "Subnet", + "path": "RedshiftServerlessStack/VPC/PrivateSubnet2/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "availabilityZone": "test-region-1b", + "cidrBlock": "10.0.128.0/19", + "mapPublicIpOnLaunch": false, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "Private" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Private" + }, + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC/PrivateSubnet2" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", + "version": "2.120.0" + } + }, + "Acl": { + "id": "Acl", + "path": "RedshiftServerlessStack/VPC/PrivateSubnet2/Acl", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "2.120.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "RedshiftServerlessStack/VPC/PrivateSubnet2/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "tags": [ + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC/PrivateSubnet2" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", + "version": "2.120.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "RedshiftServerlessStack/VPC/PrivateSubnet2/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" + }, + "subnetId": { + "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", + "version": "2.120.0" + } + }, + "DefaultRoute": { + "id": "DefaultRoute", + "path": "RedshiftServerlessStack/VPC/PrivateSubnet2/DefaultRoute", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Route", + "aws:cdk:cloudformation:props": { + "destinationCidrBlock": "0.0.0.0/0", + "natGatewayId": { + "Ref": "VPCPublicSubnet2NATGateway3C070193" + }, + "routeTableId": { + "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", + "version": "2.120.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.PrivateSubnet", + "version": "2.120.0" + } + }, + "PrivateSubnet3": { + "id": "PrivateSubnet3", + "path": "RedshiftServerlessStack/VPC/PrivateSubnet3", + "children": { + "Subnet": { + "id": "Subnet", + "path": "RedshiftServerlessStack/VPC/PrivateSubnet3/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "availabilityZone": "test-region-1c", + "cidrBlock": "10.0.160.0/19", + "mapPublicIpOnLaunch": false, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "Private" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Private" + }, + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC/PrivateSubnet3" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", + "version": "2.120.0" + } + }, + "Acl": { + "id": "Acl", + "path": "RedshiftServerlessStack/VPC/PrivateSubnet3/Acl", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "2.120.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "RedshiftServerlessStack/VPC/PrivateSubnet3/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "tags": [ + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC/PrivateSubnet3" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", + "version": "2.120.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "RedshiftServerlessStack/VPC/PrivateSubnet3/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "VPCPrivateSubnet3RouteTable192186F8" + }, + "subnetId": { + "Ref": "VPCPrivateSubnet3Subnet3EDCD457" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", + "version": "2.120.0" + } + }, + "DefaultRoute": { + "id": "DefaultRoute", + "path": "RedshiftServerlessStack/VPC/PrivateSubnet3/DefaultRoute", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Route", + "aws:cdk:cloudformation:props": { + "destinationCidrBlock": "0.0.0.0/0", + "natGatewayId": { + "Ref": "VPCPublicSubnet3NATGatewayD3048F5C" + }, + "routeTableId": { + "Ref": "VPCPrivateSubnet3RouteTable192186F8" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", + "version": "2.120.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.PrivateSubnet", + "version": "2.120.0" + } + }, + "IGW": { + "id": "IGW", + "path": "RedshiftServerlessStack/VPC/IGW", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::InternetGateway", + "aws:cdk:cloudformation:props": { + "tags": [ + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnInternetGateway", + "version": "2.120.0" + } + }, + "VPCGW": { + "id": "VPCGW", + "path": "RedshiftServerlessStack/VPC/VPCGW", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::VPCGatewayAttachment", + "aws:cdk:cloudformation:props": { + "internetGatewayId": { + "Ref": "VPCIGWB7E252D3" + }, + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnVPCGatewayAttachment", + "version": "2.120.0" + } + }, + "RestrictDefaultSecurityGroupCustomResource": { + "id": "RestrictDefaultSecurityGroupCustomResource", + "path": "RedshiftServerlessStack/VPC/RestrictDefaultSecurityGroupCustomResource", + "children": { + "Default": { + "id": "Default", + "path": "RedshiftServerlessStack/VPC/RestrictDefaultSecurityGroupCustomResource/Default", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "2.120.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.CustomResource", + "version": "2.120.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.Vpc", + "version": "2.120.0" + } + }, + "Custom::VpcRestrictDefaultSGCustomResourceProvider": { + "id": "Custom::VpcRestrictDefaultSGCustomResourceProvider", + "path": "RedshiftServerlessStack/Custom::VpcRestrictDefaultSGCustomResourceProvider", + "children": { + "Staging": { + "id": "Staging", + "path": "RedshiftServerlessStack/Custom::VpcRestrictDefaultSGCustomResourceProvider/Staging", + "constructInfo": { + "fqn": "aws-cdk-lib.AssetStaging", + "version": "2.120.0" + } + }, + "Role": { + "id": "Role", + "path": "RedshiftServerlessStack/Custom::VpcRestrictDefaultSGCustomResourceProvider/Role", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "2.120.0" + } + }, + "Handler": { + "id": "Handler", + "path": "RedshiftServerlessStack/Custom::VpcRestrictDefaultSGCustomResourceProvider/Handler", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "2.120.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.CustomResourceProviderBase", + "version": "2.120.0" + } + }, + "DefaultRole": { + "id": "DefaultRole", + "path": "RedshiftServerlessStack/DefaultRole", + "children": { + "ImportDefaultRole": { + "id": "ImportDefaultRole", + "path": "RedshiftServerlessStack/DefaultRole/ImportDefaultRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "2.120.0" + } + }, + "Resource": { + "id": "Resource", + "path": "RedshiftServerlessStack/DefaultRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "redshift.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnRole", + "version": "2.120.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Role", + "version": "2.120.0" + } + }, + "AnotherRole": { + "id": "AnotherRole", + "path": "RedshiftServerlessStack/AnotherRole", + "children": { + "ImportAnotherRole": { + "id": "ImportAnotherRole", + "path": "RedshiftServerlessStack/AnotherRole/ImportAnotherRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "2.120.0" + } + }, + "Resource": { + "id": "Resource", + "path": "RedshiftServerlessStack/AnotherRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "redshift.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnRole", + "version": "2.120.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Role", + "version": "2.120.0" + } + }, + "Namespace": { + "id": "Namespace", + "path": "RedshiftServerlessStack/Namespace", + "children": { + "Resource": { + "id": "Resource", + "path": "RedshiftServerlessStack/Namespace/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::RedshiftServerless::Namespace", + "aws:cdk:cloudformation:props": { + "adminUsername": "adminuser", + "adminUserPassword": "adminUserPassword123", + "dbName": "mydatabase", + "defaultIamRoleArn": { + "Fn::GetAtt": [ + "DefaultRoleEFEF8FA6", + "Arn" + ] + }, + "iamRoles": [ + { + "Fn::GetAtt": [ + "DefaultRoleEFEF8FA6", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "AnotherRoleE13C44E8", + "Arn" + ] + } + ], + "logExports": [ + "userlog", + "connectionlog", + "useractivitylog" + ], + "namespaceName": "redshiftserverlessstacknamespace96a02cb7" + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_redshiftserverless.CfnNamespace", + "version": "2.120.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "2.120.0" + } + }, + "WorkGroup": { + "id": "WorkGroup", + "path": "RedshiftServerlessStack/WorkGroup", + "children": { + "SecurityGroup": { + "id": "SecurityGroup", + "path": "RedshiftServerlessStack/WorkGroup/SecurityGroup", + "children": { + "Resource": { + "id": "Resource", + "path": "RedshiftServerlessStack/WorkGroup/SecurityGroup/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SecurityGroup", + "aws:cdk:cloudformation:props": { + "groupDescription": "Automatic generated security group for Redshift Serverless Security Group", + "securityGroupEgress": [ + { + "cidrIp": "0.0.0.0/0", + "description": "Allow all outbound traffic by default", + "ipProtocol": "-1" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSecurityGroup", + "version": "2.120.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.SecurityGroup", + "version": "2.120.0" + } + }, + "Resource": { + "id": "Resource", + "path": "RedshiftServerlessStack/WorkGroup/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::RedshiftServerless::Workgroup", + "aws:cdk:cloudformation:props": { + "enhancedVpcRouting": true, + "namespaceName": { + "Fn::GetAtt": [ + "Namespace9B63B8C8", + "Namespace.NamespaceName" + ] + }, + "port": 5432, + "publiclyAccessible": true, + "securityGroupIds": [ + { + "Fn::GetAtt": [ + "WorkGroupSecurityGroup82E81D37", + "GroupId" + ] + } + ], + "subnetIds": [ + { + "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + }, + { + "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" + }, + { + "Ref": "VPCPrivateSubnet3Subnet3EDCD457" + } + ], + "workgroupName": "redshiftserverlessstackworkgroupcfbe5e7c" + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_redshiftserverless.CfnWorkgroup", + "version": "2.120.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "2.120.0" + } + }, + "endpointAddress": { + "id": "endpointAddress", + "path": "RedshiftServerlessStack/endpointAddress", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnOutput", + "version": "2.120.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "RedshiftServerlessStack/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "2.120.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "RedshiftServerlessStack/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "2.120.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "2.120.0" + } + }, + "RedshiftServerless": { + "id": "RedshiftServerless", + "path": "RedshiftServerless", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "RedshiftServerless/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "RedshiftServerless/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "RedshiftServerless/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "RedshiftServerless/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "2.120.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "RedshiftServerless/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "2.120.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "2.120.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTestCase", + "version": "2.120.0-alpha.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTest", + "version": "2.120.0-alpha.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.App", + "version": "2.120.0" + } + } +} \ No newline at end of file diff --git a/test/aws-redshiftserverless/namespace.test.ts b/test/aws-redshiftserverless/namespace.test.ts new file mode 100644 index 0000000..a461ffe --- /dev/null +++ b/test/aws-redshiftserverless/namespace.test.ts @@ -0,0 +1,23 @@ +import { App, Stack } from 'aws-cdk-lib'; +import { Match, Template } from 'aws-cdk-lib/assertions'; +import { Namespace } from '../../src/aws-redshiftserverless'; + +describe('Redshift Serverless Namespace', () => { + let app: App; + let stack: Stack; + + beforeEach(() => { + app = new App(); + stack = new Stack(app, 'TestStack'); + }); + + test('Create namsepace with minimal properties ', () => { + new Namespace(stack, 'Namespace', {}); + + Template.fromStack(stack).hasResourceProperties('AWS::RedshiftServerless::Namespace', { + NamespaceName: Match.anyValue(), + }); + }); + + // WIP: add more tests +}); \ No newline at end of file diff --git a/test/aws-redshiftserverless/workgroup.test.ts b/test/aws-redshiftserverless/workgroup.test.ts new file mode 100644 index 0000000..a8f96a4 --- /dev/null +++ b/test/aws-redshiftserverless/workgroup.test.ts @@ -0,0 +1,39 @@ +import { App, Stack, aws_ec2 } from 'aws-cdk-lib'; +import { Template } from 'aws-cdk-lib/assertions'; +import { Workgroup } from '../../src/aws-redshiftserverless'; + +describe('Redshift Serverless Workgroup', () => { + let app: App; + let stack: Stack; + let vpc: aws_ec2.Vpc; + + beforeEach(() => { + app = new App(); + stack = new Stack(app, 'TestStack', { + env: { account: '012345678901', region: 'us-east-1' }, + }); + vpc = new aws_ec2.Vpc(stack, 'VPC'); + }); + + test('Create namsepace with minimal properties ', () => { + new Workgroup(stack, 'Namespace', { + vpc, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::RedshiftServerless::Workgroup', { + SecurityGroupIds: [{ + 'Fn::GetAtt': [ + 'NamespaceSecurityGroup051B6159', + 'GroupId', + ], + }], + SubnetIds: [ + { Ref: 'VPCPrivateSubnet1Subnet8BCA10E0' }, + { Ref: 'VPCPrivateSubnet2SubnetCFCDAA7A' }, + { Ref: 'VPCPrivateSubnet3Subnet3EDCD457' }, + ], + }); + }); + + // WIP: add more tests +}); \ No newline at end of file From ea83a48e561956fc6ed0bb6a045457ecf4f2ee7d Mon Sep 17 00:00:00 2001 From: maz Date: Thu, 12 Sep 2024 13:46:27 +0900 Subject: [PATCH 02/29] add namespace validation --- src/aws-redshiftserverless/namespace.ts | 145 +- src/aws-redshiftserverless/workgroup.ts | 2 +- ...efaultTestDeployAssertC5CDACEC.assets.json | 19 - ...aultTestDeployAssertC5CDACEC.template.json | 36 - .../RedshiftServerlessStack.assets.json | 34 - .../RedshiftServerlessStack.template.json | 796 ----------- .../cdk.out | 1 - .../integ.json | 14 - .../manifest.json | 359 ----- .../tree.json | 1272 ----------------- test/aws-redshiftserverless/namespace.test.ts | 154 +- 11 files changed, 283 insertions(+), 2549 deletions(-) delete mode 100644 test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessDefaultTestDeployAssertC5CDACEC.assets.json delete mode 100644 test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessDefaultTestDeployAssertC5CDACEC.template.json delete mode 100644 test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.assets.json delete mode 100644 test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.template.json delete mode 100644 test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/cdk.out delete mode 100644 test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/integ.json delete mode 100644 test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/manifest.json delete mode 100644 test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/tree.json diff --git a/src/aws-redshiftserverless/namespace.ts b/src/aws-redshiftserverless/namespace.ts index 0a0a742..f91e07c 100644 --- a/src/aws-redshiftserverless/namespace.ts +++ b/src/aws-redshiftserverless/namespace.ts @@ -1,4 +1,4 @@ -import { IResource, Lazy, Names, Resource, SecretValue, aws_redshiftserverless } from 'aws-cdk-lib'; +import { IResource, Lazy, Names, Resource, SecretValue, Stack, Token, aws_redshiftserverless } from 'aws-cdk-lib'; import { IRole } from 'aws-cdk-lib/aws-iam'; import { IKey } from 'aws-cdk-lib/aws-kms'; import { Construct } from 'constructs'; @@ -8,17 +8,25 @@ import { Construct } from 'constructs'; */ export interface INamespace extends IResource { /** - * The namespace Arn + * The namespace ARN * * @attribute */ readonly namespaceArn: string; + /** * The namespace name * * @attribute */ readonly namespaceName: string; + + /** + * The namespace id + * + * @attribute + */ + readonly namespaceId: string; } /** @@ -61,7 +69,7 @@ export interface NamespaceProps { readonly finalSnapshotName?: string; /** - * How long to retain the final snapshot. + * How long days to retain the final snapshot. * * @default - Retained indefinitely if finalSnapshotName is specified, otherwise no final snapshot */ @@ -118,14 +126,14 @@ export enum LogExport { * Attributes for importing a Redshift Serverless Namespace. */ export interface NamespaceAttributes { - /** - * The namespace Arn - */ - readonly namespaceArn: string; /** * The namespace name */ readonly namespaceName: string; + /** + * The namespace id + */ + readonly namespaceId: string; } @@ -145,16 +153,18 @@ export interface NamespaceAttributes { export class Namespace extends Resource implements INamespace { /** - * Import an existing namspace to the stack from its attributes. + * Imports an existing Namespace from attributes */ - public static fromNamespaceAttributes( - scope: Construct, - id: string, - attrs: NamespaceAttributes, - ): INamespace { + public static fromNamespaceAttributes(scope: Construct, id: string, attrs: NamespaceAttributes): INamespace { + class Import extends Resource implements INamespace { - public readonly namespaceArn = attrs.namespaceArn; public readonly namespaceName = attrs.namespaceName; + public readonly namespaceId = attrs.namespaceId; + public readonly namespaceArn = Stack.of(this).formatArn({ + resource: 'redshift-serverless', + service: 'namespace', + resourceName: attrs.namespaceId, + }); } return new Import(scope, id); @@ -168,6 +178,10 @@ export class Namespace extends Resource implements INamespace { * The namespace name */ readonly namespaceName: string; + /** + * The namespace id + */ + readonly namespaceId: string; private readonly props: NamespaceProps; @@ -179,10 +193,17 @@ export class Namespace extends Resource implements INamespace { }); this.props = props; + this.validateAdmin(); + this.validateDbName(); + this.validateFinalSnapshot(); + this.validateDefaultIamRole(); + this.validateNamespaceName(); + const namespace = this.createNamespace(); this.namespaceArn = namespace.attrNamespaceNamespaceArn; this.namespaceName = namespace.attrNamespaceNamespaceName; + this.namespaceId = namespace.attrNamespaceNamespaceId; } @@ -200,4 +221,100 @@ export class Namespace extends Resource implements INamespace { namespaceName: this.physicalName, }); } + + /** + * Validates admin settings. + */ + private validateAdmin(): void { + const adminUsername = this.props.adminUsername; + const adminUserPassword = this.props.adminUserPassword; + + if (Token.isUnresolved(adminUsername)) { return } + + if ((adminUsername !== undefined && adminUserPassword === undefined) + || (adminUsername === undefined && adminUserPassword !== undefined)) { + throw new Error('You must specify both `adminUsername` and `adminUserPassword`, or neither.'); + } + + if ( + adminUsername && + !/^[a-zA-Z][a-zA-Z_0-9+.@-]*$/.test(adminUsername) + ) { + throw new Error( + `\`adminUsername\` must start with a letter and can only contain letters, numbers, and the special characters: _, +, ., @, -, got: ${this.props.adminUsername}.` + ); + } + } + + /** + * Validates a database name. + */ + private validateDbName(): void { + const dbName = this.props.dbName; + + if (Token.isUnresolved(dbName) || dbName === undefined) { return } + + if (!/^[a-zA-Z][a-zA-Z_0-9+.@-]*$/.test(dbName) || dbName.length > 127) { + throw new Error( + `\`dbName\` must start with a letter, can only contain letters, numbers, and the special characters: _, +, ., @, -, and must not exceed 127 characters, got: ${this.props.dbName}.` + ); + } + } + + /** + * Validates final snapshot settings. + */ + private validateFinalSnapshot(): void { + const finalSnapshotName = this.props.finalSnapshotName; + const finalSnapshotRetentionPeriod = this.props.finalSnapshotRetentionPeriod; + + if (Token.isUnresolved(finalSnapshotName)) return; + + if (finalSnapshotName) { + if (!/^[a-z][a-z0-9]*(-[a-z0-9]+)*$/.test(finalSnapshotName) || finalSnapshotName.length > 255) { + throw new Error(`\`finalSnapshotName\` must be between 1 and 255 and consist only of lowercase alphanumeric characters or hyphens, with the first character as a letter, and it can't end with a hyphen or contain two consecutive hyphens, got: ${finalSnapshotName}.`); + } + } + + if (!Token.isUnresolved(finalSnapshotRetentionPeriod) + && finalSnapshotRetentionPeriod !== undefined) { + if (!finalSnapshotName) { + throw new Error('You must set \`finalSnapshotName`\ when you specify \`finalSnapshotRetentionPeriod\`.'); + } + + if (finalSnapshotRetentionPeriod < 1 || finalSnapshotRetentionPeriod > 3653) { + { + throw new Error(`\`finalSnapshotRetentionPeriod\` must be 1-3653, got: ${finalSnapshotRetentionPeriod}.`); + } + } + } + } + + /** + * Validates role settings. + */ + private validateDefaultIamRole(): void { + if (!this.props.defaultIamRole) { + return; + } + + if (!this.props.iamRoles || !this.props.iamRoles.includes(this.props.defaultIamRole)) { + throw new Error('\`defaultIamRole\` must be included in \`iamRoles\`.') + } + } + + /** + * Validates a namespace name. + */ + private validateNamespaceName(): void { + const namespaceName = this.props.namespaceName; + + if (Token.isUnresolved(namespaceName) || namespaceName === undefined) { return } + + if (!/^[a-z0-9-]+$/.test(namespaceName) || namespaceName.length < 3 || namespaceName.length > 64) { + throw new Error( + `\`namespaceName\` must be between 3 and 64 characters and consist only of lowercase alphanumeric characters or hyphens, got: ${namespaceName}.` + ); + } + } } diff --git a/src/aws-redshiftserverless/workgroup.ts b/src/aws-redshiftserverless/workgroup.ts index 1ca878b..ed961fb 100644 --- a/src/aws-redshiftserverless/workgroup.ts +++ b/src/aws-redshiftserverless/workgroup.ts @@ -39,7 +39,7 @@ export interface WorkgroupProps { /** * The base compute capacity of the workgroup in Redshift Processing Units (RPUs). * - * @default 8 + * @default 128 */ readonly baseCapacity?: number; diff --git a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessDefaultTestDeployAssertC5CDACEC.assets.json b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessDefaultTestDeployAssertC5CDACEC.assets.json deleted file mode 100644 index 8b20e2f..0000000 --- a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessDefaultTestDeployAssertC5CDACEC.assets.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "version": "36.0.0", - "files": { - "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { - "source": { - "path": "RedshiftServerlessDefaultTestDeployAssertC5CDACEC.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/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessDefaultTestDeployAssertC5CDACEC.template.json b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessDefaultTestDeployAssertC5CDACEC.template.json deleted file mode 100644 index ad9d0fb..0000000 --- a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessDefaultTestDeployAssertC5CDACEC.template.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "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/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.assets.json b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.assets.json deleted file mode 100644 index cd544fd..0000000 --- a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.assets.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "version": "36.0.0", - "files": { - "dd5711540f04e06aa955d7f4862fc04e8cdea464cb590dae91ed2976bb78098e": { - "source": { - "path": "asset.dd5711540f04e06aa955d7f4862fc04e8cdea464cb590dae91ed2976bb78098e", - "packaging": "zip" - }, - "destinations": { - "12345678-test-region": { - "bucketName": "cdk-hnb659fds-assets-12345678-test-region", - "objectKey": "dd5711540f04e06aa955d7f4862fc04e8cdea464cb590dae91ed2976bb78098e.zip", - "region": "test-region", - "assumeRoleArn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-file-publishing-role-12345678-test-region" - } - } - }, - "955942d6d7acb0180fe558fcc96546f4ec10dfe38b83a6d5baeacd5698d96fa0": { - "source": { - "path": "RedshiftServerlessStack.template.json", - "packaging": "file" - }, - "destinations": { - "12345678-test-region": { - "bucketName": "cdk-hnb659fds-assets-12345678-test-region", - "objectKey": "955942d6d7acb0180fe558fcc96546f4ec10dfe38b83a6d5baeacd5698d96fa0.json", - "region": "test-region", - "assumeRoleArn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-file-publishing-role-12345678-test-region" - } - } - } - }, - "dockerImages": {} -} \ No newline at end of file diff --git a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.template.json b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.template.json deleted file mode 100644 index d0f9c70..0000000 --- a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.template.json +++ /dev/null @@ -1,796 +0,0 @@ -{ - "Resources": { - "VPCB9E5F0B4": { - "Type": "AWS::EC2::VPC", - "Properties": { - "CidrBlock": "10.0.0.0/16", - "EnableDnsHostnames": true, - "EnableDnsSupport": true, - "InstanceTenancy": "default", - "Tags": [ - { - "Key": "Name", - "Value": "RedshiftServerlessStack/VPC" - } - ] - } - }, - "VPCPublicSubnet1SubnetB4246D30": { - "Type": "AWS::EC2::Subnet", - "Properties": { - "AvailabilityZone": "test-region-1a", - "CidrBlock": "10.0.0.0/19", - "MapPublicIpOnLaunch": true, - "Tags": [ - { - "Key": "aws-cdk:subnet-name", - "Value": "Public" - }, - { - "Key": "aws-cdk:subnet-type", - "Value": "Public" - }, - { - "Key": "Name", - "Value": "RedshiftServerlessStack/VPC/PublicSubnet1" - } - ], - "VpcId": { - "Ref": "VPCB9E5F0B4" - } - } - }, - "VPCPublicSubnet1RouteTableFEE4B781": { - "Type": "AWS::EC2::RouteTable", - "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": "RedshiftServerlessStack/VPC/PublicSubnet1" - } - ], - "VpcId": { - "Ref": "VPCB9E5F0B4" - } - } - }, - "VPCPublicSubnet1RouteTableAssociation0B0896DC": { - "Type": "AWS::EC2::SubnetRouteTableAssociation", - "Properties": { - "RouteTableId": { - "Ref": "VPCPublicSubnet1RouteTableFEE4B781" - }, - "SubnetId": { - "Ref": "VPCPublicSubnet1SubnetB4246D30" - } - } - }, - "VPCPublicSubnet1DefaultRoute91CEF279": { - "Type": "AWS::EC2::Route", - "Properties": { - "DestinationCidrBlock": "0.0.0.0/0", - "GatewayId": { - "Ref": "VPCIGWB7E252D3" - }, - "RouteTableId": { - "Ref": "VPCPublicSubnet1RouteTableFEE4B781" - } - }, - "DependsOn": [ - "VPCVPCGW99B986DC" - ] - }, - "VPCPublicSubnet1EIP6AD938E8": { - "Type": "AWS::EC2::EIP", - "Properties": { - "Domain": "vpc", - "Tags": [ - { - "Key": "Name", - "Value": "RedshiftServerlessStack/VPC/PublicSubnet1" - } - ] - } - }, - "VPCPublicSubnet1NATGatewayE0556630": { - "Type": "AWS::EC2::NatGateway", - "Properties": { - "AllocationId": { - "Fn::GetAtt": [ - "VPCPublicSubnet1EIP6AD938E8", - "AllocationId" - ] - }, - "SubnetId": { - "Ref": "VPCPublicSubnet1SubnetB4246D30" - }, - "Tags": [ - { - "Key": "Name", - "Value": "RedshiftServerlessStack/VPC/PublicSubnet1" - } - ] - }, - "DependsOn": [ - "VPCPublicSubnet1DefaultRoute91CEF279", - "VPCPublicSubnet1RouteTableAssociation0B0896DC" - ] - }, - "VPCPublicSubnet2Subnet74179F39": { - "Type": "AWS::EC2::Subnet", - "Properties": { - "AvailabilityZone": "test-region-1b", - "CidrBlock": "10.0.32.0/19", - "MapPublicIpOnLaunch": true, - "Tags": [ - { - "Key": "aws-cdk:subnet-name", - "Value": "Public" - }, - { - "Key": "aws-cdk:subnet-type", - "Value": "Public" - }, - { - "Key": "Name", - "Value": "RedshiftServerlessStack/VPC/PublicSubnet2" - } - ], - "VpcId": { - "Ref": "VPCB9E5F0B4" - } - } - }, - "VPCPublicSubnet2RouteTable6F1A15F1": { - "Type": "AWS::EC2::RouteTable", - "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": "RedshiftServerlessStack/VPC/PublicSubnet2" - } - ], - "VpcId": { - "Ref": "VPCB9E5F0B4" - } - } - }, - "VPCPublicSubnet2RouteTableAssociation5A808732": { - "Type": "AWS::EC2::SubnetRouteTableAssociation", - "Properties": { - "RouteTableId": { - "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" - }, - "SubnetId": { - "Ref": "VPCPublicSubnet2Subnet74179F39" - } - } - }, - "VPCPublicSubnet2DefaultRouteB7481BBA": { - "Type": "AWS::EC2::Route", - "Properties": { - "DestinationCidrBlock": "0.0.0.0/0", - "GatewayId": { - "Ref": "VPCIGWB7E252D3" - }, - "RouteTableId": { - "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" - } - }, - "DependsOn": [ - "VPCVPCGW99B986DC" - ] - }, - "VPCPublicSubnet2EIP4947BC00": { - "Type": "AWS::EC2::EIP", - "Properties": { - "Domain": "vpc", - "Tags": [ - { - "Key": "Name", - "Value": "RedshiftServerlessStack/VPC/PublicSubnet2" - } - ] - } - }, - "VPCPublicSubnet2NATGateway3C070193": { - "Type": "AWS::EC2::NatGateway", - "Properties": { - "AllocationId": { - "Fn::GetAtt": [ - "VPCPublicSubnet2EIP4947BC00", - "AllocationId" - ] - }, - "SubnetId": { - "Ref": "VPCPublicSubnet2Subnet74179F39" - }, - "Tags": [ - { - "Key": "Name", - "Value": "RedshiftServerlessStack/VPC/PublicSubnet2" - } - ] - }, - "DependsOn": [ - "VPCPublicSubnet2DefaultRouteB7481BBA", - "VPCPublicSubnet2RouteTableAssociation5A808732" - ] - }, - "VPCPublicSubnet3Subnet631C5E25": { - "Type": "AWS::EC2::Subnet", - "Properties": { - "AvailabilityZone": "test-region-1c", - "CidrBlock": "10.0.64.0/19", - "MapPublicIpOnLaunch": true, - "Tags": [ - { - "Key": "aws-cdk:subnet-name", - "Value": "Public" - }, - { - "Key": "aws-cdk:subnet-type", - "Value": "Public" - }, - { - "Key": "Name", - "Value": "RedshiftServerlessStack/VPC/PublicSubnet3" - } - ], - "VpcId": { - "Ref": "VPCB9E5F0B4" - } - } - }, - "VPCPublicSubnet3RouteTable98AE0E14": { - "Type": "AWS::EC2::RouteTable", - "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": "RedshiftServerlessStack/VPC/PublicSubnet3" - } - ], - "VpcId": { - "Ref": "VPCB9E5F0B4" - } - } - }, - "VPCPublicSubnet3RouteTableAssociation427FE0C6": { - "Type": "AWS::EC2::SubnetRouteTableAssociation", - "Properties": { - "RouteTableId": { - "Ref": "VPCPublicSubnet3RouteTable98AE0E14" - }, - "SubnetId": { - "Ref": "VPCPublicSubnet3Subnet631C5E25" - } - } - }, - "VPCPublicSubnet3DefaultRouteA0D29D46": { - "Type": "AWS::EC2::Route", - "Properties": { - "DestinationCidrBlock": "0.0.0.0/0", - "GatewayId": { - "Ref": "VPCIGWB7E252D3" - }, - "RouteTableId": { - "Ref": "VPCPublicSubnet3RouteTable98AE0E14" - } - }, - "DependsOn": [ - "VPCVPCGW99B986DC" - ] - }, - "VPCPublicSubnet3EIPAD4BC883": { - "Type": "AWS::EC2::EIP", - "Properties": { - "Domain": "vpc", - "Tags": [ - { - "Key": "Name", - "Value": "RedshiftServerlessStack/VPC/PublicSubnet3" - } - ] - } - }, - "VPCPublicSubnet3NATGatewayD3048F5C": { - "Type": "AWS::EC2::NatGateway", - "Properties": { - "AllocationId": { - "Fn::GetAtt": [ - "VPCPublicSubnet3EIPAD4BC883", - "AllocationId" - ] - }, - "SubnetId": { - "Ref": "VPCPublicSubnet3Subnet631C5E25" - }, - "Tags": [ - { - "Key": "Name", - "Value": "RedshiftServerlessStack/VPC/PublicSubnet3" - } - ] - }, - "DependsOn": [ - "VPCPublicSubnet3DefaultRouteA0D29D46", - "VPCPublicSubnet3RouteTableAssociation427FE0C6" - ] - }, - "VPCPrivateSubnet1Subnet8BCA10E0": { - "Type": "AWS::EC2::Subnet", - "Properties": { - "AvailabilityZone": "test-region-1a", - "CidrBlock": "10.0.96.0/19", - "MapPublicIpOnLaunch": false, - "Tags": [ - { - "Key": "aws-cdk:subnet-name", - "Value": "Private" - }, - { - "Key": "aws-cdk:subnet-type", - "Value": "Private" - }, - { - "Key": "Name", - "Value": "RedshiftServerlessStack/VPC/PrivateSubnet1" - } - ], - "VpcId": { - "Ref": "VPCB9E5F0B4" - } - } - }, - "VPCPrivateSubnet1RouteTableBE8A6027": { - "Type": "AWS::EC2::RouteTable", - "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": "RedshiftServerlessStack/VPC/PrivateSubnet1" - } - ], - "VpcId": { - "Ref": "VPCB9E5F0B4" - } - } - }, - "VPCPrivateSubnet1RouteTableAssociation347902D1": { - "Type": "AWS::EC2::SubnetRouteTableAssociation", - "Properties": { - "RouteTableId": { - "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" - }, - "SubnetId": { - "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" - } - } - }, - "VPCPrivateSubnet1DefaultRouteAE1D6490": { - "Type": "AWS::EC2::Route", - "Properties": { - "DestinationCidrBlock": "0.0.0.0/0", - "NatGatewayId": { - "Ref": "VPCPublicSubnet1NATGatewayE0556630" - }, - "RouteTableId": { - "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" - } - } - }, - "VPCPrivateSubnet2SubnetCFCDAA7A": { - "Type": "AWS::EC2::Subnet", - "Properties": { - "AvailabilityZone": "test-region-1b", - "CidrBlock": "10.0.128.0/19", - "MapPublicIpOnLaunch": false, - "Tags": [ - { - "Key": "aws-cdk:subnet-name", - "Value": "Private" - }, - { - "Key": "aws-cdk:subnet-type", - "Value": "Private" - }, - { - "Key": "Name", - "Value": "RedshiftServerlessStack/VPC/PrivateSubnet2" - } - ], - "VpcId": { - "Ref": "VPCB9E5F0B4" - } - } - }, - "VPCPrivateSubnet2RouteTable0A19E10E": { - "Type": "AWS::EC2::RouteTable", - "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": "RedshiftServerlessStack/VPC/PrivateSubnet2" - } - ], - "VpcId": { - "Ref": "VPCB9E5F0B4" - } - } - }, - "VPCPrivateSubnet2RouteTableAssociation0C73D413": { - "Type": "AWS::EC2::SubnetRouteTableAssociation", - "Properties": { - "RouteTableId": { - "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" - }, - "SubnetId": { - "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" - } - } - }, - "VPCPrivateSubnet2DefaultRouteF4F5CFD2": { - "Type": "AWS::EC2::Route", - "Properties": { - "DestinationCidrBlock": "0.0.0.0/0", - "NatGatewayId": { - "Ref": "VPCPublicSubnet2NATGateway3C070193" - }, - "RouteTableId": { - "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" - } - } - }, - "VPCPrivateSubnet3Subnet3EDCD457": { - "Type": "AWS::EC2::Subnet", - "Properties": { - "AvailabilityZone": "test-region-1c", - "CidrBlock": "10.0.160.0/19", - "MapPublicIpOnLaunch": false, - "Tags": [ - { - "Key": "aws-cdk:subnet-name", - "Value": "Private" - }, - { - "Key": "aws-cdk:subnet-type", - "Value": "Private" - }, - { - "Key": "Name", - "Value": "RedshiftServerlessStack/VPC/PrivateSubnet3" - } - ], - "VpcId": { - "Ref": "VPCB9E5F0B4" - } - } - }, - "VPCPrivateSubnet3RouteTable192186F8": { - "Type": "AWS::EC2::RouteTable", - "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": "RedshiftServerlessStack/VPC/PrivateSubnet3" - } - ], - "VpcId": { - "Ref": "VPCB9E5F0B4" - } - } - }, - "VPCPrivateSubnet3RouteTableAssociationC28D144E": { - "Type": "AWS::EC2::SubnetRouteTableAssociation", - "Properties": { - "RouteTableId": { - "Ref": "VPCPrivateSubnet3RouteTable192186F8" - }, - "SubnetId": { - "Ref": "VPCPrivateSubnet3Subnet3EDCD457" - } - } - }, - "VPCPrivateSubnet3DefaultRoute27F311AE": { - "Type": "AWS::EC2::Route", - "Properties": { - "DestinationCidrBlock": "0.0.0.0/0", - "NatGatewayId": { - "Ref": "VPCPublicSubnet3NATGatewayD3048F5C" - }, - "RouteTableId": { - "Ref": "VPCPrivateSubnet3RouteTable192186F8" - } - } - }, - "VPCIGWB7E252D3": { - "Type": "AWS::EC2::InternetGateway", - "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": "RedshiftServerlessStack/VPC" - } - ] - } - }, - "VPCVPCGW99B986DC": { - "Type": "AWS::EC2::VPCGatewayAttachment", - "Properties": { - "InternetGatewayId": { - "Ref": "VPCIGWB7E252D3" - }, - "VpcId": { - "Ref": "VPCB9E5F0B4" - } - } - }, - "VPCRestrictDefaultSecurityGroupCustomResource59474679": { - "Type": "Custom::VpcRestrictDefaultSG", - "Properties": { - "ServiceToken": { - "Fn::GetAtt": [ - "CustomVpcRestrictDefaultSGCustomResourceProviderHandlerDC833E5E", - "Arn" - ] - }, - "DefaultSecurityGroupId": { - "Fn::GetAtt": [ - "VPCB9E5F0B4", - "DefaultSecurityGroup" - ] - }, - "Account": "12345678" - }, - "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:test-region:12345678:security-group/", - { - "Fn::GetAtt": [ - "VPCB9E5F0B4", - "DefaultSecurityGroup" - ] - } - ] - ] - } - ] - } - ] - } - } - ] - } - }, - "CustomVpcRestrictDefaultSGCustomResourceProviderHandlerDC833E5E": { - "Type": "AWS::Lambda::Function", - "Properties": { - "Code": { - "S3Bucket": "cdk-hnb659fds-assets-12345678-test-region", - "S3Key": "dd5711540f04e06aa955d7f4862fc04e8cdea464cb590dae91ed2976bb78098e.zip" - }, - "Timeout": 900, - "MemorySize": 128, - "Handler": "__entrypoint__.handler", - "Role": { - "Fn::GetAtt": [ - "CustomVpcRestrictDefaultSGCustomResourceProviderRole26592FE0", - "Arn" - ] - }, - "Runtime": "nodejs18.x", - "Description": "Lambda function for removing all inbound/outbound rules from the VPC default security group" - }, - "DependsOn": [ - "CustomVpcRestrictDefaultSGCustomResourceProviderRole26592FE0" - ] - }, - "DefaultRoleEFEF8FA6": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "redshift.amazonaws.com" - } - } - ], - "Version": "2012-10-17" - } - } - }, - "AnotherRoleE13C44E8": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "redshift.amazonaws.com" - } - } - ], - "Version": "2012-10-17" - } - } - }, - "Namespace9B63B8C8": { - "Type": "AWS::RedshiftServerless::Namespace", - "Properties": { - "AdminUserPassword": "adminUserPassword123", - "AdminUsername": "adminuser", - "DbName": "mydatabase", - "DefaultIamRoleArn": { - "Fn::GetAtt": [ - "DefaultRoleEFEF8FA6", - "Arn" - ] - }, - "IamRoles": [ - { - "Fn::GetAtt": [ - "DefaultRoleEFEF8FA6", - "Arn" - ] - }, - { - "Fn::GetAtt": [ - "AnotherRoleE13C44E8", - "Arn" - ] - } - ], - "LogExports": [ - "userlog", - "connectionlog", - "useractivitylog" - ], - "NamespaceName": "redshiftserverlessstacknamespace96a02cb7" - } - }, - "WorkGroupSecurityGroup82E81D37": { - "Type": "AWS::EC2::SecurityGroup", - "Properties": { - "GroupDescription": "Automatic generated security group for Redshift Serverless Security Group", - "SecurityGroupEgress": [ - { - "CidrIp": "0.0.0.0/0", - "Description": "Allow all outbound traffic by default", - "IpProtocol": "-1" - } - ], - "VpcId": { - "Ref": "VPCB9E5F0B4" - } - } - }, - "WorkGroup9BE20B7A": { - "Type": "AWS::RedshiftServerless::Workgroup", - "Properties": { - "EnhancedVpcRouting": true, - "NamespaceName": { - "Fn::GetAtt": [ - "Namespace9B63B8C8", - "Namespace.NamespaceName" - ] - }, - "Port": 5432, - "PubliclyAccessible": true, - "SecurityGroupIds": [ - { - "Fn::GetAtt": [ - "WorkGroupSecurityGroup82E81D37", - "GroupId" - ] - } - ], - "SubnetIds": [ - { - "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" - }, - { - "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" - }, - { - "Ref": "VPCPrivateSubnet3Subnet3EDCD457" - } - ], - "WorkgroupName": "redshiftserverlessstackworkgroupcfbe5e7c" - } - } - }, - "Outputs": { - "endpointAddress": { - "Value": { - "Fn::GetAtt": [ - "WorkGroup9BE20B7A", - "Workgroup.Endpoint.Address" - ] - } - } - }, - "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/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/cdk.out b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/cdk.out deleted file mode 100644 index 1f0068d..0000000 --- a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/cdk.out +++ /dev/null @@ -1 +0,0 @@ -{"version":"36.0.0"} \ No newline at end of file diff --git a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/integ.json b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/integ.json deleted file mode 100644 index baea88a..0000000 --- a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/integ.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "enableLookups": true, - "version": "36.0.0", - "testCases": { - "RedshiftServerless/DefaultTest": { - "stacks": [ - "RedshiftServerlessStack" - ], - "stackUpdateWorkflow": false, - "assertionStack": "RedshiftServerless/DefaultTest/DeployAssert", - "assertionStackName": "RedshiftServerlessDefaultTestDeployAssertC5CDACEC" - } - } -} \ No newline at end of file diff --git a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/manifest.json b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/manifest.json deleted file mode 100644 index b7cb6a1..0000000 --- a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/manifest.json +++ /dev/null @@ -1,359 +0,0 @@ -{ - "version": "36.0.0", - "artifacts": { - "RedshiftServerlessStack.assets": { - "type": "cdk:asset-manifest", - "properties": { - "file": "RedshiftServerlessStack.assets.json", - "requiresBootstrapStackVersion": 6, - "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" - } - }, - "RedshiftServerlessStack": { - "type": "aws:cloudformation:stack", - "environment": "aws://12345678/test-region", - "properties": { - "templateFile": "RedshiftServerlessStack.template.json", - "terminationProtection": false, - "validateOnSynth": false, - "assumeRoleArn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-deploy-role-12345678-test-region", - "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-cfn-exec-role-12345678-test-region", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-12345678-test-region/955942d6d7acb0180fe558fcc96546f4ec10dfe38b83a6d5baeacd5698d96fa0.json", - "requiresBootstrapStackVersion": 6, - "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", - "additionalDependencies": [ - "RedshiftServerlessStack.assets" - ], - "lookupRole": { - "arn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-lookup-role-12345678-test-region", - "requiresBootstrapStackVersion": 8, - "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" - } - }, - "dependencies": [ - "RedshiftServerlessStack.assets" - ], - "metadata": { - "/RedshiftServerlessStack/VPC/Resource": [ - { - "type": "aws:cdk:logicalId", - "data": "VPCB9E5F0B4" - } - ], - "/RedshiftServerlessStack/VPC/PublicSubnet1/Subnet": [ - { - "type": "aws:cdk:logicalId", - "data": "VPCPublicSubnet1SubnetB4246D30" - } - ], - "/RedshiftServerlessStack/VPC/PublicSubnet1/RouteTable": [ - { - "type": "aws:cdk:logicalId", - "data": "VPCPublicSubnet1RouteTableFEE4B781" - } - ], - "/RedshiftServerlessStack/VPC/PublicSubnet1/RouteTableAssociation": [ - { - "type": "aws:cdk:logicalId", - "data": "VPCPublicSubnet1RouteTableAssociation0B0896DC" - } - ], - "/RedshiftServerlessStack/VPC/PublicSubnet1/DefaultRoute": [ - { - "type": "aws:cdk:logicalId", - "data": "VPCPublicSubnet1DefaultRoute91CEF279" - } - ], - "/RedshiftServerlessStack/VPC/PublicSubnet1/EIP": [ - { - "type": "aws:cdk:logicalId", - "data": "VPCPublicSubnet1EIP6AD938E8" - } - ], - "/RedshiftServerlessStack/VPC/PublicSubnet1/NATGateway": [ - { - "type": "aws:cdk:logicalId", - "data": "VPCPublicSubnet1NATGatewayE0556630" - } - ], - "/RedshiftServerlessStack/VPC/PublicSubnet2/Subnet": [ - { - "type": "aws:cdk:logicalId", - "data": "VPCPublicSubnet2Subnet74179F39" - } - ], - "/RedshiftServerlessStack/VPC/PublicSubnet2/RouteTable": [ - { - "type": "aws:cdk:logicalId", - "data": "VPCPublicSubnet2RouteTable6F1A15F1" - } - ], - "/RedshiftServerlessStack/VPC/PublicSubnet2/RouteTableAssociation": [ - { - "type": "aws:cdk:logicalId", - "data": "VPCPublicSubnet2RouteTableAssociation5A808732" - } - ], - "/RedshiftServerlessStack/VPC/PublicSubnet2/DefaultRoute": [ - { - "type": "aws:cdk:logicalId", - "data": "VPCPublicSubnet2DefaultRouteB7481BBA" - } - ], - "/RedshiftServerlessStack/VPC/PublicSubnet2/EIP": [ - { - "type": "aws:cdk:logicalId", - "data": "VPCPublicSubnet2EIP4947BC00" - } - ], - "/RedshiftServerlessStack/VPC/PublicSubnet2/NATGateway": [ - { - "type": "aws:cdk:logicalId", - "data": "VPCPublicSubnet2NATGateway3C070193" - } - ], - "/RedshiftServerlessStack/VPC/PublicSubnet3/Subnet": [ - { - "type": "aws:cdk:logicalId", - "data": "VPCPublicSubnet3Subnet631C5E25" - } - ], - "/RedshiftServerlessStack/VPC/PublicSubnet3/RouteTable": [ - { - "type": "aws:cdk:logicalId", - "data": "VPCPublicSubnet3RouteTable98AE0E14" - } - ], - "/RedshiftServerlessStack/VPC/PublicSubnet3/RouteTableAssociation": [ - { - "type": "aws:cdk:logicalId", - "data": "VPCPublicSubnet3RouteTableAssociation427FE0C6" - } - ], - "/RedshiftServerlessStack/VPC/PublicSubnet3/DefaultRoute": [ - { - "type": "aws:cdk:logicalId", - "data": "VPCPublicSubnet3DefaultRouteA0D29D46" - } - ], - "/RedshiftServerlessStack/VPC/PublicSubnet3/EIP": [ - { - "type": "aws:cdk:logicalId", - "data": "VPCPublicSubnet3EIPAD4BC883" - } - ], - "/RedshiftServerlessStack/VPC/PublicSubnet3/NATGateway": [ - { - "type": "aws:cdk:logicalId", - "data": "VPCPublicSubnet3NATGatewayD3048F5C" - } - ], - "/RedshiftServerlessStack/VPC/PrivateSubnet1/Subnet": [ - { - "type": "aws:cdk:logicalId", - "data": "VPCPrivateSubnet1Subnet8BCA10E0" - } - ], - "/RedshiftServerlessStack/VPC/PrivateSubnet1/RouteTable": [ - { - "type": "aws:cdk:logicalId", - "data": "VPCPrivateSubnet1RouteTableBE8A6027" - } - ], - "/RedshiftServerlessStack/VPC/PrivateSubnet1/RouteTableAssociation": [ - { - "type": "aws:cdk:logicalId", - "data": "VPCPrivateSubnet1RouteTableAssociation347902D1" - } - ], - "/RedshiftServerlessStack/VPC/PrivateSubnet1/DefaultRoute": [ - { - "type": "aws:cdk:logicalId", - "data": "VPCPrivateSubnet1DefaultRouteAE1D6490" - } - ], - "/RedshiftServerlessStack/VPC/PrivateSubnet2/Subnet": [ - { - "type": "aws:cdk:logicalId", - "data": "VPCPrivateSubnet2SubnetCFCDAA7A" - } - ], - "/RedshiftServerlessStack/VPC/PrivateSubnet2/RouteTable": [ - { - "type": "aws:cdk:logicalId", - "data": "VPCPrivateSubnet2RouteTable0A19E10E" - } - ], - "/RedshiftServerlessStack/VPC/PrivateSubnet2/RouteTableAssociation": [ - { - "type": "aws:cdk:logicalId", - "data": "VPCPrivateSubnet2RouteTableAssociation0C73D413" - } - ], - "/RedshiftServerlessStack/VPC/PrivateSubnet2/DefaultRoute": [ - { - "type": "aws:cdk:logicalId", - "data": "VPCPrivateSubnet2DefaultRouteF4F5CFD2" - } - ], - "/RedshiftServerlessStack/VPC/PrivateSubnet3/Subnet": [ - { - "type": "aws:cdk:logicalId", - "data": "VPCPrivateSubnet3Subnet3EDCD457" - } - ], - "/RedshiftServerlessStack/VPC/PrivateSubnet3/RouteTable": [ - { - "type": "aws:cdk:logicalId", - "data": "VPCPrivateSubnet3RouteTable192186F8" - } - ], - "/RedshiftServerlessStack/VPC/PrivateSubnet3/RouteTableAssociation": [ - { - "type": "aws:cdk:logicalId", - "data": "VPCPrivateSubnet3RouteTableAssociationC28D144E" - } - ], - "/RedshiftServerlessStack/VPC/PrivateSubnet3/DefaultRoute": [ - { - "type": "aws:cdk:logicalId", - "data": "VPCPrivateSubnet3DefaultRoute27F311AE" - } - ], - "/RedshiftServerlessStack/VPC/IGW": [ - { - "type": "aws:cdk:logicalId", - "data": "VPCIGWB7E252D3" - } - ], - "/RedshiftServerlessStack/VPC/VPCGW": [ - { - "type": "aws:cdk:logicalId", - "data": "VPCVPCGW99B986DC" - } - ], - "/RedshiftServerlessStack/VPC/RestrictDefaultSecurityGroupCustomResource/Default": [ - { - "type": "aws:cdk:logicalId", - "data": "VPCRestrictDefaultSecurityGroupCustomResource59474679" - } - ], - "/RedshiftServerlessStack/Custom::VpcRestrictDefaultSGCustomResourceProvider/Role": [ - { - "type": "aws:cdk:logicalId", - "data": "CustomVpcRestrictDefaultSGCustomResourceProviderRole26592FE0" - } - ], - "/RedshiftServerlessStack/Custom::VpcRestrictDefaultSGCustomResourceProvider/Handler": [ - { - "type": "aws:cdk:logicalId", - "data": "CustomVpcRestrictDefaultSGCustomResourceProviderHandlerDC833E5E" - } - ], - "/RedshiftServerlessStack/DefaultRole/Resource": [ - { - "type": "aws:cdk:logicalId", - "data": "DefaultRoleEFEF8FA6" - } - ], - "/RedshiftServerlessStack/AnotherRole/Resource": [ - { - "type": "aws:cdk:logicalId", - "data": "AnotherRoleE13C44E8" - } - ], - "/RedshiftServerlessStack/Namespace/Resource": [ - { - "type": "aws:cdk:logicalId", - "data": "Namespace9B63B8C8" - } - ], - "/RedshiftServerlessStack/WorkGroup/SecurityGroup/Resource": [ - { - "type": "aws:cdk:logicalId", - "data": "WorkGroupSecurityGroup82E81D37" - } - ], - "/RedshiftServerlessStack/WorkGroup/Resource": [ - { - "type": "aws:cdk:logicalId", - "data": "WorkGroup9BE20B7A" - } - ], - "/RedshiftServerlessStack/endpointAddress": [ - { - "type": "aws:cdk:logicalId", - "data": "endpointAddress" - } - ], - "/RedshiftServerlessStack/BootstrapVersion": [ - { - "type": "aws:cdk:logicalId", - "data": "BootstrapVersion" - } - ], - "/RedshiftServerlessStack/CheckBootstrapVersion": [ - { - "type": "aws:cdk:logicalId", - "data": "CheckBootstrapVersion" - } - ] - }, - "displayName": "RedshiftServerlessStack" - }, - "RedshiftServerlessDefaultTestDeployAssertC5CDACEC.assets": { - "type": "cdk:asset-manifest", - "properties": { - "file": "RedshiftServerlessDefaultTestDeployAssertC5CDACEC.assets.json", - "requiresBootstrapStackVersion": 6, - "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" - } - }, - "RedshiftServerlessDefaultTestDeployAssertC5CDACEC": { - "type": "aws:cloudformation:stack", - "environment": "aws://unknown-account/unknown-region", - "properties": { - "templateFile": "RedshiftServerlessDefaultTestDeployAssertC5CDACEC.template.json", - "terminationProtection": false, - "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": [ - "RedshiftServerlessDefaultTestDeployAssertC5CDACEC.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": [ - "RedshiftServerlessDefaultTestDeployAssertC5CDACEC.assets" - ], - "metadata": { - "/RedshiftServerless/DefaultTest/DeployAssert/BootstrapVersion": [ - { - "type": "aws:cdk:logicalId", - "data": "BootstrapVersion" - } - ], - "/RedshiftServerless/DefaultTest/DeployAssert/CheckBootstrapVersion": [ - { - "type": "aws:cdk:logicalId", - "data": "CheckBootstrapVersion" - } - ] - }, - "displayName": "RedshiftServerless/DefaultTest/DeployAssert" - }, - "Tree": { - "type": "cdk:tree", - "properties": { - "file": "tree.json" - } - } - } -} \ No newline at end of file diff --git a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/tree.json b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/tree.json deleted file mode 100644 index b0bd76c..0000000 --- a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/tree.json +++ /dev/null @@ -1,1272 +0,0 @@ -{ - "version": "tree-0.1", - "tree": { - "id": "App", - "path": "", - "children": { - "RedshiftServerlessStack": { - "id": "RedshiftServerlessStack", - "path": "RedshiftServerlessStack", - "children": { - "VPC": { - "id": "VPC", - "path": "RedshiftServerlessStack/VPC", - "children": { - "Resource": { - "id": "Resource", - "path": "RedshiftServerlessStack/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": "RedshiftServerlessStack/VPC" - } - ] - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnVPC", - "version": "2.120.0" - } - }, - "PublicSubnet1": { - "id": "PublicSubnet1", - "path": "RedshiftServerlessStack/VPC/PublicSubnet1", - "children": { - "Subnet": { - "id": "Subnet", - "path": "RedshiftServerlessStack/VPC/PublicSubnet1/Subnet", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", - "aws:cdk:cloudformation:props": { - "availabilityZone": "test-region-1a", - "cidrBlock": "10.0.0.0/19", - "mapPublicIpOnLaunch": true, - "tags": [ - { - "key": "aws-cdk:subnet-name", - "value": "Public" - }, - { - "key": "aws-cdk:subnet-type", - "value": "Public" - }, - { - "key": "Name", - "value": "RedshiftServerlessStack/VPC/PublicSubnet1" - } - ], - "vpcId": { - "Ref": "VPCB9E5F0B4" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", - "version": "2.120.0" - } - }, - "Acl": { - "id": "Acl", - "path": "RedshiftServerlessStack/VPC/PublicSubnet1/Acl", - "constructInfo": { - "fqn": "aws-cdk-lib.Resource", - "version": "2.120.0" - } - }, - "RouteTable": { - "id": "RouteTable", - "path": "RedshiftServerlessStack/VPC/PublicSubnet1/RouteTable", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", - "aws:cdk:cloudformation:props": { - "tags": [ - { - "key": "Name", - "value": "RedshiftServerlessStack/VPC/PublicSubnet1" - } - ], - "vpcId": { - "Ref": "VPCB9E5F0B4" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", - "version": "2.120.0" - } - }, - "RouteTableAssociation": { - "id": "RouteTableAssociation", - "path": "RedshiftServerlessStack/VPC/PublicSubnet1/RouteTableAssociation", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", - "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VPCPublicSubnet1RouteTableFEE4B781" - }, - "subnetId": { - "Ref": "VPCPublicSubnet1SubnetB4246D30" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", - "version": "2.120.0" - } - }, - "DefaultRoute": { - "id": "DefaultRoute", - "path": "RedshiftServerlessStack/VPC/PublicSubnet1/DefaultRoute", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::EC2::Route", - "aws:cdk:cloudformation:props": { - "destinationCidrBlock": "0.0.0.0/0", - "gatewayId": { - "Ref": "VPCIGWB7E252D3" - }, - "routeTableId": { - "Ref": "VPCPublicSubnet1RouteTableFEE4B781" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", - "version": "2.120.0" - } - }, - "EIP": { - "id": "EIP", - "path": "RedshiftServerlessStack/VPC/PublicSubnet1/EIP", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::EC2::EIP", - "aws:cdk:cloudformation:props": { - "domain": "vpc", - "tags": [ - { - "key": "Name", - "value": "RedshiftServerlessStack/VPC/PublicSubnet1" - } - ] - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnEIP", - "version": "2.120.0" - } - }, - "NATGateway": { - "id": "NATGateway", - "path": "RedshiftServerlessStack/VPC/PublicSubnet1/NATGateway", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", - "aws:cdk:cloudformation:props": { - "allocationId": { - "Fn::GetAtt": [ - "VPCPublicSubnet1EIP6AD938E8", - "AllocationId" - ] - }, - "subnetId": { - "Ref": "VPCPublicSubnet1SubnetB4246D30" - }, - "tags": [ - { - "key": "Name", - "value": "RedshiftServerlessStack/VPC/PublicSubnet1" - } - ] - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnNatGateway", - "version": "2.120.0" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.PublicSubnet", - "version": "2.120.0" - } - }, - "PublicSubnet2": { - "id": "PublicSubnet2", - "path": "RedshiftServerlessStack/VPC/PublicSubnet2", - "children": { - "Subnet": { - "id": "Subnet", - "path": "RedshiftServerlessStack/VPC/PublicSubnet2/Subnet", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", - "aws:cdk:cloudformation:props": { - "availabilityZone": "test-region-1b", - "cidrBlock": "10.0.32.0/19", - "mapPublicIpOnLaunch": true, - "tags": [ - { - "key": "aws-cdk:subnet-name", - "value": "Public" - }, - { - "key": "aws-cdk:subnet-type", - "value": "Public" - }, - { - "key": "Name", - "value": "RedshiftServerlessStack/VPC/PublicSubnet2" - } - ], - "vpcId": { - "Ref": "VPCB9E5F0B4" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", - "version": "2.120.0" - } - }, - "Acl": { - "id": "Acl", - "path": "RedshiftServerlessStack/VPC/PublicSubnet2/Acl", - "constructInfo": { - "fqn": "aws-cdk-lib.Resource", - "version": "2.120.0" - } - }, - "RouteTable": { - "id": "RouteTable", - "path": "RedshiftServerlessStack/VPC/PublicSubnet2/RouteTable", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", - "aws:cdk:cloudformation:props": { - "tags": [ - { - "key": "Name", - "value": "RedshiftServerlessStack/VPC/PublicSubnet2" - } - ], - "vpcId": { - "Ref": "VPCB9E5F0B4" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", - "version": "2.120.0" - } - }, - "RouteTableAssociation": { - "id": "RouteTableAssociation", - "path": "RedshiftServerlessStack/VPC/PublicSubnet2/RouteTableAssociation", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", - "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" - }, - "subnetId": { - "Ref": "VPCPublicSubnet2Subnet74179F39" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", - "version": "2.120.0" - } - }, - "DefaultRoute": { - "id": "DefaultRoute", - "path": "RedshiftServerlessStack/VPC/PublicSubnet2/DefaultRoute", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::EC2::Route", - "aws:cdk:cloudformation:props": { - "destinationCidrBlock": "0.0.0.0/0", - "gatewayId": { - "Ref": "VPCIGWB7E252D3" - }, - "routeTableId": { - "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", - "version": "2.120.0" - } - }, - "EIP": { - "id": "EIP", - "path": "RedshiftServerlessStack/VPC/PublicSubnet2/EIP", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::EC2::EIP", - "aws:cdk:cloudformation:props": { - "domain": "vpc", - "tags": [ - { - "key": "Name", - "value": "RedshiftServerlessStack/VPC/PublicSubnet2" - } - ] - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnEIP", - "version": "2.120.0" - } - }, - "NATGateway": { - "id": "NATGateway", - "path": "RedshiftServerlessStack/VPC/PublicSubnet2/NATGateway", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", - "aws:cdk:cloudformation:props": { - "allocationId": { - "Fn::GetAtt": [ - "VPCPublicSubnet2EIP4947BC00", - "AllocationId" - ] - }, - "subnetId": { - "Ref": "VPCPublicSubnet2Subnet74179F39" - }, - "tags": [ - { - "key": "Name", - "value": "RedshiftServerlessStack/VPC/PublicSubnet2" - } - ] - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnNatGateway", - "version": "2.120.0" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.PublicSubnet", - "version": "2.120.0" - } - }, - "PublicSubnet3": { - "id": "PublicSubnet3", - "path": "RedshiftServerlessStack/VPC/PublicSubnet3", - "children": { - "Subnet": { - "id": "Subnet", - "path": "RedshiftServerlessStack/VPC/PublicSubnet3/Subnet", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", - "aws:cdk:cloudformation:props": { - "availabilityZone": "test-region-1c", - "cidrBlock": "10.0.64.0/19", - "mapPublicIpOnLaunch": true, - "tags": [ - { - "key": "aws-cdk:subnet-name", - "value": "Public" - }, - { - "key": "aws-cdk:subnet-type", - "value": "Public" - }, - { - "key": "Name", - "value": "RedshiftServerlessStack/VPC/PublicSubnet3" - } - ], - "vpcId": { - "Ref": "VPCB9E5F0B4" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", - "version": "2.120.0" - } - }, - "Acl": { - "id": "Acl", - "path": "RedshiftServerlessStack/VPC/PublicSubnet3/Acl", - "constructInfo": { - "fqn": "aws-cdk-lib.Resource", - "version": "2.120.0" - } - }, - "RouteTable": { - "id": "RouteTable", - "path": "RedshiftServerlessStack/VPC/PublicSubnet3/RouteTable", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", - "aws:cdk:cloudformation:props": { - "tags": [ - { - "key": "Name", - "value": "RedshiftServerlessStack/VPC/PublicSubnet3" - } - ], - "vpcId": { - "Ref": "VPCB9E5F0B4" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", - "version": "2.120.0" - } - }, - "RouteTableAssociation": { - "id": "RouteTableAssociation", - "path": "RedshiftServerlessStack/VPC/PublicSubnet3/RouteTableAssociation", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", - "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VPCPublicSubnet3RouteTable98AE0E14" - }, - "subnetId": { - "Ref": "VPCPublicSubnet3Subnet631C5E25" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", - "version": "2.120.0" - } - }, - "DefaultRoute": { - "id": "DefaultRoute", - "path": "RedshiftServerlessStack/VPC/PublicSubnet3/DefaultRoute", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::EC2::Route", - "aws:cdk:cloudformation:props": { - "destinationCidrBlock": "0.0.0.0/0", - "gatewayId": { - "Ref": "VPCIGWB7E252D3" - }, - "routeTableId": { - "Ref": "VPCPublicSubnet3RouteTable98AE0E14" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", - "version": "2.120.0" - } - }, - "EIP": { - "id": "EIP", - "path": "RedshiftServerlessStack/VPC/PublicSubnet3/EIP", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::EC2::EIP", - "aws:cdk:cloudformation:props": { - "domain": "vpc", - "tags": [ - { - "key": "Name", - "value": "RedshiftServerlessStack/VPC/PublicSubnet3" - } - ] - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnEIP", - "version": "2.120.0" - } - }, - "NATGateway": { - "id": "NATGateway", - "path": "RedshiftServerlessStack/VPC/PublicSubnet3/NATGateway", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", - "aws:cdk:cloudformation:props": { - "allocationId": { - "Fn::GetAtt": [ - "VPCPublicSubnet3EIPAD4BC883", - "AllocationId" - ] - }, - "subnetId": { - "Ref": "VPCPublicSubnet3Subnet631C5E25" - }, - "tags": [ - { - "key": "Name", - "value": "RedshiftServerlessStack/VPC/PublicSubnet3" - } - ] - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnNatGateway", - "version": "2.120.0" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.PublicSubnet", - "version": "2.120.0" - } - }, - "PrivateSubnet1": { - "id": "PrivateSubnet1", - "path": "RedshiftServerlessStack/VPC/PrivateSubnet1", - "children": { - "Subnet": { - "id": "Subnet", - "path": "RedshiftServerlessStack/VPC/PrivateSubnet1/Subnet", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", - "aws:cdk:cloudformation:props": { - "availabilityZone": "test-region-1a", - "cidrBlock": "10.0.96.0/19", - "mapPublicIpOnLaunch": false, - "tags": [ - { - "key": "aws-cdk:subnet-name", - "value": "Private" - }, - { - "key": "aws-cdk:subnet-type", - "value": "Private" - }, - { - "key": "Name", - "value": "RedshiftServerlessStack/VPC/PrivateSubnet1" - } - ], - "vpcId": { - "Ref": "VPCB9E5F0B4" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", - "version": "2.120.0" - } - }, - "Acl": { - "id": "Acl", - "path": "RedshiftServerlessStack/VPC/PrivateSubnet1/Acl", - "constructInfo": { - "fqn": "aws-cdk-lib.Resource", - "version": "2.120.0" - } - }, - "RouteTable": { - "id": "RouteTable", - "path": "RedshiftServerlessStack/VPC/PrivateSubnet1/RouteTable", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", - "aws:cdk:cloudformation:props": { - "tags": [ - { - "key": "Name", - "value": "RedshiftServerlessStack/VPC/PrivateSubnet1" - } - ], - "vpcId": { - "Ref": "VPCB9E5F0B4" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", - "version": "2.120.0" - } - }, - "RouteTableAssociation": { - "id": "RouteTableAssociation", - "path": "RedshiftServerlessStack/VPC/PrivateSubnet1/RouteTableAssociation", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", - "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" - }, - "subnetId": { - "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", - "version": "2.120.0" - } - }, - "DefaultRoute": { - "id": "DefaultRoute", - "path": "RedshiftServerlessStack/VPC/PrivateSubnet1/DefaultRoute", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::EC2::Route", - "aws:cdk:cloudformation:props": { - "destinationCidrBlock": "0.0.0.0/0", - "natGatewayId": { - "Ref": "VPCPublicSubnet1NATGatewayE0556630" - }, - "routeTableId": { - "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", - "version": "2.120.0" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.PrivateSubnet", - "version": "2.120.0" - } - }, - "PrivateSubnet2": { - "id": "PrivateSubnet2", - "path": "RedshiftServerlessStack/VPC/PrivateSubnet2", - "children": { - "Subnet": { - "id": "Subnet", - "path": "RedshiftServerlessStack/VPC/PrivateSubnet2/Subnet", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", - "aws:cdk:cloudformation:props": { - "availabilityZone": "test-region-1b", - "cidrBlock": "10.0.128.0/19", - "mapPublicIpOnLaunch": false, - "tags": [ - { - "key": "aws-cdk:subnet-name", - "value": "Private" - }, - { - "key": "aws-cdk:subnet-type", - "value": "Private" - }, - { - "key": "Name", - "value": "RedshiftServerlessStack/VPC/PrivateSubnet2" - } - ], - "vpcId": { - "Ref": "VPCB9E5F0B4" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", - "version": "2.120.0" - } - }, - "Acl": { - "id": "Acl", - "path": "RedshiftServerlessStack/VPC/PrivateSubnet2/Acl", - "constructInfo": { - "fqn": "aws-cdk-lib.Resource", - "version": "2.120.0" - } - }, - "RouteTable": { - "id": "RouteTable", - "path": "RedshiftServerlessStack/VPC/PrivateSubnet2/RouteTable", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", - "aws:cdk:cloudformation:props": { - "tags": [ - { - "key": "Name", - "value": "RedshiftServerlessStack/VPC/PrivateSubnet2" - } - ], - "vpcId": { - "Ref": "VPCB9E5F0B4" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", - "version": "2.120.0" - } - }, - "RouteTableAssociation": { - "id": "RouteTableAssociation", - "path": "RedshiftServerlessStack/VPC/PrivateSubnet2/RouteTableAssociation", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", - "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" - }, - "subnetId": { - "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", - "version": "2.120.0" - } - }, - "DefaultRoute": { - "id": "DefaultRoute", - "path": "RedshiftServerlessStack/VPC/PrivateSubnet2/DefaultRoute", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::EC2::Route", - "aws:cdk:cloudformation:props": { - "destinationCidrBlock": "0.0.0.0/0", - "natGatewayId": { - "Ref": "VPCPublicSubnet2NATGateway3C070193" - }, - "routeTableId": { - "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", - "version": "2.120.0" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.PrivateSubnet", - "version": "2.120.0" - } - }, - "PrivateSubnet3": { - "id": "PrivateSubnet3", - "path": "RedshiftServerlessStack/VPC/PrivateSubnet3", - "children": { - "Subnet": { - "id": "Subnet", - "path": "RedshiftServerlessStack/VPC/PrivateSubnet3/Subnet", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", - "aws:cdk:cloudformation:props": { - "availabilityZone": "test-region-1c", - "cidrBlock": "10.0.160.0/19", - "mapPublicIpOnLaunch": false, - "tags": [ - { - "key": "aws-cdk:subnet-name", - "value": "Private" - }, - { - "key": "aws-cdk:subnet-type", - "value": "Private" - }, - { - "key": "Name", - "value": "RedshiftServerlessStack/VPC/PrivateSubnet3" - } - ], - "vpcId": { - "Ref": "VPCB9E5F0B4" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", - "version": "2.120.0" - } - }, - "Acl": { - "id": "Acl", - "path": "RedshiftServerlessStack/VPC/PrivateSubnet3/Acl", - "constructInfo": { - "fqn": "aws-cdk-lib.Resource", - "version": "2.120.0" - } - }, - "RouteTable": { - "id": "RouteTable", - "path": "RedshiftServerlessStack/VPC/PrivateSubnet3/RouteTable", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", - "aws:cdk:cloudformation:props": { - "tags": [ - { - "key": "Name", - "value": "RedshiftServerlessStack/VPC/PrivateSubnet3" - } - ], - "vpcId": { - "Ref": "VPCB9E5F0B4" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", - "version": "2.120.0" - } - }, - "RouteTableAssociation": { - "id": "RouteTableAssociation", - "path": "RedshiftServerlessStack/VPC/PrivateSubnet3/RouteTableAssociation", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", - "aws:cdk:cloudformation:props": { - "routeTableId": { - "Ref": "VPCPrivateSubnet3RouteTable192186F8" - }, - "subnetId": { - "Ref": "VPCPrivateSubnet3Subnet3EDCD457" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", - "version": "2.120.0" - } - }, - "DefaultRoute": { - "id": "DefaultRoute", - "path": "RedshiftServerlessStack/VPC/PrivateSubnet3/DefaultRoute", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::EC2::Route", - "aws:cdk:cloudformation:props": { - "destinationCidrBlock": "0.0.0.0/0", - "natGatewayId": { - "Ref": "VPCPublicSubnet3NATGatewayD3048F5C" - }, - "routeTableId": { - "Ref": "VPCPrivateSubnet3RouteTable192186F8" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", - "version": "2.120.0" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.PrivateSubnet", - "version": "2.120.0" - } - }, - "IGW": { - "id": "IGW", - "path": "RedshiftServerlessStack/VPC/IGW", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::EC2::InternetGateway", - "aws:cdk:cloudformation:props": { - "tags": [ - { - "key": "Name", - "value": "RedshiftServerlessStack/VPC" - } - ] - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnInternetGateway", - "version": "2.120.0" - } - }, - "VPCGW": { - "id": "VPCGW", - "path": "RedshiftServerlessStack/VPC/VPCGW", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::EC2::VPCGatewayAttachment", - "aws:cdk:cloudformation:props": { - "internetGatewayId": { - "Ref": "VPCIGWB7E252D3" - }, - "vpcId": { - "Ref": "VPCB9E5F0B4" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnVPCGatewayAttachment", - "version": "2.120.0" - } - }, - "RestrictDefaultSecurityGroupCustomResource": { - "id": "RestrictDefaultSecurityGroupCustomResource", - "path": "RedshiftServerlessStack/VPC/RestrictDefaultSecurityGroupCustomResource", - "children": { - "Default": { - "id": "Default", - "path": "RedshiftServerlessStack/VPC/RestrictDefaultSecurityGroupCustomResource/Default", - "constructInfo": { - "fqn": "aws-cdk-lib.CfnResource", - "version": "2.120.0" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.CustomResource", - "version": "2.120.0" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.Vpc", - "version": "2.120.0" - } - }, - "Custom::VpcRestrictDefaultSGCustomResourceProvider": { - "id": "Custom::VpcRestrictDefaultSGCustomResourceProvider", - "path": "RedshiftServerlessStack/Custom::VpcRestrictDefaultSGCustomResourceProvider", - "children": { - "Staging": { - "id": "Staging", - "path": "RedshiftServerlessStack/Custom::VpcRestrictDefaultSGCustomResourceProvider/Staging", - "constructInfo": { - "fqn": "aws-cdk-lib.AssetStaging", - "version": "2.120.0" - } - }, - "Role": { - "id": "Role", - "path": "RedshiftServerlessStack/Custom::VpcRestrictDefaultSGCustomResourceProvider/Role", - "constructInfo": { - "fqn": "aws-cdk-lib.CfnResource", - "version": "2.120.0" - } - }, - "Handler": { - "id": "Handler", - "path": "RedshiftServerlessStack/Custom::VpcRestrictDefaultSGCustomResourceProvider/Handler", - "constructInfo": { - "fqn": "aws-cdk-lib.CfnResource", - "version": "2.120.0" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.CustomResourceProviderBase", - "version": "2.120.0" - } - }, - "DefaultRole": { - "id": "DefaultRole", - "path": "RedshiftServerlessStack/DefaultRole", - "children": { - "ImportDefaultRole": { - "id": "ImportDefaultRole", - "path": "RedshiftServerlessStack/DefaultRole/ImportDefaultRole", - "constructInfo": { - "fqn": "aws-cdk-lib.Resource", - "version": "2.120.0" - } - }, - "Resource": { - "id": "Resource", - "path": "RedshiftServerlessStack/DefaultRole/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::IAM::Role", - "aws:cdk:cloudformation:props": { - "assumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "redshift.amazonaws.com" - } - } - ], - "Version": "2012-10-17" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_iam.CfnRole", - "version": "2.120.0" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_iam.Role", - "version": "2.120.0" - } - }, - "AnotherRole": { - "id": "AnotherRole", - "path": "RedshiftServerlessStack/AnotherRole", - "children": { - "ImportAnotherRole": { - "id": "ImportAnotherRole", - "path": "RedshiftServerlessStack/AnotherRole/ImportAnotherRole", - "constructInfo": { - "fqn": "aws-cdk-lib.Resource", - "version": "2.120.0" - } - }, - "Resource": { - "id": "Resource", - "path": "RedshiftServerlessStack/AnotherRole/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::IAM::Role", - "aws:cdk:cloudformation:props": { - "assumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "redshift.amazonaws.com" - } - } - ], - "Version": "2012-10-17" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_iam.CfnRole", - "version": "2.120.0" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_iam.Role", - "version": "2.120.0" - } - }, - "Namespace": { - "id": "Namespace", - "path": "RedshiftServerlessStack/Namespace", - "children": { - "Resource": { - "id": "Resource", - "path": "RedshiftServerlessStack/Namespace/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::RedshiftServerless::Namespace", - "aws:cdk:cloudformation:props": { - "adminUsername": "adminuser", - "adminUserPassword": "adminUserPassword123", - "dbName": "mydatabase", - "defaultIamRoleArn": { - "Fn::GetAtt": [ - "DefaultRoleEFEF8FA6", - "Arn" - ] - }, - "iamRoles": [ - { - "Fn::GetAtt": [ - "DefaultRoleEFEF8FA6", - "Arn" - ] - }, - { - "Fn::GetAtt": [ - "AnotherRoleE13C44E8", - "Arn" - ] - } - ], - "logExports": [ - "userlog", - "connectionlog", - "useractivitylog" - ], - "namespaceName": "redshiftserverlessstacknamespace96a02cb7" - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_redshiftserverless.CfnNamespace", - "version": "2.120.0" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.Resource", - "version": "2.120.0" - } - }, - "WorkGroup": { - "id": "WorkGroup", - "path": "RedshiftServerlessStack/WorkGroup", - "children": { - "SecurityGroup": { - "id": "SecurityGroup", - "path": "RedshiftServerlessStack/WorkGroup/SecurityGroup", - "children": { - "Resource": { - "id": "Resource", - "path": "RedshiftServerlessStack/WorkGroup/SecurityGroup/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::EC2::SecurityGroup", - "aws:cdk:cloudformation:props": { - "groupDescription": "Automatic generated security group for Redshift Serverless Security Group", - "securityGroupEgress": [ - { - "cidrIp": "0.0.0.0/0", - "description": "Allow all outbound traffic by default", - "ipProtocol": "-1" - } - ], - "vpcId": { - "Ref": "VPCB9E5F0B4" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.CfnSecurityGroup", - "version": "2.120.0" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_ec2.SecurityGroup", - "version": "2.120.0" - } - }, - "Resource": { - "id": "Resource", - "path": "RedshiftServerlessStack/WorkGroup/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::RedshiftServerless::Workgroup", - "aws:cdk:cloudformation:props": { - "enhancedVpcRouting": true, - "namespaceName": { - "Fn::GetAtt": [ - "Namespace9B63B8C8", - "Namespace.NamespaceName" - ] - }, - "port": 5432, - "publiclyAccessible": true, - "securityGroupIds": [ - { - "Fn::GetAtt": [ - "WorkGroupSecurityGroup82E81D37", - "GroupId" - ] - } - ], - "subnetIds": [ - { - "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" - }, - { - "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" - }, - { - "Ref": "VPCPrivateSubnet3Subnet3EDCD457" - } - ], - "workgroupName": "redshiftserverlessstackworkgroupcfbe5e7c" - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_redshiftserverless.CfnWorkgroup", - "version": "2.120.0" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.Resource", - "version": "2.120.0" - } - }, - "endpointAddress": { - "id": "endpointAddress", - "path": "RedshiftServerlessStack/endpointAddress", - "constructInfo": { - "fqn": "aws-cdk-lib.CfnOutput", - "version": "2.120.0" - } - }, - "BootstrapVersion": { - "id": "BootstrapVersion", - "path": "RedshiftServerlessStack/BootstrapVersion", - "constructInfo": { - "fqn": "aws-cdk-lib.CfnParameter", - "version": "2.120.0" - } - }, - "CheckBootstrapVersion": { - "id": "CheckBootstrapVersion", - "path": "RedshiftServerlessStack/CheckBootstrapVersion", - "constructInfo": { - "fqn": "aws-cdk-lib.CfnRule", - "version": "2.120.0" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.Stack", - "version": "2.120.0" - } - }, - "RedshiftServerless": { - "id": "RedshiftServerless", - "path": "RedshiftServerless", - "children": { - "DefaultTest": { - "id": "DefaultTest", - "path": "RedshiftServerless/DefaultTest", - "children": { - "Default": { - "id": "Default", - "path": "RedshiftServerless/DefaultTest/Default", - "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" - } - }, - "DeployAssert": { - "id": "DeployAssert", - "path": "RedshiftServerless/DefaultTest/DeployAssert", - "children": { - "BootstrapVersion": { - "id": "BootstrapVersion", - "path": "RedshiftServerless/DefaultTest/DeployAssert/BootstrapVersion", - "constructInfo": { - "fqn": "aws-cdk-lib.CfnParameter", - "version": "2.120.0" - } - }, - "CheckBootstrapVersion": { - "id": "CheckBootstrapVersion", - "path": "RedshiftServerless/DefaultTest/DeployAssert/CheckBootstrapVersion", - "constructInfo": { - "fqn": "aws-cdk-lib.CfnRule", - "version": "2.120.0" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.Stack", - "version": "2.120.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/integ-tests-alpha.IntegTestCase", - "version": "2.120.0-alpha.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/integ-tests-alpha.IntegTest", - "version": "2.120.0-alpha.0" - } - }, - "Tree": { - "id": "Tree", - "path": "Tree", - "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.3.0" - } - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.App", - "version": "2.120.0" - } - } -} \ No newline at end of file diff --git a/test/aws-redshiftserverless/namespace.test.ts b/test/aws-redshiftserverless/namespace.test.ts index a461ffe..e1d92aa 100644 --- a/test/aws-redshiftserverless/namespace.test.ts +++ b/test/aws-redshiftserverless/namespace.test.ts @@ -1,6 +1,8 @@ -import { App, Stack } from 'aws-cdk-lib'; +import { App, SecretValue, Stack } from 'aws-cdk-lib'; import { Match, Template } from 'aws-cdk-lib/assertions'; -import { Namespace } from '../../src/aws-redshiftserverless'; +import { LogExport, Namespace } from '../../src/aws-redshiftserverless'; +import { Role, ServicePrincipal } from 'aws-cdk-lib/aws-iam'; +import { Key } from 'aws-cdk-lib/aws-kms'; describe('Redshift Serverless Namespace', () => { let app: App; @@ -19,5 +21,151 @@ describe('Redshift Serverless Namespace', () => { }); }); - // WIP: add more tests + test('Create namsepace with max properties ', () => { + const defaultIamRole = new Role(stack, 'DefaultRole', { + assumedBy: new ServicePrincipal('redshift.amazonaws.com'), + }); + + const anotherRole = new Role(stack, 'AnotherRole', { + assumedBy: new ServicePrincipal('redshift.amazonaws.com'), + }); + + const kmsKey = new Key(stack, 'CMK'); + + new Namespace(stack, 'Namespace', { + adminUsername: 'my-admin', + adminUserPassword: SecretValue.unsafePlainText('My-password-123!'), + dbName: 'my-database', + defaultIamRole, + finalSnapshotName: 'my-final-snapshot', + finalSnapshotRetentionPeriod: 7, + iamRoles: [defaultIamRole, anotherRole], + logExports: [LogExport.USER_LOG, LogExport.CONNECTION_LOG, LogExport.USER_ACTIVITY_LOG], + kmsKey, + namespaceName: 'my-namespace', + }); + + Template.fromStack(stack).hasResourceProperties('AWS::RedshiftServerless::Namespace', { + AdminUsername: 'my-admin', + AdminUserPassword: 'My-password-123!', + DbName: 'my-database', + DefaultIamRoleArn: stack.resolve(defaultIamRole.roleArn), + FinalSnapshotName: 'my-final-snapshot', + FinalSnapshotRetentionPeriod: 7, + IamRoles: [stack.resolve(defaultIamRole.roleArn), stack.resolve(anotherRole.roleArn)], + KmsKeyId: stack.resolve(kmsKey.keyId), + LogExports: ['userlog', 'connectionlog', 'useractivitylog'], + NamespaceName: 'my-namespace', + }); + }); + + describe('test import method', () => { + test('import from namespaceId', () => { + const existingNamespace = Namespace.fromNamespaceAttributes(stack, 'ImportedNamespace', { + namespaceId: 'my-namespace-id', + namespaceName: 'my-namespace-name' + }); + + expect(existingNamespace.namespaceId).toEqual('my-namespace-id'); + expect(existingNamespace.namespaceArn).toEqual(Stack.of(stack).formatArn({ + resource: 'redshift-serverless', + service: 'namespace', + resourceName: 'my-namespace-id', + })); + }); + + }) + + describe('validateAdmin test', () => { + test('throws when adminUsername is set without adminUserPassword', () => { + expect(() => { + new Namespace(stack, 'Namespace', { + adminUsername: 'my-admin' + }); + }).toThrow('You must specify both `adminUsername` and `adminUserPassword`, or neither.'); + }); + + test('throws when adminUserPassword is set without adminUsername', () => { + expect(() => { + new Namespace(stack, 'Namespace', { + adminUserPassword: SecretValue.unsafePlainText('My-password-123!'), + }); + }).toThrow('You must specify both `adminUsername` and `adminUserPassword`, or neither.'); + }); + + test.each(['123abc', 'invalid$name'])('throws when adminUsername is invalid, got %s', (adminUsername) => { + expect(() => { + new Namespace(stack, 'Namespace', { + adminUsername, + adminUserPassword: SecretValue.unsafePlainText('My-password-123!'), + }); + }).toThrow(`\`adminUsername\` must start with a letter and can only contain letters, numbers, and the special characters: _, +, ., @, -, got: ${adminUsername}.`); + }); + }) + + describe('validateDbName test', () => { + test.each(['123abc', 'invalid$name'])('throws when dbName is invalid, got %s', (dbName) => { + expect(() => { + new Namespace(stack, 'Namespace', { + dbName, + }); + }).toThrow(`\`dbName\` must start with a letter, can only contain letters, numbers, and the special characters: _, +, ., @, -, and must not exceed 127 characters, got: ${dbName}.`); + }); + }) + + describe('validateFinalSnapshot test', () => { + test.each(['123abc', 'UpperName', 'invalid$name', 'end-with-a-hyphen-', 'two--consecutive-hyphens', 'a'.repeat(256)])('throws when finalSnapshotName is invalid, got %s', (finalSnapshotName) => { + expect(() => { + new Namespace(stack, 'Namespace', { + finalSnapshotName, + }); + }).toThrow(`\`finalSnapshotName\` must be between 1 and 255 and consist only of lowercase alphanumeric characters or hyphens, with the first character as a letter, and it can't end with a hyphen or contain two consecutive hyphens, got: ${finalSnapshotName}.`); + }); + + test('throws when finalSnapshotRetentionPeriod is set without finalSnapshotName', () => { + expect(() => { + new Namespace(stack, 'Namespace', { + finalSnapshotRetentionPeriod: 10, + }); + }).toThrow('You must set \`finalSnapshotName`\ when you specify \`finalSnapshotRetentionPeriod\`.'); + }); + + test.each([0, 3654])('throws when finalSnapshotRetentionPeriod is invalid, got %d', (finalSnapshotRetentionPeriod) => { + expect(() => { + new Namespace(stack, 'Namespace', { + finalSnapshotName: 'my-final-snapshot', + finalSnapshotRetentionPeriod, + }); + }).toThrow(`\`finalSnapshotRetentionPeriod\` must be 1-3653, got: ${finalSnapshotRetentionPeriod}.`); + }); + }) + + describe('validateDefaultIamRole test', () => { + test('throws when defaultIamRole role is not included in iamRoles', () => { + expect(() => { + const defaultIamRole = new Role(stack, 'DefaultRole', { + assumedBy: new ServicePrincipal('redshift.amazonaws.com'), + }); + + const anotherRole = new Role(stack, 'AnotherRole', { + assumedBy: new ServicePrincipal('redshift.amazonaws.com'), + }); + + new Namespace(stack, 'Namespace', { + defaultIamRole, + iamRoles: [anotherRole], + }); + }).toThrow('\`defaultIamRole\` must be included in \`iamRoles\`.'); + }); + }) + + describe('validateNamespaceName test', () => { + test.each(['UpperName', 'invalid$name', 'a'.repeat(2), 'a'.repeat(65)])('throws when namespaceName is invalid, got %s', (namespaceName) => { + expect(() => { + new Namespace(stack, 'Namespace', { + namespaceName, + }); + }).toThrow(`\`namespaceName\` must be between 3 and 64 characters and consist only of lowercase alphanumeric characters or hyphens, got: ${namespaceName}.`); + }); + }) }); \ No newline at end of file From f2200799b747d55f48918bae272fdd8a743f13dd Mon Sep 17 00:00:00 2001 From: maz Date: Thu, 12 Sep 2024 14:42:51 +0900 Subject: [PATCH 03/29] fix --- src/aws-redshiftserverless/namespace.ts | 10 +++++----- test/aws-redshiftserverless/namespace.test.ts | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/aws-redshiftserverless/namespace.ts b/src/aws-redshiftserverless/namespace.ts index f91e07c..6cf914b 100644 --- a/src/aws-redshiftserverless/namespace.ts +++ b/src/aws-redshiftserverless/namespace.ts @@ -241,7 +241,7 @@ export class Namespace extends Resource implements INamespace { !/^[a-zA-Z][a-zA-Z_0-9+.@-]*$/.test(adminUsername) ) { throw new Error( - `\`adminUsername\` must start with a letter and can only contain letters, numbers, and the special characters: _, +, ., @, -, got: ${this.props.adminUsername}.` + `\`adminUsername\` must start with a letter and can only contain letters, numbers, and the special characters: _, +, ., @, -, got: ${adminUsername}.` ); } } @@ -256,7 +256,7 @@ export class Namespace extends Resource implements INamespace { if (!/^[a-zA-Z][a-zA-Z_0-9+.@-]*$/.test(dbName) || dbName.length > 127) { throw new Error( - `\`dbName\` must start with a letter, can only contain letters, numbers, and the special characters: _, +, ., @, -, and must not exceed 127 characters, got: ${this.props.dbName}.` + `\`dbName\` must start with a letter, can only contain letters, numbers, and the special characters: _, +, ., @, -, and must not exceed 127 characters, got: ${dbName}.` ); } } @@ -272,7 +272,7 @@ export class Namespace extends Resource implements INamespace { if (finalSnapshotName) { if (!/^[a-z][a-z0-9]*(-[a-z0-9]+)*$/.test(finalSnapshotName) || finalSnapshotName.length > 255) { - throw new Error(`\`finalSnapshotName\` must be between 1 and 255 and consist only of lowercase alphanumeric characters or hyphens, with the first character as a letter, and it can't end with a hyphen or contain two consecutive hyphens, got: ${finalSnapshotName}.`); + throw new Error(`\`finalSnapshotName\` must be between 1 and 255, consist only of lowercase alphanumeric characters or hyphens, with the first character as a letter, and it can't end with a hyphen or contain two consecutive hyphens, got: ${finalSnapshotName}.`); } } @@ -284,7 +284,7 @@ export class Namespace extends Resource implements INamespace { if (finalSnapshotRetentionPeriod < 1 || finalSnapshotRetentionPeriod > 3653) { { - throw new Error(`\`finalSnapshotRetentionPeriod\` must be 1-3653, got: ${finalSnapshotRetentionPeriod}.`); + throw new Error(`\`finalSnapshotRetentionPeriod\` must be between 1 and 3653, got: ${finalSnapshotRetentionPeriod}.`); } } } @@ -313,7 +313,7 @@ export class Namespace extends Resource implements INamespace { if (!/^[a-z0-9-]+$/.test(namespaceName) || namespaceName.length < 3 || namespaceName.length > 64) { throw new Error( - `\`namespaceName\` must be between 3 and 64 characters and consist only of lowercase alphanumeric characters or hyphens, got: ${namespaceName}.` + `\`namespaceName\` must be between 3 and 64 characters, consist only of lowercase alphanumeric characters or hyphens, got: ${namespaceName}.` ); } } diff --git a/test/aws-redshiftserverless/namespace.test.ts b/test/aws-redshiftserverless/namespace.test.ts index e1d92aa..cf537e6 100644 --- a/test/aws-redshiftserverless/namespace.test.ts +++ b/test/aws-redshiftserverless/namespace.test.ts @@ -119,7 +119,7 @@ describe('Redshift Serverless Namespace', () => { new Namespace(stack, 'Namespace', { finalSnapshotName, }); - }).toThrow(`\`finalSnapshotName\` must be between 1 and 255 and consist only of lowercase alphanumeric characters or hyphens, with the first character as a letter, and it can't end with a hyphen or contain two consecutive hyphens, got: ${finalSnapshotName}.`); + }).toThrow(`\`finalSnapshotName\` must be between 1 and 255, consist only of lowercase alphanumeric characters or hyphens, with the first character as a letter, and it can't end with a hyphen or contain two consecutive hyphens, got: ${finalSnapshotName}.`); }); test('throws when finalSnapshotRetentionPeriod is set without finalSnapshotName', () => { @@ -136,7 +136,7 @@ describe('Redshift Serverless Namespace', () => { finalSnapshotName: 'my-final-snapshot', finalSnapshotRetentionPeriod, }); - }).toThrow(`\`finalSnapshotRetentionPeriod\` must be 1-3653, got: ${finalSnapshotRetentionPeriod}.`); + }).toThrow(`\`finalSnapshotRetentionPeriod\` must be between 1 and 3653, got: ${finalSnapshotRetentionPeriod}.`); }); }) @@ -165,7 +165,7 @@ describe('Redshift Serverless Namespace', () => { new Namespace(stack, 'Namespace', { namespaceName, }); - }).toThrow(`\`namespaceName\` must be between 3 and 64 characters and consist only of lowercase alphanumeric characters or hyphens, got: ${namespaceName}.`); + }).toThrow(`\`namespaceName\` must be between 3 and 64 characters, consist only of lowercase alphanumeric characters or hyphens, got: ${namespaceName}.`); }); }) }); \ No newline at end of file From bb9e92843bae2df83beecce4785160fe8deafa19 Mon Sep 17 00:00:00 2001 From: maz Date: Thu, 12 Sep 2024 14:58:32 +0900 Subject: [PATCH 04/29] add validation for workgroup --- src/aws-redshiftserverless/workgroup.ts | 97 ++++++++++++++- test/aws-redshiftserverless/namespace.test.ts | 3 +- test/aws-redshiftserverless/workgroup.test.ts | 115 +++++++++++++++++- 3 files changed, 204 insertions(+), 11 deletions(-) diff --git a/src/aws-redshiftserverless/workgroup.ts b/src/aws-redshiftserverless/workgroup.ts index ed961fb..88fed96 100644 --- a/src/aws-redshiftserverless/workgroup.ts +++ b/src/aws-redshiftserverless/workgroup.ts @@ -1,4 +1,4 @@ -import { IResource, Lazy, Names, Resource, aws_redshiftserverless, aws_ec2 } from 'aws-cdk-lib'; +import { IResource, Lazy, Names, Resource, aws_redshiftserverless, aws_ec2, Token, Stack } from 'aws-cdk-lib'; import { Construct } from 'constructs'; import { INamespace } from './namespace'; @@ -18,6 +18,12 @@ export interface IWorkgroup extends IResource, aws_ec2.IConnectable { * @attribute */ readonly workgroupName: string; + /** + * The workgroup id + * + * @attribute + */ + readonly workgroupId: string; /** * The workgroup endpoint address * @@ -111,14 +117,14 @@ export interface WorkgroupProps { * Attributes for importing a Redshift Serverless Workgroup. */ export interface WorkgroupAttributes { - /** - * The workgroup Arn - */ - readonly workgroupArn: string; /** * The workgroup name */ readonly workgroupName: string; + /** + * The workgroup id + */ + readonly workgroupId: string; /** * The workgroup endpoint address */ @@ -161,14 +167,19 @@ export class Workgroup extends Resource implements IWorkgroup { attrs: WorkgroupAttributes, ): IWorkgroup { class Import extends Resource implements IWorkgroup { - public readonly workgroupArn = attrs.workgroupArn; public readonly workgroupName = attrs.workgroupName; + public readonly workgroupId = attrs.workgroupId; public readonly endpointAddress = attrs.endpointAddress; public readonly port = attrs.port; public readonly connections = new aws_ec2.Connections({ securityGroups: attrs.securityGroups, defaultPort: aws_ec2.Port.tcp(attrs.port), }); + public readonly workgroupArn = Stack.of(this).formatArn({ + resource: 'redshift-serverless', + service: 'workgroup', + resourceName: attrs.workgroupId, + }); } return new Import(scope, id); @@ -178,11 +189,17 @@ export class Workgroup extends Resource implements IWorkgroup { * The workgroup Arn */ readonly workgroupArn: string; + /** * The workgroup name */ readonly workgroupName: string; + /** + * The workgroup id + */ + readonly workgroupId: string; + /** * The workgroup endpoint address */ @@ -218,10 +235,16 @@ export class Workgroup extends Resource implements IWorkgroup { subnetType: aws_ec2.SubnetType.PRIVATE_WITH_EGRESS, }; + this.validateCapacity(); + this.validateWorkgroupName(); + this.validatePort(); + this.validateSubnet(); + const workgroup = this.createWorkgroup(); this.workgroupArn = workgroup.attrWorkgroupWorkgroupArn; this.workgroupName = workgroup.attrWorkgroupWorkgroupName; + this.workgroupId = workgroup.attrWorkgroupWorkgroupId; this.endpointAddress = workgroup.attrWorkgroupEndpointAddress; this.port = workgroup.attrWorkgroupEndpointPort; } @@ -257,4 +280,66 @@ export class Workgroup extends Resource implements IWorkgroup { securityGroups: this.securityGroups, }); } + + /** + * Validates capacity settings. + */ + private validateCapacity(): void { + const baseCapacity = this.props.baseCapacity; + + + if (!Token.isUnresolved(baseCapacity) && baseCapacity !== undefined) { + if (baseCapacity < 8 || baseCapacity > 512 || baseCapacity % 8 !== 0) { + throw new Error(`\`baseCapacity\` must be between 8 and 512 in units of 8, got: ${baseCapacity}.`); + } + } + } + + /** + * Validates a workgroup name. + */ + private validateWorkgroupName(): void { + const workgroupName = this.props.workgroupName; + if (Token.isUnresolved(workgroupName) || workgroupName === undefined) { return; } + + if (!/^[a-z0-9-]{3,64}$/.test(workgroupName)) { + throw new Error( + `\`workgroupName\` must be between 3 and 64 characters long, contain only lowercase letters, numbers, and hyphens, got: ${workgroupName}.` + ); + } + } + + /** + * Validates a port number. + * + * @see https://docs.aws.amazon.com/redshift/latest/mgmt/serverless-connecting.html + */ + private validatePort(): void { + const port = this.props.port; + if (!Token.isUnresolved(port) && port !== undefined) { + + const isValidPort = ( + (port >= 5431 && port <= 5455) || + (port >= 8191 && port <= 8215) + ); + + if (!isValidPort) { + throw new Error( + `\`port\` must be in the range of 5431-5455 or 8191-8215 for Amazon Redshift Serverless, got: ${port}.` + ); + } + } + } + + /** + * Validates subnets. + * + * @see https://docs.aws.amazon.com/redshift/latest/mgmt/serverless-usage-considerations.html + */ + private validateSubnet(): void { + + if (this.props.vpc.availabilityZones.length < 3) { + throw new Error('\`vpc` must have at least three subnets, and they must span across three Availability Zones.'); + } + } } diff --git a/test/aws-redshiftserverless/namespace.test.ts b/test/aws-redshiftserverless/namespace.test.ts index cf537e6..01b41bc 100644 --- a/test/aws-redshiftserverless/namespace.test.ts +++ b/test/aws-redshiftserverless/namespace.test.ts @@ -21,7 +21,7 @@ describe('Redshift Serverless Namespace', () => { }); }); - test('Create namsepace with max properties ', () => { + test('Create namsepace with maximum properties ', () => { const defaultIamRole = new Role(stack, 'DefaultRole', { assumedBy: new ServicePrincipal('redshift.amazonaws.com'), }); @@ -73,7 +73,6 @@ describe('Redshift Serverless Namespace', () => { resourceName: 'my-namespace-id', })); }); - }) describe('validateAdmin test', () => { diff --git a/test/aws-redshiftserverless/workgroup.test.ts b/test/aws-redshiftserverless/workgroup.test.ts index a8f96a4..2768fff 100644 --- a/test/aws-redshiftserverless/workgroup.test.ts +++ b/test/aws-redshiftserverless/workgroup.test.ts @@ -1,6 +1,6 @@ import { App, Stack, aws_ec2 } from 'aws-cdk-lib'; import { Template } from 'aws-cdk-lib/assertions'; -import { Workgroup } from '../../src/aws-redshiftserverless'; +import { Namespace, Workgroup } from '../../src/aws-redshiftserverless'; describe('Redshift Serverless Workgroup', () => { let app: App; @@ -12,7 +12,7 @@ describe('Redshift Serverless Workgroup', () => { stack = new Stack(app, 'TestStack', { env: { account: '012345678901', region: 'us-east-1' }, }); - vpc = new aws_ec2.Vpc(stack, 'VPC'); + vpc = new aws_ec2.Vpc(stack, 'VPC',); }); test('Create namsepace with minimal properties ', () => { @@ -35,5 +35,114 @@ describe('Redshift Serverless Workgroup', () => { }); }); - // WIP: add more tests + test('Create namsepace with maximum properties ', () => { + const namespace = new Namespace(stack, 'Namespace', {}); + const securityGroup = aws_ec2.SecurityGroup.fromSecurityGroupId(stack, 'SG', 'sg-123456789'); + + new Workgroup(stack, 'Workgroup', { + baseCapacity: 8, + configParameters: { + aaa: 'aaa', + }, + enhancedVpcRouting: true, + namespace, + port: 5440, + publiclyAccessible: true, + securityGroups: [securityGroup], + vpc, + vpcSubnets: { + subnetType: aws_ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + workgroupName: 'my-workgroup', + }); + + Template.fromStack(stack).hasResourceProperties('AWS::RedshiftServerless::Workgroup', { + SecurityGroupIds: [stack.resolve(securityGroup.securityGroupId)], + SubnetIds: [ + { Ref: 'VPCPrivateSubnet1Subnet8BCA10E0' }, + { Ref: 'VPCPrivateSubnet2SubnetCFCDAA7A' }, + { Ref: 'VPCPrivateSubnet3Subnet3EDCD457' }, + ], + }); + }); + + describe('import method', () => { + test('imports Workgroup correctly', () => { + + const securityGroup = aws_ec2.SecurityGroup.fromSecurityGroupId(stack, 'SG', 'sg-123456789') + const importedWorkgroup = Workgroup.fromWorkgroupAttributes(stack, 'ImportedWorkgroup', { + workgroupName: 'my-workgroup', + workgroupId: 'my-workgroup-id', + endpointAddress: 'my-workgroup.endpoint.com', + port: 5439, + securityGroups: [securityGroup], + }); + + expect(importedWorkgroup.workgroupName).toEqual('my-workgroup'); + + expect(importedWorkgroup.workgroupId).toEqual('my-workgroup-id'); + + expect(importedWorkgroup.endpointAddress).toEqual('my-workgroup.endpoint.com'); + + expect(importedWorkgroup.port).toEqual(5439); + + expect(importedWorkgroup.workgroupName).toEqual('my-workgroup'); + + expect(importedWorkgroup.workgroupArn).toEqual(Stack.of(stack).formatArn({ + resource: 'redshift-serverless', + service: 'workgroup', + resourceName: 'my-workgroup-id', + })); + + expect(importedWorkgroup.connections.securityGroups).toEqual([securityGroup]); + }); + }); + + describe('validateCapacity test', () => { + test.each([0, 520, 15])('throws when baseCapacity is invalid, got %d', (baseCapacity) => { + expect(() => { + new Workgroup(stack, 'Workgroup', { + baseCapacity, + vpc, + }); + }).toThrow(`\`baseCapacity\` must be between 8 and 512 in units of 8, got: ${baseCapacity}.`); + }); + }); + + describe('validateWorkgroupName test', () => { + test.each(['ABC', 'name with spaces', 'a'.repeat(2), 'a'.repeat(100),]) + ('throws when workgroupName is invalid, got %s', (workgroupName) => { + expect(() => { + new Workgroup(stack, 'Workgroup', { + workgroupName, + vpc, + }); + }).toThrow(`\`workgroupName\` must be between 3 and 64 characters long, contain only lowercase letters, numbers, and hyphens, got: ${workgroupName}.`); + }); + }); + + describe('validatePort test', () => { + test.each([5430, 5456, 8190, 8216])('throws when port is invalid, got %d', (port) => { + expect(() => { + new Workgroup(stack, 'Workgroup', { + port, + vpc, + }); + }).toThrow(`\`port\` must be in the range of 5431-5455 or 8191-8215 for Amazon Redshift Serverless, got: ${port}.`); + }); + }); + + describe('validateSubnet test', () => { + test('throws when vpc has only 2 AZs', () => { + const vpcFor2Az = new aws_ec2.Vpc(stack, 'VPCfor2Az', { + maxAzs: 2, + }); + + expect(() => { + new Workgroup(stack, 'Workgroup', { + vpc: vpcFor2Az, + }); + }).toThrow('\`vpc` must have at least three subnets, and they must span across three Availability Zones.'); + }); + }); }); \ No newline at end of file From 87c01f9c460196657195ea091a53b1a71a00590d Mon Sep 17 00:00:00 2001 From: maz Date: Thu, 12 Sep 2024 17:02:35 +0900 Subject: [PATCH 05/29] lint --- API.md | 86 ++++++++++++--- src/aws-redshiftserverless/index.ts | 2 +- src/aws-redshiftserverless/namespace.ts | 58 +++++----- src/aws-redshiftserverless/workgroup.ts | 41 +++---- src/index.ts | 2 +- test/aws-redshiftserverless/namespace.test.ts | 101 +++++++++++------- test/aws-redshiftserverless/workgroup.test.ts | 52 +++++---- 7 files changed, 212 insertions(+), 130 deletions(-) diff --git a/API.md b/API.md index a1407f3..8771c84 100644 --- a/API.md +++ b/API.md @@ -523,7 +523,7 @@ account for data recovery and cleanup later (`RemovalPolicy.RETAIN`). | isConstruct | Checks if `x` is a construct. | | isOwnedResource | Returns true if the construct was created by CDK, and false otherwise. | | isResource | Check whether the given construct is a Resource. | -| fromNamespaceAttributes | Import an existing namspace to the stack from its attributes. | +| fromNamespaceAttributes | Imports an existing Namespace from attributes. | --- @@ -599,7 +599,7 @@ import { aws_redshiftserverless } from '@open-constructs/aws-cdk' aws_redshiftserverless.Namespace.fromNamespaceAttributes(scope: Construct, id: string, attrs: NamespaceAttributes) ``` -Import an existing namspace to the stack from its attributes. +Imports an existing Namespace from attributes. ###### `scope`Required @@ -627,6 +627,7 @@ Import an existing namspace to the stack from its attributes. | env | aws-cdk-lib.ResourceEnvironment | The environment this resource belongs to. | | stack | aws-cdk-lib.Stack | The stack in which this resource is defined. | | namespaceArn | string | The namespace Arn. | +| namespaceId | string | The namespace id. | | namespaceName | string | The namespace name. | --- @@ -686,6 +687,18 @@ The namespace Arn. --- +##### `namespaceId`Required + +```typescript +public readonly namespaceId: string; +``` + +- *Type:* string + +The namespace id. + +--- + ##### `namespaceName`Required ```typescript @@ -906,10 +919,11 @@ Import an existing workgroup to the stack from its attributes. | node | constructs.Node | The tree node. | | env | aws-cdk-lib.ResourceEnvironment | The environment this resource belongs to. | | stack | aws-cdk-lib.Stack | The stack in which this resource is defined. | -| connections | aws-cdk-lib.aws_ec2.Connections | The connection object associated with the EC2 Instance Connect Endpoint. | +| connections | aws-cdk-lib.aws_ec2.Connections | The connection object associated with the Redshift Serverless Workgroup. | | endpointAddress | string | The workgroup endpoint address. | | port | number | The workgroup port. | | workgroupArn | string | The workgroup Arn. | +| workgroupId | string | The workgroup id. | | workgroupName | string | The workgroup name. | --- @@ -965,7 +979,7 @@ public readonly connections: Connections; - *Type:* aws-cdk-lib.aws_ec2.Connections -The connection object associated with the EC2 Instance Connect Endpoint. +The connection object associated with the Redshift Serverless Workgroup. --- @@ -1005,6 +1019,18 @@ The workgroup Arn. --- +##### `workgroupId`Required + +```typescript +public readonly workgroupId: string; +``` + +- *Type:* string + +The workgroup id. + +--- + ##### `workgroupName`Required ```typescript @@ -1235,20 +1261,20 @@ const namespaceAttributes: aws_redshiftserverless.NamespaceAttributes = { ... } | **Name** | **Type** | **Description** | | --- | --- | --- | -| namespaceArn | string | The namespace Arn. | +| namespaceId | string | The namespace id. | | namespaceName | string | The namespace name. | --- -##### `namespaceArn`Required +##### `namespaceId`Required ```typescript -public readonly namespaceArn: string; +public readonly namespaceId: string; ``` - *Type:* string -The namespace Arn. +The namespace id. --- @@ -1285,7 +1311,7 @@ const namespaceProps: aws_redshiftserverless.NamespaceProps = { ... } | dbName | string | The name of the primary database created in the namespace. | | defaultIamRole | aws-cdk-lib.aws_iam.IRole | The IAM role to set as a default in the namespace. | | finalSnapshotName | string | The name of the snapshot to be created before the namespace is deleted. | -| finalSnapshotRetentionPeriod | number | How long to retain the final snapshot. | +| finalSnapshotRetentionPeriod | number | How long days to retain the final snapshot. | | iamRoles | aws-cdk-lib.aws_iam.IRole[] | A list of IAM roles to associate with the namespace. | | kmsKey | aws-cdk-lib.aws_kms.IKey | A Customer Managed Key used to encrypt your data. | | logExports | @open-constructs/aws-cdk.aws_redshiftserverless.LogExport[] | The types of logs the namespace can export. | @@ -1367,7 +1393,7 @@ public readonly finalSnapshotRetentionPeriod: number; - *Type:* number - *Default:* Retained indefinitely if finalSnapshotName is specified, otherwise no final snapshot -How long to retain the final snapshot. +How long days to retain the final snapshot. --- @@ -1441,7 +1467,7 @@ const workgroupAttributes: aws_redshiftserverless.WorkgroupAttributes = { ... } | endpointAddress | string | The workgroup endpoint address. | | port | number | The workgroup port. | | securityGroups | aws-cdk-lib.aws_ec2.ISecurityGroup[] | The security groups associated with the Redshift Serverless Workgroup. | -| workgroupArn | string | The workgroup Arn. | +| workgroupId | string | The workgroup id. | | workgroupName | string | The workgroup name. | --- @@ -1482,15 +1508,15 @@ The security groups associated with the Redshift Serverless Workgroup. --- -##### `workgroupArn`Required +##### `workgroupId`Required ```typescript -public readonly workgroupArn: string; +public readonly workgroupId: string; ``` - *Type:* string -The workgroup Arn. +The workgroup id. --- @@ -1554,7 +1580,7 @@ public readonly baseCapacity: number; ``` - *Type:* number -- *Default:* 8 +- *Default:* 128 The base compute capacity of the workgroup in Redshift Processing Units (RPUs). @@ -2019,7 +2045,8 @@ A Redshift Serverless Namespace. | node | constructs.Node | The tree node. | | env | aws-cdk-lib.ResourceEnvironment | The environment this resource belongs to. | | stack | aws-cdk-lib.Stack | The stack in which this resource is defined. | -| namespaceArn | string | The namespace Arn. | +| namespaceArn | string | The namespace ARN. | +| namespaceId | string | The namespace id. | | namespaceName | string | The namespace name. | --- @@ -2075,7 +2102,19 @@ public readonly namespaceArn: string; - *Type:* string -The namespace Arn. +The namespace ARN. + +--- + +##### `namespaceId`Required + +```typescript +public readonly namespaceId: string; +``` + +- *Type:* string + +The namespace id. --- @@ -2111,6 +2150,7 @@ A Redshift Serverless Workgroup. | endpointAddress | string | The workgroup endpoint address. | | port | number | The workgroup port. | | workgroupArn | string | The workgroup Arn. | +| workgroupId | string | The workgroup id. | | workgroupName | string | The workgroup name. | --- @@ -2206,6 +2246,18 @@ The workgroup Arn. --- +##### `workgroupId`Required + +```typescript +public readonly workgroupId: string; +``` + +- *Type:* string + +The workgroup id. + +--- + ##### `workgroupName`Required ```typescript diff --git a/src/aws-redshiftserverless/index.ts b/src/aws-redshiftserverless/index.ts index f2c6b65..de441c6 100644 --- a/src/aws-redshiftserverless/index.ts +++ b/src/aws-redshiftserverless/index.ts @@ -1,2 +1,2 @@ export * from './namespace'; -export * from './workgroup'; \ No newline at end of file +export * from './workgroup'; diff --git a/src/aws-redshiftserverless/namespace.ts b/src/aws-redshiftserverless/namespace.ts index 6cf914b..cce68ce 100644 --- a/src/aws-redshiftserverless/namespace.ts +++ b/src/aws-redshiftserverless/namespace.ts @@ -119,7 +119,7 @@ export enum LogExport { /** * User activity log */ - USER_ACTIVITY_LOG = 'useractivitylog' + USER_ACTIVITY_LOG = 'useractivitylog', } /** @@ -134,7 +134,6 @@ export interface NamespaceAttributes { * The namespace id */ readonly namespaceId: string; - } /** @@ -151,12 +150,10 @@ export interface NamespaceAttributes { * ); */ export class Namespace extends Resource implements INamespace { - /** * Imports an existing Namespace from attributes */ public static fromNamespaceAttributes(scope: Construct, id: string, attrs: NamespaceAttributes): INamespace { - class Import extends Resource implements INamespace { public readonly namespaceName = attrs.namespaceName; public readonly namespaceId = attrs.namespaceId; @@ -187,9 +184,11 @@ export class Namespace extends Resource implements INamespace { constructor(scope: Construct, id: string, props: NamespaceProps) { super(scope, id, { - physicalName: props.namespaceName ?? Lazy.string({ - produce: () => Names.uniqueResourceName(this, { maxLength: 64, allowedSpecialCharacters: '-' }).toLowerCase(), - }), + physicalName: + props.namespaceName ?? + Lazy.string({ + produce: () => Names.uniqueResourceName(this, { maxLength: 64, allowedSpecialCharacters: '-' }).toLowerCase(), + }), }); this.props = props; @@ -204,7 +203,6 @@ export class Namespace extends Resource implements INamespace { this.namespaceArn = namespace.attrNamespaceNamespaceArn; this.namespaceName = namespace.attrNamespaceNamespaceName; this.namespaceId = namespace.attrNamespaceNamespaceId; - } protected createNamespace(): aws_redshiftserverless.CfnNamespace { @@ -229,19 +227,20 @@ export class Namespace extends Resource implements INamespace { const adminUsername = this.props.adminUsername; const adminUserPassword = this.props.adminUserPassword; - if (Token.isUnresolved(adminUsername)) { return } - - if ((adminUsername !== undefined && adminUserPassword === undefined) - || (adminUsername === undefined && adminUserPassword !== undefined)) { - throw new Error('You must specify both `adminUsername` and `adminUserPassword`, or neither.'); + if (Token.isUnresolved(adminUsername)) { + return; } if ( - adminUsername && - !/^[a-zA-Z][a-zA-Z_0-9+.@-]*$/.test(adminUsername) + (adminUsername !== undefined && adminUserPassword === undefined) || + (adminUsername === undefined && adminUserPassword !== undefined) ) { + throw new Error('You must specify both `adminUsername` and `adminUserPassword`, or neither.'); + } + + if (adminUsername && !/^[a-zA-Z][a-zA-Z_0-9+.@-]*$/.test(adminUsername)) { throw new Error( - `\`adminUsername\` must start with a letter and can only contain letters, numbers, and the special characters: _, +, ., @, -, got: ${adminUsername}.` + `\`adminUsername\` must start with a letter and can only contain letters, numbers, and the special characters: _, +, ., @, -, got: ${adminUsername}.`, ); } } @@ -252,11 +251,13 @@ export class Namespace extends Resource implements INamespace { private validateDbName(): void { const dbName = this.props.dbName; - if (Token.isUnresolved(dbName) || dbName === undefined) { return } + if (Token.isUnresolved(dbName) || dbName === undefined) { + return; + } if (!/^[a-zA-Z][a-zA-Z_0-9+.@-]*$/.test(dbName) || dbName.length > 127) { throw new Error( - `\`dbName\` must start with a letter, can only contain letters, numbers, and the special characters: _, +, ., @, -, and must not exceed 127 characters, got: ${dbName}.` + `\`dbName\` must start with a letter, can only contain letters, numbers, and the special characters: _, +, ., @, -, and must not exceed 127 characters, got: ${dbName}.`, ); } } @@ -272,19 +273,22 @@ export class Namespace extends Resource implements INamespace { if (finalSnapshotName) { if (!/^[a-z][a-z0-9]*(-[a-z0-9]+)*$/.test(finalSnapshotName) || finalSnapshotName.length > 255) { - throw new Error(`\`finalSnapshotName\` must be between 1 and 255, consist only of lowercase alphanumeric characters or hyphens, with the first character as a letter, and it can't end with a hyphen or contain two consecutive hyphens, got: ${finalSnapshotName}.`); + throw new Error( + `\`finalSnapshotName\` must be between 1 and 255, consist only of lowercase alphanumeric characters or hyphens, with the first character as a letter, and it can't end with a hyphen or contain two consecutive hyphens, got: ${finalSnapshotName}.`, + ); } } - if (!Token.isUnresolved(finalSnapshotRetentionPeriod) - && finalSnapshotRetentionPeriod !== undefined) { + if (!Token.isUnresolved(finalSnapshotRetentionPeriod) && finalSnapshotRetentionPeriod !== undefined) { if (!finalSnapshotName) { - throw new Error('You must set \`finalSnapshotName`\ when you specify \`finalSnapshotRetentionPeriod\`.'); + throw new Error('You must set `finalSnapshotName` when you specify `finalSnapshotRetentionPeriod`.'); } if (finalSnapshotRetentionPeriod < 1 || finalSnapshotRetentionPeriod > 3653) { { - throw new Error(`\`finalSnapshotRetentionPeriod\` must be between 1 and 3653, got: ${finalSnapshotRetentionPeriod}.`); + throw new Error( + `\`finalSnapshotRetentionPeriod\` must be between 1 and 3653, got: ${finalSnapshotRetentionPeriod}.`, + ); } } } @@ -299,7 +303,7 @@ export class Namespace extends Resource implements INamespace { } if (!this.props.iamRoles || !this.props.iamRoles.includes(this.props.defaultIamRole)) { - throw new Error('\`defaultIamRole\` must be included in \`iamRoles\`.') + throw new Error('`defaultIamRole` must be included in `iamRoles`.'); } } @@ -309,11 +313,13 @@ export class Namespace extends Resource implements INamespace { private validateNamespaceName(): void { const namespaceName = this.props.namespaceName; - if (Token.isUnresolved(namespaceName) || namespaceName === undefined) { return } + if (Token.isUnresolved(namespaceName) || namespaceName === undefined) { + return; + } if (!/^[a-z0-9-]+$/.test(namespaceName) || namespaceName.length < 3 || namespaceName.length > 64) { throw new Error( - `\`namespaceName\` must be between 3 and 64 characters, consist only of lowercase alphanumeric characters or hyphens, got: ${namespaceName}.` + `\`namespaceName\` must be between 3 and 64 characters, consist only of lowercase alphanumeric characters or hyphens, got: ${namespaceName}.`, ); } } diff --git a/src/aws-redshiftserverless/workgroup.ts b/src/aws-redshiftserverless/workgroup.ts index 88fed96..966a65b 100644 --- a/src/aws-redshiftserverless/workgroup.ts +++ b/src/aws-redshiftserverless/workgroup.ts @@ -146,7 +146,7 @@ export interface WorkgroupAttributes { * declare const namespace: Namespace; * declare const vpc: aws_ec2.IVpc; * -* const nameSpace = new Workgroup( + * const nameSpace = new Workgroup( * stack, * 'Workgroup', * { @@ -157,15 +157,10 @@ export interface WorkgroupAttributes { * ); */ export class Workgroup extends Resource implements IWorkgroup { - /** * Import an existing workgroup to the stack from its attributes. */ - public static fromWorkgroupAttributes( - scope: Construct, - id: string, - attrs: WorkgroupAttributes, - ): IWorkgroup { + public static fromWorkgroupAttributes(scope: Construct, id: string, attrs: WorkgroupAttributes): IWorkgroup { class Import extends Resource implements IWorkgroup { public readonly workgroupName = attrs.workgroupName; public readonly workgroupId = attrs.workgroupId; @@ -221,9 +216,11 @@ export class Workgroup extends Resource implements IWorkgroup { constructor(scope: Construct, id: string, props: WorkgroupProps) { super(scope, id, { - physicalName: props.workgroupName ?? Lazy.string({ - produce: () => Names.uniqueResourceName(this, { maxLength: 64, allowedSpecialCharacters: '-' }).toLowerCase(), - }), + physicalName: + props.workgroupName ?? + Lazy.string({ + produce: () => Names.uniqueResourceName(this, { maxLength: 64, allowedSpecialCharacters: '-' }).toLowerCase(), + }), }); this.props = props; @@ -254,9 +251,9 @@ export class Workgroup extends Resource implements IWorkgroup { baseCapacity: this.props.baseCapacity, configParameters: this.props.configParameters ? Object.entries(this.props.configParameters).map(([key, value]) => ({ - parameterKey: key, - parameterValue: value, - })) + parameterKey: key, + parameterValue: value, + })) : undefined, enhancedVpcRouting: this.props.enhancedVpcRouting, namespaceName: this.props.namespace?.namespaceName, @@ -287,7 +284,6 @@ export class Workgroup extends Resource implements IWorkgroup { private validateCapacity(): void { const baseCapacity = this.props.baseCapacity; - if (!Token.isUnresolved(baseCapacity) && baseCapacity !== undefined) { if (baseCapacity < 8 || baseCapacity > 512 || baseCapacity % 8 !== 0) { throw new Error(`\`baseCapacity\` must be between 8 and 512 in units of 8, got: ${baseCapacity}.`); @@ -300,11 +296,13 @@ export class Workgroup extends Resource implements IWorkgroup { */ private validateWorkgroupName(): void { const workgroupName = this.props.workgroupName; - if (Token.isUnresolved(workgroupName) || workgroupName === undefined) { return; } + if (Token.isUnresolved(workgroupName) || workgroupName === undefined) { + return; + } if (!/^[a-z0-9-]{3,64}$/.test(workgroupName)) { throw new Error( - `\`workgroupName\` must be between 3 and 64 characters long, contain only lowercase letters, numbers, and hyphens, got: ${workgroupName}.` + `\`workgroupName\` must be between 3 and 64 characters long, contain only lowercase letters, numbers, and hyphens, got: ${workgroupName}.`, ); } } @@ -317,15 +315,11 @@ export class Workgroup extends Resource implements IWorkgroup { private validatePort(): void { const port = this.props.port; if (!Token.isUnresolved(port) && port !== undefined) { - - const isValidPort = ( - (port >= 5431 && port <= 5455) || - (port >= 8191 && port <= 8215) - ); + const isValidPort = (port >= 5431 && port <= 5455) || (port >= 8191 && port <= 8215); if (!isValidPort) { throw new Error( - `\`port\` must be in the range of 5431-5455 or 8191-8215 for Amazon Redshift Serverless, got: ${port}.` + `\`port\` must be in the range of 5431-5455 or 8191-8215 for Amazon Redshift Serverless, got: ${port}.`, ); } } @@ -337,9 +331,8 @@ export class Workgroup extends Resource implements IWorkgroup { * @see https://docs.aws.amazon.com/redshift/latest/mgmt/serverless-usage-considerations.html */ private validateSubnet(): void { - if (this.props.vpc.availabilityZones.length < 3) { - throw new Error('\`vpc` must have at least three subnets, and they must span across three Availability Zones.'); + throw new Error('`vpc` must have at least three subnets, and they must span across three Availability Zones.'); } } } diff --git a/src/index.ts b/src/index.ts index a0ed7a7..8eb5936 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,4 @@ // Export constructs here export * as aws_cur from './aws-cur'; export * as aws_ec2 from './aws-ec2'; -export * as aws_redshiftserverless from './aws-redshiftserverless'; \ No newline at end of file +export * as aws_redshiftserverless from './aws-redshiftserverless'; diff --git a/test/aws-redshiftserverless/namespace.test.ts b/test/aws-redshiftserverless/namespace.test.ts index 01b41bc..ed803e1 100644 --- a/test/aws-redshiftserverless/namespace.test.ts +++ b/test/aws-redshiftserverless/namespace.test.ts @@ -1,8 +1,8 @@ import { App, SecretValue, Stack } from 'aws-cdk-lib'; import { Match, Template } from 'aws-cdk-lib/assertions'; -import { LogExport, Namespace } from '../../src/aws-redshiftserverless'; import { Role, ServicePrincipal } from 'aws-cdk-lib/aws-iam'; import { Key } from 'aws-cdk-lib/aws-kms'; +import { LogExport, Namespace } from '../../src/aws-redshiftserverless'; describe('Redshift Serverless Namespace', () => { let app: App; @@ -63,23 +63,25 @@ describe('Redshift Serverless Namespace', () => { test('import from namespaceId', () => { const existingNamespace = Namespace.fromNamespaceAttributes(stack, 'ImportedNamespace', { namespaceId: 'my-namespace-id', - namespaceName: 'my-namespace-name' + namespaceName: 'my-namespace-name', }); expect(existingNamespace.namespaceId).toEqual('my-namespace-id'); - expect(existingNamespace.namespaceArn).toEqual(Stack.of(stack).formatArn({ - resource: 'redshift-serverless', - service: 'namespace', - resourceName: 'my-namespace-id', - })); + expect(existingNamespace.namespaceArn).toEqual( + Stack.of(stack).formatArn({ + resource: 'redshift-serverless', + service: 'namespace', + resourceName: 'my-namespace-id', + }), + ); }); - }) + }); describe('validateAdmin test', () => { test('throws when adminUsername is set without adminUserPassword', () => { expect(() => { new Namespace(stack, 'Namespace', { - adminUsername: 'my-admin' + adminUsername: 'my-admin', }); }).toThrow('You must specify both `adminUsername` and `adminUserPassword`, or neither.'); }); @@ -92,33 +94,46 @@ describe('Redshift Serverless Namespace', () => { }).toThrow('You must specify both `adminUsername` and `adminUserPassword`, or neither.'); }); - test.each(['123abc', 'invalid$name'])('throws when adminUsername is invalid, got %s', (adminUsername) => { + test.each(['123abc', 'invalid$name'])('throws when adminUsername is invalid, got %s', adminUsername => { expect(() => { new Namespace(stack, 'Namespace', { adminUsername, adminUserPassword: SecretValue.unsafePlainText('My-password-123!'), }); - }).toThrow(`\`adminUsername\` must start with a letter and can only contain letters, numbers, and the special characters: _, +, ., @, -, got: ${adminUsername}.`); + }).toThrow( + `\`adminUsername\` must start with a letter and can only contain letters, numbers, and the special characters: _, +, ., @, -, got: ${adminUsername}.`, + ); }); - }) + }); describe('validateDbName test', () => { - test.each(['123abc', 'invalid$name'])('throws when dbName is invalid, got %s', (dbName) => { + test.each(['123abc', 'invalid$name'])('throws when dbName is invalid, got %s', dbName => { expect(() => { new Namespace(stack, 'Namespace', { dbName, }); - }).toThrow(`\`dbName\` must start with a letter, can only contain letters, numbers, and the special characters: _, +, ., @, -, and must not exceed 127 characters, got: ${dbName}.`); + }).toThrow( + `\`dbName\` must start with a letter, can only contain letters, numbers, and the special characters: _, +, ., @, -, and must not exceed 127 characters, got: ${dbName}.`, + ); }); - }) + }); describe('validateFinalSnapshot test', () => { - test.each(['123abc', 'UpperName', 'invalid$name', 'end-with-a-hyphen-', 'two--consecutive-hyphens', 'a'.repeat(256)])('throws when finalSnapshotName is invalid, got %s', (finalSnapshotName) => { + test.each([ + '123abc', + 'UpperName', + 'invalid$name', + 'end-with-a-hyphen-', + 'two--consecutive-hyphens', + 'a'.repeat(256), + ])('throws when finalSnapshotName is invalid, got %s', finalSnapshotName => { expect(() => { new Namespace(stack, 'Namespace', { finalSnapshotName, }); - }).toThrow(`\`finalSnapshotName\` must be between 1 and 255, consist only of lowercase alphanumeric characters or hyphens, with the first character as a letter, and it can't end with a hyphen or contain two consecutive hyphens, got: ${finalSnapshotName}.`); + }).toThrow( + `\`finalSnapshotName\` must be between 1 and 255, consist only of lowercase alphanumeric characters or hyphens, with the first character as a letter, and it can't end with a hyphen or contain two consecutive hyphens, got: ${finalSnapshotName}.`, + ); }); test('throws when finalSnapshotRetentionPeriod is set without finalSnapshotName', () => { @@ -126,18 +141,23 @@ describe('Redshift Serverless Namespace', () => { new Namespace(stack, 'Namespace', { finalSnapshotRetentionPeriod: 10, }); - }).toThrow('You must set \`finalSnapshotName`\ when you specify \`finalSnapshotRetentionPeriod\`.'); + }).toThrow('You must set `finalSnapshotName` when you specify `finalSnapshotRetentionPeriod`.'); }); - test.each([0, 3654])('throws when finalSnapshotRetentionPeriod is invalid, got %d', (finalSnapshotRetentionPeriod) => { - expect(() => { - new Namespace(stack, 'Namespace', { - finalSnapshotName: 'my-final-snapshot', - finalSnapshotRetentionPeriod, - }); - }).toThrow(`\`finalSnapshotRetentionPeriod\` must be between 1 and 3653, got: ${finalSnapshotRetentionPeriod}.`); - }); - }) + test.each([0, 3654])( + 'throws when finalSnapshotRetentionPeriod is invalid, got %d', + finalSnapshotRetentionPeriod => { + expect(() => { + new Namespace(stack, 'Namespace', { + finalSnapshotName: 'my-final-snapshot', + finalSnapshotRetentionPeriod, + }); + }).toThrow( + `\`finalSnapshotRetentionPeriod\` must be between 1 and 3653, got: ${finalSnapshotRetentionPeriod}.`, + ); + }, + ); + }); describe('validateDefaultIamRole test', () => { test('throws when defaultIamRole role is not included in iamRoles', () => { @@ -154,17 +174,22 @@ describe('Redshift Serverless Namespace', () => { defaultIamRole, iamRoles: [anotherRole], }); - }).toThrow('\`defaultIamRole\` must be included in \`iamRoles\`.'); + }).toThrow('`defaultIamRole` must be included in `iamRoles`.'); }); - }) + }); describe('validateNamespaceName test', () => { - test.each(['UpperName', 'invalid$name', 'a'.repeat(2), 'a'.repeat(65)])('throws when namespaceName is invalid, got %s', (namespaceName) => { - expect(() => { - new Namespace(stack, 'Namespace', { - namespaceName, - }); - }).toThrow(`\`namespaceName\` must be between 3 and 64 characters, consist only of lowercase alphanumeric characters or hyphens, got: ${namespaceName}.`); - }); - }) -}); \ No newline at end of file + test.each(['UpperName', 'invalid$name', 'a'.repeat(2), 'a'.repeat(65)])( + 'throws when namespaceName is invalid, got %s', + namespaceName => { + expect(() => { + new Namespace(stack, 'Namespace', { + namespaceName, + }); + }).toThrow( + `\`namespaceName\` must be between 3 and 64 characters, consist only of lowercase alphanumeric characters or hyphens, got: ${namespaceName}.`, + ); + }, + ); + }); +}); diff --git a/test/aws-redshiftserverless/workgroup.test.ts b/test/aws-redshiftserverless/workgroup.test.ts index 2768fff..354133f 100644 --- a/test/aws-redshiftserverless/workgroup.test.ts +++ b/test/aws-redshiftserverless/workgroup.test.ts @@ -12,7 +12,7 @@ describe('Redshift Serverless Workgroup', () => { stack = new Stack(app, 'TestStack', { env: { account: '012345678901', region: 'us-east-1' }, }); - vpc = new aws_ec2.Vpc(stack, 'VPC',); + vpc = new aws_ec2.Vpc(stack, 'VPC'); }); test('Create namsepace with minimal properties ', () => { @@ -21,12 +21,11 @@ describe('Redshift Serverless Workgroup', () => { }); Template.fromStack(stack).hasResourceProperties('AWS::RedshiftServerless::Workgroup', { - SecurityGroupIds: [{ - 'Fn::GetAtt': [ - 'NamespaceSecurityGroup051B6159', - 'GroupId', - ], - }], + SecurityGroupIds: [ + { + 'Fn::GetAtt': ['NamespaceSecurityGroup051B6159', 'GroupId'], + }, + ], SubnetIds: [ { Ref: 'VPCPrivateSubnet1Subnet8BCA10E0' }, { Ref: 'VPCPrivateSubnet2SubnetCFCDAA7A' }, @@ -68,8 +67,7 @@ describe('Redshift Serverless Workgroup', () => { describe('import method', () => { test('imports Workgroup correctly', () => { - - const securityGroup = aws_ec2.SecurityGroup.fromSecurityGroupId(stack, 'SG', 'sg-123456789') + const securityGroup = aws_ec2.SecurityGroup.fromSecurityGroupId(stack, 'SG', 'sg-123456789'); const importedWorkgroup = Workgroup.fromWorkgroupAttributes(stack, 'ImportedWorkgroup', { workgroupName: 'my-workgroup', workgroupId: 'my-workgroup-id', @@ -88,18 +86,20 @@ describe('Redshift Serverless Workgroup', () => { expect(importedWorkgroup.workgroupName).toEqual('my-workgroup'); - expect(importedWorkgroup.workgroupArn).toEqual(Stack.of(stack).formatArn({ - resource: 'redshift-serverless', - service: 'workgroup', - resourceName: 'my-workgroup-id', - })); + expect(importedWorkgroup.workgroupArn).toEqual( + Stack.of(stack).formatArn({ + resource: 'redshift-serverless', + service: 'workgroup', + resourceName: 'my-workgroup-id', + }), + ); expect(importedWorkgroup.connections.securityGroups).toEqual([securityGroup]); }); }); describe('validateCapacity test', () => { - test.each([0, 520, 15])('throws when baseCapacity is invalid, got %d', (baseCapacity) => { + test.each([0, 520, 15])('throws when baseCapacity is invalid, got %d', baseCapacity => { expect(() => { new Workgroup(stack, 'Workgroup', { baseCapacity, @@ -110,25 +110,31 @@ describe('Redshift Serverless Workgroup', () => { }); describe('validateWorkgroupName test', () => { - test.each(['ABC', 'name with spaces', 'a'.repeat(2), 'a'.repeat(100),]) - ('throws when workgroupName is invalid, got %s', (workgroupName) => { + test.each(['ABC', 'name with spaces', 'a'.repeat(2), 'a'.repeat(100)])( + 'throws when workgroupName is invalid, got %s', + workgroupName => { expect(() => { new Workgroup(stack, 'Workgroup', { workgroupName, vpc, }); - }).toThrow(`\`workgroupName\` must be between 3 and 64 characters long, contain only lowercase letters, numbers, and hyphens, got: ${workgroupName}.`); - }); + }).toThrow( + `\`workgroupName\` must be between 3 and 64 characters long, contain only lowercase letters, numbers, and hyphens, got: ${workgroupName}.`, + ); + }, + ); }); describe('validatePort test', () => { - test.each([5430, 5456, 8190, 8216])('throws when port is invalid, got %d', (port) => { + test.each([5430, 5456, 8190, 8216])('throws when port is invalid, got %d', port => { expect(() => { new Workgroup(stack, 'Workgroup', { port, vpc, }); - }).toThrow(`\`port\` must be in the range of 5431-5455 or 8191-8215 for Amazon Redshift Serverless, got: ${port}.`); + }).toThrow( + `\`port\` must be in the range of 5431-5455 or 8191-8215 for Amazon Redshift Serverless, got: ${port}.`, + ); }); }); @@ -142,7 +148,7 @@ describe('Redshift Serverless Workgroup', () => { new Workgroup(stack, 'Workgroup', { vpc: vpcFor2Az, }); - }).toThrow('\`vpc` must have at least three subnets, and they must span across three Availability Zones.'); + }).toThrow('`vpc` must have at least three subnets, and they must span across three Availability Zones.'); }); }); -}); \ No newline at end of file +}); From 58893ad110d2220b0b5af12f4e454c9037acb927 Mon Sep 17 00:00:00 2001 From: maz Date: Thu, 12 Sep 2024 20:09:36 +0900 Subject: [PATCH 06/29] update --- .../integ.redshift-serverless.ts | 14 +- ...efaultTestDeployAssertC5CDACEC.assets.json | 19 + ...aultTestDeployAssertC5CDACEC.template.json | 36 + .../RedshiftServerlessStack.assets.json | 34 + .../RedshiftServerlessStack.template.json | 823 +++++++++++ .../cdk.out | 1 + .../integ.json | 14 + .../manifest.json | 359 +++++ .../tree.json | 1299 +++++++++++++++++ test/aws-redshiftserverless/workgroup.test.ts | 21 +- 10 files changed, 2616 insertions(+), 4 deletions(-) create mode 100644 test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessDefaultTestDeployAssertC5CDACEC.assets.json create mode 100644 test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessDefaultTestDeployAssertC5CDACEC.template.json create mode 100644 test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.assets.json create mode 100644 test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.template.json create mode 100644 test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/cdk.out create mode 100644 test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/integ.json create mode 100644 test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/manifest.json create mode 100644 test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/tree.json diff --git a/test/aws-redshiftserverless/integ.redshift-serverless.ts b/test/aws-redshiftserverless/integ.redshift-serverless.ts index 23d5167..b9b4408 100644 --- a/test/aws-redshiftserverless/integ.redshift-serverless.ts +++ b/test/aws-redshiftserverless/integ.redshift-serverless.ts @@ -33,10 +33,19 @@ class RedshiftServerlessStack extends cdk.Stack { }); const workgroup = new ocf.aws_redshiftserverless.Workgroup(this, 'WorkGroup', { - namespace, - vpc, + baseCapacity: 8, + configParameters: { + datestyle: 'ISO, MDY', + enable_user_activity_logging: 'true', + query_group: 'default', + require_ssl: 'true', + search_path: '$user, public', + max_query_execution_time: '14440', + }, enhancedVpcRouting: true, + namespace, publiclyAccessible: true, + vpc, port: 5432, }); this.workgroup = workgroup; @@ -58,4 +67,3 @@ new IntegTest(app, 'RedshiftServerless', { }); new cdk.CfnOutput(testCase, 'endpointAddress', { value: testCase.workgroup.endpointAddress }); -// new cdk.CfnOutput(testCase, 'port', { value: testCase.workgroup.port.toString() }); diff --git a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessDefaultTestDeployAssertC5CDACEC.assets.json b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessDefaultTestDeployAssertC5CDACEC.assets.json new file mode 100644 index 0000000..8b20e2f --- /dev/null +++ b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessDefaultTestDeployAssertC5CDACEC.assets.json @@ -0,0 +1,19 @@ +{ + "version": "36.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "RedshiftServerlessDefaultTestDeployAssertC5CDACEC.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/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessDefaultTestDeployAssertC5CDACEC.template.json b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessDefaultTestDeployAssertC5CDACEC.template.json new file mode 100644 index 0000000..ad9d0fb --- /dev/null +++ b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessDefaultTestDeployAssertC5CDACEC.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/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.assets.json b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.assets.json new file mode 100644 index 0000000..03955b6 --- /dev/null +++ b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.assets.json @@ -0,0 +1,34 @@ +{ + "version": "36.0.0", + "files": { + "dd5711540f04e06aa955d7f4862fc04e8cdea464cb590dae91ed2976bb78098e": { + "source": { + "path": "asset.dd5711540f04e06aa955d7f4862fc04e8cdea464cb590dae91ed2976bb78098e", + "packaging": "zip" + }, + "destinations": { + "12345678-test-region": { + "bucketName": "cdk-hnb659fds-assets-12345678-test-region", + "objectKey": "dd5711540f04e06aa955d7f4862fc04e8cdea464cb590dae91ed2976bb78098e.zip", + "region": "test-region", + "assumeRoleArn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-file-publishing-role-12345678-test-region" + } + } + }, + "a3b55bd2a328ce07708cdc1ce9592e1dab2d3040ec254c12265c74e8e5d2ab8d": { + "source": { + "path": "RedshiftServerlessStack.template.json", + "packaging": "file" + }, + "destinations": { + "12345678-test-region": { + "bucketName": "cdk-hnb659fds-assets-12345678-test-region", + "objectKey": "a3b55bd2a328ce07708cdc1ce9592e1dab2d3040ec254c12265c74e8e5d2ab8d.json", + "region": "test-region", + "assumeRoleArn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-file-publishing-role-12345678-test-region" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.template.json b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.template.json new file mode 100644 index 0000000..60391d3 --- /dev/null +++ b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.template.json @@ -0,0 +1,823 @@ +{ + "Resources": { + "VPCB9E5F0B4": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC" + } + ] + } + }, + "VPCPublicSubnet1SubnetB4246D30": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "AvailabilityZone": "test-region-1a", + "CidrBlock": "10.0.0.0/19", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC/PublicSubnet1" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCPublicSubnet1RouteTableFEE4B781": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC/PublicSubnet1" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCPublicSubnet1RouteTableAssociation0B0896DC": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + } + } + }, + "VPCPublicSubnet1DefaultRoute91CEF279": { + "Type": "AWS::EC2::Route", + "Properties": { + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + }, + "RouteTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + } + }, + "DependsOn": [ + "VPCVPCGW99B986DC" + ] + }, + "VPCPublicSubnet1EIP6AD938E8": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1NATGatewayE0556630": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet1EIP6AD938E8", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, + "Tags": [ + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC/PublicSubnet1" + } + ] + }, + "DependsOn": [ + "VPCPublicSubnet1DefaultRoute91CEF279", + "VPCPublicSubnet1RouteTableAssociation0B0896DC" + ] + }, + "VPCPublicSubnet2Subnet74179F39": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "AvailabilityZone": "test-region-1b", + "CidrBlock": "10.0.32.0/19", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC/PublicSubnet2" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCPublicSubnet2RouteTable6F1A15F1": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC/PublicSubnet2" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCPublicSubnet2RouteTableAssociation5A808732": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + } + } + }, + "VPCPublicSubnet2DefaultRouteB7481BBA": { + "Type": "AWS::EC2::Route", + "Properties": { + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + }, + "RouteTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + } + }, + "DependsOn": [ + "VPCVPCGW99B986DC" + ] + }, + "VPCPublicSubnet2EIP4947BC00": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2NATGateway3C070193": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet2EIP4947BC00", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, + "Tags": [ + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC/PublicSubnet2" + } + ] + }, + "DependsOn": [ + "VPCPublicSubnet2DefaultRouteB7481BBA", + "VPCPublicSubnet2RouteTableAssociation5A808732" + ] + }, + "VPCPublicSubnet3Subnet631C5E25": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "AvailabilityZone": "test-region-1c", + "CidrBlock": "10.0.64.0/19", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC/PublicSubnet3" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCPublicSubnet3RouteTable98AE0E14": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC/PublicSubnet3" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCPublicSubnet3RouteTableAssociation427FE0C6": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet3RouteTable98AE0E14" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet3Subnet631C5E25" + } + } + }, + "VPCPublicSubnet3DefaultRouteA0D29D46": { + "Type": "AWS::EC2::Route", + "Properties": { + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + }, + "RouteTableId": { + "Ref": "VPCPublicSubnet3RouteTable98AE0E14" + } + }, + "DependsOn": [ + "VPCVPCGW99B986DC" + ] + }, + "VPCPublicSubnet3EIPAD4BC883": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC/PublicSubnet3" + } + ] + } + }, + "VPCPublicSubnet3NATGatewayD3048F5C": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet3EIPAD4BC883", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VPCPublicSubnet3Subnet631C5E25" + }, + "Tags": [ + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC/PublicSubnet3" + } + ] + }, + "DependsOn": [ + "VPCPublicSubnet3DefaultRouteA0D29D46", + "VPCPublicSubnet3RouteTableAssociation427FE0C6" + ] + }, + "VPCPrivateSubnet1Subnet8BCA10E0": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "AvailabilityZone": "test-region-1a", + "CidrBlock": "10.0.96.0/19", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC/PrivateSubnet1" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCPrivateSubnet1RouteTableBE8A6027": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC/PrivateSubnet1" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCPrivateSubnet1RouteTableAssociation347902D1": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" + }, + "SubnetId": { + "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + } + } + }, + "VPCPrivateSubnet1DefaultRouteAE1D6490": { + "Type": "AWS::EC2::Route", + "Properties": { + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VPCPublicSubnet1NATGatewayE0556630" + }, + "RouteTableId": { + "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" + } + } + }, + "VPCPrivateSubnet2SubnetCFCDAA7A": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "AvailabilityZone": "test-region-1b", + "CidrBlock": "10.0.128.0/19", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC/PrivateSubnet2" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCPrivateSubnet2RouteTable0A19E10E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC/PrivateSubnet2" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCPrivateSubnet2RouteTableAssociation0C73D413": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" + }, + "SubnetId": { + "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" + } + } + }, + "VPCPrivateSubnet2DefaultRouteF4F5CFD2": { + "Type": "AWS::EC2::Route", + "Properties": { + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VPCPublicSubnet2NATGateway3C070193" + }, + "RouteTableId": { + "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" + } + } + }, + "VPCPrivateSubnet3Subnet3EDCD457": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "AvailabilityZone": "test-region-1c", + "CidrBlock": "10.0.160.0/19", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC/PrivateSubnet3" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCPrivateSubnet3RouteTable192186F8": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC/PrivateSubnet3" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCPrivateSubnet3RouteTableAssociationC28D144E": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet3RouteTable192186F8" + }, + "SubnetId": { + "Ref": "VPCPrivateSubnet3Subnet3EDCD457" + } + } + }, + "VPCPrivateSubnet3DefaultRoute27F311AE": { + "Type": "AWS::EC2::Route", + "Properties": { + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VPCPublicSubnet3NATGatewayD3048F5C" + }, + "RouteTableId": { + "Ref": "VPCPrivateSubnet3RouteTable192186F8" + } + } + }, + "VPCIGWB7E252D3": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "RedshiftServerlessStack/VPC" + } + ] + } + }, + "VPCVPCGW99B986DC": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "InternetGatewayId": { + "Ref": "VPCIGWB7E252D3" + }, + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCRestrictDefaultSecurityGroupCustomResource59474679": { + "Type": "Custom::VpcRestrictDefaultSG", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "CustomVpcRestrictDefaultSGCustomResourceProviderHandlerDC833E5E", + "Arn" + ] + }, + "DefaultSecurityGroupId": { + "Fn::GetAtt": [ + "VPCB9E5F0B4", + "DefaultSecurityGroup" + ] + }, + "Account": "12345678" + }, + "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:test-region:12345678:security-group/", + { + "Fn::GetAtt": [ + "VPCB9E5F0B4", + "DefaultSecurityGroup" + ] + } + ] + ] + } + ] + } + ] + } + } + ] + } + }, + "CustomVpcRestrictDefaultSGCustomResourceProviderHandlerDC833E5E": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "cdk-hnb659fds-assets-12345678-test-region", + "S3Key": "dd5711540f04e06aa955d7f4862fc04e8cdea464cb590dae91ed2976bb78098e.zip" + }, + "Timeout": 900, + "MemorySize": 128, + "Handler": "__entrypoint__.handler", + "Role": { + "Fn::GetAtt": [ + "CustomVpcRestrictDefaultSGCustomResourceProviderRole26592FE0", + "Arn" + ] + }, + "Runtime": "nodejs18.x", + "Description": "Lambda function for removing all inbound/outbound rules from the VPC default security group" + }, + "DependsOn": [ + "CustomVpcRestrictDefaultSGCustomResourceProviderRole26592FE0" + ] + }, + "DefaultRoleEFEF8FA6": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "redshift.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "AnotherRoleE13C44E8": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "redshift.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "Namespace9B63B8C8": { + "Type": "AWS::RedshiftServerless::Namespace", + "Properties": { + "AdminUserPassword": "adminUserPassword123", + "AdminUsername": "adminuser", + "DbName": "mydatabase", + "DefaultIamRoleArn": { + "Fn::GetAtt": [ + "DefaultRoleEFEF8FA6", + "Arn" + ] + }, + "IamRoles": [ + { + "Fn::GetAtt": [ + "DefaultRoleEFEF8FA6", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "AnotherRoleE13C44E8", + "Arn" + ] + } + ], + "LogExports": [ + "userlog", + "connectionlog", + "useractivitylog" + ], + "NamespaceName": "redshiftserverlessstacknamespace96a02cb7" + } + }, + "WorkGroupSecurityGroup82E81D37": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "Automatic generated security group for Redshift Serverless Security Group", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "WorkGroup9BE20B7A": { + "Type": "AWS::RedshiftServerless::Workgroup", + "Properties": { + "BaseCapacity": 8, + "ConfigParameters": [ + { + "ParameterKey": "datestyle", + "ParameterValue": "ISO, MDY" + }, + { + "ParameterKey": "enable_user_activity_logging", + "ParameterValue": "true" + }, + { + "ParameterKey": "query_group", + "ParameterValue": "default" + }, + { + "ParameterKey": "require_ssl", + "ParameterValue": "true" + }, + { + "ParameterKey": "search_path", + "ParameterValue": "$user, public" + }, + { + "ParameterKey": "max_query_execution_time", + "ParameterValue": "14440" + } + ], + "EnhancedVpcRouting": true, + "NamespaceName": { + "Fn::GetAtt": [ + "Namespace9B63B8C8", + "Namespace.NamespaceName" + ] + }, + "Port": 5432, + "PubliclyAccessible": true, + "SecurityGroupIds": [ + { + "Fn::GetAtt": [ + "WorkGroupSecurityGroup82E81D37", + "GroupId" + ] + } + ], + "SubnetIds": [ + { + "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + }, + { + "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" + }, + { + "Ref": "VPCPrivateSubnet3Subnet3EDCD457" + } + ], + "WorkgroupName": "redshiftserverlessstackworkgroupcfbe5e7c" + } + } + }, + "Outputs": { + "endpointAddress": { + "Value": { + "Fn::GetAtt": [ + "WorkGroup9BE20B7A", + "Workgroup.Endpoint.Address" + ] + } + } + }, + "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/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/cdk.out b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/cdk.out new file mode 100644 index 0000000..1f0068d --- /dev/null +++ b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"36.0.0"} \ No newline at end of file diff --git a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/integ.json b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/integ.json new file mode 100644 index 0000000..baea88a --- /dev/null +++ b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/integ.json @@ -0,0 +1,14 @@ +{ + "enableLookups": true, + "version": "36.0.0", + "testCases": { + "RedshiftServerless/DefaultTest": { + "stacks": [ + "RedshiftServerlessStack" + ], + "stackUpdateWorkflow": false, + "assertionStack": "RedshiftServerless/DefaultTest/DeployAssert", + "assertionStackName": "RedshiftServerlessDefaultTestDeployAssertC5CDACEC" + } + } +} \ No newline at end of file diff --git a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/manifest.json b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/manifest.json new file mode 100644 index 0000000..dee486d --- /dev/null +++ b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/manifest.json @@ -0,0 +1,359 @@ +{ + "version": "36.0.0", + "artifacts": { + "RedshiftServerlessStack.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "RedshiftServerlessStack.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "RedshiftServerlessStack": { + "type": "aws:cloudformation:stack", + "environment": "aws://12345678/test-region", + "properties": { + "templateFile": "RedshiftServerlessStack.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-deploy-role-12345678-test-region", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-cfn-exec-role-12345678-test-region", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-12345678-test-region/a3b55bd2a328ce07708cdc1ce9592e1dab2d3040ec254c12265c74e8e5d2ab8d.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "RedshiftServerlessStack.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-lookup-role-12345678-test-region", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "RedshiftServerlessStack.assets" + ], + "metadata": { + "/RedshiftServerlessStack/VPC/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCB9E5F0B4" + } + ], + "/RedshiftServerlessStack/VPC/PublicSubnet1/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet1SubnetB4246D30" + } + ], + "/RedshiftServerlessStack/VPC/PublicSubnet1/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet1RouteTableFEE4B781" + } + ], + "/RedshiftServerlessStack/VPC/PublicSubnet1/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet1RouteTableAssociation0B0896DC" + } + ], + "/RedshiftServerlessStack/VPC/PublicSubnet1/DefaultRoute": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet1DefaultRoute91CEF279" + } + ], + "/RedshiftServerlessStack/VPC/PublicSubnet1/EIP": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet1EIP6AD938E8" + } + ], + "/RedshiftServerlessStack/VPC/PublicSubnet1/NATGateway": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet1NATGatewayE0556630" + } + ], + "/RedshiftServerlessStack/VPC/PublicSubnet2/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet2Subnet74179F39" + } + ], + "/RedshiftServerlessStack/VPC/PublicSubnet2/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet2RouteTable6F1A15F1" + } + ], + "/RedshiftServerlessStack/VPC/PublicSubnet2/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet2RouteTableAssociation5A808732" + } + ], + "/RedshiftServerlessStack/VPC/PublicSubnet2/DefaultRoute": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet2DefaultRouteB7481BBA" + } + ], + "/RedshiftServerlessStack/VPC/PublicSubnet2/EIP": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet2EIP4947BC00" + } + ], + "/RedshiftServerlessStack/VPC/PublicSubnet2/NATGateway": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet2NATGateway3C070193" + } + ], + "/RedshiftServerlessStack/VPC/PublicSubnet3/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet3Subnet631C5E25" + } + ], + "/RedshiftServerlessStack/VPC/PublicSubnet3/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet3RouteTable98AE0E14" + } + ], + "/RedshiftServerlessStack/VPC/PublicSubnet3/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet3RouteTableAssociation427FE0C6" + } + ], + "/RedshiftServerlessStack/VPC/PublicSubnet3/DefaultRoute": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet3DefaultRouteA0D29D46" + } + ], + "/RedshiftServerlessStack/VPC/PublicSubnet3/EIP": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet3EIPAD4BC883" + } + ], + "/RedshiftServerlessStack/VPC/PublicSubnet3/NATGateway": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet3NATGatewayD3048F5C" + } + ], + "/RedshiftServerlessStack/VPC/PrivateSubnet1/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPrivateSubnet1Subnet8BCA10E0" + } + ], + "/RedshiftServerlessStack/VPC/PrivateSubnet1/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPrivateSubnet1RouteTableBE8A6027" + } + ], + "/RedshiftServerlessStack/VPC/PrivateSubnet1/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPrivateSubnet1RouteTableAssociation347902D1" + } + ], + "/RedshiftServerlessStack/VPC/PrivateSubnet1/DefaultRoute": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPrivateSubnet1DefaultRouteAE1D6490" + } + ], + "/RedshiftServerlessStack/VPC/PrivateSubnet2/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPrivateSubnet2SubnetCFCDAA7A" + } + ], + "/RedshiftServerlessStack/VPC/PrivateSubnet2/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPrivateSubnet2RouteTable0A19E10E" + } + ], + "/RedshiftServerlessStack/VPC/PrivateSubnet2/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPrivateSubnet2RouteTableAssociation0C73D413" + } + ], + "/RedshiftServerlessStack/VPC/PrivateSubnet2/DefaultRoute": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPrivateSubnet2DefaultRouteF4F5CFD2" + } + ], + "/RedshiftServerlessStack/VPC/PrivateSubnet3/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPrivateSubnet3Subnet3EDCD457" + } + ], + "/RedshiftServerlessStack/VPC/PrivateSubnet3/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPrivateSubnet3RouteTable192186F8" + } + ], + "/RedshiftServerlessStack/VPC/PrivateSubnet3/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPrivateSubnet3RouteTableAssociationC28D144E" + } + ], + "/RedshiftServerlessStack/VPC/PrivateSubnet3/DefaultRoute": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPrivateSubnet3DefaultRoute27F311AE" + } + ], + "/RedshiftServerlessStack/VPC/IGW": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCIGWB7E252D3" + } + ], + "/RedshiftServerlessStack/VPC/VPCGW": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCVPCGW99B986DC" + } + ], + "/RedshiftServerlessStack/VPC/RestrictDefaultSecurityGroupCustomResource/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCRestrictDefaultSecurityGroupCustomResource59474679" + } + ], + "/RedshiftServerlessStack/Custom::VpcRestrictDefaultSGCustomResourceProvider/Role": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomVpcRestrictDefaultSGCustomResourceProviderRole26592FE0" + } + ], + "/RedshiftServerlessStack/Custom::VpcRestrictDefaultSGCustomResourceProvider/Handler": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomVpcRestrictDefaultSGCustomResourceProviderHandlerDC833E5E" + } + ], + "/RedshiftServerlessStack/DefaultRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "DefaultRoleEFEF8FA6" + } + ], + "/RedshiftServerlessStack/AnotherRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "AnotherRoleE13C44E8" + } + ], + "/RedshiftServerlessStack/Namespace/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Namespace9B63B8C8" + } + ], + "/RedshiftServerlessStack/WorkGroup/SecurityGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "WorkGroupSecurityGroup82E81D37" + } + ], + "/RedshiftServerlessStack/WorkGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "WorkGroup9BE20B7A" + } + ], + "/RedshiftServerlessStack/endpointAddress": [ + { + "type": "aws:cdk:logicalId", + "data": "endpointAddress" + } + ], + "/RedshiftServerlessStack/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/RedshiftServerlessStack/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "RedshiftServerlessStack" + }, + "RedshiftServerlessDefaultTestDeployAssertC5CDACEC.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "RedshiftServerlessDefaultTestDeployAssertC5CDACEC.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "RedshiftServerlessDefaultTestDeployAssertC5CDACEC": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "RedshiftServerlessDefaultTestDeployAssertC5CDACEC.template.json", + "terminationProtection": false, + "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": [ + "RedshiftServerlessDefaultTestDeployAssertC5CDACEC.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": [ + "RedshiftServerlessDefaultTestDeployAssertC5CDACEC.assets" + ], + "metadata": { + "/RedshiftServerless/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/RedshiftServerless/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "RedshiftServerless/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + } +} \ No newline at end of file diff --git a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/tree.json b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/tree.json new file mode 100644 index 0000000..accb4a4 --- /dev/null +++ b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/tree.json @@ -0,0 +1,1299 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "RedshiftServerlessStack": { + "id": "RedshiftServerlessStack", + "path": "RedshiftServerlessStack", + "children": { + "VPC": { + "id": "VPC", + "path": "RedshiftServerlessStack/VPC", + "children": { + "Resource": { + "id": "Resource", + "path": "RedshiftServerlessStack/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": "RedshiftServerlessStack/VPC" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnVPC", + "version": "2.120.0" + } + }, + "PublicSubnet1": { + "id": "PublicSubnet1", + "path": "RedshiftServerlessStack/VPC/PublicSubnet1", + "children": { + "Subnet": { + "id": "Subnet", + "path": "RedshiftServerlessStack/VPC/PublicSubnet1/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "availabilityZone": "test-region-1a", + "cidrBlock": "10.0.0.0/19", + "mapPublicIpOnLaunch": true, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "Public" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Public" + }, + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC/PublicSubnet1" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", + "version": "2.120.0" + } + }, + "Acl": { + "id": "Acl", + "path": "RedshiftServerlessStack/VPC/PublicSubnet1/Acl", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "2.120.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "RedshiftServerlessStack/VPC/PublicSubnet1/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "tags": [ + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC/PublicSubnet1" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", + "version": "2.120.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "RedshiftServerlessStack/VPC/PublicSubnet1/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + }, + "subnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", + "version": "2.120.0" + } + }, + "DefaultRoute": { + "id": "DefaultRoute", + "path": "RedshiftServerlessStack/VPC/PublicSubnet1/DefaultRoute", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Route", + "aws:cdk:cloudformation:props": { + "destinationCidrBlock": "0.0.0.0/0", + "gatewayId": { + "Ref": "VPCIGWB7E252D3" + }, + "routeTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", + "version": "2.120.0" + } + }, + "EIP": { + "id": "EIP", + "path": "RedshiftServerlessStack/VPC/PublicSubnet1/EIP", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::EIP", + "aws:cdk:cloudformation:props": { + "domain": "vpc", + "tags": [ + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC/PublicSubnet1" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnEIP", + "version": "2.120.0" + } + }, + "NATGateway": { + "id": "NATGateway", + "path": "RedshiftServerlessStack/VPC/PublicSubnet1/NATGateway", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", + "aws:cdk:cloudformation:props": { + "allocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet1EIP6AD938E8", + "AllocationId" + ] + }, + "subnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, + "tags": [ + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC/PublicSubnet1" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnNatGateway", + "version": "2.120.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.PublicSubnet", + "version": "2.120.0" + } + }, + "PublicSubnet2": { + "id": "PublicSubnet2", + "path": "RedshiftServerlessStack/VPC/PublicSubnet2", + "children": { + "Subnet": { + "id": "Subnet", + "path": "RedshiftServerlessStack/VPC/PublicSubnet2/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "availabilityZone": "test-region-1b", + "cidrBlock": "10.0.32.0/19", + "mapPublicIpOnLaunch": true, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "Public" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Public" + }, + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC/PublicSubnet2" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", + "version": "2.120.0" + } + }, + "Acl": { + "id": "Acl", + "path": "RedshiftServerlessStack/VPC/PublicSubnet2/Acl", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "2.120.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "RedshiftServerlessStack/VPC/PublicSubnet2/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "tags": [ + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC/PublicSubnet2" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", + "version": "2.120.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "RedshiftServerlessStack/VPC/PublicSubnet2/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + }, + "subnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", + "version": "2.120.0" + } + }, + "DefaultRoute": { + "id": "DefaultRoute", + "path": "RedshiftServerlessStack/VPC/PublicSubnet2/DefaultRoute", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Route", + "aws:cdk:cloudformation:props": { + "destinationCidrBlock": "0.0.0.0/0", + "gatewayId": { + "Ref": "VPCIGWB7E252D3" + }, + "routeTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", + "version": "2.120.0" + } + }, + "EIP": { + "id": "EIP", + "path": "RedshiftServerlessStack/VPC/PublicSubnet2/EIP", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::EIP", + "aws:cdk:cloudformation:props": { + "domain": "vpc", + "tags": [ + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC/PublicSubnet2" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnEIP", + "version": "2.120.0" + } + }, + "NATGateway": { + "id": "NATGateway", + "path": "RedshiftServerlessStack/VPC/PublicSubnet2/NATGateway", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", + "aws:cdk:cloudformation:props": { + "allocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet2EIP4947BC00", + "AllocationId" + ] + }, + "subnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, + "tags": [ + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC/PublicSubnet2" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnNatGateway", + "version": "2.120.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.PublicSubnet", + "version": "2.120.0" + } + }, + "PublicSubnet3": { + "id": "PublicSubnet3", + "path": "RedshiftServerlessStack/VPC/PublicSubnet3", + "children": { + "Subnet": { + "id": "Subnet", + "path": "RedshiftServerlessStack/VPC/PublicSubnet3/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "availabilityZone": "test-region-1c", + "cidrBlock": "10.0.64.0/19", + "mapPublicIpOnLaunch": true, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "Public" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Public" + }, + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC/PublicSubnet3" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", + "version": "2.120.0" + } + }, + "Acl": { + "id": "Acl", + "path": "RedshiftServerlessStack/VPC/PublicSubnet3/Acl", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "2.120.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "RedshiftServerlessStack/VPC/PublicSubnet3/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "tags": [ + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC/PublicSubnet3" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", + "version": "2.120.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "RedshiftServerlessStack/VPC/PublicSubnet3/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "VPCPublicSubnet3RouteTable98AE0E14" + }, + "subnetId": { + "Ref": "VPCPublicSubnet3Subnet631C5E25" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", + "version": "2.120.0" + } + }, + "DefaultRoute": { + "id": "DefaultRoute", + "path": "RedshiftServerlessStack/VPC/PublicSubnet3/DefaultRoute", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Route", + "aws:cdk:cloudformation:props": { + "destinationCidrBlock": "0.0.0.0/0", + "gatewayId": { + "Ref": "VPCIGWB7E252D3" + }, + "routeTableId": { + "Ref": "VPCPublicSubnet3RouteTable98AE0E14" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", + "version": "2.120.0" + } + }, + "EIP": { + "id": "EIP", + "path": "RedshiftServerlessStack/VPC/PublicSubnet3/EIP", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::EIP", + "aws:cdk:cloudformation:props": { + "domain": "vpc", + "tags": [ + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC/PublicSubnet3" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnEIP", + "version": "2.120.0" + } + }, + "NATGateway": { + "id": "NATGateway", + "path": "RedshiftServerlessStack/VPC/PublicSubnet3/NATGateway", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", + "aws:cdk:cloudformation:props": { + "allocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet3EIPAD4BC883", + "AllocationId" + ] + }, + "subnetId": { + "Ref": "VPCPublicSubnet3Subnet631C5E25" + }, + "tags": [ + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC/PublicSubnet3" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnNatGateway", + "version": "2.120.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.PublicSubnet", + "version": "2.120.0" + } + }, + "PrivateSubnet1": { + "id": "PrivateSubnet1", + "path": "RedshiftServerlessStack/VPC/PrivateSubnet1", + "children": { + "Subnet": { + "id": "Subnet", + "path": "RedshiftServerlessStack/VPC/PrivateSubnet1/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "availabilityZone": "test-region-1a", + "cidrBlock": "10.0.96.0/19", + "mapPublicIpOnLaunch": false, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "Private" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Private" + }, + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC/PrivateSubnet1" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", + "version": "2.120.0" + } + }, + "Acl": { + "id": "Acl", + "path": "RedshiftServerlessStack/VPC/PrivateSubnet1/Acl", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "2.120.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "RedshiftServerlessStack/VPC/PrivateSubnet1/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "tags": [ + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC/PrivateSubnet1" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", + "version": "2.120.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "RedshiftServerlessStack/VPC/PrivateSubnet1/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" + }, + "subnetId": { + "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", + "version": "2.120.0" + } + }, + "DefaultRoute": { + "id": "DefaultRoute", + "path": "RedshiftServerlessStack/VPC/PrivateSubnet1/DefaultRoute", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Route", + "aws:cdk:cloudformation:props": { + "destinationCidrBlock": "0.0.0.0/0", + "natGatewayId": { + "Ref": "VPCPublicSubnet1NATGatewayE0556630" + }, + "routeTableId": { + "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", + "version": "2.120.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.PrivateSubnet", + "version": "2.120.0" + } + }, + "PrivateSubnet2": { + "id": "PrivateSubnet2", + "path": "RedshiftServerlessStack/VPC/PrivateSubnet2", + "children": { + "Subnet": { + "id": "Subnet", + "path": "RedshiftServerlessStack/VPC/PrivateSubnet2/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "availabilityZone": "test-region-1b", + "cidrBlock": "10.0.128.0/19", + "mapPublicIpOnLaunch": false, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "Private" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Private" + }, + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC/PrivateSubnet2" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", + "version": "2.120.0" + } + }, + "Acl": { + "id": "Acl", + "path": "RedshiftServerlessStack/VPC/PrivateSubnet2/Acl", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "2.120.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "RedshiftServerlessStack/VPC/PrivateSubnet2/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "tags": [ + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC/PrivateSubnet2" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", + "version": "2.120.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "RedshiftServerlessStack/VPC/PrivateSubnet2/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" + }, + "subnetId": { + "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", + "version": "2.120.0" + } + }, + "DefaultRoute": { + "id": "DefaultRoute", + "path": "RedshiftServerlessStack/VPC/PrivateSubnet2/DefaultRoute", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Route", + "aws:cdk:cloudformation:props": { + "destinationCidrBlock": "0.0.0.0/0", + "natGatewayId": { + "Ref": "VPCPublicSubnet2NATGateway3C070193" + }, + "routeTableId": { + "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", + "version": "2.120.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.PrivateSubnet", + "version": "2.120.0" + } + }, + "PrivateSubnet3": { + "id": "PrivateSubnet3", + "path": "RedshiftServerlessStack/VPC/PrivateSubnet3", + "children": { + "Subnet": { + "id": "Subnet", + "path": "RedshiftServerlessStack/VPC/PrivateSubnet3/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "availabilityZone": "test-region-1c", + "cidrBlock": "10.0.160.0/19", + "mapPublicIpOnLaunch": false, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "Private" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Private" + }, + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC/PrivateSubnet3" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", + "version": "2.120.0" + } + }, + "Acl": { + "id": "Acl", + "path": "RedshiftServerlessStack/VPC/PrivateSubnet3/Acl", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "2.120.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "RedshiftServerlessStack/VPC/PrivateSubnet3/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "tags": [ + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC/PrivateSubnet3" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", + "version": "2.120.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "RedshiftServerlessStack/VPC/PrivateSubnet3/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "VPCPrivateSubnet3RouteTable192186F8" + }, + "subnetId": { + "Ref": "VPCPrivateSubnet3Subnet3EDCD457" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", + "version": "2.120.0" + } + }, + "DefaultRoute": { + "id": "DefaultRoute", + "path": "RedshiftServerlessStack/VPC/PrivateSubnet3/DefaultRoute", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Route", + "aws:cdk:cloudformation:props": { + "destinationCidrBlock": "0.0.0.0/0", + "natGatewayId": { + "Ref": "VPCPublicSubnet3NATGatewayD3048F5C" + }, + "routeTableId": { + "Ref": "VPCPrivateSubnet3RouteTable192186F8" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", + "version": "2.120.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.PrivateSubnet", + "version": "2.120.0" + } + }, + "IGW": { + "id": "IGW", + "path": "RedshiftServerlessStack/VPC/IGW", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::InternetGateway", + "aws:cdk:cloudformation:props": { + "tags": [ + { + "key": "Name", + "value": "RedshiftServerlessStack/VPC" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnInternetGateway", + "version": "2.120.0" + } + }, + "VPCGW": { + "id": "VPCGW", + "path": "RedshiftServerlessStack/VPC/VPCGW", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::VPCGatewayAttachment", + "aws:cdk:cloudformation:props": { + "internetGatewayId": { + "Ref": "VPCIGWB7E252D3" + }, + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnVPCGatewayAttachment", + "version": "2.120.0" + } + }, + "RestrictDefaultSecurityGroupCustomResource": { + "id": "RestrictDefaultSecurityGroupCustomResource", + "path": "RedshiftServerlessStack/VPC/RestrictDefaultSecurityGroupCustomResource", + "children": { + "Default": { + "id": "Default", + "path": "RedshiftServerlessStack/VPC/RestrictDefaultSecurityGroupCustomResource/Default", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "2.120.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.CustomResource", + "version": "2.120.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.Vpc", + "version": "2.120.0" + } + }, + "Custom::VpcRestrictDefaultSGCustomResourceProvider": { + "id": "Custom::VpcRestrictDefaultSGCustomResourceProvider", + "path": "RedshiftServerlessStack/Custom::VpcRestrictDefaultSGCustomResourceProvider", + "children": { + "Staging": { + "id": "Staging", + "path": "RedshiftServerlessStack/Custom::VpcRestrictDefaultSGCustomResourceProvider/Staging", + "constructInfo": { + "fqn": "aws-cdk-lib.AssetStaging", + "version": "2.120.0" + } + }, + "Role": { + "id": "Role", + "path": "RedshiftServerlessStack/Custom::VpcRestrictDefaultSGCustomResourceProvider/Role", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "2.120.0" + } + }, + "Handler": { + "id": "Handler", + "path": "RedshiftServerlessStack/Custom::VpcRestrictDefaultSGCustomResourceProvider/Handler", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "2.120.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.CustomResourceProviderBase", + "version": "2.120.0" + } + }, + "DefaultRole": { + "id": "DefaultRole", + "path": "RedshiftServerlessStack/DefaultRole", + "children": { + "ImportDefaultRole": { + "id": "ImportDefaultRole", + "path": "RedshiftServerlessStack/DefaultRole/ImportDefaultRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "2.120.0" + } + }, + "Resource": { + "id": "Resource", + "path": "RedshiftServerlessStack/DefaultRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "redshift.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnRole", + "version": "2.120.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Role", + "version": "2.120.0" + } + }, + "AnotherRole": { + "id": "AnotherRole", + "path": "RedshiftServerlessStack/AnotherRole", + "children": { + "ImportAnotherRole": { + "id": "ImportAnotherRole", + "path": "RedshiftServerlessStack/AnotherRole/ImportAnotherRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "2.120.0" + } + }, + "Resource": { + "id": "Resource", + "path": "RedshiftServerlessStack/AnotherRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "redshift.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnRole", + "version": "2.120.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Role", + "version": "2.120.0" + } + }, + "Namespace": { + "id": "Namespace", + "path": "RedshiftServerlessStack/Namespace", + "children": { + "Resource": { + "id": "Resource", + "path": "RedshiftServerlessStack/Namespace/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::RedshiftServerless::Namespace", + "aws:cdk:cloudformation:props": { + "adminUsername": "adminuser", + "adminUserPassword": "adminUserPassword123", + "dbName": "mydatabase", + "defaultIamRoleArn": { + "Fn::GetAtt": [ + "DefaultRoleEFEF8FA6", + "Arn" + ] + }, + "iamRoles": [ + { + "Fn::GetAtt": [ + "DefaultRoleEFEF8FA6", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "AnotherRoleE13C44E8", + "Arn" + ] + } + ], + "logExports": [ + "userlog", + "connectionlog", + "useractivitylog" + ], + "namespaceName": "redshiftserverlessstacknamespace96a02cb7" + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_redshiftserverless.CfnNamespace", + "version": "2.120.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "2.120.0" + } + }, + "WorkGroup": { + "id": "WorkGroup", + "path": "RedshiftServerlessStack/WorkGroup", + "children": { + "SecurityGroup": { + "id": "SecurityGroup", + "path": "RedshiftServerlessStack/WorkGroup/SecurityGroup", + "children": { + "Resource": { + "id": "Resource", + "path": "RedshiftServerlessStack/WorkGroup/SecurityGroup/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SecurityGroup", + "aws:cdk:cloudformation:props": { + "groupDescription": "Automatic generated security group for Redshift Serverless Security Group", + "securityGroupEgress": [ + { + "cidrIp": "0.0.0.0/0", + "description": "Allow all outbound traffic by default", + "ipProtocol": "-1" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSecurityGroup", + "version": "2.120.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.SecurityGroup", + "version": "2.120.0" + } + }, + "Resource": { + "id": "Resource", + "path": "RedshiftServerlessStack/WorkGroup/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::RedshiftServerless::Workgroup", + "aws:cdk:cloudformation:props": { + "baseCapacity": 8, + "configParameters": [ + { + "parameterKey": "datestyle", + "parameterValue": "ISO, MDY" + }, + { + "parameterKey": "enable_user_activity_logging", + "parameterValue": "true" + }, + { + "parameterKey": "query_group", + "parameterValue": "default" + }, + { + "parameterKey": "require_ssl", + "parameterValue": "true" + }, + { + "parameterKey": "search_path", + "parameterValue": "$user, public" + }, + { + "parameterKey": "max_query_execution_time", + "parameterValue": "14440" + } + ], + "enhancedVpcRouting": true, + "namespaceName": { + "Fn::GetAtt": [ + "Namespace9B63B8C8", + "Namespace.NamespaceName" + ] + }, + "port": 5432, + "publiclyAccessible": true, + "securityGroupIds": [ + { + "Fn::GetAtt": [ + "WorkGroupSecurityGroup82E81D37", + "GroupId" + ] + } + ], + "subnetIds": [ + { + "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + }, + { + "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" + }, + { + "Ref": "VPCPrivateSubnet3Subnet3EDCD457" + } + ], + "workgroupName": "redshiftserverlessstackworkgroupcfbe5e7c" + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_redshiftserverless.CfnWorkgroup", + "version": "2.120.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "2.120.0" + } + }, + "endpointAddress": { + "id": "endpointAddress", + "path": "RedshiftServerlessStack/endpointAddress", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnOutput", + "version": "2.120.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "RedshiftServerlessStack/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "2.120.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "RedshiftServerlessStack/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "2.120.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "2.120.0" + } + }, + "RedshiftServerless": { + "id": "RedshiftServerless", + "path": "RedshiftServerless", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "RedshiftServerless/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "RedshiftServerless/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "RedshiftServerless/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "RedshiftServerless/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "2.120.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "RedshiftServerless/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "2.120.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "2.120.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTestCase", + "version": "2.120.0-alpha.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTest", + "version": "2.120.0-alpha.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.App", + "version": "2.120.0" + } + } +} \ No newline at end of file diff --git a/test/aws-redshiftserverless/workgroup.test.ts b/test/aws-redshiftserverless/workgroup.test.ts index 354133f..70974f6 100644 --- a/test/aws-redshiftserverless/workgroup.test.ts +++ b/test/aws-redshiftserverless/workgroup.test.ts @@ -41,7 +41,12 @@ describe('Redshift Serverless Workgroup', () => { new Workgroup(stack, 'Workgroup', { baseCapacity: 8, configParameters: { - aaa: 'aaa', + datestyle: 'ISO, MDY', + enable_user_activity_logging: 'true', + query_group: 'default', + require_ssl: 'true', + search_path: '$user, public', + max_query_execution_time: '14440', }, enhancedVpcRouting: true, namespace, @@ -56,6 +61,20 @@ describe('Redshift Serverless Workgroup', () => { }); Template.fromStack(stack).hasResourceProperties('AWS::RedshiftServerless::Workgroup', { + WorkgroupName: 'my-workgroup', + NamespaceName: stack.resolve(namespace.namespaceName), + BaseCapacity: 8, + ConfigParameters: [ + { ParameterKey: 'datestyle', ParameterValue: 'ISO, MDY' }, + { ParameterKey: 'enable_user_activity_logging', ParameterValue: 'true' }, + { ParameterKey: 'query_group', ParameterValue: 'default' }, + { ParameterKey: 'require_ssl', ParameterValue: 'true' }, + { ParameterKey: 'search_path', ParameterValue: '$user, public' }, + { ParameterKey: 'max_query_execution_time', ParameterValue: '14440' }, + ], + EnhancedVpcRouting: true, + Port: 5440, + PubliclyAccessible: true, SecurityGroupIds: [stack.resolve(securityGroup.securityGroupId)], SubnetIds: [ { Ref: 'VPCPrivateSubnet1Subnet8BCA10E0' }, From 63aca7a3fd70acd3ae549fa66ff825ea27d99020 Mon Sep 17 00:00:00 2001 From: maz Date: Thu, 12 Sep 2024 22:37:14 +0900 Subject: [PATCH 07/29] add README --- src/aws-redshiftserverless/README.md | 97 +++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) diff --git a/src/aws-redshiftserverless/README.md b/src/aws-redshiftserverless/README.md index 6e155c8..43298ae 100644 --- a/src/aws-redshiftserverless/README.md +++ b/src/aws-redshiftserverless/README.md @@ -2,4 +2,99 @@ Constructs for thw Amazon Redshift Serverlss # Redshift Serverless CDK Construct -WIP \ No newline at end of file +## Overview + +The `Namespace` construct and the `Workgroup` construct facilitate the creation and management of [Redshift Serverless Workgroups and namespaces](https://docs.aws.amazon.com/redshift/latest/mgmt/serverless-workgroup-namespace.html) within AWS CDK applications. + +## Usage + +Import the necessary classes from AWS CDK and this construct and create a VPC for the workgroup: + +```ts +import { App, Stack } from 'aws-cdk-lib'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import { Namespace, Workgroup } from '@open-constructs/aws-cdk/aws-redshiftserverless'; + +const app = new App(); +const stack = new Stack(app, 'RedshiftServerlessStack',{ + account: '012345678901' + region: 'us-east-1', +}); +const vpc = new ec2.Vpc(stack, 'MyVpc'); +``` + +**Note** If you want to use `Vpc` Construct to create a VPC for `Workgroup`, you must specify `account` and `region` in `Stack`. +`Workgroup` needs at least three subnets, and they must span across three Availability Zones. + +The environment-agnostic stacks will be created with access to only 2 AZs (Ref: [`maxAzs` property docs](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ec2.Vpc.html#maxazs)) + +For more infomation about Redshift Serverles's limitations, see [Considerations when using Amazon Redshift Serverless](https://docs.aws.amazon.com/redshift/latest/mgmt/serverless-usage-considerations.html). + +### Basic Example + +Here's how you can create a namespace and a workgroup: + +```ts +import { SecretValue } from 'aws-cdk-lib'; +import * as iam from 'aws-cdk-lib/aws-iam'; +declare const defaultIamRole: iam.IRole; +declare const anotherIamRole: iam.IRole; + +const namespace = new redshiftserverless.Namespace(stack, 'Namespace', { + namespaceName: 'my-namespace', + defaultIamRole: myIamRole, // Specify a default IAM role + iamRoles: [defaultIamRole, anotherIamRole], // Assign IAM roles list which must include default IAM Role +}); + +const workgroup = new redshiftserverless.Workgroup(stack, 'MyWorkgroup', { + workgroupName: 'my-workgroup', + namespace, + vpc, +}); +``` + +### Advanced Example + +Creating a namespace and a workgroup with custom settings: + +```ts + +declare const workgroupSecurityGroup: ec2.ISecurityGroup; + + +const namespace = new redshiftserverless.Namespace(stack, 'MyCustomNamespace', { + namespaceName: 'my-custom-namespace', + dbName: 'mydb', // Spacify user-defined database name + adminUsername: 'admin', // Specify user-defined admin username + adminUserpassword: SecretValue.unsafePlainText('My-password-123!'), // Spacify user-defined admin password + logExports: [redshiftserverless.LogExport.USER_LOG], // Log export settings +}); + +const workgroup = new redshiftserverless.Workgroup(stack, 'MyCustomWorkgroup', { + workgroupName: 'my-custom-workgroup', + namespace, + vpc, + baseCapacity: 32, // Specify Base Capacity uses to serve queries + securityGroups: [workgroupSecurityGroup], // Specify user-defined security groups +}); +``` + +### Import an existing endpoint: +You can import existing namespaces and workgroups: + +```ts +declare const securityGroup: ec2.ISecurityGroup; + +const importedNamespace = redshiftserverless.Namespace.fromNamespaceAttributes(stack, 'ImportedNamespace', { + namespaceId: 'my-namespace-id', + namespaceName: 'my-namespace-name', +}); + +const importedWorkgroup = redshiftserverless.Workgroup.fromWorkgroupAttributes(stack, 'ImportedWorkgroup', { + workgroupName: 'my-workgroup', + workgroupId: 'my-workgroup-id', + endpointAddress: 'my-workgroup.endpoint.com', + port: 5439, + securityGroups: [securityGroup], +}); +``` From 3b718774c7ea4d1aaccbd71379e71c6448de570f Mon Sep 17 00:00:00 2001 From: maz Date: Sat, 14 Sep 2024 15:16:32 +0900 Subject: [PATCH 08/29] update baseCapacity --- API.md | 6 +++++ src/aws-redshiftserverless/workgroup.ts | 17 ++++++++++++-- test/aws-redshiftserverless/workgroup.test.ts | 22 +++++++++++++++++-- 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/API.md b/API.md index 8771c84..655ea51 100644 --- a/API.md +++ b/API.md @@ -1584,6 +1584,12 @@ public readonly baseCapacity: number; The base compute capacity of the workgroup in Redshift Processing Units (RPUs). +You can adjust the Base capacity setting from 8 RPUs to 512 RPUs in units of 8. + +Also you can increment or decrement RPUs in units of 32 when setting a base capacity between 512-1024. + +> [https://docs.aws.amazon.com/redshift/latest/mgmt/serverless-capacity.html](https://docs.aws.amazon.com/redshift/latest/mgmt/serverless-capacity.html) + --- ##### `configParameters`Optional diff --git a/src/aws-redshiftserverless/workgroup.ts b/src/aws-redshiftserverless/workgroup.ts index 966a65b..46c653a 100644 --- a/src/aws-redshiftserverless/workgroup.ts +++ b/src/aws-redshiftserverless/workgroup.ts @@ -45,7 +45,12 @@ export interface WorkgroupProps { /** * The base compute capacity of the workgroup in Redshift Processing Units (RPUs). * + * You can adjust the Base capacity setting from 8 RPUs to 512 RPUs in units of 8. + * Also you can increment or decrement RPUs in units of 32 when setting a base capacity between 512-1024. + * * @default 128 + * + * @see https://docs.aws.amazon.com/redshift/latest/mgmt/serverless-capacity.html */ readonly baseCapacity?: number; @@ -285,8 +290,16 @@ export class Workgroup extends Resource implements IWorkgroup { const baseCapacity = this.props.baseCapacity; if (!Token.isUnresolved(baseCapacity) && baseCapacity !== undefined) { - if (baseCapacity < 8 || baseCapacity > 512 || baseCapacity % 8 !== 0) { - throw new Error(`\`baseCapacity\` must be between 8 and 512 in units of 8, got: ${baseCapacity}.`); + if (baseCapacity < 8 || baseCapacity > 1024) { + throw new Error(`\`baseCapacity\` must be between 8 and 1024, got: ${baseCapacity}.`); + } + + if (8 <= baseCapacity && baseCapacity <= 512 && baseCapacity % 8 !== 0) { + throw new Error(`\`baseCapacity\` must be units of 8 between 8 and 512, got: ${baseCapacity}.`); + } + + if (512 <= baseCapacity && baseCapacity <= 1024 && baseCapacity % 32 !== 0) { + throw new Error(`\`baseCapacity\` must be units of 32 between 512 and 1024, got: ${baseCapacity}.`); } } } diff --git a/test/aws-redshiftserverless/workgroup.test.ts b/test/aws-redshiftserverless/workgroup.test.ts index 70974f6..c987537 100644 --- a/test/aws-redshiftserverless/workgroup.test.ts +++ b/test/aws-redshiftserverless/workgroup.test.ts @@ -118,13 +118,31 @@ describe('Redshift Serverless Workgroup', () => { }); describe('validateCapacity test', () => { - test.each([0, 520, 15])('throws when baseCapacity is invalid, got %d', baseCapacity => { + test.each([0, 1056])('throws when baseCapacity is out of range, got %d', baseCapacity => { expect(() => { new Workgroup(stack, 'Workgroup', { baseCapacity, vpc, }); - }).toThrow(`\`baseCapacity\` must be between 8 and 512 in units of 8, got: ${baseCapacity}.`); + }).toThrow(`\`baseCapacity\` must be between 8 and 1024, got: ${baseCapacity}.`); + }); + + test('throws when baseCapacity is not units of 8 between 8 and 512', () => { + expect(() => { + new Workgroup(stack, 'Workgroup', { + baseCapacity: 15, + vpc, + }); + }).toThrow('`baseCapacity` must be units of 8 between 8 and 512, got: 15.'); + }); + + test('throws when baseCapacity is not units of 32 between 512 and 1024', () => { + expect(() => { + new Workgroup(stack, 'Workgroup', { + baseCapacity: 520, + vpc, + }); + }).toThrow('`baseCapacity` must be units of 32 between 512 and 1024, got: 520.'); }); }); From a5a62c58bd7b6c46e64232975f69716aee3fdd78 Mon Sep 17 00:00:00 2001 From: maz Date: Sun, 15 Sep 2024 22:44:42 +0900 Subject: [PATCH 09/29] update docs --- API.md | 1 - 1 file changed, 1 deletion(-) diff --git a/API.md b/API.md index cc14d5d..b185ab9 100644 --- a/API.md +++ b/API.md @@ -1675,7 +1675,6 @@ public readonly baseCapacity: number; The base compute capacity of the workgroup in Redshift Processing Units (RPUs). You can adjust the Base capacity setting from 8 RPUs to 512 RPUs in units of 8. - Also you can increment or decrement RPUs in units of 32 when setting a base capacity between 512-1024. > [https://docs.aws.amazon.com/redshift/latest/mgmt/serverless-capacity.html](https://docs.aws.amazon.com/redshift/latest/mgmt/serverless-capacity.html) From 9c7680d4b0aff129cede8cc734bf2628bb8fb70a Mon Sep 17 00:00:00 2001 From: maz Date: Fri, 27 Sep 2024 10:57:49 +0900 Subject: [PATCH 10/29] incorporate review comments --- src/aws-redshiftserverless/namespace.ts | 22 ++++++----- src/aws-redshiftserverless/workgroup.ts | 52 ++++++++++++++----------- 2 files changed, 42 insertions(+), 32 deletions(-) diff --git a/src/aws-redshiftserverless/namespace.ts b/src/aws-redshiftserverless/namespace.ts index cce68ce..938ca94 100644 --- a/src/aws-redshiftserverless/namespace.ts +++ b/src/aws-redshiftserverless/namespace.ts @@ -198,15 +198,7 @@ export class Namespace extends Resource implements INamespace { this.validateDefaultIamRole(); this.validateNamespaceName(); - const namespace = this.createNamespace(); - - this.namespaceArn = namespace.attrNamespaceNamespaceArn; - this.namespaceName = namespace.attrNamespaceNamespaceName; - this.namespaceId = namespace.attrNamespaceNamespaceId; - } - - protected createNamespace(): aws_redshiftserverless.CfnNamespace { - return new aws_redshiftserverless.CfnNamespace(this, 'Resource', { + const namespace = this.createNamespace(this, 'Resource', { adminUsername: this.props.adminUsername, adminUserPassword: this.props.adminUserPassword?.unsafeUnwrap(), dbName: this.props.dbName, @@ -218,6 +210,18 @@ export class Namespace extends Resource implements INamespace { logExports: this.props.logExports, namespaceName: this.physicalName, }); + + this.namespaceArn = namespace.attrNamespaceNamespaceArn; + this.namespaceName = namespace.attrNamespaceNamespaceName; + this.namespaceId = namespace.attrNamespaceNamespaceId; + } + + protected createNamespace( + scope: Construct, + id: string, + props: aws_redshiftserverless.CfnNamespaceProps, + ): aws_redshiftserverless.CfnNamespace { + return new aws_redshiftserverless.CfnNamespace(scope, id, props); } /** diff --git a/src/aws-redshiftserverless/workgroup.ts b/src/aws-redshiftserverless/workgroup.ts index 46c653a..48606c4 100644 --- a/src/aws-redshiftserverless/workgroup.ts +++ b/src/aws-redshiftserverless/workgroup.ts @@ -229,9 +229,16 @@ export class Workgroup extends Resource implements IWorkgroup { }); this.props = props; - this.securityGroups = props.securityGroups ?? [this.createSecurityGroup()]; - - this.connections = this.createConnections(); + this.securityGroups = props.securityGroups ?? [ + this.createSecurityGroup(this, 'SecurityGroup', { + vpc: this.props.vpc, + description: 'Automatic generated security group for Redshift Serverless Security Group', + }), + ]; + + this.connections = new aws_ec2.Connections({ + securityGroups: this.securityGroups, + }); this.vpcSubnets = props.vpcSubnets ?? { subnetType: aws_ec2.SubnetType.PRIVATE_WITH_EGRESS, @@ -242,17 +249,7 @@ export class Workgroup extends Resource implements IWorkgroup { this.validatePort(); this.validateSubnet(); - const workgroup = this.createWorkgroup(); - - this.workgroupArn = workgroup.attrWorkgroupWorkgroupArn; - this.workgroupName = workgroup.attrWorkgroupWorkgroupName; - this.workgroupId = workgroup.attrWorkgroupWorkgroupId; - this.endpointAddress = workgroup.attrWorkgroupEndpointAddress; - this.port = workgroup.attrWorkgroupEndpointPort; - } - - protected createWorkgroup(): aws_redshiftserverless.CfnWorkgroup { - return new aws_redshiftserverless.CfnWorkgroup(this, 'Resource', { + const workgroup = this.createWorkgroup(this, 'Resource', { baseCapacity: this.props.baseCapacity, configParameters: this.props.configParameters ? Object.entries(this.props.configParameters).map(([key, value]) => ({ @@ -268,19 +265,28 @@ export class Workgroup extends Resource implements IWorkgroup { subnetIds: Lazy.list({ produce: () => this.props.vpc.selectSubnets(this.vpcSubnets).subnetIds }), workgroupName: this.physicalName, }); + + this.workgroupArn = workgroup.attrWorkgroupWorkgroupArn; + this.workgroupName = workgroup.attrWorkgroupWorkgroupName; + this.workgroupId = workgroup.attrWorkgroupWorkgroupId; + this.endpointAddress = workgroup.attrWorkgroupEndpointAddress; + this.port = workgroup.attrWorkgroupEndpointPort; } - protected createSecurityGroup(): aws_ec2.SecurityGroup { - return new aws_ec2.SecurityGroup(this, 'SecurityGroup', { - vpc: this.props.vpc, - description: 'Automatic generated security group for Redshift Serverless Security Group', - }); + protected createWorkgroup( + scope: Construct, + id: string, + props: aws_redshiftserverless.CfnWorkgroupProps, + ): aws_redshiftserverless.CfnWorkgroup { + return new aws_redshiftserverless.CfnWorkgroup(scope, id, props); } - protected createConnections(): aws_ec2.Connections { - return new aws_ec2.Connections({ - securityGroups: this.securityGroups, - }); + protected createSecurityGroup( + scope: Construct, + id: string, + props: aws_ec2.SecurityGroupProps, + ): aws_ec2.SecurityGroup { + return new aws_ec2.SecurityGroup(scope, id, props); } /** From 472df470544ac3decf7d019b1f2a0f6211fbbe7f Mon Sep 17 00:00:00 2001 From: mazyu36 Date: Sat, 28 Sep 2024 20:46:17 +0900 Subject: [PATCH 11/29] Update src/aws-redshiftserverless/README.md Co-authored-by: Kenta Goto (k.goto) <24818752+go-to-k@users.noreply.github.com> Signed-off-by: mazyu36 --- src/aws-redshiftserverless/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aws-redshiftserverless/README.md b/src/aws-redshiftserverless/README.md index 43298ae..6189d8a 100644 --- a/src/aws-redshiftserverless/README.md +++ b/src/aws-redshiftserverless/README.md @@ -1,4 +1,4 @@ -Constructs for thw Amazon Redshift Serverlss +Constructs for the Amazon Redshift Serverlss # Redshift Serverless CDK Construct From 77db5f02b6461c88531b1763e970f76184e505a0 Mon Sep 17 00:00:00 2001 From: mazyu36 Date: Sat, 28 Sep 2024 20:46:31 +0900 Subject: [PATCH 12/29] Update src/aws-redshiftserverless/README.md Co-authored-by: Kenta Goto (k.goto) <24818752+go-to-k@users.noreply.github.com> Signed-off-by: mazyu36 --- src/aws-redshiftserverless/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/aws-redshiftserverless/README.md b/src/aws-redshiftserverless/README.md index 6189d8a..aab0d49 100644 --- a/src/aws-redshiftserverless/README.md +++ b/src/aws-redshiftserverless/README.md @@ -58,10 +58,8 @@ const workgroup = new redshiftserverless.Workgroup(stack, 'MyWorkgroup', { Creating a namespace and a workgroup with custom settings: ```ts - declare const workgroupSecurityGroup: ec2.ISecurityGroup; - const namespace = new redshiftserverless.Namespace(stack, 'MyCustomNamespace', { namespaceName: 'my-custom-namespace', dbName: 'mydb', // Spacify user-defined database name From 2fd59074e279f546893ca52415e721e59f4854ae Mon Sep 17 00:00:00 2001 From: maz Date: Sat, 28 Sep 2024 20:49:08 +0900 Subject: [PATCH 13/29] fix name --- src/aws-redshiftserverless/namespace.ts | 2 +- src/aws-redshiftserverless/workgroup.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/aws-redshiftserverless/namespace.ts b/src/aws-redshiftserverless/namespace.ts index 938ca94..1ea15f0 100644 --- a/src/aws-redshiftserverless/namespace.ts +++ b/src/aws-redshiftserverless/namespace.ts @@ -97,7 +97,7 @@ export interface NamespaceProps { readonly logExports?: LogExport[]; /** - * The name of the cost report. + * The namespace name. */ readonly namespaceName?: string; } diff --git a/src/aws-redshiftserverless/workgroup.ts b/src/aws-redshiftserverless/workgroup.ts index 48606c4..7e9503f 100644 --- a/src/aws-redshiftserverless/workgroup.ts +++ b/src/aws-redshiftserverless/workgroup.ts @@ -104,14 +104,14 @@ export interface WorkgroupProps { readonly vpc: aws_ec2.IVpc; /** - * Where to place the workgroup within the VPC + * Where to place the workgroup within the VPC. * * @default - private subnets */ readonly vpcSubnets?: aws_ec2.SubnetSelection; /** - * The name of the cost report. + * The workgroup name. * * @default - auto generate */ From b5b58b01f573a31d6b4deb31e83ef0d4a6418b27 Mon Sep 17 00:00:00 2001 From: maz Date: Sun, 29 Sep 2024 15:27:43 +0900 Subject: [PATCH 14/29] docs updated --- src/aws-redshiftserverless/namespace.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/aws-redshiftserverless/namespace.ts b/src/aws-redshiftserverless/namespace.ts index 1ea15f0..f20d0e6 100644 --- a/src/aws-redshiftserverless/namespace.ts +++ b/src/aws-redshiftserverless/namespace.ts @@ -36,6 +36,8 @@ export interface NamespaceProps { /** * The username of the administrator for the primary database created in the namespace. * + * You must specify both adminUsername and adminUserPassword, or neither. + * * @default - no admin user */ readonly adminUsername?: string; @@ -43,6 +45,8 @@ export interface NamespaceProps { /** * The password of the administrator for the primary database created in the namespace. * + * You must specify both adminUsername and adminUserPassword, or neither. + * * @default - no admin user */ readonly adminUserPassword?: SecretValue; @@ -50,7 +54,7 @@ export interface NamespaceProps { /** * The name of the primary database created in the namespace. * - * @default - dev + * @default - 'dev' */ readonly dbName?: string; @@ -64,6 +68,8 @@ export interface NamespaceProps { /** * The name of the snapshot to be created before the namespace is deleted. * + * If not specified, the final snapshot will not be taken. + * * @default - no final snapshot */ readonly finalSnapshotName?: string; @@ -71,6 +77,8 @@ export interface NamespaceProps { /** * How long days to retain the final snapshot. * + * You must set finalSnapshotName when you specify finalSnapshotRetentionPeriod. + * * @default - Retained indefinitely if finalSnapshotName is specified, otherwise no final snapshot */ readonly finalSnapshotRetentionPeriod?: number; @@ -98,6 +106,8 @@ export interface NamespaceProps { /** * The namespace name. + * + * @default - auto generate */ readonly namespaceName?: string; } From 1f6ddd6309fe135ace8f45b157321eb247571e35 Mon Sep 17 00:00:00 2001 From: maz Date: Sun, 29 Sep 2024 16:16:58 +0900 Subject: [PATCH 15/29] add addIamRole method --- API.md | 36 ++++++++++++-- src/aws-redshiftserverless/namespace.ts | 18 ++++++- .../integ.redshift-serverless.ts | 6 +++ .../RedshiftServerlessStack.assets.json | 4 +- .../RedshiftServerlessStack.template.json | 23 +++++++++ .../manifest.json | 8 ++- .../tree.json | 49 +++++++++++++++++++ test/aws-redshiftserverless/namespace.test.ts | 30 ++++++++++++ 8 files changed, 165 insertions(+), 9 deletions(-) diff --git a/API.md b/API.md index b6a05ff..de8d90a 100644 --- a/API.md +++ b/API.md @@ -586,6 +586,7 @@ new aws_redshiftserverless.Namespace(scope: Construct, id: string, props: Namesp | --- | --- | | toString | Returns a string representation of this construct. | | applyRemovalPolicy | Apply the given removal policy to this resource. | +| addIamRole | Adds a role to the namespace. | --- @@ -619,6 +620,22 @@ account for data recovery and cleanup later (`RemovalPolicy.RETAIN`). --- +##### `addIamRole` + +```typescript +public addIamRole(role: IRole): void +``` + +Adds a role to the namespace. + +###### `role`Required + +- *Type:* aws-cdk-lib.aws_iam.IRole + +the role to add. + +--- + #### Static Functions | **Name** | **Description** | @@ -1441,7 +1458,7 @@ const namespaceProps: aws_redshiftserverless.NamespaceProps = { ... } | iamRoles | aws-cdk-lib.aws_iam.IRole[] | A list of IAM roles to associate with the namespace. | | kmsKey | aws-cdk-lib.aws_kms.IKey | A Customer Managed Key used to encrypt your data. | | logExports | @open-constructs/aws-cdk.aws_redshiftserverless.LogExport[] | The types of logs the namespace can export. | -| namespaceName | string | The name of the cost report. | +| namespaceName | string | The namespace name. | --- @@ -1456,6 +1473,8 @@ public readonly adminUsername: string; The username of the administrator for the primary database created in the namespace. +You must specify both adminUsername and adminUserPassword, or neither. + --- ##### `adminUserPassword`Optional @@ -1469,6 +1488,8 @@ public readonly adminUserPassword: SecretValue; The password of the administrator for the primary database created in the namespace. +You must specify both adminUsername and adminUserPassword, or neither. + --- ##### `dbName`Optional @@ -1478,7 +1499,7 @@ public readonly dbName: string; ``` - *Type:* string -- *Default:* dev +- *Default:* 'dev' The name of the primary database created in the namespace. @@ -1508,6 +1529,8 @@ public readonly finalSnapshotName: string; The name of the snapshot to be created before the namespace is deleted. +If not specified, the final snapshot will not be taken. + --- ##### `finalSnapshotRetentionPeriod`Optional @@ -1521,6 +1544,8 @@ public readonly finalSnapshotRetentionPeriod: number; How long days to retain the final snapshot. +You must set finalSnapshotName when you specify finalSnapshotRetentionPeriod. + --- ##### `iamRoles`Optional @@ -1569,8 +1594,9 @@ public readonly namespaceName: string; ``` - *Type:* string +- *Default:* auto generate -The name of the cost report. +The namespace name. --- @@ -1683,7 +1709,7 @@ const workgroupProps: aws_redshiftserverless.WorkgroupProps = { ... } | publiclyAccessible | boolean | A value that specifies whether the workgroup can be accessible from a public network. | | securityGroups | aws-cdk-lib.aws_ec2.ISecurityGroup[] | The name of the primary database created in the workgroup. | | vpcSubnets | aws-cdk-lib.aws_ec2.SubnetSelection | Where to place the workgroup within the VPC. | -| workgroupName | string | The name of the cost report. | +| workgroupName | string | The workgroup name. | --- @@ -1821,7 +1847,7 @@ public readonly workgroupName: string; - *Type:* string - *Default:* auto generate -The name of the cost report. +The workgroup name. --- diff --git a/src/aws-redshiftserverless/namespace.ts b/src/aws-redshiftserverless/namespace.ts index f20d0e6..1ad8ad8 100644 --- a/src/aws-redshiftserverless/namespace.ts +++ b/src/aws-redshiftserverless/namespace.ts @@ -192,6 +192,8 @@ export class Namespace extends Resource implements INamespace { private readonly props: NamespaceProps; + private readonly iamRoles: IRole[]; + constructor(scope: Construct, id: string, props: NamespaceProps) { super(scope, id, { physicalName: @@ -201,6 +203,7 @@ export class Namespace extends Resource implements INamespace { }), }); this.props = props; + this.iamRoles = props.iamRoles ?? []; this.validateAdmin(); this.validateDbName(); @@ -215,7 +218,7 @@ export class Namespace extends Resource implements INamespace { defaultIamRoleArn: this.props.defaultIamRole?.roleArn, finalSnapshotName: this.props.finalSnapshotName, finalSnapshotRetentionPeriod: this.props.finalSnapshotRetentionPeriod, - iamRoles: Lazy.list({ produce: () => this.props.iamRoles?.map(role => role.roleArn) }, { omitEmpty: true }), + iamRoles: Lazy.list({ produce: () => this.iamRoles.map(role => role.roleArn) }, { omitEmpty: true }), kmsKeyId: this.props.kmsKey?.keyId, logExports: this.props.logExports, namespaceName: this.physicalName, @@ -337,4 +340,17 @@ export class Namespace extends Resource implements INamespace { ); } } + + /** + * Adds a role to the namespace + * + * @param role the role to add + */ + public addIamRole(role: IRole): void { + if (this.iamRoles.includes(role)) { + throw new Error('An adding IAM Role is already attached to the namespace'); + } + + this.iamRoles.push(role); + } } diff --git a/test/aws-redshiftserverless/integ.redshift-serverless.ts b/test/aws-redshiftserverless/integ.redshift-serverless.ts index b9b4408..a01e2df 100644 --- a/test/aws-redshiftserverless/integ.redshift-serverless.ts +++ b/test/aws-redshiftserverless/integ.redshift-serverless.ts @@ -32,6 +32,12 @@ class RedshiftServerlessStack extends cdk.Stack { ], }); + const addRole = new Role(this, 'AddRole', { + assumedBy: new ServicePrincipal('redshift.amazonaws.com'), + }); + + namespace.addIamRole(addRole); + const workgroup = new ocf.aws_redshiftserverless.Workgroup(this, 'WorkGroup', { baseCapacity: 8, configParameters: { diff --git a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.assets.json b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.assets.json index 03955b6..4f10151 100644 --- a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.assets.json +++ b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.assets.json @@ -15,7 +15,7 @@ } } }, - "a3b55bd2a328ce07708cdc1ce9592e1dab2d3040ec254c12265c74e8e5d2ab8d": { + "2a8884775baa3e4bf727739558ab42431a52a7c219439b077c8484fad5cd293f": { "source": { "path": "RedshiftServerlessStack.template.json", "packaging": "file" @@ -23,7 +23,7 @@ "destinations": { "12345678-test-region": { "bucketName": "cdk-hnb659fds-assets-12345678-test-region", - "objectKey": "a3b55bd2a328ce07708cdc1ce9592e1dab2d3040ec254c12265c74e8e5d2ab8d.json", + "objectKey": "2a8884775baa3e4bf727739558ab42431a52a7c219439b077c8484fad5cd293f.json", "region": "test-region", "assumeRoleArn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-file-publishing-role-12345678-test-region" } diff --git a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.template.json b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.template.json index 60391d3..492d9d4 100644 --- a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.template.json +++ b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.template.json @@ -688,6 +688,12 @@ "AnotherRoleE13C44E8", "Arn" ] + }, + { + "Fn::GetAtt": [ + "AddRole65E43A1F", + "Arn" + ] } ], "LogExports": [ @@ -698,6 +704,23 @@ "NamespaceName": "redshiftserverlessstacknamespace96a02cb7" } }, + "AddRole65E43A1F": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "redshift.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, "WorkGroupSecurityGroup82E81D37": { "Type": "AWS::EC2::SecurityGroup", "Properties": { diff --git a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/manifest.json b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/manifest.json index dee486d..4da61eb 100644 --- a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/manifest.json +++ b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/manifest.json @@ -18,7 +18,7 @@ "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-deploy-role-12345678-test-region", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-cfn-exec-role-12345678-test-region", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-12345678-test-region/a3b55bd2a328ce07708cdc1ce9592e1dab2d3040ec254c12265c74e8e5d2ab8d.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-12345678-test-region/2a8884775baa3e4bf727739558ab42431a52a7c219439b077c8484fad5cd293f.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -268,6 +268,12 @@ "data": "Namespace9B63B8C8" } ], + "/RedshiftServerlessStack/AddRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "AddRole65E43A1F" + } + ], "/RedshiftServerlessStack/WorkGroup/SecurityGroup/Resource": [ { "type": "aws:cdk:logicalId", diff --git a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/tree.json b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/tree.json index accb4a4..3f15644 100644 --- a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/tree.json +++ b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/tree.json @@ -1064,6 +1064,12 @@ "AnotherRoleE13C44E8", "Arn" ] + }, + { + "Fn::GetAtt": [ + "AddRole65E43A1F", + "Arn" + ] } ], "logExports": [ @@ -1085,6 +1091,49 @@ "version": "2.120.0" } }, + "AddRole": { + "id": "AddRole", + "path": "RedshiftServerlessStack/AddRole", + "children": { + "ImportAddRole": { + "id": "ImportAddRole", + "path": "RedshiftServerlessStack/AddRole/ImportAddRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "2.120.0" + } + }, + "Resource": { + "id": "Resource", + "path": "RedshiftServerlessStack/AddRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "redshift.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnRole", + "version": "2.120.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Role", + "version": "2.120.0" + } + }, "WorkGroup": { "id": "WorkGroup", "path": "RedshiftServerlessStack/WorkGroup", diff --git a/test/aws-redshiftserverless/namespace.test.ts b/test/aws-redshiftserverless/namespace.test.ts index ed803e1..06bb95b 100644 --- a/test/aws-redshiftserverless/namespace.test.ts +++ b/test/aws-redshiftserverless/namespace.test.ts @@ -192,4 +192,34 @@ describe('Redshift Serverless Namespace', () => { }, ); }); + + describe('test addIamRole method', () => { + test('add IAM Role after creation', () => { + const namespace = new Namespace(stack, 'Namespace', {}); + + const addRole = new Role(stack, 'AddRole', { + assumedBy: new ServicePrincipal('redshift.amazonaws.com'), + }); + + namespace.addIamRole(addRole); + + Template.fromStack(stack).hasResourceProperties('AWS::RedshiftServerless::Namespace', { + IamRoles: [stack.resolve(addRole.roleArn)], + }); + }); + + test('throws when an adding IAM role is already attached to the namespace', () => { + expect(() => { + const addRole = new Role(stack, 'AddRole', { + assumedBy: new ServicePrincipal('redshift.amazonaws.com'), + }); + + const namespace = new Namespace(stack, 'Namespace', { + iamRoles: [addRole], + }); + + namespace.addIamRole(addRole); + }).toThrow('An adding IAM Role is already attached to the namespace'); + }); + }); }); From 9e2fffa6470a489d1846ce1a9460271ea06aed5b Mon Sep 17 00:00:00 2001 From: mazyu36 Date: Sun, 29 Sep 2024 20:01:57 +0900 Subject: [PATCH 16/29] Update src/aws-redshiftserverless/namespace.ts Co-authored-by: Kenta Goto (k.goto) <24818752+go-to-k@users.noreply.github.com> Signed-off-by: mazyu36 --- src/aws-redshiftserverless/namespace.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aws-redshiftserverless/namespace.ts b/src/aws-redshiftserverless/namespace.ts index 1ad8ad8..e575d72 100644 --- a/src/aws-redshiftserverless/namespace.ts +++ b/src/aws-redshiftserverless/namespace.ts @@ -45,7 +45,7 @@ export interface NamespaceProps { /** * The password of the administrator for the primary database created in the namespace. * - * You must specify both adminUsername and adminUserPassword, or neither. + * You must specify both `adminUsername` and `adminUserPassword`, or neither. * * @default - no admin user */ From 45179ab91146b01ebba5c4ccbc78fcd98d82e00e Mon Sep 17 00:00:00 2001 From: mazyu36 Date: Sun, 29 Sep 2024 20:02:07 +0900 Subject: [PATCH 17/29] Update src/aws-redshiftserverless/namespace.ts Co-authored-by: Kenta Goto (k.goto) <24818752+go-to-k@users.noreply.github.com> Signed-off-by: mazyu36 --- src/aws-redshiftserverless/namespace.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aws-redshiftserverless/namespace.ts b/src/aws-redshiftserverless/namespace.ts index e575d72..2d37509 100644 --- a/src/aws-redshiftserverless/namespace.ts +++ b/src/aws-redshiftserverless/namespace.ts @@ -36,7 +36,7 @@ export interface NamespaceProps { /** * The username of the administrator for the primary database created in the namespace. * - * You must specify both adminUsername and adminUserPassword, or neither. + * You must specify both `adminUsername` and `adminUserPassword`, or neither. * * @default - no admin user */ From 044283e6ae02d4296154db26a728458273355d7e Mon Sep 17 00:00:00 2001 From: mazyu36 Date: Sun, 29 Sep 2024 20:02:18 +0900 Subject: [PATCH 18/29] Update src/aws-redshiftserverless/namespace.ts Co-authored-by: Kenta Goto (k.goto) <24818752+go-to-k@users.noreply.github.com> Signed-off-by: mazyu36 --- src/aws-redshiftserverless/namespace.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aws-redshiftserverless/namespace.ts b/src/aws-redshiftserverless/namespace.ts index 2d37509..17f0ea3 100644 --- a/src/aws-redshiftserverless/namespace.ts +++ b/src/aws-redshiftserverless/namespace.ts @@ -77,7 +77,7 @@ export interface NamespaceProps { /** * How long days to retain the final snapshot. * - * You must set finalSnapshotName when you specify finalSnapshotRetentionPeriod. + * You must set `finalSnapshotName` when you specify `finalSnapshotRetentionPeriod`. * * @default - Retained indefinitely if finalSnapshotName is specified, otherwise no final snapshot */ From 754f8d8ce129cc75bb7679356a35850affba0ecd Mon Sep 17 00:00:00 2001 From: mazyu36 Date: Sun, 29 Sep 2024 20:02:34 +0900 Subject: [PATCH 19/29] Update src/aws-redshiftserverless/namespace.ts Co-authored-by: Kenta Goto (k.goto) <24818752+go-to-k@users.noreply.github.com> Signed-off-by: mazyu36 --- src/aws-redshiftserverless/namespace.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aws-redshiftserverless/namespace.ts b/src/aws-redshiftserverless/namespace.ts index 17f0ea3..afb56b5 100644 --- a/src/aws-redshiftserverless/namespace.ts +++ b/src/aws-redshiftserverless/namespace.ts @@ -79,7 +79,7 @@ export interface NamespaceProps { * * You must set `finalSnapshotName` when you specify `finalSnapshotRetentionPeriod`. * - * @default - Retained indefinitely if finalSnapshotName is specified, otherwise no final snapshot + * @default - Retained indefinitely if `finalSnapshotName` is specified, otherwise no final snapshot */ readonly finalSnapshotRetentionPeriod?: number; From 7ad4f6c1e3f87290020bcb1431c8b1b16d2d5a44 Mon Sep 17 00:00:00 2001 From: mazyu36 Date: Sun, 29 Sep 2024 20:03:45 +0900 Subject: [PATCH 20/29] Update src/aws-redshiftserverless/workgroup.ts Co-authored-by: Kenta Goto (k.goto) <24818752+go-to-k@users.noreply.github.com> Signed-off-by: mazyu36 --- src/aws-redshiftserverless/workgroup.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aws-redshiftserverless/workgroup.ts b/src/aws-redshiftserverless/workgroup.ts index 7e9503f..fe4337b 100644 --- a/src/aws-redshiftserverless/workgroup.ts +++ b/src/aws-redshiftserverless/workgroup.ts @@ -45,7 +45,7 @@ export interface WorkgroupProps { /** * The base compute capacity of the workgroup in Redshift Processing Units (RPUs). * - * You can adjust the Base capacity setting from 8 RPUs to 512 RPUs in units of 8. + * You can adjust the base capacity setting from 8 RPUs to 512 RPUs in units of 8. * Also you can increment or decrement RPUs in units of 32 when setting a base capacity between 512-1024. * * @default 128 From fcefdff691bcb837dce64e6b745e2907a0177dbb Mon Sep 17 00:00:00 2001 From: mazyu36 Date: Sun, 29 Sep 2024 20:04:57 +0900 Subject: [PATCH 21/29] Update src/aws-redshiftserverless/workgroup.ts Co-authored-by: Kenta Goto (k.goto) <24818752+go-to-k@users.noreply.github.com> Signed-off-by: mazyu36 --- src/aws-redshiftserverless/workgroup.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aws-redshiftserverless/workgroup.ts b/src/aws-redshiftserverless/workgroup.ts index fe4337b..467b199 100644 --- a/src/aws-redshiftserverless/workgroup.ts +++ b/src/aws-redshiftserverless/workgroup.ts @@ -66,7 +66,7 @@ export interface WorkgroupProps { * The value that specifies whether to enable enhanced virtual private cloud (VPC) routing, * which forces Amazon Redshift Serverless to route traffic through your VPC. * - * @default - false + * @default false */ readonly enhancedVpcRouting?: boolean; From 335853520d63cd76dd587077fc57f7d4b94396aa Mon Sep 17 00:00:00 2001 From: mazyu36 Date: Sun, 29 Sep 2024 20:05:07 +0900 Subject: [PATCH 22/29] Update src/aws-redshiftserverless/workgroup.ts Co-authored-by: Kenta Goto (k.goto) <24818752+go-to-k@users.noreply.github.com> Signed-off-by: mazyu36 --- src/aws-redshiftserverless/workgroup.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/aws-redshiftserverless/workgroup.ts b/src/aws-redshiftserverless/workgroup.ts index 467b199..a4c6a36 100644 --- a/src/aws-redshiftserverless/workgroup.ts +++ b/src/aws-redshiftserverless/workgroup.ts @@ -80,14 +80,14 @@ export interface WorkgroupProps { /** * The custom port to use when connecting to a workgroup. Valid port ranges are 5431-5455 and 8191-8215. * - * @default - 5439 + * @default 5439 */ readonly port?: number; /** * A value that specifies whether the workgroup can be accessible from a public network. * - * @default - false + * @default false */ readonly publiclyAccessible?: boolean; From f7dfb94e67bc1d498d32c90378d973756df747b2 Mon Sep 17 00:00:00 2001 From: mazyu36 Date: Sun, 29 Sep 2024 20:06:16 +0900 Subject: [PATCH 23/29] Update src/aws-redshiftserverless/namespace.ts Co-authored-by: Kenta Goto (k.goto) <24818752+go-to-k@users.noreply.github.com> Signed-off-by: mazyu36 --- src/aws-redshiftserverless/namespace.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aws-redshiftserverless/namespace.ts b/src/aws-redshiftserverless/namespace.ts index afb56b5..5e3493e 100644 --- a/src/aws-redshiftserverless/namespace.ts +++ b/src/aws-redshiftserverless/namespace.ts @@ -229,7 +229,7 @@ export class Namespace extends Resource implements INamespace { this.namespaceId = namespace.attrNamespaceNamespaceId; } - protected createNamespace( + protected createResource( scope: Construct, id: string, props: aws_redshiftserverless.CfnNamespaceProps, From 8898327023fe726e0ea5aac6f97251eaff7878d1 Mon Sep 17 00:00:00 2001 From: mazyu36 Date: Sun, 29 Sep 2024 20:07:42 +0900 Subject: [PATCH 24/29] Update src/aws-redshiftserverless/namespace.ts Co-authored-by: Kenta Goto (k.goto) <24818752+go-to-k@users.noreply.github.com> Signed-off-by: mazyu36 --- src/aws-redshiftserverless/namespace.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aws-redshiftserverless/namespace.ts b/src/aws-redshiftserverless/namespace.ts index 5e3493e..3aa7d0b 100644 --- a/src/aws-redshiftserverless/namespace.ts +++ b/src/aws-redshiftserverless/namespace.ts @@ -288,7 +288,7 @@ export class Namespace extends Resource implements INamespace { if (Token.isUnresolved(finalSnapshotName)) return; - if (finalSnapshotName) { + if (finalSnapshotName !== undefined) { if (!/^[a-z][a-z0-9]*(-[a-z0-9]+)*$/.test(finalSnapshotName) || finalSnapshotName.length > 255) { throw new Error( `\`finalSnapshotName\` must be between 1 and 255, consist only of lowercase alphanumeric characters or hyphens, with the first character as a letter, and it can't end with a hyphen or contain two consecutive hyphens, got: ${finalSnapshotName}.`, From 2f3bf5afaafee1398be460c8a971c8e3ef753be0 Mon Sep 17 00:00:00 2001 From: maz Date: Sun, 29 Sep 2024 20:39:06 +0900 Subject: [PATCH 25/29] incorporate review comments --- API.md | 22 +++-- src/aws-redshiftserverless/namespace.ts | 58 +++++++++----- src/aws-redshiftserverless/workgroup.ts | 33 +++++--- test/aws-redshiftserverless/namespace.test.ts | 80 ++++++++++++------- test/aws-redshiftserverless/workgroup.test.ts | 38 +++++++-- 5 files changed, 157 insertions(+), 74 deletions(-) diff --git a/API.md b/API.md index de8d90a..7d4397a 100644 --- a/API.md +++ b/API.md @@ -1473,7 +1473,7 @@ public readonly adminUsername: string; The username of the administrator for the primary database created in the namespace. -You must specify both adminUsername and adminUserPassword, or neither. +You must specify both `adminUsername` and `adminUserPassword`, or neither. --- @@ -1488,7 +1488,7 @@ public readonly adminUserPassword: SecretValue; The password of the administrator for the primary database created in the namespace. -You must specify both adminUsername and adminUserPassword, or neither. +You must specify both `adminUsername` and `adminUserPassword`, or neither. --- @@ -1516,6 +1516,8 @@ public readonly defaultIamRole: IRole; The IAM role to set as a default in the namespace. +`defaultIamRole` must be included in `iamRoles`. + --- ##### `finalSnapshotName`Optional @@ -1540,11 +1542,11 @@ public readonly finalSnapshotRetentionPeriod: number; ``` - *Type:* number -- *Default:* Retained indefinitely if finalSnapshotName is specified, otherwise no final snapshot +- *Default:* Retained indefinitely if `finalSnapshotName` is specified, otherwise no final snapshot How long days to retain the final snapshot. -You must set finalSnapshotName when you specify finalSnapshotRetentionPeriod. +You must set `finalSnapshotName` when you specify `finalSnapshotRetentionPeriod`. --- @@ -1707,7 +1709,7 @@ const workgroupProps: aws_redshiftserverless.WorkgroupProps = { ... } | namespace | @open-constructs/aws-cdk.aws_redshiftserverless.INamespace | The namespace the workgroup is associated with. | | port | number | The custom port to use when connecting to a workgroup. | | publiclyAccessible | boolean | A value that specifies whether the workgroup can be accessible from a public network. | -| securityGroups | aws-cdk-lib.aws_ec2.ISecurityGroup[] | The name of the primary database created in the workgroup. | +| securityGroups | aws-cdk-lib.aws_ec2.ISecurityGroup[] | The security groups to associate with the workgroup. | | vpcSubnets | aws-cdk-lib.aws_ec2.SubnetSelection | Where to place the workgroup within the VPC. | | workgroupName | string | The workgroup name. | @@ -1723,6 +1725,8 @@ public readonly vpc: IVpc; The VPC to place the workgroup in. +`vpc` must have at least 3 subnets, and they must span across 3 Availability Zones. + --- ##### `baseCapacity`Optional @@ -1736,7 +1740,7 @@ public readonly baseCapacity: number; The base compute capacity of the workgroup in Redshift Processing Units (RPUs). -You can adjust the Base capacity setting from 8 RPUs to 512 RPUs in units of 8. +You can adjust the base capacity setting from 8 RPUs to 512 RPUs in units of 8. Also you can increment or decrement RPUs in units of 32 when setting a base capacity between 512-1024. > [https://docs.aws.amazon.com/redshift/latest/mgmt/serverless-capacity.html](https://docs.aws.amazon.com/redshift/latest/mgmt/serverless-capacity.html) @@ -1819,9 +1823,9 @@ public readonly securityGroups: ISecurityGroup[]; ``` - *Type:* aws-cdk-lib.aws_ec2.ISecurityGroup[] -- *Default:* no database created +- *Default:* a new security group is created -The name of the primary database created in the workgroup. +The security groups to associate with the workgroup. --- @@ -1849,6 +1853,8 @@ public readonly workgroupName: string; The workgroup name. +\`workgroupName\` must be between 3 and 64 characters long, contain only lowercase letters, numbers, and hyphens. + --- ## Classes diff --git a/src/aws-redshiftserverless/namespace.ts b/src/aws-redshiftserverless/namespace.ts index 3aa7d0b..9ed5bdd 100644 --- a/src/aws-redshiftserverless/namespace.ts +++ b/src/aws-redshiftserverless/namespace.ts @@ -61,6 +61,8 @@ export interface NamespaceProps { /** * The IAM role to set as a default in the namespace. * + * `defaultIamRole` must be included in `iamRoles`. + * * @default - no default IAM role */ readonly defaultIamRole?: IRole; @@ -211,7 +213,7 @@ export class Namespace extends Resource implements INamespace { this.validateDefaultIamRole(); this.validateNamespaceName(); - const namespace = this.createNamespace(this, 'Resource', { + const namespace = this.createResource(this, 'Resource', { adminUsername: this.props.adminUsername, adminUserPassword: this.props.adminUserPassword?.unsafeUnwrap(), dbName: this.props.dbName, @@ -272,11 +274,15 @@ export class Namespace extends Resource implements INamespace { return; } - if (!/^[a-zA-Z][a-zA-Z_0-9+.@-]*$/.test(dbName) || dbName.length > 127) { + if (!/^[a-zA-Z][a-zA-Z_0-9+.@-]*$/.test(dbName)) { throw new Error( - `\`dbName\` must start with a letter, can only contain letters, numbers, and the special characters: _, +, ., @, -, and must not exceed 127 characters, got: ${dbName}.`, + `\`dbName\` must start with a letter, can only contain letters, numbers, and the special characters: _, +, ., @, -, got: ${dbName}.`, ); } + + if (dbName.length > 127) { + throw new Error(`\`dbName\` must not exceed 127 characters, got: ${dbName.length} characters.`); + } } /** @@ -289,24 +295,32 @@ export class Namespace extends Resource implements INamespace { if (Token.isUnresolved(finalSnapshotName)) return; if (finalSnapshotName !== undefined) { - if (!/^[a-z][a-z0-9]*(-[a-z0-9]+)*$/.test(finalSnapshotName) || finalSnapshotName.length > 255) { + if (!/^[a-z][a-z0-9]*(-[a-z0-9]+)*$/.test(finalSnapshotName)) { throw new Error( - `\`finalSnapshotName\` must be between 1 and 255, consist only of lowercase alphanumeric characters or hyphens, with the first character as a letter, and it can't end with a hyphen or contain two consecutive hyphens, got: ${finalSnapshotName}.`, + `\`finalSnapshotName\` must consist only of lowercase alphanumeric characters or hyphens, with the first character as a letter, and it can't end with a hyphen or contain two consecutive hyphens, got: ${finalSnapshotName}.`, ); } - } - if (!Token.isUnresolved(finalSnapshotRetentionPeriod) && finalSnapshotRetentionPeriod !== undefined) { - if (!finalSnapshotName) { - throw new Error('You must set `finalSnapshotName` when you specify `finalSnapshotRetentionPeriod`.'); + if (finalSnapshotName.length > 255) { + throw new Error( + `\`finalSnapshotName\` must not exceed 255 characters, got: ${finalSnapshotName.length} characters.`, + ); } + } + + if (Token.isUnresolved(finalSnapshotRetentionPeriod) || finalSnapshotRetentionPeriod === undefined) { + return; + } - if (finalSnapshotRetentionPeriod < 1 || finalSnapshotRetentionPeriod > 3653) { - { - throw new Error( - `\`finalSnapshotRetentionPeriod\` must be between 1 and 3653, got: ${finalSnapshotRetentionPeriod}.`, - ); - } + if (!finalSnapshotName) { + throw new Error('You must set `finalSnapshotName` when you specify `finalSnapshotRetentionPeriod`.'); + } + + if (finalSnapshotRetentionPeriod < 1 || finalSnapshotRetentionPeriod > 3653) { + { + throw new Error( + `\`finalSnapshotRetentionPeriod\` must be between 1 and 3653, got: ${finalSnapshotRetentionPeriod}.`, + ); } } } @@ -334,9 +348,15 @@ export class Namespace extends Resource implements INamespace { return; } - if (!/^[a-z0-9-]+$/.test(namespaceName) || namespaceName.length < 3 || namespaceName.length > 64) { + if (!/^[a-z0-9-]+$/.test(namespaceName)) { + throw new Error( + `\`namespaceName\` must consist only of lowercase alphanumeric characters or hyphens, got: ${namespaceName}.`, + ); + } + + if (namespaceName.length < 3 || namespaceName.length > 64) { throw new Error( - `\`namespaceName\` must be between 3 and 64 characters, consist only of lowercase alphanumeric characters or hyphens, got: ${namespaceName}.`, + `\`namespaceName\` must be between 3 and 64 characters, got: ${namespaceName.length} characters.`, ); } } @@ -348,7 +368,9 @@ export class Namespace extends Resource implements INamespace { */ public addIamRole(role: IRole): void { if (this.iamRoles.includes(role)) { - throw new Error('An adding IAM Role is already attached to the namespace'); + throw new Error( + `An adding IAM Role is already attached to the namespace, name: ${role.roleName}, ARN: ${role.roleArn}.`, + ); } this.iamRoles.push(role); diff --git a/src/aws-redshiftserverless/workgroup.ts b/src/aws-redshiftserverless/workgroup.ts index a4c6a36..6316ae1 100644 --- a/src/aws-redshiftserverless/workgroup.ts +++ b/src/aws-redshiftserverless/workgroup.ts @@ -92,14 +92,16 @@ export interface WorkgroupProps { readonly publiclyAccessible?: boolean; /** - * The name of the primary database created in the workgroup. + * The security groups to associate with the workgroup. * - * @default - no database created + * @default - a new security group is created */ readonly securityGroups?: aws_ec2.ISecurityGroup[]; /** * The VPC to place the workgroup in. + * + * `vpc` must have at least 3 subnets, and they must span across 3 Availability Zones. */ readonly vpc: aws_ec2.IVpc; @@ -113,6 +115,8 @@ export interface WorkgroupProps { /** * The workgroup name. * + * \`workgroupName\` must be between 3 and 64 characters long, contain only lowercase letters, numbers, and hyphens. + * * @default - auto generate */ readonly workgroupName?: string; @@ -249,7 +253,7 @@ export class Workgroup extends Resource implements IWorkgroup { this.validatePort(); this.validateSubnet(); - const workgroup = this.createWorkgroup(this, 'Resource', { + const workgroup = this.createResource(this, 'Resource', { baseCapacity: this.props.baseCapacity, configParameters: this.props.configParameters ? Object.entries(this.props.configParameters).map(([key, value]) => ({ @@ -261,8 +265,8 @@ export class Workgroup extends Resource implements IWorkgroup { namespaceName: this.props.namespace?.namespaceName, publiclyAccessible: this.props.publiclyAccessible, port: this.props.port, - securityGroupIds: Lazy.list({ produce: () => this.securityGroups.map(sg => sg.securityGroupId) }), - subnetIds: Lazy.list({ produce: () => this.props.vpc.selectSubnets(this.vpcSubnets).subnetIds }), + securityGroupIds: this.securityGroups.map(sg => sg.securityGroupId), + subnetIds: this.props.vpc.selectSubnets(this.vpcSubnets).subnetIds, workgroupName: this.physicalName, }); @@ -273,7 +277,7 @@ export class Workgroup extends Resource implements IWorkgroup { this.port = workgroup.attrWorkgroupEndpointPort; } - protected createWorkgroup( + protected createResource( scope: Construct, id: string, props: aws_redshiftserverless.CfnWorkgroupProps, @@ -319,9 +323,15 @@ export class Workgroup extends Resource implements IWorkgroup { return; } - if (!/^[a-z0-9-]{3,64}$/.test(workgroupName)) { + if (!/^[a-z0-9-]+$/.test(workgroupName)) { + throw new Error( + `\`workgroupName\` must contain only lowercase letters, numbers, and hyphens, got: ${workgroupName}.`, + ); + } + + if (workgroupName.length < 3 || workgroupName.length > 64) { throw new Error( - `\`workgroupName\` must be between 3 and 64 characters long, contain only lowercase letters, numbers, and hyphens, got: ${workgroupName}.`, + `\`workgroupName\` must be between 3 and 64 characters, got: ${workgroupName.length} characters.`, ); } } @@ -350,8 +360,11 @@ export class Workgroup extends Resource implements IWorkgroup { * @see https://docs.aws.amazon.com/redshift/latest/mgmt/serverless-usage-considerations.html */ private validateSubnet(): void { - if (this.props.vpc.availabilityZones.length < 3) { - throw new Error('`vpc` must have at least three subnets, and they must span across three Availability Zones.'); + const azLength = this.props.vpc.availabilityZones.length; + if (azLength < 3) { + throw new Error( + `\`vpc\` must have at least 3 subnets, and they must span across 3 Availability Zones, got: ${azLength} AZs.`, + ); } } } diff --git a/test/aws-redshiftserverless/namespace.test.ts b/test/aws-redshiftserverless/namespace.test.ts index 06bb95b..482c5e3 100644 --- a/test/aws-redshiftserverless/namespace.test.ts +++ b/test/aws-redshiftserverless/namespace.test.ts @@ -113,27 +113,39 @@ describe('Redshift Serverless Namespace', () => { dbName, }); }).toThrow( - `\`dbName\` must start with a letter, can only contain letters, numbers, and the special characters: _, +, ., @, -, and must not exceed 127 characters, got: ${dbName}.`, + `\`dbName\` must start with a letter, can only contain letters, numbers, and the special characters: _, +, ., @, -, got: ${dbName}.`, ); }); + + test('throws when dbName length is invalid, got %s', () => { + expect(() => { + new Namespace(stack, 'Namespace', { + dbName: 'a'.repeat(128), + }); + }).toThrow('`dbName` must not exceed 127 characters, got: 128 characters.'); + }); }); describe('validateFinalSnapshot test', () => { - test.each([ - '123abc', - 'UpperName', - 'invalid$name', - 'end-with-a-hyphen-', - 'two--consecutive-hyphens', - 'a'.repeat(256), - ])('throws when finalSnapshotName is invalid, got %s', finalSnapshotName => { + test.each(['123abc', 'UpperName', 'invalid$name', 'end-with-a-hyphen-', 'two--consecutive-hyphens'])( + 'throws when finalSnapshotName is invalid, got %s', + finalSnapshotName => { + expect(() => { + new Namespace(stack, 'Namespace', { + finalSnapshotName, + }); + }).toThrow( + `\`finalSnapshotName\` must consist only of lowercase alphanumeric characters or hyphens, with the first character as a letter, and it can't end with a hyphen or contain two consecutive hyphens, got: ${finalSnapshotName}.`, + ); + }, + ); + + test('throws when finalSnapshotName length is invalid, got %s', () => { expect(() => { new Namespace(stack, 'Namespace', { - finalSnapshotName, + finalSnapshotName: 'a'.repeat(256), }); - }).toThrow( - `\`finalSnapshotName\` must be between 1 and 255, consist only of lowercase alphanumeric characters or hyphens, with the first character as a letter, and it can't end with a hyphen or contain two consecutive hyphens, got: ${finalSnapshotName}.`, - ); + }).toThrow('`finalSnapshotName` must not exceed 255 characters, got: 256 characters.'); }); test('throws when finalSnapshotRetentionPeriod is set without finalSnapshotName', () => { @@ -179,18 +191,23 @@ describe('Redshift Serverless Namespace', () => { }); describe('validateNamespaceName test', () => { - test.each(['UpperName', 'invalid$name', 'a'.repeat(2), 'a'.repeat(65)])( - 'throws when namespaceName is invalid, got %s', - namespaceName => { - expect(() => { - new Namespace(stack, 'Namespace', { - namespaceName, - }); - }).toThrow( - `\`namespaceName\` must be between 3 and 64 characters, consist only of lowercase alphanumeric characters or hyphens, got: ${namespaceName}.`, - ); - }, - ); + test.each(['UpperName', 'invalid$name'])('throws when namespaceName is invalid , got %s', namespaceName => { + expect(() => { + new Namespace(stack, 'Namespace', { + namespaceName, + }); + }).toThrow( + `\`namespaceName\` must consist only of lowercase alphanumeric characters or hyphens, got: ${namespaceName}.`, + ); + }); + + test.each(['a'.repeat(2), 'a'.repeat(65)])('throws when namespaceName length is invalid, got %s', namespaceName => { + expect(() => { + new Namespace(stack, 'Namespace', { + namespaceName, + }); + }).toThrow(`\`namespaceName\` must be between 3 and 64 characters, got: ${namespaceName.length} characters.`); + }); }); describe('test addIamRole method', () => { @@ -209,17 +226,18 @@ describe('Redshift Serverless Namespace', () => { }); test('throws when an adding IAM role is already attached to the namespace', () => { - expect(() => { - const addRole = new Role(stack, 'AddRole', { - assumedBy: new ServicePrincipal('redshift.amazonaws.com'), - }); + const addRole = new Role(stack, 'AddRole', { + assumedBy: new ServicePrincipal('redshift.amazonaws.com'), + }); + expect(() => { const namespace = new Namespace(stack, 'Namespace', { iamRoles: [addRole], }); - namespace.addIamRole(addRole); - }).toThrow('An adding IAM Role is already attached to the namespace'); + }).toThrow( + `An adding IAM Role is already attached to the namespace, name: ${addRole.roleName}, ARN: ${addRole.roleArn}.`, + ); }); }); }); diff --git a/test/aws-redshiftserverless/workgroup.test.ts b/test/aws-redshiftserverless/workgroup.test.ts index c987537..e040980 100644 --- a/test/aws-redshiftserverless/workgroup.test.ts +++ b/test/aws-redshiftserverless/workgroup.test.ts @@ -147,17 +147,24 @@ describe('Redshift Serverless Workgroup', () => { }); describe('validateWorkgroupName test', () => { - test.each(['ABC', 'name with spaces', 'a'.repeat(2), 'a'.repeat(100)])( - 'throws when workgroupName is invalid, got %s', + test.each(['ABC', 'name with spaces'])('throws when workgroupName is invalid, got %s', workgroupName => { + expect(() => { + new Workgroup(stack, 'Workgroup', { + workgroupName, + vpc, + }); + }).toThrow(`\`workgroupName\` must contain only lowercase letters, numbers, and hyphens, got: ${workgroupName}.`); + }); + + test.each(['a'.repeat(2), 'a'.repeat(100)])( + 'throws when workgroupName length is invalid, got %s', workgroupName => { expect(() => { new Workgroup(stack, 'Workgroup', { workgroupName, vpc, }); - }).toThrow( - `\`workgroupName\` must be between 3 and 64 characters long, contain only lowercase letters, numbers, and hyphens, got: ${workgroupName}.`, - ); + }).toThrow(`\`workgroupName\` must be between 3 and 64 characters, got: ${workgroupName.length} characters.`); }, ); }); @@ -176,16 +183,33 @@ describe('Redshift Serverless Workgroup', () => { }); describe('validateSubnet test', () => { - test('throws when vpc has only 2 AZs', () => { + test('throws when vpc has over 3 subnets but has only 2 AZs', () => { const vpcFor2Az = new aws_ec2.Vpc(stack, 'VPCfor2Az', { maxAzs: 2, + subnetConfiguration: [ + { + cidrMask: 24, + name: 'Public', + subnetType: aws_ec2.SubnetType.PUBLIC, + }, + { + cidrMask: 24, + name: 'Private', + subnetType: aws_ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + { + cidrMask: 24, + name: 'AnotherPrivate', + subnetType: aws_ec2.SubnetType.PRIVATE_WITH_EGRESS, + }, + ], }); expect(() => { new Workgroup(stack, 'Workgroup', { vpc: vpcFor2Az, }); - }).toThrow('`vpc` must have at least three subnets, and they must span across three Availability Zones.'); + }).toThrow('`vpc` must have at least 3 subnets, and they must span across 3 Availability Zones, got: 2 AZs.'); }); }); }); From 878394ac583243efcbbe840a79cdc4a91983adbc Mon Sep 17 00:00:00 2001 From: mazyu36 Date: Tue, 1 Oct 2024 12:40:13 +0900 Subject: [PATCH 26/29] Update test/aws-redshiftserverless/workgroup.test.ts Co-authored-by: Kenta Goto (k.goto) <24818752+go-to-k@users.noreply.github.com> Signed-off-by: mazyu36 --- test/aws-redshiftserverless/workgroup.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/aws-redshiftserverless/workgroup.test.ts b/test/aws-redshiftserverless/workgroup.test.ts index e040980..16eae0d 100644 --- a/test/aws-redshiftserverless/workgroup.test.ts +++ b/test/aws-redshiftserverless/workgroup.test.ts @@ -34,7 +34,7 @@ describe('Redshift Serverless Workgroup', () => { }); }); - test('Create namsepace with maximum properties ', () => { + test('Create workgroup with maximum properties ', () => { const namespace = new Namespace(stack, 'Namespace', {}); const securityGroup = aws_ec2.SecurityGroup.fromSecurityGroupId(stack, 'SG', 'sg-123456789'); From 899b01ef86ae8eea2f01b77406b3f5505c3dd310 Mon Sep 17 00:00:00 2001 From: mazyu36 Date: Tue, 1 Oct 2024 12:40:25 +0900 Subject: [PATCH 27/29] Update src/aws-redshiftserverless/README.md Co-authored-by: Kenta Goto (k.goto) <24818752+go-to-k@users.noreply.github.com> Signed-off-by: mazyu36 --- src/aws-redshiftserverless/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/aws-redshiftserverless/README.md b/src/aws-redshiftserverless/README.md index aab0d49..952c1dc 100644 --- a/src/aws-redshiftserverless/README.md +++ b/src/aws-redshiftserverless/README.md @@ -62,9 +62,9 @@ declare const workgroupSecurityGroup: ec2.ISecurityGroup; const namespace = new redshiftserverless.Namespace(stack, 'MyCustomNamespace', { namespaceName: 'my-custom-namespace', - dbName: 'mydb', // Spacify user-defined database name + dbName: 'mydb', // Specify user-defined database name adminUsername: 'admin', // Specify user-defined admin username - adminUserpassword: SecretValue.unsafePlainText('My-password-123!'), // Spacify user-defined admin password + adminUserPassword: SecretValue.unsafePlainText('My-password-123!'), // Specify user-defined admin password logExports: [redshiftserverless.LogExport.USER_LOG], // Log export settings }); From 2a628a2613e12cf8218354841493baec7508c221 Mon Sep 17 00:00:00 2001 From: mazyu36 Date: Tue, 1 Oct 2024 12:40:39 +0900 Subject: [PATCH 28/29] Update test/aws-redshiftserverless/workgroup.test.ts Co-authored-by: Kenta Goto (k.goto) <24818752+go-to-k@users.noreply.github.com> Signed-off-by: mazyu36 --- test/aws-redshiftserverless/workgroup.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/aws-redshiftserverless/workgroup.test.ts b/test/aws-redshiftserverless/workgroup.test.ts index 16eae0d..9d6bee1 100644 --- a/test/aws-redshiftserverless/workgroup.test.ts +++ b/test/aws-redshiftserverless/workgroup.test.ts @@ -15,7 +15,7 @@ describe('Redshift Serverless Workgroup', () => { vpc = new aws_ec2.Vpc(stack, 'VPC'); }); - test('Create namsepace with minimal properties ', () => { + test('Create workgroup with minimal properties ', () => { new Workgroup(stack, 'Namespace', { vpc, }); From 31c9ae693b7111a0f35709c482f3285d2cd7d396 Mon Sep 17 00:00:00 2001 From: maz Date: Tue, 1 Oct 2024 12:58:25 +0900 Subject: [PATCH 29/29] incorporate review comments --- src/aws-redshiftserverless/namespace.ts | 4 +- ...edshift-serverless-namespace-workgroup.ts} | 4 +- ...erlessNamespaceWorkgroupStack.assets.json} | 6 +- ...lessNamespaceWorkgroupStack.template.json} | 44 ++-- ...faultTestDeployAssertE2D901CB.assets.json} | 2 +- ...ultTestDeployAssertE2D901CB.template.json} | 0 .../cdk.out | 0 .../integ.json | 14 ++ .../manifest.json | 124 +++++------ .../tree.json | 206 +++++++++--------- .../integ.json | 14 -- test/aws-redshiftserverless/namespace.test.ts | 18 +- test/aws-redshiftserverless/workgroup.test.ts | 26 ++- 13 files changed, 240 insertions(+), 222 deletions(-) rename test/aws-redshiftserverless/{integ.redshift-serverless.ts => integ.redshift-serverless-namespace-workgroup.ts} (95%) rename test/aws-redshiftserverless/{integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.assets.json => integ.redshift-serverless-namespace-workgroup.ts.snapshot/RedshiftServerlessNamespaceWorkgroupStack.assets.json} (81%) rename test/aws-redshiftserverless/{integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.template.json => integ.redshift-serverless-namespace-workgroup.ts.snapshot/RedshiftServerlessNamespaceWorkgroupStack.template.json} (91%) rename test/aws-redshiftserverless/{integ.redshift-serverless.ts.snapshot/RedshiftServerlessDefaultTestDeployAssertC5CDACEC.assets.json => integ.redshift-serverless-namespace-workgroup.ts.snapshot/RedshiftServerlessNamespaceWorkgroupTestDefaultTestDeployAssertE2D901CB.assets.json} (85%) rename test/aws-redshiftserverless/{integ.redshift-serverless.ts.snapshot/RedshiftServerlessDefaultTestDeployAssertC5CDACEC.template.json => integ.redshift-serverless-namespace-workgroup.ts.snapshot/RedshiftServerlessNamespaceWorkgroupTestDefaultTestDeployAssertE2D901CB.template.json} (100%) rename test/aws-redshiftserverless/{integ.redshift-serverless.ts.snapshot => integ.redshift-serverless-namespace-workgroup.ts.snapshot}/cdk.out (100%) create mode 100644 test/aws-redshiftserverless/integ.redshift-serverless-namespace-workgroup.ts.snapshot/integ.json rename test/aws-redshiftserverless/{integ.redshift-serverless.ts.snapshot => integ.redshift-serverless-namespace-workgroup.ts.snapshot}/manifest.json (63%) rename test/aws-redshiftserverless/{integ.redshift-serverless.ts.snapshot => integ.redshift-serverless-namespace-workgroup.ts.snapshot}/tree.json (82%) delete mode 100644 test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/integ.json diff --git a/src/aws-redshiftserverless/namespace.ts b/src/aws-redshiftserverless/namespace.ts index 9ed5bdd..0651c9a 100644 --- a/src/aws-redshiftserverless/namespace.ts +++ b/src/aws-redshiftserverless/namespace.ts @@ -368,9 +368,7 @@ export class Namespace extends Resource implements INamespace { */ public addIamRole(role: IRole): void { if (this.iamRoles.includes(role)) { - throw new Error( - `An adding IAM Role is already attached to the namespace, name: ${role.roleName}, ARN: ${role.roleArn}.`, - ); + throw new Error(`An adding IAM Role is already attached to the namespace, ARN: ${role.roleArn}.`); } this.iamRoles.push(role); diff --git a/test/aws-redshiftserverless/integ.redshift-serverless.ts b/test/aws-redshiftserverless/integ.redshift-serverless-namespace-workgroup.ts similarity index 95% rename from test/aws-redshiftserverless/integ.redshift-serverless.ts rename to test/aws-redshiftserverless/integ.redshift-serverless-namespace-workgroup.ts index a01e2df..8f6cc7a 100644 --- a/test/aws-redshiftserverless/integ.redshift-serverless.ts +++ b/test/aws-redshiftserverless/integ.redshift-serverless-namespace-workgroup.ts @@ -64,9 +64,9 @@ const env = { region: process.env.CDK_INTEG_REGION || process.env.CDK_DEFAULT_REGION, }; -const testCase = new RedshiftServerlessStack(app, 'RedshiftServerlessStack', { env }); +const testCase = new RedshiftServerlessStack(app, 'RedshiftServerlessNamespaceWorkgroupStack', { env }); -new IntegTest(app, 'RedshiftServerless', { +new IntegTest(app, 'RedshiftServerlessNamespaceWorkgroupTest', { testCases: [testCase], enableLookups: true, stackUpdateWorkflow: false, diff --git a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.assets.json b/test/aws-redshiftserverless/integ.redshift-serverless-namespace-workgroup.ts.snapshot/RedshiftServerlessNamespaceWorkgroupStack.assets.json similarity index 81% rename from test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.assets.json rename to test/aws-redshiftserverless/integ.redshift-serverless-namespace-workgroup.ts.snapshot/RedshiftServerlessNamespaceWorkgroupStack.assets.json index 4f10151..648dee7 100644 --- a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.assets.json +++ b/test/aws-redshiftserverless/integ.redshift-serverless-namespace-workgroup.ts.snapshot/RedshiftServerlessNamespaceWorkgroupStack.assets.json @@ -15,15 +15,15 @@ } } }, - "2a8884775baa3e4bf727739558ab42431a52a7c219439b077c8484fad5cd293f": { + "4a8832c353aec7c387162f2dce3cb6290e83346da06b1ecbcc2f4b8a5794133d": { "source": { - "path": "RedshiftServerlessStack.template.json", + "path": "RedshiftServerlessNamespaceWorkgroupStack.template.json", "packaging": "file" }, "destinations": { "12345678-test-region": { "bucketName": "cdk-hnb659fds-assets-12345678-test-region", - "objectKey": "2a8884775baa3e4bf727739558ab42431a52a7c219439b077c8484fad5cd293f.json", + "objectKey": "4a8832c353aec7c387162f2dce3cb6290e83346da06b1ecbcc2f4b8a5794133d.json", "region": "test-region", "assumeRoleArn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-file-publishing-role-12345678-test-region" } diff --git a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.template.json b/test/aws-redshiftserverless/integ.redshift-serverless-namespace-workgroup.ts.snapshot/RedshiftServerlessNamespaceWorkgroupStack.template.json similarity index 91% rename from test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.template.json rename to test/aws-redshiftserverless/integ.redshift-serverless-namespace-workgroup.ts.snapshot/RedshiftServerlessNamespaceWorkgroupStack.template.json index 492d9d4..ed5aa2b 100644 --- a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessStack.template.json +++ b/test/aws-redshiftserverless/integ.redshift-serverless-namespace-workgroup.ts.snapshot/RedshiftServerlessNamespaceWorkgroupStack.template.json @@ -10,7 +10,7 @@ "Tags": [ { "Key": "Name", - "Value": "RedshiftServerlessStack/VPC" + "Value": "RedshiftServerlessNamespaceWorkgroupStack/VPC" } ] } @@ -32,7 +32,7 @@ }, { "Key": "Name", - "Value": "RedshiftServerlessStack/VPC/PublicSubnet1" + "Value": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet1" } ], "VpcId": { @@ -46,7 +46,7 @@ "Tags": [ { "Key": "Name", - "Value": "RedshiftServerlessStack/VPC/PublicSubnet1" + "Value": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet1" } ], "VpcId": { @@ -87,7 +87,7 @@ "Tags": [ { "Key": "Name", - "Value": "RedshiftServerlessStack/VPC/PublicSubnet1" + "Value": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet1" } ] } @@ -107,7 +107,7 @@ "Tags": [ { "Key": "Name", - "Value": "RedshiftServerlessStack/VPC/PublicSubnet1" + "Value": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet1" } ] }, @@ -133,7 +133,7 @@ }, { "Key": "Name", - "Value": "RedshiftServerlessStack/VPC/PublicSubnet2" + "Value": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet2" } ], "VpcId": { @@ -147,7 +147,7 @@ "Tags": [ { "Key": "Name", - "Value": "RedshiftServerlessStack/VPC/PublicSubnet2" + "Value": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet2" } ], "VpcId": { @@ -188,7 +188,7 @@ "Tags": [ { "Key": "Name", - "Value": "RedshiftServerlessStack/VPC/PublicSubnet2" + "Value": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet2" } ] } @@ -208,7 +208,7 @@ "Tags": [ { "Key": "Name", - "Value": "RedshiftServerlessStack/VPC/PublicSubnet2" + "Value": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet2" } ] }, @@ -234,7 +234,7 @@ }, { "Key": "Name", - "Value": "RedshiftServerlessStack/VPC/PublicSubnet3" + "Value": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet3" } ], "VpcId": { @@ -248,7 +248,7 @@ "Tags": [ { "Key": "Name", - "Value": "RedshiftServerlessStack/VPC/PublicSubnet3" + "Value": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet3" } ], "VpcId": { @@ -289,7 +289,7 @@ "Tags": [ { "Key": "Name", - "Value": "RedshiftServerlessStack/VPC/PublicSubnet3" + "Value": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet3" } ] } @@ -309,7 +309,7 @@ "Tags": [ { "Key": "Name", - "Value": "RedshiftServerlessStack/VPC/PublicSubnet3" + "Value": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet3" } ] }, @@ -335,7 +335,7 @@ }, { "Key": "Name", - "Value": "RedshiftServerlessStack/VPC/PrivateSubnet1" + "Value": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet1" } ], "VpcId": { @@ -349,7 +349,7 @@ "Tags": [ { "Key": "Name", - "Value": "RedshiftServerlessStack/VPC/PrivateSubnet1" + "Value": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet1" } ], "VpcId": { @@ -397,7 +397,7 @@ }, { "Key": "Name", - "Value": "RedshiftServerlessStack/VPC/PrivateSubnet2" + "Value": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet2" } ], "VpcId": { @@ -411,7 +411,7 @@ "Tags": [ { "Key": "Name", - "Value": "RedshiftServerlessStack/VPC/PrivateSubnet2" + "Value": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet2" } ], "VpcId": { @@ -459,7 +459,7 @@ }, { "Key": "Name", - "Value": "RedshiftServerlessStack/VPC/PrivateSubnet3" + "Value": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet3" } ], "VpcId": { @@ -473,7 +473,7 @@ "Tags": [ { "Key": "Name", - "Value": "RedshiftServerlessStack/VPC/PrivateSubnet3" + "Value": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet3" } ], "VpcId": { @@ -510,7 +510,7 @@ "Tags": [ { "Key": "Name", - "Value": "RedshiftServerlessStack/VPC" + "Value": "RedshiftServerlessNamespaceWorkgroupStack/VPC" } ] } @@ -701,7 +701,7 @@ "connectionlog", "useractivitylog" ], - "NamespaceName": "redshiftserverlessstacknamespace96a02cb7" + "NamespaceName": "redshiftserverlessnamespaceworkgroupstacknamespace9213ae95" } }, "AddRole65E43A1F": { @@ -795,7 +795,7 @@ "Ref": "VPCPrivateSubnet3Subnet3EDCD457" } ], - "WorkgroupName": "redshiftserverlessstackworkgroupcfbe5e7c" + "WorkgroupName": "redshiftserverlessnamespaceworkgroupstackworkgroup276abff0" } } }, diff --git a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessDefaultTestDeployAssertC5CDACEC.assets.json b/test/aws-redshiftserverless/integ.redshift-serverless-namespace-workgroup.ts.snapshot/RedshiftServerlessNamespaceWorkgroupTestDefaultTestDeployAssertE2D901CB.assets.json similarity index 85% rename from test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessDefaultTestDeployAssertC5CDACEC.assets.json rename to test/aws-redshiftserverless/integ.redshift-serverless-namespace-workgroup.ts.snapshot/RedshiftServerlessNamespaceWorkgroupTestDefaultTestDeployAssertE2D901CB.assets.json index 8b20e2f..a459197 100644 --- a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessDefaultTestDeployAssertC5CDACEC.assets.json +++ b/test/aws-redshiftserverless/integ.redshift-serverless-namespace-workgroup.ts.snapshot/RedshiftServerlessNamespaceWorkgroupTestDefaultTestDeployAssertE2D901CB.assets.json @@ -3,7 +3,7 @@ "files": { "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { "source": { - "path": "RedshiftServerlessDefaultTestDeployAssertC5CDACEC.template.json", + "path": "RedshiftServerlessNamespaceWorkgroupTestDefaultTestDeployAssertE2D901CB.template.json", "packaging": "file" }, "destinations": { diff --git a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessDefaultTestDeployAssertC5CDACEC.template.json b/test/aws-redshiftserverless/integ.redshift-serverless-namespace-workgroup.ts.snapshot/RedshiftServerlessNamespaceWorkgroupTestDefaultTestDeployAssertE2D901CB.template.json similarity index 100% rename from test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/RedshiftServerlessDefaultTestDeployAssertC5CDACEC.template.json rename to test/aws-redshiftserverless/integ.redshift-serverless-namespace-workgroup.ts.snapshot/RedshiftServerlessNamespaceWorkgroupTestDefaultTestDeployAssertE2D901CB.template.json diff --git a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/cdk.out b/test/aws-redshiftserverless/integ.redshift-serverless-namespace-workgroup.ts.snapshot/cdk.out similarity index 100% rename from test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/cdk.out rename to test/aws-redshiftserverless/integ.redshift-serverless-namespace-workgroup.ts.snapshot/cdk.out diff --git a/test/aws-redshiftserverless/integ.redshift-serverless-namespace-workgroup.ts.snapshot/integ.json b/test/aws-redshiftserverless/integ.redshift-serverless-namespace-workgroup.ts.snapshot/integ.json new file mode 100644 index 0000000..6edd209 --- /dev/null +++ b/test/aws-redshiftserverless/integ.redshift-serverless-namespace-workgroup.ts.snapshot/integ.json @@ -0,0 +1,14 @@ +{ + "enableLookups": true, + "version": "36.0.0", + "testCases": { + "RedshiftServerlessNamespaceWorkgroupTest/DefaultTest": { + "stacks": [ + "RedshiftServerlessNamespaceWorkgroupStack" + ], + "stackUpdateWorkflow": false, + "assertionStack": "RedshiftServerlessNamespaceWorkgroupTest/DefaultTest/DeployAssert", + "assertionStackName": "RedshiftServerlessNamespaceWorkgroupTestDefaultTestDeployAssertE2D901CB" + } + } +} \ No newline at end of file diff --git a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/manifest.json b/test/aws-redshiftserverless/integ.redshift-serverless-namespace-workgroup.ts.snapshot/manifest.json similarity index 63% rename from test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/manifest.json rename to test/aws-redshiftserverless/integ.redshift-serverless-namespace-workgroup.ts.snapshot/manifest.json index 4da61eb..c1a9f31 100644 --- a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/manifest.json +++ b/test/aws-redshiftserverless/integ.redshift-serverless-namespace-workgroup.ts.snapshot/manifest.json @@ -1,28 +1,28 @@ { "version": "36.0.0", "artifacts": { - "RedshiftServerlessStack.assets": { + "RedshiftServerlessNamespaceWorkgroupStack.assets": { "type": "cdk:asset-manifest", "properties": { - "file": "RedshiftServerlessStack.assets.json", + "file": "RedshiftServerlessNamespaceWorkgroupStack.assets.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" } }, - "RedshiftServerlessStack": { + "RedshiftServerlessNamespaceWorkgroupStack": { "type": "aws:cloudformation:stack", "environment": "aws://12345678/test-region", "properties": { - "templateFile": "RedshiftServerlessStack.template.json", + "templateFile": "RedshiftServerlessNamespaceWorkgroupStack.template.json", "terminationProtection": false, "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-deploy-role-12345678-test-region", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-cfn-exec-role-12345678-test-region", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-12345678-test-region/2a8884775baa3e4bf727739558ab42431a52a7c219439b077c8484fad5cd293f.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-12345678-test-region/4a8832c353aec7c387162f2dce3cb6290e83346da06b1ecbcc2f4b8a5794133d.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ - "RedshiftServerlessStack.assets" + "RedshiftServerlessNamespaceWorkgroupStack.assets" ], "lookupRole": { "arn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-lookup-role-12345678-test-region", @@ -31,295 +31,295 @@ } }, "dependencies": [ - "RedshiftServerlessStack.assets" + "RedshiftServerlessNamespaceWorkgroupStack.assets" ], "metadata": { - "/RedshiftServerlessStack/VPC/Resource": [ + "/RedshiftServerlessNamespaceWorkgroupStack/VPC/Resource": [ { "type": "aws:cdk:logicalId", "data": "VPCB9E5F0B4" } ], - "/RedshiftServerlessStack/VPC/PublicSubnet1/Subnet": [ + "/RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet1/Subnet": [ { "type": "aws:cdk:logicalId", "data": "VPCPublicSubnet1SubnetB4246D30" } ], - "/RedshiftServerlessStack/VPC/PublicSubnet1/RouteTable": [ + "/RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet1/RouteTable": [ { "type": "aws:cdk:logicalId", "data": "VPCPublicSubnet1RouteTableFEE4B781" } ], - "/RedshiftServerlessStack/VPC/PublicSubnet1/RouteTableAssociation": [ + "/RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet1/RouteTableAssociation": [ { "type": "aws:cdk:logicalId", "data": "VPCPublicSubnet1RouteTableAssociation0B0896DC" } ], - "/RedshiftServerlessStack/VPC/PublicSubnet1/DefaultRoute": [ + "/RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet1/DefaultRoute": [ { "type": "aws:cdk:logicalId", "data": "VPCPublicSubnet1DefaultRoute91CEF279" } ], - "/RedshiftServerlessStack/VPC/PublicSubnet1/EIP": [ + "/RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet1/EIP": [ { "type": "aws:cdk:logicalId", "data": "VPCPublicSubnet1EIP6AD938E8" } ], - "/RedshiftServerlessStack/VPC/PublicSubnet1/NATGateway": [ + "/RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet1/NATGateway": [ { "type": "aws:cdk:logicalId", "data": "VPCPublicSubnet1NATGatewayE0556630" } ], - "/RedshiftServerlessStack/VPC/PublicSubnet2/Subnet": [ + "/RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet2/Subnet": [ { "type": "aws:cdk:logicalId", "data": "VPCPublicSubnet2Subnet74179F39" } ], - "/RedshiftServerlessStack/VPC/PublicSubnet2/RouteTable": [ + "/RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet2/RouteTable": [ { "type": "aws:cdk:logicalId", "data": "VPCPublicSubnet2RouteTable6F1A15F1" } ], - "/RedshiftServerlessStack/VPC/PublicSubnet2/RouteTableAssociation": [ + "/RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet2/RouteTableAssociation": [ { "type": "aws:cdk:logicalId", "data": "VPCPublicSubnet2RouteTableAssociation5A808732" } ], - "/RedshiftServerlessStack/VPC/PublicSubnet2/DefaultRoute": [ + "/RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet2/DefaultRoute": [ { "type": "aws:cdk:logicalId", "data": "VPCPublicSubnet2DefaultRouteB7481BBA" } ], - "/RedshiftServerlessStack/VPC/PublicSubnet2/EIP": [ + "/RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet2/EIP": [ { "type": "aws:cdk:logicalId", "data": "VPCPublicSubnet2EIP4947BC00" } ], - "/RedshiftServerlessStack/VPC/PublicSubnet2/NATGateway": [ + "/RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet2/NATGateway": [ { "type": "aws:cdk:logicalId", "data": "VPCPublicSubnet2NATGateway3C070193" } ], - "/RedshiftServerlessStack/VPC/PublicSubnet3/Subnet": [ + "/RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet3/Subnet": [ { "type": "aws:cdk:logicalId", "data": "VPCPublicSubnet3Subnet631C5E25" } ], - "/RedshiftServerlessStack/VPC/PublicSubnet3/RouteTable": [ + "/RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet3/RouteTable": [ { "type": "aws:cdk:logicalId", "data": "VPCPublicSubnet3RouteTable98AE0E14" } ], - "/RedshiftServerlessStack/VPC/PublicSubnet3/RouteTableAssociation": [ + "/RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet3/RouteTableAssociation": [ { "type": "aws:cdk:logicalId", "data": "VPCPublicSubnet3RouteTableAssociation427FE0C6" } ], - "/RedshiftServerlessStack/VPC/PublicSubnet3/DefaultRoute": [ + "/RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet3/DefaultRoute": [ { "type": "aws:cdk:logicalId", "data": "VPCPublicSubnet3DefaultRouteA0D29D46" } ], - "/RedshiftServerlessStack/VPC/PublicSubnet3/EIP": [ + "/RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet3/EIP": [ { "type": "aws:cdk:logicalId", "data": "VPCPublicSubnet3EIPAD4BC883" } ], - "/RedshiftServerlessStack/VPC/PublicSubnet3/NATGateway": [ + "/RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet3/NATGateway": [ { "type": "aws:cdk:logicalId", "data": "VPCPublicSubnet3NATGatewayD3048F5C" } ], - "/RedshiftServerlessStack/VPC/PrivateSubnet1/Subnet": [ + "/RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet1/Subnet": [ { "type": "aws:cdk:logicalId", "data": "VPCPrivateSubnet1Subnet8BCA10E0" } ], - "/RedshiftServerlessStack/VPC/PrivateSubnet1/RouteTable": [ + "/RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet1/RouteTable": [ { "type": "aws:cdk:logicalId", "data": "VPCPrivateSubnet1RouteTableBE8A6027" } ], - "/RedshiftServerlessStack/VPC/PrivateSubnet1/RouteTableAssociation": [ + "/RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet1/RouteTableAssociation": [ { "type": "aws:cdk:logicalId", "data": "VPCPrivateSubnet1RouteTableAssociation347902D1" } ], - "/RedshiftServerlessStack/VPC/PrivateSubnet1/DefaultRoute": [ + "/RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet1/DefaultRoute": [ { "type": "aws:cdk:logicalId", "data": "VPCPrivateSubnet1DefaultRouteAE1D6490" } ], - "/RedshiftServerlessStack/VPC/PrivateSubnet2/Subnet": [ + "/RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet2/Subnet": [ { "type": "aws:cdk:logicalId", "data": "VPCPrivateSubnet2SubnetCFCDAA7A" } ], - "/RedshiftServerlessStack/VPC/PrivateSubnet2/RouteTable": [ + "/RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet2/RouteTable": [ { "type": "aws:cdk:logicalId", "data": "VPCPrivateSubnet2RouteTable0A19E10E" } ], - "/RedshiftServerlessStack/VPC/PrivateSubnet2/RouteTableAssociation": [ + "/RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet2/RouteTableAssociation": [ { "type": "aws:cdk:logicalId", "data": "VPCPrivateSubnet2RouteTableAssociation0C73D413" } ], - "/RedshiftServerlessStack/VPC/PrivateSubnet2/DefaultRoute": [ + "/RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet2/DefaultRoute": [ { "type": "aws:cdk:logicalId", "data": "VPCPrivateSubnet2DefaultRouteF4F5CFD2" } ], - "/RedshiftServerlessStack/VPC/PrivateSubnet3/Subnet": [ + "/RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet3/Subnet": [ { "type": "aws:cdk:logicalId", "data": "VPCPrivateSubnet3Subnet3EDCD457" } ], - "/RedshiftServerlessStack/VPC/PrivateSubnet3/RouteTable": [ + "/RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet3/RouteTable": [ { "type": "aws:cdk:logicalId", "data": "VPCPrivateSubnet3RouteTable192186F8" } ], - "/RedshiftServerlessStack/VPC/PrivateSubnet3/RouteTableAssociation": [ + "/RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet3/RouteTableAssociation": [ { "type": "aws:cdk:logicalId", "data": "VPCPrivateSubnet3RouteTableAssociationC28D144E" } ], - "/RedshiftServerlessStack/VPC/PrivateSubnet3/DefaultRoute": [ + "/RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet3/DefaultRoute": [ { "type": "aws:cdk:logicalId", "data": "VPCPrivateSubnet3DefaultRoute27F311AE" } ], - "/RedshiftServerlessStack/VPC/IGW": [ + "/RedshiftServerlessNamespaceWorkgroupStack/VPC/IGW": [ { "type": "aws:cdk:logicalId", "data": "VPCIGWB7E252D3" } ], - "/RedshiftServerlessStack/VPC/VPCGW": [ + "/RedshiftServerlessNamespaceWorkgroupStack/VPC/VPCGW": [ { "type": "aws:cdk:logicalId", "data": "VPCVPCGW99B986DC" } ], - "/RedshiftServerlessStack/VPC/RestrictDefaultSecurityGroupCustomResource/Default": [ + "/RedshiftServerlessNamespaceWorkgroupStack/VPC/RestrictDefaultSecurityGroupCustomResource/Default": [ { "type": "aws:cdk:logicalId", "data": "VPCRestrictDefaultSecurityGroupCustomResource59474679" } ], - "/RedshiftServerlessStack/Custom::VpcRestrictDefaultSGCustomResourceProvider/Role": [ + "/RedshiftServerlessNamespaceWorkgroupStack/Custom::VpcRestrictDefaultSGCustomResourceProvider/Role": [ { "type": "aws:cdk:logicalId", "data": "CustomVpcRestrictDefaultSGCustomResourceProviderRole26592FE0" } ], - "/RedshiftServerlessStack/Custom::VpcRestrictDefaultSGCustomResourceProvider/Handler": [ + "/RedshiftServerlessNamespaceWorkgroupStack/Custom::VpcRestrictDefaultSGCustomResourceProvider/Handler": [ { "type": "aws:cdk:logicalId", "data": "CustomVpcRestrictDefaultSGCustomResourceProviderHandlerDC833E5E" } ], - "/RedshiftServerlessStack/DefaultRole/Resource": [ + "/RedshiftServerlessNamespaceWorkgroupStack/DefaultRole/Resource": [ { "type": "aws:cdk:logicalId", "data": "DefaultRoleEFEF8FA6" } ], - "/RedshiftServerlessStack/AnotherRole/Resource": [ + "/RedshiftServerlessNamespaceWorkgroupStack/AnotherRole/Resource": [ { "type": "aws:cdk:logicalId", "data": "AnotherRoleE13C44E8" } ], - "/RedshiftServerlessStack/Namespace/Resource": [ + "/RedshiftServerlessNamespaceWorkgroupStack/Namespace/Resource": [ { "type": "aws:cdk:logicalId", "data": "Namespace9B63B8C8" } ], - "/RedshiftServerlessStack/AddRole/Resource": [ + "/RedshiftServerlessNamespaceWorkgroupStack/AddRole/Resource": [ { "type": "aws:cdk:logicalId", "data": "AddRole65E43A1F" } ], - "/RedshiftServerlessStack/WorkGroup/SecurityGroup/Resource": [ + "/RedshiftServerlessNamespaceWorkgroupStack/WorkGroup/SecurityGroup/Resource": [ { "type": "aws:cdk:logicalId", "data": "WorkGroupSecurityGroup82E81D37" } ], - "/RedshiftServerlessStack/WorkGroup/Resource": [ + "/RedshiftServerlessNamespaceWorkgroupStack/WorkGroup/Resource": [ { "type": "aws:cdk:logicalId", "data": "WorkGroup9BE20B7A" } ], - "/RedshiftServerlessStack/endpointAddress": [ + "/RedshiftServerlessNamespaceWorkgroupStack/endpointAddress": [ { "type": "aws:cdk:logicalId", "data": "endpointAddress" } ], - "/RedshiftServerlessStack/BootstrapVersion": [ + "/RedshiftServerlessNamespaceWorkgroupStack/BootstrapVersion": [ { "type": "aws:cdk:logicalId", "data": "BootstrapVersion" } ], - "/RedshiftServerlessStack/CheckBootstrapVersion": [ + "/RedshiftServerlessNamespaceWorkgroupStack/CheckBootstrapVersion": [ { "type": "aws:cdk:logicalId", "data": "CheckBootstrapVersion" } ] }, - "displayName": "RedshiftServerlessStack" + "displayName": "RedshiftServerlessNamespaceWorkgroupStack" }, - "RedshiftServerlessDefaultTestDeployAssertC5CDACEC.assets": { + "RedshiftServerlessNamespaceWorkgroupTestDefaultTestDeployAssertE2D901CB.assets": { "type": "cdk:asset-manifest", "properties": { - "file": "RedshiftServerlessDefaultTestDeployAssertC5CDACEC.assets.json", + "file": "RedshiftServerlessNamespaceWorkgroupTestDefaultTestDeployAssertE2D901CB.assets.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" } }, - "RedshiftServerlessDefaultTestDeployAssertC5CDACEC": { + "RedshiftServerlessNamespaceWorkgroupTestDefaultTestDeployAssertE2D901CB": { "type": "aws:cloudformation:stack", "environment": "aws://unknown-account/unknown-region", "properties": { - "templateFile": "RedshiftServerlessDefaultTestDeployAssertC5CDACEC.template.json", + "templateFile": "RedshiftServerlessNamespaceWorkgroupTestDefaultTestDeployAssertE2D901CB.template.json", "terminationProtection": false, "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", @@ -328,7 +328,7 @@ "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ - "RedshiftServerlessDefaultTestDeployAssertC5CDACEC.assets" + "RedshiftServerlessNamespaceWorkgroupTestDefaultTestDeployAssertE2D901CB.assets" ], "lookupRole": { "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", @@ -337,23 +337,23 @@ } }, "dependencies": [ - "RedshiftServerlessDefaultTestDeployAssertC5CDACEC.assets" + "RedshiftServerlessNamespaceWorkgroupTestDefaultTestDeployAssertE2D901CB.assets" ], "metadata": { - "/RedshiftServerless/DefaultTest/DeployAssert/BootstrapVersion": [ + "/RedshiftServerlessNamespaceWorkgroupTest/DefaultTest/DeployAssert/BootstrapVersion": [ { "type": "aws:cdk:logicalId", "data": "BootstrapVersion" } ], - "/RedshiftServerless/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + "/RedshiftServerlessNamespaceWorkgroupTest/DefaultTest/DeployAssert/CheckBootstrapVersion": [ { "type": "aws:cdk:logicalId", "data": "CheckBootstrapVersion" } ] }, - "displayName": "RedshiftServerless/DefaultTest/DeployAssert" + "displayName": "RedshiftServerlessNamespaceWorkgroupTest/DefaultTest/DeployAssert" }, "Tree": { "type": "cdk:tree", diff --git a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/tree.json b/test/aws-redshiftserverless/integ.redshift-serverless-namespace-workgroup.ts.snapshot/tree.json similarity index 82% rename from test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/tree.json rename to test/aws-redshiftserverless/integ.redshift-serverless-namespace-workgroup.ts.snapshot/tree.json index 3f15644..a789500 100644 --- a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/tree.json +++ b/test/aws-redshiftserverless/integ.redshift-serverless-namespace-workgroup.ts.snapshot/tree.json @@ -4,17 +4,17 @@ "id": "App", "path": "", "children": { - "RedshiftServerlessStack": { - "id": "RedshiftServerlessStack", - "path": "RedshiftServerlessStack", + "RedshiftServerlessNamespaceWorkgroupStack": { + "id": "RedshiftServerlessNamespaceWorkgroupStack", + "path": "RedshiftServerlessNamespaceWorkgroupStack", "children": { "VPC": { "id": "VPC", - "path": "RedshiftServerlessStack/VPC", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC", "children": { "Resource": { "id": "Resource", - "path": "RedshiftServerlessStack/VPC/Resource", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::VPC", "aws:cdk:cloudformation:props": { @@ -25,7 +25,7 @@ "tags": [ { "key": "Name", - "value": "RedshiftServerlessStack/VPC" + "value": "RedshiftServerlessNamespaceWorkgroupStack/VPC" } ] } @@ -37,11 +37,11 @@ }, "PublicSubnet1": { "id": "PublicSubnet1", - "path": "RedshiftServerlessStack/VPC/PublicSubnet1", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet1", "children": { "Subnet": { "id": "Subnet", - "path": "RedshiftServerlessStack/VPC/PublicSubnet1/Subnet", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet1/Subnet", "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { @@ -59,7 +59,7 @@ }, { "key": "Name", - "value": "RedshiftServerlessStack/VPC/PublicSubnet1" + "value": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet1" } ], "vpcId": { @@ -74,7 +74,7 @@ }, "Acl": { "id": "Acl", - "path": "RedshiftServerlessStack/VPC/PublicSubnet1/Acl", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet1/Acl", "constructInfo": { "fqn": "aws-cdk-lib.Resource", "version": "2.120.0" @@ -82,14 +82,14 @@ }, "RouteTable": { "id": "RouteTable", - "path": "RedshiftServerlessStack/VPC/PublicSubnet1/RouteTable", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet1/RouteTable", "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { "tags": [ { "key": "Name", - "value": "RedshiftServerlessStack/VPC/PublicSubnet1" + "value": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet1" } ], "vpcId": { @@ -104,7 +104,7 @@ }, "RouteTableAssociation": { "id": "RouteTableAssociation", - "path": "RedshiftServerlessStack/VPC/PublicSubnet1/RouteTableAssociation", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet1/RouteTableAssociation", "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", "aws:cdk:cloudformation:props": { @@ -123,7 +123,7 @@ }, "DefaultRoute": { "id": "DefaultRoute", - "path": "RedshiftServerlessStack/VPC/PublicSubnet1/DefaultRoute", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet1/DefaultRoute", "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { @@ -143,7 +143,7 @@ }, "EIP": { "id": "EIP", - "path": "RedshiftServerlessStack/VPC/PublicSubnet1/EIP", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet1/EIP", "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::EIP", "aws:cdk:cloudformation:props": { @@ -151,7 +151,7 @@ "tags": [ { "key": "Name", - "value": "RedshiftServerlessStack/VPC/PublicSubnet1" + "value": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet1" } ] } @@ -163,7 +163,7 @@ }, "NATGateway": { "id": "NATGateway", - "path": "RedshiftServerlessStack/VPC/PublicSubnet1/NATGateway", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet1/NATGateway", "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { @@ -179,7 +179,7 @@ "tags": [ { "key": "Name", - "value": "RedshiftServerlessStack/VPC/PublicSubnet1" + "value": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet1" } ] } @@ -197,11 +197,11 @@ }, "PublicSubnet2": { "id": "PublicSubnet2", - "path": "RedshiftServerlessStack/VPC/PublicSubnet2", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet2", "children": { "Subnet": { "id": "Subnet", - "path": "RedshiftServerlessStack/VPC/PublicSubnet2/Subnet", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet2/Subnet", "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { @@ -219,7 +219,7 @@ }, { "key": "Name", - "value": "RedshiftServerlessStack/VPC/PublicSubnet2" + "value": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet2" } ], "vpcId": { @@ -234,7 +234,7 @@ }, "Acl": { "id": "Acl", - "path": "RedshiftServerlessStack/VPC/PublicSubnet2/Acl", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet2/Acl", "constructInfo": { "fqn": "aws-cdk-lib.Resource", "version": "2.120.0" @@ -242,14 +242,14 @@ }, "RouteTable": { "id": "RouteTable", - "path": "RedshiftServerlessStack/VPC/PublicSubnet2/RouteTable", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet2/RouteTable", "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { "tags": [ { "key": "Name", - "value": "RedshiftServerlessStack/VPC/PublicSubnet2" + "value": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet2" } ], "vpcId": { @@ -264,7 +264,7 @@ }, "RouteTableAssociation": { "id": "RouteTableAssociation", - "path": "RedshiftServerlessStack/VPC/PublicSubnet2/RouteTableAssociation", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet2/RouteTableAssociation", "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", "aws:cdk:cloudformation:props": { @@ -283,7 +283,7 @@ }, "DefaultRoute": { "id": "DefaultRoute", - "path": "RedshiftServerlessStack/VPC/PublicSubnet2/DefaultRoute", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet2/DefaultRoute", "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { @@ -303,7 +303,7 @@ }, "EIP": { "id": "EIP", - "path": "RedshiftServerlessStack/VPC/PublicSubnet2/EIP", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet2/EIP", "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::EIP", "aws:cdk:cloudformation:props": { @@ -311,7 +311,7 @@ "tags": [ { "key": "Name", - "value": "RedshiftServerlessStack/VPC/PublicSubnet2" + "value": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet2" } ] } @@ -323,7 +323,7 @@ }, "NATGateway": { "id": "NATGateway", - "path": "RedshiftServerlessStack/VPC/PublicSubnet2/NATGateway", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet2/NATGateway", "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { @@ -339,7 +339,7 @@ "tags": [ { "key": "Name", - "value": "RedshiftServerlessStack/VPC/PublicSubnet2" + "value": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet2" } ] } @@ -357,11 +357,11 @@ }, "PublicSubnet3": { "id": "PublicSubnet3", - "path": "RedshiftServerlessStack/VPC/PublicSubnet3", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet3", "children": { "Subnet": { "id": "Subnet", - "path": "RedshiftServerlessStack/VPC/PublicSubnet3/Subnet", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet3/Subnet", "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { @@ -379,7 +379,7 @@ }, { "key": "Name", - "value": "RedshiftServerlessStack/VPC/PublicSubnet3" + "value": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet3" } ], "vpcId": { @@ -394,7 +394,7 @@ }, "Acl": { "id": "Acl", - "path": "RedshiftServerlessStack/VPC/PublicSubnet3/Acl", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet3/Acl", "constructInfo": { "fqn": "aws-cdk-lib.Resource", "version": "2.120.0" @@ -402,14 +402,14 @@ }, "RouteTable": { "id": "RouteTable", - "path": "RedshiftServerlessStack/VPC/PublicSubnet3/RouteTable", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet3/RouteTable", "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { "tags": [ { "key": "Name", - "value": "RedshiftServerlessStack/VPC/PublicSubnet3" + "value": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet3" } ], "vpcId": { @@ -424,7 +424,7 @@ }, "RouteTableAssociation": { "id": "RouteTableAssociation", - "path": "RedshiftServerlessStack/VPC/PublicSubnet3/RouteTableAssociation", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet3/RouteTableAssociation", "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", "aws:cdk:cloudformation:props": { @@ -443,7 +443,7 @@ }, "DefaultRoute": { "id": "DefaultRoute", - "path": "RedshiftServerlessStack/VPC/PublicSubnet3/DefaultRoute", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet3/DefaultRoute", "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { @@ -463,7 +463,7 @@ }, "EIP": { "id": "EIP", - "path": "RedshiftServerlessStack/VPC/PublicSubnet3/EIP", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet3/EIP", "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::EIP", "aws:cdk:cloudformation:props": { @@ -471,7 +471,7 @@ "tags": [ { "key": "Name", - "value": "RedshiftServerlessStack/VPC/PublicSubnet3" + "value": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet3" } ] } @@ -483,7 +483,7 @@ }, "NATGateway": { "id": "NATGateway", - "path": "RedshiftServerlessStack/VPC/PublicSubnet3/NATGateway", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet3/NATGateway", "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", "aws:cdk:cloudformation:props": { @@ -499,7 +499,7 @@ "tags": [ { "key": "Name", - "value": "RedshiftServerlessStack/VPC/PublicSubnet3" + "value": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PublicSubnet3" } ] } @@ -517,11 +517,11 @@ }, "PrivateSubnet1": { "id": "PrivateSubnet1", - "path": "RedshiftServerlessStack/VPC/PrivateSubnet1", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet1", "children": { "Subnet": { "id": "Subnet", - "path": "RedshiftServerlessStack/VPC/PrivateSubnet1/Subnet", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet1/Subnet", "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { @@ -539,7 +539,7 @@ }, { "key": "Name", - "value": "RedshiftServerlessStack/VPC/PrivateSubnet1" + "value": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet1" } ], "vpcId": { @@ -554,7 +554,7 @@ }, "Acl": { "id": "Acl", - "path": "RedshiftServerlessStack/VPC/PrivateSubnet1/Acl", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet1/Acl", "constructInfo": { "fqn": "aws-cdk-lib.Resource", "version": "2.120.0" @@ -562,14 +562,14 @@ }, "RouteTable": { "id": "RouteTable", - "path": "RedshiftServerlessStack/VPC/PrivateSubnet1/RouteTable", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet1/RouteTable", "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { "tags": [ { "key": "Name", - "value": "RedshiftServerlessStack/VPC/PrivateSubnet1" + "value": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet1" } ], "vpcId": { @@ -584,7 +584,7 @@ }, "RouteTableAssociation": { "id": "RouteTableAssociation", - "path": "RedshiftServerlessStack/VPC/PrivateSubnet1/RouteTableAssociation", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet1/RouteTableAssociation", "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", "aws:cdk:cloudformation:props": { @@ -603,7 +603,7 @@ }, "DefaultRoute": { "id": "DefaultRoute", - "path": "RedshiftServerlessStack/VPC/PrivateSubnet1/DefaultRoute", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet1/DefaultRoute", "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { @@ -629,11 +629,11 @@ }, "PrivateSubnet2": { "id": "PrivateSubnet2", - "path": "RedshiftServerlessStack/VPC/PrivateSubnet2", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet2", "children": { "Subnet": { "id": "Subnet", - "path": "RedshiftServerlessStack/VPC/PrivateSubnet2/Subnet", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet2/Subnet", "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { @@ -651,7 +651,7 @@ }, { "key": "Name", - "value": "RedshiftServerlessStack/VPC/PrivateSubnet2" + "value": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet2" } ], "vpcId": { @@ -666,7 +666,7 @@ }, "Acl": { "id": "Acl", - "path": "RedshiftServerlessStack/VPC/PrivateSubnet2/Acl", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet2/Acl", "constructInfo": { "fqn": "aws-cdk-lib.Resource", "version": "2.120.0" @@ -674,14 +674,14 @@ }, "RouteTable": { "id": "RouteTable", - "path": "RedshiftServerlessStack/VPC/PrivateSubnet2/RouteTable", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet2/RouteTable", "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { "tags": [ { "key": "Name", - "value": "RedshiftServerlessStack/VPC/PrivateSubnet2" + "value": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet2" } ], "vpcId": { @@ -696,7 +696,7 @@ }, "RouteTableAssociation": { "id": "RouteTableAssociation", - "path": "RedshiftServerlessStack/VPC/PrivateSubnet2/RouteTableAssociation", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet2/RouteTableAssociation", "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", "aws:cdk:cloudformation:props": { @@ -715,7 +715,7 @@ }, "DefaultRoute": { "id": "DefaultRoute", - "path": "RedshiftServerlessStack/VPC/PrivateSubnet2/DefaultRoute", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet2/DefaultRoute", "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { @@ -741,11 +741,11 @@ }, "PrivateSubnet3": { "id": "PrivateSubnet3", - "path": "RedshiftServerlessStack/VPC/PrivateSubnet3", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet3", "children": { "Subnet": { "id": "Subnet", - "path": "RedshiftServerlessStack/VPC/PrivateSubnet3/Subnet", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet3/Subnet", "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", "aws:cdk:cloudformation:props": { @@ -763,7 +763,7 @@ }, { "key": "Name", - "value": "RedshiftServerlessStack/VPC/PrivateSubnet3" + "value": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet3" } ], "vpcId": { @@ -778,7 +778,7 @@ }, "Acl": { "id": "Acl", - "path": "RedshiftServerlessStack/VPC/PrivateSubnet3/Acl", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet3/Acl", "constructInfo": { "fqn": "aws-cdk-lib.Resource", "version": "2.120.0" @@ -786,14 +786,14 @@ }, "RouteTable": { "id": "RouteTable", - "path": "RedshiftServerlessStack/VPC/PrivateSubnet3/RouteTable", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet3/RouteTable", "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", "aws:cdk:cloudformation:props": { "tags": [ { "key": "Name", - "value": "RedshiftServerlessStack/VPC/PrivateSubnet3" + "value": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet3" } ], "vpcId": { @@ -808,7 +808,7 @@ }, "RouteTableAssociation": { "id": "RouteTableAssociation", - "path": "RedshiftServerlessStack/VPC/PrivateSubnet3/RouteTableAssociation", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet3/RouteTableAssociation", "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", "aws:cdk:cloudformation:props": { @@ -827,7 +827,7 @@ }, "DefaultRoute": { "id": "DefaultRoute", - "path": "RedshiftServerlessStack/VPC/PrivateSubnet3/DefaultRoute", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/PrivateSubnet3/DefaultRoute", "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::Route", "aws:cdk:cloudformation:props": { @@ -853,14 +853,14 @@ }, "IGW": { "id": "IGW", - "path": "RedshiftServerlessStack/VPC/IGW", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/IGW", "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::InternetGateway", "aws:cdk:cloudformation:props": { "tags": [ { "key": "Name", - "value": "RedshiftServerlessStack/VPC" + "value": "RedshiftServerlessNamespaceWorkgroupStack/VPC" } ] } @@ -872,7 +872,7 @@ }, "VPCGW": { "id": "VPCGW", - "path": "RedshiftServerlessStack/VPC/VPCGW", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/VPCGW", "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::VPCGatewayAttachment", "aws:cdk:cloudformation:props": { @@ -891,11 +891,11 @@ }, "RestrictDefaultSecurityGroupCustomResource": { "id": "RestrictDefaultSecurityGroupCustomResource", - "path": "RedshiftServerlessStack/VPC/RestrictDefaultSecurityGroupCustomResource", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/RestrictDefaultSecurityGroupCustomResource", "children": { "Default": { "id": "Default", - "path": "RedshiftServerlessStack/VPC/RestrictDefaultSecurityGroupCustomResource/Default", + "path": "RedshiftServerlessNamespaceWorkgroupStack/VPC/RestrictDefaultSecurityGroupCustomResource/Default", "constructInfo": { "fqn": "aws-cdk-lib.CfnResource", "version": "2.120.0" @@ -915,11 +915,11 @@ }, "Custom::VpcRestrictDefaultSGCustomResourceProvider": { "id": "Custom::VpcRestrictDefaultSGCustomResourceProvider", - "path": "RedshiftServerlessStack/Custom::VpcRestrictDefaultSGCustomResourceProvider", + "path": "RedshiftServerlessNamespaceWorkgroupStack/Custom::VpcRestrictDefaultSGCustomResourceProvider", "children": { "Staging": { "id": "Staging", - "path": "RedshiftServerlessStack/Custom::VpcRestrictDefaultSGCustomResourceProvider/Staging", + "path": "RedshiftServerlessNamespaceWorkgroupStack/Custom::VpcRestrictDefaultSGCustomResourceProvider/Staging", "constructInfo": { "fqn": "aws-cdk-lib.AssetStaging", "version": "2.120.0" @@ -927,7 +927,7 @@ }, "Role": { "id": "Role", - "path": "RedshiftServerlessStack/Custom::VpcRestrictDefaultSGCustomResourceProvider/Role", + "path": "RedshiftServerlessNamespaceWorkgroupStack/Custom::VpcRestrictDefaultSGCustomResourceProvider/Role", "constructInfo": { "fqn": "aws-cdk-lib.CfnResource", "version": "2.120.0" @@ -935,7 +935,7 @@ }, "Handler": { "id": "Handler", - "path": "RedshiftServerlessStack/Custom::VpcRestrictDefaultSGCustomResourceProvider/Handler", + "path": "RedshiftServerlessNamespaceWorkgroupStack/Custom::VpcRestrictDefaultSGCustomResourceProvider/Handler", "constructInfo": { "fqn": "aws-cdk-lib.CfnResource", "version": "2.120.0" @@ -949,11 +949,11 @@ }, "DefaultRole": { "id": "DefaultRole", - "path": "RedshiftServerlessStack/DefaultRole", + "path": "RedshiftServerlessNamespaceWorkgroupStack/DefaultRole", "children": { "ImportDefaultRole": { "id": "ImportDefaultRole", - "path": "RedshiftServerlessStack/DefaultRole/ImportDefaultRole", + "path": "RedshiftServerlessNamespaceWorkgroupStack/DefaultRole/ImportDefaultRole", "constructInfo": { "fqn": "aws-cdk-lib.Resource", "version": "2.120.0" @@ -961,7 +961,7 @@ }, "Resource": { "id": "Resource", - "path": "RedshiftServerlessStack/DefaultRole/Resource", + "path": "RedshiftServerlessNamespaceWorkgroupStack/DefaultRole/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::IAM::Role", "aws:cdk:cloudformation:props": { @@ -992,11 +992,11 @@ }, "AnotherRole": { "id": "AnotherRole", - "path": "RedshiftServerlessStack/AnotherRole", + "path": "RedshiftServerlessNamespaceWorkgroupStack/AnotherRole", "children": { "ImportAnotherRole": { "id": "ImportAnotherRole", - "path": "RedshiftServerlessStack/AnotherRole/ImportAnotherRole", + "path": "RedshiftServerlessNamespaceWorkgroupStack/AnotherRole/ImportAnotherRole", "constructInfo": { "fqn": "aws-cdk-lib.Resource", "version": "2.120.0" @@ -1004,7 +1004,7 @@ }, "Resource": { "id": "Resource", - "path": "RedshiftServerlessStack/AnotherRole/Resource", + "path": "RedshiftServerlessNamespaceWorkgroupStack/AnotherRole/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::IAM::Role", "aws:cdk:cloudformation:props": { @@ -1035,11 +1035,11 @@ }, "Namespace": { "id": "Namespace", - "path": "RedshiftServerlessStack/Namespace", + "path": "RedshiftServerlessNamespaceWorkgroupStack/Namespace", "children": { "Resource": { "id": "Resource", - "path": "RedshiftServerlessStack/Namespace/Resource", + "path": "RedshiftServerlessNamespaceWorkgroupStack/Namespace/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::RedshiftServerless::Namespace", "aws:cdk:cloudformation:props": { @@ -1077,7 +1077,7 @@ "connectionlog", "useractivitylog" ], - "namespaceName": "redshiftserverlessstacknamespace96a02cb7" + "namespaceName": "redshiftserverlessnamespaceworkgroupstacknamespace9213ae95" } }, "constructInfo": { @@ -1093,11 +1093,11 @@ }, "AddRole": { "id": "AddRole", - "path": "RedshiftServerlessStack/AddRole", + "path": "RedshiftServerlessNamespaceWorkgroupStack/AddRole", "children": { "ImportAddRole": { "id": "ImportAddRole", - "path": "RedshiftServerlessStack/AddRole/ImportAddRole", + "path": "RedshiftServerlessNamespaceWorkgroupStack/AddRole/ImportAddRole", "constructInfo": { "fqn": "aws-cdk-lib.Resource", "version": "2.120.0" @@ -1105,7 +1105,7 @@ }, "Resource": { "id": "Resource", - "path": "RedshiftServerlessStack/AddRole/Resource", + "path": "RedshiftServerlessNamespaceWorkgroupStack/AddRole/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::IAM::Role", "aws:cdk:cloudformation:props": { @@ -1136,15 +1136,15 @@ }, "WorkGroup": { "id": "WorkGroup", - "path": "RedshiftServerlessStack/WorkGroup", + "path": "RedshiftServerlessNamespaceWorkgroupStack/WorkGroup", "children": { "SecurityGroup": { "id": "SecurityGroup", - "path": "RedshiftServerlessStack/WorkGroup/SecurityGroup", + "path": "RedshiftServerlessNamespaceWorkgroupStack/WorkGroup/SecurityGroup", "children": { "Resource": { "id": "Resource", - "path": "RedshiftServerlessStack/WorkGroup/SecurityGroup/Resource", + "path": "RedshiftServerlessNamespaceWorkgroupStack/WorkGroup/SecurityGroup/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::EC2::SecurityGroup", "aws:cdk:cloudformation:props": { @@ -1174,7 +1174,7 @@ }, "Resource": { "id": "Resource", - "path": "RedshiftServerlessStack/WorkGroup/Resource", + "path": "RedshiftServerlessNamespaceWorkgroupStack/WorkGroup/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::RedshiftServerless::Workgroup", "aws:cdk:cloudformation:props": { @@ -1233,7 +1233,7 @@ "Ref": "VPCPrivateSubnet3Subnet3EDCD457" } ], - "workgroupName": "redshiftserverlessstackworkgroupcfbe5e7c" + "workgroupName": "redshiftserverlessnamespaceworkgroupstackworkgroup276abff0" } }, "constructInfo": { @@ -1249,7 +1249,7 @@ }, "endpointAddress": { "id": "endpointAddress", - "path": "RedshiftServerlessStack/endpointAddress", + "path": "RedshiftServerlessNamespaceWorkgroupStack/endpointAddress", "constructInfo": { "fqn": "aws-cdk-lib.CfnOutput", "version": "2.120.0" @@ -1257,7 +1257,7 @@ }, "BootstrapVersion": { "id": "BootstrapVersion", - "path": "RedshiftServerlessStack/BootstrapVersion", + "path": "RedshiftServerlessNamespaceWorkgroupStack/BootstrapVersion", "constructInfo": { "fqn": "aws-cdk-lib.CfnParameter", "version": "2.120.0" @@ -1265,7 +1265,7 @@ }, "CheckBootstrapVersion": { "id": "CheckBootstrapVersion", - "path": "RedshiftServerlessStack/CheckBootstrapVersion", + "path": "RedshiftServerlessNamespaceWorkgroupStack/CheckBootstrapVersion", "constructInfo": { "fqn": "aws-cdk-lib.CfnRule", "version": "2.120.0" @@ -1277,17 +1277,17 @@ "version": "2.120.0" } }, - "RedshiftServerless": { - "id": "RedshiftServerless", - "path": "RedshiftServerless", + "RedshiftServerlessNamespaceWorkgroupTest": { + "id": "RedshiftServerlessNamespaceWorkgroupTest", + "path": "RedshiftServerlessNamespaceWorkgroupTest", "children": { "DefaultTest": { "id": "DefaultTest", - "path": "RedshiftServerless/DefaultTest", + "path": "RedshiftServerlessNamespaceWorkgroupTest/DefaultTest", "children": { "Default": { "id": "Default", - "path": "RedshiftServerless/DefaultTest/Default", + "path": "RedshiftServerlessNamespaceWorkgroupTest/DefaultTest/Default", "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0" @@ -1295,11 +1295,11 @@ }, "DeployAssert": { "id": "DeployAssert", - "path": "RedshiftServerless/DefaultTest/DeployAssert", + "path": "RedshiftServerlessNamespaceWorkgroupTest/DefaultTest/DeployAssert", "children": { "BootstrapVersion": { "id": "BootstrapVersion", - "path": "RedshiftServerless/DefaultTest/DeployAssert/BootstrapVersion", + "path": "RedshiftServerlessNamespaceWorkgroupTest/DefaultTest/DeployAssert/BootstrapVersion", "constructInfo": { "fqn": "aws-cdk-lib.CfnParameter", "version": "2.120.0" @@ -1307,7 +1307,7 @@ }, "CheckBootstrapVersion": { "id": "CheckBootstrapVersion", - "path": "RedshiftServerless/DefaultTest/DeployAssert/CheckBootstrapVersion", + "path": "RedshiftServerlessNamespaceWorkgroupTest/DefaultTest/DeployAssert/CheckBootstrapVersion", "constructInfo": { "fqn": "aws-cdk-lib.CfnRule", "version": "2.120.0" diff --git a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/integ.json b/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/integ.json deleted file mode 100644 index baea88a..0000000 --- a/test/aws-redshiftserverless/integ.redshift-serverless.ts.snapshot/integ.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "enableLookups": true, - "version": "36.0.0", - "testCases": { - "RedshiftServerless/DefaultTest": { - "stacks": [ - "RedshiftServerlessStack" - ], - "stackUpdateWorkflow": false, - "assertionStack": "RedshiftServerless/DefaultTest/DeployAssert", - "assertionStackName": "RedshiftServerlessDefaultTestDeployAssertC5CDACEC" - } - } -} \ No newline at end of file diff --git a/test/aws-redshiftserverless/namespace.test.ts b/test/aws-redshiftserverless/namespace.test.ts index 482c5e3..21727a9 100644 --- a/test/aws-redshiftserverless/namespace.test.ts +++ b/test/aws-redshiftserverless/namespace.test.ts @@ -2,7 +2,7 @@ import { App, SecretValue, Stack } from 'aws-cdk-lib'; import { Match, Template } from 'aws-cdk-lib/assertions'; import { Role, ServicePrincipal } from 'aws-cdk-lib/aws-iam'; import { Key } from 'aws-cdk-lib/aws-kms'; -import { LogExport, Namespace } from '../../src/aws-redshiftserverless'; +import { INamespace, LogExport, Namespace } from '../../src/aws-redshiftserverless'; describe('Redshift Serverless Namespace', () => { let app: App; @@ -60,13 +60,21 @@ describe('Redshift Serverless Namespace', () => { }); describe('test import method', () => { - test('import from namespaceId', () => { - const existingNamespace = Namespace.fromNamespaceAttributes(stack, 'ImportedNamespace', { + let existingNamespace: INamespace; + + beforeEach(() => { + stack = new Stack(); + existingNamespace = Namespace.fromNamespaceAttributes(stack, 'ImportedNamespace', { namespaceId: 'my-namespace-id', namespaceName: 'my-namespace-name', }); + }); + test('should correctly set namespaceId', () => { expect(existingNamespace.namespaceId).toEqual('my-namespace-id'); + }); + + test('should correctly format namespaceArn', () => { expect(existingNamespace.namespaceArn).toEqual( Stack.of(stack).formatArn({ resource: 'redshift-serverless', @@ -235,9 +243,7 @@ describe('Redshift Serverless Namespace', () => { iamRoles: [addRole], }); namespace.addIamRole(addRole); - }).toThrow( - `An adding IAM Role is already attached to the namespace, name: ${addRole.roleName}, ARN: ${addRole.roleArn}.`, - ); + }).toThrow(`An adding IAM Role is already attached to the namespace, ARN: ${addRole.roleArn}.`); }); }); }); diff --git a/test/aws-redshiftserverless/workgroup.test.ts b/test/aws-redshiftserverless/workgroup.test.ts index 9d6bee1..9410b34 100644 --- a/test/aws-redshiftserverless/workgroup.test.ts +++ b/test/aws-redshiftserverless/workgroup.test.ts @@ -1,6 +1,6 @@ import { App, Stack, aws_ec2 } from 'aws-cdk-lib'; import { Template } from 'aws-cdk-lib/assertions'; -import { Namespace, Workgroup } from '../../src/aws-redshiftserverless'; +import { IWorkgroup, Namespace, Workgroup } from '../../src/aws-redshiftserverless'; describe('Redshift Serverless Workgroup', () => { let app: App; @@ -85,26 +85,38 @@ describe('Redshift Serverless Workgroup', () => { }); describe('import method', () => { - test('imports Workgroup correctly', () => { - const securityGroup = aws_ec2.SecurityGroup.fromSecurityGroupId(stack, 'SG', 'sg-123456789'); - const importedWorkgroup = Workgroup.fromWorkgroupAttributes(stack, 'ImportedWorkgroup', { + let securityGroup: aws_ec2.ISecurityGroup; + let importedWorkgroup: IWorkgroup; + + beforeEach(() => { + stack = new Stack(); + securityGroup = aws_ec2.SecurityGroup.fromSecurityGroupId(stack, 'SG', 'sg-123456789'); + importedWorkgroup = Workgroup.fromWorkgroupAttributes(stack, 'ImportedWorkgroup', { workgroupName: 'my-workgroup', workgroupId: 'my-workgroup-id', endpointAddress: 'my-workgroup.endpoint.com', port: 5439, securityGroups: [securityGroup], }); + }); + test('should correctly set workgroupName', () => { expect(importedWorkgroup.workgroupName).toEqual('my-workgroup'); + }); + test('should correctly set workgroupId', () => { expect(importedWorkgroup.workgroupId).toEqual('my-workgroup-id'); + }); + test('should correctly set endpointAddress', () => { expect(importedWorkgroup.endpointAddress).toEqual('my-workgroup.endpoint.com'); + }); + test('should correctly set port', () => { expect(importedWorkgroup.port).toEqual(5439); + }); - expect(importedWorkgroup.workgroupName).toEqual('my-workgroup'); - + test('should correctly format workgroupArn', () => { expect(importedWorkgroup.workgroupArn).toEqual( Stack.of(stack).formatArn({ resource: 'redshift-serverless', @@ -112,7 +124,9 @@ describe('Redshift Serverless Workgroup', () => { resourceName: 'my-workgroup-id', }), ); + }); + test('should correctly set security groups', () => { expect(importedWorkgroup.connections.securityGroups).toEqual([securityGroup]); }); });