packages/aws-cdk-lib/aws-efs/lib/efs-file-system.ts (392 lines of code) (raw):
import { Construct, DependencyGroup, IDependable } from 'constructs';
import { AccessPoint, AccessPointOptions } from './access-point';
import { CfnFileSystem, CfnMountTarget } from './efs.generated';
import * as ec2 from '../../aws-ec2';
import * as iam from '../../aws-iam';
import * as kms from '../../aws-kms';
import { ArnFormat, FeatureFlags, Lazy, Names, RemovalPolicy, Resource, Size, Stack, Tags, Token, ValidationError } from '../../core';
import { addConstructMetadata, MethodMetadata } from '../../core/lib/metadata-resource';
import * as cxapi from '../../cx-api';
/**
* EFS Lifecycle Policy, if a file is not accessed for given days, it will move to EFS Infrequent Access
* or Archive storage.
*
* @see http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-efs-filesystem.html#cfn-elasticfilesystem-filesystem-lifecyclepolicies
*/
export enum LifecyclePolicy {
/**
* After 1 day of not being accessed.
*/
AFTER_1_DAY = 'AFTER_1_DAY',
/**
* After 7 days of not being accessed.
*/
AFTER_7_DAYS = 'AFTER_7_DAYS',
/**
* After 14 days of not being accessed.
*/
AFTER_14_DAYS = 'AFTER_14_DAYS',
/**
* After 30 days of not being accessed.
*/
AFTER_30_DAYS = 'AFTER_30_DAYS',
/**
* After 60 days of not being accessed.
*/
AFTER_60_DAYS = 'AFTER_60_DAYS',
/**
* After 90 days of not being accessed.
*/
AFTER_90_DAYS = 'AFTER_90_DAYS',
/**
* After 180 days of not being accessed.
*/
AFTER_180_DAYS = 'AFTER_180_DAYS',
/**
* After 270 days of not being accessed.
*/
AFTER_270_DAYS = 'AFTER_270_DAYS',
/**
* After 365 days of not being accessed.
*/
AFTER_365_DAYS = 'AFTER_365_DAYS',
}
/**
* EFS Out Of Infrequent Access Policy, if a file is accessed given times, it will move back to primary
* storage class.
*
* @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-efs-filesystem-lifecyclepolicy.html#cfn-efs-filesystem-lifecyclepolicy-transitiontoprimarystorageclass
*/
export enum OutOfInfrequentAccessPolicy {
/**
* After 1 access
*/
AFTER_1_ACCESS = 'AFTER_1_ACCESS',
}
/**
* EFS Performance mode.
*
* @see https://docs.aws.amazon.com/efs/latest/ug/performance.html#performancemodes
*/
export enum PerformanceMode {
/**
* General Purpose is ideal for latency-sensitive use cases, like web serving
* environments, content management systems, home directories, and general file serving.
* Recommended for the majority of Amazon EFS file systems.
*/
GENERAL_PURPOSE = 'generalPurpose',
/**
* File systems in the Max I/O mode can scale to higher levels of aggregate
* throughput and operations per second. This scaling is done with a tradeoff
* of slightly higher latencies for file metadata operations.
* Highly parallelized applications and workloads, such as big data analysis,
* media processing, and genomics analysis, can benefit from this mode.
*/
MAX_IO = 'maxIO',
}
/**
* EFS Throughput mode.
*
* @see https://docs.aws.amazon.com/efs/latest/ug/performance.html#throughput-modes
*/
export enum ThroughputMode {
/**
* This mode scales as the size of the file system in the standard storage class grows.
*/
BURSTING = 'bursting',
/**
* This mode can instantly provision the throughput of the file system (in MiB/s) independent of the amount of data stored.
*/
PROVISIONED = 'provisioned',
/**
* This mode scales the throughput automatically regardless of file system size.
*/
ELASTIC = 'elastic',
}
/**
* The status of the file system's replication overwrite protection.
*
* @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-efs-filesystem-filesystemprotection.html
*/
export enum ReplicationOverwriteProtection {
/**
* Enable the filesystem's replication overwrite protection.
*/
ENABLED = 'ENABLED',
/**
* Disable the filesystem's replication overwrite protection.
*/
DISABLED = 'DISABLED',
}
/**
* Represents an Amazon EFS file system
*/
export interface IFileSystem extends ec2.IConnectable, iam.IResourceWithPolicy {
/**
* The ID of the file system, assigned by Amazon EFS.
*
* @attribute
*/
readonly fileSystemId: string;
/**
* The ARN of the file system.
*
* @attribute
*/
readonly fileSystemArn: string;
/**
* Dependable that can be depended upon to ensure the mount targets of the filesystem are ready
*/
readonly mountTargetsAvailable: IDependable;
/**
* Grant the actions defined in actions to the given grantee
* on this File System resource.
*/
grant(grantee: iam.IGrantable, ...actions: string[]): iam.Grant;
/**
* Grant read permissions for this file system to an IAM principal.
* @param grantee The principal to grant read to
*/
grantRead(grantee: iam.IGrantable): iam.Grant;
/**
* Grant read and write permissions for this file system to an IAM principal.
* @param grantee The principal to grant read and write to
*/
grantReadWrite(grantee: iam.IGrantable): iam.Grant;
/**
* As root user, grant read and write permissions for this file system to an IAM principal.
* @param grantee The principal to grant root access to
*/
grantRootAccess(grantee: iam.IGrantable): iam.Grant;
}
/**
* Properties of EFS FileSystem.
*/
export interface FileSystemProps {
/**
* VPC to launch the file system in.
*/
readonly vpc: ec2.IVpc;
/**
* Security Group to assign to this file system.
*
* @default - creates new security group which allows all outbound traffic
*/
readonly securityGroup?: ec2.ISecurityGroup;
/**
* Which subnets to place the mount target in the VPC.
*
* @default - the Vpc default strategy if not specified
*/
readonly vpcSubnets?: ec2.SubnetSelection;
/**
* Defines if the data at rest in the file system is encrypted or not.
*
* @default - If your application has the '@aws-cdk/aws-efs:defaultEncryptionAtRest' feature flag set, the default is true, otherwise, the default is false.
* @link https://docs.aws.amazon.com/cdk/latest/guide/featureflags.html
*/
readonly encrypted?: boolean;
/**
* The file system's name.
*
* @default - CDK generated name
*/
readonly fileSystemName?: string;
/**
* The KMS key used for encryption. This is required to encrypt the data at rest if @encrypted is set to true.
*
* @default - if 'encrypted' is true, the default key for EFS (/aws/elasticfilesystem) is used
*/
readonly kmsKey?: kms.IKey;
/**
* A policy used by EFS lifecycle management to transition files to the Infrequent Access (IA) storage class.
*
* @default - None. EFS will not transition files to the IA storage class.
*/
readonly lifecyclePolicy?: LifecyclePolicy;
/**
* A policy used by EFS lifecycle management to transition files from Infrequent Access (IA) storage class to
* primary storage class.
*
* @default - None. EFS will not transition files from IA storage to primary storage.
*/
readonly outOfInfrequentAccessPolicy?: OutOfInfrequentAccessPolicy;
/**
* The number of days after files were last accessed in primary storage (the Standard storage class) at which to move them to Archive storage.
* Metadata operations such as listing the contents of a directory don't count as file access events.
*
* @default - None. EFS will not transition files to Archive storage class.
*/
readonly transitionToArchivePolicy?: LifecyclePolicy;
/**
* The performance mode that the file system will operate under.
* An Amazon EFS file system's performance mode can't be changed after the file system has been created.
* Updating this property will replace the file system.
*
* @default PerformanceMode.GENERAL_PURPOSE
*/
readonly performanceMode?: PerformanceMode;
/**
* Enum to mention the throughput mode of the file system.
*
* @default ThroughputMode.BURSTING
*/
readonly throughputMode?: ThroughputMode;
/**
* Provisioned throughput for the file system.
* This is a required property if the throughput mode is set to PROVISIONED.
* Must be at least 1MiB/s.
*
* @default - none, errors out
*/
readonly provisionedThroughputPerSecond?: Size;
/**
* The removal policy to apply to the file system.
*
* @default RemovalPolicy.RETAIN
*/
readonly removalPolicy?: RemovalPolicy;
/**
* Whether to enable automatic backups for the file system.
*
* @default false
*/
readonly enableAutomaticBackups?: boolean;
/**
* File system policy is an IAM resource policy used to control NFS access to an EFS file system.
*
* @default none
*/
readonly fileSystemPolicy?: iam.PolicyDocument;
/**
* Allow access from anonymous client that doesn't use IAM authentication.
*
* @default false when using `grantRead`, `grantWrite`, `grantRootAccess`
* or set `@aws-cdk/aws-efs:denyAnonymousAccess` feature flag, otherwise true
*/
readonly allowAnonymousAccess?: boolean;
/**
* Whether this is a One Zone file system.
* If enabled, `performanceMode` must be set to `GENERAL_PURPOSE` and `vpcSubnets` cannot be set.
*
* @default false
* @link https://docs.aws.amazon.com/efs/latest/ug/availability-durability.html#file-system-type
*/
readonly oneZone?: boolean;
/**
* Whether to enable the filesystem's replication overwrite protection or not.
* Set false if you want to create a read-only filesystem for use as a replication destination.
*
* @see https://docs.aws.amazon.com/efs/latest/ug/replication-use-cases.html#replicate-existing-destination
*
* @default ReplicationOverwriteProtection.ENABLED
*/
readonly replicationOverwriteProtection?: ReplicationOverwriteProtection;
/**
* Replication configuration for the file system.
*
* @default - no replication
*/
readonly replicationConfiguration?: ReplicationConfiguration;
}
/**
* Properties that describe an existing EFS file system.
*/
export interface FileSystemAttributes {
/**
* The security group of the file system
*/
readonly securityGroup: ec2.ISecurityGroup;
/**
* The File System's ID.
*
* @default - determined based on fileSystemArn
*/
readonly fileSystemId?: string;
/**
* The File System's Arn.
*
* @default - determined based on fileSystemId
*/
readonly fileSystemArn?: string;
}
/**
* Properties for the ReplicationConfiguration.
*/
export interface ReplicationConfigurationProps {
/**
* The existing destination file system for the replication.
*
* @default - None
*/
readonly destinationFileSystem?: IFileSystem;
/**
* AWS KMS key used to protect the encrypted file system.
*
* @default - use service-managed KMS key for Amazon EFS
*/
readonly kmsKey?: kms.IKey;
/**
* The AWS Region in which the destination file system is located.
*
* @default - the region of the stack
*/
readonly region?: string;
/**
* The availability zone name of the destination file system.
* One zone file system is used as the destination file system when this property is set.
*
* @default - no availability zone is set
*/
readonly availabilityZone?: string;
}
/**
* Properties for configuring ReplicationConfiguration to replicate
* to a new One Zone file system.
*/
export interface OneZoneFileSystemProps {
/**
* AWS KMS key used to protect the encrypted file system.
*
* @default - use service-managed KMS key for Amazon EFS
*/
readonly kmsKey?: kms.IKey;
/**
* The AWS Region in which the destination file system is located.
*/
readonly region: string;
/**
* The availability zone name of the destination file system.
* One zone file system is used as the destination file system when this property is set.
*/
readonly availabilityZone: string;
}
/**
* Properties for configuring ReplicationConfiguration to replicate
* to a new Regional file system.
*/
export interface RegionalFileSystemProps {
/**
* AWS KMS key used to protect the encrypted file system.
*
* @default - use service-managed KMS key for Amazon EFS
*/
readonly kmsKey?: kms.IKey;
/**
* The AWS Region in which the destination file system is located.
*
* @default - the region of the stack
*/
readonly region?: string;
}
/**
* Properties for configuring ReplicationConfiguration to replicate
* to an existing file system.
*/
export interface ExistingFileSystemProps {
/**
* The existing destination file system for the replication.
*/
readonly destinationFileSystem: IFileSystem;
}
/**
* EFS Replication Configuration
*/
export abstract class ReplicationConfiguration {
/**
* Specify the existing destination file system for the replication.
*
* @param destinationFileSystem The existing destination file system for the replication
*/
public static existingFileSystem(destinationFileSystem: IFileSystem): ReplicationConfiguration {
return new ExistingFileSystem({ destinationFileSystem });
}
/**
* Create a new regional destination file system for the replication.
*
* @param region The AWS Region in which the destination file system is located. Default is the region of the stack.
* @param kmsKey AWS KMS key used to protect the encrypted file system. Default is service-managed KMS key for Amazon EFS.
*/
public static regionalFileSystem(region?: string, kmsKey?: kms.IKey): ReplicationConfiguration {
return new RegionalFileSystem({ region, kmsKey });
}
/**
* Create a new one zone destination file system for the replication.
*
* @param region The AWS Region in which the specified availability zone belongs to.
* @param availabilityZone The availability zone name of the destination file system.
* @param kmsKey AWS KMS key used to protect the encrypted file system. Default is service-managed KMS key for Amazon EFS.
*/
public static oneZoneFileSystem(region: string, availabilityZone: string, kmsKey?: kms.IKey): ReplicationConfiguration {
return new OneZoneFileSystem({ region, availabilityZone, kmsKey });
}
/**
* The existing destination file system for the replication.
*/
public readonly destinationFileSystem?: IFileSystem;
/**
* AWS KMS key used to protect the encrypted file system.
*/
public readonly kmsKey?: kms.IKey;
/**
* The AWS Region in which the destination file system is located.
*/
public readonly region?: string;
/**
* The availability zone name of the destination file system.
* One zone file system is used as the destination file system when this property is set.
*/
public readonly availabilityZone?: string;
constructor(options: ReplicationConfigurationProps) {
this.destinationFileSystem = options.destinationFileSystem;
this.kmsKey = options.kmsKey;
this.region = options.region;
this.availabilityZone = options.availabilityZone;
}
}
/**
* Represents an existing file system used as the destination file system
* for ReplicationConfiguration.
*/
class ExistingFileSystem extends ReplicationConfiguration {
constructor(props: ExistingFileSystemProps) {
super(props);
}
}
/**
* Represents a new Regional file system used as the
* destination file system for ReplicationConfiguration.
*/
class RegionalFileSystem extends ReplicationConfiguration {
constructor(props: RegionalFileSystemProps) {
super(props);
}
}
/**
* Represents a new One Zone file system used as the
* destination file system for ReplicationConfiguration.
*/
class OneZoneFileSystem extends ReplicationConfiguration {
constructor(props: OneZoneFileSystemProps) {
super(props);
}
}
enum ClientAction {
MOUNT = 'elasticfilesystem:ClientMount',
WRITE = 'elasticfilesystem:ClientWrite',
ROOT_ACCESS = 'elasticfilesystem:ClientRootAccess',
}
abstract class FileSystemBase extends Resource implements IFileSystem {
/**
* The security groups/rules used to allow network connections to the file system.
*/
public abstract readonly connections: ec2.Connections;
/**
* @attribute
*/
public abstract readonly fileSystemId: string;
/**
* @attribute
*/
public abstract readonly fileSystemArn: string;
/**
* Dependable that can be depended upon to ensure the mount targets of the filesystem are ready
*/
public abstract readonly mountTargetsAvailable: IDependable;
/**
* @internal
*/
protected _resource?: CfnFileSystem;
/**
* @internal
*/
protected _fileSystemPolicy?: iam.PolicyDocument;
/**
* @internal
*/
protected _grantedClient: boolean = false;
/**
* Grant the actions defined in actions to the given grantee
* on this File System resource.
*
* @param grantee Principal to grant right to
* @param actions The actions to grant
*/
public grant(grantee: iam.IGrantable, ...actions: string[]): iam.Grant {
return iam.Grant.addToPrincipalOrResource({
grantee: grantee,
actions: actions,
resourceArns: [this.fileSystemArn],
resource: this,
});
}
/**
* Grant the client actions defined in actions to the given grantee on this File System resource.
* If this method is used and the allowAnonymousAccess props are not specified,
* anonymous access to this file system is prohibited.
*
* @param grantee The principal to grant right to
* @param actions The client actions to grant
* @param conditions The conditions to grant
*/
private _grantClient(grantee: iam.IGrantable, actions: ClientAction[], conditions?: Record<string, Record<string, unknown>>): iam.Grant {
this._grantedClient = true;
return iam.Grant.addToPrincipalOrResource({
grantee: grantee,
actions: actions,
resourceArns: [this.fileSystemArn],
resource: this,
conditions,
});
}
/**
* Grant read permissions for this file system to an IAM principal.
* @param grantee The principal to grant read to
*/
public grantRead(grantee: iam.IGrantable): iam.Grant {
return this._grantClient(grantee, [ClientAction.MOUNT], {
Bool: {
'elasticfilesystem:AccessedViaMountTarget': 'true',
},
});
}
/**
* Grant read and write permissions for this file system to an IAM principal.
* @param grantee The principal to grant read and write to
*/
public grantReadWrite(grantee: iam.IGrantable): iam.Grant {
return this._grantClient(grantee, [
ClientAction.MOUNT,
ClientAction.WRITE,
], {
Bool: {
'elasticfilesystem:AccessedViaMountTarget': 'true',
},
});
}
/**
* As root user, grant read and write permissions for this file system to an IAM principal.
* @param grantee The principal to grant root access to
*/
public grantRootAccess(grantee: iam.IGrantable): iam.Grant {
return this._grantClient(grantee, [
ClientAction.MOUNT,
ClientAction.WRITE,
ClientAction.ROOT_ACCESS,
], {
Bool: {
'elasticfilesystem:AccessedViaMountTarget': 'true',
},
});
}
/**
* Adds a statement to the resource policy associated with this file system.
* A resource policy will be automatically created upon the first call to `addToResourcePolicy`.
*
* Note that this does not work with imported file systems.
*
* @param statement The policy statement to add
*/
public addToResourcePolicy(
statement: iam.PolicyStatement,
): iam.AddToResourcePolicyResult {
if (!this._resource) {
return { statementAdded: false };
}
this._fileSystemPolicy = this._fileSystemPolicy ?? new iam.PolicyDocument({ statements: [] });
this._fileSystemPolicy.addStatements(statement);
return {
statementAdded: true,
policyDependable: this,
};
}
}
/**
* The Elastic File System implementation of IFileSystem.
* It creates a new, empty file system in Amazon Elastic File System (Amazon EFS).
* It also creates mount target (AWS::EFS::MountTarget) implicitly to mount the
* EFS file system on an Amazon Elastic Compute Cloud (Amazon EC2) instance or another resource.
*
* @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-efs-filesystem.html
*
* @resource AWS::EFS::FileSystem
*/
export class FileSystem extends FileSystemBase {
/**
* The default port File System listens on.
*/
public static readonly DEFAULT_PORT: number = 2049;
/**
* Import an existing File System from the given properties.
*/
public static fromFileSystemAttributes(scope: Construct, id: string, attrs: FileSystemAttributes): IFileSystem {
return new ImportedFileSystem(scope, id, attrs);
}
/**
* The security groups/rules used to allow network connections to the file system.
*/
public readonly connections: ec2.Connections;
/**
* @attribute
*/
public readonly fileSystemId: string;
/**
* @attribute
*/
public readonly fileSystemArn: string;
public readonly mountTargetsAvailable: IDependable;
private readonly _mountTargetsAvailable = new DependencyGroup();
private readonly props: FileSystemProps;
/**
* Constructor for creating a new EFS FileSystem.
*/
constructor(scope: Construct, id: string, props: FileSystemProps) {
super(scope, id);
// Enhanced CDK Analytics Telemetry
addConstructMetadata(this, props);
this.props = props;
if (props.performanceMode === PerformanceMode.MAX_IO && props.oneZone) {
throw new ValidationError('performanceMode MAX_IO is not supported for One Zone file systems.', this);
}
if (props.oneZone) { this.oneZoneValidation(); }
if (props.throughputMode === ThroughputMode.PROVISIONED && props.provisionedThroughputPerSecond === undefined) {
throw new ValidationError('Property provisionedThroughputPerSecond is required when throughputMode is PROVISIONED', this);
}
if (props.throughputMode === ThroughputMode.ELASTIC && props.performanceMode === PerformanceMode.MAX_IO) {
throw new ValidationError('ThroughputMode ELASTIC is not supported for file systems with performanceMode MAX_IO', this);
}
if (props.replicationConfiguration && props.replicationOverwriteProtection === ReplicationOverwriteProtection.DISABLED) {
throw new ValidationError('Cannot configure \'replicationConfiguration\' when \'replicationOverwriteProtection\' is set to \'DISABLED\'', this);
}
// we explicitly use 'undefined' to represent 'false' to maintain backwards compatibility since
// its considered an actual change in CloudFormations eyes, even though they have the same meaning.
const encrypted = props.encrypted ?? (FeatureFlags.of(this).isEnabled(
cxapi.EFS_DEFAULT_ENCRYPTION_AT_REST) ? true : undefined);
// LifecyclePolicies must be an array of objects, each containing a single policy
const lifecyclePolicies: CfnFileSystem.LifecyclePolicyProperty[] = [];
if (props.lifecyclePolicy) {
lifecyclePolicies.push({ transitionToIa: props.lifecyclePolicy });
}
if (props.outOfInfrequentAccessPolicy) {
lifecyclePolicies.push({ transitionToPrimaryStorageClass: props.outOfInfrequentAccessPolicy });
}
if (props.transitionToArchivePolicy) {
lifecyclePolicies.push({ transitionToArchive: props.transitionToArchivePolicy });
}
// if props.vpcSubnets.availabilityZones is defined, select the first one as the zone otherwise
// the first AZ of the VPC.
const oneZoneAzName = props.vpcSubnets?.availabilityZones ?
props.vpcSubnets.availabilityZones[0] : props.vpc.availabilityZones[0];
const fileSystemProtection = props.replicationOverwriteProtection !== undefined ? {
replicationOverwriteProtection: props.replicationOverwriteProtection,
} : undefined;
const replicationConfiguration = props.replicationConfiguration ? {
destinations: [
{
fileSystemId: props.replicationConfiguration.destinationFileSystem?.fileSystemId,
kmsKeyId: props.replicationConfiguration.kmsKey?.keyArn,
region: props.replicationConfiguration.destinationFileSystem ?
props.replicationConfiguration.destinationFileSystem.env.region :
(props.replicationConfiguration.region ?? Stack.of(this).region),
availabilityZoneName: props.replicationConfiguration.availabilityZone,
},
],
} : undefined;
this._resource = new CfnFileSystem(this, 'Resource', {
encrypted: encrypted,
kmsKeyId: props.kmsKey?.keyArn,
lifecyclePolicies: lifecyclePolicies.length > 0 ? lifecyclePolicies : undefined,
performanceMode: props.performanceMode,
throughputMode: props.throughputMode,
provisionedThroughputInMibps: props.provisionedThroughputPerSecond?.toMebibytes(),
backupPolicy: props.enableAutomaticBackups ? { status: 'ENABLED' } : undefined,
fileSystemPolicy: Lazy.any({
produce: () => {
const denyAnonymousAccessFlag = FeatureFlags.of(this).isEnabled(cxapi.EFS_DENY_ANONYMOUS_ACCESS) ?? false;
const denyAnonymousAccessByDefault = denyAnonymousAccessFlag || this._grantedClient;
const allowAnonymousAccess = props.allowAnonymousAccess ?? !denyAnonymousAccessByDefault;
if (!allowAnonymousAccess) {
this.addToResourcePolicy(new iam.PolicyStatement({
principals: [new iam.AnyPrincipal()],
actions: [
ClientAction.WRITE,
ClientAction.ROOT_ACCESS,
],
conditions: {
Bool: {
'elasticfilesystem:AccessedViaMountTarget': 'true',
},
},
}));
}
return this._fileSystemPolicy;
},
}),
fileSystemProtection,
availabilityZoneName: props.oneZone ? oneZoneAzName : undefined,
replicationConfiguration,
});
this._resource.applyRemovalPolicy(props.removalPolicy);
this.fileSystemId = this._resource.ref;
this.fileSystemArn = this._resource.attrArn;
this._fileSystemPolicy = props.fileSystemPolicy;
Tags.of(this).add('Name', props.fileSystemName || this.node.path);
const securityGroup = (props.securityGroup || new ec2.SecurityGroup(this, 'EfsSecurityGroup', {
vpc: props.vpc,
}));
this.connections = new ec2.Connections({
securityGroups: [securityGroup],
defaultPort: ec2.Port.tcp(FileSystem.DEFAULT_PORT),
});
// When oneZone is specified, to avoid deployment failure, mountTarget should also be created only in the specified AZ.
let subnetSelection: ec2.SubnetSelection;
if (props.oneZone) {
subnetSelection = {
availabilityZones: [oneZoneAzName],
};
} else {
subnetSelection = props.vpcSubnets ?? { onePerAz: true };
}
const subnets = props.vpc.selectSubnets(subnetSelection);
// We now have to create the mount target for each of the mentioned subnet
// we explicitly use FeatureFlags to maintain backwards compatibility
const useMountTargetOrderInsensitiveLogicalID = FeatureFlags.of(this).isEnabled(cxapi.EFS_MOUNTTARGET_ORDERINSENSITIVE_LOGICAL_ID);
this.mountTargetsAvailable = [];
if (useMountTargetOrderInsensitiveLogicalID) {
subnets.subnets.forEach((subnet) => {
const subnetUniqueId = Token.isUnresolved(subnet.node.id) ? Names.uniqueResourceName(subnet, { maxLength: 16 }) : subnet.node.id;
const mountTarget = new CfnMountTarget(this,
`EfsMountTarget-${subnetUniqueId}`,
{
fileSystemId: this.fileSystemId,
securityGroups: Array.of(securityGroup.securityGroupId),
subnetId: subnet.subnetId,
});
this._mountTargetsAvailable.add(mountTarget);
});
} else {
let mountTargetCount = 0;
subnets.subnetIds.forEach((subnetId: string) => {
const mountTarget = new CfnMountTarget(this,
'EfsMountTarget' + (++mountTargetCount),
{
fileSystemId: this.fileSystemId,
securityGroups: Array.of(securityGroup.securityGroupId),
subnetId,
});
this._mountTargetsAvailable.add(mountTarget);
});
}
this.mountTargetsAvailable = this._mountTargetsAvailable;
}
private oneZoneValidation() {
// validate when props.oneZone is enabled
if (this.props.vpcSubnets && !this.props.vpcSubnets.availabilityZones) {
throw new ValidationError('When oneZone is enabled and vpcSubnets defined, vpcSubnets.availabilityZones can not be undefined.', this);
}
// when vpcSubnets.availabilityZones is defined
if (this.props.vpcSubnets && this.props.vpcSubnets.availabilityZones) {
// it has to be only one az
if (this.props.vpcSubnets.availabilityZones?.length !== 1) {
throw new ValidationError('When oneZone is enabled, vpcSubnets.availabilityZones should exactly have one zone.', this);
}
// it has to be in availabilityZones
// but we only check this when vpc.availabilityZones are valid(not dummy values nore unresolved tokens)
const isNotUnresolvedToken = (x: string) => !Token.isUnresolved(x);
const isNotDummy = (x: string) => !x.startsWith('dummy');
if (this.props.vpc.availabilityZones.every(isNotUnresolvedToken) &&
this.props.vpc.availabilityZones.every(isNotDummy) &&
!this.props.vpc.availabilityZones.includes(this.props.vpcSubnets.availabilityZones[0])) {
throw new ValidationError('vpcSubnets.availabilityZones specified is not in vpc.availabilityZones.', this);
}
}
}
/**
* create access point from this filesystem
*/
@MethodMetadata()
public addAccessPoint(id: string, accessPointOptions: AccessPointOptions = {}): AccessPoint {
return new AccessPoint(this, id, {
fileSystem: this,
...accessPointOptions,
});
}
}
class ImportedFileSystem extends FileSystemBase {
/**
* The security groups/rules used to allow network connections to the file system.
*/
public readonly connections: ec2.Connections;
/**
* @attribute
*/
public readonly fileSystemId: string;
/**
* @attribute
*/
public readonly fileSystemArn: string;
/**
* Dependable that can be depended upon to ensure the mount targets of the filesystem are ready
*/
public readonly mountTargetsAvailable: IDependable;
constructor(scope: Construct, id: string, attrs: FileSystemAttributes) {
super(scope, id);
// Enhanced CDK Analytics Telemetry
addConstructMetadata(this, attrs);
if (!!attrs.fileSystemId === !!attrs.fileSystemArn) {
throw new ValidationError('One of fileSystemId or fileSystemArn, but not both, must be provided.', this);
}
this.fileSystemArn = attrs.fileSystemArn ?? Stack.of(scope).formatArn({
service: 'elasticfilesystem',
resource: 'file-system',
resourceName: attrs.fileSystemId,
});
const parsedArn = Stack.of(scope).splitArn(this.fileSystemArn, ArnFormat.SLASH_RESOURCE_NAME);
if (!parsedArn.resourceName) {
throw new ValidationError(`Invalid FileSystem Arn ${this.fileSystemArn}`, this);
}
this.fileSystemId = attrs.fileSystemId ?? parsedArn.resourceName;
this.connections = new ec2.Connections({
securityGroups: [attrs.securityGroup],
defaultPort: ec2.Port.tcp(FileSystem.DEFAULT_PORT),
});
this.mountTargetsAvailable = new DependencyGroup();
}
}