Skip to content

Commit 9b208a6

Browse files
committed
feat(aws-efs): adding construct library for creating EFS
* 100% unit test coverage. * This was tested by creating an EFS using this construct in a cdk application. A instance was also created in this app, which successfully mounted it. closes aws#6286
1 parent 747bdb2 commit 9b208a6

File tree

7 files changed

+544
-8
lines changed

7 files changed

+544
-8
lines changed

packages/@aws-cdk/aws-efs/README.md

+25
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,29 @@
1515
---
1616
<!--END STABILITY BANNER-->
1717

18+
This construct library allows you to set up AWS Elastic File System (EFS).
19+
20+
```ts
21+
import efs = require('@aws-cdk/aws-efs');
22+
23+
const myVpc = new ec2.Vpc(this, 'VPC');
24+
const fileSystem = new efs.EfsFileSystem(this, 'MyEfsFileSystem', {
25+
vpc: myVpc,
26+
encrypted: true,
27+
lifecyclePolicy: EfsLifecyclePolicyProperty.AFTER_14_DAYS,
28+
performanceMode: EfsPerformanceMode.GENERAL_PURPOSE,
29+
throughputMode: EfsThroughputMode.BURSTING
30+
});
31+
```
32+
33+
### Connecting
34+
35+
To control who can access the EFS, use the `.connections` attribute. EFS has
36+
a fixed default port, so you don't need to specify the port:
37+
38+
```ts
39+
fileSystem.connections.allowDefaultPortFrom(instance);
40+
```
41+
42+
1843
This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
import * as ec2 from '@aws-cdk/aws-ec2';
2+
import * as kms from '@aws-cdk/aws-kms';
3+
import {Construct, Resource, Tag} from "@aws-cdk/core";
4+
import {CfnFileSystem, CfnMountTarget} from "./efs.generated";
5+
import {FileSystemProps, IFileSystem} from "./file-system";
6+
7+
/**
8+
* EFS Lifecycle Policy, if a file is not accessed for given days, it will move to EFS Infrequent Access.
9+
*
10+
* @see http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-efs-filesystem.html#cfn-efs-filesystem-performancemode
11+
*/
12+
export enum EfsLifecyclePolicyProperty {
13+
/**
14+
* After 7 days of inaccessibility.
15+
*/
16+
AFTER_7_DAYS,
17+
18+
/**
19+
* After 14 days of inaccessibility.
20+
*/
21+
AFTER_14_DAYS,
22+
23+
/**
24+
* After 30 days of inaccessibility.
25+
*/
26+
AFTER_30_DAYS,
27+
28+
/**
29+
* After 60 days of inaccessibility.
30+
*/
31+
AFTER_60_DAYS,
32+
33+
/**
34+
* After 90 days of inaccessibility.
35+
*/
36+
AFTER_90_DAYS
37+
}
38+
39+
/**
40+
* EFS Performance mode.
41+
*
42+
* @see http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-efs-filesystem.html#cfn-efs-filesystem-performancemode
43+
*/
44+
export enum EfsPerformanceMode {
45+
/**
46+
* This is the general purpose performance mode for most file systems.
47+
*/
48+
GENERAL_PURPOSE = "generalPurpose",
49+
50+
/**
51+
* This performance mode can scale to higher levels of aggregate throughput and operations per second with a
52+
* tradeoff of slightly higher latencies.
53+
*/
54+
MAX_IO = "maxIO"
55+
}
56+
57+
/**
58+
* EFS Throughput mode.
59+
*
60+
* @see http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-efs-filesystem.html#cfn-elasticfilesystem-filesystem-throughputmode
61+
*/
62+
export enum EfsThroughputMode {
63+
/**
64+
* This mode on Amazon EFS scales as the size of the file system in the standard storage class grows.
65+
*/
66+
BURSTING = "bursting",
67+
68+
/**
69+
* This mode can instantly provision the throughput of the file system (in MiB/s) independent of the amount of data stored.
70+
*/
71+
PROVISIONED = "provisioned"
72+
}
73+
74+
/**
75+
* Properties of EFS FileSystem.
76+
*/
77+
export interface EfsFileSystemProps extends FileSystemProps {
78+
/**
79+
* Defines if the data at rest in the file system is encrypted or not.
80+
*
81+
* @default - false
82+
*/
83+
readonly encrypted?: boolean;
84+
85+
/**
86+
* The KMS key used for encryption. This is required to encrypt the data at rest if @encrypted is set to true.
87+
*
88+
* @default - if @encrypted is true, the default key for EFS (/aws/elasticfilesystem) is used
89+
*/
90+
readonly kmsKey?: kms.IKey;
91+
92+
/**
93+
* The key value pair added to the File system.
94+
*
95+
* @default - no tags will be added
96+
*/
97+
readonly fileSystemTags?: Tag[];
98+
99+
/**
100+
* A policy used by EFS lifecycle management to transition files to the Infrequent Access (IA) storage class.
101+
*
102+
* @default - none
103+
*/
104+
readonly lifecyclePolicy?: EfsLifecyclePolicyProperty;
105+
106+
/**
107+
* Enum to mention the performance mode of the file system.
108+
*
109+
* @default - GENERAL_PURPOSE
110+
*/
111+
readonly performanceMode?: EfsPerformanceMode;
112+
113+
/**
114+
* Enum to mention the throughput mode of the file system.
115+
*
116+
* @default - BURSTING
117+
*/
118+
readonly throughputMode?: EfsThroughputMode;
119+
120+
/**
121+
* Provisioned throughput for the file system. This is a required property if the throughput mode is set to PROVISIONED.
122+
* Valid values are 1-1024.
123+
*
124+
* @default - None, errors out
125+
*/
126+
readonly provisionedThroughputInMibps?: number;
127+
}
128+
129+
/**
130+
* A new or imported EFS File System.
131+
*/
132+
abstract class EFSFileSystemBase extends Resource implements IFileSystem {
133+
134+
/**
135+
* The security groups/rules used to allow network connections to the file system.
136+
*/
137+
public abstract readonly connections: ec2.Connections;
138+
139+
/**
140+
* @attribute
141+
*/
142+
public abstract readonly fileSystemID: string;
143+
}
144+
145+
/**
146+
* Properties that describe an existing EFS file system.
147+
*/
148+
export interface EfsFileSystemAttributes {
149+
/**
150+
* The security group of the file system
151+
*/
152+
readonly securityGroup: ec2.ISecurityGroup;
153+
154+
/**
155+
* The File System's ID.
156+
*/
157+
readonly fileSystemID: string;
158+
}
159+
160+
/**
161+
* The Elastic File System implementation of IFileSystem.
162+
* It creates a new, empty file system in Amazon Elastic File System (Amazon EFS).
163+
* It also creates mount target (AWS::EFS::MountTarget) implicitly to mount the
164+
* EFS file system on an Amazon Elastic Compute Cloud (Amazon EC2) instance or another resource.
165+
*
166+
* @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-efs-filesystem.html
167+
*
168+
* @resource AWS::EFS::FileSystem
169+
*/
170+
export class EfsFileSystem extends EFSFileSystemBase {
171+
172+
/**
173+
* Import an existing File System from the given properties.
174+
*/
175+
public static fromEfsFileSystemAttributes(scope: Construct, id: string, attrs: EfsFileSystemAttributes): IFileSystem {
176+
class Import extends EFSFileSystemBase implements IFileSystem {
177+
public readonly fileSystemID = attrs.fileSystemID;
178+
public readonly connections = new ec2.Connections({
179+
securityGroups: [attrs.securityGroup],
180+
defaultPort: ec2.Port.tcp(EfsFileSystem.DEFAULT_PORT)
181+
});
182+
}
183+
184+
return new Import(scope, id);
185+
}
186+
187+
/**
188+
* The default port File System listens on.
189+
*/
190+
private static readonly DEFAULT_PORT: number = 2049;
191+
192+
/**
193+
* The security groups/rules used to allow network connections to the file system.
194+
*/
195+
public readonly connections: ec2.Connections;
196+
197+
/**
198+
* @attribute
199+
*/
200+
public readonly fileSystemID: string;
201+
202+
private readonly mountTargets: CfnMountTarget[] = [];
203+
private readonly efsFileSystem: CfnFileSystem;
204+
205+
/**
206+
* Constructor for creating a new EFS FileSystem.
207+
*/
208+
constructor(scope: Construct, id: string, props: EfsFileSystemProps) {
209+
super(scope, id);
210+
211+
if (props.throughputMode === EfsThroughputMode.PROVISIONED) {
212+
if (props.provisionedThroughputInMibps === undefined) {
213+
throw new Error('Property provisionedThroughputInMibps is required when throughputMode is PROVISIONED');
214+
} else if (!Number.isInteger(props.provisionedThroughputInMibps)) {
215+
throw new Error("Invalid input for provisionedThroughputInMibps");
216+
} else if (props.provisionedThroughputInMibps < 1 || props.provisionedThroughputInMibps > 1024) {
217+
this.node.addWarning("Valid values for throughput are 1-1024 MiB/s. You can get this limit increased by contacting AWS Support.");
218+
}
219+
}
220+
221+
this.efsFileSystem = new CfnFileSystem(this, "FileSystem", {
222+
encrypted: props.encrypted,
223+
kmsKeyId: (props.kmsKey ? props.kmsKey.keyId : undefined),
224+
fileSystemTags: props.fileSystemTags,
225+
lifecyclePolicies: (props.lifecyclePolicy ? Array.of({
226+
transitionToIa: EfsLifecyclePolicyProperty[props.lifecyclePolicy]
227+
} as CfnFileSystem.LifecyclePolicyProperty) : undefined),
228+
performanceMode: props.performanceMode,
229+
throughputMode: props.throughputMode,
230+
provisionedThroughputInMibps: props.provisionedThroughputInMibps
231+
});
232+
233+
this.fileSystemID = this.efsFileSystem.ref;
234+
this.node.defaultChild = this.efsFileSystem;
235+
236+
const securityGroup = (props.securityGroup || new ec2.SecurityGroup(this, 'EfsSecurityGroup', {
237+
vpc: props.vpc
238+
}));
239+
240+
this.connections = new ec2.Connections({
241+
securityGroups: [securityGroup],
242+
defaultPort: ec2.Port.tcp(EfsFileSystem.DEFAULT_PORT)
243+
});
244+
245+
const subnets = props.vpc.selectSubnets(props.vpcSubnets);
246+
247+
// We now have to create the mount target for each of the mentioned subnet
248+
let mountTargetCount = 0;
249+
subnets.subnetIds.forEach((subnetId: string) => {
250+
const efsMountTarget = new CfnMountTarget(this,
251+
"EfsMountTarget" + (++mountTargetCount),
252+
{
253+
fileSystemId: this.fileSystemID,
254+
securityGroups: Array.of(securityGroup.securityGroupId),
255+
subnetId
256+
});
257+
this.mountTargets.push(efsMountTarget);
258+
});
259+
}
260+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import * as ec2 from '@aws-cdk/aws-ec2';
2+
import {IResource} from "@aws-cdk/core";
3+
4+
/**
5+
* Interface to implement AWS File Systems.
6+
*/
7+
export interface IFileSystem extends IResource, ec2.IConnectable {
8+
/**
9+
* The ID of the file system, assigned by Amazon EFS.
10+
*
11+
* @attribute
12+
*/
13+
readonly fileSystemID: string;
14+
}
15+
16+
/**
17+
* Properties of FileSystem
18+
*/
19+
export interface FileSystemProps {
20+
/**
21+
* VPC to launch the file system in.
22+
*/
23+
readonly vpc: ec2.IVpc;
24+
25+
/**
26+
* Security Group to assign to this file system.
27+
*
28+
* @default - creates new security group which allow all out bound trafficcloudformation
29+
*/
30+
readonly securityGroup?: ec2.ISecurityGroup;
31+
32+
/**
33+
* Where to place the mount target within the VPC.
34+
*
35+
* @default - Private subnets
36+
*/
37+
readonly vpcSubnets?: ec2.SubnetSelection;
38+
}
+2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
// AWS::EFS CloudFormation Resources:
2+
export * from './file-system';
3+
export * from './efs-file-system';
24
export * from './efs.generated';

packages/@aws-cdk/aws-efs/package.json

+14-2
Original file line numberDiff line numberDiff line change
@@ -85,14 +85,26 @@
8585
"pkglint": "1.24.0"
8686
},
8787
"dependencies": {
88-
"@aws-cdk/core": "1.24.0"
88+
"@aws-cdk/core": "1.24.0",
89+
"@aws-cdk/aws-ec2": "1.24.0",
90+
"@aws-cdk/aws-kms": "1.24.0",
91+
"@aws-cdk/cx-api": "1.24.0"
8992
},
9093
"homepage": "https://github.com/aws/aws-cdk",
9194
"peerDependencies": {
92-
"@aws-cdk/core": "1.24.0"
95+
"@aws-cdk/core": "1.24.0",
96+
"@aws-cdk/aws-ec2": "1.24.0",
97+
"@aws-cdk/aws-kms": "1.24.0",
98+
"@aws-cdk/cx-api": "1.24.0"
9399
},
94100
"engines": {
95101
"node": ">= 10.3.0"
96102
},
103+
"awslint": {
104+
"exclude": [
105+
"props-physical-name:@aws-cdk/aws-efs.EfsFileSystemProps",
106+
"resource-interface:@aws-cdk/aws-efs.EfsFileSystem"
107+
]
108+
},
97109
"stability": "experimental"
98110
}

0 commit comments

Comments
 (0)