Skip to content

Commit f4829ba

Browse files
authored
feat(aws-fargate-stepfunctions): new construct (#677)
* created README.md * removed arn env var prop and fixed state machine doc comments * made createCloudWatchAlarms prop optional * created new construct * fixed README typo * refactored test to single concept design * updated default for vpcProps
1 parent 45ebd9f commit f4829ba

13 files changed

+3558
-2
lines changed

DESIGN_GUIDELINES.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -347,14 +347,14 @@ Existing Inconsistencies would not be published, that’s for our internal use
347347
| Name | Type | Description | Notes |
348348
| --- | --- | --- |--- |
349349
| stateMachineProps |[`sfn.StateMachineProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-stepfunctions.StateMachineProps.html)|Optional user provided props to override the default props for `sfn.StateMachine`|
350-
| createCloudWatchAlarms | `boolean`|Whether to create recommended CloudWatch alarms.|
350+
| createCloudWatchAlarms? | `boolean`|Whether to create recommended CloudWatch alarms.|
351351

352352
**Required Construct Properties**
353353

354354
| Name | Type | Description | Notes |
355355
| --- | --- | --- |--- |
356356
| stateMachine| [`sfn.StateMachine`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-stepfunctions.StateMachine.html)|Returns an instance of `sfn.StateMachine` created by the construct.|
357-
| stateMachineLoggingGroup|[`logs.ILogGroup`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-logs.ILogGroup.html)|Returns an instance of the `logs.ILogGroup` created by the construct for StateMachine.|
357+
| stateMachineLogGroup|[`logs.ILogGroup`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-logs.ILogGroup.html)|Returns an instance of the `logs.ILogGroup` created by the construct for StateMachine.|
358358
| cloudwatchAlarms? | [`cloudwatch.Alarm[]`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cloudwatch.Alarm.html)|Returns a list of `cloudwatch.Alarm` created by the construct.|
359359

360360
## VPC
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
lib/*.js
2+
test/*.js
3+
*.d.ts
4+
coverage
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
lib/*.js
2+
test/*.js
3+
*.js.map
4+
*.d.ts
5+
node_modules
6+
*.generated.ts
7+
dist
8+
.jsii
9+
10+
.LAST_BUILD
11+
.nyc_output
12+
coverage
13+
.nycrc
14+
.LAST_PACKAGE
15+
*.snk
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Exclude typescript source and config
2+
*.ts
3+
tsconfig.json
4+
coverage
5+
.nyc_output
6+
*.tgz
7+
*.snk
8+
*.tsbuildinfo
9+
10+
# Include javascript files and typescript declarations
11+
!*.js
12+
!*.d.ts
13+
14+
# Exclude jsii outdir
15+
dist
16+
17+
# Include .jsii
18+
!.jsii
19+
20+
# Include .jsii
21+
!.jsii
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
# aws-fargate-stepfunctions module
2+
<!--BEGIN STABILITY BANNER-->
3+
4+
---
5+
6+
![Stability: Experimental](https://img.shields.io/badge/stability-Experimental-important.svg?style=for-the-badge)
7+
8+
> All classes are under active development and subject to non-backward compatible changes or removal in any
9+
> future version. These are not subject to the [Semantic Versioning](https://semver.org/) model.
10+
> This means that while you may use them, you may need to update your source code when upgrading to a newer version of this package.
11+
12+
---
13+
<!--END STABILITY BANNER-->
14+
15+
| **Reference Documentation**:| <span style="font-weight: normal">https://docs.aws.amazon.com/solutions/latest/constructs/</span>|
16+
|:-------------|:-------------|
17+
<div style="height:8px"></div>
18+
19+
| **Language** | **Package** |
20+
|:-------------|-----------------|
21+
|![Python Logo](https://docs.aws.amazon.com/cdk/api/latest/img/python32.png) Python|`aws_solutions_constructs.aws_fargate_stepfunctions`|
22+
|![Typescript Logo](https://docs.aws.amazon.com/cdk/api/latest/img/typescript32.png) Typescript|`@aws-solutions-constructs/aws-fargate-stepfunctions`|
23+
|![Java Logo](https://docs.aws.amazon.com/cdk/api/latest/img/java32.png) Java|`software.amazon.awsconstructs.services.fargatestepfunctions`|
24+
25+
This AWS Solutions Construct implements an AWS Fargate service that can execute an AWS Step Functions state machine
26+
27+
Here is a minimal deployable pattern definition:
28+
29+
Typescript
30+
``` typescript
31+
import { Construct } from 'constructs';
32+
import { Stack, StackProps } from 'aws-cdk-lib';
33+
import { FargateToStepfunctions, FargateToStepfunctionsProps } from '@aws-solutions-constructs/aws-fargate-stepfunctions';
34+
import * as stepfunctions from 'aws-cdk-lib/aws-stepfunctions';
35+
36+
const startState = new stepfunctions.Pass(this, 'StartState');
37+
38+
const constructProps: FargateToStepfunctionsProps = {
39+
publicApi: true,
40+
ecrRepositoryArn: "arn:aws:ecr:us-east-1:123456789012:repository/your-ecr-repo",
41+
stateMachineProps: {
42+
definition: startState
43+
}
44+
};
45+
46+
new FargateToStepfunctions(this, 'test-construct', constructProps);
47+
```
48+
49+
Python
50+
``` python
51+
from aws_solutions_constructs.aws_fargate_stepfunctions import FargateToStepfunctions, FargateToStepfunctionsProps
52+
from aws_cdk import (
53+
aws_stepfunctions as stepfunctions,
54+
Stack
55+
)
56+
from constructs import Construct
57+
58+
start_state = stepfunctions.Pass(self, 'start_state')
59+
60+
FargateToStepfunctions(self, 'test_construct',
61+
public_api=True,
62+
ecr_repository_arn="arn:aws:ecr:us-east-1:123456789012:repository/your-ecr-repo",
63+
state_machine_props=stepfunctions.StateMachineProps(
64+
definition=start_state))
65+
```
66+
67+
Java
68+
``` java
69+
import software.constructs.Construct;
70+
71+
import software.amazon.awscdk.Stack;
72+
import software.amazon.awscdk.StackProps;
73+
import software.amazon.awsconstructs.services.fargatestepfunctions.*;
74+
import software.amazon.awscdk.services.stepfunctions.*;
75+
76+
start_state = stepfunctions.Pass(self, 'start_state')
77+
78+
new FargateToStepfunctions(this, "test-construct", new FargateToStepfunctionsProps.Builder()
79+
.publicApi(true)
80+
.ecrRepositoryArn("arn:aws:ecr:us-east-1:123456789012:repository/your-ecr-repo")
81+
.stateMachineProps(new StateMachineProps.Builder()
82+
.definition(startState)
83+
.build()
84+
.build());
85+
```
86+
87+
## Pattern Construct Props
88+
89+
| **Name** | **Type** | **Description** |
90+
|:-------------|:----------------|-----------------|
91+
| publicApi | `boolean` | Whether the construct is deploying a private or public API. This has implications for the VPC. |
92+
| vpcProps? | [`ec2.VpcProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.VpcProps.html) | Optional custom properties for a VPC the construct will create. This VPC will be used by any Private Hosted Zone the construct creates (that's why loadBalancerProps and privateHostedZoneProps can't include a VPC). Providing both this and existingVpc is an error. |
93+
| existingVpc? | [`ec2.IVpc`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.IVpc.html) | An existing VPC in which to deploy the construct. Providing both this and vpcProps is an error. If the client provides an existing load balancer and/or existing Private Hosted Zone, those constructs must exist in this VPC. |
94+
| clusterProps? | [`ecs.ClusterProps`](https://docs.aws.amazon.com/cdk/api/v1/docs/@aws-cdk_aws-ecs.ClusterProps.html) | Optional properties to create a new ECS cluster. To provide an existing cluster, use the cluster attribute of fargateServiceProps. |
95+
| ecrRepositoryArn? | `string` | The arn of an ECR Repository containing the image to use to generate the containers. Either this or the image property of containerDefinitionProps must be provided. format: arn:aws:ecr:*region*:*account number*:repository/*Repository Name* |
96+
| ecrImageVersion? | `string` | The version of the image to use from the repository. Defaults to 'Latest' |
97+
| containerDefinitionProps? | [`ecs.ContainerDefinitionProps \| any`](https://docs.aws.amazon.com/cdk/api/v1/docs/@aws-cdk_aws-ecs.ContainerDefinitionProps.html) | Optional props to define the container created for the Fargate Service (defaults found in fargate-defaults.ts) |
98+
| fargateTaskDefinitionProps? | [`ecs.FargateTaskDefinitionProps \| any`](https://docs.aws.amazon.com/cdk/api/v1/docs/@aws-cdk_aws-ecs.FargateTaskDefinitionProps.html) | Optional props to define the Fargate Task Definition for this construct (defaults found in fargate-defaults.ts) |
99+
| fargateServiceProps? | [`ecs.FargateServiceProps \| any`](https://docs.aws.amazon.com/cdk/api/v1/docs/@aws-cdk_aws-ecs.FargateServiceProps.html) | Optional values to override default Fargate Task definition properties (fargate-defaults.ts). The construct will default to launching the service is the most isolated subnets available (precedence: Isolated, Private and Public). Override those and other defaults here. |
100+
|existingFargateServiceObject? | [`ecs.FargateService`](https://docs.aws.amazon.com/cdk/api/v1/docs/@aws-cdk_aws-ecs.FargateService.html) | A Fargate Service already instantiated (probably by another Solutions Construct). If this is specified, then no props defining a new service can be provided, including: ecrImageVersion, containerDefinitionProps, fargateTaskDefinitionProps, ecrRepositoryArn, fargateServiceProps, clusterProps |
101+
|existingContainerDefinitionObject? | [`ecs.ContainerDefinition`](https://docs.aws.amazon.com/cdk/api/v1/docs/@aws-cdk_aws-ecs.ContainerDefinition.html) | A container definition already instantiated as part of a Fargate service. This must be the container in the existingFargateServiceObject |
102+
|stateMachineProps|[`sfn.StateMachineProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-stepfunctions.StateMachineProps.html)|User provided props to override the default props for sfn.StateMachine.|
103+
| createCloudWatchAlarms? | `boolean`|Whether to create recommended CloudWatch alarms. Default is true.|
104+
|logGroupProps?|[`logs.LogGroupProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-logs.LogGroupProps.html)|Optional user provided props to override the default props for for the CloudWatchLogs LogGroup.|
105+
|stateMachineEnvironmentVariableName?|`string`|Optional name for the container environment variable containing the state machine ARN.|
106+
107+
## Pattern Properties
108+
109+
| **Name** | **Type** | **Description** |
110+
|:-------------|:----------------|-----------------|
111+
| vpc | [`ec2.IVpc`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.IVpc.html) | The VPC used by the construct (whether created by the construct or provided by the client) |
112+
| service | [`ecs.FargateService`](https://docs.aws.amazon.com/cdk/api/v1/docs/@aws-cdk_aws-ecs.FargateService.html) | The AWS Fargate service used by this construct (whether created by this construct or passed to this construct at initialization) |
113+
| container | [`ecs.ContainerDefinition`](https://docs.aws.amazon.com/cdk/api/v1/docs/@aws-cdk_aws-ecs.ContainerDefinition.html) | The container associated with the AWS Fargate service in the service property. |
114+
| stateMachine| [`sfn.StateMachine`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-stepfunctions.StateMachine.html)|Returns an instance of `sfn.StateMachine` created by the construct.|
115+
| stateMachineLogGroup|[`logs.ILogGroup`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-logs.ILogGroup.html)|Returns an instance of the `logs.ILogGroup` created by the construct for StateMachine.|
116+
| cloudwatchAlarms? | [`cloudwatch.Alarm[]`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cloudwatch.Alarm.html)|Returns a list of `cloudwatch.Alarm` created by the construct.|
117+
118+
## Default settings
119+
120+
Out of the box implementation of the Construct without any override will set the following defaults:
121+
122+
### AWS Fargate Service
123+
* Sets up an AWS Fargate service
124+
* Uses the existing service if provided
125+
* Creates a new service if none provided.
126+
* Service will run in isolated subnets if available, then private subnets if available and finally public subnets
127+
* Adds an environment variable to the container containing the ARN of the state machine
128+
* Default name is `STATE_MACHINE_ARN`
129+
* Add permissions to the container IAM role allowing it to start the execution of a state machine
130+
131+
### AWS Step Functions
132+
* Sets up an AWS Step Functions state machine
133+
* Uses an existing state machine if one is provided, otherwise creates a new one
134+
* Adds an Interface Endpoint to the VPC for Step Functions (the service by default runs in Isolated or Private subnets)
135+
* Enables CloudWatch logging
136+
137+
## Architecture
138+
![Architecture Diagram](architecture.png)
139+
140+
***
141+
&copy; Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
/**
2+
* Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance
5+
* with the License. A copy of the License is located at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES
10+
* OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions
11+
* and limitations under the License.
12+
*/
13+
14+
// Note: To ensure CDKv2 compatibility, keep the import statement for Construct separate
15+
import { Construct } from "@aws-cdk/core";
16+
import * as defaults from "@aws-solutions-constructs/core";
17+
import * as ecs from "@aws-cdk/aws-ecs";
18+
import * as ec2 from "@aws-cdk/aws-ec2";
19+
import * as sfn from '@aws-cdk/aws-stepfunctions';
20+
import * as logs from '@aws-cdk/aws-logs';
21+
import * as cloudwatch from '@aws-cdk/aws-cloudwatch';
22+
23+
export interface FargateToStepfunctionsProps {
24+
/**
25+
* Whether the construct is deploying a private or public API. This has implications for the VPC deployed
26+
* by this construct.
27+
*
28+
* @default - none
29+
*/
30+
readonly publicApi: boolean;
31+
/**
32+
* Optional custom properties for a VPC the construct will create. This VPC will
33+
* be used by the new Fargate service the construct creates (that's
34+
* why targetGroupProps can't include a VPC). Providing
35+
* both this and existingVpc is an error. A Step Functions Interface
36+
* endpoint will be included in this VPC.
37+
*
38+
* @default - A set of defaults from vpc-defaults.ts: DefaultPublicPrivateVpcProps() for public APIs
39+
* and DefaultIsolatedVpcProps() for private APIs.
40+
*/
41+
readonly vpcProps?: ec2.VpcProps;
42+
/**
43+
* An existing VPC in which to deploy the construct. Providing both this and
44+
* vpcProps is an error. If the client provides an existing Fargate service,
45+
* this value must be the VPC where the service is running. A Step Functions Interface
46+
* endpoint will be added to this VPC.
47+
*
48+
* @default - none
49+
*/
50+
readonly existingVpc?: ec2.IVpc;
51+
/**
52+
* Optional properties to create a new ECS cluster
53+
*/
54+
readonly clusterProps?: ecs.ClusterProps;
55+
/**
56+
* The arn of an ECR Repository containing the image to use
57+
* to generate the containers
58+
*
59+
* format:
60+
* arn:aws:ecr:[region]:[account number]:repository/[Repository Name]
61+
*/
62+
readonly ecrRepositoryArn?: string;
63+
/**
64+
* The version of the image to use from the repository
65+
*
66+
* @default - 'latest'
67+
*/
68+
readonly ecrImageVersion?: string;
69+
/*
70+
* Optional props to define the container created for the Fargate Service
71+
*
72+
* defaults - fargate-defaults.ts
73+
*/
74+
readonly containerDefinitionProps?: ecs.ContainerDefinitionProps | any;
75+
/*
76+
* Optional props to define the Fargate Task Definition for this construct
77+
*
78+
* defaults - fargate-defaults.ts
79+
*/
80+
readonly fargateTaskDefinitionProps?: ecs.FargateTaskDefinitionProps | any;
81+
/**
82+
* Optional values to override default Fargate Task definition properties
83+
* (fargate-defaults.ts). The construct will default to launching the service
84+
* is the most isolated subnets available (precedence: Isolated, Private and
85+
* Public). Override those and other defaults here.
86+
*
87+
* defaults - fargate-defaults.ts
88+
*/
89+
readonly fargateServiceProps?: ecs.FargateServiceProps | any;
90+
/**
91+
* A Fargate Service already instantiated (probably by another Solutions Construct). If
92+
* this is specified, then no props defining a new service can be provided, including:
93+
* existingImageObject, ecrImageVersion, containerDefintionProps, fargateTaskDefinitionProps,
94+
* ecrRepositoryArn, fargateServiceProps, clusterProps, existingClusterInterface. If this value
95+
* is provided, then existingContainerDefinitionObject must be provided as well.
96+
*
97+
* @default - none
98+
*/
99+
readonly existingFargateServiceObject?: ecs.FargateService;
100+
/*
101+
* A container definition already instantiated as part of a Fargate service. This must
102+
* be the container in the existingFargateServiceObject.
103+
*
104+
* @default - None
105+
*/
106+
readonly existingContainerDefinitionObject?: ecs.ContainerDefinition;
107+
/**
108+
* User provided StateMachineProps to override the defaults
109+
*
110+
* @default - None
111+
*/
112+
readonly stateMachineProps: sfn.StateMachineProps;
113+
/**
114+
* Whether to create recommended CloudWatch alarms
115+
*
116+
* @default - true
117+
*/
118+
readonly createCloudWatchAlarms?: boolean;
119+
/**
120+
* User provided props to override the default props for the CloudWatchLogs LogGroup.
121+
*
122+
* @default - Default props are used
123+
*/
124+
readonly logGroupProps?: logs.LogGroupProps;
125+
/**
126+
* Optional name for the container environment variable containing the state machine ARN.
127+
*
128+
* @default - None
129+
*/
130+
readonly stateMachineEnvironmentVariableName?: string;
131+
}
132+
133+
export class FargateToStepfunctions extends Construct {
134+
public readonly vpc: ec2.IVpc;
135+
public readonly service: ecs.FargateService;
136+
public readonly container: ecs.ContainerDefinition;
137+
public readonly stateMachine: sfn.StateMachine;
138+
public readonly stateMachineLogGroup: logs.ILogGroup;
139+
public readonly cloudwatchAlarms?: cloudwatch.Alarm[];
140+
141+
constructor(scope: Construct, id: string, props: FargateToStepfunctionsProps) {
142+
super(scope, id);
143+
defaults.CheckProps(props);
144+
defaults.CheckFargateProps(props);
145+
146+
this.vpc = defaults.buildVpc(scope, {
147+
existingVpc: props.existingVpc,
148+
defaultVpcProps: props.publicApi ? defaults.DefaultPublicPrivateVpcProps() : defaults.DefaultIsolatedVpcProps(),
149+
userVpcProps: props.vpcProps,
150+
constructVpcProps: { enableDnsHostnames: true, enableDnsSupport: true }
151+
});
152+
153+
defaults.AddAwsServiceEndpoint(scope, this.vpc, defaults.ServiceEndpointTypes.STEP_FUNCTIONS);
154+
155+
if (props.existingFargateServiceObject) {
156+
this.service = props.existingFargateServiceObject;
157+
// CheckFargateProps confirms that the container is provided
158+
this.container = props.existingContainerDefinitionObject!;
159+
} else {
160+
[this.service, this.container] = defaults.CreateFargateService(
161+
scope,
162+
id,
163+
this.vpc,
164+
props.clusterProps,
165+
props.ecrRepositoryArn,
166+
props.ecrImageVersion,
167+
props.fargateTaskDefinitionProps,
168+
props.containerDefinitionProps,
169+
props.fargateServiceProps
170+
);
171+
}
172+
173+
[this.stateMachine, this.stateMachineLogGroup] = defaults.buildStateMachine(this, props.stateMachineProps,
174+
props.logGroupProps);
175+
176+
this.stateMachine.grantStartExecution(this.service.taskDefinition.taskRole);
177+
178+
if (props.createCloudWatchAlarms === undefined || props.createCloudWatchAlarms) {
179+
// Deploy best-practice CloudWatch Alarm for state machine
180+
this.cloudwatchAlarms = defaults.buildStepFunctionCWAlarms(this, this.stateMachine);
181+
}
182+
183+
// Add environment variable
184+
const stateMachineEnvironmentVariableName = props.stateMachineEnvironmentVariableName || 'STATE_MACHINE_ARN';
185+
this.container.addEnvironment(stateMachineEnvironmentVariableName, this.stateMachine.stateMachineArn);
186+
}
187+
}

0 commit comments

Comments
 (0)