@go-to-k/cdkd 0.243.0 → 0.244.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import { a as getLiveRenderer, c as PATTERN_B_RESOURCE_TYPES, d as generateResourceNameWithFallback, f as withSkipPrefix, i as runStackBuffered, n as getLogger, o as PATTERN_B_NAME_OPTIONS, p as withStackName, s as PATTERN_B_NAME_PROPERTIES, u as generateResourceName } from "./logger-BzO-joNR.js";
3
3
  import { A as withErrorHandling, C as StackHasActiveImportsError, S as ResourceUpdateNotSupportedError, _ as MissingCdkCliError, a as normalizeAwsTagsToCfn, b as ProvisioningError, f as LocalInvokeBuildError$1, i as matchesCdkPath, k as normalizeAwsError, l as CdkdError, m as LocalStartServiceError, n as isTerminationProtectionPropagationError, o as resolveExplicitPhysicalId, p as LocalMigrateError, r as CDK_PATH_TAG, s as assertRegionMatch, t as disableInstanceApiTermination, v as NestedStackChildDirectDestroyError, w as StackTerminationProtectionError, x as ResourceTimeoutError, y as PartialFailureError } from "./ec2-termination-protection-q-WGWgxa.js";
4
4
  import { a as setAwsClients, i as resetAwsClients, r as getAwsClients, t as AwsClients } from "./aws-clients-B15NAPbL.js";
5
- import { $ as getDockerCmd, A as DiffCalculator, B as buildAssetRedirectMap, C as findActionableSilentDrops, Ct as resolveBucketRegion, D as refStateLookupFromResource, E as cfnRefValueFromPhysicalId, F as rebuildClientForBucketRegion, G as BOOTSTRAP_MARKER_PREFIX, H as loadPublishableAssetManifest, I as shouldRetainResource, J as parseBootstrapMarker, K as ensureAssetStorage, L as AssetPublisher, M as TemplateParser, N as LockManager, O as WAFv2WebACLProvider, P as S3StateBackend, Q as formatDockerLoginError, R as stringifyValue, S as ProviderRegistry, T as IntrinsicFunctionResolver, U as rewriteTemplateAssetReferences, V as createAssetRedirectResolver, W as AssetModeResolver, X as validateContainerRepoName, Y as validateAssetBucketName, Z as buildDockerImage, _ as green, _t as CFN_TEMPLATE_URL_LIMIT, a as withRetry, at as synthesisStatusMessage, b as IAMRoleProvider, bt as uploadCfnTemplate, c as computeImplicitDeleteEdges, ct as resolveApp, d as isStatefulRecreateTargetSync, dt as resolveSkipPrefix, et as runDockerForeground, f as renderStatefulReason, ft as resolveStateBucketWithDefault, g as gray, gt as CFN_TEMPLATE_BODY_LIMIT, h as cyan, ht as warnDeprecatedNoPrefixCliFlag, i as withResourceDeadline, it as Synthesizer, j as DagBuilder, k as applyRoleArnIfSet, l as extractDeploymentEventError, lt as resolveAutoAssetStorage, m as bold, mt as resolveUseCdkBootstrapAssets, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nt as AssetManifestLoader, o as isRetryableTransientError, ot as getDefaultStateBucketName, p as formatResourceLine, pt as resolveStateBucketWithDefaultAndSource, q as getBootstrapMarkerKey, r as DeployEngine, rt as getDockerImageBySourceHash, s as IMPLICIT_DELETE_DEPENDENCIES, st as getLegacyStateBucketName, t as DEFAULT_RESOURCE_TIMEOUT_MS, tt as runDockerStreaming, u as MULTI_REGION_RECREATE_BLOCKED_TYPES, ut as resolveCaptureObservedState, v as red, vt as MIGRATE_TMP_PREFIX, w as CloudControlProvider, x as collectInlinePolicyNamesManagedBySiblings, xt as AssemblyReader, y as yellow, yt as findLargeInlineResources, z as WorkGraph } from "./deploy-engine-DNqZHDA5.js";
5
+ import { $ as getDockerCmd, A as DiffCalculator, B as buildAssetRedirectMap, C as findActionableSilentDrops, Ct as resolveBucketRegion, D as refStateLookupFromResource, E as cfnRefValueFromPhysicalId, F as rebuildClientForBucketRegion, G as BOOTSTRAP_MARKER_PREFIX, H as loadPublishableAssetManifest, I as shouldRetainResource, J as parseBootstrapMarker, K as ensureAssetStorage, L as AssetPublisher, M as TemplateParser, N as LockManager, O as WAFv2WebACLProvider, P as S3StateBackend, Q as formatDockerLoginError, R as stringifyValue, S as ProviderRegistry, T as IntrinsicFunctionResolver, U as rewriteTemplateAssetReferences, V as createAssetRedirectResolver, W as AssetModeResolver, X as validateContainerRepoName, Y as validateAssetBucketName, Z as buildDockerImage, _ as green, _t as CFN_TEMPLATE_URL_LIMIT, a as withRetry, at as synthesisStatusMessage, b as IAMRoleProvider, bt as uploadCfnTemplate, c as computeImplicitDeleteEdges, ct as resolveApp, d as isStatefulRecreateTargetSync, dt as resolveSkipPrefix, et as runDockerForeground, f as renderStatefulReason, ft as resolveStateBucketWithDefault, g as gray, gt as CFN_TEMPLATE_BODY_LIMIT, h as cyan, ht as warnDeprecatedNoPrefixCliFlag, i as withResourceDeadline, it as Synthesizer, j as DagBuilder, k as applyRoleArnIfSet, l as extractDeploymentEventError, lt as resolveAutoAssetStorage, m as bold, mt as resolveUseCdkBootstrapAssets, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nt as AssetManifestLoader, o as isRetryableTransientError, ot as getDefaultStateBucketName, p as formatResourceLine, pt as resolveStateBucketWithDefaultAndSource, q as getBootstrapMarkerKey, r as DeployEngine, rt as getDockerImageBySourceHash, s as IMPLICIT_DELETE_DEPENDENCIES, st as getLegacyStateBucketName, t as DEFAULT_RESOURCE_TIMEOUT_MS, tt as runDockerStreaming, u as MULTI_REGION_RECREATE_BLOCKED_TYPES, ut as resolveCaptureObservedState, v as red, vt as MIGRATE_TMP_PREFIX, w as CloudControlProvider, x as collectInlinePolicyNamesManagedBySiblings, xt as AssemblyReader, y as yellow, yt as findLargeInlineResources, z as WorkGraph } from "./deploy-engine-3KNTmr1u.js";
6
6
  import { t as expectedOwnerParam } from "./expected-bucket-owner-BjEfUnkA.js";
7
7
  import { t as ASGProvider } from "./asg-provider-Dbl1_mwT.js";
8
8
  import { AsyncLocalStorage } from "node:async_hooks";
