Skip to content

Commit f7ddf3f

Browse files
feat(aws-fargate-sqs): Created new construct (#588)
* created new construct * fixed README * updated integ test with encryption * minor doc update * fixed variable typo in unit test * fixed variable typo in integ test * fixed versioning in package.json * added assertions for public and private api * added assertions for dlq * added queuePermissions prop Co-authored-by: biffgaut <[email protected]>
1 parent 29a3b2a commit f7ddf3f

13 files changed

+3505
-1
lines changed

DESIGN_GUIDELINES.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ Existing Inconsistencies would not be published, that’s for our internal use
305305
| Name | Type | Notes |
306306
| --- | --- | --- |
307307
| queueProps? | sqs.QueueProps ||
308-
| existingQueueObj? | sqs.Qeue ||
308+
| existingQueueObj? | sqs.Queue ||
309309
| deployDeadLetterQueue? | Boolean ||
310310
| deadLetterQueueProps? | sqs.QueueProps ||
311311
| maxReceiveCount | number ||
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,96 @@
1+
# aws-fargate-sqs 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_sqs`|
22+
|![Typescript Logo](https://docs.aws.amazon.com/cdk/api/latest/img/typescript32.png) Typescript|`@aws-solutions-constructs/aws-fargate-sqs`|
23+
|![Java Logo](https://docs.aws.amazon.com/cdk/api/latest/img/java32.png) Java|`software.amazon.awsconstructs.services.fargatesqs`|
24+
25+
This AWS Solutions Construct implements an AWS Fargate service that can write to an Amazon SQS queue
26+
27+
Here is a minimal deployable pattern definition:
28+
29+
Typescript
30+
``` typescript
31+
import { FargateToSqs, FargateToSqsProps } from '@aws-solutions-constructs/aws-fargate-sqs';
32+
33+
const props: FargateToSqsProps = {
34+
publicApi: true,
35+
ecrRepositoryArn: "arn of a repo in ECR in your account",
36+
});
37+
38+
new FargateToSqs(stack, 'test-construct', props);
39+
```
40+
41+
## Pattern Construct Props
42+
43+
| **Name** | **Type** | **Description** |
44+
|:-------------|:----------------|-----------------|
45+
| publicApi | boolean | Whether the construct is deploying a private or public API. This has implications for the VPC and ALB. |
46+
| 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 the new ALB and 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. |
47+
| 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. |
48+
| 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. |
49+
| 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* |
50+
| ecrImageVersion? | string | The version of the image to use from the repository. Defaults to 'Latest' |
51+
| 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) |
52+
| 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) |
53+
| 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. |
54+
| 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: existingImageObject, ecrImageVersion, containerDefintionProps, fargateTaskDefinitionProps, ecrRepositoryArn, fargateServiceProps, clusterProps, existingClusterInterface |
55+
| 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 |
56+
|existingQueueObj?|[sqs.Queue](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-sqs.Queue.html)|An optional, existing SQS queue to be used instead of the default queue. Providing both this and queueProps will cause an error.|
57+
|queueProps?|[sqs.QueueProps](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-sqs.QueueProps.html)|Optional user-provided properties to override the default properties for the SQS queue.|
58+
|deployDeadLetterQueue?|boolean|Whether to create a secondary queue to be used as a dead letter queue. Defaults to `true`.|
59+
|deadLetterQueueProps?|[sqs.QueueProps](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-sqs.QueueProps.html)|Optional user-provided props to override the default props for the dead letter queue. Only used if the `deployDeadLetterQueue` property is set to true.|
60+
|maxReceiveCount?|integer|The number of times a message can be unsuccessfully dequeued before being moved to the dead letter queue. Defaults to `15`.|
61+
|queueUrlEnvironmentVariableName?|string|Optional Name for the SQS queue name environment variable set for the container.|
62+
|queuePermissions?|`string[]`|Optional queue permissions to grant to the Fargate service. One or more of the following may be specified: `Read`,`Write`. Default is `Write`|
63+
64+
65+
## Pattern Properties
66+
67+
| **Name** | **Type** | **Description** |
68+
|:-------------|:----------------|-----------------|
69+
| 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) |
70+
| 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) |
71+
| 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. |
72+
|sqsQueue|[sqs.Queue](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-sqs.Queue.html)|Returns an instance of the SQS queue created by the pattern. |
73+
|deadLetterQueue?|[sqs.Queue](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-sqs.Queue.html)|Returns an instance of the dead letter queue created by the pattern, if one is deployed.|
74+
75+
## Default settings
76+
77+
Out of the box implementation of the Construct without any override will set the following defaults:
78+
79+
### AWS Fargate Service
80+
* Sets up an AWS Fargate service
81+
* Uses the existing service if provided
82+
* Creates a new service if none provided.
83+
* Service will run in isolated subnets if available, then private subnets if available and finally public subnets
84+
* Adds environment variables to the container with the name of the SQS queue
85+
* Add permissions to the container IAM role allowing it to publish to the SQS queue
86+
87+
### Amazon SQS Queue
88+
* Sets up an Amazon SQS queue
89+
* Uses an existing queue if one is provided, otherwise creates a new one
90+
* Adds an Interface Endpoint to the VPC for SQS (the service by default runs in Isolated or Private subnets)
91+
92+
## Architecture
93+
![Architecture Diagram](architecture.png)
94+
95+
***
96+
&copy; Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
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+
import * as ec2 from "@aws-cdk/aws-ec2";
15+
import * as sqs from "@aws-cdk/aws-sqs";
16+
// Note: To ensure CDKv2 compatibility, keep the import statement for Construct separate
17+
import { Construct } from "@aws-cdk/core";
18+
import * as defaults from "@aws-solutions-constructs/core";
19+
import * as ecs from "@aws-cdk/aws-ecs";
20+
21+
export interface FargateToSqsProps {
22+
/**
23+
* Optional custom properties for a VPC the construct will create. This VPC will
24+
* be used by the new Fargate service the construct creates (that's
25+
* why targetGroupProps can't include a VPC). Providing
26+
* both this and existingVpc is an error. An SQS Interface
27+
* endpoint will be included in this VPC.
28+
*
29+
* @default - none
30+
*/
31+
readonly vpcProps?: ec2.VpcProps;
32+
/**
33+
* An existing VPC in which to deploy the construct. Providing both this and
34+
* vpcProps is an error. If the client provides an existing Fargate service,
35+
* this value must be the VPC where the service is running. An SQS Interface
36+
* endpoint will be added to this VPC.
37+
*
38+
* @default - none
39+
*/
40+
readonly existingVpc?: ec2.IVpc;
41+
/**
42+
* Whether the construct is deploying a private or public API. This has implications for the VPC deployed
43+
* by this construct.
44+
*
45+
* @default - none
46+
*/
47+
readonly publicApi: boolean;
48+
/**
49+
* Optional properties to create a new ECS cluster
50+
*/
51+
readonly clusterProps?: ecs.ClusterProps;
52+
/**
53+
* The arn of an ECR Repository containing the image to use
54+
* to generate the containers
55+
*
56+
* format:
57+
* arn:aws:ecr:[region]:[account number]:repository/[Repository Name]
58+
*/
59+
readonly ecrRepositoryArn?: string;
60+
/**
61+
* The version of the image to use from the repository
62+
*
63+
* @default - 'latest'
64+
*/
65+
readonly ecrImageVersion?: string;
66+
/*
67+
* Optional props to define the container created for the Fargate Service
68+
*
69+
* defaults - fargate-defaults.ts
70+
*/
71+
readonly containerDefinitionProps?: ecs.ContainerDefinitionProps | any;
72+
/*
73+
* Optional props to define the Fargate Task Definition for this construct
74+
*
75+
* defaults - fargate-defaults.ts
76+
*/
77+
readonly fargateTaskDefinitionProps?: ecs.FargateTaskDefinitionProps | any;
78+
/**
79+
* Optional values to override default Fargate Task definition properties
80+
* (fargate-defaults.ts). The construct will default to launching the service
81+
* is the most isolated subnets available (precedence: Isolated, Private and
82+
* Public). Override those and other defaults here.
83+
*
84+
* defaults - fargate-defaults.ts
85+
*/
86+
readonly fargateServiceProps?: ecs.FargateServiceProps | any;
87+
/**
88+
* A Fargate Service already instantiated (probably by another Solutions Construct). If
89+
* this is specified, then no props defining a new service can be provided, including:
90+
* existingImageObject, ecrImageVersion, containerDefintionProps, fargateTaskDefinitionProps,
91+
* ecrRepositoryArn, fargateServiceProps, clusterProps, existingClusterInterface. If this value
92+
* is provided, then existingContainerDefinitionObject must be provided as well.
93+
*
94+
* @default - none
95+
*/
96+
readonly existingFargateServiceObject?: ecs.FargateService;
97+
/*
98+
* A container definition already instantiated as part of a Fargate service. This must
99+
* be the container in the existingFargateServiceObject.
100+
*
101+
* @default - None
102+
*/
103+
readonly existingContainerDefinitionObject?: ecs.ContainerDefinition;
104+
/**
105+
* Existing instance of SQS queue object, Providing both this and queueProps will cause an error.
106+
*
107+
* @default - Default props are used
108+
*/
109+
readonly existingQueueObj?: sqs.Queue;
110+
/**
111+
* Optional user-provided props to override the default props for the SQS queue.
112+
*
113+
* @default - Default props are used
114+
*/
115+
readonly queueProps?: sqs.QueueProps;
116+
/**
117+
* Optional user provided properties for the dead letter queue
118+
*
119+
* @default - Default props are used
120+
*/
121+
readonly deadLetterQueueProps?: sqs.QueueProps;
122+
/**
123+
* Whether to deploy a secondary queue to be used as a dead letter queue.
124+
*
125+
* @default - true.
126+
*/
127+
readonly deployDeadLetterQueue?: boolean;
128+
/**
129+
* The number of times a message can be unsuccessfully dequeued before being moved to the dead-letter queue.
130+
*
131+
* @default - required field if deployDeadLetterQueue=true.
132+
*/
133+
readonly maxReceiveCount?: number;
134+
/**
135+
* Optional Name for the SQS queue ARN environment variable to set for the container.
136+
*
137+
* @default - None
138+
*/
139+
readonly queueArnEnvironmentVariableName?: string;
140+
/**
141+
* Optional Name for the SQS queue name environment variable to set for the container.
142+
*
143+
* @default - None
144+
*/
145+
readonly queueUrlEnvironmentVariableName?: string;
146+
/**
147+
* Optional queue permissions to grant to the Fargate service. One or more of the following may be specified: `Read`,`Write`. Default is `Write`
148+
*
149+
* @default - Write
150+
*/
151+
readonly queuePermissions?: string[];
152+
}
153+
154+
export class FargateToSqs extends Construct {
155+
public readonly sqsQueue: sqs.Queue;
156+
public readonly deadLetterQueue?: sqs.DeadLetterQueue;
157+
public readonly service: ecs.FargateService;
158+
public readonly vpc: ec2.IVpc;
159+
public readonly container: ecs.ContainerDefinition;
160+
161+
constructor(scope: Construct, id: string, props: FargateToSqsProps) {
162+
super(scope, id);
163+
defaults.CheckProps(props);
164+
defaults.CheckFargateProps(props);
165+
166+
this.vpc = defaults.buildVpc(scope, {
167+
existingVpc: props.existingVpc,
168+
defaultVpcProps: props.publicApi ? defaults.DefaultPublicPrivateVpcProps() : defaults.DefaultIsolatedVpcProps(),
169+
userVpcProps: props.vpcProps,
170+
constructVpcProps: { enableDnsHostnames: true, enableDnsSupport: true }
171+
});
172+
173+
defaults.AddAwsServiceEndpoint(scope, this.vpc, defaults.ServiceEndpointTypes.SQS);
174+
175+
if (props.existingFargateServiceObject) {
176+
this.service = props.existingFargateServiceObject;
177+
// CheckFargateProps confirms that the container is provided
178+
this.container = props.existingContainerDefinitionObject!;
179+
} else {
180+
[this.service, this.container] = defaults.CreateFargateService(
181+
scope,
182+
id,
183+
this.vpc,
184+
props.clusterProps,
185+
props.ecrRepositoryArn,
186+
props.ecrImageVersion,
187+
props.fargateTaskDefinitionProps,
188+
props.containerDefinitionProps,
189+
props.fargateServiceProps
190+
);
191+
}
192+
193+
// Setup the dead letter queue, if applicable
194+
this.deadLetterQueue = defaults.buildDeadLetterQueue(this, {
195+
existingQueueObj: props.existingQueueObj,
196+
deployDeadLetterQueue: props.deployDeadLetterQueue,
197+
deadLetterQueueProps: props.deadLetterQueueProps,
198+
maxReceiveCount: props.maxReceiveCount
199+
});
200+
201+
// Setup the SQS Queue
202+
[this.sqsQueue] = defaults.buildQueue(this, `${id}-queue`, {
203+
queueProps: props.queueProps,
204+
deadLetterQueue: this.deadLetterQueue,
205+
existingQueueObj: props.existingQueueObj,
206+
});
207+
208+
// Enable message send and receive permissions for Fargate service by default
209+
if (props.queuePermissions) {
210+
if (props.queuePermissions.includes('Read')) {
211+
this.sqsQueue.grantConsumeMessages(this.service.taskDefinition.taskRole);
212+
}
213+
if (props.queuePermissions.includes('Write')) {
214+
this.sqsQueue.grantSendMessages(this.service.taskDefinition.taskRole);
215+
}
216+
} else {
217+
this.sqsQueue.grantSendMessages(this.service.taskDefinition.taskRole);
218+
}
219+
220+
// Setting environment variables
221+
const queueArnEnvironmentVariableName = props.queueArnEnvironmentVariableName || 'SQS_QUEUE_ARN';
222+
this.container.addEnvironment(queueArnEnvironmentVariableName, this.sqsQueue.queueArn);
223+
const queueUrlEnvironmentVariableName = props.queueUrlEnvironmentVariableName || 'SQS_QUEUE_URL';
224+
this.container.addEnvironment(queueUrlEnvironmentVariableName, this.sqsQueue.queueUrl);
225+
}
226+
}

0 commit comments

Comments
 (0)