Repository: awslabs/aws-ddk (language: python)

Issue:
core: EMR Serverless Cluster Environment
Create a core construct for an EMR serverless cluster 


Discussion / hints:

Fix patch:
diff --git a/API.md b/API.md
index 98cdfab1..585c3537 100644
--- a/API.md
+++ b/API.md
@@ -3343,6 +3343,196 @@ List of CloudWatch Alarms linked to the stage.
 ---
 
 
+### EMRServerlessCluster <a name="EMRServerlessCluster" id="aws-ddk-core.EMRServerlessCluster"></a>
+
+#### Initializers <a name="Initializers" id="aws-ddk-core.EMRServerlessCluster.Initializer"></a>
+
+```typescript
+import { EMRServerlessCluster } from 'aws-ddk-core'
+
+new EMRServerlessCluster(scope: Construct, id: string, props: EMRServerlessClusterProps)
+```
+
+| **Name** | **Type** | **Description** |
+| --- | --- | --- |
+| <code><a href="#aws-ddk-core.EMRServerlessCluster.Initializer.parameter.scope">scope</a></code> | <code>constructs.Construct</code> | *No description.* |
+| <code><a href="#aws-ddk-core.EMRServerlessCluster.Initializer.parameter.id">id</a></code> | <code>string</code> | *No description.* |
+| <code><a href="#aws-ddk-core.EMRServerlessCluster.Initializer.parameter.props">props</a></code> | <code><a href="#aws-ddk-core.EMRServerlessClusterProps">EMRServerlessClusterProps</a></code> | *No description.* |
+
+---
+
+##### `scope`<sup>Required</sup> <a name="scope" id="aws-ddk-core.EMRServerlessCluster.Initializer.parameter.scope"></a>
+
+- *Type:* constructs.Construct
+
+---
+
+##### `id`<sup>Required</sup> <a name="id" id="aws-ddk-core.EMRServerlessCluster.Initializer.parameter.id"></a>
+
+- *Type:* string
+
+---
+
+##### `props`<sup>Required</sup> <a name="props" id="aws-ddk-core.EMRServerlessCluster.Initializer.parameter.props"></a>
+
+- *Type:* <a href="#aws-ddk-core.EMRServerlessClusterProps">EMRServerlessClusterProps</a>
+
+---
+
+#### Methods <a name="Methods" id="Methods"></a>
+
+| **Name** | **Description** |
+| --- | --- |
+| <code><a href="#aws-ddk-core.EMRServerlessCluster.toString">toString</a></code> | Returns a string representation of this construct. |
+| <code><a href="#aws-ddk-core.EMRServerlessCluster.createVpc">createVpc</a></code> | *No description.* |
+
+---
+
+##### `toString` <a name="toString" id="aws-ddk-core.EMRServerlessCluster.toString"></a>
+
+```typescript
+public toString(): string
+```
+
+Returns a string representation of this construct.
+
+##### `createVpc` <a name="createVpc" id="aws-ddk-core.EMRServerlessCluster.createVpc"></a>
+
+```typescript
+public createVpc(scope: Construct, resourceName: string, vpcCidr: string): IVpc
+```
+
+###### `scope`<sup>Required</sup> <a name="scope" id="aws-ddk-core.EMRServerlessCluster.createVpc.parameter.scope"></a>
+
+- *Type:* constructs.Construct
+
+---
+
+###### `resourceName`<sup>Required</sup> <a name="resourceName" id="aws-ddk-core.EMRServerlessCluster.createVpc.parameter.resourceName"></a>
+
+- *Type:* string
+
+---
+
+###### `vpcCidr`<sup>Required</sup> <a name="vpcCidr" id="aws-ddk-core.EMRServerlessCluster.createVpc.parameter.vpcCidr"></a>
+
+- *Type:* string
+
+---
+
+#### Static Functions <a name="Static Functions" id="Static Functions"></a>
+
+| **Name** | **Description** |
+| --- | --- |
+| <code><a href="#aws-ddk-core.EMRServerlessCluster.isConstruct">isConstruct</a></code> | Checks if `x` is a construct. |
+
+---
+
+##### ~~`isConstruct`~~ <a name="isConstruct" id="aws-ddk-core.EMRServerlessCluster.isConstruct"></a>
+
+```typescript
+import { EMRServerlessCluster } from 'aws-ddk-core'
+
+EMRServerlessCluster.isConstruct(x: any)
+```
+
+Checks if `x` is a construct.
+
+###### `x`<sup>Required</sup> <a name="x" id="aws-ddk-core.EMRServerlessCluster.isConstruct.parameter.x"></a>
+
+- *Type:* any
+
+Any object.
+
+---
+
+#### Properties <a name="Properties" id="Properties"></a>
+
+| **Name** | **Type** | **Description** |
+| --- | --- | --- |
+| <code><a href="#aws-ddk-core.EMRServerlessCluster.property.node">node</a></code> | <code>constructs.Node</code> | The tree node. |
+| <code><a href="#aws-ddk-core.EMRServerlessCluster.property.emrServerlessApplication">emrServerlessApplication</a></code> | <code>aws-cdk-lib.aws_emrserverless.CfnApplication</code> | *No description.* |
+| <code><a href="#aws-ddk-core.EMRServerlessCluster.property.networkConfiguration">networkConfiguration</a></code> | <code>aws-cdk-lib.aws_emrserverless.CfnApplication.NetworkConfigurationProperty</code> | *No description.* |
+| <code><a href="#aws-ddk-core.EMRServerlessCluster.property.role">role</a></code> | <code>aws-cdk-lib.aws_iam.Role</code> | *No description.* |
+| <code><a href="#aws-ddk-core.EMRServerlessCluster.property.s3Bucket">s3Bucket</a></code> | <code>aws-cdk-lib.aws_s3.IBucket</code> | *No description.* |
+| <code><a href="#aws-ddk-core.EMRServerlessCluster.property.securityGroup">securityGroup</a></code> | <code>aws-cdk-lib.aws_ec2.SecurityGroup</code> | *No description.* |
+| <code><a href="#aws-ddk-core.EMRServerlessCluster.property.vpc">vpc</a></code> | <code>aws-cdk-lib.aws_ec2.IVpc</code> | *No description.* |
+
+---
+
+##### `node`<sup>Required</sup> <a name="node" id="aws-ddk-core.EMRServerlessCluster.property.node"></a>
+
+```typescript
+public readonly node: Node;
+```
+
+- *Type:* constructs.Node
+
+The tree node.
+
+---
+
+##### `emrServerlessApplication`<sup>Required</sup> <a name="emrServerlessApplication" id="aws-ddk-core.EMRServerlessCluster.property.emrServerlessApplication"></a>
+
+```typescript
+public readonly emrServerlessApplication: CfnApplication;
+```
+
+- *Type:* aws-cdk-lib.aws_emrserverless.CfnApplication
+
+---
+
+##### `networkConfiguration`<sup>Required</sup> <a name="networkConfiguration" id="aws-ddk-core.EMRServerlessCluster.property.networkConfiguration"></a>
+
+```typescript
+public readonly networkConfiguration: NetworkConfigurationProperty;
+```
+
+- *Type:* aws-cdk-lib.aws_emrserverless.CfnApplication.NetworkConfigurationProperty
+
+---
+
+##### `role`<sup>Required</sup> <a name="role" id="aws-ddk-core.EMRServerlessCluster.property.role"></a>
+
+```typescript
+public readonly role: Role;
+```
+
+- *Type:* aws-cdk-lib.aws_iam.Role
+
+---
+
+##### `s3Bucket`<sup>Required</sup> <a name="s3Bucket" id="aws-ddk-core.EMRServerlessCluster.property.s3Bucket"></a>
+
+```typescript
+public readonly s3Bucket: IBucket;
+```
+
+- *Type:* aws-cdk-lib.aws_s3.IBucket
+
+---
+
+##### `securityGroup`<sup>Optional</sup> <a name="securityGroup" id="aws-ddk-core.EMRServerlessCluster.property.securityGroup"></a>
+
+```typescript
+public readonly securityGroup: SecurityGroup;
+```
+
+- *Type:* aws-cdk-lib.aws_ec2.SecurityGroup
+
+---
+
+##### `vpc`<sup>Optional</sup> <a name="vpc" id="aws-ddk-core.EMRServerlessCluster.property.vpc"></a>
+
+```typescript
+public readonly vpc: IVpc;
+```
+
+- *Type:* aws-cdk-lib.aws_ec2.IVpc
+
+---
+
+
 ### EventStage <a name="EventStage" id="aws-ddk-core.EventStage"></a>
 
 Class that represents an event stage within a data pipeline.