@@ -59,13 +59,14 @@ import { BudgetsClient, CreateBudgetCommand, CreateNotificationCommand, CreateSu
59
59
  import { AddTagsToStreamCommand, CreateStreamCommand, DecreaseStreamRetentionPeriodCommand, DeleteStreamCommand, DeregisterStreamConsumerCommand, DescribeStreamCommand, DescribeStreamConsumerCommand, DescribeStreamSummaryCommand, IncreaseStreamRetentionPeriodCommand, KinesisClient, ListStreamsCommand, ListTagsForResourceCommand as ListTagsForResourceCommand$18, ListTagsForStreamCommand, RegisterStreamConsumerCommand, RemoveTagsFromStreamCommand, ResourceNotFoundException as ResourceNotFoundException$8, StartStreamEncryptionCommand, StopStreamEncryptionCommand, TagResourceCommand as TagResourceCommand$17, UntagResourceCommand as UntagResourceCommand$17, UpdateShardCountCommand, UpdateStreamModeCommand } from "@aws-sdk/client-kinesis";
60
60
  import { CreateScheduleCommand, DeleteScheduleCommand, GetScheduleCommand, ResourceNotFoundException as ResourceNotFoundException$9, SchedulerClient, UpdateScheduleCommand } from "@aws-sdk/client-scheduler";
61
61
  import { AccessPointNotFound, CreateAccessPointCommand, CreateFileSystemCommand, CreateMountTargetCommand, DeleteAccessPointCommand, DeleteFileSystemCommand, DeleteMountTargetCommand, DescribeAccessPointsCommand, DescribeBackupPolicyCommand, DescribeFileSystemPolicyCommand, DescribeFileSystemsCommand, DescribeLifecycleConfigurationCommand, DescribeMountTargetSecurityGroupsCommand, DescribeMountTargetsCommand, EFSClient, FileSystemNotFound, ModifyMountTargetSecurityGroupsCommand, MountTargetNotFound, PutBackupPolicyCommand, PutFileSystemPolicyCommand, PutLifecycleConfigurationCommand, UpdateFileSystemCommand, UpdateFileSystemProtectionCommand } from "@aws-sdk/client-efs";
62
+ import { CreateFileSystemCommand as CreateFileSystemCommand$1, CreateFileSystemFromBackupCommand, DeleteFileSystemCommand as DeleteFileSystemCommand$1, DescribeFileSystemsCommand as DescribeFileSystemsCommand$1, FSxClient, FileSystemNotFound as FileSystemNotFound$1, TagResourceCommand as TagResourceCommand$18, UntagResourceCommand as UntagResourceCommand$18, UpdateFileSystemCommand as UpdateFileSystemCommand$1 } from "@aws-sdk/client-fsx";
62
63
  import { CreateDeliveryStreamCommand, DeleteDeliveryStreamCommand, DescribeDeliveryStreamCommand, FirehoseClient, ListDeliveryStreamsCommand, ListTagsForDeliveryStreamCommand, ResourceNotFoundException as ResourceNotFoundException$10, TagDeliveryStreamCommand, UntagDeliveryStreamCommand, UpdateDestinationCommand } from "@aws-sdk/client-firehose";
63
64
  import { AddTagsCommand as AddTagsCommand$1, CloudTrailClient, CreateTrailCommand, DeleteTrailCommand, GetEventSelectorsCommand, GetInsightSelectorsCommand, GetTrailCommand, GetTrailStatusCommand, ListTagsCommand as ListTagsCommand$1, ListTrailsCommand, PutEventSelectorsCommand, PutInsightSelectorsCommand, RemoveTagsCommand as RemoveTagsCommand$1, StartLoggingCommand, StopLoggingCommand, TrailNotFoundException, UpdateTrailCommand } from "@aws-sdk/client-cloudtrail";
64
65
  import { BatchGetProjectsCommand, CodeBuildClient, CreateProjectCommand, DeleteProjectCommand, ListProjectsCommand, ResourceNotFoundException as ResourceNotFoundException$11, UpdateProjectCommand } from "@aws-sdk/client-codebuild";
65
- import { CodeCommitClient, CreateRepositoryCommand as CreateRepositoryCommand$1, DeleteRepositoryCommand as DeleteRepositoryCommand$1, GetRepositoryCommand, ListRepositoriesCommand, ListTagsForResourceCommand as ListTagsForResourceCommand$19, RepositoryDoesNotExistException, TagResourceCommand as TagResourceCommand$18, UntagResourceCommand as UntagResourceCommand$18, UpdateRepositoryDescriptionCommand, UpdateRepositoryEncryptionKeyCommand, UpdateRepositoryNameCommand } from "@aws-sdk/client-codecommit";
66
- import { CreateLifecyclePolicyCommand, DLMClient, DeleteLifecyclePolicyCommand as DeleteLifecyclePolicyCommand$1, GetLifecyclePoliciesCommand, GetLifecyclePolicyCommand as GetLifecyclePolicyCommand$1, ResourceNotFoundException as ResourceNotFoundException$12, TagResourceCommand as TagResourceCommand$19, UntagResourceCommand as UntagResourceCommand$19, UpdateLifecyclePolicyCommand } from "@aws-sdk/client-dlm";
67
- import { CreateVectorBucketCommand, DeleteIndexCommand, DeleteVectorBucketCommand, GetVectorBucketCommand, ListIndexesCommand, ListTagsForResourceCommand as ListTagsForResourceCommand$20, ListVectorBucketsCommand, S3VectorsClient, TagResourceCommand as TagResourceCommand$20, UntagResourceCommand as UntagResourceCommand$20 } from "@aws-sdk/client-s3vectors";
68
- import { CreateNamespaceCommand, CreateTableBucketCommand, CreateTableCommand as CreateTableCommand$2, DeleteNamespaceCommand as DeleteNamespaceCommand$1, DeleteTableBucketCommand, DeleteTableCommand as DeleteTableCommand$2, GetTableBucketCommand, GetTableCommand as GetTableCommand$1, ListNamespacesCommand as ListNamespacesCommand$1, ListTableBucketsCommand, ListTablesCommand as ListTablesCommand$1, ListTagsForResourceCommand as ListTagsForResourceCommand$21, NotFoundException as NotFoundException$6, S3TablesClient, TagResourceCommand as TagResourceCommand$21, UntagResourceCommand as UntagResourceCommand$21 } from "@aws-sdk/client-s3tables";
66
+ import { CodeCommitClient, CreateRepositoryCommand as CreateRepositoryCommand$1, DeleteRepositoryCommand as DeleteRepositoryCommand$1, GetRepositoryCommand, ListRepositoriesCommand, ListTagsForResourceCommand as ListTagsForResourceCommand$19, RepositoryDoesNotExistException, TagResourceCommand as TagResourceCommand$19, UntagResourceCommand as UntagResourceCommand$19, UpdateRepositoryDescriptionCommand, UpdateRepositoryEncryptionKeyCommand, UpdateRepositoryNameCommand } from "@aws-sdk/client-codecommit";
67
+ import { CreateLifecyclePolicyCommand, DLMClient, DeleteLifecyclePolicyCommand as DeleteLifecyclePolicyCommand$1, GetLifecyclePoliciesCommand, GetLifecyclePolicyCommand as GetLifecyclePolicyCommand$1, ResourceNotFoundException as ResourceNotFoundException$12, TagResourceCommand as TagResourceCommand$20, UntagResourceCommand as UntagResourceCommand$20, UpdateLifecyclePolicyCommand } from "@aws-sdk/client-dlm";
68
+ import { CreateVectorBucketCommand, DeleteIndexCommand, DeleteVectorBucketCommand, GetVectorBucketCommand, ListIndexesCommand, ListTagsForResourceCommand as ListTagsForResourceCommand$20, ListVectorBucketsCommand, S3VectorsClient, TagResourceCommand as TagResourceCommand$21, UntagResourceCommand as UntagResourceCommand$21 } from "@aws-sdk/client-s3vectors";
69
+ import { CreateNamespaceCommand, CreateTableBucketCommand, CreateTableCommand as CreateTableCommand$2, DeleteNamespaceCommand as DeleteNamespaceCommand$1, DeleteTableBucketCommand, DeleteTableCommand as DeleteTableCommand$2, GetTableBucketCommand, GetTableCommand as GetTableCommand$1, ListNamespacesCommand as ListNamespacesCommand$1, ListTableBucketsCommand, ListTablesCommand as ListTablesCommand$1, ListTagsForResourceCommand as ListTagsForResourceCommand$21, NotFoundException as NotFoundException$6, S3TablesClient, TagResourceCommand as TagResourceCommand$22, UntagResourceCommand as UntagResourceCommand$22 } from "@aws-sdk/client-s3tables";
69
70
  import { Document, Pair, Scalar, YAMLMap, YAMLSeq, parse as parse$1, stringify } from "yaml";
70
71
  import { createLocalStartAgentCoreCommand, createLocalStartCloudFrontCommand, createLocalStateProvider, getEmbedConfig, isCfnFlagPresent, listTargets, rejectExplicitCfnStackWithMultipleStacks, resolveCfnFallbackRegion, setEmbedConfig, substituteAgainstState, substituteAgainstStateAsync, substituteEnvVarsFromState, substituteEnvVarsFromStateAsync } from "cdk-local";
71
72
  import { A2A_CONTAINER_PORT, A2A_PATH, AGENTCORE_A2A_PROTOCOL, AGENTCORE_AGUI_PROTOCOL, AGENTCORE_MCP_PROTOCOL, ConnectionRegistry, EcsTaskResolutionError, HOST_GATEWAY_MIN_VERSION, LocalInvokeBuildError, MCP_CONTAINER_PORT, MCP_PATH, a2aInvokeOnce, addAlbSpecificOptions, addCommonEcsServiceOptions, addStartServiceSpecificOptions, albStrategy, architectureToPlatform, attachAuthorizers, attachStageContext, availableApiIdentifiers, bufferToBody, buildAgentCoreCodeImage, buildCognitoJwksUrl, buildConnectEvent, buildContainerImage, buildCorsConfigByApiId, buildCorsConfigFromCloudFrontChain, buildDisconnectEvent, buildJwksUrlFromIssuer, buildMessageEvent, buildMgmtEndpointEnvUrl, buildStageMap, classifySourceChange, createAuthorizerCache, createFileWatcher, createFileWatcher as createFileWatcher$1, createJwksCache, createWatchPredicates, defaultCredentialsLoader, derivePseudoParametersFromRegion, discoverRoutes, discoverWebSocketApis, downloadAndExtractS3Bundle, filterRoutesByApiIdentifier, groupRoutesByServer, handleConnectionsRequest, invokeAgentCore, invokeAgentCoreWs, materializeLayerFromArn, mcpInvokeOnce, parseConnectionsPath, parseSelectionExpressionPath, pickAgentCoreCandidateStack, pickAgentCoreCandidateStack as pickAgentCoreCandidateStack$1, probeHostGatewaySupport, readMtlsMaterialsFromDisk, resolveAgentCoreTarget, resolveEnvVars, resolveHostGatewayExtraHosts, resolveRuntimeCodeMountPath, resolveRuntimeFileExtension, resolveRuntimeImage, resolveSingleTarget, resolveWatchConfig, runEcsServiceEmulator, signAgentCoreInvocation, startApiServer, substituteImagePlaceholders, tryResolveImageFnJoin, verifyJwtViaDiscovery, waitForAgentCorePing } from "cdk-local/internal";
@@ -1888,7 +1889,7 @@ const FLUSH_INTERVAL_MS = 2e3;
1888
1889
  const FLUSH_EVENT_THRESHOLD = 50;
1889
1890
  /** Build-time cdkd version, with a dev fallback for non-built contexts. */
1890
1891
  function getCdkdVersion() {
1891
- return "0.243.0";
1892
+ return "0.244.0";
1892
1893
  }
1893
1894
  /**
1894
1895
  * Generate a time-sortable unique run id, e.g.
@@ -34402,6 +34403,601 @@ var EFSProvider = class {
34402
34403
  }
34403
34404
  };
34404
34405
 
34406
+ //#endregion
34407
+ //#region src/provisioning/providers/fsx-filesystem-provider.ts
34408
+ /**
34409
+ * Default polling budget for FSx lifecycle transitions. Lustre SCRATCH
34410
+ * creates typically finish in 5-10 minutes, but PERSISTENT creates,
34411
+ * storage-capacity growth and deletes can take substantially longer —
34412
+ * mirror the Custom Resource provider's 1-hour ceiling.
34413
+ */
34414
+ const DEFAULT_MAX_WAIT_MS = 3600 * 1e3;
34415
+ const DEFAULT_POLL_INTERVAL_MS = 15e3;
34416
+ /**
34417
+ * Lustre sub-properties that `UpdateFileSystem` accepts (the mutable
34418
+ * subset of the CFn `LustreConfiguration` block). Everything else in the
34419
+ * block is fixed at creation — FSx has no API to change it in place.
34420
+ */
34421
+ const LUSTRE_MUTABLE_SUBPROPS = new Set([
34422
+ "WeeklyMaintenanceStartTime",
34423
+ "DailyAutomaticBackupStartTime",
34424
+ "AutomaticBackupRetentionDays",
34425
+ "AutoImportPolicy",
34426
+ "DataCompressionType",
34427
+ "PerUnitStorageThroughput",
34428
+ "MetadataConfiguration",
34429
+ "ThroughputCapacity",
34430
+ "DataReadCacheConfiguration"
34431
+ ]);
34432
+ /**
34433
+ * Top-level properties that are create-only per the CFn registry schema
34434
+ * (`createOnlyProperties`). A change on any of these is routed through
34435
+ * DELETE+CREATE by the replacement-detection layer; if a diff somehow
34436
+ * reaches update() with one of them changed, refuse loudly instead of
34437
+ * silently applying a partial update.
34438
+ */
34439
+ const TOP_LEVEL_IMMUTABLE_PROPS = [
34440
+ "FileSystemType",
34441
+ "SubnetIds",
34442
+ "SecurityGroupIds",
34443
+ "KmsKeyId",
34444
+ "BackupId"
34445
+ ];
34446
+ const toNumber = (v) => v === void 0 ? void 0 : Number(v);
34447
+ const toBoolean = (v) => {
34448
+ if (v === void 0) return void 0;
34449
+ if (typeof v === "string") return v === "true";
34450
+ return Boolean(v);
34451
+ };
34452
+ /**
34453
+ * SDK Provider for `AWS::FSx::FileSystem`.
34454
+ *
34455
+ * The type is `ProvisioningType: NON_PROVISIONABLE` in the CFn registry,
34456
+ * so cdkd's Cloud Control fallback cannot handle it (issue #1042).
34457
+ *
34458
+ * v1 scope: the **Lustre** variant (the CDK L2, `aws-fsx.LustreFileSystem`).
34459
+ * The `WindowsConfiguration` / `OntapConfiguration` / `OpenZFSConfiguration`
34460
+ * sub-trees are declared `unhandledByDesign`, so templates using them are
34461
+ * rejected by the property-coverage pre-flight instead of silently dropping
34462
+ * the whole variant config (each non-Lustre `FileSystemType` REQUIRES its
34463
+ * variant block, so no non-Lustre template can slip past the pre-flight).
34464
+ *
34465
+ * Lifecycle handling — every mutation is async on AWS:
34466
+ * - `create` → `CreateFileSystem` (or `CreateFileSystemFromBackup` when
34467
+ * `BackupId` is set) + poll `DescribeFileSystems` until `AVAILABLE`.
34468
+ * - `update` → `UpdateFileSystem` for the mutable surface (StorageCapacity,
34469
+ * Lustre mutable sub-props, StorageType, FileSystemTypeVersion,
34470
+ * NetworkType) + `TagResource`/`UntagResource` for `Tags`; polls back to
34471
+ * `AVAILABLE`.
34472
+ * - `delete` → `DeleteFileSystem` + poll until the file system is GONE
34473
+ * (`FileSystemNotFound` / dropped from the Describe response). A timeout
34474
+ * here is a hard error — a lingering FSx file system bills per hour.
34475
+ *
34476
+ * `getMinResourceTimeoutMs()` lifts the deploy engine's per-resource
34477
+ * deadline to the polling ceiling (mirrors `CustomResourceProvider`), so
34478
+ * slow FSx creates don't require a manual `--resource-timeout`.
34479
+ */
34480
+ var FSxFileSystemProvider = class {
34481
+ /**
34482
+ * Cloud Control has NO handlers for this type (`ProvisioningType:
34483
+ * NON_PROVISIONABLE` in the CFn registry), so the deploy engine's #614
34484
+ * silent-drop auto-route MUST NOT send a Windows/ONTAP/OpenZFS template
34485
+ * to CC — it would fail at provisioning time with an opaque
34486
+ * UnsupportedActionException. With this opt-out the ProviderRegistry
34487
+ * rejects such templates pre-flight with a clear error instead.
34488
+ * (The runtime Tier 3 set cannot express this: it excludes SDK-covered
34489
+ * types by design, so `isNonProvisionable()` is false for this type.)
34490
+ */
34491
+ disableCcApiFallback = true;
34492
+ client;
34493
+ providerRegion = process.env["AWS_REGION"];
34494
+ logger = getLogger().child("FSxFileSystemProvider");
34495
+ pollIntervalMs;
34496
+ maxWaitMs;
34497
+ constructor(options) {
34498
+ this.pollIntervalMs = options?.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
34499
+ this.maxWaitMs = options?.maxWaitMs ?? DEFAULT_MAX_WAIT_MS;
34500
+ }
34501
+ handledProperties = new Map([["AWS::FSx::FileSystem", new Set([
34502
+ "BackupId",
34503
+ "FileSystemType",
34504
+ "FileSystemTypeVersion",
34505
+ "KmsKeyId",
34506
+ "LustreConfiguration",
34507
+ "NetworkType",
34508
+ "SecurityGroupIds",
34509
+ "StorageCapacity",
34510
+ "StorageType",
34511
+ "SubnetIds",
34512
+ "Tags"
34513
+ ])]]);
34514
+ unhandledByDesign = new Map([["AWS::FSx::FileSystem", new Map([
34515
+ ["WindowsConfiguration", "FSx for Windows File Server variant — requires Active Directory wiring and Windows-specific update/delete semantics (final backups, throughput tiers) that v1 does not implement; only the Lustre variant (the CDK L2) is supported. Follow-up to issue #1042."],
34516
+ ["OntapConfiguration", "FSx for NetApp ONTAP variant — the file system is only a container for SVMs/volumes (separate AWS::FSx::StorageVirtualMachine / AWS::FSx::Volume types, both still unsupported), so shipping it alone would be misleading; only the Lustre variant is supported in v1. Follow-up to issue #1042."],
34517
+ ["OpenZFSConfiguration", "FSx for OpenZFS variant — root-volume semantics (RootVolumeId, child AWS::FSx::Volume trees) are not implemented in v1; only the Lustre variant is supported. Follow-up to issue #1042."]
34518
+ ])]]);
34519
+ getClient() {
34520
+ if (!this.client) this.client = new FSxClient(this.providerRegion ? { region: this.providerRegion } : {});
34521
+ return this.client;
34522
+ }
34523
+ /**
34524
+ * Self-reported minimum per-resource timeout: the deploy engine resolves
34525
+ * `max(getMinResourceTimeoutMs(), globalCliDefault)` so FSx's slow
34526
+ * create/delete polling fits inside the resource deadline without the
34527
+ * user passing `--resource-timeout`.
34528
+ */
34529
+ getMinResourceTimeoutMs() {
34530
+ return this.maxWaitMs;
34531
+ }
34532
+ async create(logicalId, resourceType, properties) {
34533
+ if (resourceType !== "AWS::FSx::FileSystem") throw new ProvisioningError(`Unsupported resource type: ${resourceType}`, resourceType, logicalId);
34534
+ const backupId = properties["BackupId"];
34535
+ const fileSystemType = properties["FileSystemType"];
34536
+ if (backupId === void 0 && fileSystemType !== "LUSTRE") throw new ProvisioningError(`AWS::FSx::FileSystem: FileSystemType '${fileSystemType ?? "(unset)"}' is not supported by cdkd yet — only the LUSTRE variant is implemented (issue #1042). Windows / ONTAP / OpenZFS file systems can follow in a later PR.`, resourceType, logicalId);
34537
+ this.logger.debug(`Creating FSx FileSystem ${logicalId}`);
34538
+ const tokenHash = createHash("sha256").update([
34539
+ properties["FileSystemType"],
34540
+ properties["SubnetIds"],
34541
+ properties["SecurityGroupIds"],
34542
+ properties["KmsKeyId"],
34543
+ properties["BackupId"]
34544
+ ].map((v) => JSON.stringify(v ?? null)).join(" ")).digest("hex").slice(0, 12);
34545
+ const clientRequestToken = `cdkd-${logicalId.slice(0, 45)}-${tokenHash}`;
34546
+ const tags = properties["Tags"];
34547
+ const common = {
34548
+ ClientRequestToken: clientRequestToken,
34549
+ SubnetIds: properties["SubnetIds"],
34550
+ SecurityGroupIds: properties["SecurityGroupIds"],
34551
+ KmsKeyId: properties["KmsKeyId"],
34552
+ StorageType: properties["StorageType"],
34553
+ StorageCapacity: toNumber(properties["StorageCapacity"]),
34554
+ FileSystemTypeVersion: properties["FileSystemTypeVersion"],
34555
+ NetworkType: properties["NetworkType"],
34556
+ LustreConfiguration: this.toCreateLustreConfiguration(properties["LustreConfiguration"]),
34557
+ Tags: tags?.map((t) => ({
34558
+ Key: t.Key,
34559
+ Value: t.Value
34560
+ }))
34561
+ };
34562
+ let fileSystemId;
34563
+ try {
34564
+ let created;
34565
+ if (backupId !== void 0) created = (await this.getClient().send(new CreateFileSystemFromBackupCommand({
34566
+ ...common,
34567
+ BackupId: backupId
34568
+ }))).FileSystem;
34569
+ else created = (await this.getClient().send(new CreateFileSystemCommand$1({
34570
+ ...common,
34571
+ FileSystemType: fileSystemType
34572
+ }))).FileSystem;
34573
+ fileSystemId = created?.FileSystemId;
34574
+ if (!fileSystemId) throw new ProvisioningError(`FSx CreateFileSystem for ${logicalId} returned no FileSystemId`, resourceType, logicalId);
34575
+ const fs = await this.waitForFileSystemAvailable(fileSystemId, logicalId, resourceType);
34576
+ this.logger.debug(`Successfully created FSx FileSystem ${logicalId}: ${fileSystemId}`);
34577
+ return {
34578
+ physicalId: fileSystemId,
34579
+ attributes: this.buildAttributes(fs)
34580
+ };
34581
+ } catch (error) {
34582
+ if (fileSystemId !== void 0) try {
34583
+ await this.getClient().send(new DeleteFileSystemCommand$1({ FileSystemId: fileSystemId }));
34584
+ this.logger.warn(`Rolled back partially-created FSx FileSystem ${fileSystemId}`);
34585
+ } catch (cleanupError) {
34586
+ this.logger.warn(`Failed to roll back partially-created FSx FileSystem ${fileSystemId}: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)} — delete it manually to stop billing`);
34587
+ }
34588
+ if (error instanceof ProvisioningError) throw error;
34589
+ const cause = error instanceof Error ? error : void 0;
34590
+ throw new ProvisioningError(`Failed to create FSx FileSystem ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, void 0, cause);
34591
+ }
34592
+ }
34593
+ /**
34594
+ * Map the CFn `LustreConfiguration` block to the SDK create shape. The
34595
+ * field names are identical (both PascalCase); numeric / boolean fields
34596
+ * are coerced defensively because template values can arrive as strings.
34597
+ */
34598
+ toCreateLustreConfiguration(config) {
34599
+ if (!config) return void 0;
34600
+ const metadata = config["MetadataConfiguration"];
34601
+ const readCache = config["DataReadCacheConfiguration"];
34602
+ return {
34603
+ WeeklyMaintenanceStartTime: config["WeeklyMaintenanceStartTime"],
34604
+ ImportPath: config["ImportPath"],
34605
+ ExportPath: config["ExportPath"],
34606
+ ImportedFileChunkSize: toNumber(config["ImportedFileChunkSize"]),
34607
+ DeploymentType: config["DeploymentType"],
34608
+ AutoImportPolicy: config["AutoImportPolicy"],
34609
+ PerUnitStorageThroughput: toNumber(config["PerUnitStorageThroughput"]),
34610
+ DailyAutomaticBackupStartTime: config["DailyAutomaticBackupStartTime"],
34611
+ AutomaticBackupRetentionDays: toNumber(config["AutomaticBackupRetentionDays"]),
34612
+ CopyTagsToBackups: toBoolean(config["CopyTagsToBackups"]),
34613
+ DriveCacheType: config["DriveCacheType"],
34614
+ DataCompressionType: config["DataCompressionType"],
34615
+ EfaEnabled: toBoolean(config["EfaEnabled"]),
34616
+ ThroughputCapacity: toNumber(config["ThroughputCapacity"]),
34617
+ MetadataConfiguration: metadata ? {
34618
+ Mode: metadata["Mode"],
34619
+ Iops: toNumber(metadata["Iops"])
34620
+ } : void 0,
34621
+ DataReadCacheConfiguration: readCache ? {
34622
+ SizingMode: readCache["SizingMode"],
34623
+ SizeGiB: toNumber(readCache["SizeGiB"])
34624
+ } : void 0
34625
+ };
34626
+ }
34627
+ async update(logicalId, physicalId, resourceType, properties, previousProperties) {
34628
+ const changed = (key) => JSON.stringify(properties[key]) !== JSON.stringify(previousProperties[key]);
34629
+ for (const key of TOP_LEVEL_IMMUTABLE_PROPS) {
34630
+ const next = properties[key];
34631
+ const prev = previousProperties[key];
34632
+ if (JSON.stringify(next ?? null) !== JSON.stringify(prev ?? null)) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, `AWS FSx FileSystem ${key} is immutable on AWS — UpdateFileSystem does not accept ${key}; the property is fixed at creation. Re-deploy with cdkd deploy --replace, or destroy + redeploy the stack.`);
34633
+ }
34634
+ const nextLustre = properties["LustreConfiguration"] ?? {};
34635
+ const prevLustre = previousProperties["LustreConfiguration"] ?? {};
34636
+ const lustreKeys = new Set([...Object.keys(nextLustre), ...Object.keys(prevLustre)]);
34637
+ const lustreMutableDiff = {};
34638
+ let lustreHasMutableDiff = false;
34639
+ for (const key of lustreKeys) {
34640
+ const next = nextLustre[key];
34641
+ const prev = prevLustre[key];
34642
+ if (JSON.stringify(next) === JSON.stringify(prev)) continue;
34643
+ if (!LUSTRE_MUTABLE_SUBPROPS.has(key)) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, `AWS FSx FileSystem LustreConfiguration.${key} is immutable on AWS — UpdateFileSystem cannot change it after creation. Re-deploy with cdkd deploy --replace, or destroy + redeploy the stack.`);
34644
+ lustreHasMutableDiff = true;
34645
+ switch (key) {
34646
+ case "WeeklyMaintenanceStartTime":
34647
+ case "DailyAutomaticBackupStartTime":
34648
+ lustreMutableDiff[key] = next;
34649
+ break;
34650
+ case "AutomaticBackupRetentionDays":
34651
+ case "PerUnitStorageThroughput":
34652
+ case "ThroughputCapacity":
34653
+ lustreMutableDiff[key] = toNumber(next);
34654
+ break;
34655
+ case "AutoImportPolicy":
34656
+ case "DataCompressionType":
34657
+ lustreMutableDiff[key] = next;
34658
+ break;
34659
+ case "MetadataConfiguration": {
34660
+ const metadata = next;
34661
+ lustreMutableDiff.MetadataConfiguration = metadata ? {
34662
+ Mode: metadata["Mode"],
34663
+ Iops: toNumber(metadata["Iops"])
34664
+ } : void 0;
34665
+ break;
34666
+ }
34667
+ case "DataReadCacheConfiguration": {
34668
+ const readCache = next;
34669
+ lustreMutableDiff.DataReadCacheConfiguration = readCache ? {
34670
+ SizingMode: readCache["SizingMode"],
34671
+ SizeGiB: toNumber(readCache["SizeGiB"])
34672
+ } : void 0;
34673
+ break;
34674
+ }
34675
+ }
34676
+ }
34677
+ const storageCapacityChanged = changed("StorageCapacity");
34678
+ const storageTypeChanged = changed("StorageType");
34679
+ const typeVersionChanged = changed("FileSystemTypeVersion");
34680
+ const networkTypeChanged = changed("NetworkType");
34681
+ const tagsChanged = changed("Tags");
34682
+ if (!lustreHasMutableDiff && !storageCapacityChanged && !storageTypeChanged && !typeVersionChanged && !networkTypeChanged && !tagsChanged) {
34683
+ this.logger.debug(`No mutable diff for FSx FileSystem ${logicalId}, skipping update`);
34684
+ return {
34685
+ physicalId,
34686
+ wasReplaced: false
34687
+ };
34688
+ }
34689
+ this.logger.debug(`Updating FSx FileSystem ${logicalId}: ${physicalId}`);
34690
+ try {
34691
+ const needsUpdateCall = lustreHasMutableDiff || storageCapacityChanged || storageTypeChanged || typeVersionChanged || networkTypeChanged;
34692
+ let updatedFs;
34693
+ if (needsUpdateCall) {
34694
+ const callTimeMs = Date.now();
34695
+ const respPendingActions = ((await this.getClient().send(new UpdateFileSystemCommand$1({
34696
+ FileSystemId: physicalId,
34697
+ ...storageCapacityChanged && { StorageCapacity: toNumber(properties["StorageCapacity"]) },
34698
+ ...storageTypeChanged && { StorageType: properties["StorageType"] },
34699
+ ...typeVersionChanged && { FileSystemTypeVersion: properties["FileSystemTypeVersion"] },
34700
+ ...networkTypeChanged && { NetworkType: properties["NetworkType"] },
34701
+ ...lustreHasMutableDiff && { LustreConfiguration: lustreMutableDiff }
34702
+ }))).FileSystem?.AdministrativeActions ?? []).filter((a) => a.AdministrativeActionType === "FILE_SYSTEM_UPDATE" && (a.Status === "PENDING" || a.Status === "IN_PROGRESS"));
34703
+ const requestTimes = respPendingActions.map((a) => a.RequestTime?.getTime()).filter((t) => t !== void 0);
34704
+ const actionThresholdMs = requestTimes.length > 0 ? Math.min(...requestTimes) : callTimeMs - 6e4;
34705
+ updatedFs = await this.waitForUpdateActionComplete(physicalId, logicalId, resourceType, actionThresholdMs, respPendingActions.length > 0);
34706
+ }
34707
+ if (tagsChanged) await this.applyTagDiff(physicalId, properties["Tags"], previousProperties["Tags"]);
34708
+ if (!updatedFs) try {
34709
+ updatedFs = (await this.getClient().send(new DescribeFileSystemsCommand$1({ FileSystemIds: [physicalId] }))).FileSystems?.[0];
34710
+ } catch (describeError) {
34711
+ this.logger.debug(`Post-update attribute refresh for ${physicalId} failed (returning without attributes): ${describeError instanceof Error ? describeError.message : String(describeError)}`);
34712
+ }
34713
+ this.logger.debug(`Successfully updated FSx FileSystem ${logicalId}`);
34714
+ return {
34715
+ physicalId,
34716
+ wasReplaced: false,
34717
+ ...updatedFs && { attributes: this.buildAttributes(updatedFs) }
34718
+ };
34719
+ } catch (error) {
34720
+ if (error instanceof ProvisioningError) throw error;
34721
+ const cause = error instanceof Error ? error : void 0;
34722
+ throw new ProvisioningError(`Failed to update FSx FileSystem ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, physicalId, cause);
34723
+ }
34724
+ }
34725
+ /**
34726
+ * Apply a `Tags` diff via `TagResource` / `UntagResource` (the FSx
34727
+ * `UpdateFileSystem` API does not accept tags). Needs the ARN — resolve
34728
+ * it from `DescribeFileSystems`.
34729
+ */
34730
+ async applyTagDiff(physicalId, nextTags, prevTags) {
34731
+ const arn = (await this.getClient().send(new DescribeFileSystemsCommand$1({ FileSystemIds: [physicalId] }))).FileSystems?.[0]?.ResourceARN;
34732
+ if (!arn) throw new Error(`could not resolve ResourceARN for FSx FileSystem ${physicalId}`);
34733
+ const next = new Map((nextTags ?? []).map((t) => [t.Key, t.Value]));
34734
+ const prev = new Map((prevTags ?? []).map((t) => [t.Key, t.Value]));
34735
+ const toSet = [];
34736
+ for (const [key, value] of next) {
34737
+ if (key === void 0) continue;
34738
+ if (prev.get(key) !== value) toSet.push({
34739
+ Key: key,
34740
+ Value: value
34741
+ });
34742
+ }
34743
+ const toRemove = [];
34744
+ for (const key of prev.keys()) if (key !== void 0 && !next.has(key)) toRemove.push(key);
34745
+ if (toSet.length > 0) await this.getClient().send(new TagResourceCommand$18({
34746
+ ResourceARN: arn,
34747
+ Tags: toSet
34748
+ }));
34749
+ if (toRemove.length > 0) await this.getClient().send(new UntagResourceCommand$18({
34750
+ ResourceARN: arn,
34751
+ TagKeys: toRemove
34752
+ }));
34753
+ }
34754
+ async delete(logicalId, physicalId, resourceType, _properties, context) {
34755
+ this.logger.debug(`Deleting FSx FileSystem ${logicalId}: ${physicalId}`);
34756
+ try {
34757
+ await this.getClient().send(new DeleteFileSystemCommand$1({ FileSystemId: physicalId }));
34758
+ } catch (error) {
34759
+ if (error instanceof FileSystemNotFound$1) {
34760
+ assertRegionMatch(await this.getClient().config.region(), context?.expectedRegion, resourceType, logicalId, physicalId);
34761
+ this.logger.debug(`FSx FileSystem ${physicalId} does not exist, skipping deletion`);
34762
+ return;
34763
+ }
34764
+ const cause = error instanceof Error ? error : void 0;
34765
+ throw new ProvisioningError(`Failed to delete FSx FileSystem ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, physicalId, cause);
34766
+ }
34767
+ await this.waitForFileSystemDeleted(physicalId, logicalId, resourceType);
34768
+ this.logger.debug(`Successfully deleted FSx FileSystem ${logicalId}`);
34769
+ }
34770
+ /**
34771
+ * Issue the polling `DescribeFileSystems` with bounded tolerance for
34772
+ * TRANSIENT errors (throttling / 5xx / connection resets): up to
34773
+ * `maxConsecutiveTransient` consecutive failures are absorbed (with the
34774
+ * normal poll delay) before the error propagates. A 5-10 minute create
34775
+ * poll at 15s intervals would otherwise turn a single throttle into a
34776
+ * spurious failure + best-effort rollback cycle. Non-transient errors
34777
+ * (incl. FileSystemNotFound) propagate immediately.
34778
+ */
34779
+ async describeForPoll(fileSystemId, transientState, maxConsecutiveTransient = 5) {
34780
+ try {
34781
+ const response = await this.getClient().send(new DescribeFileSystemsCommand$1({ FileSystemIds: [fileSystemId] }));
34782
+ transientState.count = 0;
34783
+ return response.FileSystems?.[0];
34784
+ } catch (error) {
34785
+ const name = error instanceof Error ? error.name : "";
34786
+ const msg = error instanceof Error ? error.message : String(error);
34787
+ if ((name === "ThrottlingException" || name === "ServiceLimitExceeded" || name === "InternalServerError" || name === "TimeoutError" || /rate exceeded|too many requests|timed? ?out|ECONNRESET|EPIPE|socket hang up/i.test(msg)) && transientState.count < maxConsecutiveTransient) {
34788
+ transientState.count += 1;
34789
+ this.logger.debug(`Transient DescribeFileSystems error while polling ${fileSystemId} (${transientState.count}/${maxConsecutiveTransient}): ${msg} — retrying`);
34790
+ return;
34791
+ }
34792
+ throw error;
34793
+ }
34794
+ }
34795
+ async waitForFileSystemAvailable(fileSystemId, logicalId, resourceType) {
34796
+ const startTime = Date.now();
34797
+ const transientState = { count: 0 };
34798
+ while (Date.now() - startTime < this.maxWaitMs) {
34799
+ const fs = await this.describeForPoll(fileSystemId, transientState);
34800
+ const lifecycle = fs?.Lifecycle;
34801
+ if (fs && lifecycle === "AVAILABLE") return fs;
34802
+ if (lifecycle === "FAILED" || lifecycle === "MISCONFIGURED") throw new ProvisioningError(`FSx FileSystem ${fileSystemId} entered lifecycle state ${lifecycle}: ${fs?.FailureDetails?.Message ?? "no failure details reported"}`, resourceType, logicalId, fileSystemId);
34803
+ this.logger.debug(`FSx FileSystem ${fileSystemId} state: ${lifecycle ?? "unknown"}, waiting...`);
34804
+ await new Promise((resolve) => setTimeout(resolve, this.pollIntervalMs));
34805
+ }
34806
+ throw new ProvisioningError(`Timed out waiting for FSx FileSystem ${fileSystemId} to become AVAILABLE (${Math.round(this.maxWaitMs / 6e4)} min)`, resourceType, logicalId, fileSystemId);
34807
+ }
34808
+ /**
34809
+ * Wait until the async `FILE_SYSTEM_UPDATE` administrative action kicked
34810
+ * off by `UpdateFileSystem` completes (and the Lifecycle is AVAILABLE).
34811
+ * `STORAGE_OPTIMIZATION` actions are intentionally ignored — they can run
34812
+ * for hours after a capacity grow, and CloudFormation does not wait for
34813
+ * them either (`UPDATED_OPTIMIZING` counts as done). A FAILED update
34814
+ * action is a hard error carrying the action's failure message.
34815
+ *
34816
+ * `actionThresholdMs` scopes the wait to THIS update's actions: FSx keeps
34817
+ * terminal (COMPLETED / FAILED) actions in the history, so only actions
34818
+ * whose `RequestTime` is at or after the threshold are considered — a
34819
+ * PAST failed update must not fail this one's retry. An action without a
34820
+ * `RequestTime` is conservatively tracked.
34821
+ *
34822
+ * `requireActionObservation` guards the eventual-consistency race: when
34823
+ * the UpdateFileSystem response confirmed a newly-created action, the
34824
+ * wait refuses to return until an in-threshold action has been observed
34825
+ * in at least one Describe response — a lagging read replica could
34826
+ * otherwise briefly show none and cause a premature return with the
34827
+ * pre-update config. Terminal actions stay in the history, so the
34828
+ * observation is guaranteed to eventually succeed (bounded by
34829
+ * `maxWaitMs`).
34830
+ */
34831
+ async waitForUpdateActionComplete(fileSystemId, logicalId, resourceType, actionThresholdMs, requireActionObservation) {
34832
+ const startTime = Date.now();
34833
+ const transientState = { count: 0 };
34834
+ let seenTrackedAction = false;
34835
+ while (Date.now() - startTime < this.maxWaitMs) {
34836
+ const fs = await this.describeForPoll(fileSystemId, transientState);
34837
+ if (fs) {
34838
+ const updateActions = (fs.AdministrativeActions ?? []).filter((a) => a.AdministrativeActionType === "FILE_SYSTEM_UPDATE" && (a.RequestTime === void 0 || a.RequestTime.getTime() >= actionThresholdMs));
34839
+ if (updateActions.length > 0) seenTrackedAction = true;
34840
+ const failed = updateActions.find((a) => a.Status === "FAILED");
34841
+ if (failed) throw new ProvisioningError(`FSx FileSystem ${fileSystemId} update failed (FILE_SYSTEM_UPDATE administrative action): ${failed.FailureDetails?.Message ?? "no failure details reported"}`, resourceType, logicalId, fileSystemId);
34842
+ if (!updateActions.some((a) => a.Status === "PENDING" || a.Status === "IN_PROGRESS") && (!requireActionObservation || seenTrackedAction) && fs.Lifecycle === "AVAILABLE") return fs;
34843
+ this.logger.debug(`FSx FileSystem ${fileSystemId} update in progress (lifecycle: ${fs.Lifecycle ?? "unknown"}), waiting...`);
34844
+ }
34845
+ await new Promise((resolve) => setTimeout(resolve, this.pollIntervalMs));
34846
+ }
34847
+ throw new ProvisioningError(`Timed out waiting for FSx FileSystem ${fileSystemId} update to complete (${Math.round(this.maxWaitMs / 6e4)} min)`, resourceType, logicalId, fileSystemId);
34848
+ }
34849
+ async waitForFileSystemDeleted(fileSystemId, logicalId, resourceType) {
34850
+ const startTime = Date.now();
34851
+ const transientState = { count: 0 };
34852
+ while (Date.now() - startTime < this.maxWaitMs) {
34853
+ let fs;
34854
+ let sawResponse = true;
34855
+ try {
34856
+ fs = await this.describeForPoll(fileSystemId, transientState);
34857
+ if (fs === void 0 && transientState.count > 0) sawResponse = false;
34858
+ } catch (error) {
34859
+ if (error instanceof FileSystemNotFound$1) return;
34860
+ const cause = error instanceof Error ? error : void 0;
34861
+ throw new ProvisioningError(`Failed to poll FSx FileSystem ${fileSystemId} deletion: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, fileSystemId, cause);
34862
+ }
34863
+ if (!fs && sawResponse) return;
34864
+ if (!fs) {
34865
+ await new Promise((resolve) => setTimeout(resolve, this.pollIntervalMs));
34866
+ continue;
34867
+ }
34868
+ if (fs.Lifecycle === "FAILED") throw new ProvisioningError(`FSx FileSystem ${fileSystemId} entered lifecycle state FAILED during deletion: ${fs.FailureDetails?.Message ?? "no failure details reported"}`, resourceType, logicalId, fileSystemId);
34869
+ this.logger.debug(`FSx FileSystem ${fileSystemId} state: ${fs.Lifecycle ?? "unknown"}, waiting for deletion...`);
34870
+ await new Promise((resolve) => setTimeout(resolve, this.pollIntervalMs));
34871
+ }
34872
+ throw new ProvisioningError(`Timed out waiting for FSx FileSystem ${fileSystemId} deletion (${Math.round(this.maxWaitMs / 6e4)} min) — verify and delete it manually to stop billing`, resourceType, logicalId, fileSystemId);
34873
+ }
34874
+ buildAttributes(fs) {
34875
+ const attributes = {};
34876
+ if (fs.ResourceARN !== void 0) attributes["ResourceARN"] = fs.ResourceARN;
34877
+ if (fs.DNSName !== void 0) attributes["DNSName"] = fs.DNSName;
34878
+ if (fs.LustreConfiguration?.MountName !== void 0) attributes["LustreMountName"] = fs.LustreConfiguration.MountName;
34879
+ if (fs.FileSystemId !== void 0) attributes["FileSystemId"] = fs.FileSystemId;
34880
+ return attributes;
34881
+ }
34882
+ async getAttribute(physicalId, _resourceType, attributeName) {
34883
+ if (attributeName === "Id" || attributeName === "FileSystemId") return physicalId;
34884
+ const fs = (await this.getClient().send(new DescribeFileSystemsCommand$1({ FileSystemIds: [physicalId] }))).FileSystems?.[0];
34885
+ if (!fs) return void 0;
34886
+ switch (attributeName) {
34887
+ case "ResourceARN": return fs.ResourceARN;
34888
+ case "DNSName": return fs.DNSName;
34889
+ case "LustreMountName": return fs.LustreConfiguration?.MountName;
34890
+ case "RootVolumeId": return fs.OpenZFSConfiguration?.RootVolumeId;
34891
+ default: return;
34892
+ }
34893
+ }
34894
+ /**
34895
+ * State property paths this provider cannot read back from AWS:
34896
+ * - `SecurityGroupIds` — `DescribeFileSystems` returns network
34897
+ * interface ids, never the original security group list.
34898
+ * - `BackupId` — creation-source input, not surfaced on the deployed
34899
+ * file system.
34900
+ */
34901
+ getDriftUnknownPaths(resourceType) {
34902
+ if (resourceType !== "AWS::FSx::FileSystem") return [];
34903
+ return ["SecurityGroupIds", "BackupId"];
34904
+ }
34905
+ /**
34906
+ * Read the AWS-current file system configuration in CFn-property shape
34907
+ * via `DescribeFileSystems`. Lustre data-repository fields (`ImportPath`
34908
+ * / `ExportPath` / `AutoImportPolicy` / `ImportedFileChunkSize`) are
34909
+ * mapped back from the nested `DataRepositoryConfiguration` the API
34910
+ * returns. Returns `undefined` when the file system is gone.
34911
+ */
34912
+ async readCurrentState(physicalId, _logicalId, resourceType) {
34913
+ if (resourceType !== "AWS::FSx::FileSystem") return void 0;
34914
+ let fs;
34915
+ try {
34916
+ fs = (await this.getClient().send(new DescribeFileSystemsCommand$1({ FileSystemIds: [physicalId] }))).FileSystems?.[0];
34917
+ } catch (err) {
34918
+ if (err instanceof FileSystemNotFound$1) return void 0;
34919
+ throw err;
34920
+ }
34921
+ if (!fs) return void 0;
34922
+ const result = {};
34923
+ if (fs.FileSystemType !== void 0) result["FileSystemType"] = fs.FileSystemType;
34924
+ if (fs.StorageCapacity !== void 0) result["StorageCapacity"] = fs.StorageCapacity;
34925
+ if (fs.StorageType !== void 0) result["StorageType"] = fs.StorageType;
34926
+ if (fs.SubnetIds !== void 0) result["SubnetIds"] = [...fs.SubnetIds];
34927
+ if (fs.KmsKeyId !== void 0) result["KmsKeyId"] = fs.KmsKeyId;
34928
+ if (fs.FileSystemTypeVersion !== void 0) result["FileSystemTypeVersion"] = fs.FileSystemTypeVersion;
34929
+ if (fs.NetworkType !== void 0) result["NetworkType"] = fs.NetworkType;
34930
+ const lustre = fs.LustreConfiguration;
34931
+ if (lustre) {
34932
+ const config = {};
34933
+ if (lustre.WeeklyMaintenanceStartTime !== void 0) config["WeeklyMaintenanceStartTime"] = lustre.WeeklyMaintenanceStartTime;
34934
+ if (lustre.DeploymentType !== void 0) config["DeploymentType"] = lustre.DeploymentType;
34935
+ if (lustre.PerUnitStorageThroughput !== void 0) config["PerUnitStorageThroughput"] = lustre.PerUnitStorageThroughput;
34936
+ if (lustre.DailyAutomaticBackupStartTime !== void 0) config["DailyAutomaticBackupStartTime"] = lustre.DailyAutomaticBackupStartTime;
34937
+ if (lustre.AutomaticBackupRetentionDays !== void 0) config["AutomaticBackupRetentionDays"] = lustre.AutomaticBackupRetentionDays;
34938
+ if (lustre.CopyTagsToBackups !== void 0) config["CopyTagsToBackups"] = lustre.CopyTagsToBackups;
34939
+ if (lustre.DriveCacheType !== void 0) config["DriveCacheType"] = lustre.DriveCacheType;
34940
+ if (lustre.DataCompressionType !== void 0) config["DataCompressionType"] = lustre.DataCompressionType;
34941
+ if (lustre.EfaEnabled !== void 0) config["EfaEnabled"] = lustre.EfaEnabled;
34942
+ if (lustre.ThroughputCapacity !== void 0) config["ThroughputCapacity"] = lustre.ThroughputCapacity;
34943
+ if (lustre.MetadataConfiguration) {
34944
+ const metadata = {};
34945
+ if (lustre.MetadataConfiguration.Mode !== void 0) metadata["Mode"] = lustre.MetadataConfiguration.Mode;
34946
+ if (lustre.MetadataConfiguration.Iops !== void 0) metadata["Iops"] = lustre.MetadataConfiguration.Iops;
34947
+ if (Object.keys(metadata).length > 0) config["MetadataConfiguration"] = metadata;
34948
+ }
34949
+ if (lustre.DataReadCacheConfiguration) {
34950
+ const readCache = {};
34951
+ if (lustre.DataReadCacheConfiguration.SizingMode !== void 0) readCache["SizingMode"] = lustre.DataReadCacheConfiguration.SizingMode;
34952
+ if (lustre.DataReadCacheConfiguration.SizeGiB !== void 0) readCache["SizeGiB"] = lustre.DataReadCacheConfiguration.SizeGiB;
34953
+ if (Object.keys(readCache).length > 0) config["DataReadCacheConfiguration"] = readCache;
34954
+ }
34955
+ const dataRepo = lustre.DataRepositoryConfiguration;
34956
+ if (dataRepo) {
34957
+ if (dataRepo.ImportPath !== void 0) config["ImportPath"] = dataRepo.ImportPath;
34958
+ if (dataRepo.ExportPath !== void 0) config["ExportPath"] = dataRepo.ExportPath;
34959
+ if (dataRepo.AutoImportPolicy !== void 0) config["AutoImportPolicy"] = dataRepo.AutoImportPolicy;
34960
+ if (dataRepo.ImportedFileChunkSize !== void 0) config["ImportedFileChunkSize"] = dataRepo.ImportedFileChunkSize;
34961
+ }
34962
+ if (Object.keys(config).length > 0) result["LustreConfiguration"] = config;
34963
+ }
34964
+ result["Tags"] = normalizeAwsTagsToCfn(fs.Tags);
34965
+ return result;
34966
+ }
34967
+ /**
34968
+ * Adopt an existing FSx file system into cdkd state. Explicit physical
34969
+ * id is verified via `DescribeFileSystems`; otherwise a paginated walk
34970
+ * matches the `aws:cdk:path` tag (`Tags` ride inline on each item).
34971
+ */
34972
+ async import(input) {
34973
+ if (input.resourceType !== "AWS::FSx::FileSystem") return null;
34974
+ if (input.knownPhysicalId) try {
34975
+ const fs = (await this.getClient().send(new DescribeFileSystemsCommand$1({ FileSystemIds: [input.knownPhysicalId] }))).FileSystems?.[0];
34976
+ return fs?.FileSystemId ? {
34977
+ physicalId: fs.FileSystemId,
34978
+ attributes: this.buildAttributes(fs)
34979
+ } : null;
34980
+ } catch (err) {
34981
+ if (err instanceof FileSystemNotFound$1) return null;
34982
+ throw err;
34983
+ }
34984
+ if (!input.cdkPath) return null;
34985
+ let nextToken;
34986
+ do {
34987
+ const list = await this.getClient().send(new DescribeFileSystemsCommand$1({ ...nextToken && { NextToken: nextToken } }));
34988
+ for (const fs of list.FileSystems ?? []) {
34989
+ if (!fs.FileSystemId) continue;
34990
+ if (matchesCdkPath(fs.Tags, input.cdkPath)) return {
34991
+ physicalId: fs.FileSystemId,
34992
+ attributes: this.buildAttributes(fs)
34993
+ };
34994
+ }
34995
+ nextToken = list.NextToken;
34996
+ } while (nextToken);
34997
+ return null;
34998
+ }
34999
+ };
35000
+
34405
35001
  //#endregion
