constructor()

in packages/aws-cdk-lib/aws-efs/lib/efs-file-system.ts [730:891]


  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;
  }