diff --git a/packages/aws-cdk-lib/aws-backup/lib/resource.ts b/packages/aws-cdk-lib/aws-backup/lib/resource.ts index fcf6a8645ae7d..97826e79b149c 100644 --- a/packages/aws-cdk-lib/aws-backup/lib/resource.ts +++ b/packages/aws-cdk-lib/aws-backup/lib/resource.ts @@ -1,9 +1,9 @@ import { Construct } from 'constructs'; import * as dynamodb from '../../aws-dynamodb'; import * as ec2 from '../../aws-ec2'; -import * as efs from '../../aws-efs'; import * as rds from '../../aws-rds'; import { Stack } from '../../core'; +import { IFileSystemRef } from '../../interfaces/generated/aws-efs-interfaces.generated'; /** * An operation that is applied to a key-value pair @@ -83,11 +83,11 @@ export class BackupResource { /** * An EFS file system */ - public static fromEfsFileSystem(fileSystem: efs.IFileSystem) { + public static fromEfsFileSystem(fileSystem: IFileSystemRef) { return BackupResource.fromArn(Stack.of(fileSystem).formatArn({ service: 'elasticfilesystem', resource: 'file-system', - resourceName: fileSystem.fileSystemId, + resourceName: fileSystem.fileSystemRef.fileSystemId, })); } diff --git a/packages/aws-cdk-lib/aws-batch/lib/ecs-container-definition.ts b/packages/aws-cdk-lib/aws-batch/lib/ecs-container-definition.ts index 900e0bd699d7a..e329e76253f51 100644 --- a/packages/aws-cdk-lib/aws-batch/lib/ecs-container-definition.ts +++ b/packages/aws-cdk-lib/aws-batch/lib/ecs-container-definition.ts @@ -7,8 +7,9 @@ import * as iam from '../../aws-iam'; import { LogGroup } from '../../aws-logs'; import * as secretsmanager from '../../aws-secretsmanager'; import * as ssm from '../../aws-ssm'; -import { Lazy, PhysicalName, Size, ValidationError } from '../../core'; +import { Lazy, PhysicalName, Size, UnscopedValidationError, ValidationError } from '../../core'; import { propertyInjectable } from '../../core/lib/prop-injectable'; +import { IFileSystemRef } from '../../interfaces/generated/aws-efs-interfaces.generated'; const EFS_VOLUME_SYMBOL = Symbol.for('aws-cdk-lib/aws-batch/lib/container-definition.EfsVolume'); const HOST_VOLUME_SYMBOL = Symbol.for('aws-cdk-lib/aws-batch/lib/container-definition.HostVolume'); @@ -174,7 +175,7 @@ export interface EfsVolumeOptions extends EcsVolumeOptions { /** * The EFS File System that supports this volume */ - readonly fileSystem: IFileSystem; + readonly fileSystem: IFileSystemRef; /** * The directory within the Amazon EFS file system to mount as the root directory inside the host. @@ -239,10 +240,21 @@ export class EfsVolume extends EcsVolume { return x !== null && typeof(x) === 'object' && EFS_VOLUME_SYMBOL in x; } + protected readonly _fileSystem: IFileSystemRef; + /** * The EFS File System that supports this volume */ - public readonly fileSystem: IFileSystem; + public get fileSystem(): IFileSystem { + return toIFileSystem(this._fileSystem); + } + + /** + * @internal + */ + public get _fileSystemRef(): IFileSystemRef { + return this._fileSystem; + } /** * The directory within the Amazon EFS file system to mount as the root directory inside the host. @@ -298,7 +310,7 @@ export class EfsVolume extends EcsVolume { constructor(options: EfsVolumeOptions) { super(options); - this.fileSystem = options.fileSystem; + this._fileSystem = options.fileSystem; this.rootDirectory = options.rootDirectory; this.enableTransitEncryption = options.enableTransitEncryption; this.transitEncryptionPort = options.transitEncryptionPort; @@ -700,7 +712,7 @@ abstract class EcsContainerDefinitionBase extends Construct implements IEcsConta return { name: volume.name, efsVolumeConfiguration: { - fileSystemId: volume.fileSystem.fileSystemId, + fileSystemId: volume._fileSystemRef.fileSystemRef.fileSystemId, rootDirectory: volume.rootDirectory, transitEncryption: volume.enableTransitEncryption ? 'ENABLED' : (volume.enableTransitEncryption === false ? 'DISABLED' : undefined), transitEncryptionPort: volume.transitEncryptionPort, @@ -1204,3 +1216,10 @@ function createExecutionRole(scope: Construct, id: string, logging: boolean): ia return execRole; } + +function toIFileSystem(fileSystem: IFileSystemRef): IFileSystem { + if (!('fileSystemId' in fileSystem) || !('fileSystemArn' in fileSystem)) { + throw new UnscopedValidationError(`'fileSystem' instance should implement IFileSystem, but doesn't: ${fileSystem.constructor.name}`); + } + return fileSystem as IFileSystem; +} diff --git a/packages/aws-cdk-lib/aws-efs/lib/access-point.ts b/packages/aws-cdk-lib/aws-efs/lib/access-point.ts index 0b1c195caf0c1..2fb6744c99307 100644 --- a/packages/aws-cdk-lib/aws-efs/lib/access-point.ts +++ b/packages/aws-cdk-lib/aws-efs/lib/access-point.ts @@ -1,14 +1,15 @@ import { Construct } from 'constructs'; import { IFileSystem } from './efs-file-system'; import { CfnAccessPoint } from './efs.generated'; -import { ArnFormat, IResource, Resource, Stack, Tags, Token, ValidationError } from '../../core'; +import { ArnFormat, IResource, Resource, Stack, Tags, Token, UnscopedValidationError, ValidationError } from '../../core'; import { addConstructMetadata } from '../../core/lib/metadata-resource'; import { propertyInjectable } from '../../core/lib/prop-injectable'; +import { AccessPointReference, IAccessPointRef, IFileSystemRef } from '../../interfaces/generated/aws-efs-interfaces.generated'; /** * Represents an EFS AccessPoint */ -export interface IAccessPoint extends IResource { +export interface IAccessPoint extends IAccessPointRef, IResource { /** * The ID of the AccessPoint * @@ -122,7 +123,7 @@ export interface AccessPointProps extends AccessPointOptions { /** * The efs filesystem */ - readonly fileSystem: IFileSystem; + readonly fileSystem: IFileSystemRef; } /** @@ -150,7 +151,7 @@ export interface AccessPointAttributes { * * @default - no EFS file system */ - readonly fileSystem?: IFileSystem; + readonly fileSystem?: IFileSystemRef; } abstract class AccessPointBase extends Resource implements IAccessPoint { @@ -170,6 +171,13 @@ abstract class AccessPointBase extends Resource implements IAccessPoint { * The file system of the access point */ public abstract readonly fileSystem: IFileSystem; + + public get accessPointRef(): AccessPointReference { + return { + accessPointId: this.accessPointId, + accessPointArn: this.accessPointArn, + }; + } } /** @@ -208,10 +216,14 @@ export class AccessPoint extends AccessPointBase { */ public readonly accessPointId: string; + private readonly _fileSystem: IFileSystemRef; + /** * The file system of the access point */ - public readonly fileSystem: IFileSystem; + public get fileSystem(): IFileSystem { + return toIFileSystem(this._fileSystem); + } constructor(scope: Construct, id: string, props: AccessPointProps) { super(scope, id); @@ -224,7 +236,7 @@ export class AccessPoint extends AccessPointBase { } const resource = new CfnAccessPoint(this, 'Resource', { - fileSystemId: props.fileSystem.fileSystemId, + fileSystemId: props.fileSystem.fileSystemRef.fileSystemId, rootDirectory: { creationInfo: props.createAcl ? { ownerGid: props.createAcl.ownerGid, @@ -249,7 +261,7 @@ export class AccessPoint extends AccessPointBase { resource: 'access-point', resourceName: this.accessPointId, }); - this.fileSystem = props.fileSystem; + this._fileSystem = props.fileSystem; } } @@ -259,7 +271,7 @@ class ImportedAccessPoint extends AccessPointBase { public static readonly PROPERTY_INJECTION_ID: string = 'aws-cdk-lib.aws-efs.ImportedAccessPoint'; public readonly accessPointId: string; public readonly accessPointArn: string; - private readonly _fileSystem?: IFileSystem; + private readonly _fileSystem?: IFileSystemRef; constructor(scope: Construct, id: string, attrs: AccessPointAttributes) { super(scope, id); @@ -300,6 +312,13 @@ class ImportedAccessPoint extends AccessPointBase { throw new ValidationError("fileSystem is only available if 'fromAccessPointAttributes()' is used and a fileSystem is passed in as an attribute.", this); } - return this._fileSystem; + return toIFileSystem(this._fileSystem); + } +} + +function toIFileSystem(fileSystem: IFileSystemRef): IFileSystem { + if (!('fileSystemId' in fileSystem) || !('fileSystemArn' in fileSystem)) { + throw new UnscopedValidationError(`'fileSystem' instance should implement IFileSystem, but doesn't: ${fileSystem.constructor.name}`); } + return fileSystem as IFileSystem; } diff --git a/packages/aws-cdk-lib/aws-efs/lib/efs-file-system.ts b/packages/aws-cdk-lib/aws-efs/lib/efs-file-system.ts index 87d5045d58d74..7dd2f85bbb333 100644 --- a/packages/aws-cdk-lib/aws-efs/lib/efs-file-system.ts +++ b/packages/aws-cdk-lib/aws-efs/lib/efs-file-system.ts @@ -8,6 +8,7 @@ import { ArnFormat, FeatureFlags, Lazy, Names, RemovalPolicy, Resource, Size, St import { addConstructMetadata, MethodMetadata } from '../../core/lib/metadata-resource'; import { propertyInjectable } from '../../core/lib/prop-injectable'; import * as cxapi from '../../cx-api'; +import { FileSystemReference, IFileSystemRef } from '../../interfaces/generated/aws-efs-interfaces.generated'; /** * EFS Lifecycle Policy, if a file is not accessed for given days, it will move to EFS Infrequent Access @@ -141,7 +142,7 @@ export enum ReplicationOverwriteProtection { /** * Represents an Amazon EFS file system */ -export interface IFileSystem extends ec2.IConnectable, iam.IResourceWithPolicy { +export interface IFileSystem extends IFileSystemRef, ec2.IConnectable, iam.IResourceWithPolicy { /** * The ID of the file system, assigned by Amazon EFS. * @@ -368,7 +369,7 @@ export interface ReplicationConfigurationProps { * * @default - None */ - readonly destinationFileSystem?: IFileSystem; + readonly destinationFileSystem?: IFileSystemRef; /** * AWS KMS key used to protect the encrypted file system. @@ -445,7 +446,7 @@ export interface ExistingFileSystemProps { /** * The existing destination file system for the replication. */ - readonly destinationFileSystem: IFileSystem; + readonly destinationFileSystem: IFileSystemRef; } /** @@ -457,7 +458,7 @@ export abstract class ReplicationConfiguration { * * @param destinationFileSystem The existing destination file system for the replication */ - public static existingFileSystem(destinationFileSystem: IFileSystem): ReplicationConfiguration { + public static existingFileSystem(destinationFileSystem: IFileSystemRef): ReplicationConfiguration { return new ExistingFileSystem({ destinationFileSystem }); } @@ -482,10 +483,21 @@ export abstract class ReplicationConfiguration { return new OneZoneFileSystem({ region, availabilityZone, kmsKey }); } + protected readonly _destinationFileSystem?: IFileSystemRef; + /** * The existing destination file system for the replication. */ - public readonly destinationFileSystem?: IFileSystem; + public get destinationFileSystem(): IFileSystem | undefined { + return this._destinationFileSystem ? toIFileSystem(this._destinationFileSystem) : undefined; + } + + /** + * @internal + */ + public get _destinationFileSystemRef(): IFileSystemRef | undefined { + return this._destinationFileSystem; + } /** * AWS KMS key used to protect the encrypted file system. @@ -504,7 +516,7 @@ export abstract class ReplicationConfiguration { public readonly availabilityZone?: string; constructor(options: ReplicationConfigurationProps) { - this.destinationFileSystem = options.destinationFileSystem; + this._destinationFileSystem = options.destinationFileSystem; this.kmsKey = options.kmsKey; this.region = options.region; this.availabilityZone = options.availabilityZone; @@ -567,6 +579,13 @@ abstract class FileSystemBase extends Resource implements IFileSystem { */ public abstract readonly mountTargetsAvailable: IDependable; + public get fileSystemRef(): FileSystemReference { + return { + fileSystemId: this.fileSystemId, + fileSystemArn: this.fileSystemArn, + }; + } + /** * @internal */ @@ -791,10 +810,10 @@ export class FileSystem extends FileSystemBase { const replicationConfiguration = props.replicationConfiguration ? { destinations: [ { - fileSystemId: props.replicationConfiguration.destinationFileSystem?.fileSystemId, + fileSystemId: props.replicationConfiguration._destinationFileSystemRef?.fileSystemRef.fileSystemId, kmsKeyId: props.replicationConfiguration.kmsKey?.keyArn, - region: props.replicationConfiguration.destinationFileSystem ? - props.replicationConfiguration.destinationFileSystem.env.region : + region: props.replicationConfiguration._destinationFileSystemRef ? + props.replicationConfiguration._destinationFileSystemRef.env.region : (props.replicationConfiguration.region ?? Stack.of(this).region), availabilityZoneName: props.replicationConfiguration.availabilityZone, }, @@ -987,3 +1006,10 @@ class ImportedFileSystem extends FileSystemBase { this.mountTargetsAvailable = new DependencyGroup(); } } + +function toIFileSystem(fileSystem: IFileSystemRef): IFileSystem { + if (!('fileSystemId' in fileSystem) || !('fileSystemArn' in fileSystem)) { + throw new ValidationError(`'fileSystem' instance should implement IFileSystem, but doesn't: ${fileSystem.constructor.name}`, fileSystem as any); + } + return fileSystem as IFileSystem; +}