34406
35002
  //#region src/provisioning/providers/firehose-provider.ts
34407
35003
  /**
@@ -36623,11 +37219,11 @@ var CodeCommitRepositoryProvider = class {
36623
37219
  const repoArn = metadata?.Arn;
36624
37220
  if (repoArn) {
36625
37221
  const removedKeys = Object.keys(oldTagMap).filter((k) => !(k in newTagMap));
36626
- if (removedKeys.length > 0) await this.getClient().send(new UntagResourceCommand$18({
37222
+ if (removedKeys.length > 0) await this.getClient().send(new UntagResourceCommand$19({
36627
37223
  resourceArn: repoArn,
36628
37224
  tagKeys: removedKeys
36629
37225
  }));
36630
- if (Object.keys(newTagMap).length > 0) await this.getClient().send(new TagResourceCommand$18({
37226
+ if (Object.keys(newTagMap).length > 0) await this.getClient().send(new TagResourceCommand$19({
36631
37227
  resourceArn: repoArn,
36632
37228
  tags: newTagMap
36633
37229
  }));
@@ -36884,7 +37480,7 @@ var DLMLifecyclePolicyProvider = class {
36884
37480
  if (tagsChanged && arn) {
36885
37481
  const removedKeys = Object.keys(oldTags).filter((k) => !(k in newTags));
36886
37482
  if (removedKeys.length > 0) {
36887
- await this.getClient().send(new UntagResourceCommand$19({
37483
+ await this.getClient().send(new UntagResourceCommand$20({
36888
37484
  ResourceArn: arn,
36889
37485
  TagKeys: removedKeys
36890
37486
  }));
@@ -36893,7 +37489,7 @@ var DLMLifecyclePolicyProvider = class {
36893
37489
  const tagsToAdd = {};
36894
37490
  for (const [k, v] of Object.entries(newTags)) if (oldTags[k] !== v) tagsToAdd[k] = v;
36895
37491
  if (Object.keys(tagsToAdd).length > 0) {
36896
- await this.getClient().send(new TagResourceCommand$19({
37492
+ await this.getClient().send(new TagResourceCommand$20({
36897
37493
  ResourceArn: arn,
36898
37494
  Tags: tagsToAdd
36899
37495
  }));
@@ -37096,11 +37692,11 @@ var S3VectorsProvider = class {
37096
37692
  }
37097
37693
  if (!resourceArn) throw new ProvisioningError(`Could not resolve ARN for S3 VectorBucket ${logicalId} (${physicalId}); cannot apply tag update.`, resourceType, logicalId, physicalId);
37098
37694
  try {
37099
- if (Object.keys(toSet).length > 0) await this.getClient().send(new TagResourceCommand$20({
37695
+ if (Object.keys(toSet).length > 0) await this.getClient().send(new TagResourceCommand$21({
37100
37696
  resourceArn,
37101
37697
  tags: toSet
37102
37698
  }));
37103
- if (toRemove.length > 0) await this.getClient().send(new UntagResourceCommand$20({
37699
+ if (toRemove.length > 0) await this.getClient().send(new UntagResourceCommand$21({
37104
37700
  resourceArn,
37105
37701
  tagKeys: toRemove
37106
37702
  }));
@@ -38091,7 +38687,7 @@ var S3TablesProvider = class {
38091
38687
  const resourceArn = await this.lookupTableArn(tableBucketARN, namespace, name);
38092
38688
  if (!resourceArn) throw new ProvisioningError(`applyTableTagsDiff: GetTable returned no tableARN for ${physicalId} — table is gone or state is out-of-sync. Refusing to silently drop the tag update (run 'cdkd state orphan ${logicalId}' to clean up if the table was deleted out-of-band).`, resourceType, logicalId, physicalId);
38093
38689
  if (removedKeys.length > 0) try {
38094
- await this.getClient().send(new UntagResourceCommand$21({
38690
+ await this.getClient().send(new UntagResourceCommand$22({
38095
38691
  resourceArn,
38096
38692
  tagKeys: removedKeys
38097
38693
  }));
@@ -38100,7 +38696,7 @@ var S3TablesProvider = class {
38100
38696
  throw new ProvisioningError(`applyTableTagsDiff: UntagResource failed for ${resourceArn} (keys: ${removedKeys.join(", ")}): ${err instanceof Error ? err.message : String(err)}. State has NOT been updated so the next deploy will retry the tag-diff.`, resourceType, logicalId, physicalId, cause);
38101
38697
  }
38102
38698
  if (Object.keys(upserts).length > 0) try {
38103
- await this.getClient().send(new TagResourceCommand$21({
38699
+ await this.getClient().send(new TagResourceCommand$22({
38104
38700
  resourceArn,
38105
38701
  tags: upserts
38106
38702
  }));
@@ -38132,7 +38728,7 @@ var S3TablesProvider = class {
38132
38728
  if (removedKeys.length === 0 && Object.keys(upserts).length === 0) return;
38133
38729
  const resourceArn = physicalId;
38134
38730
  if (removedKeys.length > 0) try {
38135
- await this.getClient().send(new UntagResourceCommand$21({
38731
+ await this.getClient().send(new UntagResourceCommand$22({
38136
38732
  resourceArn,
38137
38733
  tagKeys: removedKeys
38138
38734
  }));
@@ -38141,7 +38737,7 @@ var S3TablesProvider = class {
38141
38737
  throw new ProvisioningError(`applyTableBucketTagsDiff: UntagResource failed for ${resourceArn} (keys: ${removedKeys.join(", ")}): ${err instanceof Error ? err.message : String(err)}. State has NOT been updated so the next deploy will retry the tag-diff.`, resourceType, logicalId, physicalId, cause);
38142
38738
  }
38143
38739
  if (Object.keys(upserts).length > 0) try {
38144
- await this.getClient().send(new TagResourceCommand$21({
38740
+ await this.getClient().send(new TagResourceCommand$22({
38145
38741
  resourceArn,
38146
38742
  tags: upserts
38147
38743
  }));
@@ -39790,6 +40386,7 @@ function registerAllProviders(registry) {
39790
40386
  registry.register("AWS::EFS::FileSystem", efsProvider);
39791
40387
  registry.register("AWS::EFS::MountTarget", efsProvider);
39792
40388
  registry.register("AWS::EFS::AccessPoint", efsProvider);
40389
+ registry.register("AWS::FSx::FileSystem", new FSxFileSystemProvider());
39793
40390
  registry.register("AWS::KinesisFirehose::DeliveryStream", new FirehoseProvider());
39794
40391
  registry.register("AWS::CloudTrail::Trail", new CloudTrailProvider());
39795
40392
  registry.register("AWS::CodeBuild::Project", new CodeBuildProvider());
@@ -59068,7 +59665,7 @@ function reorderArgs(argv) {
59068
59665
  async function main() {
59069
59666
  installPipeCloseHandler();
59070
59667
  const program = new Command();
59071
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.243.0");
59668
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.244.0");
59072
59669
  program.addCommand(createBootstrapCommand());
59073
59670
  program.addCommand(createSynthCommand());
59074
59671
  program.addCommand(createListCommand());