@@ -8647,6 +8837,284 @@ The Kinesis data stream to use as a source for this delivery stream.
 
 ---
 
+### EMRServerlessClusterProps <a name="EMRServerlessClusterProps" id="aws-ddk-core.EMRServerlessClusterProps"></a>
+
+#### Initializer <a name="Initializer" id="aws-ddk-core.EMRServerlessClusterProps.Initializer"></a>
+
+```typescript
+import { EMRServerlessClusterProps } from 'aws-ddk-core'
+
+const eMRServerlessClusterProps: EMRServerlessClusterProps = { ... }
+```
+
+#### Properties <a name="Properties" id="Properties"></a>
+
+| **Name** | **Type** | **Description** |
+| --- | --- | --- |
+| <code><a href="#aws-ddk-core.EMRServerlessClusterProps.property.releaseLabel">releaseLabel</a></code> | <code>string</code> | The EMR release version associated with the application. |
+| <code><a href="#aws-ddk-core.EMRServerlessClusterProps.property.type">type</a></code> | <code>string</code> | The type of application, such as Spark or Hive. |
+| <code><a href="#aws-ddk-core.EMRServerlessClusterProps.property.architecture">architecture</a></code> | <code>string</code> | The CPU architecture type of the application. |
+| <code><a href="#aws-ddk-core.EMRServerlessClusterProps.property.autoStartConfiguration">autoStartConfiguration</a></code> | <code>aws-cdk-lib.IResolvable \| aws-cdk-lib.aws_emrserverless.CfnApplication.AutoStartConfigurationProperty</code> | The configuration for an application to automatically start on job submission. |
+| <code><a href="#aws-ddk-core.EMRServerlessClusterProps.property.autoStopConfiguration">autoStopConfiguration</a></code> | <code>aws-cdk-lib.IResolvable \| aws-cdk-lib.aws_emrserverless.CfnApplication.AutoStopConfigurationProperty</code> | The configuration for an application to automatically stop after a certain amount of time being idle. |
+| <code><a href="#aws-ddk-core.EMRServerlessClusterProps.property.imageConfiguration">imageConfiguration</a></code> | <code>aws-cdk-lib.IResolvable \| aws-cdk-lib.aws_emrserverless.CfnApplication.ImageConfigurationInputProperty</code> | `AWS::EMRServerless::Application.ImageConfiguration`. |
+| <code><a href="#aws-ddk-core.EMRServerlessClusterProps.property.initialCapacity">initialCapacity</a></code> | <code>aws-cdk-lib.IResolvable \| aws-cdk-lib.IResolvable \| aws-cdk-lib.aws_emrserverless.CfnApplication.InitialCapacityConfigKeyValuePairProperty[]</code> | The initial capacity of the application. |
+| <code><a href="#aws-ddk-core.EMRServerlessClusterProps.property.maximumCapacity">maximumCapacity</a></code> | <code>aws-cdk-lib.IResolvable \| aws-cdk-lib.aws_emrserverless.CfnApplication.MaximumAllowedResourcesProperty</code> | The maximum capacity of the application. |
+| <code><a href="#aws-ddk-core.EMRServerlessClusterProps.property.name">name</a></code> | <code>string</code> | The name of the application. |
+| <code><a href="#aws-ddk-core.EMRServerlessClusterProps.property.networkConfiguration">networkConfiguration</a></code> | <code>aws-cdk-lib.IResolvable \| aws-cdk-lib.aws_emrserverless.CfnApplication.NetworkConfigurationProperty</code> | The network configuration for customer VPC connectivity for the application. |
+| <code><a href="#aws-ddk-core.EMRServerlessClusterProps.property.tags">tags</a></code> | <code>aws-cdk-lib.CfnTag[]</code> | The tags assigned to the application. |
+| <code><a href="#aws-ddk-core.EMRServerlessClusterProps.property.workerTypeSpecifications">workerTypeSpecifications</a></code> | <code>aws-cdk-lib.IResolvable \| {[ key: string ]: aws-cdk-lib.IResolvable \| aws-cdk-lib.aws_emrserverless.CfnApplication.WorkerTypeSpecificationInputProperty}</code> | `AWS::EMRServerless::Application.WorkerTypeSpecifications`. |
+| <code><a href="#aws-ddk-core.EMRServerlessClusterProps.property.additionalPolicyStatements">additionalPolicyStatements</a></code> | <code>aws-cdk-lib.aws_iam.PolicyStatement[]</code> | Additional policy statements to add to the emr role. |
+| <code><a href="#aws-ddk-core.EMRServerlessClusterProps.property.s3Bucket">s3Bucket</a></code> | <code>aws-cdk-lib.aws_s3.IBucket</code> | S3 Bucket. |
+| <code><a href="#aws-ddk-core.EMRServerlessClusterProps.property.securityGroup">securityGroup</a></code> | <code>aws-cdk-lib.aws_ec2.SecurityGroup</code> | Security Group. |
+| <code><a href="#aws-ddk-core.EMRServerlessClusterProps.property.vpcCidr">vpcCidr</a></code> | <code>string</code> | The IP range (CIDR notation) for this VPC. |
+| <code><a href="#aws-ddk-core.EMRServerlessClusterProps.property.vpcId">vpcId</a></code> | <code>string</code> | Existing vpc id. |
+
+---
+
+##### `releaseLabel`<sup>Required</sup> <a name="releaseLabel" id="aws-ddk-core.EMRServerlessClusterProps.property.releaseLabel"></a>
+
+```typescript
+public readonly releaseLabel: string;
+```
+
+- *Type:* string
+
+The EMR release version associated with the application.
+
+*Minimum* : 1
+
+*Maximum* : 64
+
+*Pattern* : `^[A-Za-z0-9._/-]+$`
+
+> [http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-emrserverless-application.html#cfn-emrserverless-application-releaselabel](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-emrserverless-application.html#cfn-emrserverless-application-releaselabel)
+
+---
+
+##### `type`<sup>Required</sup> <a name="type" id="aws-ddk-core.EMRServerlessClusterProps.property.type"></a>
+
+```typescript
+public readonly type: string;
+```
+
+- *Type:* string
+
+The type of application, such as Spark or Hive.
+
+> [http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-emrserverless-application.html#cfn-emrserverless-application-type](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-emrserverless-application.html#cfn-emrserverless-application-type)
+
+---
+
+##### `architecture`<sup>Optional</sup> <a name="architecture" id="aws-ddk-core.EMRServerlessClusterProps.property.architecture"></a>
+
+```typescript
+public readonly architecture: string;
+```
+
+- *Type:* string
+
+The CPU architecture type of the application.
+
+Allowed values: `X86_64` or `ARM64`
+
+> [http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-emrserverless-application.html#cfn-emrserverless-application-architecture](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-emrserverless-application.html#cfn-emrserverless-application-architecture)
+
+---
+
+##### `autoStartConfiguration`<sup>Optional</sup> <a name="autoStartConfiguration" id="aws-ddk-core.EMRServerlessClusterProps.property.autoStartConfiguration"></a>
+
+```typescript
+public readonly autoStartConfiguration: IResolvable | AutoStartConfigurationProperty;
+```
+
+- *Type:* aws-cdk-lib.IResolvable | aws-cdk-lib.aws_emrserverless.CfnApplication.AutoStartConfigurationProperty
+
+The configuration for an application to automatically start on job submission.
+
+> [http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-emrserverless-application.html#cfn-emrserverless-application-autostartconfiguration](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-emrserverless-application.html#cfn-emrserverless-application-autostartconfiguration)
+
+---
+
+##### `autoStopConfiguration`<sup>Optional</sup> <a name="autoStopConfiguration" id="aws-ddk-core.EMRServerlessClusterProps.property.autoStopConfiguration"></a>
+
+```typescript
+public readonly autoStopConfiguration: IResolvable | AutoStopConfigurationProperty;
+```
+
+- *Type:* aws-cdk-lib.IResolvable | aws-cdk-lib.aws_emrserverless.CfnApplication.AutoStopConfigurationProperty
+
+The configuration for an application to automatically stop after a certain amount of time being idle.
+
+> [http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-emrserverless-application.html#cfn-emrserverless-application-autostopconfiguration](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-emrserverless-application.html#cfn-emrserverless-application-autostopconfiguration)
+
+---
+
+##### `imageConfiguration`<sup>Optional</sup> <a name="imageConfiguration" id="aws-ddk-core.EMRServerlessClusterProps.property.imageConfiguration"></a>
+
+```typescript
+public readonly imageConfiguration: IResolvable | ImageConfigurationInputProperty;
+```
+
+- *Type:* aws-cdk-lib.IResolvable | aws-cdk-lib.aws_emrserverless.CfnApplication.ImageConfigurationInputProperty
+
+`AWS::EMRServerless::Application.ImageConfiguration`.
+
+> [http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-emrserverless-application.html#cfn-emrserverless-application-imageconfiguration](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-emrserverless-application.html#cfn-emrserverless-application-imageconfiguration)
+
+---
+
+##### `initialCapacity`<sup>Optional</sup> <a name="initialCapacity" id="aws-ddk-core.EMRServerlessClusterProps.property.initialCapacity"></a>
+
+```typescript
+public readonly initialCapacity: IResolvable | IResolvable | InitialCapacityConfigKeyValuePairProperty[];
+```
+
+- *Type:* aws-cdk-lib.IResolvable | aws-cdk-lib.IResolvable | aws-cdk-lib.aws_emrserverless.CfnApplication.InitialCapacityConfigKeyValuePairProperty[]
+
+The initial capacity of the application.
+
+> [http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-emrserverless-application.html#cfn-emrserverless-application-initialcapacity](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-emrserverless-application.html#cfn-emrserverless-application-initialcapacity)
+
+---
+
+##### `maximumCapacity`<sup>Optional</sup> <a name="maximumCapacity" id="aws-ddk-core.EMRServerlessClusterProps.property.maximumCapacity"></a>
+
+```typescript
+public readonly maximumCapacity: IResolvable | MaximumAllowedResourcesProperty;
+```
+
+- *Type:* aws-cdk-lib.IResolvable | aws-cdk-lib.aws_emrserverless.CfnApplication.MaximumAllowedResourcesProperty
+
+The maximum capacity of the application.
+
+This is cumulative across all workers at any given point in time during the lifespan of the application is created. No new resources will be created once any one of the defined limits is hit.
+
+> [http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-emrserverless-application.html#cfn-emrserverless-application-maximumcapacity](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-emrserverless-application.html#cfn-emrserverless-application-maximumcapacity)
+
+---
+
+##### `name`<sup>Optional</sup> <a name="name" id="aws-ddk-core.EMRServerlessClusterProps.property.name"></a>
+
+```typescript
+public readonly name: string;
+```
+
+- *Type:* string
+
+The name of the application.
+
+*Minimum* : 1
+
+*Maximum* : 64
+
+*Pattern* : `^[A-Za-z0-9._\\/#-]+$`
+
+> [http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-emrserverless-application.html#cfn-emrserverless-application-name](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-emrserverless-application.html#cfn-emrserverless-application-name)
+
+---
+
+##### `networkConfiguration`<sup>Optional</sup> <a name="networkConfiguration" id="aws-ddk-core.EMRServerlessClusterProps.property.networkConfiguration"></a>
+
+```typescript
+public readonly networkConfiguration: IResolvable | NetworkConfigurationProperty;
+```
+
+- *Type:* aws-cdk-lib.IResolvable | aws-cdk-lib.aws_emrserverless.CfnApplication.NetworkConfigurationProperty
+
+The network configuration for customer VPC connectivity for the application.
+
+> [http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-emrserverless-application.html#cfn-emrserverless-application-networkconfiguration](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-emrserverless-application.html#cfn-emrserverless-application-networkconfiguration)
+
+---
+
+##### `tags`<sup>Optional</sup> <a name="tags" id="aws-ddk-core.EMRServerlessClusterProps.property.tags"></a>
+
+```typescript
+public readonly tags: CfnTag[];
+```
+
+- *Type:* aws-cdk-lib.CfnTag[]
+
+The tags assigned to the application.
+
+> [http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-emrserverless-application.html#cfn-emrserverless-application-tags](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-emrserverless-application.html#cfn-emrserverless-application-tags)
+
+---
+
+##### `workerTypeSpecifications`<sup>Optional</sup> <a name="workerTypeSpecifications" id="aws-ddk-core.EMRServerlessClusterProps.property.workerTypeSpecifications"></a>
+
+```typescript
+public readonly workerTypeSpecifications: IResolvable | {[ key: string ]: IResolvable | WorkerTypeSpecificationInputProperty};
+```
+
+- *Type:* aws-cdk-lib.IResolvable | {[ key: string ]: aws-cdk-lib.IResolvable | aws-cdk-lib.aws_emrserverless.CfnApplication.WorkerTypeSpecificationInputProperty}
+
+`AWS::EMRServerless::Application.WorkerTypeSpecifications`.
+
+> [http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-emrserverless-application.html#cfn-emrserverless-application-workertypespecifications](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-emrserverless-application.html#cfn-emrserverless-application-workertypespecifications)
+
+---
+
+##### `additionalPolicyStatements`<sup>Optional</sup> <a name="additionalPolicyStatements" id="aws-ddk-core.EMRServerlessClusterProps.property.additionalPolicyStatements"></a>
+
+```typescript
+public readonly additionalPolicyStatements: PolicyStatement[];
+```
+
+- *Type:* aws-cdk-lib.aws_iam.PolicyStatement[]
+
+Additional policy statements to add to the emr role.
+
+---
+
+##### `s3Bucket`<sup>Optional</sup> <a name="s3Bucket" id="aws-ddk-core.EMRServerlessClusterProps.property.s3Bucket"></a>
+
+```typescript
+public readonly s3Bucket: IBucket;
+```
+
+- *Type:* aws-cdk-lib.aws_s3.IBucket
+
+S3 Bucket.
+
+---
+
+##### `securityGroup`<sup>Optional</sup> <a name="securityGroup" id="aws-ddk-core.EMRServerlessClusterProps.property.securityGroup"></a>
+
+```typescript
+public readonly securityGroup: SecurityGroup;
+```
+
+- *Type:* aws-cdk-lib.aws_ec2.SecurityGroup
+
+Security Group.
+
+---
+
+##### `vpcCidr`<sup>Optional</sup> <a name="vpcCidr" id="aws-ddk-core.EMRServerlessClusterProps.property.vpcCidr"></a>
+
+```typescript
+public readonly vpcCidr: string;
+```
+
+- *Type:* string
+
+The IP range (CIDR notation) for this VPC.
+
+---
+
+##### `vpcId`<sup>Optional</sup> <a name="vpcId" id="aws-ddk-core.EMRServerlessClusterProps.property.vpcId"></a>
+
+```typescript
+public readonly vpcId: string;
+```
+
+- *Type:* string
+
+Existing vpc id.
+
+---
+
 ### EnvironmentConfiguration <a name="EnvironmentConfiguration" id="aws-ddk-core.EnvironmentConfiguration"></a>
 
 #### Initializer <a name="Initializer" id="aws-ddk-core.EnvironmentConfiguration.Initializer"></a>
diff --git a/src/core/emr-serverless-cluster.ts b/src/core/emr-serverless-cluster.ts
new file mode 100644
index 00000000..3af42177
--- /dev/null
+++ b/src/core/emr-serverless-cluster.ts
@@ -0,0 +1,161 @@
+import * as ec2 from "aws-cdk-lib/aws-ec2";
+import * as emr from "aws-cdk-lib/aws-emrserverless";
+import * as iam from "aws-cdk-lib/aws-iam";
+import * as s3 from "aws-cdk-lib/aws-s3";
+import { Construct } from "constructs";
+
+import { S3Factory } from "./s3-factory";
+import { overrideProps } from "./utils";
+
+export interface EMRServerlessClusterProps extends emr.CfnApplicationProps {
+  /**
+   * Existing vpc id
+   */
+  readonly vpcId?: string;
+  /**
+   * The IP range (CIDR notation) for this VPC
+   */
+  readonly vpcCidr?: string;
+  /**
+   * S3 Bucket
+   */
+  readonly s3Bucket?: s3.IBucket;
+  /**
+   * Security Group
+   */
+  readonly securityGroup?: ec2.SecurityGroup;
+  /**
+   * Additional policy statements to add to the emr role
+   */
+  readonly additionalPolicyStatements?: iam.PolicyStatement[];
+}
+
+export class EMRServerlessCluster extends Construct {
+  readonly vpc?: ec2.IVpc;
+  readonly s3Bucket: s3.IBucket;
+  readonly role: iam.Role;
+  readonly emrServerlessApplication: emr.CfnApplication;
+  readonly securityGroup?: ec2.SecurityGroup;
+  readonly networkConfiguration: emr.CfnApplication.NetworkConfigurationProperty;
+
+  constructor(scope: Construct, id: string, props: EMRServerlessClusterProps) {
+    super(scope, id);
+
+    const name = props.name ?? "DDKEmrServerlessCluster";
+
+    if (props.vpcId) {
+      this.vpc = ec2.Vpc.fromLookup(scope, "VPC", { vpcId: props.vpcId });
+    } else if (props.vpcCidr) {
+      this.vpc = this.createVpc(scope, name, props.vpcCidr);
+    } else {
+      throw new Error("One of 'vpcId' or 'vpcCidr' must be provided");
+    }
+
+    if (this.vpc) {
+      this.securityGroup =
+        props.securityGroup ??
+        new ec2.SecurityGroup(scope, "EMR Serverless Security Group", {
+          securityGroupName: `EMR Serverless Security Group`,
+          description: "Security group with a self-referencing inbound rule.",
+          vpc: this.vpc,
+        });
+      this.securityGroup.addIngressRule(this.securityGroup, ec2.Port.allTraffic(), "Self referencing rule");
+    }
+    if (props.s3Bucket) {
+      this.s3Bucket = props.s3Bucket;
+    } else {
+      this.s3Bucket = S3Factory.bucket(this, "EMR Serverless Cluster Bucket", {
+        versioned: true,
+      });
+    }
+
+    this.role = new iam.Role(scope, "EMR Serverless Cluster Role", {
+      assumedBy: new iam.ServicePrincipal("emr-serverless.amazonaws.com"),
+      path: "/service-role/",
+    });
+    this.role.addManagedPolicy(
+      new iam.ManagedPolicy(this, "MWAA Execution Policy", {
+        statements: [
+          new iam.PolicyStatement({
+            actions: ["s3:GetObject*", "s3:ListBucket"],
+            resources: ["arn:aws:s3:::*.elasticmapreduce", "arn:aws:s3:::*.elasticmapreduce/*"],
+          }),
+          new iam.PolicyStatement({
+            actions: ["s3:DeleteObject", "s3:PutObject", "s3:GetObject*", "s3:GetBucket*", "s3:List*"],
+            resources: [this.s3Bucket.bucketArn, `${this.s3Bucket.bucketArn}/*`],
+          }),
+          new iam.PolicyStatement({
+            actions: [
+              "glue:GetDatabase",
+              "glue:CreateDatabase",
+              "glue:GetDataBases",
+              "glue:CreateTable",
+              "glue:GetTable",
+              "glue:UpdateTable",
+              "glue:DeleteTable",
+              "glue:GetTables",
+              "glue:GetPartition",
+              "glue:GetPartitions",
+              "glue:CreatePartition",
+              "glue:BatchCreatePartition",
+              "glue:GetUserDefinedFunctions",
+            ],
+            resources: ["*"],
+          }),
+        ],
+      }),
+    );
+
+    if (props.additionalPolicyStatements) {
+      props.additionalPolicyStatements.forEach((statement) => {
+        this.role.addToPolicy(statement);
+      });
+    }
+
+    if (!props.networkConfiguration && this.vpc && this.securityGroup) {
+      this.networkConfiguration = {
+        securityGroupIds: [this.securityGroup.securityGroupId],
+        subnetIds: this.vpc.selectSubnets({ subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }).subnetIds,
+      };
+    } else {
+      this.networkConfiguration = {};
+    }
+
+    const defaultProps: Partial<emr.CfnApplicationProps> = {
+      networkConfiguration: this.networkConfiguration,
+    };
+
+    const mergedProps = overrideProps(defaultProps, props);
+
+    this.emrServerlessApplication = new emr.CfnApplication(this, "DDK EMR Serverless Application", {
+      ...mergedProps,
+    });
+  }
+  createVpc(scope: Construct, resourceName: string, vpcCidr: string): ec2.IVpc {
+    const vpcCIDRMask = +vpcCidr.split("/")[1];
+    if (vpcCIDRMask > 20 || vpcCIDRMask < 16) {
+      throw new Error("Vpc Cidr Range must of size >=16 and <=20");
+    }
+    const subnetCIDRMask = vpcCIDRMask + 4;
+    const vpc = new ec2.Vpc(scope, "Vpc", {
+      ipAddresses: ec2.IpAddresses.cidr(vpcCidr),
+      enableDnsSupport: true,
+      enableDnsHostnames: true,
+      vpcName: resourceName,
+      subnetConfiguration: [
+        {
+          name: "Public",
+          subnetType: ec2.SubnetType.PUBLIC,
+          cidrMask: subnetCIDRMask,
+        },
+        {
+          name: "Private",
+          subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
+          cidrMask: subnetCIDRMask,
+        },
+      ],
+    });
+
+    return vpc;
+  }
+}
diff --git a/src/core/index.ts b/src/core/index.ts
index 7eb69fda..547e87de 100644
--- a/src/core/index.ts
+++ b/src/core/index.ts
@@ -1,3 +1,4 @@
+export * from "./emr-serverless-cluster";
 export * from "./mwaa-environment";
 export * from "./glue-factory";
 export * from "./kms-factory";


Test patch:
diff --git a/test/emr-serverless-cluster.test.ts b/test/emr-serverless-cluster.test.ts
new file mode 100644
index 00000000..bcebe79c
--- /dev/null
+++ b/test/emr-serverless-cluster.test.ts
@@ -0,0 +1,94 @@
+import * as cdk from "aws-cdk-lib";
+import { Match, Template } from "aws-cdk-lib/assertions";
+import * as s3 from "aws-cdk-lib/aws-s3";
+
+import { EMRServerlessCluster } from "../src";
+
+test("EMR Serverless Cluster Existing Vpc & Bucket", () => {
+  const app = new cdk.App();
+  const stack = new cdk.Stack(app, "dummy-stack", {
+    env: {
+      account: "123456789012",
+      region: "us-east-1",
+    },
+  });
+  new EMRServerlessCluster(stack, "MWAA-pipeline", {
+    releaseLabel: "emr-6.11.0",
+    type: "SPARK",
+    name: "MyEMRApp",
+    vpcId: "vpc-01234567",
+    s3Bucket: new s3.Bucket(stack, "my-dummy-bucket", {}),
+  });
+
+  const template = Template.fromStack(stack);
+  template.hasResourceProperties("AWS::EMRServerless::Application", {});
+  template.hasResourceProperties("AWS::IAM::Role", {});
+  template.resourceCountIs("AWS::EC2::VPC", 0);
+});
+
+test("EMR Serverless Cluster New Vpc & Bucket", () => {
+  const app = new cdk.App();
+  const stack = new cdk.Stack(app, "dummy-stack", {
+    env: {
+      account: "123456789012",
+      region: "us-east-1",
+    },
+  });
+  new EMRServerlessCluster(stack, "EMR App", {
+    releaseLabel: "emr-6.11.0",
+    type: "SPARK",
+    name: "MyEMRApp",
+    vpcCidr: "10.40.0.0/16",
+  });
+
+  const template = Template.fromStack(stack);
+  template.hasResourceProperties("AWS::EMRServerless::Application", {
+    Name: "MyEMRApp",
+    NetworkConfiguration: {
+      SecurityGroupIds: Match.anyValue(),
+      SubnetIds: [Match.anyValue(), Match.anyValue(), Match.anyValue()],
+    },
+  });
+  template.hasResourceProperties("AWS::IAM::Role", {});
+  template.resourceCountIs("AWS::EC2::VPC", 1);
+  template.hasResourceProperties("AWS::EC2::VPC", {
+    CidrBlock: "10.40.0.0/16",
+  });
+  template.resourceCountIs("AWS::EC2::Subnet", 6);
+  template.resourceCountIs("AWS::EC2::NatGateway", 3);
+  template.resourceCountIs("AWS::EC2::Route", 6);
+  template.resourceCountIs("AWS::EC2::InternetGateway", 1);
+  template.resourceCountIs("AWS::EC2::VPCGatewayAttachment", 1);
+  template.resourceCountIs("AWS::S3::Bucket", 1);
+});
+
+test("Vpc Cidr or Id must be provided", () => {
+  const stack = new cdk.Stack();
+  expect(() => {
+    new EMRServerlessCluster(stack, "Stage", { name: "EmrApp", releaseLabel: "emr-6.11.0", type: "SPARK" });
+  }).toThrowError("One of 'vpcId' or 'vpcCidr' must be provided");
+});
+
+test("Invalid Vpc Cidr: Too Large", () => {
+  const stack = new cdk.Stack();
+  expect(() => {
+    new EMRServerlessCluster(stack, "Stage", {
+      name: "EmrApp",
+      releaseLabel: "emr-6.11.0",
+      type: "SPARK",
+      vpcCidr: "10.0.0.0/15",
+    });
+  }).toThrowError("Vpc Cidr Range must of size >=16 and <=20");
+});
+
+test("Invalid Vpc Cidr: Too Small", () => {
+  const stack = new cdk.Stack();
+  expect(() => {
+    new EMRServerlessCluster(stack, "Stage", {
+      name: "EmrApp",
+      releaseLabel: "emr-6.11.0",
+      type: "SPARK",
+      vpcCidr: "10.0.0.0/21",
+    });
+  }).toThrowError("Vpc Cidr Range must of size >=16 and <=20");
+});