@go-to-k/cdkd 0.310.0 → 0.312.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/README.md +2 -2
- package/dist/{asg-provider-I1bFHVsO.js → asg-provider-CVLTQtQr.js} +5 -3
- package/dist/asg-provider-CVLTQtQr.js.map +1 -0
- package/dist/cli.js +2 -2
- package/dist/{iam-policy-targets-D94wh05t.js → created-resource-sink-BT2Dfnpt.js} +51 -2
- package/dist/created-resource-sink-BT2Dfnpt.js.map +1 -0
- package/dist/{db-instance-modify-retry-BUG7NMWS.js → db-instance-modify-retry-D7wXWxVo.js} +2 -2
- package/dist/{db-instance-modify-retry-BUG7NMWS.js.map → db-instance-modify-retry-D7wXWxVo.js.map} +1 -1
- package/dist/{deploy-engine-DZO2SOQJ.js → deploy-engine-CVNzK__j.js} +914 -185
- package/dist/deploy-engine-CVNzK__j.js.map +1 -0
- package/dist/{iam-role-provider-BWw7I-SZ.js → iam-role-provider-DM7bN9m1.js} +5 -3
- package/dist/iam-role-provider-DM7bN9m1.js.map +1 -0
- package/dist/index.d.ts +9 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/{neptune-provider-8kjFmR1l.js → neptune-provider-qdoLunCh.js} +55 -6
- package/dist/neptune-provider-qdoLunCh.js.map +1 -0
- package/dist/{program-CS420Kx9.js → program-Nk_95KKk.js} +37 -19
- package/dist/program-Nk_95KKk.js.map +1 -0
- package/dist/{provider-classes-KsrvwO_r.js → provider-classes-Dz0pYmlJ.js} +2099 -217
- package/dist/provider-classes-Dz0pYmlJ.js.map +1 -0
- package/dist/{rds-provider-BqwTQeS-.js → rds-provider-CXSZq1c8.js} +28 -14
- package/dist/rds-provider-CXSZq1c8.js.map +1 -0
- package/dist/{version-QOtLxcEo.js → version-BqCEt5Wu.js} +2 -2
- package/dist/{version-QOtLxcEo.js.map → version-BqCEt5Wu.js.map} +1 -1
- package/package.json +2 -2
- package/dist/asg-provider-I1bFHVsO.js.map +0 -1
- package/dist/deploy-engine-DZO2SOQJ.js.map +0 -1
- package/dist/iam-policy-targets-D94wh05t.js.map +0 -1
- package/dist/iam-role-provider-BWw7I-SZ.js.map +0 -1
- package/dist/neptune-provider-8kjFmR1l.js.map +0 -1
- package/dist/program-CS420Kx9.js.map +0 -1
- package/dist/provider-classes-KsrvwO_r.js.map +0 -1
- package/dist/rds-provider-BqwTQeS-.js.map +0 -1
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { r as getAwsClients, s as withApiGatewayPacing } from "./aws-clients-Bu9EMILF.js";
|
|
2
2
|
import { B as SECRET_REF_MAX_CODE_POINTS, C as generateResourceName, D as getCurrentStackInstanceId, J as displayStackName, K as displayIdent, M as recordedGeneratedNameKept, Q as safeMsg, T as generatedNameFor, Y as isPasteableIdent, Z as plainIdentOr, a as safeStringify, i as isAwsAuthoredFailure, k as isBeforeStateRead, n as describeAwsFailure, q as displaySafe, r as describeAwsStatusReason, s as getLogger, t as VERBOSE_POINTER, w as generateResourceNameWithFallback } from "./aws-failure-text-NSBdKPYK.js";
|
|
3
|
-
import { $ as
|
|
3
|
+
import { $ as logGroupProtectionSite, $n as plainOrDescribed, A as withoutServerErrorRetries, Ar as markNonRetryable, At as createMaskedLogSinks, B as quotedRemedyLogicalId, C as RecentIdSet, Ct as compositeIdSeparatorRefusal, D as replayFollowedAmbiguousAttempt, Dr as THROTTLING_ERROR_NAMES, E as isInsideWindow, Et as packCompositeId, F as VALUE_NOT_SHOWN, Ft as withDerivedNameMasks, G as ProtectionFlipRegistry, Gt as markCreatedBeforeFailure, H as remedyLogicalId, Ht as isAuxiliaryFailure, I as isPlainImportJson, J as deleteWithProtectionCompensation, Jn as commandHole, Kt as markSupersedesEarlierCreate, L as isPlainImportValue, Mn as ProvisioningError, Mr as wrapMaskedAwsError, Mt as isSecretDerivedValue, N as markNotGone, Nt as maskDeep, O as replayedSendWindow, Or as isMarkedNonRetryable, Ot as segmentAfterAnchor, P as assertRegionMatch, Pn as ResourceUpdateNotSupportedError, Pt as maskerOrIdentity, Q as isTerminalDeleteFailure, R as isQuotableImportValue, Rt as clearCreatedBeforeFailure, S as AmbiguousCreateLatch, Sr as isExplicitDenyError, St as compositeIdFormatMessage, T as createAttemptKey, Tr as isTransientServerError, Tt as logicalIdShown, U as resolveExplicitPhysicalId, V as refusalTypeShown, Wt as markAuxiliaryFailure, Xn as isInertUnquoted, Yn as hasClauseBreak, Z as isTerminalDbWaitStatus, Zn as pasteableCommand, _n as CdkdError, a as retractCreatedResource, an as injectiveKey, at as userPoolProtectionSite, bt as startInterruptWatch, c as SECRET_DERIVED_READ_LIVE, ct as WITHHELD_AWS_COMMAND, d as readPrincipalLists, dn as ambientClientDefaults, dt as protectedReplacementAdvice, et as observeThenDisableProtection, fn as ambientCredentialConfig, fr as markNameCollision, ft as renderDisableCommand, h as clearOnUpdateRemoval, hn as AccountIdUnavailableError, i as reportCreatedResource, j as RESOURCE_NOT_FOUND, jr as markRedactedCause, jt as createMaskedRetryLogger, k as setBounded, kr as isThrottlingError, kt as stateOrphanRecordRemedy, l as holdsSecretDerivedEntry, lt as isAwsCliLiteral, mn as credentialFingerprint, mr as relayedNameCollision, mt as ElapsedBudgetRegistry, nr as shellQuote, nt as rdsFamilyProtectionSite, on as injectiveKeyPrefix, p as recordedPrincipalsRepair, pn as clientDefaultsFor, pr as markReplayMayCollide, pt as ElapsedBudget, q as deleteAfterProtectionFlipWithFinalSnapshot, rr as withheldTargetClause, st as UNNAMEABLE_ID_CLAUSE, tt as protectionFlipKey, u as onlySecretDerived, un as withPasteableAwsProfile, ut as pasteableAwsCommand, v as removedTemplateKeys, vr as explicitDenyPolicyKind, w as ambiguousAttemptLead, wr as isRetryableTransientError, wt as compositeIdSkipResult, x as AMBIGUOUS_LATCH_TTL_MS, xr as isAmbiguousOutcomeError, xt as canonicalizeRoute53QueryName, y as withRemovalDefaults, yt as isInterruptedWaitError, z as normalizeAwsTagsToCfn } from "./created-resource-sink-BT2Dfnpt.js";
|
|
4
4
|
import { c as ambientRegion } from "./aws-client-defaults-BX9Y_fKp.js";
|
|
5
|
-
import { $
|
|
6
|
-
import { n as collectInlinePolicyNamesManagedBySiblings, r as IamCreateClientCache, t as IAMRoleProvider } from "./iam-role-provider-
|
|
7
|
-
import { a as resolveSecretDerivedPrincipals, i as isResolvableSecretPrincipalList, n as runDestroyForStack, o as canonicalizeIpProtocolValue, r as holdsUnprovenSecretPrincipalToken, s as resolvedResourceTimeoutMs, t as canonicalizeIpv4Cidr } from "./program-
|
|
8
|
-
import { t as modifyDbInstanceWhenAvailable } from "./db-instance-modify-retry-
|
|
9
|
-
import { RDSProvider } from "./rds-provider-
|
|
10
|
-
import { NeptuneProvider } from "./neptune-provider-
|
|
11
|
-
import { ASGProvider } from "./asg-provider-
|
|
5
|
+
import { $ as getPriorAttempts, $s as isWarmThroughputDecrease, A as DYNAMODB_DELETE_MIN_RESOURCE_TIMEOUT_MS, Ad as renderAssemblyPathEscape, Ai as acquireIdempotencyToken, Ao as accountArgs, B as deleteTableWithIndexBusyRetry, Bc as markSameGenerationBag, Bi as refuseMalformedDesiredTags, Bn as isRedactedRecordedValue, Bs as findSilentDropProperties, C as planContributorInsightsOp, Co as passedParameterClassesOf, D as reverseMapTableContributorInsights, E as reverseMapIndexContributorInsights, Ei as earliestDefined, F as resolveDynamoDbDeleteBudgetClock, Fa as s3BucketDomainName, Fi as markDeleteStarted, Fr as getStackRecords, G as isTtlRateLimited, H as relayedIndexBusyDelete, Hc as recordReferenceProvenanceEntry, Hi as tagPlanWarning, Hn as redactedDeleteAddressSkip, Hs as withoutSilentDropProperties, I as resolveDynamoDbDeleteBudgetMs, Ia as s3BucketDualStackDomainName, Ii as DBPROXY_TAGS_WHAT, It as getNestedRevertRun, J as sendTtlWaitingOutRateLimit, K as planTimeToLive, Kc as hasMaskableValues, L as DELETE_INDEX_WAIT_PROCEED_NOTE, La as s3BucketRegionalDomainName, Li as DBPROXY_TAG_OPTIONS, Ln as getCurrentProducerRegions, Lr as replacedDeleteFailureVerdict, Ls as withheldAccountClause, M as beginDeleteWait, N as compensateRemovedDeletionProtection, Na as isSettledInstanceState, Nr as awaitInFlightSibling, O as stripIndexContributorInsights, Od as describeFileReadFailure, Oi as reserveStackCreateToken, P as deleteBudgetKey, Pa as s3BucketArn, Pc as passedNoEchoParametersOf, Pi as isRefusedByName, Q as isTruthyCfnBoolean, Qs as coerceWarmThroughput$1, R as INDEX_SETTLE_POLL_INTERVAL_MS, Ra as s3BucketWebsiteUrl, Ri as planTagDiff, S as indexDeclaresContributorInsights, Sa as reEnableInstanceApiTermination, Sc as sameLambdaFunctionAddress, T as readContributorInsightsSpec, Ta as isUsableAttemptedName, Ts as refuseMalformedResourcesForDestroy, U as waitForIndexesSettled, Ua as outputReferenceProvenanceOf, Uc as snapshotPassProvenance, Ui as definedAttributes, Ut as getCurrentNestedStackContext, V as maskedLogger, Vc as redactForState, Vi as tagMapAsList, Vn as redactedDeleteAddressFields, W as isTtlAlreadyDisabled, Wi as stringifyIfAssigned, Wt as withNestedStackContext, X as S3_AUTO_DELETE_OBJECTS_TAG, Xi as waitForLambdaFunctionActive, Y as ECR_AUTO_DELETE_IMAGES_TAG, Z as hasCdkAutoDeleteTag, Zs as WARM_THROUGHPUT_MEMBERS, _ as streamMemberRefusals, _l as recordAttributeIdCopy, ac as configIntegerRefusal, as as refuseMalformedNestedChildOutputs, b as CONTRIBUTOR_INSIGHTS_KEY, ba as observeThenDisableInstanceApiTermination, bc as canonicalLambdaFunctionName, bl as carriesSecretMask, bo as parseWebACLArn, c as DynamoDBGlobalTableProvider, ca as unchangedBehindSecretReference, cc as replayWarn, cl as dynamicReferenceTokens, d as declaredStreamPolicyMember, dc as requireConfigString, dd as decodeListingKey, dt as listNestedTemplateRows, ea as getCurrentResourceSecrets, ec as toCfnInteger, en as chunks, et as markRefusedBeforeApplying, f as declaredStreamTagsMember, ft as renderNestedTemplateTreeDefect, fu as rewriteTemplateAssetReferences, g as streamDeclaresTags, ga as markWaitAbandoned, gc as blockDeviceMappingsDifferOnlyInDeleteOnTermination, gl as physicalNameCopiesOf, h as streamDeclaresPolicy, ha as isWaitAbandonedError, hc as withRetry, hd as derivePartitionAndUrlSuffix, hl as recoverMaskedOutput, ic as configBooleanRefusal, iu as timePhase, j as DYNAMODB_DELETE_POLL_COST_MS, jd as resolveAssemblyPath, k as DYNAMODB_DELETE_DEADLINE_MARGIN_MS, kd as displayAssemblyPath, l as STREAM_POLICY_KEY, lc as requireConfigArray, lo as getAccountInfo, lt as findNestedTemplateTreeDefect, m as reverseMapStreamPolicy, ma as withIndeterminateGuard, md as canonicalizeRegion, nc as coerceCfnBoolean, nn as lookupEachName, oa as slowCcOperationTimeoutMs, oc as configStringRefusal, ol as withoutPhysicalNameCopies, p as planStreamMemberOps, pa as deleteSkipReason, pi as secretNamedAttributeNamesOf, q as readTtlSpec, rc as coerceCfnInteger, rn as withApiLimit, sa as onlySecretReferencesDiffer, sc as readConfigString, su as stringifyValue, t as DeployEngine, tc as toFiniteNumber, tn as isAccessDeniedError, u as STREAM_TAGS_KEY, uc as requireConfigObject, ut as isAbsoluteAssetPath, v as streamPolicyMatchesDeclared, va as ec2InstanceProtectionSite, vc as ecsServiceLaunchTypeSetOrChanged, vt as enclosingDeadlineExpired, w as planIndexContributorInsightsOps, x as contributorInsightsRefusals, xa as reDisableInstanceApiTermination, xc as lambdaFunctionNameForMask, y as streamTagsMatchDeclared, ya as isTerminationProtectionPropagationError, yc as emrClusterInstancesReplaced, yt as enclosingDeadlineRemainingMs, z as TABLE_INDEX_NOUN, zi as readTagList, zn as REDACTED_DELETE_ADDRESS_SKIP_REASON, zt as revertNestedChildFromJournal } from "./deploy-engine-CVNzK__j.js";
|
|
6
|
+
import { n as collectInlinePolicyNamesManagedBySiblings, r as IamCreateClientCache, t as IAMRoleProvider } from "./iam-role-provider-DM7bN9m1.js";
|
|
7
|
+
import { a as resolveSecretDerivedPrincipals, i as isResolvableSecretPrincipalList, n as runDestroyForStack, o as canonicalizeIpProtocolValue, r as holdsUnprovenSecretPrincipalToken, s as resolvedResourceTimeoutMs, t as canonicalizeIpv4Cidr } from "./program-Nk_95KKk.js";
|
|
8
|
+
import { t as modifyDbInstanceWhenAvailable } from "./db-instance-modify-retry-D7wXWxVo.js";
|
|
9
|
+
import { RDSProvider } from "./rds-provider-CXSZq1c8.js";
|
|
10
|
+
import { NeptuneProvider } from "./neptune-provider-qdoLunCh.js";
|
|
11
|
+
import { ASGProvider } from "./asg-provider-CVLTQtQr.js";
|
|
12
12
|
import { createHash, randomUUID } from "node:crypto";
|
|
13
13
|
import { CreateBucketCommand, DeleteBucketAnalyticsConfigurationCommand, DeleteBucketCommand, DeleteBucketCorsCommand, DeleteBucketEncryptionCommand, DeleteBucketIntelligentTieringConfigurationCommand, DeleteBucketInventoryConfigurationCommand, DeleteBucketLifecycleCommand, DeleteBucketMetricsConfigurationCommand, DeleteBucketOwnershipControlsCommand, DeleteBucketPolicyCommand, DeleteBucketReplicationCommand, DeleteBucketTaggingCommand, DeleteBucketWebsiteCommand, DeleteObjectsCommand, GetBucketAccelerateConfigurationCommand, GetBucketCorsCommand, GetBucketEncryptionCommand, GetBucketLifecycleConfigurationCommand, GetBucketLocationCommand, GetBucketLoggingCommand, GetBucketNotificationConfigurationCommand, GetBucketOwnershipControlsCommand, GetBucketPolicyCommand, GetBucketReplicationCommand, GetBucketTaggingCommand, GetBucketVersioningCommand, GetBucketWebsiteCommand, GetObjectCommand, GetObjectLockConfigurationCommand, GetPublicAccessBlockCommand, HeadBucketCommand, ListBucketAnalyticsConfigurationsCommand, ListBucketIntelligentTieringConfigurationsCommand, ListBucketInventoryConfigurationsCommand, ListBucketMetricsConfigurationsCommand, ListBucketsCommand, ListObjectVersionsCommand, ListObjectsV2Command, NoSuchBucket, PutBucketAccelerateConfigurationCommand, PutBucketAnalyticsConfigurationCommand, PutBucketCorsCommand, PutBucketEncryptionCommand, PutBucketIntelligentTieringConfigurationCommand, PutBucketInventoryConfigurationCommand, PutBucketLifecycleConfigurationCommand, PutBucketLoggingCommand, PutBucketMetricsConfigurationCommand, PutBucketNotificationConfigurationCommand, PutBucketOwnershipControlsCommand, PutBucketPolicyCommand, PutBucketReplicationCommand, PutBucketTaggingCommand, PutBucketVersioningCommand, PutBucketWebsiteCommand, PutObjectLockConfigurationCommand, PutPublicAccessBlockCommand, S3Client } from "@aws-sdk/client-s3";
|
|
14
14
|
import { AddRoleToInstanceProfileCommand, AddUserToGroupCommand, AttachGroupPolicyCommand, AttachRolePolicyCommand, AttachUserPolicyCommand, CreateAccessKeyCommand, CreateGroupCommand, CreateInstanceProfileCommand, CreateLoginProfileCommand, CreatePolicyCommand, CreatePolicyVersionCommand, CreateUserCommand, DeleteAccessKeyCommand, DeleteGroupCommand, DeleteGroupPolicyCommand, DeleteInstanceProfileCommand, DeleteLoginProfileCommand, DeletePolicyCommand, DeletePolicyVersionCommand, DeleteRolePolicyCommand, DeleteUserCommand, DeleteUserPermissionsBoundaryCommand, DeleteUserPolicyCommand, DetachGroupPolicyCommand, DetachRolePolicyCommand, DetachUserPolicyCommand, GetAccessKeyLastUsedCommand, GetGroupCommand, GetGroupPolicyCommand, GetInstanceProfileCommand, GetPolicyCommand, GetPolicyVersionCommand, GetRolePolicyCommand, GetUserCommand, GetUserPolicyCommand, IAMClient, ListAccessKeysCommand, ListAttachedGroupPoliciesCommand, ListAttachedUserPoliciesCommand, ListEntitiesForPolicyCommand, ListGroupPoliciesCommand, ListGroupsForUserCommand, ListPoliciesCommand, ListPolicyTagsCommand, ListPolicyVersionsCommand, ListUserPoliciesCommand, NoSuchEntityException, PutGroupPolicyCommand, PutRolePolicyCommand, PutUserPermissionsBoundaryCommand, PutUserPolicyCommand, RemoveRoleFromInstanceProfileCommand, RemoveUserFromGroupCommand, TagPolicyCommand, TagUserCommand, UntagPolicyCommand, UntagUserCommand, UpdateAccessKeyCommand, UpdateGroupCommand, UpdateLoginProfileCommand, UpdateUserCommand } from "@aws-sdk/client-iam";
|
|
@@ -63,7 +63,7 @@ import { CodeCommitClient, CreateCommitCommand, CreateRepositoryCommand as Creat
|
|
|
63
63
|
import { CreateLifecyclePolicyCommand, DLMClient, DeleteLifecyclePolicyCommand as DeleteLifecyclePolicyCommand$1, GetLifecyclePoliciesCommand, GetLifecyclePolicyCommand as GetLifecyclePolicyCommand$1, ResourceNotFoundException as ResourceNotFoundException$16, TagResourceCommand as TagResourceCommand$26, UntagResourceCommand as UntagResourceCommand$27, UpdateLifecyclePolicyCommand } from "@aws-sdk/client-dlm";
|
|
64
64
|
import { CreateVectorBucketCommand, DeleteIndexCommand, DeleteVectorBucketCommand, GetVectorBucketCommand, ListIndexesCommand, ListTagsForResourceCommand as ListTagsForResourceCommand$18, S3VectorsClient, TagResourceCommand as TagResourceCommand$27, UntagResourceCommand as UntagResourceCommand$28 } from "@aws-sdk/client-s3vectors";
|
|
65
65
|
import { ListTagsForResourceCommand as ListTagsForResourceCommand$19, S3ControlClient, TagResourceCommand as TagResourceCommand$28, UntagResourceCommand as UntagResourceCommand$29 } from "@aws-sdk/client-s3-control";
|
|
66
|
-
import { CreateNamespaceCommand, CreateTableBucketCommand, CreateTableCommand as CreateTableCommand$2, DeleteNamespaceCommand as DeleteNamespaceCommand$1, DeleteTableBucketCommand, DeleteTableCommand as DeleteTableCommand$2, GetNamespaceCommand as GetNamespaceCommand$1, GetTableBucketCommand, GetTableCommand as GetTableCommand$1, ListNamespacesCommand as ListNamespacesCommand$1, ListTableBucketsCommand, ListTablesCommand, ListTagsForResourceCommand as ListTagsForResourceCommand$20, NotFoundException as NotFoundException$7, RenameTableCommand, S3TablesClient, TagResourceCommand as TagResourceCommand$29, UntagResourceCommand as UntagResourceCommand$30 } from "@aws-sdk/client-s3tables";
|
|
66
|
+
import { CreateNamespaceCommand, CreateTableBucketCommand, CreateTableCommand as CreateTableCommand$2, DeleteNamespaceCommand as DeleteNamespaceCommand$1, DeleteTableBucketCommand, DeleteTableBucketMetricsConfigurationCommand, DeleteTableBucketReplicationCommand, DeleteTableCommand as DeleteTableCommand$2, GetNamespaceCommand as GetNamespaceCommand$1, GetTableBucketCommand, GetTableBucketEncryptionCommand, GetTableBucketMaintenanceConfigurationCommand, GetTableBucketMetricsConfigurationCommand, GetTableBucketReplicationCommand, GetTableBucketStorageClassCommand, GetTableCommand as GetTableCommand$1, GetTableMaintenanceConfigurationCommand, ListNamespacesCommand as ListNamespacesCommand$1, ListTableBucketsCommand, ListTablesCommand, ListTagsForResourceCommand as ListTagsForResourceCommand$20, NotFoundException as NotFoundException$7, PutTableBucketEncryptionCommand, PutTableBucketMaintenanceConfigurationCommand, PutTableBucketMetricsConfigurationCommand, PutTableBucketReplicationCommand, PutTableBucketStorageClassCommand, PutTableMaintenanceConfigurationCommand, RenameTableCommand, S3TablesClient, TagResourceCommand as TagResourceCommand$29, UntagResourceCommand as UntagResourceCommand$30 } from "@aws-sdk/client-s3tables";
|
|
67
67
|
|
|
68
68
|
//#region src/provisioning/providers/iam-policy-provider.ts
|
|
69
69
|
const POLICY_NAME_SKIP_REASON = "no policy name in state — no delete issued";
|
|
@@ -656,6 +656,7 @@ var IAMManagedPolicyProvider = class {
|
|
|
656
656
|
if (!policyArn) throw new ProvisioningError(`CreatePolicy succeeded but no Arn returned for ${logicalId}`, resourceType, logicalId, policyName);
|
|
657
657
|
leftBehindArn = policyArn;
|
|
658
658
|
createdPolicyIdentity = policyIdentityToken(response.Policy?.PolicyId);
|
|
659
|
+
reportCreatedResource(logicalId, resourceType, policyArn, createdPolicyIdentity);
|
|
659
660
|
log.debug(`Created IAM managed policy: ${v(policyArn)}`);
|
|
660
661
|
try {
|
|
661
662
|
await this.attachToPrincipals(policyArn, principals.lists.Groups, principals.lists.Roles, principals.lists.Users, log);
|
|
@@ -664,6 +665,7 @@ var IAMManagedPolicyProvider = class {
|
|
|
664
665
|
await this.detachAllPrincipals(policyArn);
|
|
665
666
|
await this.deleteAllNonDefaultVersions(policyArn);
|
|
666
667
|
await this.iamClient.send(new DeletePolicyCommand({ PolicyArn: policyArn }));
|
|
668
|
+
retractCreatedResource(logicalId, resourceType, policyArn);
|
|
667
669
|
leftBehindArn = void 0;
|
|
668
670
|
log.debug(`Cleaned up partially-created managed policy ${logicalId} (${v(policyArn)}) after attachment failure`);
|
|
669
671
|
} catch (cleanupError) {
|
|
@@ -1263,6 +1265,7 @@ var IAMInstanceProfileProvider = class {
|
|
|
1263
1265
|
}));
|
|
1264
1266
|
leftBehind = true;
|
|
1265
1267
|
createdProfileIdentity = instanceProfileIdentityToken(response.InstanceProfile?.InstanceProfileId);
|
|
1268
|
+
reportCreatedResource(logicalId, resourceType, instanceProfileName, createdProfileIdentity);
|
|
1266
1269
|
log.debug(`Created IAM instance profile: ${v(instanceProfileName)}`);
|
|
1267
1270
|
const attachedRoles = [];
|
|
1268
1271
|
try {
|
|
@@ -1285,6 +1288,7 @@ var IAMInstanceProfileProvider = class {
|
|
|
1285
1288
|
if (!(err instanceof NoSuchEntityException)) throw err;
|
|
1286
1289
|
}
|
|
1287
1290
|
await this.iamClient.send(new DeleteInstanceProfileCommand({ InstanceProfileName: instanceProfileName }));
|
|
1291
|
+
retractCreatedResource(logicalId, resourceType, instanceProfileName);
|
|
1288
1292
|
leftBehind = false;
|
|
1289
1293
|
log.debug(`Cleaned up partially-created IAM instance profile ${logicalId} (${v(instanceProfileName)}) after wiring failure`);
|
|
1290
1294
|
} catch (cleanupError) {
|
|
@@ -1534,12 +1538,14 @@ var IAMAccessKeyProvider = class {
|
|
|
1534
1538
|
const accessKeyId = response.AccessKey?.AccessKeyId;
|
|
1535
1539
|
const secretAccessKey = response.AccessKey?.SecretAccessKey;
|
|
1536
1540
|
leftBehindKeyId = accessKeyId;
|
|
1541
|
+
reportCreatedResource(logicalId, resourceType, accessKeyId ?? "");
|
|
1537
1542
|
if (!accessKeyId || !secretAccessKey) {
|
|
1538
1543
|
if (accessKeyId) try {
|
|
1539
1544
|
await this.iamClient.send(new DeleteAccessKeyCommand({
|
|
1540
1545
|
UserName: userName,
|
|
1541
1546
|
AccessKeyId: accessKeyId
|
|
1542
1547
|
}));
|
|
1548
|
+
retractCreatedResource(logicalId, resourceType, accessKeyId);
|
|
1543
1549
|
leftBehindKeyId = void 0;
|
|
1544
1550
|
} catch (cleanupError) {
|
|
1545
1551
|
const lead = `Failed to clean up IAM access key ${logicalId} (${v(accessKeyId)}) minted by a partial CreateAccessKey response`;
|
|
@@ -1559,6 +1565,7 @@ var IAMAccessKeyProvider = class {
|
|
|
1559
1565
|
UserName: userName,
|
|
1560
1566
|
AccessKeyId: accessKeyId
|
|
1561
1567
|
}));
|
|
1568
|
+
retractCreatedResource(logicalId, resourceType, accessKeyId);
|
|
1562
1569
|
leftBehindKeyId = void 0;
|
|
1563
1570
|
log.debug(`Cleaned up partially-created IAM access key ${logicalId} (${v(accessKeyId)}) after status wiring failure`);
|
|
1564
1571
|
} catch (cleanupError) {
|
|
@@ -1584,7 +1591,10 @@ var IAMAccessKeyProvider = class {
|
|
|
1584
1591
|
};
|
|
1585
1592
|
} catch (error) {
|
|
1586
1593
|
const reconciled = await this.deleteOrphanFromFailedAttempt(userName, logicalId, baseline, attemptStartMs, log);
|
|
1587
|
-
if (leftBehindKeyId !== void 0 && reconciled.has(leftBehindKeyId))
|
|
1594
|
+
if (leftBehindKeyId !== void 0 && reconciled.has(leftBehindKeyId)) {
|
|
1595
|
+
retractCreatedResource(logicalId, resourceType, leftBehindKeyId);
|
|
1596
|
+
leftBehindKeyId = void 0;
|
|
1597
|
+
}
|
|
1588
1598
|
const cause = error instanceof Error ? error : void 0;
|
|
1589
1599
|
const thrown = this.wrapMaskedError(log, error, (text) => new ProvisioningError(`Failed to create IAM access key ${logicalId}: ${text}`, resourceType, logicalId, void 0, cause));
|
|
1590
1600
|
if (leftBehindKeyId !== void 0) {
|
|
@@ -1935,6 +1945,7 @@ var IAMUserGroupProvider = class {
|
|
|
1935
1945
|
const response = await (await this.createClient.get()).send(new CreateUserCommand(createParams));
|
|
1936
1946
|
leftBehind = true;
|
|
1937
1947
|
createdUserIdentity = userOrGroupIdentityToken(response.User?.UserId);
|
|
1948
|
+
reportCreatedResource(logicalId, resourceType, userName, createdUserIdentity);
|
|
1938
1949
|
try {
|
|
1939
1950
|
const permissionsBoundary = properties["PermissionsBoundary"];
|
|
1940
1951
|
if (permissionsBoundary) {
|
|
@@ -1995,6 +2006,7 @@ var IAMUserGroupProvider = class {
|
|
|
1995
2006
|
if (!(err instanceof NoSuchEntityException)) throw err;
|
|
1996
2007
|
}
|
|
1997
2008
|
await this.iamClient.send(new DeleteUserCommand({ UserName: userName }));
|
|
2009
|
+
retractCreatedResource(logicalId, resourceType, userName);
|
|
1998
2010
|
leftBehind = false;
|
|
1999
2011
|
log.debug(`Cleaned up partially-created IAM user ${logicalId} (${v(userName)}) after wiring failure`);
|
|
2000
2012
|
} catch (cleanupError) {
|
|
@@ -2337,6 +2349,7 @@ var IAMUserGroupProvider = class {
|
|
|
2337
2349
|
const response = await (await this.createClient.get()).send(new CreateGroupCommand(createParams));
|
|
2338
2350
|
leftBehind = true;
|
|
2339
2351
|
createdGroupIdentity = userOrGroupIdentityToken(response.Group?.GroupId);
|
|
2352
|
+
reportCreatedResource(logicalId, resourceType, groupName, createdGroupIdentity);
|
|
2340
2353
|
try {
|
|
2341
2354
|
const managedPolicyArns = properties["ManagedPolicyArns"];
|
|
2342
2355
|
if (managedPolicyArns && Array.isArray(managedPolicyArns)) for (const policyArn of managedPolicyArns) {
|
|
@@ -2361,6 +2374,7 @@ var IAMUserGroupProvider = class {
|
|
|
2361
2374
|
await this.detachAllGroupPolicies(groupName, log);
|
|
2362
2375
|
await this.deleteAllGroupInlinePolicies(groupName, log);
|
|
2363
2376
|
await this.iamClient.send(new DeleteGroupCommand({ GroupName: groupName }));
|
|
2377
|
+
retractCreatedResource(logicalId, resourceType, groupName);
|
|
2364
2378
|
leftBehind = false;
|
|
2365
2379
|
log.debug(`Cleaned up partially-created IAM group ${logicalId} (${v(groupName)}) after wiring failure`);
|
|
2366
2380
|
} catch (cleanupError) {
|
|
@@ -4803,6 +4817,7 @@ var S3BucketProvider = class S3BucketProvider {
|
|
|
4803
4817
|
}
|
|
4804
4818
|
createdNewBucket = adoptedOwnLeftover || preflight.kind === "absent";
|
|
4805
4819
|
bucketLeftBehind = createdNewBucket;
|
|
4820
|
+
if (createdNewBucket) reportCreatedResource(logicalId, resourceType, bucketName);
|
|
4806
4821
|
if (createdNewBucket) windowSpent = true;
|
|
4807
4822
|
if (preflight.kind === "region" && preflight.region !== "us-east-1") this.refuseForeignRegionAdopt(logicalId, resourceType, bucketName, "us-east-1", preflight.region);
|
|
4808
4823
|
if (preflight.kind === "region" && !adoptedOwnLeftover) this.logger.warn(`S3 bucket ${this.shown(bucketName)} for ${displaySafe(logicalId)} (${resourceType}) already existed in ${preflight.region} and was ADOPTED, not created. In us-east-1 S3 answers a re-create of a bucket you already own with 200 OK and RESETS that bucket's access control lists, so any ACL previously set on ${this.shown(bucketName)} is now the default. cdkd will not delete this bucket if the rest of this create fails.`);
|
|
@@ -4832,6 +4847,7 @@ var S3BucketProvider = class S3BucketProvider {
|
|
|
4832
4847
|
if (createdNewBucket) try {
|
|
4833
4848
|
await this.s3Client.send(new DeleteBucketCommand({ Bucket: bucketName }));
|
|
4834
4849
|
bucketLeftBehind = false;
|
|
4850
|
+
retractCreatedResource(logicalId, resourceType, bucketName);
|
|
4835
4851
|
this.logger.debug(`Cleaned up partially-created S3 bucket ${displaySafe(logicalId)} (${this.shown(bucketName)}) after wiring failure`);
|
|
4836
4852
|
} catch (cleanupError) {
|
|
4837
4853
|
this.logger.debug(`DeleteBucket cleanup failed for S3 bucket ${displaySafe(logicalId)} (${this.shown(bucketName)}): ${describeAwsFailure(cleanupError).detail}`);
|
|
@@ -6263,7 +6279,7 @@ function normalizeStatement(statement) {
|
|
|
6263
6279
|
for (const key of PRINCIPAL_KEYS) if (Object.prototype.hasOwnProperty.call(out, key)) out[key] = normalizePrincipal(out[key]);
|
|
6264
6280
|
return out;
|
|
6265
6281
|
}
|
|
6266
|
-
function canonicalJson$
|
|
6282
|
+
function canonicalJson$3(value) {
|
|
6267
6283
|
const sortKeys = (v) => {
|
|
6268
6284
|
if (Array.isArray(v)) return v.map(sortKeys);
|
|
6269
6285
|
if (v !== null && typeof v === "object") {
|
|
@@ -6287,7 +6303,7 @@ function policyContentKey(document) {
|
|
|
6287
6303
|
if (Object.prototype.hasOwnProperty.call(doc, "Statement")) doc["Statement"] = (Array.isArray(doc["Statement"]) ? doc["Statement"] : [doc["Statement"]]).map(normalizeStatement);
|
|
6288
6304
|
value = doc;
|
|
6289
6305
|
}
|
|
6290
|
-
return canonicalJson$
|
|
6306
|
+
return canonicalJson$3(value);
|
|
6291
6307
|
}
|
|
6292
6308
|
|
|
6293
6309
|
//#endregion
|
|
@@ -6565,7 +6581,7 @@ function listedQueues(bag) {
|
|
|
6565
6581
|
function isListedQueueUrl(value) {
|
|
6566
6582
|
return isSqsQueueUrl(value) && !value.includes(",") && !value.includes("*");
|
|
6567
6583
|
}
|
|
6568
|
-
function canonicalJson$
|
|
6584
|
+
function canonicalJson$2(value) {
|
|
6569
6585
|
const sortKeys = (v) => {
|
|
6570
6586
|
if (Array.isArray(v)) return v.map(sortKeys);
|
|
6571
6587
|
if (v !== null && typeof v === "object") {
|
|
@@ -6580,14 +6596,14 @@ function canonicalJson$1(value) {
|
|
|
6580
6596
|
}
|
|
6581
6597
|
function canonicalPolicy$1(text) {
|
|
6582
6598
|
try {
|
|
6583
|
-
return canonicalJson$
|
|
6599
|
+
return canonicalJson$2(JSON.parse(text));
|
|
6584
6600
|
} catch {
|
|
6585
6601
|
return `raw:${text}`;
|
|
6586
6602
|
}
|
|
6587
6603
|
}
|
|
6588
6604
|
function policyReference(document) {
|
|
6589
6605
|
if (typeof document === "string" && document.length > 0) return canonicalPolicy$1(document);
|
|
6590
|
-
if (document !== null && typeof document === "object") return canonicalJson$
|
|
6606
|
+
if (document !== null && typeof document === "object") return canonicalJson$2(document);
|
|
6591
6607
|
}
|
|
6592
6608
|
function splitQueueUrls(physicalId) {
|
|
6593
6609
|
return physicalId.split(",").filter((url) => url.length > 0);
|
|
@@ -6683,7 +6699,8 @@ var SNSTopicProvider = class {
|
|
|
6683
6699
|
if (properties["MaximumMessageSize"] != null) topicAttributes["MaximumMessageSize"] = stringifyValue(properties["MaximumMessageSize"]);
|
|
6684
6700
|
let tags;
|
|
6685
6701
|
if (properties["Tags"] != null) tags = desiredTags;
|
|
6686
|
-
const
|
|
6702
|
+
const wiringDeclared = Boolean(properties["ArchivePolicy"]) || Boolean(properties["DataProtectionPolicy"]) || properties["DeliveryStatusLogging"] != null || Array.isArray(properties["Subscription"]);
|
|
6703
|
+
const heldBefore = wiringDeclared ? await this.topicHeldBefore(topicName) : "free";
|
|
6687
6704
|
const createParams = {
|
|
6688
6705
|
Name: topicName,
|
|
6689
6706
|
...Object.keys(topicAttributes).length > 0 && { Attributes: topicAttributes },
|
|
@@ -6691,6 +6708,7 @@ var SNSTopicProvider = class {
|
|
|
6691
6708
|
};
|
|
6692
6709
|
const topicArn = (await this.snsClient.send(new CreateTopicCommand(createParams))).TopicArn;
|
|
6693
6710
|
if (!topicArn) throw new Error("CreateTopic did not return TopicArn");
|
|
6711
|
+
if (wiringDeclared && heldBefore === "free") reportCreatedResource(logicalId, resourceType, topicArn);
|
|
6694
6712
|
try {
|
|
6695
6713
|
if (properties["ArchivePolicy"]) {
|
|
6696
6714
|
const archivePolicy = typeof properties["ArchivePolicy"] === "string" ? properties["ArchivePolicy"] : JSON.stringify(properties["ArchivePolicy"]);
|
|
@@ -6722,6 +6740,7 @@ var SNSTopicProvider = class {
|
|
|
6722
6740
|
if (heldBefore !== "free") warn(skippedCleanupText(heldBefore, `SNS topic ${logicalId} (${topicArn})`, pasteableAwsCommand(maskSecrets)`aws sns delete-topic --topic-arn ${topicArn}`.render()));
|
|
6723
6741
|
else try {
|
|
6724
6742
|
await this.snsClient.send(new DeleteTopicCommand({ TopicArn: topicArn }));
|
|
6743
|
+
retractCreatedResource(logicalId, resourceType, topicArn);
|
|
6725
6744
|
this.logger.debug(`Cleaned up partially-created SNS topic ${logicalId} (${topicArn}) after wiring failure`);
|
|
6726
6745
|
} catch (cleanupError) {
|
|
6727
6746
|
leftBehindArn = topicArn;
|
|
@@ -7609,7 +7628,7 @@ var SNSTopicPolicyProvider = class {
|
|
|
7609
7628
|
if (candidates.length === 0) return [];
|
|
7610
7629
|
let reference;
|
|
7611
7630
|
if (typeof document === "string" && document.length > 0) reference = canonicalPolicy(document);
|
|
7612
|
-
else if (document !== null && typeof document === "object") reference = canonicalJson(document);
|
|
7631
|
+
else if (document !== null && typeof document === "object") reference = canonicalJson$1(document);
|
|
7613
7632
|
if (reference === void 0) {
|
|
7614
7633
|
this.logger.warn(mask(safeMsg`The topics ${candidates.join(", ")} listed by ${logicalId} were not checked (no policy document recorded to compare with) and may still carry its policy.`));
|
|
7615
7634
|
return [];
|
|
@@ -7726,7 +7745,7 @@ function defaultTopicPolicy(topicArn) {
|
|
|
7726
7745
|
}]
|
|
7727
7746
|
});
|
|
7728
7747
|
}
|
|
7729
|
-
function canonicalJson(value) {
|
|
7748
|
+
function canonicalJson$1(value) {
|
|
7730
7749
|
const sortKeys = (v) => {
|
|
7731
7750
|
if (Array.isArray(v)) return v.map(sortKeys);
|
|
7732
7751
|
if (v !== null && typeof v === "object") {
|
|
@@ -7740,7 +7759,7 @@ function canonicalJson(value) {
|
|
|
7740
7759
|
}
|
|
7741
7760
|
function canonicalPolicy(text) {
|
|
7742
7761
|
try {
|
|
7743
|
-
return canonicalJson(JSON.parse(text));
|
|
7762
|
+
return canonicalJson$1(JSON.parse(text));
|
|
7744
7763
|
} catch {
|
|
7745
7764
|
return `raw:${text}`;
|
|
7746
7765
|
}
|
|
@@ -8059,6 +8078,7 @@ var LambdaFunctionProvider = class {
|
|
|
8059
8078
|
functionCreated = true;
|
|
8060
8079
|
createdFunctionName = response.FunctionName || functionName;
|
|
8061
8080
|
createdFunctionIdentity = functionIdentityToken(response.FunctionArn, response.LastModified);
|
|
8081
|
+
reportCreatedResource(logicalId, resourceType, createdFunctionName, createdFunctionIdentity);
|
|
8062
8082
|
const recursiveLoop = properties["RecursiveLoop"];
|
|
8063
8083
|
if (recursiveLoop !== void 0) await this.applyPostCreateConfig(() => this.lambdaClient.send(new PutFunctionRecursionConfigCommand({
|
|
8064
8084
|
FunctionName: functionName,
|
|
@@ -8093,6 +8113,7 @@ var LambdaFunctionProvider = class {
|
|
|
8093
8113
|
minDelay: 1,
|
|
8094
8114
|
maxDelay: 5
|
|
8095
8115
|
}, { FunctionName: functionName });
|
|
8116
|
+
reportCreatedResource(logicalId, resourceType, createdFunctionName);
|
|
8096
8117
|
await this.putRuntimeManagementConfig(functionName, runtimeManagementConfig);
|
|
8097
8118
|
createdFunctionIdentity = void 0;
|
|
8098
8119
|
}, {
|
|
@@ -8117,6 +8138,7 @@ var LambdaFunctionProvider = class {
|
|
|
8117
8138
|
const cause = error instanceof Error ? error : void 0;
|
|
8118
8139
|
const thrown = this.wrapMaskedError(log, error, (text) => new ProvisioningError(`Failed to create Lambda function ${logicalId}: ${text}`, resourceType, logicalId, functionName, cause ?? new Error(safeStringify(error))));
|
|
8119
8140
|
if (createdFunctionName !== void 0 && !postCreateCleanup.deleted) markCreatedBeforeFailure(thrown, logicalId, resourceType, createdFunctionName, createdFunctionIdentity);
|
|
8141
|
+
else if (createdFunctionName !== void 0) retractCreatedResource(logicalId, resourceType, createdFunctionName);
|
|
8120
8142
|
throw thrown;
|
|
8121
8143
|
}
|
|
8122
8144
|
}
|
|
@@ -10398,6 +10420,7 @@ var LambdaMicrovmImageProvider = class {
|
|
|
10398
10420
|
const imageArn = response.imageArn;
|
|
10399
10421
|
createdArn = imageArn;
|
|
10400
10422
|
if (!imageArn) throw new ProvisioningError(`CreateMicrovmImage succeeded but no imageArn returned for ${logicalId}`, resourceType, logicalId);
|
|
10423
|
+
reportCreatedResource(logicalId, resourceType, imageArn);
|
|
10401
10424
|
this.logger.debug(`Created MicroVM image ${logicalId}: ${imageArn} (state=${response.state})`);
|
|
10402
10425
|
const noWait = process.env["CDKD_NO_WAIT"] === "true";
|
|
10403
10426
|
let latest = {
|
|
@@ -10656,15 +10679,15 @@ function buildCommonImageInput(properties) {
|
|
|
10656
10679
|
return input;
|
|
10657
10680
|
}
|
|
10658
10681
|
function mapCodeArtifact(value) {
|
|
10659
|
-
if (!isRecord$
|
|
10682
|
+
if (!isRecord$2(value)) return void 0;
|
|
10660
10683
|
const uri = value["Uri"];
|
|
10661
10684
|
return typeof uri === "string" ? { uri } : void 0;
|
|
10662
10685
|
}
|
|
10663
10686
|
function mapLogging(value) {
|
|
10664
|
-
if (!isRecord$
|
|
10687
|
+
if (!isRecord$2(value)) return void 0;
|
|
10665
10688
|
if (value["Disabled"] === true) return { disabled: {} };
|
|
10666
10689
|
const cloudWatch = value["CloudWatch"];
|
|
10667
|
-
if (isRecord$
|
|
10690
|
+
if (isRecord$2(cloudWatch)) {
|
|
10668
10691
|
const cw = {};
|
|
10669
10692
|
if (typeof cloudWatch["LogGroup"] === "string") cw.logGroup = cloudWatch["LogGroup"];
|
|
10670
10693
|
if (typeof cloudWatch["LogStream"] === "string") cw.logStream = cloudWatch["LogStream"];
|
|
@@ -10673,32 +10696,32 @@ function mapLogging(value) {
|
|
|
10673
10696
|
}
|
|
10674
10697
|
function mapCpuConfigurations(value) {
|
|
10675
10698
|
if (!Array.isArray(value)) return void 0;
|
|
10676
|
-
return value.filter(isRecord$
|
|
10699
|
+
return value.filter(isRecord$2).map((c) => ({ architecture: c["Architecture"] }));
|
|
10677
10700
|
}
|
|
10678
10701
|
function mapResources(value) {
|
|
10679
10702
|
if (!Array.isArray(value)) return void 0;
|
|
10680
|
-
return value.filter(isRecord$
|
|
10703
|
+
return value.filter(isRecord$2).map((r) => Number(r["MinimumMemoryInMiB"])).filter((n) => Number.isFinite(n)).map((minimumMemoryInMiB) => ({ minimumMemoryInMiB }));
|
|
10681
10704
|
}
|
|
10682
10705
|
function mapHooks(value) {
|
|
10683
|
-
if (!isRecord$
|
|
10706
|
+
if (!isRecord$2(value)) return void 0;
|
|
10684
10707
|
return lowerFirstKeysDeep(value);
|
|
10685
10708
|
}
|
|
10686
10709
|
function mapKeyValueListToRecord(value) {
|
|
10687
10710
|
if (!Array.isArray(value)) return void 0;
|
|
10688
10711
|
const out = {};
|
|
10689
|
-
for (const entry of value) if (isRecord$
|
|
10712
|
+
for (const entry of value) if (isRecord$2(entry) && typeof entry["Key"] === "string") out[entry["Key"]] = typeof entry["Value"] === "string" ? entry["Value"] : "";
|
|
10690
10713
|
return Object.keys(out).length > 0 ? out : void 0;
|
|
10691
10714
|
}
|
|
10692
10715
|
function lowerFirstKeysDeep(value) {
|
|
10693
10716
|
if (Array.isArray(value)) return value.map(lowerFirstKeysDeep);
|
|
10694
|
-
if (isRecord$
|
|
10717
|
+
if (isRecord$2(value)) {
|
|
10695
10718
|
const out = {};
|
|
10696
10719
|
for (const [k, v] of Object.entries(value)) out[k.charAt(0).toLowerCase() + k.slice(1)] = lowerFirstKeysDeep(v);
|
|
10697
10720
|
return out;
|
|
10698
10721
|
}
|
|
10699
10722
|
return value;
|
|
10700
10723
|
}
|
|
10701
|
-
function isRecord$
|
|
10724
|
+
function isRecord$2(value) {
|
|
10702
10725
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
10703
10726
|
}
|
|
10704
10727
|
|
|
@@ -10784,7 +10807,10 @@ var LambdaWebFunctionRevisionProvider = class {
|
|
|
10784
10807
|
throw error;
|
|
10785
10808
|
}
|
|
10786
10809
|
createdArn = response.revisionArn;
|
|
10787
|
-
if (createdArn)
|
|
10810
|
+
if (createdArn) {
|
|
10811
|
+
revisionsCreatedByThisProcess.add(createdArn);
|
|
10812
|
+
reportCreatedResource(logicalId, resourceType, createdArn);
|
|
10813
|
+
}
|
|
10788
10814
|
const replayWindow = replayedSendWindow(response, attemptStartMs);
|
|
10789
10815
|
if (replayWindow !== void 0) await this.reportPossibleRevisionOrphans(logicalId, replayWindow, log, input.functionName);
|
|
10790
10816
|
if (!createdArn || !response.revisionId) throw new ProvisioningError(`CreateWebFunctionRevision succeeded but returned no revision ARN for ${logicalIdShown(logicalId)}`, resourceType, logicalId);
|
|
@@ -10798,6 +10824,7 @@ var LambdaWebFunctionRevisionProvider = class {
|
|
|
10798
10824
|
let leftBehindArn = createdArn;
|
|
10799
10825
|
if (leftBehindArn) try {
|
|
10800
10826
|
await this.delete(logicalId, leftBehindArn, resourceType, void 0, context?.maskSecrets ? { maskSecrets: context.maskSecrets } : void 0);
|
|
10827
|
+
retractCreatedResource(logicalId, resourceType, leftBehindArn);
|
|
10801
10828
|
leftBehindArn = void 0;
|
|
10802
10829
|
} catch (cleanupError) {
|
|
10803
10830
|
log.warn(safeMsg`Failed to delete partially-created Lambda web function revision ${logicalId}: ${describeAwsFailure(cleanupError).detail}. The failed deploy records it for \`cdkd rollback --revert-failed\`, or delete it by hand`);
|
|
@@ -11167,6 +11194,7 @@ var LambdaWebFunctionEndpointProvider = class {
|
|
|
11167
11194
|
try {
|
|
11168
11195
|
createdArn = (await this.client.send(new CreateWebFunctionEndpointCommand(input))).endpointArn;
|
|
11169
11196
|
if (!createdArn) throw new ProvisioningError(`CreateWebFunctionEndpoint succeeded but returned no endpoint ARN for ${logicalIdShown(logicalId)}`, resourceType, logicalId);
|
|
11197
|
+
reportCreatedResource(logicalId, resourceType, createdArn);
|
|
11170
11198
|
const settled = await this.waitForSettled(input.functionName, input.endpointName, logicalId, resourceType, "create", void 0, context?.maskSecrets);
|
|
11171
11199
|
return {
|
|
11172
11200
|
physicalId: createdArn,
|
|
@@ -11489,6 +11517,11 @@ var LambdaNetworkConnectorProvider = class {
|
|
|
11489
11517
|
const tagList = refuseMalformedDesiredTags(properties["Tags"], resourceType, logicalId, void 0, "Tags", DBPROXY_TAGS_WHAT, DBPROXY_TAG_OPTIONS);
|
|
11490
11518
|
const name = typeof properties["Name"] === "string" && properties["Name"] !== "" ? properties["Name"] : generatedNameFor("AWS::Lambda::NetworkConnector", logicalId);
|
|
11491
11519
|
const vpc = this.readVpcEgress(properties, logicalId, resourceType, void 0);
|
|
11520
|
+
if (declaredElasticIp(properties) !== void 0) {
|
|
11521
|
+
const message = elasticIpRefusalMessage(logicalId, "create");
|
|
11522
|
+
if (context?.replayingState !== true) throw new ProvisioningError(message, resourceType, logicalId);
|
|
11523
|
+
this.logger.warn(safeMsg`${message} Proceeding without it: this create replays a cdkd state record.`);
|
|
11524
|
+
}
|
|
11492
11525
|
const createToken = acquireIdempotencyToken({
|
|
11493
11526
|
scope: "CreateNetworkConnector",
|
|
11494
11527
|
logicalId
|
|
@@ -11510,6 +11543,7 @@ var LambdaNetworkConnectorProvider = class {
|
|
|
11510
11543
|
try {
|
|
11511
11544
|
createdArn = (await this.client.send(new CreateNetworkConnectorCommand(input))).Arn;
|
|
11512
11545
|
if (!createdArn) throw new ProvisioningError(`CreateNetworkConnector succeeded but returned no ARN for ${logicalIdShown(logicalId)}`, resourceType, logicalId);
|
|
11546
|
+
reportCreatedResource(logicalId, resourceType, createdArn);
|
|
11513
11547
|
const settled = await this.waitForSettled(createdArn, logicalId, "create");
|
|
11514
11548
|
createToken.release();
|
|
11515
11549
|
return {
|
|
@@ -11527,6 +11561,12 @@ var LambdaNetworkConnectorProvider = class {
|
|
|
11527
11561
|
assertRegionMatch(context?.expectedRegion ? await this.client.config.region() : void 0, context?.expectedRegion, resourceType, logicalId, physicalId, "pre-update");
|
|
11528
11562
|
refuseMalformedDesiredTags(properties["Tags"], resourceType, logicalId, physicalId, "Tags", DBPROXY_TAGS_WHAT, DBPROXY_TAG_OPTIONS);
|
|
11529
11563
|
const vpc = this.readVpcEgress(properties, logicalId, resourceType, physicalId);
|
|
11564
|
+
const desiredElasticIp = declaredElasticIp(properties);
|
|
11565
|
+
if (desiredElasticIp !== void 0 && !isDeepStrictEqual(desiredElasticIp, declaredElasticIp(previousProperties))) {
|
|
11566
|
+
const message = elasticIpRefusalMessage(logicalId, "update");
|
|
11567
|
+
if (context?.replayingState !== true && context?.desiredFromAwsReadback !== true) throw new ProvisioningError(message, resourceType, logicalId, physicalId);
|
|
11568
|
+
this.logger.warn(safeMsg`${message} Proceeding without it: this update restores a recorded or read-back configuration.`);
|
|
11569
|
+
}
|
|
11530
11570
|
const updateRole = this.readOperatorRole(properties, logicalId, resourceType, physicalId, context);
|
|
11531
11571
|
if (typeof previousProperties["OperatorRole"] === "string" && properties["OperatorRole"] === void 0 && context?.replayingState !== true && context?.desiredFromAwsReadback !== true) throw new ProvisioningError(`OperatorRole cannot be removed in place for Lambda network connector ${logicalIdShown(logicalId)}: cdkd sends no role when the template declares none, so the current one would stay attached. Set it to another role, or replace the connector (change its Name).`, resourceType, logicalId, physicalId);
|
|
11532
11572
|
try {
|
|
@@ -11725,6 +11765,15 @@ var LambdaNetworkConnectorProvider = class {
|
|
|
11725
11765
|
return markRedactedCause(build(`${failure.summary}${relayedNameCollision(failure.detail)}`));
|
|
11726
11766
|
}
|
|
11727
11767
|
};
|
|
11768
|
+
const ELASTIC_IP_KEY = "ElasticIpConfiguration";
|
|
11769
|
+
function declaredElasticIp(properties) {
|
|
11770
|
+
const config = properties["Configuration"];
|
|
11771
|
+
const vpc = isPlainRecord$3(config) ? config["VpcEgressConfiguration"] : void 0;
|
|
11772
|
+
return isPlainRecord$3(vpc) ? vpc[ELASTIC_IP_KEY] : void 0;
|
|
11773
|
+
}
|
|
11774
|
+
function elasticIpRefusalMessage(logicalId, mode) {
|
|
11775
|
+
return `AWS::Lambda::NetworkConnector ${logicalIdShown(logicalId)}: Configuration.VpcEgressConfiguration.${ELASTIC_IP_KEY} cannot be sent by cdkd yet — the AWS SDK for JavaScript (@aws-sdk/client-lambda-core) does not model the member, so it would be dropped from the ${mode === "create" ? "CreateNetworkConnector" : "UpdateNetworkConnector"} request without an error. Remove ${ELASTIC_IP_KEY} from Configuration.VpcEgressConfiguration to deploy the connector without it.`;
|
|
11776
|
+
}
|
|
11728
11777
|
var TerminalConnectorStateError = class extends Error {};
|
|
11729
11778
|
function buildAttributes(resp) {
|
|
11730
11779
|
return definedAttributes({
|
|
@@ -11739,6 +11788,172 @@ function versionOfArn(arn) {
|
|
|
11739
11788
|
return match ? Number(match[1]) : void 0;
|
|
11740
11789
|
}
|
|
11741
11790
|
|
|
11791
|
+
//#endregion
|
|
11792
|
+
//#region src/provisioning/delete-gone-wait.ts
|
|
11793
|
+
async function waitForGoneAfterDelete(opts) {
|
|
11794
|
+
const sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
11795
|
+
const now = opts.now ?? Date.now;
|
|
11796
|
+
const userTimeoutMs = resolvedResourceTimeoutMs(opts.resourceType);
|
|
11797
|
+
const maxWaitMs = userTimeoutMs === void 0 ? opts.maxWaitMs : Math.min(opts.maxWaitMs, userTimeoutMs / 2);
|
|
11798
|
+
const startedAt = now();
|
|
11799
|
+
const stopped = `${opts.what}: the delete was ACCEPTED by AWS, but cdkd stopped waiting for it to disappear`;
|
|
11800
|
+
const consequence = "AWS finishes the delete on its side; until it does, a create of the same name is refused with \"already exists\".";
|
|
11801
|
+
const watch = startInterruptWatch(`${opts.what} deletion wait`);
|
|
11802
|
+
try {
|
|
11803
|
+
let lastStatus;
|
|
11804
|
+
let sawNonFailedStatus = false;
|
|
11805
|
+
for (;;) {
|
|
11806
|
+
if (watch.isInterrupted()) {
|
|
11807
|
+
opts.logger.warn(safeMsg`${stopped} (interrupted). ${consequence}`);
|
|
11808
|
+
return;
|
|
11809
|
+
}
|
|
11810
|
+
try {
|
|
11811
|
+
const status = await opts.describe();
|
|
11812
|
+
if (status === void 0) {
|
|
11813
|
+
opts.logger.debug(safeMsg`${opts.what} is gone`);
|
|
11814
|
+
return;
|
|
11815
|
+
}
|
|
11816
|
+
const failure = opts.failedStatus?.(status);
|
|
11817
|
+
if (failure !== void 0) {
|
|
11818
|
+
if (sawNonFailedStatus || now() - startedAt >= opts.pollIntervalMs) throw markWaitAbandoned(failure);
|
|
11819
|
+
} else sawNonFailedStatus = true;
|
|
11820
|
+
lastStatus = status;
|
|
11821
|
+
opts.logger.debug(safeMsg`${opts.what} status: ${status}, waiting for it to disappear`);
|
|
11822
|
+
} catch (error) {
|
|
11823
|
+
if (isWaitAbandonedError(error)) throw error;
|
|
11824
|
+
if (!isThrottlingError(error) && !isTransientServerError(error)) {
|
|
11825
|
+
opts.logger.debug(safeMsg`${opts.what}: status read failed: ${describeAwsFailure(error).detail}`);
|
|
11826
|
+
opts.logger.warn(safeMsg`${stopped}: its status could not be read (${describeAwsFailure(error).summary}). ${consequence}`);
|
|
11827
|
+
return;
|
|
11828
|
+
}
|
|
11829
|
+
opts.logger.debug(safeMsg`${opts.what}: status read throttled or failed transiently, re-polling`);
|
|
11830
|
+
}
|
|
11831
|
+
const remainingMs = maxWaitMs - (now() - startedAt);
|
|
11832
|
+
if (remainingMs <= 0) {
|
|
11833
|
+
opts.logger.warn(safeMsg`${stopped} after ${Math.round(maxWaitMs / 1e3)}s` + safeMsg`${lastStatus !== void 0 ? ` (last status: ${lastStatus})` : ""}. ${consequence}`);
|
|
11834
|
+
return;
|
|
11835
|
+
}
|
|
11836
|
+
await sleep(Math.min(opts.pollIntervalMs, remainingMs));
|
|
11837
|
+
}
|
|
11838
|
+
} finally {
|
|
11839
|
+
watch.dispose();
|
|
11840
|
+
}
|
|
11841
|
+
}
|
|
11842
|
+
|
|
11843
|
+
//#endregion
|
|
11844
|
+
//#region src/provisioning/dynamodb-vector-indexes.ts
|
|
11845
|
+
function vectorIndexesByName(value) {
|
|
11846
|
+
const out = /* @__PURE__ */ new Map();
|
|
11847
|
+
if (!Array.isArray(value)) return out;
|
|
11848
|
+
for (const entry of value) {
|
|
11849
|
+
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) continue;
|
|
11850
|
+
const name = entry["IndexName"];
|
|
11851
|
+
if (typeof name === "string") out.set(name, entry);
|
|
11852
|
+
}
|
|
11853
|
+
return out;
|
|
11854
|
+
}
|
|
11855
|
+
function vectorIndexForSend(entry) {
|
|
11856
|
+
const out = {};
|
|
11857
|
+
for (const key of [
|
|
11858
|
+
"IndexName",
|
|
11859
|
+
"VectorAttribute",
|
|
11860
|
+
"Projection",
|
|
11861
|
+
"DistanceFunction"
|
|
11862
|
+
]) if (entry[key] !== void 0) out[key] = entry[key];
|
|
11863
|
+
if (entry["Dimensions"] !== void 0) out["Dimensions"] = coerceCfnInteger(entry["Dimensions"]) ?? entry["Dimensions"];
|
|
11864
|
+
if (entry["SearchSchema"] !== void 0) out["SearchSchema"] = entry["SearchSchema"];
|
|
11865
|
+
return out;
|
|
11866
|
+
}
|
|
11867
|
+
function vectorIndexesForCreate(value) {
|
|
11868
|
+
if (value === void 0 || value === null) return void 0;
|
|
11869
|
+
if (!Array.isArray(value)) return value;
|
|
11870
|
+
return value.map((entry) => typeof entry === "object" && entry !== null && !Array.isArray(entry) ? vectorIndexForSend(entry) : entry);
|
|
11871
|
+
}
|
|
11872
|
+
function sortedByJson(list) {
|
|
11873
|
+
if (!Array.isArray(list)) return list;
|
|
11874
|
+
return [...list].sort((a, b) => {
|
|
11875
|
+
const x = JSON.stringify(a) ?? "";
|
|
11876
|
+
const y = JSON.stringify(b) ?? "";
|
|
11877
|
+
return x < y ? -1 : x > y ? 1 : 0;
|
|
11878
|
+
});
|
|
11879
|
+
}
|
|
11880
|
+
function vectorIndexKey(entry) {
|
|
11881
|
+
const e = entry;
|
|
11882
|
+
const projection = e["Projection"];
|
|
11883
|
+
const normalizedProjection = typeof projection === "object" && projection !== null && !Array.isArray(projection) ? {
|
|
11884
|
+
ProjectionType: projection["ProjectionType"],
|
|
11885
|
+
NonKeyAttributes: sortedByJson(nonEmpty(projection["NonKeyAttributes"]))
|
|
11886
|
+
} : projection;
|
|
11887
|
+
const attribute = e["VectorAttribute"];
|
|
11888
|
+
return JSON.stringify([
|
|
11889
|
+
e["IndexName"],
|
|
11890
|
+
typeof attribute === "object" && attribute !== null ? attribute["AttributeName"] : attribute,
|
|
11891
|
+
coerceCfnInteger(e["Dimensions"]) ?? e["Dimensions"],
|
|
11892
|
+
e["DistanceFunction"],
|
|
11893
|
+
normalizedProjection,
|
|
11894
|
+
sortedByJson(Array.isArray(e["SearchSchema"]) && e["SearchSchema"].length > 0 ? e["SearchSchema"].map((s) => typeof s === "object" && s !== null ? {
|
|
11895
|
+
AttributeName: s["AttributeName"],
|
|
11896
|
+
SearchSchemaElementType: s["SearchSchemaElementType"]
|
|
11897
|
+
} : s) : nonEmpty(e["SearchSchema"]))
|
|
11898
|
+
]);
|
|
11899
|
+
}
|
|
11900
|
+
function nonEmpty(value) {
|
|
11901
|
+
return Array.isArray(value) && value.length === 0 ? void 0 : value;
|
|
11902
|
+
}
|
|
11903
|
+
function planVectorIndexUpdates(previous, desired, live) {
|
|
11904
|
+
const prevByName = vectorIndexesByName(previous);
|
|
11905
|
+
const desiredByName = vectorIndexesByName(desired);
|
|
11906
|
+
const liveByName = live === void 0 ? void 0 : new Map(live.filter((d) => typeof d.IndexName === "string").map((d) => [d.IndexName, d]));
|
|
11907
|
+
const plan = {
|
|
11908
|
+
ops: [],
|
|
11909
|
+
changed: [],
|
|
11910
|
+
adopted: [],
|
|
11911
|
+
alreadyGone: []
|
|
11912
|
+
};
|
|
11913
|
+
const liveHolds = (name, entry) => {
|
|
11914
|
+
const l = liveByName?.get(name);
|
|
11915
|
+
return l !== void 0 && l.IndexStatus !== "DELETING" && vectorIndexKey(l) === vectorIndexKey(entry);
|
|
11916
|
+
};
|
|
11917
|
+
for (const name of prevByName.keys()) {
|
|
11918
|
+
if (desiredByName.has(name)) continue;
|
|
11919
|
+
const l = liveByName?.get(name);
|
|
11920
|
+
if (liveByName !== void 0 && (l === void 0 || l.IndexStatus === "DELETING")) {
|
|
11921
|
+
plan.alreadyGone.push(name);
|
|
11922
|
+
continue;
|
|
11923
|
+
}
|
|
11924
|
+
plan.ops.push({ Delete: { IndexName: name } });
|
|
11925
|
+
}
|
|
11926
|
+
for (const [name, entry] of desiredByName) {
|
|
11927
|
+
const before = prevByName.get(name);
|
|
11928
|
+
if (before === void 0) {
|
|
11929
|
+
const l = liveByName?.get(name);
|
|
11930
|
+
if (l === void 0 || l.IndexStatus === "DELETING") plan.ops.push({ Create: vectorIndexForSend(entry) });
|
|
11931
|
+
else if (liveHolds(name, entry)) plan.adopted.push(name);
|
|
11932
|
+
else plan.changed.push(name);
|
|
11933
|
+
continue;
|
|
11934
|
+
}
|
|
11935
|
+
if (vectorIndexKey(before) === vectorIndexKey(entry)) continue;
|
|
11936
|
+
if (!liveHolds(name, entry)) plan.changed.push(name);
|
|
11937
|
+
}
|
|
11938
|
+
return plan;
|
|
11939
|
+
}
|
|
11940
|
+
function readbackVectorIndexes(live) {
|
|
11941
|
+
if (live === void 0 || live.length === 0) return void 0;
|
|
11942
|
+
return live.map((d) => {
|
|
11943
|
+
const out = {};
|
|
11944
|
+
if (d.IndexName !== void 0) out["IndexName"] = d.IndexName;
|
|
11945
|
+
if (d.VectorAttribute !== void 0) out["VectorAttribute"] = d.VectorAttribute;
|
|
11946
|
+
if (d.Dimensions !== void 0) out["Dimensions"] = d.Dimensions;
|
|
11947
|
+
if (d.DistanceFunction !== void 0) out["DistanceFunction"] = d.DistanceFunction;
|
|
11948
|
+
if (d.Projection !== void 0) out["Projection"] = d.Projection;
|
|
11949
|
+
if (d.SearchSchema !== void 0 && d.SearchSchema.length > 0) out["SearchSchema"] = d.SearchSchema;
|
|
11950
|
+
return out;
|
|
11951
|
+
});
|
|
11952
|
+
}
|
|
11953
|
+
function vectorIndexesSettled(live) {
|
|
11954
|
+
return (live ?? []).every((d) => d.IndexStatus === void 0 || d.IndexStatus === "ACTIVE");
|
|
11955
|
+
}
|
|
11956
|
+
|
|
11742
11957
|
//#endregion
|
|
11743
11958
|
//#region src/provisioning/providers/dynamodb-table-provider.ts
|
|
11744
11959
|
function isTableName(id) {
|
|
@@ -12150,6 +12365,10 @@ const tableNameReleaseWait = {
|
|
|
12150
12365
|
maxPolls: 600,
|
|
12151
12366
|
intervalMs: INDEX_SETTLE_POLL_INTERVAL_MS
|
|
12152
12367
|
};
|
|
12368
|
+
const tableDeleteGoneWait = {
|
|
12369
|
+
maxWaitMs: 600 * DYNAMODB_DELETE_POLL_COST_MS,
|
|
12370
|
+
pollIntervalMs: INDEX_SETTLE_POLL_INTERVAL_MS
|
|
12371
|
+
};
|
|
12153
12372
|
var DynamoDBTableProvider = class {
|
|
12154
12373
|
dynamoDBClient;
|
|
12155
12374
|
createClient;
|
|
@@ -12161,7 +12380,7 @@ var DynamoDBTableProvider = class {
|
|
|
12161
12380
|
if (!failure.redacted) return wrapMaskedAwsError(m, error, build);
|
|
12162
12381
|
this.logger.debug(m(build(m(failure.detail)).message));
|
|
12163
12382
|
const relay = isAuxiliaryFailure(error) ? "" : relayedNameCollision(failure.detail);
|
|
12164
|
-
const wrapped = build(`${m(failure.summary)}${relay}${relayedIndexBusyDelete(failure.detail)}`);
|
|
12383
|
+
const wrapped = build(`${m(failure.summary)}${relay}${relayedIndexBusyDelete(failure.detail, TABLE_INDEX_NOUN)}`);
|
|
12165
12384
|
return error instanceof Error ? markRedactedCause(wrapped) : wrapped;
|
|
12166
12385
|
}
|
|
12167
12386
|
handledProperties = /* @__PURE__ */ new Map([["AWS::DynamoDB::Table", /* @__PURE__ */ new Set([
|
|
@@ -12183,7 +12402,8 @@ var DynamoDBTableProvider = class {
|
|
|
12183
12402
|
"TimeToLiveSpecification",
|
|
12184
12403
|
"ResourcePolicy",
|
|
12185
12404
|
"KinesisStreamSpecification",
|
|
12186
|
-
"ContributorInsightsSpecification"
|
|
12405
|
+
"ContributorInsightsSpecification",
|
|
12406
|
+
"VectorIndexes"
|
|
12187
12407
|
])]]);
|
|
12188
12408
|
unhandledByDesign = /* @__PURE__ */ new Map([["AWS::DynamoDB::Table", /* @__PURE__ */ new Map([["ImportSourceSpecification", "S3 import uses the separate ImportTable API (not CreateTable) and is create-only with no readback; deferred to a dedicated import-from-S3 PR"]])]]);
|
|
12189
12409
|
deleteBudgets = new ElapsedBudgetRegistry();
|
|
@@ -12257,6 +12477,8 @@ var DynamoDBTableProvider = class {
|
|
|
12257
12477
|
const declaredGsis = properties["GlobalSecondaryIndexes"];
|
|
12258
12478
|
createParams.GlobalSecondaryIndexes = Array.isArray(declaredGsis) ? declaredGsis.map((entry) => this.coerceIndexThroughputForCreate(logicalId, stripIndexContributorInsights(entry), maskSecrets)) : declaredGsis;
|
|
12259
12479
|
}
|
|
12480
|
+
const createVectorIndexes = vectorIndexesForCreate(properties["VectorIndexes"]);
|
|
12481
|
+
if (createVectorIndexes !== void 0) createParams.VectorIndexes = createVectorIndexes;
|
|
12260
12482
|
if (properties["LocalSecondaryIndexes"]) createParams.LocalSecondaryIndexes = properties["LocalSecondaryIndexes"];
|
|
12261
12483
|
const sseCreateRefusal = sseSpecificationRefusal(properties["SSESpecification"], logicalId);
|
|
12262
12484
|
if (sseCreateRefusal !== void 0 && context?.replayingState !== true) throw new ProvisioningError(`${maskSecrets(sseCreateRefusal)}. Nothing was created; fix the template value`, resourceType, logicalId);
|
|
@@ -12280,8 +12502,13 @@ var DynamoDBTableProvider = class {
|
|
|
12280
12502
|
const createOut = await (await this.getCreateClient()).send(new CreateTableCommand(createParams));
|
|
12281
12503
|
tableCreated = true;
|
|
12282
12504
|
createdTableId = createOut?.TableDescription?.TableId;
|
|
12283
|
-
|
|
12284
|
-
|
|
12505
|
+
reportCreatedResource(logicalId, resourceType, tableName, createdTableId);
|
|
12506
|
+
debug(`CreateTable initiated for ${tableName}, waiting for ACTIVE status`);
|
|
12507
|
+
const tableInfo = await timePhase("provider waits", "DynamoDB table: wait for ACTIVE", () => this.waitForTableActive(tableName, maskSecrets), logicalId);
|
|
12508
|
+
if (createVectorIndexes !== void 0) await timePhase("provider waits", "DynamoDB table: wait for vector indexes", () => this.waitForTableAndIndexesActive(tableName, void 0, {
|
|
12509
|
+
after: "CreateTable",
|
|
12510
|
+
maskSecrets
|
|
12511
|
+
}), logicalId);
|
|
12285
12512
|
await this.applyPointInTimeRecovery(tableName, properties["PointInTimeRecoverySpecification"], void 0, maskSecrets);
|
|
12286
12513
|
await this.applyTimeToLive(tableName, properties["TimeToLiveSpecification"], void 0, "create", {
|
|
12287
12514
|
logicalId,
|
|
@@ -12292,7 +12519,7 @@ var DynamoDBTableProvider = class {
|
|
|
12292
12519
|
await this.applyContributorInsights(tableName, properties["ContributorInsightsSpecification"], void 0, maskSecrets);
|
|
12293
12520
|
await this.applyIndexContributorInsights(tableName, properties["GlobalSecondaryIndexes"], void 0, maskSecrets);
|
|
12294
12521
|
await this.applyStreamMembers(logicalId, resourceType, tableName, tableInfo.streamArn, properties["StreamSpecification"], void 0, true, maskSecrets);
|
|
12295
|
-
|
|
12522
|
+
debug(`Successfully created DynamoDB table ${logicalId}: ${tableName}`);
|
|
12296
12523
|
return {
|
|
12297
12524
|
physicalId: tableName,
|
|
12298
12525
|
attributes: {
|
|
@@ -12306,7 +12533,8 @@ var DynamoDBTableProvider = class {
|
|
|
12306
12533
|
let tableLeftBehind = false;
|
|
12307
12534
|
if (tableCreated) {
|
|
12308
12535
|
try {
|
|
12309
|
-
await this.
|
|
12536
|
+
await this.rollBackCreatedTable(logicalId, tableName, maskSecrets);
|
|
12537
|
+
retractCreatedResource(logicalId, resourceType, tableName);
|
|
12310
12538
|
debug(`Rolled back partially-created DynamoDB table ${tableName}`);
|
|
12311
12539
|
} catch (cleanupError) {
|
|
12312
12540
|
tableLeftBehind = true;
|
|
@@ -12323,6 +12551,38 @@ var DynamoDBTableProvider = class {
|
|
|
12323
12551
|
throw thrown;
|
|
12324
12552
|
}
|
|
12325
12553
|
}
|
|
12554
|
+
async rollBackCreatedTable(logicalId, tableName, maskSecrets) {
|
|
12555
|
+
const logger = maskedLogger(this.logger, maskSecrets, tableName);
|
|
12556
|
+
const allowanceMs = Math.min(resolveDynamoDbDeleteBudgetMs(), enclosingDeadlineRemainingMs() - DYNAMODB_DELETE_DEADLINE_MARGIN_MS);
|
|
12557
|
+
const budget = allowanceMs > 0 ? new ElapsedBudget(allowanceMs, resolveDynamoDbDeleteBudgetClock()) : void 0;
|
|
12558
|
+
await deleteTableWithIndexBusyRetry({
|
|
12559
|
+
logicalId,
|
|
12560
|
+
physicalId: tableName,
|
|
12561
|
+
typeLabel: "table",
|
|
12562
|
+
indexNoun: TABLE_INDEX_NOUN,
|
|
12563
|
+
maxRetries: 14,
|
|
12564
|
+
logger,
|
|
12565
|
+
deleteTable: async () => {
|
|
12566
|
+
await this.dynamoDBClient.send(new DeleteTableCommand({ TableName: tableName }));
|
|
12567
|
+
},
|
|
12568
|
+
reArm: () => {
|
|
12569
|
+
const wait = beginDeleteWait(900, budget);
|
|
12570
|
+
return waitForIndexesSettled({
|
|
12571
|
+
tableName,
|
|
12572
|
+
logicalId,
|
|
12573
|
+
logger,
|
|
12574
|
+
describeTable: () => this.dynamoDBClient.send(new DescribeTableCommand({ TableName: tableName })),
|
|
12575
|
+
maxAttempts: wait.grantedPolls,
|
|
12576
|
+
budgetWait: wait,
|
|
12577
|
+
shortCapUnlessVectorBusy: 60,
|
|
12578
|
+
proceedNote: DELETE_INDEX_WAIT_PROCEED_NOTE
|
|
12579
|
+
});
|
|
12580
|
+
},
|
|
12581
|
+
shouldKeepRetrying: () => budget !== void 0 && !budget.isExhausted(),
|
|
12582
|
+
retryWarning: () => `DynamoDB table ${logicalId}: AWS refused the DeleteTable rolling back the partially-created table ${tableName} because ${TABLE_INDEX_NOUN} is still being created, updated or deleted. Waiting for the indexes to settle and retrying (up to ${14} retries in all, within ~${Math.max(1, Math.round((budget?.totalMs ?? 0) / 6e4))} minutes).`,
|
|
12583
|
+
sleepSeam: deleteTableRetryDelays
|
|
12584
|
+
});
|
|
12585
|
+
}
|
|
12326
12586
|
async update(logicalId, physicalId, resourceType, properties, previousProperties, context) {
|
|
12327
12587
|
const markUnsettled = (key) => context?.markUnsettled?.(key);
|
|
12328
12588
|
const maskSecrets = context?.maskSecrets ?? ((text) => text);
|
|
@@ -12367,10 +12627,19 @@ var DynamoDBTableProvider = class {
|
|
|
12367
12627
|
if (context?.replayingState !== true && context?.desiredFromAwsReadback !== true) throw new ProvisioningError(`${lsiMessage}. Nothing was applied to the table; revert the LocalSecondaryIndexes change, or create a new table under a new logical ID (a new table starts empty)`, resourceType, logicalId, physicalId);
|
|
12368
12628
|
warn(`${lsiMessage}; the LocalSecondaryIndexes change was not applied`);
|
|
12369
12629
|
}
|
|
12630
|
+
const vectorIndexPlan = JSON.stringify(properties["VectorIndexes"]) !== JSON.stringify(previousProperties["VectorIndexes"]) ? planVectorIndexUpdates(previousProperties["VectorIndexes"], properties["VectorIndexes"], table?.VectorIndexes ?? (table === void 0 ? void 0 : [])) : void 0;
|
|
12631
|
+
if (vectorIndexPlan !== void 0 && vectorIndexPlan.changed.length > 0) {
|
|
12632
|
+
const vectorMessage = `AWS::DynamoDB::Table ${logicalId}: VectorIndexes ${vectorIndexPlan.changed.map((n) => maskSecrets(n)).join(", ")} changed definition, which DynamoDB cannot modify in place`;
|
|
12633
|
+
if (context?.replayingState !== true && context?.desiredFromAwsReadback !== true) throw new ProvisioningError(`${maskSecrets(vectorMessage)}. Nothing was applied to the table; rename the index (so it is dropped and re-created) or revert the change`, resourceType, logicalId, physicalId);
|
|
12634
|
+
warn(`${vectorMessage}; that change was not applied`);
|
|
12635
|
+
}
|
|
12370
12636
|
let latestStreamArn = table?.LatestStreamArn;
|
|
12371
12637
|
if (table?.TableArn) await this.applyTagDiff(table.TableArn, resourceType, logicalId, previousProperties["Tags"], properties["Tags"], {
|
|
12372
12638
|
forceUpsert: context?.unsettledProperties?.has("Tags") === true,
|
|
12373
|
-
beforeWrite: () => markUnsettled("Tags")
|
|
12639
|
+
beforeWrite: () => markUnsettled("Tags"),
|
|
12640
|
+
afterAdded: (keys) => {
|
|
12641
|
+
if (keys.length > 0) context?.markAttempted?.("Tags", keys);
|
|
12642
|
+
}
|
|
12374
12643
|
});
|
|
12375
12644
|
const normalizeTableClass = (v) => typeof v === "string" && v.length > 0 ? v : "STANDARD";
|
|
12376
12645
|
const tableClassChanged = normalizeTableClass(properties["TableClass"]) !== normalizeTableClass(previousProperties["TableClass"]);
|
|
@@ -12482,7 +12751,7 @@ var DynamoDBTableProvider = class {
|
|
|
12482
12751
|
if (tableClassChanged) markUnsettled("TableClass");
|
|
12483
12752
|
if (updateInput.GlobalSecondaryIndexUpdates !== void 0) markUnsettled("GlobalSecondaryIndexes");
|
|
12484
12753
|
await this.dynamoDBClient.send(new UpdateTableCommand(updateInput));
|
|
12485
|
-
if (billingMode !== liveBillingMode) await this.waitForTableAndIndexesActive(physicalId, BILLING_FLIP_ACTIVE_WAIT_ATTEMPTS);
|
|
12754
|
+
if (billingMode !== liveBillingMode) await this.waitForTableAndIndexesActive(physicalId, BILLING_FLIP_ACTIVE_WAIT_ATTEMPTS, { maskSecrets });
|
|
12486
12755
|
else await this.waitForTableActiveAfterUpdate(physicalId, 60);
|
|
12487
12756
|
this.logger.debug(`Updated BillingMode/ProvisionedThroughput/TableClass on DynamoDB table ${physicalId}`);
|
|
12488
12757
|
}
|
|
@@ -12595,8 +12864,9 @@ var DynamoDBTableProvider = class {
|
|
|
12595
12864
|
if (context?.unsettledProperties?.has("GlobalSecondaryIndexes") === true && currentLiveIndexNames !== void 0) this.warnUndeclaredLiveIndexes(physicalId, currentLiveIndexNames, [previousProperties["GlobalSecondaryIndexes"], properties["GlobalSecondaryIndexes"]], maskSecrets);
|
|
12596
12865
|
if (JSON.stringify(properties["GlobalSecondaryIndexes"]) !== JSON.stringify(previousProperties["GlobalSecondaryIndexes"])) {
|
|
12597
12866
|
markUnsettled("GlobalSecondaryIndexes");
|
|
12598
|
-
await this.applyGsiUpdates(physicalId, resourceType, logicalId, previousProperties["GlobalSecondaryIndexes"], properties["GlobalSecondaryIndexes"], properties["AttributeDefinitions"], gsiHandledByBillingFlip, currentLiveIndexNames, currentLiveIndexByName, liveCapacityComparable, effectiveBillingMode === "PAY_PER_REQUEST", maskSecrets);
|
|
12867
|
+
await this.applyGsiUpdates(physicalId, resourceType, logicalId, previousProperties["GlobalSecondaryIndexes"], properties["GlobalSecondaryIndexes"], properties["AttributeDefinitions"], gsiHandledByBillingFlip, currentLiveIndexNames, currentLiveIndexByName, liveCapacityComparable, effectiveBillingMode === "PAY_PER_REQUEST", maskSecrets, (indexName) => context?.markAttempted?.("GlobalSecondaryIndexes", [indexName]));
|
|
12599
12868
|
}
|
|
12869
|
+
if (vectorIndexPlan !== void 0) await this.applyVectorIndexUpdates(physicalId, vectorIndexPlan, properties["AttributeDefinitions"], maskSecrets, () => markUnsettled("VectorIndexes"), (indexName) => context?.markAttempted?.("VectorIndexes", [indexName]));
|
|
12600
12870
|
if (JSON.stringify(properties["PointInTimeRecoverySpecification"]) !== JSON.stringify(previousProperties["PointInTimeRecoverySpecification"])) {
|
|
12601
12871
|
markUnsettled("PointInTimeRecoverySpecification");
|
|
12602
12872
|
await this.applyPointInTimeRecovery(physicalId, properties["PointInTimeRecoverySpecification"], previousProperties["PointInTimeRecoverySpecification"], maskSecrets);
|
|
@@ -12712,16 +12982,18 @@ var DynamoDBTableProvider = class {
|
|
|
12712
12982
|
}
|
|
12713
12983
|
try {
|
|
12714
12984
|
const reArmPolls = () => {
|
|
12715
|
-
const wait = beginDeleteWait(
|
|
12985
|
+
const wait = beginDeleteWait(900, budget);
|
|
12716
12986
|
return {
|
|
12717
12987
|
maxAttempts: wait.grantedPolls,
|
|
12718
|
-
budgetWait: wait
|
|
12988
|
+
budgetWait: wait,
|
|
12989
|
+
shortCapUnlessVectorBusy: 60
|
|
12719
12990
|
};
|
|
12720
12991
|
};
|
|
12721
12992
|
await deleteTableWithIndexBusyRetry({
|
|
12722
12993
|
logicalId,
|
|
12723
12994
|
physicalId,
|
|
12724
12995
|
typeLabel: "table",
|
|
12996
|
+
indexNoun: TABLE_INDEX_NOUN,
|
|
12725
12997
|
maxRetries: 14,
|
|
12726
12998
|
logger: loopLogger,
|
|
12727
12999
|
deleteTable: async () => {
|
|
@@ -12743,6 +13015,22 @@ var DynamoDBTableProvider = class {
|
|
|
12743
13015
|
},
|
|
12744
13016
|
sleepSeam: deleteTableRetryDelays
|
|
12745
13017
|
});
|
|
13018
|
+
const mask = maskerOrIdentity(context?.maskSecrets);
|
|
13019
|
+
await waitForGoneAfterDelete({
|
|
13020
|
+
what: mask(`DynamoDB table ${physicalId}`),
|
|
13021
|
+
resourceType,
|
|
13022
|
+
describe: async () => {
|
|
13023
|
+
try {
|
|
13024
|
+
return (await this.dynamoDBClient.send(new DescribeTableCommand({ TableName: physicalId }))).Table?.TableStatus ?? "UNKNOWN";
|
|
13025
|
+
} catch (describeError) {
|
|
13026
|
+
if (describeError instanceof ResourceNotFoundException$1) return void 0;
|
|
13027
|
+
throw describeError;
|
|
13028
|
+
}
|
|
13029
|
+
},
|
|
13030
|
+
logger: loopLogger,
|
|
13031
|
+
pollIntervalMs: tableDeleteGoneWait.pollIntervalMs,
|
|
13032
|
+
maxWaitMs: Math.min(tableDeleteGoneWait.maxWaitMs, budget.remainingMs())
|
|
13033
|
+
});
|
|
12746
13034
|
this.logger.debug(`Successfully deleted DynamoDB table ${logicalId}`);
|
|
12747
13035
|
this.deleteBudgets.release(deleteBudgetKey(physicalId, context?.expectedRegion));
|
|
12748
13036
|
this.protectionFlips.release(deleteBudgetKey(physicalId, context?.expectedRegion));
|
|
@@ -12786,6 +13074,13 @@ var DynamoDBTableProvider = class {
|
|
|
12786
13074
|
ResourceArn: tableArn,
|
|
12787
13075
|
Tags: tagsToAdd
|
|
12788
13076
|
}));
|
|
13077
|
+
let recordedKeys;
|
|
13078
|
+
try {
|
|
13079
|
+
recordedKeys = /* @__PURE__ */ new Set([...planTagDiff(void 0, oldTagsRaw).set.keys()]);
|
|
13080
|
+
} catch {
|
|
13081
|
+
recordedKeys = void 0;
|
|
13082
|
+
}
|
|
13083
|
+
unsettled.afterAdded?.(tagsToAdd.map((t) => t.Key).filter((key) => recordedKeys !== void 0 && !recordedKeys.has(key)));
|
|
12789
13084
|
this.logger.debug(`Added/updated ${tagsToAdd.length} tag(s) on DynamoDB table ${tableArn}`);
|
|
12790
13085
|
}
|
|
12791
13086
|
}
|
|
@@ -13090,7 +13385,7 @@ var DynamoDBTableProvider = class {
|
|
|
13090
13385
|
const warn = (message) => this.logger.warn(maskSecrets(message));
|
|
13091
13386
|
const ops = planIndexContributorInsightsOps(desiredIndexes, previousIndexes, (indexName, reason) => warn(`${this.indexScopeAt(indexName, tableName, maskSecrets)}: ${reason}, so its Contributor Insights was left as it is. Fix the template value and re-deploy.`));
|
|
13092
13387
|
if (ops.length === 0) return;
|
|
13093
|
-
await this.waitForTableAndIndexesActive(tableName);
|
|
13388
|
+
await this.waitForTableAndIndexesActive(tableName, void 0, { maskSecrets });
|
|
13094
13389
|
for (const op of ops) {
|
|
13095
13390
|
beforeSend();
|
|
13096
13391
|
await this.sendContributorInsightsOp(tableName, op, maskSecrets);
|
|
@@ -13107,11 +13402,11 @@ var DynamoDBTableProvider = class {
|
|
|
13107
13402
|
})), `set ContributorInsights on ${target}`);
|
|
13108
13403
|
debug(`Set ContributorInsightsAction=${op.action}${op.mode !== void 0 ? ` Mode=${op.mode}` : ""} on ${target}`);
|
|
13109
13404
|
}
|
|
13110
|
-
async waitForTableActive(tableName, maxAttempts = 60) {
|
|
13405
|
+
async waitForTableActive(tableName, maskSecrets, maxAttempts = 60) {
|
|
13111
13406
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
13112
13407
|
const response = await this.dynamoDBClient.send(new DescribeTableCommand({ TableName: tableName }));
|
|
13113
13408
|
const status = response.Table?.TableStatus;
|
|
13114
|
-
this.logger.debug(`Table ${tableName} status: ${status} (attempt ${attempt}/${maxAttempts})`);
|
|
13409
|
+
this.logger.debug(maskSecrets(`Table ${tableName} status: ${status} (attempt ${attempt}/${maxAttempts})`));
|
|
13115
13410
|
if (status === "ACTIVE") return {
|
|
13116
13411
|
tableArn: response.Table?.TableArn,
|
|
13117
13412
|
tableId: response.Table?.TableId,
|
|
@@ -13149,17 +13444,38 @@ var DynamoDBTableProvider = class {
|
|
|
13149
13444
|
}
|
|
13150
13445
|
throw new Error(maskSecrets(`DynamoDB table ${tableName} was still ${last ?? "unread"} ${KINESIS_DESTINATION_SETTLE_POLLS * KINESIS_DESTINATION_SETTLE_POLL_MS / 1e3} seconds after its encryption change`));
|
|
13151
13446
|
}
|
|
13152
|
-
async waitForTableAndIndexesActive(tableName, maxAttempts = 1800) {
|
|
13447
|
+
async waitForTableAndIndexesActive(tableName, maxAttempts = 1800, opts = {}) {
|
|
13153
13448
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
13154
13449
|
const table = (await this.dynamoDBClient.send(new DescribeTableCommand({ TableName: tableName }))).Table;
|
|
13155
13450
|
const tableActive = table?.TableStatus === "ACTIVE";
|
|
13156
13451
|
const indexesActive = (table?.GlobalSecondaryIndexes ?? []).every((gsi) => gsi.IndexStatus === "ACTIVE");
|
|
13157
|
-
if (tableActive && indexesActive) return;
|
|
13452
|
+
if (tableActive && indexesActive && vectorIndexesSettled(table?.VectorIndexes)) return;
|
|
13158
13453
|
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
13159
13454
|
}
|
|
13160
|
-
|
|
13455
|
+
const m = maskerOrIdentity(opts.maskSecrets);
|
|
13456
|
+
throw new Error(m(`Table ${m(tableName)} and its indexes did not reach ACTIVE within ${maxAttempts} seconds after ${opts.after ?? "UpdateTable"}`));
|
|
13457
|
+
}
|
|
13458
|
+
async applyVectorIndexUpdates(physicalId, plan, desiredAttributeDefinitions, maskSecrets, beforeFirstOp, onCreated) {
|
|
13459
|
+
const debug = (message) => this.logger.debug(maskSecrets(message));
|
|
13460
|
+
const warn = (message) => this.logger.warn(maskSecrets(message));
|
|
13461
|
+
for (const name of plan.alreadyGone) debug(`${this.vectorIndexScopeAt(name, physicalId, maskSecrets)} is recorded in cdkd state but not live; skipping its Delete (already removed)`);
|
|
13462
|
+
for (const name of plan.adopted) warn(`${this.vectorIndexScopeAt(name, physicalId, maskSecrets)} already exists in AWS with the declared definition but is absent from cdkd's recorded previous state, so its Create is being skipped. This usually means an earlier deploy created the index and then failed before state was written.`);
|
|
13463
|
+
if (plan.ops.length === 0) return;
|
|
13464
|
+
await this.waitForTableAndIndexesActive(physicalId, void 0, { maskSecrets });
|
|
13465
|
+
beforeFirstOp();
|
|
13466
|
+
for (const op of plan.ops) {
|
|
13467
|
+
const input = {
|
|
13468
|
+
TableName: physicalId,
|
|
13469
|
+
VectorIndexUpdates: [op]
|
|
13470
|
+
};
|
|
13471
|
+
if (op.Create && desiredAttributeDefinitions) input.AttributeDefinitions = desiredAttributeDefinitions;
|
|
13472
|
+
await this.dynamoDBClient.send(new UpdateTableCommand(input));
|
|
13473
|
+
if (op.Create?.IndexName !== void 0) onCreated(op.Create.IndexName);
|
|
13474
|
+
await this.waitForTableAndIndexesActive(physicalId, void 0, { maskSecrets });
|
|
13475
|
+
debug(`${op.Create ? "created" : "deleted"} ` + this.vectorIndexScopeAt(op.Create?.IndexName ?? op.Delete?.IndexName, physicalId, maskSecrets));
|
|
13476
|
+
}
|
|
13161
13477
|
}
|
|
13162
|
-
async applyGsiUpdates(physicalId, resourceType, logicalId, previousGsis, desiredGsis, desiredAttributeDefinitions, handledByBillingFlip, liveIndexNames, liveIndexByName, liveCapacityComparable, onDemandCeilingsSendable, maskSecrets) {
|
|
13478
|
+
async applyGsiUpdates(physicalId, resourceType, logicalId, previousGsis, desiredGsis, desiredAttributeDefinitions, handledByBillingFlip, liveIndexNames, liveIndexByName, liveCapacityComparable, onDemandCeilingsSendable, maskSecrets, onCreated = () => void 0) {
|
|
13163
13479
|
const warn = (message) => this.logger.warn(maskSecrets(message));
|
|
13164
13480
|
const debug = (message) => this.logger.debug(maskSecrets(message));
|
|
13165
13481
|
const prev = previousGsis ?? [];
|
|
@@ -13234,7 +13550,7 @@ var DynamoDBTableProvider = class {
|
|
|
13234
13550
|
}
|
|
13235
13551
|
if (updateHasMember) ops.push({ Update: update });
|
|
13236
13552
|
}
|
|
13237
|
-
await this.runGsiOps(physicalId, ops, desiredAttributeDefinitions, maskSecrets);
|
|
13553
|
+
await this.runGsiOps(physicalId, ops, desiredAttributeDefinitions, maskSecrets, onCreated);
|
|
13238
13554
|
}
|
|
13239
13555
|
coerceWarmThroughputForSend(scope, value, maskSecrets) {
|
|
13240
13556
|
const warn = (message) => this.logger.warn(maskSecrets(message));
|
|
@@ -13261,6 +13577,9 @@ var DynamoDBTableProvider = class {
|
|
|
13261
13577
|
this.logger.warn(maskSecrets(`${this.indexScopeAt(name, physicalId, maskSecrets)} is live, but neither cdkd's record nor the template declares it, so cdkd left it in place while converging the unsettled GlobalSecondaryIndexes (CloudFormation never deletes an index it did not record). It may belong to another tool, or an earlier failed cdkd update may have created it; cdkd cannot tell which. If it should not exist, delete it ` + (secretDerived ? `with an UpdateTable GlobalSecondaryIndexUpdates Delete for the index.` : `with: aws dynamodb update-table --table-name ${physicalId} --global-secondary-index-updates '[{"Delete":{"IndexName":"${name}"}}]' (in the table's region)`)));
|
|
13262
13578
|
}
|
|
13263
13579
|
}
|
|
13580
|
+
vectorIndexScopeAt(indexName, physicalId, maskSecrets) {
|
|
13581
|
+
return `vector index ${typeof indexName === "string" ? maskSecrets(indexName) : "<unnamed>"} on DynamoDB table ${maskSecrets(physicalId)}`;
|
|
13582
|
+
}
|
|
13264
13583
|
indexScopeAt(indexName, physicalId, maskSecrets) {
|
|
13265
13584
|
return `GSI ${typeof indexName === "string" ? maskSecrets(indexName) : "<unnamed>"} on DynamoDB table ${physicalId}`;
|
|
13266
13585
|
}
|
|
@@ -13398,7 +13717,7 @@ var DynamoDBTableProvider = class {
|
|
|
13398
13717
|
}
|
|
13399
13718
|
return sendable;
|
|
13400
13719
|
}
|
|
13401
|
-
async runGsiOps(physicalId, ops, desiredAttributeDefinitions, maskSecrets) {
|
|
13720
|
+
async runGsiOps(physicalId, ops, desiredAttributeDefinitions, maskSecrets, onCreated = () => void 0) {
|
|
13402
13721
|
const debug = (message) => this.logger.debug(maskSecrets(message));
|
|
13403
13722
|
for (const op of ops) {
|
|
13404
13723
|
const input = {
|
|
@@ -13407,7 +13726,8 @@ var DynamoDBTableProvider = class {
|
|
|
13407
13726
|
};
|
|
13408
13727
|
if (op.Create && desiredAttributeDefinitions) input.AttributeDefinitions = desiredAttributeDefinitions;
|
|
13409
13728
|
await this.dynamoDBClient.send(new UpdateTableCommand(input));
|
|
13410
|
-
|
|
13729
|
+
if (op.Create?.IndexName !== void 0) onCreated(op.Create.IndexName);
|
|
13730
|
+
await this.waitForTableAndIndexesActive(physicalId, void 0, { maskSecrets });
|
|
13411
13731
|
debug(`${op.Create ? "created" : op.Delete ? "deleted" : "updated"} ${this.indexScopeAt(op.Create?.IndexName ?? op.Delete?.IndexName ?? op.Update?.IndexName, physicalId, maskSecrets)}`);
|
|
13412
13732
|
}
|
|
13413
13733
|
}
|
|
@@ -13469,7 +13789,8 @@ var DynamoDBTableProvider = class {
|
|
|
13469
13789
|
return [
|
|
13470
13790
|
"AttributeDefinitions",
|
|
13471
13791
|
"GlobalSecondaryIndexes[]",
|
|
13472
|
-
"LocalSecondaryIndexes[]"
|
|
13792
|
+
"LocalSecondaryIndexes[]",
|
|
13793
|
+
"VectorIndexes"
|
|
13473
13794
|
];
|
|
13474
13795
|
}
|
|
13475
13796
|
getDriftUnknownPaths(resourceType, properties) {
|
|
@@ -13547,15 +13868,19 @@ var DynamoDBTableProvider = class {
|
|
|
13547
13868
|
aws
|
|
13548
13869
|
};
|
|
13549
13870
|
}
|
|
13550
|
-
async readUnsettled(physicalId, logicalId, resourceType, names, recordedProperties, desiredProperties) {
|
|
13871
|
+
async readUnsettled(physicalId, logicalId, resourceType, names, recordedProperties, desiredProperties, attemptedItems) {
|
|
13551
13872
|
const live = await this.readCurrentState(physicalId, logicalId, resourceType, recordedProperties);
|
|
13552
13873
|
if (typeof live !== "object" || live === null) return live;
|
|
13553
13874
|
const out = { ...live };
|
|
13554
13875
|
if (out["BillingMode"] === "PAY_PER_REQUEST") delete out["ProvisionedThroughput"];
|
|
13555
13876
|
if (names.has("GlobalSecondaryIndexes")) {
|
|
13556
|
-
out["GlobalSecondaryIndexes"] = projectIndexesOnto(out["GlobalSecondaryIndexes"], recordedProperties?.["GlobalSecondaryIndexes"], desiredProperties?.["GlobalSecondaryIndexes"]);
|
|
13877
|
+
out["GlobalSecondaryIndexes"] = projectIndexesOnto(out["GlobalSecondaryIndexes"], recordedProperties?.["GlobalSecondaryIndexes"], desiredProperties?.["GlobalSecondaryIndexes"], attemptedItems?.get("GlobalSecondaryIndexes"));
|
|
13557
13878
|
if (out["GlobalSecondaryIndexes"] === void 0) delete out["GlobalSecondaryIndexes"];
|
|
13558
13879
|
}
|
|
13880
|
+
if (names.has("VectorIndexes")) {
|
|
13881
|
+
out["VectorIndexes"] = projectIndexesOnto(out["VectorIndexes"], recordedProperties?.["VectorIndexes"], desiredProperties?.["VectorIndexes"], attemptedItems?.get("VectorIndexes"));
|
|
13882
|
+
if (out["VectorIndexes"] === void 0) delete out["VectorIndexes"];
|
|
13883
|
+
}
|
|
13559
13884
|
const strict = async (key, read) => {
|
|
13560
13885
|
if (!names.has(key)) return;
|
|
13561
13886
|
const value = await read();
|
|
@@ -13644,6 +13969,8 @@ var DynamoDBTableProvider = class {
|
|
|
13644
13969
|
const desiredByName = desiredIndexEntriesByName(properties?.["LocalSecondaryIndexes"]);
|
|
13645
13970
|
result["LocalSecondaryIndexes"] = table.LocalSecondaryIndexes.map((live) => reverseMapSecondaryIndex(live, live.IndexName === void 0 ? void 0 : desiredByName.get(live.IndexName), bagInformative));
|
|
13646
13971
|
}
|
|
13972
|
+
const liveVectorIndexes = readbackVectorIndexes(table.VectorIndexes);
|
|
13973
|
+
if (liveVectorIndexes !== void 0) result["VectorIndexes"] = liveVectorIndexes;
|
|
13647
13974
|
if (table.SSEDescription?.Status === "ENABLED") {
|
|
13648
13975
|
const sse = { SSEEnabled: true };
|
|
13649
13976
|
if (table.SSEDescription.KMSMasterKeyArn !== void 0) sse["KMSMasterKeyId"] = table.SSEDescription.KMSMasterKeyArn;
|
|
@@ -13870,9 +14197,9 @@ var DynamoDBTableProvider = class {
|
|
|
13870
14197
|
function isTransientStreamReadFailure(err) {
|
|
13871
14198
|
return isThrottlingError(err) || isTransientServerError(err) || isAmbiguousOutcomeError(err) || err instanceof ResourceNotFoundException$1;
|
|
13872
14199
|
}
|
|
13873
|
-
function projectIndexesOnto(live, recorded, desired) {
|
|
14200
|
+
function projectIndexesOnto(live, recorded, desired, attempted = /* @__PURE__ */ new Set()) {
|
|
13874
14201
|
if (!Array.isArray(live)) return void 0;
|
|
13875
|
-
const named =
|
|
14202
|
+
const named = new Set([...attempted].filter(isUsableAttemptedName));
|
|
13876
14203
|
for (const list of [recorded, desired]) {
|
|
13877
14204
|
if (!Array.isArray(list)) continue;
|
|
13878
14205
|
for (const entry of list) {
|
|
@@ -13928,7 +14255,7 @@ var LogsLogGroupProvider = class {
|
|
|
13928
14255
|
"DeletionProtectionEnabled",
|
|
13929
14256
|
"BearerTokenAuthenticationEnabled"
|
|
13930
14257
|
])]]);
|
|
13931
|
-
unhandledByDesign = /* @__PURE__ */ new Map([["AWS::Logs::LogGroup", /* @__PURE__ */ new Map([["ResourcePolicyDocument", "
|
|
14258
|
+
unhandledByDesign = /* @__PURE__ */ new Map([["AWS::Logs::LogGroup", /* @__PURE__ */ new Map([["ResourcePolicyDocument", "not driven by this provider by decision (issue #1412): no CreateLogGroup / PutRetentionPolicy member carries it, and both policy lifecycles — the account-scoped AWS::Logs::ResourcePolicy type and the log-group-scoped logs:PutResourcePolicy (resourceArn + policyScope RESOURCE) — are ones this provider does not take on — routed via Cloud Control, whose handler applies it"]])]]);
|
|
13932
14259
|
constructor() {
|
|
13933
14260
|
const awsClients = getAwsClients();
|
|
13934
14261
|
this.logsClient = awsClients.cloudWatchLogs;
|
|
@@ -13991,6 +14318,7 @@ var LogsLogGroupProvider = class {
|
|
|
13991
14318
|
await this.logsClient.send(new CreateLogGroupCommand(createParams));
|
|
13992
14319
|
createdNewLogGroup = true;
|
|
13993
14320
|
leftBehind = true;
|
|
14321
|
+
reportCreatedResource(logicalId, resourceType, logGroupName);
|
|
13994
14322
|
} catch (createError) {
|
|
13995
14323
|
if (createError instanceof ResourceAlreadyExistsException) this.logger.debug(`Log group ${logGroupName} already exists, using existing`);
|
|
13996
14324
|
else throw createError;
|
|
@@ -14037,6 +14365,7 @@ var LogsLogGroupProvider = class {
|
|
|
14037
14365
|
if (createdNewLogGroup) try {
|
|
14038
14366
|
await this.logsClient.send(new DeleteLogGroupCommand({ logGroupName }));
|
|
14039
14367
|
leftBehind = false;
|
|
14368
|
+
retractCreatedResource(logicalId, resourceType, logGroupName);
|
|
14040
14369
|
this.logger.debug(`Cleaned up partially-created log group ${displaySafe(logicalId)} (${displaySafe(logGroupName)}) after wiring failure`);
|
|
14041
14370
|
} catch (cleanupError) {
|
|
14042
14371
|
const mask = maskerOrIdentity(context?.maskSecrets);
|
|
@@ -14387,6 +14716,29 @@ var LogsLogGroupProvider = class {
|
|
|
14387
14716
|
|
|
14388
14717
|
//#endregion
|
|
14389
14718
|
//#region src/provisioning/providers/cloudwatch-alarm-provider.ts
|
|
14719
|
+
function isDefaultEvaluationWindow(value) {
|
|
14720
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
|
|
14721
|
+
const keys = Object.keys(value);
|
|
14722
|
+
if (keys.length !== 1 || keys[0] !== "SlidingWindow") return false;
|
|
14723
|
+
const sliding = value["SlidingWindow"];
|
|
14724
|
+
return sliding !== null && typeof sliding === "object" && !Array.isArray(sliding) && Object.keys(sliding).length === 0;
|
|
14725
|
+
}
|
|
14726
|
+
const PROMQL_EXCLUDED_MEMBERS = [
|
|
14727
|
+
"Namespace",
|
|
14728
|
+
"MetricName",
|
|
14729
|
+
"Dimensions",
|
|
14730
|
+
"Period",
|
|
14731
|
+
"Unit",
|
|
14732
|
+
"Statistic",
|
|
14733
|
+
"ExtendedStatistic",
|
|
14734
|
+
"Metrics",
|
|
14735
|
+
"Threshold",
|
|
14736
|
+
"ComparisonOperator",
|
|
14737
|
+
"ThresholdMetricId",
|
|
14738
|
+
"EvaluationPeriods",
|
|
14739
|
+
"DatapointsToAlarm",
|
|
14740
|
+
"EvaluationWindow"
|
|
14741
|
+
];
|
|
14390
14742
|
function isAlarmWriteThrottle(error) {
|
|
14391
14743
|
return isThrottlingError(error) || error instanceof Error && error.message.includes("Rate exceeded");
|
|
14392
14744
|
}
|
|
@@ -14422,9 +14774,13 @@ var CloudWatchAlarmProvider = class {
|
|
|
14422
14774
|
"Tags",
|
|
14423
14775
|
"ExtendedStatistic",
|
|
14424
14776
|
"EvaluateLowSampleCountPercentile",
|
|
14425
|
-
"ThresholdMetricId"
|
|
14777
|
+
"ThresholdMetricId",
|
|
14778
|
+
"ActionConfiguration",
|
|
14779
|
+
"WarmUpConfiguration",
|
|
14780
|
+
"EvaluationWindow",
|
|
14781
|
+
"EvaluationCriteria",
|
|
14782
|
+
"EvaluationInterval"
|
|
14426
14783
|
])]]);
|
|
14427
|
-
unhandledByDesign = /* @__PURE__ */ new Map([["AWS::CloudWatch::Alarm", /* @__PURE__ */ new Map([["EvaluationCriteria", "Absent from both the SDK PutMetricAlarm input and the aws-cdk-lib CfnAlarm L1 (a newer CFn-schema-only property ahead of SDK/CDK support); no wire path to forward it and no CDK app can emit it."], ["EvaluationInterval", "Absent from both the SDK PutMetricAlarm input and the aws-cdk-lib CfnAlarm L1 (a newer CFn-schema-only property ahead of SDK/CDK support); no wire path to forward it and no CDK app can emit it."]])]]);
|
|
14428
14784
|
constructor() {
|
|
14429
14785
|
const awsClients = getAwsClients();
|
|
14430
14786
|
this.cloudWatchClient = awsClients.cloudWatch;
|
|
@@ -14573,7 +14929,12 @@ var CloudWatchAlarmProvider = class {
|
|
|
14573
14929
|
Unit: emptyToUndefined(properties["Unit"]),
|
|
14574
14930
|
ExtendedStatistic: emptyToUndefined(properties["ExtendedStatistic"]),
|
|
14575
14931
|
EvaluateLowSampleCountPercentile: emptyToUndefined(properties["EvaluateLowSampleCountPercentile"]),
|
|
14576
|
-
ThresholdMetricId: emptyToUndefined(properties["ThresholdMetricId"])
|
|
14932
|
+
ThresholdMetricId: emptyToUndefined(properties["ThresholdMetricId"]),
|
|
14933
|
+
ActionConfiguration: properties["ActionConfiguration"],
|
|
14934
|
+
WarmUpConfiguration: properties["WarmUpConfiguration"],
|
|
14935
|
+
EvaluationWindow: properties["EvaluationWindow"],
|
|
14936
|
+
EvaluationCriteria: properties["EvaluationCriteria"],
|
|
14937
|
+
EvaluationInterval: properties["EvaluationInterval"]
|
|
14577
14938
|
};
|
|
14578
14939
|
const metricsValue = properties["Metrics"];
|
|
14579
14940
|
if (Array.isArray(metricsValue) && metricsValue.length > 0) params["Metrics"] = metricsValue.map((m) => {
|
|
@@ -14605,6 +14966,7 @@ var CloudWatchAlarmProvider = class {
|
|
|
14605
14966
|
params["Period"] = properties["Period"];
|
|
14606
14967
|
params["Statistic"] = emptyToUndefined(properties["Statistic"]);
|
|
14607
14968
|
params["Dimensions"] = properties["Dimensions"];
|
|
14969
|
+
if (properties["EvaluationCriteria"] !== void 0 && Array.isArray(params["Dimensions"]) && params["Dimensions"].length === 0) delete params["Dimensions"];
|
|
14608
14970
|
}
|
|
14609
14971
|
return params;
|
|
14610
14972
|
}
|
|
@@ -14615,30 +14977,40 @@ var CloudWatchAlarmProvider = class {
|
|
|
14615
14977
|
}))).MetricAlarms?.[0];
|
|
14616
14978
|
if (!alarm) return RESOURCE_NOT_FOUND;
|
|
14617
14979
|
const result = {};
|
|
14980
|
+
const promql = alarm.EvaluationCriteria !== void 0;
|
|
14618
14981
|
if (alarm.AlarmName !== void 0) result["AlarmName"] = alarm.AlarmName;
|
|
14619
14982
|
result["AlarmDescription"] = alarm.AlarmDescription ?? "";
|
|
14620
|
-
|
|
14621
|
-
|
|
14622
|
-
|
|
14623
|
-
|
|
14624
|
-
|
|
14625
|
-
|
|
14626
|
-
|
|
14627
|
-
|
|
14983
|
+
if (!promql) {
|
|
14984
|
+
result["MetricName"] = alarm.MetricName ?? "";
|
|
14985
|
+
result["Namespace"] = alarm.Namespace ?? "";
|
|
14986
|
+
result["Statistic"] = alarm.Statistic ?? "";
|
|
14987
|
+
if (alarm.ComparisonOperator !== void 0) result["ComparisonOperator"] = alarm.ComparisonOperator;
|
|
14988
|
+
if (alarm.Threshold !== void 0) result["Threshold"] = alarm.Threshold;
|
|
14989
|
+
if (alarm.EvaluationPeriods !== void 0) result["EvaluationPeriods"] = alarm.EvaluationPeriods;
|
|
14990
|
+
if (alarm.Period !== void 0) result["Period"] = alarm.Period;
|
|
14991
|
+
if (alarm.DatapointsToAlarm !== void 0) result["DatapointsToAlarm"] = alarm.DatapointsToAlarm;
|
|
14992
|
+
}
|
|
14628
14993
|
result["ActionsEnabled"] = alarm.ActionsEnabled ?? true;
|
|
14629
14994
|
result["AlarmActions"] = alarm.AlarmActions ? [...alarm.AlarmActions] : [];
|
|
14630
14995
|
result["OKActions"] = alarm.OKActions ? [...alarm.OKActions] : [];
|
|
14631
14996
|
result["InsufficientDataActions"] = alarm.InsufficientDataActions ? [...alarm.InsufficientDataActions] : [];
|
|
14632
14997
|
result["TreatMissingData"] = alarm.TreatMissingData ?? "";
|
|
14633
|
-
|
|
14634
|
-
|
|
14635
|
-
|
|
14636
|
-
|
|
14637
|
-
|
|
14638
|
-
|
|
14639
|
-
|
|
14998
|
+
if (!promql) {
|
|
14999
|
+
result["Unit"] = alarm.Unit ?? "";
|
|
15000
|
+
result["Dimensions"] = (alarm.Dimensions ?? []).map((d) => ({
|
|
15001
|
+
...d.Name !== void 0 ? { Name: d.Name } : {},
|
|
15002
|
+
...d.Value !== void 0 ? { Value: d.Value } : {}
|
|
15003
|
+
}));
|
|
15004
|
+
result["Metrics"] = (alarm.Metrics ?? []).map((m) => m);
|
|
15005
|
+
}
|
|
15006
|
+
if (!promql && alarm.ExtendedStatistic !== void 0) result["ExtendedStatistic"] = alarm.ExtendedStatistic;
|
|
14640
15007
|
if (alarm.EvaluateLowSampleCountPercentile !== void 0) result["EvaluateLowSampleCountPercentile"] = alarm.EvaluateLowSampleCountPercentile;
|
|
14641
|
-
if (alarm.ThresholdMetricId !== void 0) result["ThresholdMetricId"] = alarm.ThresholdMetricId;
|
|
15008
|
+
if (!promql && alarm.ThresholdMetricId !== void 0) result["ThresholdMetricId"] = alarm.ThresholdMetricId;
|
|
15009
|
+
if (alarm.ActionConfiguration !== void 0) result["ActionConfiguration"] = alarm.ActionConfiguration;
|
|
15010
|
+
if (alarm.WarmUpConfiguration !== void 0) result["WarmUpConfiguration"] = alarm.WarmUpConfiguration;
|
|
15011
|
+
if (!promql && alarm.EvaluationWindow !== void 0 && !isDefaultEvaluationWindow(alarm.EvaluationWindow)) result["EvaluationWindow"] = alarm.EvaluationWindow;
|
|
15012
|
+
if (alarm.EvaluationCriteria !== void 0) result["EvaluationCriteria"] = alarm.EvaluationCriteria;
|
|
15013
|
+
if (promql && alarm.EvaluationInterval !== void 0) result["EvaluationInterval"] = alarm.EvaluationInterval;
|
|
14642
15014
|
if (alarm.AlarmArn) try {
|
|
14643
15015
|
const tagsResp = await this.cloudWatchClient.send(new ListTagsForResourceCommand$4({ ResourceARN: alarm.AlarmArn }));
|
|
14644
15016
|
result["Tags"] = normalizeAwsTagsToCfn(tagsResp.Tags);
|
|
@@ -14647,6 +15019,26 @@ var CloudWatchAlarmProvider = class {
|
|
|
14647
15019
|
}
|
|
14648
15020
|
return result;
|
|
14649
15021
|
}
|
|
15022
|
+
async canonicalizeDriftPair(resourceType, baseline, aws) {
|
|
15023
|
+
if (resourceType !== "AWS::CloudWatch::Alarm" || !isDefaultEvaluationWindow(baseline["EvaluationWindow"]) || aws["EvaluationWindow"] !== void 0) return {
|
|
15024
|
+
baseline,
|
|
15025
|
+
aws
|
|
15026
|
+
};
|
|
15027
|
+
const trimmed = { ...baseline };
|
|
15028
|
+
delete trimmed["EvaluationWindow"];
|
|
15029
|
+
return {
|
|
15030
|
+
baseline: trimmed,
|
|
15031
|
+
aws
|
|
15032
|
+
};
|
|
15033
|
+
}
|
|
15034
|
+
getDriftAbsentMeansDefaultKeys(resourceType, properties) {
|
|
15035
|
+
if (resourceType !== "AWS::CloudWatch::Alarm") return [];
|
|
15036
|
+
if (properties["EvaluationCriteria"] !== void 0) return [...PROMQL_EXCLUDED_MEMBERS].filter((key) => properties[key] === void 0);
|
|
15037
|
+
const keys = ["EvaluationCriteria", "EvaluationInterval"];
|
|
15038
|
+
const declared = properties["EvaluationWindow"];
|
|
15039
|
+
if (declared === void 0 || isDefaultEvaluationWindow(declared)) keys.push("EvaluationWindow");
|
|
15040
|
+
return keys;
|
|
15041
|
+
}
|
|
14650
15042
|
generatedCreateName(_resourceType, logicalId, properties) {
|
|
14651
15043
|
if (properties["AlarmName"]) return void 0;
|
|
14652
15044
|
return generatedNameFor("AWS::CloudWatch::Alarm", logicalId);
|
|
@@ -15721,6 +16113,7 @@ var EventBridgeRuleProvider = class {
|
|
|
15721
16113
|
if (properties["Tags"]) putRuleParams["Tags"] = desiredTags;
|
|
15722
16114
|
const ruleArn = (await this.eventBridgeClient.send(new PutRuleCommand(putRuleParams))).RuleArn;
|
|
15723
16115
|
this.logger.debug(`Created EventBridge rule: ${ruleName} (${ruleArn})`);
|
|
16116
|
+
if (heldBefore === "free") reportCreatedResource(logicalId, resourceType, ruleArn);
|
|
15724
16117
|
const eventBusName = properties["EventBusName"];
|
|
15725
16118
|
try {
|
|
15726
16119
|
if (targets && targets.length > 0) {
|
|
@@ -15750,6 +16143,7 @@ var EventBridgeRuleProvider = class {
|
|
|
15750
16143
|
Name: ruleName,
|
|
15751
16144
|
EventBusName: eventBusName
|
|
15752
16145
|
}));
|
|
16146
|
+
retractCreatedResource(logicalId, resourceType, ruleArn);
|
|
15753
16147
|
this.logger.debug(`Cleaned up partially-created EventBridge rule ${logicalId} (${ruleName}) after wiring failure`);
|
|
15754
16148
|
} catch (cleanupError) {
|
|
15755
16149
|
leftLiveArn = ruleArn;
|
|
@@ -16122,6 +16516,7 @@ var EventBridgeBusProvider = class {
|
|
|
16122
16516
|
if (properties["LogConfig"] !== void 0) createParams.LogConfig = properties["LogConfig"];
|
|
16123
16517
|
const response = await (await this.getCreateClient()).send(new CreateEventBusCommand(createParams));
|
|
16124
16518
|
busCreated = true;
|
|
16519
|
+
reportCreatedResource(logicalId, resourceType, name);
|
|
16125
16520
|
const policy = policyDocument(properties["Policy"]);
|
|
16126
16521
|
if (policy !== void 0) await this.eventBridgeClient.send(new PutPermissionCommand({
|
|
16127
16522
|
EventBusName: name,
|
|
@@ -17151,6 +17546,7 @@ var EC2Provider = class {
|
|
|
17151
17546
|
}
|
|
17152
17547
|
const vpcId = response.Vpc.VpcId;
|
|
17153
17548
|
ec2IdsCreatedByThisProcess.add(vpcId);
|
|
17549
|
+
reportCreatedResource(logicalId, resourceType, vpcId);
|
|
17154
17550
|
const vpcReplayWindow = replayedSendWindow(response, attemptStartMs);
|
|
17155
17551
|
if (vpcReplayWindow !== void 0) await this.reportPossibleOrphanVpcs(logicalId, cidrBlock, desiredTags, vpcReplayWindow, context);
|
|
17156
17552
|
let defaultSgId;
|
|
@@ -17179,6 +17575,7 @@ var EC2Provider = class {
|
|
|
17179
17575
|
} catch (innerError) {
|
|
17180
17576
|
try {
|
|
17181
17577
|
await this.ec2Client.send(new DeleteVpcCommand({ VpcId: vpcId }));
|
|
17578
|
+
retractCreatedResource(logicalId, resourceType, vpcId);
|
|
17182
17579
|
this.logger.debug(`Cleaned up partially-created VPC ${logicalId} (${vpcId}) after wiring failure`);
|
|
17183
17580
|
} catch (cleanupError) {
|
|
17184
17581
|
leftBehindId = vpcId;
|
|
@@ -17334,6 +17731,7 @@ var EC2Provider = class {
|
|
|
17334
17731
|
}
|
|
17335
17732
|
const subnetId = response.Subnet.SubnetId;
|
|
17336
17733
|
ec2IdsCreatedByThisProcess.add(subnetId);
|
|
17734
|
+
reportCreatedResource(logicalId, resourceType, subnetId);
|
|
17337
17735
|
const subnetReplayWindow = replayedSendWindow(response, attemptStartMs);
|
|
17338
17736
|
if (subnetReplayWindow !== void 0) await this.reportPossibleOrphanSubnets(logicalId, vpcId, cidrBlock, desiredTags, subnetReplayWindow, context);
|
|
17339
17737
|
const availabilityZone = response.Subnet.AvailabilityZone;
|
|
@@ -17350,6 +17748,7 @@ var EC2Provider = class {
|
|
|
17350
17748
|
} catch (innerError) {
|
|
17351
17749
|
try {
|
|
17352
17750
|
await this.ec2Client.send(new DeleteSubnetCommand({ SubnetId: subnetId }));
|
|
17751
|
+
retractCreatedResource(logicalId, resourceType, subnetId);
|
|
17353
17752
|
this.logger.debug(`Cleaned up partially-created Subnet ${logicalId} (${subnetId}) after wiring failure`);
|
|
17354
17753
|
} catch (cleanupError) {
|
|
17355
17754
|
leftBehindId = subnetId;
|
|
@@ -17604,6 +18003,7 @@ var EC2Provider = class {
|
|
|
17604
18003
|
} catch {
|
|
17605
18004
|
createdId = allocationId;
|
|
17606
18005
|
}
|
|
18006
|
+
reportCreatedResource(logicalId, resourceType, createdId);
|
|
17607
18007
|
ec2IdsCreatedByThisProcess.add(allocationId);
|
|
17608
18008
|
const eipReplayWindow = replayedSendWindow(response, attemptStartMs);
|
|
17609
18009
|
if (eipReplayWindow !== void 0) await this.reportPossibleOrphanAddresses(logicalId, input, desiredTags, eipReplayWindow, context);
|
|
@@ -17636,6 +18036,7 @@ var EC2Provider = class {
|
|
|
17636
18036
|
} finally {
|
|
17637
18037
|
watch.dispose();
|
|
17638
18038
|
}
|
|
18039
|
+
retractCreatedResource(logicalId, resourceType, createdId);
|
|
17639
18040
|
createdId = void 0;
|
|
17640
18041
|
this.logger.debug(safeMsg`Released partially-created EIP ${logicalId} (${allocatedId})`);
|
|
17641
18042
|
} catch (cleanupError) {
|
|
@@ -17772,6 +18173,7 @@ var EC2Provider = class {
|
|
|
17772
18173
|
VpnGatewayId: gatewayId
|
|
17773
18174
|
}));
|
|
17774
18175
|
attachSent = true;
|
|
18176
|
+
reportCreatedResource(logicalId, resourceType, physicalId);
|
|
17775
18177
|
await this.waitForVpnGatewayAttachment(gatewayId, vpcId, "attached", logicalId);
|
|
17776
18178
|
}
|
|
17777
18179
|
this.logger.debug(`Successfully created VPCGatewayAttachment ${logicalId}: ${physicalId}`);
|
|
@@ -18068,6 +18470,7 @@ var EC2Provider = class {
|
|
|
18068
18470
|
})));
|
|
18069
18471
|
const natGatewayId = response.NatGateway.NatGatewayId;
|
|
18070
18472
|
createdId = natGatewayId;
|
|
18473
|
+
reportCreatedResource(logicalId, resourceType, natGatewayId);
|
|
18071
18474
|
if (!tagsApplied) await this.applyTags(natGatewayId, desiredTags, logicalId, maskerOrIdentity(context?.maskSecrets));
|
|
18072
18475
|
let described;
|
|
18073
18476
|
if (process.env["CDKD_NO_WAIT"] !== "true") {
|
|
@@ -18465,6 +18868,7 @@ var EC2Provider = class {
|
|
|
18465
18868
|
...TagSpecifications && { TagSpecifications }
|
|
18466
18869
|
})));
|
|
18467
18870
|
const groupId = response.GroupId;
|
|
18871
|
+
reportCreatedResource(logicalId, resourceType, groupId);
|
|
18468
18872
|
try {
|
|
18469
18873
|
const ingressRules = properties["SecurityGroupIngress"];
|
|
18470
18874
|
const egressRules = properties["SecurityGroupEgress"];
|
|
@@ -18481,6 +18885,7 @@ var EC2Provider = class {
|
|
|
18481
18885
|
} catch (innerError) {
|
|
18482
18886
|
try {
|
|
18483
18887
|
await this.ec2Client.send(new DeleteSecurityGroupCommand({ GroupId: groupId }));
|
|
18888
|
+
retractCreatedResource(logicalId, resourceType, groupId);
|
|
18484
18889
|
this.logger.debug(`Cleaned up partially-created SecurityGroup ${logicalId} (${groupId}) after wiring failure`);
|
|
18485
18890
|
} catch (cleanupError) {
|
|
18486
18891
|
leftBehindId = groupId;
|
|
@@ -19027,6 +19432,7 @@ var EC2Provider = class {
|
|
|
19027
19432
|
const instance = response.Instances?.[0];
|
|
19028
19433
|
if (!instance?.InstanceId) throw new Error("No instance ID returned from RunInstances");
|
|
19029
19434
|
const instanceId = instance.InstanceId;
|
|
19435
|
+
reportCreatedResource(logicalId, resourceType, instanceId);
|
|
19030
19436
|
try {
|
|
19031
19437
|
if (!tagsApplied) await this.applyTags(instanceId, desiredTags, logicalId, maskerOrIdentity(context?.maskSecrets));
|
|
19032
19438
|
if (process.env["CDKD_NO_WAIT"] !== "true") {
|
|
@@ -19056,6 +19462,7 @@ var EC2Provider = class {
|
|
|
19056
19462
|
} catch (innerError) {
|
|
19057
19463
|
try {
|
|
19058
19464
|
await this.ec2Client.send(new TerminateInstancesCommand({ InstanceIds: [instanceId] }));
|
|
19465
|
+
retractCreatedResource(logicalId, resourceType, instanceId);
|
|
19059
19466
|
runInstancesToken.release();
|
|
19060
19467
|
this.logger.debug(`Terminate requested for partially-created EC2 Instance ${logicalId} (${instanceId}) after wiring failure (not waiting for terminated state)`);
|
|
19061
19468
|
} catch (cleanupError) {
|
|
@@ -21655,6 +22062,7 @@ var ApiGatewayProvider = class ApiGatewayProvider {
|
|
|
21655
22062
|
documentationVersion: properties["DocumentationVersion"],
|
|
21656
22063
|
canarySettings: toSdkCanarySettings(properties["CanarySetting"])
|
|
21657
22064
|
}));
|
|
22065
|
+
reportCreatedResource(logicalId, resourceType, stageName);
|
|
21658
22066
|
const methodSettings = properties["MethodSettings"];
|
|
21659
22067
|
const postCreateOps = buildMethodSettingsPatchOps(void 0, methodSettings);
|
|
21660
22068
|
const accessLogSetting = properties["AccessLogSetting"];
|
|
@@ -21688,6 +22096,7 @@ var ApiGatewayProvider = class ApiGatewayProvider {
|
|
|
21688
22096
|
restApiId,
|
|
21689
22097
|
stageName
|
|
21690
22098
|
}));
|
|
22099
|
+
retractCreatedResource(logicalId, resourceType, stageName);
|
|
21691
22100
|
} catch (cleanupError) {
|
|
21692
22101
|
stageLeftBehind = true;
|
|
21693
22102
|
const cleanupFailure = describeAwsFailure(cleanupError);
|
|
@@ -21945,6 +22354,7 @@ var ApiGatewayProvider = class ApiGatewayProvider {
|
|
|
21945
22354
|
}
|
|
21946
22355
|
await putMethod();
|
|
21947
22356
|
}
|
|
22357
|
+
reportCreatedResource(logicalId, resourceType, physicalId);
|
|
21948
22358
|
try {
|
|
21949
22359
|
const integration = properties["Integration"];
|
|
21950
22360
|
if (integration) await this.apiGatewayClient.send(new PutIntegrationCommand(putIntegrationInput({
|
|
@@ -21973,6 +22383,7 @@ var ApiGatewayProvider = class ApiGatewayProvider {
|
|
|
21973
22383
|
resourceId,
|
|
21974
22384
|
httpMethod
|
|
21975
22385
|
}));
|
|
22386
|
+
retractCreatedResource(logicalId, resourceType, physicalId);
|
|
21976
22387
|
log.debug(`Cleaned up partially-created API Gateway Method ${logicalId} (${methodPath}) after wiring failure`);
|
|
21977
22388
|
} catch (cleanupError) {
|
|
21978
22389
|
methodLeftBehind = true;
|
|
@@ -22719,6 +23130,20 @@ var ApiGatewayV2Provider = class ApiGatewayV2Provider {
|
|
|
22719
23130
|
])]
|
|
22720
23131
|
]);
|
|
22721
23132
|
removalDefaults = /* @__PURE__ */ new Map([["AWS::ApiGatewayV2::Authorizer", /* @__PURE__ */ new Map([["IdentitySource", []]])]]);
|
|
23133
|
+
removalHandledInUpdate = /* @__PURE__ */ new Map([["AWS::ApiGatewayV2::Route", /* @__PURE__ */ new Set([
|
|
23134
|
+
"ApiId",
|
|
23135
|
+
"RouteKey",
|
|
23136
|
+
"AuthorizationScopes",
|
|
23137
|
+
"Target",
|
|
23138
|
+
"AuthorizationType",
|
|
23139
|
+
"AuthorizerId",
|
|
23140
|
+
"OperationName",
|
|
23141
|
+
"ApiKeyRequired",
|
|
23142
|
+
"RequestModels",
|
|
23143
|
+
"RequestParameters",
|
|
23144
|
+
"ModelSelectionExpression",
|
|
23145
|
+
"RouteResponseSelectionExpression"
|
|
23146
|
+
])]]);
|
|
22722
23147
|
unhandledByDesign = /* @__PURE__ */ new Map([["AWS::ApiGatewayV2::Api", /* @__PURE__ */ new Map([
|
|
22723
23148
|
["Body", "OpenAPI/Swagger inline spec; routed through ImportApi, not the field-by-field CreateApi path."],
|
|
22724
23149
|
["BodyS3Location", "OpenAPI/Swagger spec on S3; routed through ImportApi, not the field-by-field CreateApi path."],
|
|
@@ -23756,12 +24181,15 @@ var ApiGatewayV2Provider = class ApiGatewayV2Provider {
|
|
|
23756
24181
|
input.OperationName = properties["OperationName"];
|
|
23757
24182
|
changed = true;
|
|
23758
24183
|
}
|
|
23759
|
-
{
|
|
24184
|
+
if (restoreFromAws) {
|
|
23760
24185
|
const r = this.clearableUpdate(properties["ApiKeyRequired"], previousProperties["ApiKeyRequired"], false);
|
|
23761
24186
|
if (r.changed) {
|
|
23762
24187
|
input.ApiKeyRequired = r.value;
|
|
23763
24188
|
changed = true;
|
|
23764
24189
|
}
|
|
24190
|
+
} else if (properties["ApiKeyRequired"] !== void 0 && properties["ApiKeyRequired"] !== previousProperties["ApiKeyRequired"]) {
|
|
24191
|
+
input.ApiKeyRequired = properties["ApiKeyRequired"];
|
|
24192
|
+
changed = true;
|
|
23765
24193
|
}
|
|
23766
24194
|
if (restoreFromAws) {
|
|
23767
24195
|
const merged = this.mapWithRemovals(properties["RequestModels"], previousProperties["RequestModels"]);
|
|
@@ -25099,14 +25527,57 @@ function camelToPascalCaseKeys(value, preserveKeys) {
|
|
|
25099
25527
|
//#region src/provisioning/providers/agentcore-runtime-provider.ts
|
|
25100
25528
|
const CFN_MAP_KEYS = /* @__PURE__ */ new Set(["Tags", "AdvertisedScopeMapping"]);
|
|
25101
25529
|
const SDK_MAP_KEYS = /* @__PURE__ */ new Set(["tags", "advertisedScopeMapping"]);
|
|
25530
|
+
const RUNTIME_TAGS_WHAT = "a map of tag keys to scalar values or a list of tags with a non-empty string Key and a scalar Value";
|
|
25531
|
+
function isUserTagKey(key) {
|
|
25532
|
+
return !key.startsWith("aws:");
|
|
25533
|
+
}
|
|
25534
|
+
function desiredRuntimeTags(raw, resourceType, logicalId, physicalId) {
|
|
25535
|
+
const tags = refuseMalformedDesiredTags(tagMapAsList(raw), resourceType, logicalId, physicalId, "Tags", RUNTIME_TAGS_WHAT);
|
|
25536
|
+
if (!tags.every((t) => isUserTagKey(t.Key))) throw markNonRetryable(new ProvisioningError(`${physicalId !== void 0 ? "desired " : ""}Tags of ${resourceType} ${logicalId} holds a reserved aws: key, which AWS does not let a user set — the resource was not ${physicalId !== void 0 ? "updated" : "created"}`, resourceType, logicalId, physicalId));
|
|
25537
|
+
return tags;
|
|
25538
|
+
}
|
|
25539
|
+
const CREATE_TAG_RETRY_DELAYS_MS = [
|
|
25540
|
+
500,
|
|
25541
|
+
1e3,
|
|
25542
|
+
2e3,
|
|
25543
|
+
4e3
|
|
25544
|
+
];
|
|
25545
|
+
function isTransientTagFailure(error) {
|
|
25546
|
+
return isThrottlingError(error) || error instanceof ResourceNotFoundException$6 || error instanceof Error && error.name === "ResourceNotFoundException";
|
|
25547
|
+
}
|
|
25548
|
+
function isNonEmptyObject(value) {
|
|
25549
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && Object.keys(value).length > 0;
|
|
25550
|
+
}
|
|
25551
|
+
function writeSharedRuntimeMembers(input, properties) {
|
|
25552
|
+
const requestHeaders = properties["RequestHeaderConfiguration"];
|
|
25553
|
+
if (isNonEmptyObject(requestHeaders)) input["requestHeaderConfiguration"] = pascalToCamelCaseKeys(requestHeaders, CFN_MAP_KEYS);
|
|
25554
|
+
const filesystems = properties["FilesystemConfigurations"];
|
|
25555
|
+
if (Array.isArray(filesystems) && filesystems.length > 0) input["filesystemConfigurations"] = pascalToCamelCaseKeys(filesystems, CFN_MAP_KEYS);
|
|
25556
|
+
const capacityProvider = properties["CapacityProviderConfiguration"];
|
|
25557
|
+
if (isNonEmptyObject(capacityProvider)) input["capacityProviderConfiguration"] = pascalToCamelCaseKeys(capacityProvider, CFN_MAP_KEYS);
|
|
25558
|
+
const platformVersion = properties["PlatformVersion"];
|
|
25559
|
+
if (platformVersion !== void 0 && platformVersion !== null && platformVersion !== "") input["platformVersion"] = platformVersion;
|
|
25560
|
+
}
|
|
25102
25561
|
var AgentCoreRuntimeProvider = class {
|
|
25103
25562
|
client;
|
|
25104
25563
|
logger = getLogger().child("AgentCoreRuntimeProvider");
|
|
25564
|
+
sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
25565
|
+
async sendCreateTagCall(send) {
|
|
25566
|
+
for (let attempt = 0;; attempt++) try {
|
|
25567
|
+
return await send();
|
|
25568
|
+
} catch (error) {
|
|
25569
|
+
const delay = CREATE_TAG_RETRY_DELAYS_MS[attempt];
|
|
25570
|
+
if (delay === void 0 || !isTransientTagFailure(error)) throw error;
|
|
25571
|
+
this.logger.debug(safeMsg`Post-create tag call failed transiently (${describeAwsFailure(error).summary}); retrying in ${delay}ms`);
|
|
25572
|
+
await this.sleep(delay);
|
|
25573
|
+
}
|
|
25574
|
+
}
|
|
25105
25575
|
wrapCaughtError(mask, error, build) {
|
|
25106
25576
|
const failure = describeAwsFailure(error);
|
|
25107
25577
|
if (!failure.redacted) return wrapMaskedAwsError(mask, error, build);
|
|
25108
25578
|
this.logger.debug(mask(build(mask(failure.detail)).message));
|
|
25109
|
-
const
|
|
25579
|
+
const relay = isAuxiliaryFailure(error) ? "" : relayedNameCollision(failure.detail);
|
|
25580
|
+
const wrapped = build(`${mask(failure.summary)}${relay}`);
|
|
25110
25581
|
return error instanceof Error ? markRedactedCause(wrapped) : wrapped;
|
|
25111
25582
|
}
|
|
25112
25583
|
handledProperties = /* @__PURE__ */ new Map([["AWS::BedrockAgentCore::Runtime", /* @__PURE__ */ new Set([
|
|
@@ -25119,7 +25590,12 @@ var AgentCoreRuntimeProvider = class {
|
|
|
25119
25590
|
"ProtocolConfiguration",
|
|
25120
25591
|
"LifecycleConfiguration",
|
|
25121
25592
|
"EnvironmentVariables",
|
|
25122
|
-
"ClientToken"
|
|
25593
|
+
"ClientToken",
|
|
25594
|
+
"RequestHeaderConfiguration",
|
|
25595
|
+
"FilesystemConfigurations",
|
|
25596
|
+
"CapacityProviderConfiguration",
|
|
25597
|
+
"PlatformVersion",
|
|
25598
|
+
"Tags"
|
|
25123
25599
|
])]]);
|
|
25124
25600
|
constructor() {
|
|
25125
25601
|
const awsClients = getAwsClients();
|
|
@@ -25131,6 +25607,8 @@ var AgentCoreRuntimeProvider = class {
|
|
|
25131
25607
|
if (!agentRuntimeName) throw new ProvisioningError(`AgentRuntimeName is required for ${logicalId}`, resourceType, logicalId);
|
|
25132
25608
|
const roleArn = properties["RoleArn"];
|
|
25133
25609
|
if (!roleArn) throw new ProvisioningError(`RoleArn is required for ${logicalId}`, resourceType, logicalId);
|
|
25610
|
+
const desiredTags = desiredRuntimeTags(properties["Tags"], resourceType, logicalId);
|
|
25611
|
+
let createdRuntimeId;
|
|
25134
25612
|
try {
|
|
25135
25613
|
const input = {
|
|
25136
25614
|
agentRuntimeName,
|
|
@@ -25148,24 +25626,34 @@ var AgentCoreRuntimeProvider = class {
|
|
|
25148
25626
|
if (properties["LifecycleConfiguration"] !== void 0 && typeof properties["LifecycleConfiguration"] === "object" && properties["LifecycleConfiguration"] !== null && Object.keys(properties["LifecycleConfiguration"]).length > 0) input["lifecycleConfiguration"] = pascalToCamelCaseKeys(properties["LifecycleConfiguration"], CFN_MAP_KEYS);
|
|
25149
25627
|
if (properties["EnvironmentVariables"] !== void 0) input["environmentVariables"] = properties["EnvironmentVariables"];
|
|
25150
25628
|
if (properties["ClientToken"] !== void 0) input["clientToken"] = properties["ClientToken"];
|
|
25629
|
+
writeSharedRuntimeMembers(input, properties);
|
|
25630
|
+
if (desiredTags.length > 0) input["tags"] = Object.fromEntries(desiredTags.map((t) => [t.Key, t.Value]));
|
|
25151
25631
|
const response = await this.client.send(new CreateAgentRuntimeCommand(input));
|
|
25152
25632
|
const agentRuntimeId = response.agentRuntimeId;
|
|
25153
25633
|
const agentRuntimeArn = response.agentRuntimeArn;
|
|
25634
|
+
createdRuntimeId = agentRuntimeId;
|
|
25635
|
+
reportCreatedResource(logicalId, resourceType, agentRuntimeId);
|
|
25154
25636
|
this.logger.debug(`Created BedrockAgentCore Runtime: ${agentRuntimeId} (${agentRuntimeArn})`);
|
|
25637
|
+
if (desiredTags.length > 0) await this.ensureCreateTags(agentRuntimeId, agentRuntimeArn, desiredTags);
|
|
25155
25638
|
return {
|
|
25156
25639
|
physicalId: agentRuntimeId,
|
|
25157
25640
|
attributes: this.buildAttributes(response, agentRuntimeName)
|
|
25158
25641
|
};
|
|
25159
25642
|
} catch (error) {
|
|
25643
|
+
if (createdRuntimeId !== void 0) markAuxiliaryFailure(error, logicalId);
|
|
25160
25644
|
const cause = error instanceof Error ? error : void 0;
|
|
25161
|
-
|
|
25645
|
+
const thrown = this.wrapCaughtError(maskerOrIdentity(context?.maskSecrets), error, (text) => new ProvisioningError(`Failed to create BedrockAgentCore Runtime ${logicalId}: ${text}`, resourceType, logicalId, void 0, cause));
|
|
25646
|
+
if (createdRuntimeId !== void 0) markCreatedBeforeFailure(thrown, logicalId, resourceType, createdRuntimeId);
|
|
25647
|
+
throw thrown;
|
|
25162
25648
|
}
|
|
25163
25649
|
}
|
|
25164
|
-
async update(logicalId, physicalId, resourceType, properties,
|
|
25650
|
+
async update(logicalId, physicalId, resourceType, properties, previousProperties, context) {
|
|
25165
25651
|
this.logger.debug(`Updating BedrockAgentCore Runtime ${logicalId}: ${physicalId}`);
|
|
25166
25652
|
assertRegionMatch(context?.expectedRegion ? await this.client.config.region() : void 0, context?.expectedRegion, resourceType, logicalId, physicalId, "pre-update");
|
|
25167
25653
|
const roleArn = properties["RoleArn"];
|
|
25168
25654
|
if (!roleArn) throw new ProvisioningError(`RoleArn is required for ${logicalId}`, resourceType, logicalId, physicalId);
|
|
25655
|
+
desiredRuntimeTags(properties["Tags"], resourceType, logicalId, physicalId);
|
|
25656
|
+
const mask = maskerOrIdentity(context?.maskSecrets);
|
|
25169
25657
|
try {
|
|
25170
25658
|
const input = {
|
|
25171
25659
|
agentRuntimeId: physicalId,
|
|
@@ -25183,8 +25671,10 @@ var AgentCoreRuntimeProvider = class {
|
|
|
25183
25671
|
if (properties["LifecycleConfiguration"] !== void 0 && typeof properties["LifecycleConfiguration"] === "object" && properties["LifecycleConfiguration"] !== null && Object.keys(properties["LifecycleConfiguration"]).length > 0) input["lifecycleConfiguration"] = pascalToCamelCaseKeys(properties["LifecycleConfiguration"], CFN_MAP_KEYS);
|
|
25184
25672
|
if (properties["EnvironmentVariables"] !== void 0) input["environmentVariables"] = properties["EnvironmentVariables"];
|
|
25185
25673
|
if (properties["ClientToken"] !== void 0) input["clientToken"] = properties["ClientToken"];
|
|
25674
|
+
writeSharedRuntimeMembers(input, properties);
|
|
25186
25675
|
const response = await this.client.send(new UpdateAgentRuntimeCommand(input));
|
|
25187
25676
|
const agentRuntimeId = response.agentRuntimeId;
|
|
25677
|
+
await this.syncTags(logicalId, resourceType, physicalId, response.agentRuntimeArn, previousProperties["Tags"], properties["Tags"], mask);
|
|
25188
25678
|
this.logger.debug(`Successfully updated BedrockAgentCore Runtime ${logicalId}`);
|
|
25189
25679
|
return {
|
|
25190
25680
|
physicalId: agentRuntimeId,
|
|
@@ -25192,10 +25682,44 @@ var AgentCoreRuntimeProvider = class {
|
|
|
25192
25682
|
attributes: this.buildAttributes(response, properties["AgentRuntimeName"])
|
|
25193
25683
|
};
|
|
25194
25684
|
} catch (error) {
|
|
25685
|
+
if (error instanceof CdkdError) throw error;
|
|
25195
25686
|
const cause = error instanceof Error ? error : void 0;
|
|
25196
|
-
throw this.wrapCaughtError(
|
|
25687
|
+
throw this.wrapCaughtError(mask, error, (text) => new ProvisioningError(`Failed to update BedrockAgentCore Runtime ${logicalId}: ${text}`, resourceType, logicalId, physicalId, cause));
|
|
25197
25688
|
}
|
|
25198
25689
|
}
|
|
25690
|
+
async ensureCreateTags(agentRuntimeId, resourceArn, desired) {
|
|
25691
|
+
let live;
|
|
25692
|
+
try {
|
|
25693
|
+
live = (await this.sendCreateTagCall(() => this.client.send(new ListTagsForResourceCommand$6({ resourceArn })))).tags ?? {};
|
|
25694
|
+
} catch (err) {
|
|
25695
|
+
this.logger.debug(safeMsg`Could not read the tags of new runtime ${agentRuntimeId} (${describeAwsFailure(err).detail}); setting every declared tag`);
|
|
25696
|
+
}
|
|
25697
|
+
const missing = Object.fromEntries(desired.filter((t) => live?.[t.Key] !== t.Value).map((t) => [t.Key, t.Value]));
|
|
25698
|
+
if (Object.keys(missing).length === 0) return;
|
|
25699
|
+
if (live !== void 0) this.logger.debug(safeMsg`New runtime ${agentRuntimeId} lacks ${Object.keys(missing).length} of the tag(s) CreateAgentRuntime was sent; setting them with TagResource`);
|
|
25700
|
+
await this.sendCreateTagCall(() => this.client.send(new TagResourceCommand$9({
|
|
25701
|
+
resourceArn,
|
|
25702
|
+
tags: missing
|
|
25703
|
+
})));
|
|
25704
|
+
}
|
|
25705
|
+
async syncTags(logicalId, resourceType, physicalId, responseArn, previousTagsRaw, nextTagsRaw, mask) {
|
|
25706
|
+
const plan = planTagDiff(tagMapAsList(previousTagsRaw), tagMapAsList(nextTagsRaw));
|
|
25707
|
+
const warning = tagPlanWarning(plan, resourceType, logicalId);
|
|
25708
|
+
if (warning !== void 0) this.logger.warn(mask(warning));
|
|
25709
|
+
const remove = plan.remove.filter(isUserTagKey);
|
|
25710
|
+
const set = Object.fromEntries([...plan.set].filter(([k]) => isUserTagKey(k)));
|
|
25711
|
+
if (remove.length === 0 && Object.keys(set).length === 0) return;
|
|
25712
|
+
const resourceArn = responseArn ?? (await this.client.send(new GetAgentRuntimeCommand({ agentRuntimeId: physicalId }))).agentRuntimeArn;
|
|
25713
|
+
if (!resourceArn) throw new ProvisioningError(`Cannot apply the Tags change to ${logicalId}: AWS returned no runtime ARN`, resourceType, logicalId, physicalId);
|
|
25714
|
+
if (remove.length > 0) await this.client.send(new UntagResourceCommand$9({
|
|
25715
|
+
resourceArn,
|
|
25716
|
+
tagKeys: remove
|
|
25717
|
+
}));
|
|
25718
|
+
if (Object.keys(set).length > 0) await this.client.send(new TagResourceCommand$9({
|
|
25719
|
+
resourceArn,
|
|
25720
|
+
tags: set
|
|
25721
|
+
}));
|
|
25722
|
+
}
|
|
25199
25723
|
async delete(logicalId, physicalId, resourceType, _properties, context) {
|
|
25200
25724
|
this.logger.debug(`Deleting BedrockAgentCore Runtime ${logicalId}: ${physicalId}`);
|
|
25201
25725
|
try {
|
|
@@ -25263,6 +25787,16 @@ var AgentCoreRuntimeProvider = class {
|
|
|
25263
25787
|
}
|
|
25264
25788
|
if (resp.lifecycleConfiguration !== void 0) result["LifecycleConfiguration"] = camelToPascalCaseKeys(resp.lifecycleConfiguration, SDK_MAP_KEYS);
|
|
25265
25789
|
if (resp.environmentVariables !== void 0) result["EnvironmentVariables"] = resp.environmentVariables;
|
|
25790
|
+
result["RequestHeaderConfiguration"] = resp.requestHeaderConfiguration !== void 0 ? camelToPascalCaseKeys(resp.requestHeaderConfiguration, SDK_MAP_KEYS) : {};
|
|
25791
|
+
result["FilesystemConfigurations"] = resp.filesystemConfigurations !== void 0 ? camelToPascalCaseKeys(resp.filesystemConfigurations, SDK_MAP_KEYS) : [];
|
|
25792
|
+
result["CapacityProviderConfiguration"] = resp.capacityProviderConfiguration !== void 0 ? camelToPascalCaseKeys(resp.capacityProviderConfiguration, SDK_MAP_KEYS) : {};
|
|
25793
|
+
result["PlatformVersion"] = resp.platformVersion ?? "";
|
|
25794
|
+
if (resp.agentRuntimeArn) try {
|
|
25795
|
+
const tagsResp = await this.client.send(new ListTagsForResourceCommand$6({ resourceArn: resp.agentRuntimeArn }));
|
|
25796
|
+
result["Tags"] = Object.fromEntries(Object.entries(tagsResp.tags ?? {}).filter(([k]) => isUserTagKey(k)));
|
|
25797
|
+
} catch (err) {
|
|
25798
|
+
this.logger.debug(safeMsg`Failed to read tags for runtime ${physicalId}: ${describeAwsFailure(err).detail}`);
|
|
25799
|
+
}
|
|
25266
25800
|
return result;
|
|
25267
25801
|
}
|
|
25268
25802
|
async import(input) {
|
|
@@ -26108,6 +26642,60 @@ function isEcsErrorNamed(error, names) {
|
|
|
26108
26642
|
return typeof name === "string" && names.includes(name);
|
|
26109
26643
|
}
|
|
26110
26644
|
const settleRolloutDelays = { sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)) };
|
|
26645
|
+
function requestedRolloutOf(service) {
|
|
26646
|
+
if (!service) return void 0;
|
|
26647
|
+
const primary = service.deployments?.find((d) => d.status === "PRIMARY");
|
|
26648
|
+
const deploymentId = typeof primary?.id === "string" && primary.id ? primary.id : void 0;
|
|
26649
|
+
const taskDefinitionRaw = primary?.taskDefinition ?? service.taskDefinition;
|
|
26650
|
+
const taskDefinition = typeof taskDefinitionRaw === "string" && taskDefinitionRaw ? taskDefinitionRaw : void 0;
|
|
26651
|
+
if (deploymentId === void 0 && taskDefinition === void 0) return void 0;
|
|
26652
|
+
return {
|
|
26653
|
+
deploymentId,
|
|
26654
|
+
taskDefinition
|
|
26655
|
+
};
|
|
26656
|
+
}
|
|
26657
|
+
function failedRequestedDeployment(requested, deployments) {
|
|
26658
|
+
if (!Array.isArray(deployments)) return void 0;
|
|
26659
|
+
const target = requested?.deploymentId !== void 0 ? deployments.find((d) => d?.id === requested.deploymentId) : deployments.find((d) => d?.status === "PRIMARY");
|
|
26660
|
+
return target?.rolloutState === "FAILED" ? target : void 0;
|
|
26661
|
+
}
|
|
26662
|
+
function taskDefinitionRevision(arn) {
|
|
26663
|
+
const match = typeof arn === "string" ? /:task-definition\/[^:]+:(\d+)$/.exec(arn) : null;
|
|
26664
|
+
return match ? match[1] : void 0;
|
|
26665
|
+
}
|
|
26666
|
+
function describeRollout(rollout) {
|
|
26667
|
+
const revision = taskDefinitionRevision(rollout.taskDefinition);
|
|
26668
|
+
const id = typeof rollout.id === "string" && /^ecs-svc\/\d+$/.test(rollout.id) ? rollout.id : void 0;
|
|
26669
|
+
if (id && revision) return `deployment ${id} (task definition revision ${revision})`;
|
|
26670
|
+
if (id) return `deployment ${id}`;
|
|
26671
|
+
if (revision) return `task definition revision ${revision}`;
|
|
26672
|
+
return "another deployment";
|
|
26673
|
+
}
|
|
26674
|
+
var EcsCircuitBreakerVerdict = class extends Error {
|
|
26675
|
+
constructor(message) {
|
|
26676
|
+
super(message);
|
|
26677
|
+
this.name = "EcsCircuitBreakerVerdict";
|
|
26678
|
+
}
|
|
26679
|
+
};
|
|
26680
|
+
function wrapBreakerFailedError(failed) {
|
|
26681
|
+
return new EcsCircuitBreakerVerdict(`its deployment circuit breaker failed the rollout of ${describeRollout(failed)} (deployment FAILED). The new tasks failed to start or failed their health checks`);
|
|
26682
|
+
}
|
|
26683
|
+
function controllerSkipsWait(properties) {
|
|
26684
|
+
let type;
|
|
26685
|
+
try {
|
|
26686
|
+
type = readConfigString(properties["DeploymentController"], "Type", "ECS", "DeploymentController");
|
|
26687
|
+
} catch {
|
|
26688
|
+
return "its DeploymentController could not be read";
|
|
26689
|
+
}
|
|
26690
|
+
if (type === "ECS") return void 0;
|
|
26691
|
+
if (type === "CODE_DEPLOY" || type === "EXTERNAL") return `its DeploymentController is ${type}, which ECS does not settle`;
|
|
26692
|
+
return "its DeploymentController type is not one cdkd can settle";
|
|
26693
|
+
}
|
|
26694
|
+
function rolloutSupersededBy(requested, settled) {
|
|
26695
|
+
if (!requested || !settled) return void 0;
|
|
26696
|
+
if (requested.deploymentId !== void 0 && typeof settled.id === "string" && settled.id) return settled.id === requested.deploymentId ? void 0 : describeRollout(settled);
|
|
26697
|
+
if (requested.taskDefinition !== void 0 && typeof settled.taskDefinition === "string" && settled.taskDefinition) return settled.taskDefinition === requested.taskDefinition ? void 0 : describeRollout(settled);
|
|
26698
|
+
}
|
|
26111
26699
|
function markNotGoneOnNotFoundClass$1(error, wrapped) {
|
|
26112
26700
|
return error instanceof Error && error.name.includes("NotFound") ? markNotGone(wrapped) : wrapped;
|
|
26113
26701
|
}
|
|
@@ -26257,7 +26845,7 @@ var ECSProvider = class {
|
|
|
26257
26845
|
switch (resourceType) {
|
|
26258
26846
|
case "AWS::ECS::Cluster": return this.createCluster(logicalId, resourceType, properties, this.operationSinks(context, [[properties["ClusterName"], properties["ClusterName"]]]));
|
|
26259
26847
|
case "AWS::ECS::TaskDefinition": return this.createTaskDefinition(logicalId, resourceType, properties, this.operationSinks(context, [[properties["Family"], properties["Family"]]]));
|
|
26260
|
-
case "AWS::ECS::Service": return this.createService(logicalId, resourceType, properties, this.operationSinks(context, [[properties["ServiceName"], properties["ServiceName"]], [properties["Cluster"], clusterNameOfRef(properties["Cluster"])]]));
|
|
26848
|
+
case "AWS::ECS::Service": return this.createService(logicalId, resourceType, properties, this.operationSinks(context, [[properties["ServiceName"], properties["ServiceName"]], [properties["Cluster"], clusterNameOfRef(properties["Cluster"])]]), context?.replayingState === true);
|
|
26261
26849
|
default: throw new ProvisioningError(`Unsupported resource type: ${resourceType}`, resourceType, logicalId);
|
|
26262
26850
|
}
|
|
26263
26851
|
}
|
|
@@ -26274,7 +26862,7 @@ var ECSProvider = class {
|
|
|
26274
26862
|
[properties["Cluster"], recordedCluster],
|
|
26275
26863
|
[previousProperties["Cluster"], recordedCluster],
|
|
26276
26864
|
[properties["Cluster"], clusterNameOfRef(properties["Cluster"])]
|
|
26277
|
-
]), context?.desiredFromAwsReadback === true);
|
|
26865
|
+
]), context?.desiredFromAwsReadback === true, context?.replayingState === true);
|
|
26278
26866
|
}
|
|
26279
26867
|
default: throw new ProvisioningError(`Unsupported resource type: ${resourceType}`, resourceType, logicalId, physicalId);
|
|
26280
26868
|
}
|
|
@@ -26494,14 +27082,15 @@ var ECSProvider = class {
|
|
|
26494
27082
|
default: return;
|
|
26495
27083
|
}
|
|
26496
27084
|
}
|
|
26497
|
-
async createService(logicalId, resourceType, properties, log) {
|
|
27085
|
+
async createService(logicalId, resourceType, properties, log, replayingState) {
|
|
26498
27086
|
log.debug(`Creating ECS service ${logicalId}`);
|
|
26499
27087
|
const desiredTags = refuseMalformedDesiredTags(properties["Tags"], resourceType, logicalId);
|
|
26500
27088
|
const client = this.getClient();
|
|
26501
27089
|
const serviceName = properties["ServiceName"] || generatedNameFor("AWS::ECS::Service", logicalId);
|
|
26502
27090
|
let survivorArn;
|
|
26503
27091
|
try {
|
|
26504
|
-
const
|
|
27092
|
+
const skipReason = controllerSkipsWait(properties);
|
|
27093
|
+
const heldBefore = process.env["CDKD_NO_WAIT"] !== "true" && skipReason === void 0 && !replayingState ? await nameHeldBefore(() => this.serviceNameHeld(properties["Cluster"], serviceName), (error) => hasErrorName(error, ["ClusterNotFoundException"])) : "free";
|
|
26505
27094
|
const service = (await client.send(new CreateServiceCommand({
|
|
26506
27095
|
cluster: properties["Cluster"],
|
|
26507
27096
|
serviceName,
|
|
@@ -26532,9 +27121,20 @@ var ECSProvider = class {
|
|
|
26532
27121
|
}))).service;
|
|
26533
27122
|
if (!service || !service.serviceArn) throw new Error("CreateService did not return service ARN");
|
|
26534
27123
|
log.debug(`Successfully created ECS service ${logicalId}: ${service.serviceArn}`);
|
|
27124
|
+
if (heldBefore === "free") reportCreatedResource(logicalId, resourceType, service.serviceArn);
|
|
26535
27125
|
try {
|
|
26536
|
-
await this.settleService(logicalId, service.serviceName ?? service.serviceArn, properties["Cluster"], log);
|
|
27126
|
+
await this.settleService(logicalId, service.serviceName ?? service.serviceArn, properties["Cluster"], log, requestedRolloutOf(service), skipReason);
|
|
26537
27127
|
} catch (waitError) {
|
|
27128
|
+
if (replayingState) {
|
|
27129
|
+
log.warn(`${this.wrapSteadyStateError(logicalId, waitError, properties["Cluster"], log, false).message} Continuing the rollback: the restored service stays recorded.`);
|
|
27130
|
+
return {
|
|
27131
|
+
physicalId: service.serviceArn,
|
|
27132
|
+
attributes: {
|
|
27133
|
+
ServiceArn: service.serviceArn,
|
|
27134
|
+
Name: service.serviceName
|
|
27135
|
+
}
|
|
27136
|
+
};
|
|
27137
|
+
}
|
|
26538
27138
|
const aws = pasteableAwsCommand(log.mask);
|
|
26539
27139
|
const cleanupCluster = properties["Cluster"];
|
|
26540
27140
|
const clusterArg = cleanupCluster ? aws` --cluster ${cleanupCluster}` : aws``;
|
|
@@ -26547,6 +27147,7 @@ var ECSProvider = class {
|
|
|
26547
27147
|
service: service.serviceArn,
|
|
26548
27148
|
force: true
|
|
26549
27149
|
}));
|
|
27150
|
+
retractCreatedResource(logicalId, resourceType, service.serviceArn);
|
|
26550
27151
|
log.warn(`Deleted partially-created ECS service ${logicalId} (${service.serviceArn}) after the steady-state wait failed, so the next deploy's CreateService does not collide on the name. Its stopped tasks remain inspectable for about an hour: ${listStopped.render()}`);
|
|
26551
27152
|
} catch (cleanupError) {
|
|
26552
27153
|
survivorArn = service.serviceArn;
|
|
@@ -26555,10 +27156,7 @@ var ECSProvider = class {
|
|
|
26555
27156
|
if (cleanupFailure.redacted) log.debug(`${cleanupHead}${cleanupFailure.detail}`);
|
|
26556
27157
|
log.warn(`${cleanupHead}${cleanupFailure.redacted ? `${cleanupFailure.summary} ` : `${cleanupFailure.detail}. `}Manual deletion may be required before the next deploy: ${deleteCommand.render()}`);
|
|
26557
27158
|
}
|
|
26558
|
-
|
|
26559
|
-
if (waitFailure.redacted) log.debug(`ECS service ${logicalId} steady-state wait failed: ${waitFailure.detail}`);
|
|
26560
|
-
const steadyStateError = new Error(`ECS service ${logicalIdShown(logicalId)} did not reach steady state under --full-wait: ${waitFailure.summary.replace(/\.$/, "")}. Inspect why its tasks stopped (stopped tasks stay visible for about an hour): ${listStopped.render()}, then ${aws`aws ecs describe-tasks${clusterArg} --tasks '<task-arn>' --query 'tasks[].[stoppedReason,containers[].reason]'`.render()}`, { cause: waitError });
|
|
26561
|
-
throw waitFailure.redacted ? markRedactedCause(steadyStateError) : steadyStateError;
|
|
27159
|
+
throw this.wrapSteadyStateError(logicalId, waitError, properties["Cluster"], log);
|
|
26562
27160
|
}
|
|
26563
27161
|
return {
|
|
26564
27162
|
physicalId: service.serviceArn,
|
|
@@ -26601,30 +27199,68 @@ var ECSProvider = class {
|
|
|
26601
27199
|
reduced.name = error.name;
|
|
26602
27200
|
return markRedactedCause(reduced);
|
|
26603
27201
|
}
|
|
26604
|
-
|
|
26605
|
-
|
|
27202
|
+
wrapSteadyStateError(logicalId, waitError, cluster, log, offerNoWait = true) {
|
|
27203
|
+
const aws = pasteableAwsCommand(log.mask);
|
|
27204
|
+
const clusterArg = cluster ? aws` --cluster ${cluster}` : aws``;
|
|
27205
|
+
const listStopped = aws`aws ecs list-tasks${clusterArg} --desired-status STOPPED`;
|
|
27206
|
+
const waitFailure = describeAwsFailure(waitError);
|
|
27207
|
+
if (waitFailure.redacted) log.debug(`ECS service ${logicalId} steady-state wait failed: ${waitFailure.detail}`);
|
|
27208
|
+
const flagsAvailable = offerNoWait && process.env["CDKD_WAIT_FLAGS_AVAILABLE"] === "true";
|
|
27209
|
+
const timeoutHint = flagsAvailable && !(waitError instanceof EcsCircuitBreakerVerdict) ? ` To wait longer, raise the limit with --resource-timeout AWS::ECS::Service=${commandHole("duration")}.` : "";
|
|
27210
|
+
const noWaitHint = flagsAvailable ? " To deploy without waiting for steady state, pass --no-wait." : "";
|
|
27211
|
+
const steadyStateError = new Error(`ECS service ${logicalIdShown(logicalId)} did not reach steady state: ${waitFailure.summary.replace(/\.$/, "")}. Inspect why its tasks stopped (stopped tasks stay visible for about an hour): ${listStopped.render()}, then ${aws`aws ecs describe-tasks${clusterArg} --tasks '<task-arn>' --query 'tasks[].[stoppedReason,containers[].reason]'`.render()}.${timeoutHint}${noWaitHint}`, { cause: waitError });
|
|
27212
|
+
return waitFailure.redacted ? markRedactedCause(steadyStateError) : steadyStateError;
|
|
27213
|
+
}
|
|
27214
|
+
async settleService(logicalId, serviceRef, cluster, log, requested, skipReason) {
|
|
27215
|
+
if (skipReason !== void 0) {
|
|
27216
|
+
this.logger.info(log.mask(`ECS service ${logicalIdShown(logicalId)} accepted (not waiting for steady state: ${skipReason}).`));
|
|
27217
|
+
return;
|
|
27218
|
+
}
|
|
27219
|
+
if (process.env["CDKD_NO_WAIT"] !== "true") {
|
|
26606
27220
|
log.debug(`Waiting for ECS service ${logicalId} to reach steady state...`);
|
|
26607
27221
|
const maxWaitTime = Math.max(600, (resolvedResourceTimeoutMs("AWS::ECS::Service") ?? 0) / 1e3);
|
|
27222
|
+
const client = this.getClient();
|
|
27223
|
+
const breakerVerdict = new AbortController();
|
|
27224
|
+
let failedRollout;
|
|
27225
|
+
const watchedClient = { send: async (command) => {
|
|
27226
|
+
const output = await client.send(command);
|
|
27227
|
+
if (failedRollout === void 0) {
|
|
27228
|
+
failedRollout = failedRequestedDeployment(requested, output?.services?.[0]?.deployments);
|
|
27229
|
+
if (failedRollout !== void 0) breakerVerdict.abort();
|
|
27230
|
+
}
|
|
27231
|
+
return output;
|
|
27232
|
+
} };
|
|
26608
27233
|
try {
|
|
26609
27234
|
await waitUntilServicesStable({
|
|
26610
|
-
client:
|
|
27235
|
+
client: watchedClient,
|
|
26611
27236
|
maxWaitTime,
|
|
26612
27237
|
minDelay: 5,
|
|
26613
|
-
maxDelay: 10
|
|
27238
|
+
maxDelay: 10,
|
|
27239
|
+
abortSignal: breakerVerdict.signal
|
|
26614
27240
|
}, {
|
|
26615
27241
|
cluster,
|
|
26616
27242
|
services: [serviceRef]
|
|
26617
27243
|
});
|
|
26618
27244
|
} catch (waiterError) {
|
|
27245
|
+
if (failedRollout !== void 0) {
|
|
27246
|
+
log.debug(`ECS service ${logicalId} deployment ${failedRollout.id ?? "(no id)"} FAILED: ${failedRollout.rolloutStateReason ?? "(no rollout reason)"}`);
|
|
27247
|
+
throw wrapBreakerFailedError(failedRollout);
|
|
27248
|
+
}
|
|
26619
27249
|
throw this.wrapWaiterResultError(waiterError, logicalId, log);
|
|
26620
27250
|
}
|
|
27251
|
+
if (failedRollout !== void 0) throw wrapBreakerFailedError(failedRollout);
|
|
26621
27252
|
const rolloutDeadline = Date.now() + 12e4;
|
|
27253
|
+
let settledDeployment;
|
|
26622
27254
|
for (;;) {
|
|
26623
27255
|
const deployments = (await this.getClient().send(new DescribeServicesCommand({
|
|
26624
27256
|
cluster,
|
|
26625
27257
|
services: [serviceRef]
|
|
26626
27258
|
})))?.services?.[0]?.deployments;
|
|
26627
|
-
const
|
|
27259
|
+
const failedNow = failedRequestedDeployment(requested, deployments);
|
|
27260
|
+
if (failedNow !== void 0) throw wrapBreakerFailedError(failedNow);
|
|
27261
|
+
settledDeployment = deployments && deployments.length === 1 ? deployments[0] : void 0;
|
|
27262
|
+
const rolloutState = settledDeployment?.rolloutState;
|
|
27263
|
+
if (settledDeployment !== void 0 && rolloutState === "FAILED") throw wrapBreakerFailedError(settledDeployment);
|
|
26628
27264
|
if (rolloutState === void 0 || rolloutState === "COMPLETED") break;
|
|
26629
27265
|
if (Date.now() >= rolloutDeadline) {
|
|
26630
27266
|
log.warn(`ECS service ${logicalId} is steady but its rollout is still ${rolloutState} after the post-stability grace window; continuing`);
|
|
@@ -26632,15 +27268,22 @@ var ECSProvider = class {
|
|
|
26632
27268
|
}
|
|
26633
27269
|
await settleRolloutDelays.sleep(3e3);
|
|
26634
27270
|
}
|
|
27271
|
+
const supersededBy = rolloutSupersededBy(requested, settledDeployment);
|
|
27272
|
+
if (supersededBy !== void 0) {
|
|
27273
|
+
log.debug(`ECS service ${logicalId} settled deployment ${settledDeployment?.id ?? "(no id)"}: ${settledDeployment?.rolloutStateReason ?? "(no rollout reason)"}`);
|
|
27274
|
+
throw new EcsCircuitBreakerVerdict(`its deployment circuit breaker rolled the rollout back: the service settled on ${supersededBy}, not on the deployment this update started (${describeRollout({
|
|
27275
|
+
id: requested.deploymentId,
|
|
27276
|
+
taskDefinition: requested.taskDefinition
|
|
27277
|
+
})}). The new tasks failed to start or failed their health checks`);
|
|
27278
|
+
}
|
|
26635
27279
|
log.debug(`ECS service ${logicalId} reached steady state`);
|
|
26636
27280
|
return;
|
|
26637
27281
|
}
|
|
26638
27282
|
const aws = pasteableAwsCommand(log.mask);
|
|
26639
27283
|
const clusterArg = cluster ? aws` --cluster ${cluster}` : aws``;
|
|
26640
|
-
|
|
26641
|
-
this.logger.info(log.mask(`ECS service ${logicalIdShown(logicalId)} accepted (not waiting for steady state${fullWaitHint}). To wait manually: ${aws`aws ecs wait services-stable${clusterArg} --services ${serviceRef}`.render()}`));
|
|
27284
|
+
this.logger.info(log.mask(`ECS service ${logicalIdShown(logicalId)} accepted (not waiting for steady state under --no-wait). To wait manually: ${aws`aws ecs wait services-stable${clusterArg} --services ${serviceRef}`.render()}`));
|
|
26642
27285
|
}
|
|
26643
|
-
async updateService(logicalId, physicalId, resourceType, properties, previousProperties, log, desiredFromAwsReadback) {
|
|
27286
|
+
async updateService(logicalId, physicalId, resourceType, properties, previousProperties, log, desiredFromAwsReadback, replayingState) {
|
|
26644
27287
|
log.debug(`Updating ECS service ${logicalId}: ${physicalId}`);
|
|
26645
27288
|
refuseMalformedDesiredTags(properties["Tags"], resourceType, logicalId, physicalId);
|
|
26646
27289
|
const client = this.getClient();
|
|
@@ -26710,7 +27353,12 @@ var ECSProvider = class {
|
|
|
26710
27353
|
forceNewDeployment: forceNewDeploymentInput
|
|
26711
27354
|
}))).service;
|
|
26712
27355
|
if (service?.serviceArn) await this.applyTagDiff(service.serviceArn, resourceType, logicalId, previousProperties["Tags"], properties["Tags"], log);
|
|
26713
|
-
|
|
27356
|
+
try {
|
|
27357
|
+
await this.settleService(logicalId, service?.serviceName ?? physicalId, properties["Cluster"], log, requestedRolloutOf(service), desiredFromAwsReadback ? "a drift revert does not wait for it" : controllerSkipsWait(properties));
|
|
27358
|
+
} catch (waitError) {
|
|
27359
|
+
if (replayingState) log.warn(`${this.wrapSteadyStateError(logicalId, waitError, properties["Cluster"], log, false).message} The rollback update was applied; continuing.`);
|
|
27360
|
+
else throw this.wrapSteadyStateError(logicalId, waitError, properties["Cluster"], log);
|
|
27361
|
+
}
|
|
26714
27362
|
return {
|
|
26715
27363
|
physicalId,
|
|
26716
27364
|
wasReplaced: false,
|
|
@@ -27982,6 +28630,7 @@ var ELBv2Provider = class {
|
|
|
27982
28630
|
if (!lb || !lb.LoadBalancerArn) throw new Error("CreateLoadBalancer did not return LoadBalancer ARN");
|
|
27983
28631
|
const lbArn = lb.LoadBalancerArn;
|
|
27984
28632
|
this.logger.debug(`Successfully created LoadBalancer ${logicalId}: ${lbArn}`);
|
|
28633
|
+
if (heldBefore === "free") reportCreatedResource(logicalId, resourceType, lbArn);
|
|
27985
28634
|
try {
|
|
27986
28635
|
if (waitForActive) {
|
|
27987
28636
|
this.logger.debug(`Waiting for LoadBalancer ${logicalId} to reach active state...`);
|
|
@@ -28020,6 +28669,7 @@ var ELBv2Provider = class {
|
|
|
28020
28669
|
if (heldBefore !== "free") this.logger.warn(maskerOrIdentity(maskSecrets)(skippedCleanupText(heldBefore, `LoadBalancer ${logicalId} (${lbArn})`, pasteableAwsCommand(maskSecrets)`aws elbv2 delete-load-balancer --load-balancer-arn ${lbArn}`.render())));
|
|
28021
28670
|
else try {
|
|
28022
28671
|
await this.getClient().send(new DeleteLoadBalancerCommand({ LoadBalancerArn: lbArn }));
|
|
28672
|
+
retractCreatedResource(logicalId, resourceType, lbArn);
|
|
28023
28673
|
this.logger.debug(`Cleaned up partially-created LoadBalancer ${logicalId} (${lbArn}) after wiring failure`);
|
|
28024
28674
|
} catch (cleanupError) {
|
|
28025
28675
|
leftBehindArn = lbArn;
|
|
@@ -28288,6 +28938,7 @@ var ELBv2Provider = class {
|
|
|
28288
28938
|
if (!tg || !tg.TargetGroupArn) throw new Error("CreateTargetGroup did not return TargetGroup ARN");
|
|
28289
28939
|
const tgArn = tg.TargetGroupArn;
|
|
28290
28940
|
this.logger.debug(`Successfully created TargetGroup ${logicalId}: ${tgArn}`);
|
|
28941
|
+
if (heldBefore === "free") reportCreatedResource(logicalId, resourceType, tgArn);
|
|
28291
28942
|
try {
|
|
28292
28943
|
if (tgAttributes.length > 0) {
|
|
28293
28944
|
await this.getClient().send(new ModifyTargetGroupAttributesCommand({
|
|
@@ -28310,6 +28961,7 @@ var ELBv2Provider = class {
|
|
|
28310
28961
|
if (isInterruptedWaitError(innerError)) this.logger.warn(maskerOrIdentity(maskSecrets)(`Interrupted after creating TargetGroup ${logicalId} (${tgArn}) but before its targets were registered. Nothing in cdkd state refers to it, so cdkd is deleting it now. If that delete fails, remove it yourself: ${pasteableAwsCommand(maskSecrets)`aws elbv2 delete-target-group --target-group-arn ${tgArn}`.render()}`));
|
|
28311
28962
|
try {
|
|
28312
28963
|
await this.getClient().send(new DeleteTargetGroupCommand({ TargetGroupArn: tgArn }));
|
|
28964
|
+
retractCreatedResource(logicalId, resourceType, tgArn);
|
|
28313
28965
|
this.logger.debug(`Cleaned up partially-created TargetGroup ${logicalId} (${tgArn}) after wiring failure`);
|
|
28314
28966
|
} catch (cleanupError) {
|
|
28315
28967
|
leftBehindArn = tgArn;
|
|
@@ -28483,6 +29135,7 @@ var ELBv2Provider = class {
|
|
|
28483
29135
|
if (!listener || !listener.ListenerArn) throw new Error("CreateListener did not return Listener ARN");
|
|
28484
29136
|
const listenerArn = listener.ListenerArn;
|
|
28485
29137
|
this.logger.debug(`Successfully created Listener ${logicalId}: ${listenerArn}`);
|
|
29138
|
+
if (heldBefore === "free") reportCreatedResource(logicalId, resourceType, listenerArn);
|
|
28486
29139
|
try {
|
|
28487
29140
|
if (listenerAttributes.length > 0) {
|
|
28488
29141
|
const watch = startInterruptWatch(`ELBv2 Listener ${logicalId} attributes`);
|
|
@@ -28508,6 +29161,7 @@ var ELBv2Provider = class {
|
|
|
28508
29161
|
if (isInterruptedWaitError(innerError)) this.logger.warn(maskerOrIdentity(maskSecrets)(`Interrupted after creating Listener ${logicalId} (${listenerArn}) but before its attributes were applied. Nothing in cdkd state refers to it, so cdkd is deleting it now — left behind it would fail the next deploy with DuplicateListener and destroy could not reach it. If that delete fails, outside a rollback's re-create, the failed deploy's rollback journal records it for \`cdkd rollback --revert-failed\`; otherwise remove it yourself: ${pasteableAwsCommand(maskSecrets)`aws elbv2 delete-listener --listener-arn ${listenerArn}`.render()}`));
|
|
28509
29162
|
try {
|
|
28510
29163
|
await this.getClient().send(new DeleteListenerCommand({ ListenerArn: listenerArn }));
|
|
29164
|
+
retractCreatedResource(logicalId, resourceType, listenerArn);
|
|
28511
29165
|
this.logger.debug(`Cleaned up partially-created Listener ${logicalId} (${listenerArn}) after attributes-wiring failure`);
|
|
28512
29166
|
} catch (cleanupError) {
|
|
28513
29167
|
leftBehindArn = listenerArn;
|
|
@@ -29048,6 +29702,7 @@ const POLL_INTERVAL_MS$1 = 5e3;
|
|
|
29048
29702
|
const POLL_TIMEOUT_MS$1 = 18e5;
|
|
29049
29703
|
const RETAINED_ON_REMOVAL = [
|
|
29050
29704
|
"Auth",
|
|
29705
|
+
"DefaultAuthScheme",
|
|
29051
29706
|
"RequireTLS",
|
|
29052
29707
|
"IdleClientTimeout",
|
|
29053
29708
|
"DebugLogging",
|
|
@@ -29059,7 +29714,14 @@ const CFN_KEEPS_ON_REMOVAL$1 = /* @__PURE__ */ new Set([
|
|
|
29059
29714
|
"DebugLogging",
|
|
29060
29715
|
"VpcSecurityGroupIds"
|
|
29061
29716
|
]);
|
|
29062
|
-
const authRemovalRefused = (properties) => {
|
|
29717
|
+
const authRemovalRefused = (properties, previousProperties) => authRequired({ DefaultAuthScheme: properties["DefaultAuthScheme"] !== void 0 ? properties["DefaultAuthScheme"] : previousProperties["DefaultAuthScheme"] });
|
|
29718
|
+
const leavesProxyWithoutAuth = (properties, previousProperties) => {
|
|
29719
|
+
const desired = properties["Auth"];
|
|
29720
|
+
const declaredEmpty = desired === null || Array.isArray(desired) && desired.length === 0;
|
|
29721
|
+
if (properties["DefaultAuthScheme"] === "NONE" && previousProperties["DefaultAuthScheme"] !== "NONE" && (desired === void 0 || declaredEmpty)) return true;
|
|
29722
|
+
return declaredEmpty && JSON.stringify(desired) !== JSON.stringify(previousProperties["Auth"]) && authRemovalRefused(properties, previousProperties);
|
|
29723
|
+
};
|
|
29724
|
+
const authRequired = (properties) => {
|
|
29063
29725
|
const scheme = properties["DefaultAuthScheme"];
|
|
29064
29726
|
return scheme === void 0 || scheme === "NONE";
|
|
29065
29727
|
};
|
|
@@ -29079,6 +29741,9 @@ var RDSDBProxyProvider = class {
|
|
|
29079
29741
|
"RequireTLS",
|
|
29080
29742
|
"IdleClientTimeout",
|
|
29081
29743
|
"DebugLogging",
|
|
29744
|
+
"DefaultAuthScheme",
|
|
29745
|
+
"EndpointNetworkType",
|
|
29746
|
+
"TargetConnectionNetworkType",
|
|
29082
29747
|
"Tags"
|
|
29083
29748
|
])]]);
|
|
29084
29749
|
getClient() {
|
|
@@ -29105,18 +29770,21 @@ var RDSDBProxyProvider = class {
|
|
|
29105
29770
|
const engineFamily = properties["EngineFamily"];
|
|
29106
29771
|
if (!engineFamily) throw new ProvisioningError(`EngineFamily is required for AWS::RDS::DBProxy ${logicalId}`, resourceType, logicalId);
|
|
29107
29772
|
const auth = properties["Auth"];
|
|
29108
|
-
if (!auth || auth.length === 0) throw new ProvisioningError(`Auth (at least one entry) is required for AWS::RDS::DBProxy ${logicalId}`, resourceType, logicalId);
|
|
29773
|
+
if ((!auth || auth.length === 0) && authRequired(properties)) throw new ProvisioningError(`Auth (at least one entry) is required for AWS::RDS::DBProxy ${logicalId} while DefaultAuthScheme is NONE or unset`, resourceType, logicalId);
|
|
29109
29774
|
const roleArn = properties["RoleArn"];
|
|
29110
29775
|
if (!roleArn) throw new ProvisioningError(`RoleArn is required for AWS::RDS::DBProxy ${logicalId}`, resourceType, logicalId);
|
|
29111
29776
|
const vpcSubnetIds = properties["VpcSubnetIds"];
|
|
29112
29777
|
if (!vpcSubnetIds || vpcSubnetIds.length === 0) throw new ProvisioningError(`VpcSubnetIds (at least one) is required for AWS::RDS::DBProxy ${logicalId}`, resourceType, logicalId);
|
|
29113
29778
|
const client = this.getClient();
|
|
29114
|
-
this.logger.debug(`Creating DBProxy ${dbProxyName} (${engineFamily})`);
|
|
29779
|
+
this.logger.debug(mask(`Creating DBProxy ${dbProxyName} (${engineFamily})`));
|
|
29115
29780
|
try {
|
|
29116
29781
|
await this.getCreateClient().send(new CreateDBProxyCommand({
|
|
29117
29782
|
DBProxyName: dbProxyName,
|
|
29118
29783
|
EngineFamily: engineFamily,
|
|
29119
|
-
Auth: auth,
|
|
29784
|
+
Auth: auth && auth.length > 0 ? auth : void 0,
|
|
29785
|
+
DefaultAuthScheme: properties["DefaultAuthScheme"],
|
|
29786
|
+
EndpointNetworkType: properties["EndpointNetworkType"],
|
|
29787
|
+
TargetConnectionNetworkType: properties["TargetConnectionNetworkType"],
|
|
29120
29788
|
RoleArn: roleArn,
|
|
29121
29789
|
VpcSubnetIds: vpcSubnetIds,
|
|
29122
29790
|
VpcSecurityGroupIds: properties["VpcSecurityGroupIds"],
|
|
@@ -29128,6 +29796,7 @@ var RDSDBProxyProvider = class {
|
|
|
29128
29796
|
} catch (error) {
|
|
29129
29797
|
throw this.wrapCaughtError(error, "CREATE", resourceType, logicalId, void 0, mask);
|
|
29130
29798
|
}
|
|
29799
|
+
reportCreatedResource(logicalId, resourceType, dbProxyName);
|
|
29131
29800
|
let endpoint;
|
|
29132
29801
|
let dbProxyArn;
|
|
29133
29802
|
let vpcId;
|
|
@@ -29167,13 +29836,16 @@ var RDSDBProxyProvider = class {
|
|
|
29167
29836
|
}
|
|
29168
29837
|
async update(logicalId, physicalId, resourceType, properties, previousProperties, context) {
|
|
29169
29838
|
refuseMalformedDesiredTags(properties["Tags"], resourceType, logicalId, physicalId, "Tags", DBPROXY_TAGS_WHAT, DBPROXY_TAG_OPTIONS);
|
|
29170
|
-
if (context?.replayingState !== true && context?.desiredFromAwsReadback !== true && this.removedRetained(properties, previousProperties, context).includes("Auth") && authRemovalRefused(properties)) throw markNonRetryable(new ProvisioningError(safeMsg`${logicalId} (${resourceType}): Auth was removed from the template, but AWS requires Auth while DefaultAuthScheme is NONE or unset, and CloudFormation's update fails on the same change. Declare Auth again; nothing was changed.`, resourceType, logicalId, physicalId));
|
|
29839
|
+
if (context?.replayingState !== true && context?.desiredFromAwsReadback !== true && this.removedRetained(properties, previousProperties, context).includes("Auth") && authRemovalRefused(properties, previousProperties)) throw markNonRetryable(new ProvisioningError(safeMsg`${logicalId} (${resourceType}): Auth was removed from the template, but AWS requires Auth while DefaultAuthScheme is NONE or unset, and CloudFormation's update fails on the same change. Declare Auth again; nothing was changed.`, resourceType, logicalId, physicalId));
|
|
29840
|
+
if (context?.replayingState !== true && context?.desiredFromAwsReadback !== true && leavesProxyWithoutAuth(properties, previousProperties)) throw markNonRetryable(new ProvisioningError(safeMsg`${logicalId} (${resourceType}): the update leaves the proxy with no Auth while DefaultAuthScheme is NONE or unset, and AWS requires Auth then. Declare Auth; nothing was changed.`, resourceType, logicalId, physicalId));
|
|
29171
29841
|
const client = this.getClient();
|
|
29172
29842
|
const { mask } = withDerivedNameMasks(this.logger, createMaskedLogSinks(this.logger, context?.maskSecrets), [[previousProperties["DBProxyName"], physicalId]]);
|
|
29173
29843
|
for (const field of [
|
|
29174
29844
|
"DBProxyName",
|
|
29175
29845
|
"EngineFamily",
|
|
29176
|
-
"VpcSubnetIds"
|
|
29846
|
+
"VpcSubnetIds",
|
|
29847
|
+
"EndpointNetworkType",
|
|
29848
|
+
"TargetConnectionNetworkType"
|
|
29177
29849
|
]) if (JSON.stringify(properties[field]) !== JSON.stringify(previousProperties[field]) && !await unchangedBehindSecretReference({
|
|
29178
29850
|
resourceType,
|
|
29179
29851
|
key: field,
|
|
@@ -29186,6 +29858,7 @@ var RDSDBProxyProvider = class {
|
|
|
29186
29858
|
let hasModify = false;
|
|
29187
29859
|
for (const key of [
|
|
29188
29860
|
"Auth",
|
|
29861
|
+
"DefaultAuthScheme",
|
|
29189
29862
|
"RequireTLS",
|
|
29190
29863
|
"IdleClientTimeout",
|
|
29191
29864
|
"DebugLogging",
|
|
@@ -29313,7 +29986,10 @@ var RDSDBProxyProvider = class {
|
|
|
29313
29986
|
SecretArn: a.SecretArn,
|
|
29314
29987
|
IAMAuth: a.IAMAuth,
|
|
29315
29988
|
ClientPasswordAuthType: a.ClientPasswordAuthType
|
|
29316
|
-
}))
|
|
29989
|
+
})),
|
|
29990
|
+
...p.DefaultAuthScheme !== void 0 && { DefaultAuthScheme: p.DefaultAuthScheme },
|
|
29991
|
+
...p.EndpointNetworkType !== void 0 && { EndpointNetworkType: p.EndpointNetworkType },
|
|
29992
|
+
...p.TargetConnectionNetworkType !== void 0 && { TargetConnectionNetworkType: p.TargetConnectionNetworkType }
|
|
29317
29993
|
};
|
|
29318
29994
|
if (p.DBProxyArn) try {
|
|
29319
29995
|
const tagResp = await client.send(new ListTagsForResourceCommand$10({ ResourceName: p.DBProxyArn }));
|
|
@@ -29416,6 +30092,7 @@ var RDSDBProxyEndpointProvider = class {
|
|
|
29416
30092
|
"VpcSubnetIds",
|
|
29417
30093
|
"VpcSecurityGroupIds",
|
|
29418
30094
|
"TargetRole",
|
|
30095
|
+
"EndpointNetworkType",
|
|
29419
30096
|
"Tags"
|
|
29420
30097
|
])]]);
|
|
29421
30098
|
getClient() {
|
|
@@ -29452,11 +30129,13 @@ var RDSDBProxyEndpointProvider = class {
|
|
|
29452
30129
|
VpcSubnetIds: vpcSubnetIds,
|
|
29453
30130
|
VpcSecurityGroupIds: properties["VpcSecurityGroupIds"],
|
|
29454
30131
|
TargetRole: properties["TargetRole"],
|
|
30132
|
+
EndpointNetworkType: properties["EndpointNetworkType"],
|
|
29455
30133
|
Tags: tags.length > 0 ? tags : void 0
|
|
29456
30134
|
}));
|
|
29457
30135
|
} catch (error) {
|
|
29458
30136
|
throw this.wrapCaughtError(error, "CREATE", resourceType, logicalId, void 0, mask);
|
|
29459
30137
|
}
|
|
30138
|
+
reportCreatedResource(logicalId, resourceType, dbProxyEndpointName);
|
|
29460
30139
|
let endpoint;
|
|
29461
30140
|
let arn;
|
|
29462
30141
|
let isDefault;
|
|
@@ -29506,7 +30185,8 @@ var RDSDBProxyEndpointProvider = class {
|
|
|
29506
30185
|
"DBProxyName",
|
|
29507
30186
|
"DBProxyEndpointName",
|
|
29508
30187
|
"VpcSubnetIds",
|
|
29509
|
-
"TargetRole"
|
|
30188
|
+
"TargetRole",
|
|
30189
|
+
"EndpointNetworkType"
|
|
29510
30190
|
]) if (JSON.stringify(properties[field]) !== JSON.stringify(previousProperties[field]) && !await unchangedBehindSecretReference({
|
|
29511
30191
|
resourceType,
|
|
29512
30192
|
key: field,
|
|
@@ -29610,7 +30290,8 @@ var RDSDBProxyEndpointProvider = class {
|
|
|
29610
30290
|
DBProxyName: e.DBProxyName,
|
|
29611
30291
|
VpcSubnetIds: e.VpcSubnetIds ?? [],
|
|
29612
30292
|
VpcSecurityGroupIds: e.VpcSecurityGroupIds ?? [],
|
|
29613
|
-
TargetRole: e.TargetRole ?? "READ_WRITE"
|
|
30293
|
+
TargetRole: e.TargetRole ?? "READ_WRITE",
|
|
30294
|
+
...e.EndpointNetworkType !== void 0 && { EndpointNetworkType: e.EndpointNetworkType }
|
|
29614
30295
|
};
|
|
29615
30296
|
if (e.DBProxyEndpointArn) try {
|
|
29616
30297
|
const tagResp = await client.send(new ListTagsForResourceCommand$10({ ResourceName: e.DBProxyEndpointArn }));
|
|
@@ -29816,6 +30497,7 @@ var RDSDBProxyTargetGroupProvider = class {
|
|
|
29816
30497
|
throw await this.retireRegistrationAfterFailedCreate(this.wrapError(error, "CREATE (describe)", resourceType, logicalId, void 0, mask), dbProxyName, targetGroupName, dbClusterIdentifiers, dbInstanceIdentifiers, context?.maskSecrets);
|
|
29817
30498
|
}
|
|
29818
30499
|
if (!targetGroupArn) throw await this.retireRegistrationAfterFailedCreate(new ProvisioningError(`Failed to recover TargetGroupArn for ${dbProxyName}/${targetGroupName} after create`, resourceType, logicalId), dbProxyName, targetGroupName, dbClusterIdentifiers, dbInstanceIdentifiers, context?.maskSecrets);
|
|
30500
|
+
if (dbClusterIdentifiers.length > 0 || dbInstanceIdentifiers.length > 0) reportCreatedResource(logicalId, resourceType, targetGroupArn);
|
|
29819
30501
|
if (tags.length > 0) try {
|
|
29820
30502
|
await client.send(new AddTagsToResourceCommand$2({
|
|
29821
30503
|
ResourceName: targetGroupArn,
|
|
@@ -30135,6 +30817,7 @@ var RDSDBProxyTargetGroupProvider = class {
|
|
|
30135
30817
|
DBClusterIdentifiers: clusters,
|
|
30136
30818
|
DBInstanceIdentifiers: instances
|
|
30137
30819
|
}));
|
|
30820
|
+
if (leftBehind) retractCreatedResource(leftBehind.logicalId, leftBehind.resourceType, leftBehind.physicalId);
|
|
30138
30821
|
return original;
|
|
30139
30822
|
} catch (cleanupError) {
|
|
30140
30823
|
const aws = pasteableAwsCommand(maskSecrets);
|
|
@@ -30271,6 +30954,25 @@ function masterUserPasswordToSend(properties, previousProperties, context) {
|
|
|
30271
30954
|
return typeof desired === "string" && typeof recorded === "string" && recorded === desired && dynamicReferenceTokens(recorded).length === 0 && recorded !== "***" ? void 0 : desired;
|
|
30272
30955
|
}
|
|
30273
30956
|
const DOCDB_DEFAULT_PORT = 27017;
|
|
30957
|
+
const DOCDB_CLUSTER_KEPT_ON_REMOVAL = [
|
|
30958
|
+
"DeletionProtection",
|
|
30959
|
+
"BackupRetentionPeriod",
|
|
30960
|
+
"VpcSecurityGroupIds",
|
|
30961
|
+
"EngineVersion",
|
|
30962
|
+
"PreferredBackupWindow",
|
|
30963
|
+
"PreferredMaintenanceWindow",
|
|
30964
|
+
"DBClusterParameterGroupName"
|
|
30965
|
+
];
|
|
30966
|
+
const DOCDB_INSTANCE_KEPT_ON_REMOVAL = ["PreferredMaintenanceWindow"];
|
|
30967
|
+
function keptOnRemovalWarning$1(keys, properties, previousProperties, context, logicalId, resourceType) {
|
|
30968
|
+
const removedSet = context?.removedProperties ?? new Set(removedTemplateKeys(previousProperties, properties));
|
|
30969
|
+
const removed = keys.filter((key) => removedSet.has(key));
|
|
30970
|
+
if (removed.length === 0) return void 0;
|
|
30971
|
+
const one = removed.length === 1;
|
|
30972
|
+
const names = `${one ? "property" : "properties"} ${removed.join(", ")}`;
|
|
30973
|
+
const modify = resourceType === "AWS::DocDB::DBInstance" ? "ModifyDBInstance" : "ModifyDBCluster";
|
|
30974
|
+
return context?.replayingState ? safeMsg`${logicalId} (${resourceType}): ${names} ${one ? "is" : "are"} absent from the state being restored; ${modify} keeps a setting it is not sent, so the rollback leaves any value the failed deploy applied in place.` : safeMsg`${logicalId} (${resourceType}): ${names} ${one ? "was" : "were"} removed from the template; cdkd leaves the current AWS ${one ? "value" : "values"} in place, as CloudFormation does. Declare ${one ? "it" : "them"} to change ${one ? "it" : "them"}.`;
|
|
30975
|
+
}
|
|
30274
30976
|
const SECURITY_GROUP_CHANGE_MEMBER_STATUSES = /* @__PURE__ */ new Set(["modifying"]);
|
|
30275
30977
|
const PORT_CHANGE_MEMBER_STATUSES = /* @__PURE__ */ new Set(["modifying", "rebooting"]);
|
|
30276
30978
|
function numberOrUndefined(value) {
|
|
@@ -30312,6 +31014,25 @@ var DocDBProvider = class {
|
|
|
30312
31014
|
logger = getLogger().child("DocDBProvider");
|
|
30313
31015
|
protectionFlips = new ProtectionFlipRegistry();
|
|
30314
31016
|
disableCcApiFallback = true;
|
|
31017
|
+
removalHandledInUpdate = /* @__PURE__ */ new Map([["AWS::DocDB::DBCluster", /* @__PURE__ */ new Set([
|
|
31018
|
+
"DBClusterIdentifier",
|
|
31019
|
+
"DBSubnetGroupName",
|
|
31020
|
+
"KmsKeyId",
|
|
31021
|
+
"MasterUsername",
|
|
31022
|
+
"StorageEncrypted",
|
|
31023
|
+
"Port",
|
|
31024
|
+
"Tags",
|
|
31025
|
+
"MasterUserPassword",
|
|
31026
|
+
...DOCDB_CLUSTER_KEPT_ON_REMOVAL
|
|
31027
|
+
])], ["AWS::DocDB::DBInstance", /* @__PURE__ */ new Set([
|
|
31028
|
+
"DBInstanceIdentifier",
|
|
31029
|
+
"DBClusterIdentifier",
|
|
31030
|
+
"AvailabilityZone",
|
|
31031
|
+
"DBInstanceClass",
|
|
31032
|
+
"Tags",
|
|
31033
|
+
"AutoMinorVersionUpgrade",
|
|
31034
|
+
...DOCDB_INSTANCE_KEPT_ON_REMOVAL
|
|
31035
|
+
])]]);
|
|
30315
31036
|
handledProperties = /* @__PURE__ */ new Map([["AWS::DocDB::DBCluster", /* @__PURE__ */ new Set([
|
|
30316
31037
|
"DBClusterIdentifier",
|
|
30317
31038
|
"EngineVersion",
|
|
@@ -30365,7 +31086,7 @@ var DocDBProvider = class {
|
|
|
30365
31086
|
async update(logicalId, physicalId, resourceType, properties, previousProperties, context) {
|
|
30366
31087
|
switch (resourceType) {
|
|
30367
31088
|
case "AWS::DocDB::DBCluster": return this.updateDBCluster(logicalId, physicalId, resourceType, properties, previousProperties, context);
|
|
30368
|
-
case "AWS::DocDB::DBInstance": return this.updateDBInstance(logicalId, physicalId, resourceType, properties, previousProperties, context
|
|
31089
|
+
case "AWS::DocDB::DBInstance": return this.updateDBInstance(logicalId, physicalId, resourceType, properties, previousProperties, context);
|
|
30369
31090
|
default: throw new ProvisioningError(`Unsupported resource type: ${resourceType}`, resourceType, logicalId, physicalId);
|
|
30370
31091
|
}
|
|
30371
31092
|
}
|
|
@@ -30410,6 +31131,7 @@ var DocDBProvider = class {
|
|
|
30410
31131
|
}));
|
|
30411
31132
|
clusterCreated = true;
|
|
30412
31133
|
createdResourceId = response.DBCluster?.DbClusterResourceId;
|
|
31134
|
+
reportCreatedResource(logicalId, resourceType, dbClusterIdentifier, createdResourceId);
|
|
30413
31135
|
if (!response.DBCluster) throw new Error("CreateDBCluster did not return DBCluster");
|
|
30414
31136
|
this.logger.debug(`Successfully created DocDB DBCluster ${logicalId}: ${dbClusterIdentifier}`);
|
|
30415
31137
|
if (process.env["CDKD_NO_WAIT"] !== "true") await this.waitForClusterAvailable(logicalId, dbClusterIdentifier);
|
|
@@ -30456,6 +31178,8 @@ var DocDBProvider = class {
|
|
|
30456
31178
|
for (const member of described?.DBClusterMembers ?? []) if (member.DBInstanceIdentifier) await this.waitForMemberAfterClusterChange(member.DBInstanceIdentifier, logicalId, SECURITY_GROUP_CHANGE_MEMBER_STATUSES, "VPC security groups");
|
|
30457
31179
|
}
|
|
30458
31180
|
if (described?.DBClusterArn) await applyDocDBTagDiff(this.getClient(), this.logger, described.DBClusterArn, resourceType, logicalId, previousProperties["Tags"], properties["Tags"]);
|
|
31181
|
+
const keptWarning = keptOnRemovalWarning$1(DOCDB_CLUSTER_KEPT_ON_REMOVAL, properties, previousProperties, context, logicalId, resourceType);
|
|
31182
|
+
if (keptWarning !== void 0) this.logger.warn(keptWarning);
|
|
30459
31183
|
return {
|
|
30460
31184
|
physicalId,
|
|
30461
31185
|
wasReplaced: false,
|
|
@@ -30565,6 +31289,7 @@ var DocDBProvider = class {
|
|
|
30565
31289
|
}));
|
|
30566
31290
|
instanceCreated = true;
|
|
30567
31291
|
createdResourceId = response.DBInstance?.DbiResourceId;
|
|
31292
|
+
reportCreatedResource(logicalId, resourceType, dbInstanceIdentifier, createdResourceId);
|
|
30568
31293
|
if (!response.DBInstance) throw new Error("CreateDBInstance did not return DBInstance");
|
|
30569
31294
|
this.logger.debug(`Successfully created DocDB DBInstance ${logicalId}: ${dbInstanceIdentifier}`);
|
|
30570
31295
|
if (process.env["CDKD_NO_WAIT"] !== "true") await this.waitForInstanceAvailable(logicalId, dbInstanceIdentifier);
|
|
@@ -30578,8 +31303,9 @@ var DocDBProvider = class {
|
|
|
30578
31303
|
throw thrown;
|
|
30579
31304
|
}
|
|
30580
31305
|
}
|
|
30581
|
-
async updateDBInstance(logicalId, physicalId, resourceType, properties, previousProperties,
|
|
31306
|
+
async updateDBInstance(logicalId, physicalId, resourceType, properties, previousProperties, context) {
|
|
30582
31307
|
this.logger.debug(`Updating DocDB DBInstance ${logicalId}: ${physicalId}`);
|
|
31308
|
+
const mask = context?.maskSecrets;
|
|
30583
31309
|
refuseMalformedDesiredTags(properties["Tags"], resourceType, logicalId, physicalId);
|
|
30584
31310
|
try {
|
|
30585
31311
|
await modifyDbInstanceWhenAvailable({
|
|
@@ -30600,6 +31326,8 @@ var DocDBProvider = class {
|
|
|
30600
31326
|
this.logger.debug(`Successfully updated DocDB DBInstance ${logicalId}`);
|
|
30601
31327
|
const described = await this.describeDBInstance(physicalId);
|
|
30602
31328
|
if (described?.DBInstanceArn) await applyDocDBTagDiff(this.getClient(), this.logger, described.DBInstanceArn, resourceType, logicalId, previousProperties["Tags"], properties["Tags"]);
|
|
31329
|
+
const keptWarning = keptOnRemovalWarning$1(DOCDB_INSTANCE_KEPT_ON_REMOVAL, properties, previousProperties, context, logicalId, resourceType);
|
|
31330
|
+
if (keptWarning !== void 0) this.logger.warn(keptWarning);
|
|
30603
31331
|
return {
|
|
30604
31332
|
physicalId,
|
|
30605
31333
|
wasReplaced: false,
|
|
@@ -31268,6 +31996,7 @@ var Route53Provider = class {
|
|
|
31268
31996
|
if (!hostedZone?.Id) throw new Error("CreateHostedZone did not return HostedZone.Id");
|
|
31269
31997
|
const zoneId = hostedZone.Id.replace("/hostedzone/", "");
|
|
31270
31998
|
createdZoneId = zoneId;
|
|
31999
|
+
reportCreatedResource(logicalId, resourceType, zoneId);
|
|
31271
32000
|
if (vpcs && vpcs.length > 1) for (let i = 1; i < vpcs.length; i++) {
|
|
31272
32001
|
const additionalVpc = vpcs[i];
|
|
31273
32002
|
this.logger.debug(`Associating additional VPC ${String(additionalVpc["VPCId"])} with hosted zone ${zoneId}`);
|
|
@@ -31293,6 +32022,7 @@ var Route53Provider = class {
|
|
|
31293
32022
|
await this.deleteQueryLoggingConfigForZone(zoneId, logicalId);
|
|
31294
32023
|
await this.getClient().send(new DeleteHostedZoneCommand({ Id: zoneId }));
|
|
31295
32024
|
zoneRolledBack = true;
|
|
32025
|
+
retractCreatedResource(logicalId, resourceType, zoneId);
|
|
31296
32026
|
callerReferenceToken.release();
|
|
31297
32027
|
} catch (deleteError) {
|
|
31298
32028
|
const head = `Best-effort rollback DeleteHostedZone for ${zoneId} also failed: `;
|
|
@@ -32213,6 +32943,27 @@ function sanitizeDescription(value) {
|
|
|
32213
32943
|
function isPlainObject$2(value) {
|
|
32214
32944
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
32215
32945
|
}
|
|
32946
|
+
const DATA_PROTECTION_FALSE_DEFAULTS = ["ExcludeRuleMatchDetails", "ExcludeRateBasedDetails"];
|
|
32947
|
+
function toCfnDataProtectionConfig(config, baseline) {
|
|
32948
|
+
const entries = config["DataProtections"];
|
|
32949
|
+
if (!Array.isArray(entries)) return config;
|
|
32950
|
+
const baseEntries = isPlainObject$2(baseline) && Array.isArray(baseline["DataProtections"]) ? baseline["DataProtections"] : [];
|
|
32951
|
+
return {
|
|
32952
|
+
...config,
|
|
32953
|
+
DataProtections: entries.map((entry, i) => {
|
|
32954
|
+
if (!isPlainObject$2(entry)) return entry;
|
|
32955
|
+
const base = baseEntries[i];
|
|
32956
|
+
const converted = { ...entry };
|
|
32957
|
+
for (const key of DATA_PROTECTION_FALSE_DEFAULTS) if (converted[key] === false && !(isPlainObject$2(base) && key in base)) delete converted[key];
|
|
32958
|
+
return converted;
|
|
32959
|
+
})
|
|
32960
|
+
};
|
|
32961
|
+
}
|
|
32962
|
+
function applicationConfigForUpdate(next, previous) {
|
|
32963
|
+
if (next === void 0 || next === null) return void 0;
|
|
32964
|
+
if (isDeepStrictEqual(next, previous)) return void 0;
|
|
32965
|
+
return next;
|
|
32966
|
+
}
|
|
32216
32967
|
function toSdkByteMatchStatement(byteMatchStatement) {
|
|
32217
32968
|
const encoded = byteMatchStatement["SearchStringBase64"];
|
|
32218
32969
|
if (typeof encoded !== "string") return byteMatchStatement;
|
|
@@ -32391,7 +33142,11 @@ var WAFv2WebACLProvider = class {
|
|
|
32391
33142
|
"CaptchaConfig",
|
|
32392
33143
|
"ChallengeConfig",
|
|
32393
33144
|
"TokenDomains",
|
|
32394
|
-
"AssociationConfig"
|
|
33145
|
+
"AssociationConfig",
|
|
33146
|
+
"DataProtectionConfig",
|
|
33147
|
+
"OnSourceDDoSProtectionConfig",
|
|
33148
|
+
"ApplicationConfig",
|
|
33149
|
+
"MonetizationConfig"
|
|
32395
33150
|
])]]);
|
|
32396
33151
|
getClient() {
|
|
32397
33152
|
if (!this.wafv2Client) {
|
|
@@ -32432,7 +33187,11 @@ var WAFv2WebACLProvider = class {
|
|
|
32432
33187
|
CaptchaConfig: properties["CaptchaConfig"],
|
|
32433
33188
|
ChallengeConfig: properties["ChallengeConfig"],
|
|
32434
33189
|
TokenDomains: properties["TokenDomains"],
|
|
32435
|
-
AssociationConfig: properties["AssociationConfig"]
|
|
33190
|
+
AssociationConfig: properties["AssociationConfig"],
|
|
33191
|
+
DataProtectionConfig: properties["DataProtectionConfig"],
|
|
33192
|
+
OnSourceDDoSProtectionConfig: properties["OnSourceDDoSProtectionConfig"],
|
|
33193
|
+
ApplicationConfig: properties["ApplicationConfig"],
|
|
33194
|
+
MonetizationConfig: properties["MonetizationConfig"]
|
|
32436
33195
|
}))).Summary;
|
|
32437
33196
|
if (!summary?.ARN || !summary?.Id) throw new Error("CreateWebACL did not return Summary with ARN and Id");
|
|
32438
33197
|
this.logger.debug(`Successfully created WAFv2 WebACL ${logicalId}: ${summary.ARN}`);
|
|
@@ -32486,7 +33245,11 @@ var WAFv2WebACLProvider = class {
|
|
|
32486
33245
|
CaptchaConfig: properties["CaptchaConfig"],
|
|
32487
33246
|
ChallengeConfig: properties["ChallengeConfig"],
|
|
32488
33247
|
TokenDomains: properties["TokenDomains"],
|
|
32489
|
-
AssociationConfig: properties["AssociationConfig"]
|
|
33248
|
+
AssociationConfig: properties["AssociationConfig"],
|
|
33249
|
+
DataProtectionConfig: properties["DataProtectionConfig"],
|
|
33250
|
+
OnSourceDDoSProtectionConfig: properties["OnSourceDDoSProtectionConfig"],
|
|
33251
|
+
ApplicationConfig: applicationConfigForUpdate(properties["ApplicationConfig"], previousProperties["ApplicationConfig"]),
|
|
33252
|
+
MonetizationConfig: properties["MonetizationConfig"]
|
|
32490
33253
|
}));
|
|
32491
33254
|
await this.applyTagDiff(physicalId, resourceType, logicalId, previousProperties["Tags"], properties["Tags"]);
|
|
32492
33255
|
this.logger.debug(`Successfully updated WAFv2 WebACL ${logicalId}`);
|
|
@@ -32593,6 +33356,10 @@ var WAFv2WebACLProvider = class {
|
|
|
32593
33356
|
if (webACL.ChallengeConfig) result["ChallengeConfig"] = webACL.ChallengeConfig;
|
|
32594
33357
|
result["TokenDomains"] = webACL.TokenDomains ? [...webACL.TokenDomains] : [];
|
|
32595
33358
|
if (webACL.AssociationConfig) result["AssociationConfig"] = webACL.AssociationConfig;
|
|
33359
|
+
if (webACL.DataProtectionConfig) result["DataProtectionConfig"] = toCfnDataProtectionConfig(webACL.DataProtectionConfig, properties?.["DataProtectionConfig"]);
|
|
33360
|
+
if (webACL.OnSourceDDoSProtectionConfig) result["OnSourceDDoSProtectionConfig"] = webACL.OnSourceDDoSProtectionConfig;
|
|
33361
|
+
if (webACL.ApplicationConfig) result["ApplicationConfig"] = webACL.ApplicationConfig;
|
|
33362
|
+
if (webACL.MonetizationConfig) result["MonetizationConfig"] = webACL.MonetizationConfig;
|
|
32596
33363
|
try {
|
|
32597
33364
|
const tagsResp = await this.getClient().send(new ListTagsForResourceCommand$13({ ResourceARN: physicalId }));
|
|
32598
33365
|
result["Tags"] = normalizeAwsTagsToCfn(tagsResp.TagInfoForResource?.TagList);
|
|
@@ -33068,6 +33835,7 @@ var CognitoUserPoolProvider = class {
|
|
|
33068
33835
|
if (!userPool?.Id) throw new Error("CreateUserPool did not return UserPool.Id");
|
|
33069
33836
|
const userPoolId = userPool.Id;
|
|
33070
33837
|
createdUserPoolId = userPoolId;
|
|
33838
|
+
reportCreatedResource(logicalId, resourceType, userPoolId);
|
|
33071
33839
|
const replayWindow = replayedSendWindow(created, attemptStartMs);
|
|
33072
33840
|
if (replayWindow !== void 0) await this.reportPossibleOrphanPools(logicalId, poolName, replayWindow, createMaskedLogSinks(this.logger, context?.maskSecrets), userPoolId);
|
|
33073
33841
|
const userPoolArn = userPool.Arn;
|
|
@@ -33095,6 +33863,7 @@ var CognitoUserPoolProvider = class {
|
|
|
33095
33863
|
markAuxiliaryFailure(error, logicalId);
|
|
33096
33864
|
try {
|
|
33097
33865
|
await this.getClient().send(new DeleteUserPoolCommand({ UserPoolId: createdUserPoolId }));
|
|
33866
|
+
retractCreatedResource(logicalId, resourceType, createdUserPoolId);
|
|
33098
33867
|
this.logger.debug(`Rolled back partially-created Cognito User Pool ${createdUserPoolId}`);
|
|
33099
33868
|
} catch (rollbackError) {
|
|
33100
33869
|
poolLeftBehind = true;
|
|
@@ -33791,6 +34560,36 @@ function nodesToRemove(nodes, desiredCount, desiredZones) {
|
|
|
33791
34560
|
if (keep.size + unnamed < desiredCount) return void 0;
|
|
33792
34561
|
return named.map((n) => n.id).filter((id) => !keep.has(id)).sort();
|
|
33793
34562
|
}
|
|
34563
|
+
const KEPT_ON_REMOVAL$1 = [
|
|
34564
|
+
"EngineVersion",
|
|
34565
|
+
"CacheParameterGroupName",
|
|
34566
|
+
"PreferredMaintenanceWindow",
|
|
34567
|
+
"SnapshotWindow",
|
|
34568
|
+
"IpDiscovery",
|
|
34569
|
+
"SnapshotRetentionLimit",
|
|
34570
|
+
"AutoMinorVersionUpgrade",
|
|
34571
|
+
"NotificationTopicArn",
|
|
34572
|
+
"VpcSecurityGroupIds",
|
|
34573
|
+
"TransitEncryptionEnabled",
|
|
34574
|
+
"PreferredAvailabilityZone"
|
|
34575
|
+
];
|
|
34576
|
+
const NOT_MODIFIABLE = /* @__PURE__ */ new Set(["TransitEncryptionEnabled", "PreferredAvailabilityZone"]);
|
|
34577
|
+
const PLACEMENT_ON_REMOVAL = ["AZMode", "PreferredAvailabilityZones"];
|
|
34578
|
+
const removalWarnings = (logicalId, kept, placement, caller) => {
|
|
34579
|
+
const lines = [];
|
|
34580
|
+
const head = (names) => safeMsg`${logicalId} (AWS::ElastiCache::CacheCluster): ${names.length === 1 ? "property" : "properties"} ${names.join(", ")}`;
|
|
34581
|
+
if (kept.length > 0) {
|
|
34582
|
+
const one = kept.length === 1;
|
|
34583
|
+
const fixed = kept.filter((name) => NOT_MODIFIABLE.has(name));
|
|
34584
|
+
const replaceNote = fixed.length === 0 ? "" : safeMsg` (${fixed.join(", ")} ${fixed.length === 1 ? "changes" : "change"} only by replacing the cluster)`;
|
|
34585
|
+
lines.push(caller === "rollback" ? `${head(kept)} ${one ? "is" : "are"} absent from the state being restored; the rollback sends nothing for ${one ? "it" : "them"}, so the cluster keeps the value it holds now.` : `${head(kept)} ${one ? "was" : "were"} removed from the template and ${one ? "keeps its" : "keep their"} current AWS value, as CloudFormation leaves ${one ? "it" : "them"}; cdkd sends nothing for a removed property. To change a value, declare it explicitly${replaceNote}.`);
|
|
34586
|
+
}
|
|
34587
|
+
if (placement.length > 0) {
|
|
34588
|
+
const one = placement.length === 1;
|
|
34589
|
+
lines.push(caller === "rollback" ? `${head(placement)} ${one ? "is" : "are"} absent from the state being restored; the rollback leaves the cluster unchanged.` : `${head(placement)} ${one ? "was" : "were"} removed from the template; cdkd sends nothing for a removed property, so the nodes stay in their zones. CloudFormation updates a cross-az cluster, or a single-az one that keeps its zone list, in place. It replaces a memcached single-az cluster left with no zone, and cdkd plans that replacement too (go-to-k/cdkd#5558). To move the nodes, replace the cluster, for example by changing its logical ID.`);
|
|
34590
|
+
}
|
|
34591
|
+
return lines;
|
|
34592
|
+
};
|
|
33794
34593
|
var ElastiCacheProvider = class {
|
|
33795
34594
|
client;
|
|
33796
34595
|
createClient;
|
|
@@ -33840,6 +34639,22 @@ var ElastiCacheProvider = class {
|
|
|
33840
34639
|
"TransitEncryptionEnabled"
|
|
33841
34640
|
])]]);
|
|
33842
34641
|
unhandledByDesign = /* @__PURE__ */ new Map([["AWS::ElastiCache::CacheCluster", /* @__PURE__ */ new Map([["CacheSecurityGroupNames", "EC2-Classic-only — use VpcSecurityGroupIds for VPC-deployed clusters (EC2-Classic retired 2022-08-15)"]])]]);
|
|
34642
|
+
removalHandledInUpdate = /* @__PURE__ */ new Map([["AWS::ElastiCache::CacheCluster", /* @__PURE__ */ new Set([
|
|
34643
|
+
"CacheSubnetGroupName",
|
|
34644
|
+
"ClusterName",
|
|
34645
|
+
"Engine",
|
|
34646
|
+
"NetworkType",
|
|
34647
|
+
"Port",
|
|
34648
|
+
"SnapshotName",
|
|
34649
|
+
"SnapshotArns",
|
|
34650
|
+
"CacheSecurityGroupNames",
|
|
34651
|
+
"CacheNodeType",
|
|
34652
|
+
"NumCacheNodes",
|
|
34653
|
+
"Tags",
|
|
34654
|
+
"LogDeliveryConfigurations",
|
|
34655
|
+
...KEPT_ON_REMOVAL$1,
|
|
34656
|
+
...PLACEMENT_ON_REMOVAL
|
|
34657
|
+
])]]);
|
|
33843
34658
|
getClient() {
|
|
33844
34659
|
if (!this.client) {
|
|
33845
34660
|
this.client = new ElastiCacheClient({
|
|
@@ -33869,7 +34684,7 @@ var ElastiCacheProvider = class {
|
|
|
33869
34684
|
const mask = context?.maskSecrets;
|
|
33870
34685
|
switch (resourceType) {
|
|
33871
34686
|
case "AWS::ElastiCache::SubnetGroup": return this.updateSubnetGroup(logicalId, physicalId, resourceType, properties, previousProperties, mask);
|
|
33872
|
-
case "AWS::ElastiCache::CacheCluster": return this.updateCacheCluster(logicalId, physicalId, resourceType, properties, previousProperties, mask);
|
|
34687
|
+
case "AWS::ElastiCache::CacheCluster": return this.updateCacheCluster(logicalId, physicalId, resourceType, properties, previousProperties, mask, context);
|
|
33873
34688
|
default: throw new ProvisioningError(`Unsupported resource type: ${resourceType}`, resourceType, logicalId, physicalId);
|
|
33874
34689
|
}
|
|
33875
34690
|
}
|
|
@@ -33976,6 +34791,7 @@ var ElastiCacheProvider = class {
|
|
|
33976
34791
|
...tags.length > 0 && { Tags: tags }
|
|
33977
34792
|
}));
|
|
33978
34793
|
clusterCreated = true;
|
|
34794
|
+
reportCreatedResource(logicalId, resourceType, cacheClusterId);
|
|
33979
34795
|
this.logger.debug(`Successfully created CacheCluster ${logicalId}: ${cacheClusterId}`);
|
|
33980
34796
|
if (process.env["CDKD_NO_WAIT"] !== "true") await this.waitForClusterAvailable(cacheClusterId);
|
|
33981
34797
|
const described = await this.describeCacheCluster(cacheClusterId);
|
|
@@ -34000,7 +34816,7 @@ var ElastiCacheProvider = class {
|
|
|
34000
34816
|
throw thrown;
|
|
34001
34817
|
}
|
|
34002
34818
|
}
|
|
34003
|
-
async updateCacheCluster(logicalId, physicalId, resourceType, properties, previousProperties, mask) {
|
|
34819
|
+
async updateCacheCluster(logicalId, physicalId, resourceType, properties, previousProperties, mask, context) {
|
|
34004
34820
|
this.logger.debug(`Updating CacheCluster ${logicalId}: ${physicalId}`);
|
|
34005
34821
|
refuseMalformedDesiredTags(properties["Tags"], resourceType, logicalId, physicalId);
|
|
34006
34822
|
try {
|
|
@@ -34039,6 +34855,7 @@ var ElastiCacheProvider = class {
|
|
|
34039
34855
|
const described = await this.describeCacheCluster(physicalId);
|
|
34040
34856
|
this.warnTransitEncryptionNotApplied(logicalId, properties, previousProperties, described?.TransitEncryptionEnabled);
|
|
34041
34857
|
if (described?.ARN) await this.applyTagDiff(described.ARN, resourceType, logicalId, previousProperties["Tags"], properties["Tags"]);
|
|
34858
|
+
this.warnRemovalsLeftInPlace(logicalId, properties, previousProperties, context);
|
|
34042
34859
|
const attributes = {};
|
|
34043
34860
|
if (described?.CacheNodes?.[0]?.Endpoint) {
|
|
34044
34861
|
const endpoint = described.CacheNodes[0].Endpoint;
|
|
@@ -34139,6 +34956,13 @@ var ElastiCacheProvider = class {
|
|
|
34139
34956
|
if (notApplied.length === 0) return;
|
|
34140
34957
|
this.logger.warn(safeMsg`CacheCluster ${logicalId}: the ${notApplied.join(", ")} change is not applied to the ` + "existing cluster (ModifyCacheCluster cannot change it, and CloudFormation leaves it unchanged too). To apply it, replace the cluster, for example by changing its logical ID.");
|
|
34141
34958
|
}
|
|
34959
|
+
warnRemovalsLeftInPlace(logicalId, properties, previousProperties, context) {
|
|
34960
|
+
if (context?.desiredFromAwsReadback) return;
|
|
34961
|
+
const removed = context?.removedProperties;
|
|
34962
|
+
const wasRemoved = (key) => removed !== void 0 ? removed.has(key) : properties[key] === void 0 && previousProperties[key] !== void 0;
|
|
34963
|
+
const lines = removalWarnings(logicalId, KEPT_ON_REMOVAL$1.filter(wasRemoved), PLACEMENT_ON_REMOVAL.filter(wasRemoved), context?.replayingState ? "rollback" : "deploy");
|
|
34964
|
+
for (const line of lines) this.logger.warn(line);
|
|
34965
|
+
}
|
|
34142
34966
|
buildLogDeliveryConfigurationsForUpdate(newConfigs, previousConfigs) {
|
|
34143
34967
|
const kept = newConfigs ?? [];
|
|
34144
34968
|
const keptLogTypes = new Set(kept.map((c) => c.LogType).filter((t) => t !== void 0));
|
|
@@ -34786,6 +35610,7 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
|
|
|
34786
35610
|
if (!service || !service.Id) throw new Error("CreateService did not return Service ID");
|
|
34787
35611
|
const serviceId = service.Id;
|
|
34788
35612
|
leftBehindServiceId = serviceId;
|
|
35613
|
+
reportCreatedResource(logicalId, resourceType, serviceId);
|
|
34789
35614
|
this.logger.debug(`Successfully created service discovery service ${logicalId}: ${serviceId}`);
|
|
34790
35615
|
try {
|
|
34791
35616
|
const attrs = this.normalizeServiceAttributes(properties["ServiceAttributes"]);
|
|
@@ -34810,6 +35635,7 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
|
|
|
34810
35635
|
try {
|
|
34811
35636
|
await client.send(new DeleteServiceCommand$1({ Id: serviceId }));
|
|
34812
35637
|
leftBehindServiceId = void 0;
|
|
35638
|
+
retractCreatedResource(logicalId, resourceType, serviceId);
|
|
34813
35639
|
this.logger.debug(`Cleaned up partially-created ServiceDiscovery Service ${logicalId} (${serviceId}) after ServiceAttributes wiring failure`);
|
|
34814
35640
|
} catch (cleanupError) {
|
|
34815
35641
|
const cleanupFailure = describeAwsFailure(cleanupError);
|
|
@@ -35303,6 +36129,25 @@ const APPSYNC_APIKEY_ID_FORMAT = {
|
|
|
35303
36129
|
label: "AppSync ApiKey",
|
|
35304
36130
|
segments: ["apiId", "apiKeyId"]
|
|
35305
36131
|
};
|
|
36132
|
+
const CFN_APPSYNC_ARN_RESOURCE_PATHS = {
|
|
36133
|
+
"AWS::AppSync::GraphQLApi": /^apis\/([^/|]+)$/,
|
|
36134
|
+
"AWS::AppSync::DataSource": /^apis\/([^/|]+)\/datasources\/([^/|]+)$/,
|
|
36135
|
+
"AWS::AppSync::Resolver": /^apis\/([^/|]+)\/types\/([^/|]+)\/resolvers\/([^/|]+)$/,
|
|
36136
|
+
"AWS::AppSync::ApiKey": /^apis\/([^/|]+)\/apikeys?\/([^/|]+)$/
|
|
36137
|
+
};
|
|
36138
|
+
function graphQLSchemaApiId(physicalId) {
|
|
36139
|
+
const schema = /^([a-z0-9]+)GraphQLSchema$/.exec(physicalId);
|
|
36140
|
+
return schema ? schema[1] : physicalId;
|
|
36141
|
+
}
|
|
36142
|
+
function appSyncPhysicalIdFromCfn(resourceType, logicalId, physicalId, region) {
|
|
36143
|
+
if (resourceType === "AWS::AppSync::GraphQLSchema") return graphQLSchemaApiId(physicalId);
|
|
36144
|
+
const pathPattern = CFN_APPSYNC_ARN_RESOURCE_PATHS[resourceType];
|
|
36145
|
+
const arn = /^arn:[^:]+:appsync:([^:]*):[^:]*:(.+)$/.exec(physicalId);
|
|
36146
|
+
const segments = pathPattern && arn ? pathPattern.exec(arn[2]) : null;
|
|
36147
|
+
if (!arn || !segments) return physicalId;
|
|
36148
|
+
if (canonicalizeRegion(arn[1]) !== canonicalizeRegion(region)) throw markNonRetryable(new ProvisioningError(safeMsg`${resourceType} ${physicalId} is in region ${arn[1]}, not the import region ${region}`, resourceType, logicalId, physicalId));
|
|
36149
|
+
return segments.slice(1).join("|");
|
|
36150
|
+
}
|
|
35306
36151
|
const MUTABLE_GRAPHQL_API_CONFIG_PROPERTIES = [
|
|
35307
36152
|
"UserPoolConfig",
|
|
35308
36153
|
"OpenIDConnectConfig",
|
|
@@ -35442,7 +36287,7 @@ var AppSyncProvider = class {
|
|
|
35442
36287
|
}
|
|
35443
36288
|
if (resourceType === "AWS::AppSync::ApiKey" && parts.length === 2) {
|
|
35444
36289
|
const [apiId, apiKeyId] = parts;
|
|
35445
|
-
const apiKeyArn = await arn(`apis/${apiId}/
|
|
36290
|
+
const apiKeyArn = await arn(`apis/${apiId}/apikeys/${apiKeyId}`);
|
|
35446
36291
|
return {
|
|
35447
36292
|
ApiKey: apiKeyId,
|
|
35448
36293
|
...apiKeyArn && { Arn: apiKeyArn }
|
|
@@ -35591,12 +36436,13 @@ var AppSyncProvider = class {
|
|
|
35591
36436
|
};
|
|
35592
36437
|
}
|
|
35593
36438
|
async updateGraphQLSchema(logicalId, physicalId, resourceType, properties, previousProperties, mask = maskerOrIdentity(void 0)) {
|
|
36439
|
+
const recordedApiId = graphQLSchemaApiId(physicalId);
|
|
35594
36440
|
if (properties["ApiId"] !== void 0 && previousProperties["ApiId"] !== void 0 && properties["ApiId"] !== previousProperties["ApiId"] && !await unchangedBehindSecretReference({
|
|
35595
36441
|
resourceType,
|
|
35596
36442
|
key: "ApiId",
|
|
35597
36443
|
desired: properties["ApiId"],
|
|
35598
36444
|
previous: previousProperties["ApiId"],
|
|
35599
|
-
physicalName:
|
|
36445
|
+
physicalName: recordedApiId,
|
|
35600
36446
|
maskSecrets: mask
|
|
35601
36447
|
})) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, "AWS AppSync GraphQLSchema.ApiId cannot move a schema to another API in place (CloudFormation fails a template change of it too) — deploy with --replace, or give the schema a new logical ID, to create it on the new API");
|
|
35602
36448
|
const newDef = properties["Definition"];
|
|
@@ -35621,7 +36467,7 @@ var AppSyncProvider = class {
|
|
|
35621
36467
|
physicalId,
|
|
35622
36468
|
wasReplaced: false
|
|
35623
36469
|
};
|
|
35624
|
-
const apiId = properties["ApiId"] ??
|
|
36470
|
+
const apiId = properties["ApiId"] ?? recordedApiId;
|
|
35625
36471
|
try {
|
|
35626
36472
|
await this.getClient().send(new StartSchemaCreationCommand({
|
|
35627
36473
|
apiId,
|
|
@@ -36234,6 +37080,7 @@ var AppSyncProvider = class {
|
|
|
36234
37080
|
throw error;
|
|
36235
37081
|
}
|
|
36236
37082
|
createdApiId = response.graphqlApi?.apiId;
|
|
37083
|
+
if (createdApiId) reportCreatedResource(logicalId, resourceType, createdApiId);
|
|
36237
37084
|
const apiId = response.graphqlApi.apiId;
|
|
36238
37085
|
const replayWindow = replayedSendWindow(response, attemptStartMs);
|
|
36239
37086
|
if (replayWindow !== void 0) await this.reportPossibleOrphanApis(logicalId, input, replayWindow, maskerOrIdentity(context?.maskSecrets), apiId);
|
|
@@ -36257,6 +37104,7 @@ var AppSyncProvider = class {
|
|
|
36257
37104
|
markAuxiliaryFailure(error, logicalId);
|
|
36258
37105
|
try {
|
|
36259
37106
|
await this.getClient().send(new DeleteGraphqlApiCommand({ apiId: createdApiId }));
|
|
37107
|
+
retractCreatedResource(logicalId, resourceType, createdApiId);
|
|
36260
37108
|
this.logger.debug(`Rolled back partially-created GraphQL API ${createdApiId}`);
|
|
36261
37109
|
} catch (rollbackError) {
|
|
36262
37110
|
apiLeftBehind = true;
|
|
@@ -36543,7 +37391,7 @@ var AppSyncProvider = class {
|
|
|
36543
37391
|
maskSecrets: context?.maskSecrets,
|
|
36544
37392
|
...context?.replayingState === true && { onRefusal: (message) => this.logger.warn(message) }
|
|
36545
37393
|
});
|
|
36546
|
-
const apiKeyArn = await this.buildAppSyncArnOrWarn(`apis/${apiId}/
|
|
37394
|
+
const apiKeyArn = await this.buildAppSyncArnOrWarn(`apis/${apiId}/apikeys/${apiKeyId}`, logicalId, physicalId);
|
|
36547
37395
|
return {
|
|
36548
37396
|
physicalId,
|
|
36549
37397
|
attributes: {
|
|
@@ -36628,10 +37476,11 @@ var AppSyncProvider = class {
|
|
|
36628
37476
|
}
|
|
36629
37477
|
}
|
|
36630
37478
|
async readGraphQLSchema(physicalId, properties) {
|
|
37479
|
+
const apiId = graphQLSchemaApiId(physicalId);
|
|
36631
37480
|
let resp;
|
|
36632
37481
|
try {
|
|
36633
37482
|
resp = await this.getClient().send(new GetIntrospectionSchemaCommand({
|
|
36634
|
-
apiId
|
|
37483
|
+
apiId,
|
|
36635
37484
|
format: "SDL"
|
|
36636
37485
|
}));
|
|
36637
37486
|
} catch (err) {
|
|
@@ -36648,7 +37497,7 @@ var AppSyncProvider = class {
|
|
|
36648
37497
|
if (await this.canonicalizeSdl(stateDefinition, "state") === canonicalAws) definitionToReturn = stateDefinition;
|
|
36649
37498
|
}
|
|
36650
37499
|
return {
|
|
36651
|
-
ApiId:
|
|
37500
|
+
ApiId: apiId,
|
|
36652
37501
|
Definition: definitionToReturn
|
|
36653
37502
|
};
|
|
36654
37503
|
}
|
|
@@ -36889,14 +37738,18 @@ var AppSyncProvider = class {
|
|
|
36889
37738
|
return RESOURCE_NOT_FOUND;
|
|
36890
37739
|
}
|
|
36891
37740
|
async import(input) {
|
|
37741
|
+
const known = input.knownPhysicalId && appSyncPhysicalIdFromCfn(input.resourceType, input.logicalId, input.knownPhysicalId, input.region);
|
|
36892
37742
|
if (input.resourceType !== "AWS::AppSync::GraphQLApi") {
|
|
36893
|
-
if (
|
|
36894
|
-
physicalId:
|
|
36895
|
-
attributes: await this.childImportAttributes(input.resourceType,
|
|
37743
|
+
if (known) return {
|
|
37744
|
+
physicalId: known,
|
|
37745
|
+
attributes: await this.childImportAttributes(input.resourceType, known, input.region)
|
|
36896
37746
|
};
|
|
36897
37747
|
return null;
|
|
36898
37748
|
}
|
|
36899
|
-
const explicit = resolveExplicitPhysicalId(
|
|
37749
|
+
const explicit = resolveExplicitPhysicalId(known ? {
|
|
37750
|
+
...input,
|
|
37751
|
+
knownPhysicalId: known
|
|
37752
|
+
} : input, null);
|
|
36900
37753
|
if (explicit) try {
|
|
36901
37754
|
const response = await this.getClient().send(new GetGraphqlApiCommand({ apiId: explicit }));
|
|
36902
37755
|
return {
|
|
@@ -39391,6 +40244,7 @@ var KMSProvider = class {
|
|
|
39391
40244
|
heldAtMs: Date.now()
|
|
39392
40245
|
});
|
|
39393
40246
|
createdKeyId = keyId;
|
|
40247
|
+
reportCreatedResource(logicalId, resourceType, keyId);
|
|
39394
40248
|
const declinedAtMs = supersededAttempts.get(attemptKey);
|
|
39395
40249
|
supersededAttempts.delete(attemptKey);
|
|
39396
40250
|
supersededPending = declinedAtMs !== void 0 && Date.now() - declinedAtMs <= 18e5;
|
|
@@ -39398,6 +40252,7 @@ var KMSProvider = class {
|
|
|
39398
40252
|
if (replayWindow !== void 0) await this.reportPossibleOrphanKeys(logicalId, input, replayWindow);
|
|
39399
40253
|
}
|
|
39400
40254
|
createdKeyId = keyId;
|
|
40255
|
+
reportCreatedResource(logicalId, resourceType, keyId);
|
|
39401
40256
|
if (enableKeyRotation === true) {
|
|
39402
40257
|
const rotationPeriodInDays = properties["RotationPeriodInDays"];
|
|
39403
40258
|
this.logger.debug(`Enabling key rotation for KMS Key ${logicalId}`);
|
|
@@ -40623,58 +41478,6 @@ var BudgetsBudgetProvider = class {
|
|
|
40623
41478
|
}
|
|
40624
41479
|
};
|
|
40625
41480
|
|
|
40626
|
-
//#endregion
|
|
40627
|
-
//#region src/provisioning/delete-gone-wait.ts
|
|
40628
|
-
async function waitForGoneAfterDelete(opts) {
|
|
40629
|
-
const sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
40630
|
-
const now = opts.now ?? Date.now;
|
|
40631
|
-
const userTimeoutMs = resolvedResourceTimeoutMs(opts.resourceType);
|
|
40632
|
-
const maxWaitMs = userTimeoutMs === void 0 ? opts.maxWaitMs : Math.min(opts.maxWaitMs, userTimeoutMs / 2);
|
|
40633
|
-
const startedAt = now();
|
|
40634
|
-
const stopped = `${opts.what}: the delete was ACCEPTED by AWS, but cdkd stopped waiting for it to disappear`;
|
|
40635
|
-
const consequence = "AWS finishes the delete on its side; until it does, a create of the same name is refused with \"already exists\".";
|
|
40636
|
-
const watch = startInterruptWatch(`${opts.what} deletion wait`);
|
|
40637
|
-
try {
|
|
40638
|
-
let lastStatus;
|
|
40639
|
-
let sawNonFailedStatus = false;
|
|
40640
|
-
for (;;) {
|
|
40641
|
-
if (watch.isInterrupted()) {
|
|
40642
|
-
opts.logger.warn(safeMsg`${stopped} (interrupted). ${consequence}`);
|
|
40643
|
-
return;
|
|
40644
|
-
}
|
|
40645
|
-
try {
|
|
40646
|
-
const status = await opts.describe();
|
|
40647
|
-
if (status === void 0) {
|
|
40648
|
-
opts.logger.debug(safeMsg`${opts.what} is gone`);
|
|
40649
|
-
return;
|
|
40650
|
-
}
|
|
40651
|
-
const failure = opts.failedStatus?.(status);
|
|
40652
|
-
if (failure !== void 0) {
|
|
40653
|
-
if (sawNonFailedStatus || now() - startedAt >= opts.pollIntervalMs) throw markWaitAbandoned(failure);
|
|
40654
|
-
} else sawNonFailedStatus = true;
|
|
40655
|
-
lastStatus = status;
|
|
40656
|
-
opts.logger.debug(safeMsg`${opts.what} status: ${status}, waiting for it to disappear`);
|
|
40657
|
-
} catch (error) {
|
|
40658
|
-
if (isWaitAbandonedError(error)) throw error;
|
|
40659
|
-
if (!isThrottlingError(error) && !isTransientServerError(error)) {
|
|
40660
|
-
opts.logger.debug(safeMsg`${opts.what}: status read failed: ${describeAwsFailure(error).detail}`);
|
|
40661
|
-
opts.logger.warn(safeMsg`${stopped}: its status could not be read (${describeAwsFailure(error).summary}). ${consequence}`);
|
|
40662
|
-
return;
|
|
40663
|
-
}
|
|
40664
|
-
opts.logger.debug(safeMsg`${opts.what}: status read throttled or failed transiently, re-polling`);
|
|
40665
|
-
}
|
|
40666
|
-
const remainingMs = maxWaitMs - (now() - startedAt);
|
|
40667
|
-
if (remainingMs <= 0) {
|
|
40668
|
-
opts.logger.warn(safeMsg`${stopped} after ${Math.round(maxWaitMs / 1e3)}s` + safeMsg`${lastStatus !== void 0 ? ` (last status: ${lastStatus})` : ""}. ${consequence}`);
|
|
40669
|
-
return;
|
|
40670
|
-
}
|
|
40671
|
-
await sleep(Math.min(opts.pollIntervalMs, remainingMs));
|
|
40672
|
-
}
|
|
40673
|
-
} finally {
|
|
40674
|
-
watch.dispose();
|
|
40675
|
-
}
|
|
40676
|
-
}
|
|
40677
|
-
|
|
40678
41481
|
//#endregion
|
|
40679
41482
|
//#region src/provisioning/providers/kinesis-provider.ts
|
|
40680
41483
|
function isKmsEncryption(value) {
|
|
@@ -40864,6 +41667,7 @@ var KinesisStreamProvider = class {
|
|
|
40864
41667
|
...Object.keys(tags).length > 0 && { Tags: tags }
|
|
40865
41668
|
}));
|
|
40866
41669
|
streamCreated = true;
|
|
41670
|
+
reportCreatedResource(logicalId, resourceType, streamName);
|
|
40867
41671
|
this.logger.debug(`CreateStream initiated for ${streamName}, waiting for ACTIVE status`);
|
|
40868
41672
|
const streamInfo = await this.waitForStreamActive(streamName);
|
|
40869
41673
|
const retentionPeriodHours = retentionRead.kind === "usable" ? retentionRead.hours : void 0;
|
|
@@ -40969,7 +41773,10 @@ var KinesisStreamProvider = class {
|
|
|
40969
41773
|
}
|
|
40970
41774
|
await this.applyTagDiff(physicalId, resourceType, logicalId, previousProperties["Tags"], properties["Tags"], {
|
|
40971
41775
|
forceUpsert: context?.unsettledProperties?.has("Tags") === true,
|
|
40972
|
-
beforeWrite: () => markUnsettled("Tags")
|
|
41776
|
+
beforeWrite: () => markUnsettled("Tags"),
|
|
41777
|
+
afterAdded: (keys) => {
|
|
41778
|
+
if (keys.length > 0) context?.markAttempted?.("Tags", keys);
|
|
41779
|
+
}
|
|
40973
41780
|
});
|
|
40974
41781
|
const newEncryption = properties["StreamEncryption"];
|
|
40975
41782
|
const oldEncryption = previousProperties["StreamEncryption"];
|
|
@@ -41031,10 +41838,13 @@ var KinesisStreamProvider = class {
|
|
|
41031
41838
|
}
|
|
41032
41839
|
if (toEnable.length > 0) {
|
|
41033
41840
|
this.logger.debug(`Enabling ${toEnable.length} shard-level metric(s) on ${physicalId}`);
|
|
41034
|
-
await this.getClient().send(new EnableEnhancedMonitoringCommand({
|
|
41841
|
+
const current = expandShardLevelMetrics((await this.getClient().send(new EnableEnhancedMonitoringCommand({
|
|
41035
41842
|
StreamName: physicalId,
|
|
41036
41843
|
ShardLevelMetrics: toEnable
|
|
41037
|
-
}));
|
|
41844
|
+
})))?.CurrentShardLevelMetrics ?? []);
|
|
41845
|
+
const before = new Set(Array.isArray(current) ? current : []);
|
|
41846
|
+
const added = toEnable.filter((metric) => !before.has(metric));
|
|
41847
|
+
if (added.length > 0) context?.markAttempted?.("DesiredShardLevelMetrics", added);
|
|
41038
41848
|
await this.waitForStreamActive(physicalId);
|
|
41039
41849
|
}
|
|
41040
41850
|
}
|
|
@@ -41201,6 +42011,13 @@ var KinesisStreamProvider = class {
|
|
|
41201
42011
|
StreamName: streamName,
|
|
41202
42012
|
Tags: tagsToAdd
|
|
41203
42013
|
}));
|
|
42014
|
+
let recordedKeys;
|
|
42015
|
+
try {
|
|
42016
|
+
recordedKeys = /* @__PURE__ */ new Set([...planTagDiff(void 0, oldTagsRaw).set.keys()]);
|
|
42017
|
+
} catch {
|
|
42018
|
+
recordedKeys = void 0;
|
|
42019
|
+
}
|
|
42020
|
+
unsettled.afterAdded?.(Object.keys(tagsToAdd).filter((key) => recordedKeys !== void 0 && !recordedKeys.has(key)));
|
|
41204
42021
|
this.logger.debug(`Added/updated ${Object.keys(tagsToAdd).length} tag(s) on Kinesis stream ${streamName}`);
|
|
41205
42022
|
}
|
|
41206
42023
|
}
|
|
@@ -41217,7 +42034,7 @@ var KinesisStreamProvider = class {
|
|
|
41217
42034
|
const secretDerived = mask(physicalId) !== physicalId;
|
|
41218
42035
|
warn(`Kinesis stream ${physicalId} has shard-level metrics enabled that neither cdkd's record nor the template declares (${undeclared.join(", ")}), so cdkd left them enabled while converging the unsettled DesiredShardLevelMetrics (CloudFormation never disables a metric it did not record). Another tool may have enabled them, or an earlier failed cdkd update may have; cdkd cannot tell which. If they should be off, disable them ` + (secretDerived ? `with DisableEnhancedMonitoring for those metrics.` : `with: aws kinesis disable-enhanced-monitoring --stream-name ${physicalId} --shard-level-metrics ${undeclared.join(" ")} (in the stream's region)`));
|
|
41219
42036
|
}
|
|
41220
|
-
async readUnsettled(physicalId, logicalId, resourceType, names, recordedProperties, desiredProperties) {
|
|
42037
|
+
async readUnsettled(physicalId, logicalId, resourceType, names, recordedProperties, desiredProperties, attemptedItems) {
|
|
41221
42038
|
const live = await this.readCurrentState(physicalId, logicalId, resourceType);
|
|
41222
42039
|
if (typeof live !== "object" || live === null) return live;
|
|
41223
42040
|
const out = { ...live };
|
|
@@ -41226,6 +42043,7 @@ var KinesisStreamProvider = class {
|
|
|
41226
42043
|
const expanded = expandShardLevelMetrics(bag?.["DesiredShardLevelMetrics"]);
|
|
41227
42044
|
return isUsableMetricsList(expanded) ? expanded : [];
|
|
41228
42045
|
}));
|
|
42046
|
+
for (const metric of attemptedItems?.get("DesiredShardLevelMetrics") ?? []) if (metric !== "ALL" && isUsableAttemptedName(metric)) named.add(metric);
|
|
41229
42047
|
const liveMetrics = expandShardLevelMetrics(out["DesiredShardLevelMetrics"]);
|
|
41230
42048
|
out["DesiredShardLevelMetrics"] = (Array.isArray(liveMetrics) ? liveMetrics : []).filter((metric) => typeof metric === "string" && named.has(metric));
|
|
41231
42049
|
}
|
|
@@ -41386,6 +42204,7 @@ var KinesisStreamConsumerProvider = class {
|
|
|
41386
42204
|
if (!consumer?.ConsumerARN || !consumer.ConsumerName) throw new ProvisioningError("RegisterStreamConsumer did not return ConsumerARN/ConsumerName", resourceType, logicalId);
|
|
41387
42205
|
const consumerArn = consumer.ConsumerARN;
|
|
41388
42206
|
createdArn = consumerArn;
|
|
42207
|
+
reportCreatedResource(logicalId, resourceType, consumerArn);
|
|
41389
42208
|
await this.waitForConsumerActive(consumerArn);
|
|
41390
42209
|
this.logger.debug(`Successfully registered Kinesis stream consumer ${logicalId}`);
|
|
41391
42210
|
return {
|
|
@@ -42259,6 +43078,7 @@ var PipesPipeProvider = class {
|
|
|
42259
43078
|
...Object.keys(tags).length > 0 && { Tags: tags }
|
|
42260
43079
|
}));
|
|
42261
43080
|
createdIdentity = pipeIdentityToken(name, created?.Arn, created?.CreationTime);
|
|
43081
|
+
reportCreatedResource(logicalId, resourceType, name, createdIdentity);
|
|
42262
43082
|
} catch (error) {
|
|
42263
43083
|
const cause = error instanceof Error ? error : void 0;
|
|
42264
43084
|
throw this.wrapCaughtError(mask, error, (text) => new ProvisioningError(`Failed to create Pipe ${logicalId}: ${text}`, resourceType, logicalId, void 0, cause));
|
|
@@ -42566,7 +43386,10 @@ var PipesPipeProvider = class {
|
|
|
42566
43386
|
try {
|
|
42567
43387
|
await this.getClient().send(new DeletePipeCommand({ Name: name }));
|
|
42568
43388
|
} catch (cleanupError) {
|
|
42569
|
-
if (cleanupError instanceof NotFoundException$6)
|
|
43389
|
+
if (cleanupError instanceof NotFoundException$6) {
|
|
43390
|
+
retractCreatedResource(logicalId, resourceType, name);
|
|
43391
|
+
return original;
|
|
43392
|
+
}
|
|
42570
43393
|
return orphaned(describeAwsFailure(cleanupError).summary);
|
|
42571
43394
|
}
|
|
42572
43395
|
let gone = false;
|
|
@@ -42592,10 +43415,12 @@ var PipesPipeProvider = class {
|
|
|
42592
43415
|
return orphaned("its delete did not complete (AWS reports a failed or rolled-back delete)");
|
|
42593
43416
|
}
|
|
42594
43417
|
if (gone) {
|
|
43418
|
+
retractCreatedResource(logicalId, resourceType, name);
|
|
42595
43419
|
original.message += " (cdkd deleted the pipe it had created, so nothing is left behind)";
|
|
42596
43420
|
return original;
|
|
42597
43421
|
}
|
|
42598
43422
|
if (sawDeleting) {
|
|
43423
|
+
retractCreatedResource(logicalId, resourceType, name);
|
|
42599
43424
|
original.message += " (cdkd started deleting the pipe it had created; a re-deploy may report the name in use until AWS finishes)";
|
|
42600
43425
|
return original;
|
|
42601
43426
|
}
|
|
@@ -42741,7 +43566,7 @@ var EFSProvider = class {
|
|
|
42741
43566
|
const log = createMaskedLogSinks(this.logger, context?.maskSecrets);
|
|
42742
43567
|
properties = withRemovalDefaults(this.removalDefaults, resourceType, properties, previousProperties, context);
|
|
42743
43568
|
switch (resourceType) {
|
|
42744
|
-
case "AWS::EFS::FileSystem": return this.updateFileSystem(logicalId, physicalId, resourceType, properties, previousProperties, log);
|
|
43569
|
+
case "AWS::EFS::FileSystem": return this.updateFileSystem(logicalId, physicalId, resourceType, properties, previousProperties, log, context?.replayingState === true || context?.desiredFromAwsReadback === true);
|
|
42745
43570
|
case "AWS::EFS::MountTarget": return this.updateMountTarget(logicalId, physicalId, resourceType, properties, log);
|
|
42746
43571
|
case "AWS::EFS::AccessPoint": return this.updateAccessPoint(logicalId, physicalId, resourceType, properties, previousProperties, log);
|
|
42747
43572
|
default: throw new ProvisioningError(`Unsupported resource type: ${resourceType}`, resourceType, logicalId, physicalId);
|
|
@@ -42789,7 +43614,7 @@ var EFSProvider = class {
|
|
|
42789
43614
|
throw this.wrapMaskedError(log, error, (text) => new ProvisioningError(`Failed to update EFS AccessPoint ${logicalId}: ${text}`, resourceType, logicalId, physicalId, cause));
|
|
42790
43615
|
}
|
|
42791
43616
|
}
|
|
42792
|
-
async updateFileSystem(logicalId, physicalId, resourceType, properties, previousProperties, log) {
|
|
43617
|
+
async updateFileSystem(logicalId, physicalId, resourceType, properties, previousProperties, log, stateBorneDesired) {
|
|
42793
43618
|
for (const key of [
|
|
42794
43619
|
"Encrypted",
|
|
42795
43620
|
"KmsKeyId",
|
|
@@ -42804,8 +43629,13 @@ var EFSProvider = class {
|
|
|
42804
43629
|
const newProvisioned = properties["ProvisionedThroughputInMibps"];
|
|
42805
43630
|
const oldThroughputMode = previousProperties["ThroughputMode"];
|
|
42806
43631
|
const oldProvisioned = previousProperties["ProvisionedThroughputInMibps"];
|
|
43632
|
+
const throughputValueMissing = newThroughputMode === "provisioned" && newProvisioned === void 0 && (oldProvisioned !== void 0 || oldThroughputMode !== "provisioned");
|
|
43633
|
+
if (throughputValueMissing) {
|
|
43634
|
+
if (!stateBorneDesired) throw new ProvisioningError(`Failed to update EFS FileSystem ${logicalId}: Throughput value must be specified for provisioned throughput mode. The template sets ThroughputMode: provisioned without ProvisionedThroughputInMibps, which CloudFormation rejects too. Set ProvisionedThroughputInMibps, or change ThroughputMode (e.g. to bursting or elastic).`, resourceType, logicalId, physicalId);
|
|
43635
|
+
log.warn(`EFS FileSystem ${logicalId}: the desired properties (from cdkd state or an AWS readback, not the template) set ThroughputMode: provisioned without ProvisionedThroughputInMibps, which AWS rejects; leaving the file system's throughput as it is on AWS and applying the rest of the update. Its throughput may now differ from the record: run cdkd drift to see it.`);
|
|
43636
|
+
}
|
|
42807
43637
|
const effectiveThroughputMode = newThroughputMode === void 0 && newProvisioned === void 0 && oldThroughputMode === "provisioned" ? "bursting" : newThroughputMode;
|
|
42808
|
-
const throughputModeChanged = effectiveThroughputMode !== void 0 && effectiveThroughputMode !== oldThroughputMode;
|
|
43638
|
+
const throughputModeChanged = !throughputValueMissing && effectiveThroughputMode !== void 0 && effectiveThroughputMode !== oldThroughputMode;
|
|
42809
43639
|
const provisionedChanged = newProvisioned !== void 0 && newProvisioned !== oldProvisioned;
|
|
42810
43640
|
const changed = (key) => JSON.stringify(properties[key]) !== JSON.stringify(previousProperties[key]);
|
|
42811
43641
|
const lifecycleChanged = changed("LifecyclePolicies");
|
|
@@ -42926,6 +43756,7 @@ var EFSProvider = class {
|
|
|
42926
43756
|
}))
|
|
42927
43757
|
});
|
|
42928
43758
|
fileSystemId = created.fileSystemId;
|
|
43759
|
+
reportCreatedResource(logicalId, resourceType, fileSystemId);
|
|
42929
43760
|
const available = await this.waitForFileSystemAvailable(fileSystemId, logicalId, resourceType, log);
|
|
42930
43761
|
const arn = created.arn ?? available.FileSystemArn;
|
|
42931
43762
|
await this.applyLifecyclePolicies(fileSystemId, properties["LifecyclePolicies"], log);
|
|
@@ -42947,6 +43778,7 @@ var EFSProvider = class {
|
|
|
42947
43778
|
try {
|
|
42948
43779
|
await this.getClient().send(new DeleteFileSystemCommand({ FileSystemId: fileSystemId }));
|
|
42949
43780
|
this.unconfirmedCreationTokens.delete(creationToken);
|
|
43781
|
+
retractCreatedResource(logicalId, resourceType, fileSystemId);
|
|
42950
43782
|
log.debug(`Rolled back partially-created EFS FileSystem ${fileSystemId}`);
|
|
42951
43783
|
} catch (cleanupError) {
|
|
42952
43784
|
fileSystemLeftBehind = true;
|
|
@@ -43124,6 +43956,7 @@ var EFSProvider = class {
|
|
|
43124
43956
|
}));
|
|
43125
43957
|
const mountTargetId = response.MountTargetId;
|
|
43126
43958
|
createdMountTargetId = mountTargetId;
|
|
43959
|
+
reportCreatedResource(logicalId, resourceType, mountTargetId);
|
|
43127
43960
|
log.debug(`Created EFS MountTarget ${logicalId}: ${mountTargetId}, waiting for available state`);
|
|
43128
43961
|
await this.waitForMountTargetAvailable(mountTargetId, logicalId, resourceType, log);
|
|
43129
43962
|
log.debug(`Successfully created EFS MountTarget ${logicalId}: ${mountTargetId}`);
|
|
@@ -43775,6 +44608,7 @@ var FSxFileSystemProvider = class {
|
|
|
43775
44608
|
throw markNonRetryable(new ProvisioningError(safeMsg`FSx answered the create of ${logicalId} with file system ${returnedId}, which ${createdAt === void 0 ? "carries no creation time" : "predates this create"}: the create token cdkd derives for this stack's file system is held by it, and it is NOT recorded in cdkd state. It is not one this deploy, or an interrupted earlier deploy of this stack, made: it was created under this token by an earlier cdkd version, or a completed deploy recorded it and cdkd later let go of it, and it may hold data, so cdkd neither records nor deletes it. Inspect it with: ${inspect} --file-system-ids ${returnedId} -- then import it into this stack, or delete it once you are sure its data is not needed, and deploy again.`, resourceType, logicalId));
|
|
43776
44609
|
}
|
|
43777
44610
|
fileSystemId = returnedId;
|
|
44611
|
+
reportCreatedResource(logicalId, resourceType, returnedId);
|
|
43778
44612
|
const fs = await this.waitForFileSystemAvailable(fileSystemId, logicalId, resourceType, context?.maskSecrets);
|
|
43779
44613
|
this.logger.debug(`Successfully created FSx FileSystem ${logicalId}: ${fileSystemId}`);
|
|
43780
44614
|
this.createTokenFirstSentAt.delete(clientRequestToken);
|
|
@@ -43786,6 +44620,7 @@ var FSxFileSystemProvider = class {
|
|
|
43786
44620
|
let survivorId;
|
|
43787
44621
|
if (fileSystemId !== void 0) try {
|
|
43788
44622
|
await this.getClient().send(new DeleteFileSystemCommand$1({ FileSystemId: fileSystemId }));
|
|
44623
|
+
retractCreatedResource(logicalId, resourceType, fileSystemId);
|
|
43789
44624
|
this.createTokenFirstSentAt.delete(clientRequestToken);
|
|
43790
44625
|
this.logger.warn(`Rolled back partially-created FSx FileSystem ${fileSystemId}`);
|
|
43791
44626
|
} catch (cleanupError) {
|
|
@@ -44712,11 +45547,11 @@ var FSxFileSystemProvider = class {
|
|
|
44712
45547
|
|
|
44713
45548
|
//#endregion
|
|
44714
45549
|
//#region src/provisioning/emr-configuration.ts
|
|
44715
|
-
function isRecord(value) {
|
|
45550
|
+
function isRecord$1(value) {
|
|
44716
45551
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
44717
45552
|
}
|
|
44718
45553
|
function toSdkConfiguration(raw) {
|
|
44719
|
-
if (!isRecord(raw)) return raw;
|
|
45554
|
+
if (!isRecord$1(raw)) return raw;
|
|
44720
45555
|
const { ConfigurationProperties, Configurations, ...rest } = raw;
|
|
44721
45556
|
return {
|
|
44722
45557
|
...rest,
|
|
@@ -44733,9 +45568,9 @@ function toSdkStepConfigs(value) {
|
|
|
44733
45568
|
if (value === void 0) return void 0;
|
|
44734
45569
|
if (!Array.isArray(value)) return value;
|
|
44735
45570
|
return value.map((step) => {
|
|
44736
|
-
if (!isRecord(step)) return step;
|
|
45571
|
+
if (!isRecord$1(step)) return step;
|
|
44737
45572
|
const hadoopJarStep = step["HadoopJarStep"];
|
|
44738
|
-
if (!isRecord(hadoopJarStep) || hadoopJarStep["StepProperties"] === void 0) return step;
|
|
45573
|
+
if (!isRecord$1(hadoopJarStep) || hadoopJarStep["StepProperties"] === void 0) return step;
|
|
44739
45574
|
const { StepProperties, ...restHadoopJarStep } = hadoopJarStep;
|
|
44740
45575
|
return {
|
|
44741
45576
|
...step,
|
|
@@ -44750,7 +45585,7 @@ function toSdkInstanceTypeConfigs(value) {
|
|
|
44750
45585
|
if (value === void 0) return void 0;
|
|
44751
45586
|
if (!Array.isArray(value)) return value;
|
|
44752
45587
|
return value.map((instanceTypeConfig) => {
|
|
44753
|
-
if (!isRecord(instanceTypeConfig) || instanceTypeConfig["Configurations"] === void 0) return instanceTypeConfig;
|
|
45588
|
+
if (!isRecord$1(instanceTypeConfig) || instanceTypeConfig["Configurations"] === void 0) return instanceTypeConfig;
|
|
44754
45589
|
return {
|
|
44755
45590
|
...instanceTypeConfig,
|
|
44756
45591
|
Configurations: toSdkConfigurations(instanceTypeConfig["Configurations"])
|
|
@@ -44897,6 +45732,7 @@ var EMRInstanceGroupConfigProvider = class {
|
|
|
44897
45732
|
const groupId = response.InstanceGroupIds?.[0];
|
|
44898
45733
|
if (groupId) groupsCreatedByThisProcess.add(groupId);
|
|
44899
45734
|
createdGroupId = groupId;
|
|
45735
|
+
reportCreatedResource(logicalId, resourceType, groupId ?? "");
|
|
44900
45736
|
const replayWindow = replayedSendWindow(response, attemptStartMs);
|
|
44901
45737
|
if (replayWindow !== void 0 && group.InstanceRole === "TASK") await reportOrphans(replayWindow);
|
|
44902
45738
|
if (!groupId) throw new ProvisioningError(`EMR AddInstanceGroups for ${logicalId} returned no instance group id`, resourceType, logicalId);
|
|
@@ -44923,6 +45759,7 @@ var EMRInstanceGroupConfigProvider = class {
|
|
|
44923
45759
|
}]
|
|
44924
45760
|
}));
|
|
44925
45761
|
log.warn(safeMsg`Scaled partially-created EMR TASK instance group ${logicalId} (${leftBehindGroupId}) to 0; EMR has no delete API, so the empty group stays on cluster ${log.value(jobFlowId)} until it terminates`);
|
|
45762
|
+
retractCreatedResource(logicalId, resourceType, leftBehindGroupId);
|
|
44926
45763
|
leftBehindGroupId = void 0;
|
|
44927
45764
|
} catch (cleanupError) {
|
|
44928
45765
|
const cleanupHead = safeMsg`Failed to scale partially-created EMR TASK instance group ${logicalId} (${leftBehindGroupId}) to 0: `;
|
|
@@ -45272,6 +46109,7 @@ var EMRInstanceFleetConfigProvider = class {
|
|
|
45272
46109
|
const fleetId = response.InstanceFleetId;
|
|
45273
46110
|
if (fleetId) fleetsCreatedByThisProcess.add(fleetId);
|
|
45274
46111
|
createdFleetId = fleetId;
|
|
46112
|
+
reportCreatedResource(logicalId, resourceType, fleetId ?? "");
|
|
45275
46113
|
const replayWindow = replayedSendWindow(response, attemptStartMs);
|
|
45276
46114
|
if (replayWindow !== void 0 && fleet.InstanceFleetType === "TASK") await reportOrphans(replayWindow);
|
|
45277
46115
|
if (!fleetId) throw new ProvisioningError(`EMR AddInstanceFleet for ${logicalId} returned no instance fleet id`, resourceType, logicalId);
|
|
@@ -45763,6 +46601,7 @@ var EMRClusterProvider = class {
|
|
|
45763
46601
|
}
|
|
45764
46602
|
clusterId = response.JobFlowId;
|
|
45765
46603
|
if (clusterId) clustersCreatedByThisProcess.add(clusterId);
|
|
46604
|
+
reportCreatedResource(logicalId, resourceType, clusterId ?? "");
|
|
45766
46605
|
const replayWindow = replayedSendWindow(response, attemptStartMs);
|
|
45767
46606
|
if (replayWindow !== void 0) await reportOrphans(replayWindow);
|
|
45768
46607
|
if (!clusterId) throw new ProvisioningError(`EMR RunJobFlow for ${logicalId} returned no JobFlowId`, resourceType, logicalId);
|
|
@@ -45780,6 +46619,7 @@ var EMRClusterProvider = class {
|
|
|
45780
46619
|
TerminationProtected: false
|
|
45781
46620
|
}));
|
|
45782
46621
|
await this.getClient().send(new TerminateJobFlowsCommand({ JobFlowIds: [clusterId] }));
|
|
46622
|
+
retractCreatedResource(logicalId, resourceType, clusterId);
|
|
45783
46623
|
this.logger.warn(`Rolled back partially-created EMR Cluster ${clusterId}`);
|
|
45784
46624
|
} catch (cleanupError) {
|
|
45785
46625
|
survivorId = clusterId;
|
|
@@ -46739,6 +47579,7 @@ var FirehoseProvider = class {
|
|
|
46739
47579
|
const response = await this.getCreateClient().send(new CreateDeliveryStreamCommand(input));
|
|
46740
47580
|
const physicalId = deliveryStreamName || input.DeliveryStreamName || response.DeliveryStreamARN?.split("/").pop() || "";
|
|
46741
47581
|
createdStreamName = physicalId;
|
|
47582
|
+
reportCreatedResource(logicalId, resourceType, physicalId);
|
|
46742
47583
|
const arn = response.DeliveryStreamARN;
|
|
46743
47584
|
this.logger.debug(`Successfully created Firehose delivery stream ${logicalId}: ${physicalId}`);
|
|
46744
47585
|
await this.waitForActive(physicalId, logicalId, resourceType, maskerOrIdentity(context?.maskSecrets));
|
|
@@ -47634,7 +48475,7 @@ function readListBlock(raw, path) {
|
|
|
47634
48475
|
};
|
|
47635
48476
|
}
|
|
47636
48477
|
}
|
|
47637
|
-
function listOf(read) {
|
|
48478
|
+
function listOf$1(read) {
|
|
47638
48479
|
return read.kind === "list" ? read.value : void 0;
|
|
47639
48480
|
}
|
|
47640
48481
|
function retainPreviousLists(desired, previous, keys, live) {
|
|
@@ -47805,6 +48646,7 @@ var CloudTrailProvider = class {
|
|
|
47805
48646
|
trailCreated = true;
|
|
47806
48647
|
const trailArn = result.TrailARN;
|
|
47807
48648
|
createdTrailArn = result.TrailARN;
|
|
48649
|
+
if (createdTrailArn) reportCreatedResource(logicalId, resourceType, createdTrailArn);
|
|
47808
48650
|
const basicForCreate = eventSelectors && eventSelectors.length > 0 ? eventSelectors : void 0;
|
|
47809
48651
|
if (basicForCreate || advancedEventSelectors && advancedEventSelectors.length > 0) {
|
|
47810
48652
|
this.logger.debug(`Setting event selectors for CloudTrail Trail ${logicalId}`);
|
|
@@ -47882,14 +48724,14 @@ var CloudTrailProvider = class {
|
|
|
47882
48724
|
const advancedRead = readListBlock(properties["AdvancedEventSelectors"], "AWS::CloudTrail::Trail AdvancedEventSelectors");
|
|
47883
48725
|
for (const read of [basicRead, advancedRead]) if (read.kind === "unusable") this.logger.warn(safeMsg`${read.detail} The trail's existing event selectors are left untouched for this update rather than reset to the AWS default.`);
|
|
47884
48726
|
const selectorsUnusable = basicRead.kind === "unusable" || advancedRead.kind === "unusable";
|
|
47885
|
-
const newEventSelectors = listOf(basicRead);
|
|
47886
|
-
const newAdvancedSelectors = listOf(advancedRead);
|
|
48727
|
+
const newEventSelectors = listOf$1(basicRead);
|
|
48728
|
+
const newAdvancedSelectors = listOf$1(advancedRead);
|
|
47887
48729
|
const oldEventSelectors = previousProperties["EventSelectors"];
|
|
47888
48730
|
const oldAdvancedSelectors = previousProperties["AdvancedEventSelectors"];
|
|
47889
48731
|
const hadAdvancedSelectors = Array.isArray(oldAdvancedSelectors) && oldAdvancedSelectors.length > 0;
|
|
47890
48732
|
const aggregationRead = readListBlock(properties["AggregationConfigurations"], "AWS::CloudTrail::Trail AggregationConfigurations");
|
|
47891
48733
|
if (aggregationRead.kind === "unusable") this.logger.warn(safeMsg`${aggregationRead.detail} The trail's existing aggregation configurations are left untouched for this update rather than cleared.`);
|
|
47892
|
-
const newAggregation = listOf(aggregationRead);
|
|
48734
|
+
const newAggregation = listOf$1(aggregationRead);
|
|
47893
48735
|
const aggregationChanged = aggregationRead.kind !== "unusable" && setKey(newAggregation) !== setKey(previousProperties["AggregationConfigurations"]);
|
|
47894
48736
|
const aggregationCleared = aggregationChanged && nonEmptyListOf(aggregationRead) === void 0;
|
|
47895
48737
|
const putAggregation = async () => {
|
|
@@ -48294,7 +49136,8 @@ var CodeBuildProvider = class {
|
|
|
48294
49136
|
batchReportMode: cfnBuildBatchConfig["BatchReportMode"],
|
|
48295
49137
|
restrictions: restrictions ? {
|
|
48296
49138
|
maximumBuildsAllowed: restrictions["MaximumBuildsAllowed"],
|
|
48297
|
-
computeTypesAllowed: restrictions["ComputeTypesAllowed"]
|
|
49139
|
+
computeTypesAllowed: restrictions["ComputeTypesAllowed"],
|
|
49140
|
+
fleetsAllowed: restrictions["FleetsAllowed"]
|
|
48298
49141
|
} : void 0
|
|
48299
49142
|
};
|
|
48300
49143
|
}
|
|
@@ -48363,6 +49206,7 @@ var CodeBuildProvider = class {
|
|
|
48363
49206
|
const projectName = result.project.name;
|
|
48364
49207
|
const projectArn = result.project.arn;
|
|
48365
49208
|
createdName = projectName;
|
|
49209
|
+
reportCreatedResource(logicalId, resourceType, createdName);
|
|
48366
49210
|
if (visibilityRead.kind === "usable" && (visibilityRead.visibility !== DEFAULT_PROJECT_VISIBILITY || visibilityRead.resourceAccessRole !== void 0)) await this.applyVisibility(projectArn, visibilityRead);
|
|
48367
49211
|
this.logger.debug(`Successfully created CodeBuild Project ${logicalId}: ${projectName}`);
|
|
48368
49212
|
return {
|
|
@@ -48602,6 +49446,7 @@ var CodeBuildProvider = class {
|
|
|
48602
49446
|
const r = {};
|
|
48603
49447
|
if (project.buildBatchConfig.restrictions.maximumBuildsAllowed !== void 0) r["MaximumBuildsAllowed"] = project.buildBatchConfig.restrictions.maximumBuildsAllowed;
|
|
48604
49448
|
if (project.buildBatchConfig.restrictions.computeTypesAllowed !== void 0) r["ComputeTypesAllowed"] = project.buildBatchConfig.restrictions.computeTypesAllowed;
|
|
49449
|
+
if (project.buildBatchConfig.restrictions.fleetsAllowed !== void 0) r["FleetsAllowed"] = project.buildBatchConfig.restrictions.fleetsAllowed;
|
|
48605
49450
|
bbc["Restrictions"] = r;
|
|
48606
49451
|
}
|
|
48607
49452
|
if (project.buildBatchConfig.timeoutInMins !== void 0) bbc["TimeoutInMins"] = project.buildBatchConfig.timeoutInMins;
|
|
@@ -48784,6 +49629,7 @@ var CodeCommitRepositoryProvider = class {
|
|
|
48784
49629
|
if (!metadata?.repositoryName) throw new Error("CreateRepository did not return repository metadata");
|
|
48785
49630
|
const createdName = metadata.repositoryName;
|
|
48786
49631
|
leftLiveName = createdName;
|
|
49632
|
+
reportCreatedResource(logicalId, resourceType, createdName);
|
|
48787
49633
|
try {
|
|
48788
49634
|
const code = properties["Code"];
|
|
48789
49635
|
if (code) await this.seedInitialCommit(createdName, code);
|
|
@@ -48797,7 +49643,10 @@ var CodeCommitRepositoryProvider = class {
|
|
|
48797
49643
|
}
|
|
48798
49644
|
} catch (postCreateError) {
|
|
48799
49645
|
this.logger.warn(`Post-create step failed for CodeCommit Repository ${logicalId}; deleting the just-created repository ${createdName} to avoid an orphan`);
|
|
48800
|
-
if (await this.bestEffortDelete(createdName, maskerOrIdentity(context?.maskSecrets)))
|
|
49646
|
+
if (await this.bestEffortDelete(createdName, maskerOrIdentity(context?.maskSecrets))) {
|
|
49647
|
+
retractCreatedResource(logicalId, resourceType, leftLiveName);
|
|
49648
|
+
leftLiveName = void 0;
|
|
49649
|
+
}
|
|
48801
49650
|
throw markAuxiliaryFailure(postCreateError, logicalId);
|
|
48802
49651
|
}
|
|
48803
49652
|
this.logger.debug(`Successfully created CodeCommit Repository ${logicalId}: ${createdName}`);
|
|
@@ -49166,6 +50015,28 @@ var CodeCommitRepositoryProvider = class {
|
|
|
49166
50015
|
|
|
49167
50016
|
//#endregion
|
|
49168
50017
|
//#region src/provisioning/providers/dlm-lifecycle-policy-provider.ts
|
|
50018
|
+
const KEPT_ON_REMOVAL = [
|
|
50019
|
+
"Description",
|
|
50020
|
+
"ExecutionRoleArn",
|
|
50021
|
+
"State",
|
|
50022
|
+
"PolicyDetails",
|
|
50023
|
+
"CreateInterval",
|
|
50024
|
+
"RetainInterval",
|
|
50025
|
+
"CopyTags",
|
|
50026
|
+
"ExtendDeletion",
|
|
50027
|
+
"CrossRegionCopyTargets",
|
|
50028
|
+
"Exclusions"
|
|
50029
|
+
];
|
|
50030
|
+
function keptRemovedNames(properties, previousProperties, context) {
|
|
50031
|
+
if (context?.desiredFromAwsReadback) return [];
|
|
50032
|
+
const removed = context?.removedProperties;
|
|
50033
|
+
return KEPT_ON_REMOVAL.filter((key) => previousProperties[key] != null && properties[key] == null && (removed === void 0 || removed.has(key) || properties[key] === null));
|
|
50034
|
+
}
|
|
50035
|
+
const keptOnRemovalWarning = (logicalId, names, caller) => {
|
|
50036
|
+
const one = names.length === 1;
|
|
50037
|
+
const subject = one ? "property" : "properties";
|
|
50038
|
+
return caller === "rollback" ? safeMsg`${logicalId} (AWS::DLM::LifecyclePolicy): ${subject} ${names.join(", ")} ${one ? "is" : "are"} absent from the state being restored; UpdateLifecyclePolicy keeps a field it is not sent, so the rollback leaves the value the failed deploy applied in place.` : safeMsg`${logicalId} (AWS::DLM::LifecyclePolicy): ${subject} ${names.join(", ")} ${one ? "was" : "were"} removed from the template and ${one ? "keeps its" : "keep their"} current AWS value, as CloudFormation leaves ${one ? "it" : "them"}; UpdateLifecyclePolicy keeps a field it is not sent. Declare the intended value explicitly to change it.`;
|
|
50039
|
+
};
|
|
49169
50040
|
const createLifecyclePolicyLatch = new AmbiguousCreateLatch("dlm:CreateLifecyclePolicy");
|
|
49170
50041
|
const policiesCreatedByThisProcess = new RecentIdSet();
|
|
49171
50042
|
var DLMLifecyclePolicyProvider = class {
|
|
@@ -49195,6 +50066,11 @@ var DLMLifecyclePolicyProvider = class {
|
|
|
49195
50066
|
"CrossRegionCopyTargets",
|
|
49196
50067
|
"Exclusions"
|
|
49197
50068
|
])]]);
|
|
50069
|
+
removalHandledInUpdate = /* @__PURE__ */ new Map([["AWS::DLM::LifecyclePolicy", /* @__PURE__ */ new Set([
|
|
50070
|
+
...KEPT_ON_REMOVAL,
|
|
50071
|
+
"Tags",
|
|
50072
|
+
"DefaultPolicy"
|
|
50073
|
+
])]]);
|
|
49198
50074
|
getClient() {
|
|
49199
50075
|
if (!this.client) this.client = new DLMClient({
|
|
49200
50076
|
...ambientClientDefaults(),
|
|
@@ -49319,6 +50195,8 @@ var DLMLifecyclePolicyProvider = class {
|
|
|
49319
50195
|
...properties["CreateInterval"] != null && { CreateInterval: Number(properties["CreateInterval"]) },
|
|
49320
50196
|
...properties["RetainInterval"] != null && { RetainInterval: Number(properties["RetainInterval"]) }
|
|
49321
50197
|
}));
|
|
50198
|
+
const keptNames = keptRemovedNames(properties, previousProperties, context);
|
|
50199
|
+
if (keptNames.length > 0) this.logger.warn(keptOnRemovalWarning(logicalId, keptNames, context?.replayingState ? "rollback" : "deploy"));
|
|
49322
50200
|
const plan = planTagDiff(previousProperties["Tags"], properties["Tags"]);
|
|
49323
50201
|
const tagWarning = tagPlanWarning(plan, resourceType, logicalId);
|
|
49324
50202
|
if (tagWarning !== void 0) this.logger.warn(tagWarning);
|
|
@@ -49657,6 +50535,370 @@ function notEmptyRefusalMessage(bucketName, maskSecrets) {
|
|
|
49657
50535
|
const remedy = command ? `Delete all objects first (e.g. ${command}) and destroy again.` : secretDerived ? "Delete all objects first, via the console, and destroy again: the bucket name is derived from a secret, so cdkd does not print it." : "Delete all objects first, via the console, and destroy again: the bucket name cdkd recorded cannot be reproduced safely on a command line, so any command shown here could act on a different bucket or run part of the name as shell.";
|
|
49658
50536
|
return mask(`bucket ${displayIdent(mask(bucketName))} is not empty. Matching CloudFormation, cdkd does not delete a non-empty directory bucket without an explicit opt-in. ${remedy}`);
|
|
49659
50537
|
}
|
|
50538
|
+
function isRecord(value) {
|
|
50539
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
50540
|
+
}
|
|
50541
|
+
function itemId(item) {
|
|
50542
|
+
if (!isRecord(item)) return void 0;
|
|
50543
|
+
const id = item["Id"];
|
|
50544
|
+
return typeof id === "string" && id !== "" ? id : void 0;
|
|
50545
|
+
}
|
|
50546
|
+
function canonicalJson(value) {
|
|
50547
|
+
const sorted = (v) => {
|
|
50548
|
+
if (Array.isArray(v)) return v.map(sorted);
|
|
50549
|
+
if (isRecord(v)) return Object.fromEntries(Object.keys(v).sort().map((k) => [k, sorted(v[k])]));
|
|
50550
|
+
return v;
|
|
50551
|
+
};
|
|
50552
|
+
return JSON.stringify(sorted(value)) ?? "undefined";
|
|
50553
|
+
}
|
|
50554
|
+
function sameJson(a, b) {
|
|
50555
|
+
return canonicalJson(a) === canonicalJson(b);
|
|
50556
|
+
}
|
|
50557
|
+
function optionalString(value, path, refuse) {
|
|
50558
|
+
if (value === void 0 || value === null) return void 0;
|
|
50559
|
+
if (typeof value !== "string") refuse(path, "a string");
|
|
50560
|
+
return value;
|
|
50561
|
+
}
|
|
50562
|
+
function optionalBoolean(value, path, refuse) {
|
|
50563
|
+
if (value === void 0 || value === null) return void 0;
|
|
50564
|
+
if (typeof value === "boolean") return value;
|
|
50565
|
+
if (value === "true") return true;
|
|
50566
|
+
if (value === "false") return false;
|
|
50567
|
+
return refuse(path, "a boolean");
|
|
50568
|
+
}
|
|
50569
|
+
function optionalInteger(value, path, refuse) {
|
|
50570
|
+
if (value === void 0 || value === null) return void 0;
|
|
50571
|
+
if (typeof value === "number" && Number.isSafeInteger(value) && value >= 0) return value;
|
|
50572
|
+
if (typeof value === "string" && /^[0-9]{1,15}$/.test(value)) return Number(value);
|
|
50573
|
+
return refuse(path, "a non-negative integer");
|
|
50574
|
+
}
|
|
50575
|
+
function listOf(value, path, refuse) {
|
|
50576
|
+
if (!Array.isArray(value)) refuse(path, "a list");
|
|
50577
|
+
return value;
|
|
50578
|
+
}
|
|
50579
|
+
function encryptionToSdk(value, refuse) {
|
|
50580
|
+
if (value === void 0 || value === null) return void 0;
|
|
50581
|
+
if (!isRecord(value)) refuse("BucketEncryption", "an object");
|
|
50582
|
+
const rules = listOf(value["ServerSideEncryptionConfiguration"], "BucketEncryption.ServerSideEncryptionConfiguration", refuse);
|
|
50583
|
+
if (rules.length === 0) return void 0;
|
|
50584
|
+
return { Rules: rules.map((rule, i) => {
|
|
50585
|
+
const path = `BucketEncryption.ServerSideEncryptionConfiguration[${i}]`;
|
|
50586
|
+
if (!isRecord(rule)) refuse(path, "an object");
|
|
50587
|
+
const out = {};
|
|
50588
|
+
const byDefault = rule["ServerSideEncryptionByDefault"];
|
|
50589
|
+
if (byDefault !== void 0 && byDefault !== null) {
|
|
50590
|
+
if (!isRecord(byDefault)) refuse(`${path}.ServerSideEncryptionByDefault`, "an object");
|
|
50591
|
+
const algorithm = optionalString(byDefault["SSEAlgorithm"], `${path}.ServerSideEncryptionByDefault.SSEAlgorithm`, refuse);
|
|
50592
|
+
const keyId = optionalString(byDefault["KMSMasterKeyID"], `${path}.ServerSideEncryptionByDefault.KMSMasterKeyID`, refuse);
|
|
50593
|
+
out.ApplyServerSideEncryptionByDefault = {
|
|
50594
|
+
SSEAlgorithm: algorithm,
|
|
50595
|
+
...keyId !== void 0 ? { KMSMasterKeyID: keyId } : {}
|
|
50596
|
+
};
|
|
50597
|
+
}
|
|
50598
|
+
const bucketKey = optionalBoolean(rule["BucketKeyEnabled"], `${path}.BucketKeyEnabled`, refuse);
|
|
50599
|
+
if (bucketKey !== void 0) out.BucketKeyEnabled = bucketKey;
|
|
50600
|
+
return out;
|
|
50601
|
+
}) };
|
|
50602
|
+
}
|
|
50603
|
+
function lifecycleFilterToSdk(rule, path, refuse) {
|
|
50604
|
+
const prefix = optionalString(rule["Prefix"], `${path}.Prefix`, refuse);
|
|
50605
|
+
const greater = optionalInteger(rule["ObjectSizeGreaterThan"], `${path}.ObjectSizeGreaterThan`, refuse);
|
|
50606
|
+
const less = optionalInteger(rule["ObjectSizeLessThan"], `${path}.ObjectSizeLessThan`, refuse);
|
|
50607
|
+
const members = {
|
|
50608
|
+
...prefix !== void 0 ? { Prefix: prefix } : {},
|
|
50609
|
+
...greater !== void 0 ? { ObjectSizeGreaterThan: greater } : {},
|
|
50610
|
+
...less !== void 0 ? { ObjectSizeLessThan: less } : {}
|
|
50611
|
+
};
|
|
50612
|
+
const count = Object.keys(members).length;
|
|
50613
|
+
if (count === 0) return { Prefix: "" };
|
|
50614
|
+
if (count === 1) return members;
|
|
50615
|
+
return { And: members };
|
|
50616
|
+
}
|
|
50617
|
+
function lifecycleToSdk(value, refuse) {
|
|
50618
|
+
if (value === void 0 || value === null) return void 0;
|
|
50619
|
+
if (!isRecord(value)) refuse("LifecycleConfiguration", "an object");
|
|
50620
|
+
const rules = listOf(value["Rules"], "LifecycleConfiguration.Rules", refuse);
|
|
50621
|
+
if (rules.length === 0) return void 0;
|
|
50622
|
+
return { Rules: rules.map((rule, i) => {
|
|
50623
|
+
const path = `LifecycleConfiguration.Rules[${i}]`;
|
|
50624
|
+
if (!isRecord(rule)) refuse(path, "an object");
|
|
50625
|
+
const id = optionalString(rule["Id"], `${path}.Id`, refuse);
|
|
50626
|
+
const status = optionalString(rule["Status"], `${path}.Status`, refuse);
|
|
50627
|
+
const days = optionalInteger(rule["ExpirationInDays"], `${path}.ExpirationInDays`, refuse);
|
|
50628
|
+
const out = {
|
|
50629
|
+
...id !== void 0 ? { ID: id } : {},
|
|
50630
|
+
Status: status,
|
|
50631
|
+
Filter: lifecycleFilterToSdk(rule, path, refuse)
|
|
50632
|
+
};
|
|
50633
|
+
if (days !== void 0) out.Expiration = { Days: days };
|
|
50634
|
+
const abort = rule["AbortIncompleteMultipartUpload"];
|
|
50635
|
+
if (abort !== void 0 && abort !== null) {
|
|
50636
|
+
if (!isRecord(abort)) refuse(`${path}.AbortIncompleteMultipartUpload`, "an object");
|
|
50637
|
+
const after = optionalInteger(abort["DaysAfterInitiation"], `${path}.AbortIncompleteMultipartUpload.DaysAfterInitiation`, refuse);
|
|
50638
|
+
out.AbortIncompleteMultipartUpload = after !== void 0 ? { DaysAfterInitiation: after } : {};
|
|
50639
|
+
}
|
|
50640
|
+
return out;
|
|
50641
|
+
}) };
|
|
50642
|
+
}
|
|
50643
|
+
function keyedItems(value, property, refuse) {
|
|
50644
|
+
const out = /* @__PURE__ */ new Map();
|
|
50645
|
+
if (value === void 0 || value === null) return out;
|
|
50646
|
+
listOf(value, property, refuse).forEach((item, i) => {
|
|
50647
|
+
if (!isRecord(item)) refuse(`${property}[${i}]`, "an object");
|
|
50648
|
+
const id = itemId(item);
|
|
50649
|
+
if (id === void 0) refuse(`${property}[${i}].Id`, "a non-empty string");
|
|
50650
|
+
if (out.has(id)) refuse(`${property}[${i}].Id`, "an Id no other item of the list carries");
|
|
50651
|
+
out.set(id, item);
|
|
50652
|
+
});
|
|
50653
|
+
return out;
|
|
50654
|
+
}
|
|
50655
|
+
function recordedItems(value) {
|
|
50656
|
+
const out = /* @__PURE__ */ new Map();
|
|
50657
|
+
if (!Array.isArray(value)) return out;
|
|
50658
|
+
for (const item of value) {
|
|
50659
|
+
const id = itemId(item);
|
|
50660
|
+
if (id !== void 0 && !out.has(id)) out.set(id, item);
|
|
50661
|
+
}
|
|
50662
|
+
return out;
|
|
50663
|
+
}
|
|
50664
|
+
function metricsItemToSdk(id, item, path, refuse) {
|
|
50665
|
+
const prefix = optionalString(item["Prefix"], `${path}.Prefix`, refuse);
|
|
50666
|
+
const accessPoint = optionalString(item["AccessPointArn"], `${path}.AccessPointArn`, refuse);
|
|
50667
|
+
if (prefix !== void 0 && accessPoint !== void 0) return {
|
|
50668
|
+
Id: id,
|
|
50669
|
+
Filter: { And: {
|
|
50670
|
+
Prefix: prefix,
|
|
50671
|
+
AccessPointArn: accessPoint
|
|
50672
|
+
} }
|
|
50673
|
+
};
|
|
50674
|
+
if (prefix !== void 0) return {
|
|
50675
|
+
Id: id,
|
|
50676
|
+
Filter: { Prefix: prefix }
|
|
50677
|
+
};
|
|
50678
|
+
if (accessPoint !== void 0) return {
|
|
50679
|
+
Id: id,
|
|
50680
|
+
Filter: { AccessPointArn: accessPoint }
|
|
50681
|
+
};
|
|
50682
|
+
return { Id: id };
|
|
50683
|
+
}
|
|
50684
|
+
function inventoryItemToSdk(id, item, path, refuse) {
|
|
50685
|
+
const destination = item["Destination"];
|
|
50686
|
+
if (!isRecord(destination)) refuse(`${path}.Destination`, "an object");
|
|
50687
|
+
const bucketArn = optionalString(destination["BucketArn"], `${path}.Destination.BucketArn`, refuse);
|
|
50688
|
+
const accountId = optionalString(destination["BucketAccountId"], `${path}.Destination.BucketAccountId`, refuse);
|
|
50689
|
+
const format = optionalString(destination["Format"], `${path}.Destination.Format`, refuse);
|
|
50690
|
+
const destPrefix = optionalString(destination["Prefix"], `${path}.Destination.Prefix`, refuse);
|
|
50691
|
+
const enabled = optionalBoolean(item["Enabled"], `${path}.Enabled`, refuse);
|
|
50692
|
+
const versions = optionalString(item["IncludedObjectVersions"], `${path}.IncludedObjectVersions`, refuse);
|
|
50693
|
+
const prefix = optionalString(item["Prefix"], `${path}.Prefix`, refuse);
|
|
50694
|
+
const frequency = optionalString(item["ScheduleFrequency"], `${path}.ScheduleFrequency`, refuse);
|
|
50695
|
+
const fields = item["OptionalFields"];
|
|
50696
|
+
let optionalFields;
|
|
50697
|
+
if (fields !== void 0 && fields !== null) optionalFields = listOf(fields, `${path}.OptionalFields`, refuse).map((f, j) => {
|
|
50698
|
+
if (typeof f !== "string") refuse(`${path}.OptionalFields[${j}]`, "a string");
|
|
50699
|
+
return f;
|
|
50700
|
+
});
|
|
50701
|
+
return {
|
|
50702
|
+
Id: id,
|
|
50703
|
+
Destination: { S3BucketDestination: {
|
|
50704
|
+
Bucket: bucketArn,
|
|
50705
|
+
Format: format,
|
|
50706
|
+
...accountId !== void 0 ? { AccountId: accountId } : {},
|
|
50707
|
+
...destPrefix !== void 0 ? { Prefix: destPrefix } : {}
|
|
50708
|
+
} },
|
|
50709
|
+
IsEnabled: enabled,
|
|
50710
|
+
IncludedObjectVersions: versions,
|
|
50711
|
+
Schedule: { Frequency: frequency },
|
|
50712
|
+
...prefix !== void 0 ? { Filter: { Prefix: prefix } } : {},
|
|
50713
|
+
...optionalFields !== void 0 ? { OptionalFields: optionalFields } : {}
|
|
50714
|
+
};
|
|
50715
|
+
}
|
|
50716
|
+
function desiredConfigurations(properties, refuse, onUnusable) {
|
|
50717
|
+
const warnOut = (error, what) => onUnusable?.(`${error.message.replace(/ — the resource was not created$/, "")}; replaying a recorded state, so the bucket is created without ${what}`);
|
|
50718
|
+
const build = (fallback, what, run) => {
|
|
50719
|
+
if (!onUnusable) return run();
|
|
50720
|
+
try {
|
|
50721
|
+
return run();
|
|
50722
|
+
} catch (error) {
|
|
50723
|
+
if (!(error instanceof ProvisioningError)) throw error;
|
|
50724
|
+
warnOut(error, what);
|
|
50725
|
+
return fallback;
|
|
50726
|
+
}
|
|
50727
|
+
};
|
|
50728
|
+
const buildList = (property, toSdk) => {
|
|
50729
|
+
if (!onUnusable) {
|
|
50730
|
+
const out = /* @__PURE__ */ new Map();
|
|
50731
|
+
let i = 0;
|
|
50732
|
+
for (const [id, item] of keyedItems(properties[property], property, refuse)) out.set(id, toSdk(id, item, `${property}[${i++}]`));
|
|
50733
|
+
return out;
|
|
50734
|
+
}
|
|
50735
|
+
const out = /* @__PURE__ */ new Map();
|
|
50736
|
+
const value = properties[property];
|
|
50737
|
+
if (value === void 0 || value === null) return out;
|
|
50738
|
+
build(void 0, `any ${property} item`, () => listOf(value, property, refuse))?.forEach((item, i) => {
|
|
50739
|
+
const path = `${property}[${i}]`;
|
|
50740
|
+
build(void 0, `${path}`, () => {
|
|
50741
|
+
if (!isRecord(item)) refuse(path, "an object");
|
|
50742
|
+
const id = itemId(item);
|
|
50743
|
+
if (id === void 0) refuse(`${path}.Id`, "a non-empty string");
|
|
50744
|
+
if (out.has(id)) refuse(`${path}.Id`, "an Id no other item of the list carries");
|
|
50745
|
+
out.set(id, toSdk(id, item, path));
|
|
50746
|
+
});
|
|
50747
|
+
});
|
|
50748
|
+
return out;
|
|
50749
|
+
};
|
|
50750
|
+
const metrics = buildList("MetricsConfigurations", (id, item, path) => metricsItemToSdk(id, item, path, refuse));
|
|
50751
|
+
const inventory = buildList("InventoryConfigurations", (id, item, path) => inventoryItemToSdk(id, item, path, refuse));
|
|
50752
|
+
return {
|
|
50753
|
+
encryption: build(void 0, "its BucketEncryption", () => encryptionToSdk(properties["BucketEncryption"], refuse)),
|
|
50754
|
+
lifecycle: build(void 0, "its LifecycleConfiguration", () => lifecycleToSdk(properties["LifecycleConfiguration"], refuse)),
|
|
50755
|
+
metrics,
|
|
50756
|
+
inventory
|
|
50757
|
+
};
|
|
50758
|
+
}
|
|
50759
|
+
function configurationRefuser(resourceType, logicalId, physicalId) {
|
|
50760
|
+
const updating = physicalId !== void 0;
|
|
50761
|
+
return (path, expected) => {
|
|
50762
|
+
throw markNonRetryable(new ProvisioningError(`${updating ? "desired " : ""}${path} of ${resourceType} ${logicalId} is not ${expected} — the resource was not ${updating ? "updated" : "created"}`, resourceType, logicalId, physicalId));
|
|
50763
|
+
};
|
|
50764
|
+
}
|
|
50765
|
+
function encryptionFromSdk(rules) {
|
|
50766
|
+
return { ServerSideEncryptionConfiguration: rules.map((rule) => {
|
|
50767
|
+
const out = {};
|
|
50768
|
+
const byDefault = rule.ApplyServerSideEncryptionByDefault;
|
|
50769
|
+
if (byDefault) out["ServerSideEncryptionByDefault"] = {
|
|
50770
|
+
...byDefault.SSEAlgorithm !== void 0 ? { SSEAlgorithm: byDefault.SSEAlgorithm } : {},
|
|
50771
|
+
...byDefault.KMSMasterKeyID !== void 0 ? { KMSMasterKeyID: byDefault.KMSMasterKeyID } : {}
|
|
50772
|
+
};
|
|
50773
|
+
if (rule.BucketKeyEnabled !== void 0) out["BucketKeyEnabled"] = rule.BucketKeyEnabled;
|
|
50774
|
+
return out;
|
|
50775
|
+
}) };
|
|
50776
|
+
}
|
|
50777
|
+
function lifecycleFromSdk(rules) {
|
|
50778
|
+
return { Rules: rules.map((rule) => {
|
|
50779
|
+
const out = {};
|
|
50780
|
+
if (rule.ID !== void 0) out["Id"] = rule.ID;
|
|
50781
|
+
if (rule.Status !== void 0) out["Status"] = rule.Status;
|
|
50782
|
+
const scope = {
|
|
50783
|
+
...rule.Filter?.And ?? {},
|
|
50784
|
+
...rule.Filter ?? {}
|
|
50785
|
+
};
|
|
50786
|
+
const prefix = scope["Prefix"] ?? rule.Prefix;
|
|
50787
|
+
if (prefix !== void 0 && prefix !== "") out["Prefix"] = prefix;
|
|
50788
|
+
if (typeof scope["ObjectSizeGreaterThan"] === "number") out["ObjectSizeGreaterThan"] = String(scope["ObjectSizeGreaterThan"]);
|
|
50789
|
+
if (typeof scope["ObjectSizeLessThan"] === "number") out["ObjectSizeLessThan"] = String(scope["ObjectSizeLessThan"]);
|
|
50790
|
+
if (rule.Expiration?.Days !== void 0) out["ExpirationInDays"] = rule.Expiration.Days;
|
|
50791
|
+
if (rule.AbortIncompleteMultipartUpload) {
|
|
50792
|
+
const after = rule.AbortIncompleteMultipartUpload.DaysAfterInitiation;
|
|
50793
|
+
out["AbortIncompleteMultipartUpload"] = after !== void 0 ? { DaysAfterInitiation: after } : {};
|
|
50794
|
+
}
|
|
50795
|
+
return out;
|
|
50796
|
+
}) };
|
|
50797
|
+
}
|
|
50798
|
+
function metricsFromSdk(item) {
|
|
50799
|
+
const filter = item.Filter;
|
|
50800
|
+
const scope = filter?.And ?? filter ?? {};
|
|
50801
|
+
return {
|
|
50802
|
+
Id: item.Id,
|
|
50803
|
+
...scope.Prefix !== void 0 ? { Prefix: scope.Prefix } : {},
|
|
50804
|
+
...scope.AccessPointArn !== void 0 ? { AccessPointArn: scope.AccessPointArn } : {}
|
|
50805
|
+
};
|
|
50806
|
+
}
|
|
50807
|
+
function inventoryFromSdk(item) {
|
|
50808
|
+
const dest = item.Destination?.S3BucketDestination;
|
|
50809
|
+
return {
|
|
50810
|
+
Id: item.Id,
|
|
50811
|
+
Destination: {
|
|
50812
|
+
...dest?.Bucket !== void 0 ? { BucketArn: dest.Bucket } : {},
|
|
50813
|
+
...dest?.AccountId !== void 0 ? { BucketAccountId: dest.AccountId } : {},
|
|
50814
|
+
...dest?.Format !== void 0 ? { Format: dest.Format } : {},
|
|
50815
|
+
...dest?.Prefix !== void 0 ? { Prefix: dest.Prefix } : {}
|
|
50816
|
+
},
|
|
50817
|
+
...item.IsEnabled !== void 0 ? { Enabled: item.IsEnabled } : {},
|
|
50818
|
+
...item.IncludedObjectVersions !== void 0 ? { IncludedObjectVersions: item.IncludedObjectVersions } : {},
|
|
50819
|
+
...item.Filter?.Prefix !== void 0 ? { Prefix: item.Filter.Prefix } : {},
|
|
50820
|
+
...item.Schedule?.Frequency !== void 0 ? { ScheduleFrequency: item.Schedule.Frequency } : {},
|
|
50821
|
+
...item.OptionalFields !== void 0 && item.OptionalFields.length > 0 ? { OptionalFields: [...item.OptionalFields] } : {}
|
|
50822
|
+
};
|
|
50823
|
+
}
|
|
50824
|
+
function impliedBucketKey(algorithm) {
|
|
50825
|
+
if (algorithm === "AES256") return false;
|
|
50826
|
+
if (algorithm === "aws:kms") return true;
|
|
50827
|
+
}
|
|
50828
|
+
function canonicalizeConfigurationsForDrift(properties) {
|
|
50829
|
+
let out = properties;
|
|
50830
|
+
const encryption = properties["BucketEncryption"];
|
|
50831
|
+
if (isRecord(encryption) && Array.isArray(encryption["ServerSideEncryptionConfiguration"])) {
|
|
50832
|
+
let changed = false;
|
|
50833
|
+
const rules = encryption["ServerSideEncryptionConfiguration"].map((rule) => {
|
|
50834
|
+
if (!isRecord(rule) || !("BucketKeyEnabled" in rule)) return rule;
|
|
50835
|
+
const byDefault = rule["ServerSideEncryptionByDefault"];
|
|
50836
|
+
const implied = impliedBucketKey(isRecord(byDefault) ? byDefault["SSEAlgorithm"] : void 0);
|
|
50837
|
+
const declared = rule["BucketKeyEnabled"];
|
|
50838
|
+
if (implied === void 0 || (declared === "true" ? true : declared === "false" ? false : declared) !== implied) return rule;
|
|
50839
|
+
changed = true;
|
|
50840
|
+
const { BucketKeyEnabled: _dropped, ...rest } = rule;
|
|
50841
|
+
return rest;
|
|
50842
|
+
});
|
|
50843
|
+
if (changed) out = {
|
|
50844
|
+
...out,
|
|
50845
|
+
BucketEncryption: {
|
|
50846
|
+
...encryption,
|
|
50847
|
+
ServerSideEncryptionConfiguration: rules
|
|
50848
|
+
}
|
|
50849
|
+
};
|
|
50850
|
+
}
|
|
50851
|
+
const lifecycle = properties["LifecycleConfiguration"];
|
|
50852
|
+
if (isRecord(lifecycle) && Array.isArray(lifecycle["Rules"])) {
|
|
50853
|
+
let changed = false;
|
|
50854
|
+
const rules = lifecycle["Rules"].map((rule) => {
|
|
50855
|
+
if (!isRecord(rule) || rule["Prefix"] !== "") return rule;
|
|
50856
|
+
changed = true;
|
|
50857
|
+
const { Prefix: _dropped, ...rest } = rule;
|
|
50858
|
+
return rest;
|
|
50859
|
+
});
|
|
50860
|
+
if (changed) out = {
|
|
50861
|
+
...out,
|
|
50862
|
+
LifecycleConfiguration: {
|
|
50863
|
+
...lifecycle,
|
|
50864
|
+
Rules: rules
|
|
50865
|
+
}
|
|
50866
|
+
};
|
|
50867
|
+
}
|
|
50868
|
+
return out;
|
|
50869
|
+
}
|
|
50870
|
+
function liveMatchesDesired(name, desired, live) {
|
|
50871
|
+
const d = canonicalizeConfigurationsForDrift({ [name]: desired[name] })[name];
|
|
50872
|
+
let l = canonicalizeConfigurationsForDrift({ [name]: live[name] })[name];
|
|
50873
|
+
if (name === "LifecycleConfiguration" && isRecord(d) && isRecord(l)) {
|
|
50874
|
+
const dRules = Array.isArray(d["Rules"]) ? d["Rules"] : [];
|
|
50875
|
+
const lRules = Array.isArray(l["Rules"]) ? l["Rules"] : [];
|
|
50876
|
+
l = {
|
|
50877
|
+
...l,
|
|
50878
|
+
Rules: lRules.map((rule, i) => {
|
|
50879
|
+
const declared = dRules[i];
|
|
50880
|
+
if (!isRecord(rule) || !isRecord(declared) || "Id" in declared) return rule;
|
|
50881
|
+
const { Id: _assigned, ...rest } = rule;
|
|
50882
|
+
return rest;
|
|
50883
|
+
})
|
|
50884
|
+
};
|
|
50885
|
+
}
|
|
50886
|
+
if (name === "MetricsConfigurations" || name === "InventoryConfigurations") {
|
|
50887
|
+
const withSortedFields = (item) => isRecord(item) && Array.isArray(item["OptionalFields"]) ? {
|
|
50888
|
+
...item,
|
|
50889
|
+
OptionalFields: [...item["OptionalFields"]].map(String).sort()
|
|
50890
|
+
} : item;
|
|
50891
|
+
const asSet = (v) => Array.isArray(v) ? v.map((item) => canonicalJson(withSortedFields(item))).sort() : [canonicalJson(v)];
|
|
50892
|
+
return sameJson(asSet(d), asSet(l));
|
|
50893
|
+
}
|
|
50894
|
+
return sameJson(d, l);
|
|
50895
|
+
}
|
|
50896
|
+
const CONFIGURATION_READ_ACTIONS = {
|
|
50897
|
+
BucketEncryption: "s3express:GetEncryptionConfiguration",
|
|
50898
|
+
LifecycleConfiguration: "s3express:GetLifecycleConfiguration",
|
|
50899
|
+
MetricsConfigurations: "s3express:GetMetricsConfiguration",
|
|
50900
|
+
InventoryConfigurations: "s3express:GetInventoryConfiguration"
|
|
50901
|
+
};
|
|
49660
50902
|
var S3DirectoryBucketProvider = class {
|
|
49661
50903
|
s3Client;
|
|
49662
50904
|
createClient;
|
|
@@ -49674,8 +50916,44 @@ var S3DirectoryBucketProvider = class {
|
|
|
49674
50916
|
"DataRedundancy",
|
|
49675
50917
|
"LocationName",
|
|
49676
50918
|
"BucketName",
|
|
49677
|
-
"Tags"
|
|
50919
|
+
"Tags",
|
|
50920
|
+
"BucketEncryption",
|
|
50921
|
+
"LifecycleConfiguration",
|
|
50922
|
+
"MetricsConfigurations",
|
|
50923
|
+
"InventoryConfigurations"
|
|
49678
50924
|
])]]);
|
|
50925
|
+
async readUnsettled(physicalId, _logicalId, _resourceType, names, recordedProperties, desiredProperties) {
|
|
50926
|
+
const live = await this.readState(physicalId);
|
|
50927
|
+
if (live === RESOURCE_NOT_FOUND) return live;
|
|
50928
|
+
const desired = desiredProperties ?? recordedProperties ?? {};
|
|
50929
|
+
const out = {};
|
|
50930
|
+
for (const name of names) {
|
|
50931
|
+
if (!Object.hasOwn(live, name)) continue;
|
|
50932
|
+
if (desired[name] !== void 0 && liveMatchesDesired(name, desired, live)) {
|
|
50933
|
+
out[name] = desired[name];
|
|
50934
|
+
continue;
|
|
50935
|
+
}
|
|
50936
|
+
if (name === "MetricsConfigurations" || name === "InventoryConfigurations") {
|
|
50937
|
+
const named = /* @__PURE__ */ new Set([...recordedItems(recordedProperties?.[name]).keys(), ...recordedItems(desiredProperties?.[name]).keys()]);
|
|
50938
|
+
const items = live[name];
|
|
50939
|
+
out[name] = Array.isArray(items) ? items.filter((item) => {
|
|
50940
|
+
const id = itemId(item);
|
|
50941
|
+
return id !== void 0 && named.has(id);
|
|
50942
|
+
}) : items;
|
|
50943
|
+
continue;
|
|
50944
|
+
}
|
|
50945
|
+
out[name] = live[name];
|
|
50946
|
+
}
|
|
50947
|
+
return out;
|
|
50948
|
+
}
|
|
50949
|
+
getDriftUnorderedPaths(resourceType) {
|
|
50950
|
+
if (resourceType !== "AWS::S3Express::DirectoryBucket") return [];
|
|
50951
|
+
return ["MetricsConfigurations", "InventoryConfigurations"];
|
|
50952
|
+
}
|
|
50953
|
+
canonicalizeDriftProperties(resourceType, properties) {
|
|
50954
|
+
if (resourceType !== "AWS::S3Express::DirectoryBucket") return properties;
|
|
50955
|
+
return canonicalizeConfigurationsForDrift(properties);
|
|
50956
|
+
}
|
|
49679
50957
|
ec2Client;
|
|
49680
50958
|
s3ControlClient;
|
|
49681
50959
|
providerRegion = ambientRegion();
|
|
@@ -49739,6 +51017,7 @@ var S3DirectoryBucketProvider = class {
|
|
|
49739
51017
|
async create(logicalId, resourceType, properties, context) {
|
|
49740
51018
|
this.logger.debug(`Creating S3 Express Directory Bucket ${logicalId}`);
|
|
49741
51019
|
const desiredTags = refuseMalformedDesiredTags(properties["Tags"], resourceType, logicalId);
|
|
51020
|
+
const configs = desiredConfigurations(properties, configurationRefuser(resourceType, logicalId), replayWarn(this.logger, context).onUnusable);
|
|
49742
51021
|
const dataRedundancy = requireConfigString(properties["DataRedundancy"], "SingleAvailabilityZone", "AWS::S3Express::DirectoryBucket DataRedundancy", replayWarn(this.logger, context));
|
|
49743
51022
|
const azName = properties["LocationName"]?.replace(/--x-s3$/, "") || "us-east-1a";
|
|
49744
51023
|
const azId = await this.getAzId(azName);
|
|
@@ -49746,6 +51025,7 @@ var S3DirectoryBucketProvider = class {
|
|
|
49746
51025
|
if (!bucketName) bucketName = generatedNameFor("AWS::S3Express::DirectoryBucket", logicalId, { zoneId: azId });
|
|
49747
51026
|
const tags = desiredTags;
|
|
49748
51027
|
const includeTags = tags.length > 0;
|
|
51028
|
+
let bucketCreated = false;
|
|
49749
51029
|
try {
|
|
49750
51030
|
const attributes = await this.buildAttributes(bucketName);
|
|
49751
51031
|
await (await this.getCreateClient()).send(new CreateBucketCommand({
|
|
@@ -49762,19 +51042,112 @@ var S3DirectoryBucketProvider = class {
|
|
|
49762
51042
|
...includeTags ? { Tags: tags } : {}
|
|
49763
51043
|
}
|
|
49764
51044
|
}));
|
|
51045
|
+
bucketCreated = true;
|
|
49765
51046
|
this.logger.debug(`Created S3 Express Directory Bucket: ${bucketName}`);
|
|
51047
|
+
await this.applyConfigurations(bucketName, configs, properties, {}, true);
|
|
49766
51048
|
return {
|
|
49767
51049
|
physicalId: bucketName,
|
|
49768
51050
|
attributes
|
|
49769
51051
|
};
|
|
49770
51052
|
} catch (error) {
|
|
49771
51053
|
const cause = error instanceof Error ? error : void 0;
|
|
49772
|
-
|
|
51054
|
+
const thrown = this.wrapCaughtError(maskerOrIdentity(context?.maskSecrets), error, (text) => new ProvisioningError(`Failed to create S3 Express Directory Bucket ${logicalId}: ${text}`, resourceType, logicalId, bucketName, cause));
|
|
51055
|
+
if (bucketCreated) markCreatedBeforeFailure(thrown, logicalId, resourceType, bucketName);
|
|
51056
|
+
throw thrown;
|
|
51057
|
+
}
|
|
51058
|
+
}
|
|
51059
|
+
async applyConfigurations(bucketName, desired, desiredRaw, previousRaw, creating, markUnsettled = () => {}) {
|
|
51060
|
+
const changed = (desiredValue, previousValue) => creating || !sameJson(desiredValue, previousValue);
|
|
51061
|
+
const holds = (value, toSdk) => {
|
|
51062
|
+
try {
|
|
51063
|
+
return toSdk(value, () => {
|
|
51064
|
+
throw new Error("malformed");
|
|
51065
|
+
}) !== void 0;
|
|
51066
|
+
} catch {
|
|
51067
|
+
return true;
|
|
51068
|
+
}
|
|
51069
|
+
};
|
|
51070
|
+
if (changed(desiredRaw["BucketEncryption"], previousRaw["BucketEncryption"])) {
|
|
51071
|
+
if (desired.encryption) {
|
|
51072
|
+
markUnsettled("BucketEncryption");
|
|
51073
|
+
await this.s3Client.send(new PutBucketEncryptionCommand({
|
|
51074
|
+
Bucket: bucketName,
|
|
51075
|
+
ServerSideEncryptionConfiguration: desired.encryption
|
|
51076
|
+
}));
|
|
51077
|
+
} else if (!creating && holds(previousRaw["BucketEncryption"], encryptionToSdk)) {
|
|
51078
|
+
markUnsettled("BucketEncryption");
|
|
51079
|
+
await this.s3Client.send(new DeleteBucketEncryptionCommand({ Bucket: bucketName }));
|
|
51080
|
+
this.logger.debug("Sent DeleteBucketEncryption: the default encryption is back to SSE-S3");
|
|
51081
|
+
}
|
|
51082
|
+
}
|
|
51083
|
+
if (changed(desiredRaw["LifecycleConfiguration"], previousRaw["LifecycleConfiguration"])) {
|
|
51084
|
+
if (desired.lifecycle) {
|
|
51085
|
+
markUnsettled("LifecycleConfiguration");
|
|
51086
|
+
await this.s3Client.send(new PutBucketLifecycleConfigurationCommand({
|
|
51087
|
+
Bucket: bucketName,
|
|
51088
|
+
LifecycleConfiguration: desired.lifecycle
|
|
51089
|
+
}));
|
|
51090
|
+
} else if (!creating && holds(previousRaw["LifecycleConfiguration"], lifecycleToSdk)) {
|
|
51091
|
+
markUnsettled("LifecycleConfiguration");
|
|
51092
|
+
await this.s3Client.send(new DeleteBucketLifecycleCommand({ Bucket: bucketName }));
|
|
51093
|
+
this.logger.debug("Sent DeleteBucketLifecycle: every lifecycle rule is removed");
|
|
51094
|
+
}
|
|
51095
|
+
}
|
|
51096
|
+
const desiredMetrics = recordedItems(desiredRaw["MetricsConfigurations"]);
|
|
51097
|
+
const previousMetrics = creating ? /* @__PURE__ */ new Map() : recordedItems(previousRaw["MetricsConfigurations"]);
|
|
51098
|
+
for (const [id, config] of desired.metrics) {
|
|
51099
|
+
if (previousMetrics.has(id) && sameJson(previousMetrics.get(id), desiredMetrics.get(id))) continue;
|
|
51100
|
+
markUnsettled("MetricsConfigurations");
|
|
51101
|
+
await this.s3Client.send(new PutBucketMetricsConfigurationCommand({
|
|
51102
|
+
Bucket: bucketName,
|
|
51103
|
+
Id: id,
|
|
51104
|
+
MetricsConfiguration: config
|
|
51105
|
+
}));
|
|
51106
|
+
}
|
|
51107
|
+
for (const id of previousMetrics.keys()) {
|
|
51108
|
+
if (desired.metrics.has(id)) continue;
|
|
51109
|
+
markUnsettled("MetricsConfigurations");
|
|
51110
|
+
await this.deleteItemIdempotently(new DeleteBucketMetricsConfigurationCommand({
|
|
51111
|
+
Bucket: bucketName,
|
|
51112
|
+
Id: id
|
|
51113
|
+
}));
|
|
51114
|
+
}
|
|
51115
|
+
const desiredInventory = recordedItems(desiredRaw["InventoryConfigurations"]);
|
|
51116
|
+
const previousInventory = creating ? /* @__PURE__ */ new Map() : recordedItems(previousRaw["InventoryConfigurations"]);
|
|
51117
|
+
for (const [id, config] of desired.inventory) {
|
|
51118
|
+
if (previousInventory.has(id) && sameJson(previousInventory.get(id), desiredInventory.get(id))) continue;
|
|
51119
|
+
markUnsettled("InventoryConfigurations");
|
|
51120
|
+
await this.s3Client.send(new PutBucketInventoryConfigurationCommand({
|
|
51121
|
+
Bucket: bucketName,
|
|
51122
|
+
Id: id,
|
|
51123
|
+
InventoryConfiguration: config
|
|
51124
|
+
}));
|
|
51125
|
+
}
|
|
51126
|
+
for (const id of previousInventory.keys()) {
|
|
51127
|
+
if (desired.inventory.has(id)) continue;
|
|
51128
|
+
markUnsettled("InventoryConfigurations");
|
|
51129
|
+
await this.deleteItemIdempotently(new DeleteBucketInventoryConfigurationCommand({
|
|
51130
|
+
Bucket: bucketName,
|
|
51131
|
+
Id: id
|
|
51132
|
+
}));
|
|
51133
|
+
}
|
|
51134
|
+
}
|
|
51135
|
+
async deleteItemIdempotently(command) {
|
|
51136
|
+
try {
|
|
51137
|
+
if (command instanceof DeleteBucketMetricsConfigurationCommand) await this.s3Client.send(command);
|
|
51138
|
+
else await this.s3Client.send(command);
|
|
51139
|
+
} catch (error) {
|
|
51140
|
+
if (error instanceof Error && error.name === "NoSuchConfiguration") {
|
|
51141
|
+
this.logger.debug("A configuration this update deletes is already gone");
|
|
51142
|
+
return;
|
|
51143
|
+
}
|
|
51144
|
+
throw error;
|
|
49773
51145
|
}
|
|
49774
51146
|
}
|
|
49775
51147
|
async update(logicalId, physicalId, resourceType, properties, previousProperties, context) {
|
|
49776
51148
|
if (context?.expectedRegion) for (const clientRegion of [await this.s3Client.config.region(), await this.getS3ControlClient().config.region()]) assertRegionMatch(clientRegion, context.expectedRegion, resourceType, logicalId, physicalId, "pre-update");
|
|
49777
51149
|
refuseMalformedDesiredTags(properties["Tags"], resourceType, logicalId, physicalId);
|
|
51150
|
+
const configs = desiredConfigurations(properties, configurationRefuser(resourceType, logicalId, physicalId));
|
|
49778
51151
|
try {
|
|
49779
51152
|
const plan = planTagDiff(previousProperties["Tags"], properties["Tags"]);
|
|
49780
51153
|
const tagWarning = tagPlanWarning(plan, resourceType, logicalId);
|
|
@@ -49787,18 +51160,25 @@ var S3DirectoryBucketProvider = class {
|
|
|
49787
51160
|
if (removedKeys.length > 0 || tagsToApply.length > 0) {
|
|
49788
51161
|
const accountId = await this.getAccountId();
|
|
49789
51162
|
const resourceArn = await this.buildBucketArn(physicalId, accountId);
|
|
49790
|
-
if (removedKeys.length > 0)
|
|
49791
|
-
|
|
49792
|
-
|
|
49793
|
-
|
|
49794
|
-
|
|
49795
|
-
|
|
49796
|
-
|
|
49797
|
-
|
|
49798
|
-
|
|
49799
|
-
|
|
51163
|
+
if (removedKeys.length > 0) {
|
|
51164
|
+
context?.markUnsettled?.("Tags");
|
|
51165
|
+
await this.getS3ControlClient().send(new UntagResourceCommand$29({
|
|
51166
|
+
AccountId: accountId,
|
|
51167
|
+
ResourceArn: resourceArn,
|
|
51168
|
+
TagKeys: removedKeys
|
|
51169
|
+
}));
|
|
51170
|
+
}
|
|
51171
|
+
if (tagsToApply.length > 0) {
|
|
51172
|
+
context?.markUnsettled?.("Tags");
|
|
51173
|
+
await this.getS3ControlClient().send(new TagResourceCommand$28({
|
|
51174
|
+
AccountId: accountId,
|
|
51175
|
+
ResourceArn: resourceArn,
|
|
51176
|
+
Tags: tagsToApply
|
|
51177
|
+
}));
|
|
51178
|
+
}
|
|
49800
51179
|
this.logger.debug(`Updated tags for S3 Express Directory Bucket ${physicalId}`);
|
|
49801
|
-
}
|
|
51180
|
+
}
|
|
51181
|
+
await this.applyConfigurations(physicalId, configs, properties, previousProperties, false, (key) => context?.markUnsettled?.(key));
|
|
49802
51182
|
return {
|
|
49803
51183
|
physicalId,
|
|
49804
51184
|
wasReplaced: false
|
|
@@ -49871,6 +51251,9 @@ var S3DirectoryBucketProvider = class {
|
|
|
49871
51251
|
} while (continuationToken);
|
|
49872
51252
|
}
|
|
49873
51253
|
async readCurrentState(physicalId, _logicalId, _resourceType) {
|
|
51254
|
+
return this.readState(physicalId);
|
|
51255
|
+
}
|
|
51256
|
+
async readState(physicalId) {
|
|
49874
51257
|
let locationType;
|
|
49875
51258
|
try {
|
|
49876
51259
|
locationType = (await this.s3Client.send(new HeadBucketCommand({ Bucket: physicalId })))?.BucketLocationType;
|
|
@@ -49882,8 +51265,63 @@ var S3DirectoryBucketProvider = class {
|
|
|
49882
51265
|
const result = { BucketName: physicalId };
|
|
49883
51266
|
if (physicalId.endsWith("--x-s3")) result["DataRedundancy"] = locationType === "LocalZone" ? "SingleLocalZone" : "SingleAvailabilityZone";
|
|
49884
51267
|
result["Tags"] = await this.readTags(physicalId);
|
|
51268
|
+
const reads = [
|
|
51269
|
+
["BucketEncryption", () => this.readEncryption(physicalId)],
|
|
51270
|
+
["LifecycleConfiguration", () => this.readLifecycle(physicalId)],
|
|
51271
|
+
["MetricsConfigurations", () => this.readMetrics(physicalId)],
|
|
51272
|
+
["InventoryConfigurations", () => this.readInventory(physicalId)]
|
|
51273
|
+
];
|
|
51274
|
+
(await Promise.all(reads.map(([key, read]) => read().catch((error) => {
|
|
51275
|
+
const name = error?.name;
|
|
51276
|
+
if (name === "AccessDenied" || name === "AccessDeniedException") throw new Error(`Reading ${key} of an S3 Express directory bucket needs ${CONFIGURATION_READ_ACTIONS[key]}: grant it to read the bucket back`, { cause: error });
|
|
51277
|
+
throw error;
|
|
51278
|
+
})))).forEach((value, i) => {
|
|
51279
|
+
result[reads[i][0]] = value;
|
|
51280
|
+
});
|
|
49885
51281
|
return result;
|
|
49886
51282
|
}
|
|
51283
|
+
async readEncryption(bucket) {
|
|
51284
|
+
try {
|
|
51285
|
+
return encryptionFromSdk((await this.s3Client.send(new GetBucketEncryptionCommand({ Bucket: bucket }))).ServerSideEncryptionConfiguration?.Rules ?? []);
|
|
51286
|
+
} catch (err) {
|
|
51287
|
+
if (err.name === "ServerSideEncryptionConfigurationNotFoundError") return { ServerSideEncryptionConfiguration: [] };
|
|
51288
|
+
throw err;
|
|
51289
|
+
}
|
|
51290
|
+
}
|
|
51291
|
+
async readLifecycle(bucket) {
|
|
51292
|
+
try {
|
|
51293
|
+
return lifecycleFromSdk((await this.s3Client.send(new GetBucketLifecycleConfigurationCommand({ Bucket: bucket }))).Rules ?? []);
|
|
51294
|
+
} catch (err) {
|
|
51295
|
+
if (err.name === "NoSuchLifecycleConfiguration") return { Rules: [] };
|
|
51296
|
+
throw err;
|
|
51297
|
+
}
|
|
51298
|
+
}
|
|
51299
|
+
async readMetrics(bucket) {
|
|
51300
|
+
const out = [];
|
|
51301
|
+
let token;
|
|
51302
|
+
do {
|
|
51303
|
+
const resp = await this.s3Client.send(new ListBucketMetricsConfigurationsCommand({
|
|
51304
|
+
Bucket: bucket,
|
|
51305
|
+
ContinuationToken: token
|
|
51306
|
+
}));
|
|
51307
|
+
for (const item of resp.MetricsConfigurationList ?? []) out.push(metricsFromSdk(item));
|
|
51308
|
+
token = resp.IsTruncated ? resp.NextContinuationToken : void 0;
|
|
51309
|
+
} while (token);
|
|
51310
|
+
return out;
|
|
51311
|
+
}
|
|
51312
|
+
async readInventory(bucket) {
|
|
51313
|
+
const out = [];
|
|
51314
|
+
let token;
|
|
51315
|
+
do {
|
|
51316
|
+
const resp = await this.s3Client.send(new ListBucketInventoryConfigurationsCommand({
|
|
51317
|
+
Bucket: bucket,
|
|
51318
|
+
ContinuationToken: token
|
|
51319
|
+
}));
|
|
51320
|
+
for (const item of resp.InventoryConfigurationList ?? []) out.push(inventoryFromSdk(item));
|
|
51321
|
+
token = resp.IsTruncated ? resp.NextContinuationToken : void 0;
|
|
51322
|
+
} while (token);
|
|
51323
|
+
return out;
|
|
51324
|
+
}
|
|
49887
51325
|
async readTags(bucketName) {
|
|
49888
51326
|
const accountId = await this.getAccountId();
|
|
49889
51327
|
const resourceArn = await this.buildBucketArn(bucketName, accountId);
|
|
@@ -49962,6 +51400,173 @@ function tableIdentityFromGetTable(tableARN, namespace, name) {
|
|
|
49962
51400
|
name
|
|
49963
51401
|
};
|
|
49964
51402
|
}
|
|
51403
|
+
function isCfnObject(value) {
|
|
51404
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
51405
|
+
}
|
|
51406
|
+
function desiredObject(properties, key, resourceType, logicalId, physicalId) {
|
|
51407
|
+
const value = properties[key];
|
|
51408
|
+
if (value === void 0) return void 0;
|
|
51409
|
+
if (isCfnObject(value)) return value;
|
|
51410
|
+
throw new ProvisioningError(`${key} for ${resourceType} ${logicalId} must be an object; refusing before any call`, resourceType, logicalId, physicalId);
|
|
51411
|
+
}
|
|
51412
|
+
function recordedObject(properties, key) {
|
|
51413
|
+
const value = properties[key];
|
|
51414
|
+
return isCfnObject(value) ? value : void 0;
|
|
51415
|
+
}
|
|
51416
|
+
var NotAnInteger = class extends Error {
|
|
51417
|
+
member;
|
|
51418
|
+
constructor(member) {
|
|
51419
|
+
super(`${member} must be an integer`);
|
|
51420
|
+
this.member = member;
|
|
51421
|
+
}
|
|
51422
|
+
};
|
|
51423
|
+
function integer(value, member) {
|
|
51424
|
+
if (value === void 0) return void 0;
|
|
51425
|
+
const n = typeof value === "number" ? value : typeof value === "string" && value.trim() !== "" ? Number(value) : NaN;
|
|
51426
|
+
if (Number.isInteger(n)) return n;
|
|
51427
|
+
throw new NotAnInteger(member);
|
|
51428
|
+
}
|
|
51429
|
+
function refuseNonIntegers(convert, key, resourceType, logicalId, physicalId) {
|
|
51430
|
+
try {
|
|
51431
|
+
return convert();
|
|
51432
|
+
} catch (error) {
|
|
51433
|
+
if (!(error instanceof NotAnInteger)) throw error;
|
|
51434
|
+
throw new ProvisioningError(`${key}.${error.member} for ${resourceType} ${logicalId} must be an integer; refusing before any call`, resourceType, logicalId, physicalId, error);
|
|
51435
|
+
}
|
|
51436
|
+
}
|
|
51437
|
+
function list(value) {
|
|
51438
|
+
return Array.isArray(value) ? value : void 0;
|
|
51439
|
+
}
|
|
51440
|
+
function defined(value) {
|
|
51441
|
+
return Object.fromEntries(Object.entries(value).filter(([, v]) => v !== void 0));
|
|
51442
|
+
}
|
|
51443
|
+
function maintenanceStatus(value) {
|
|
51444
|
+
return typeof value === "string" ? value.toLowerCase() : void 0;
|
|
51445
|
+
}
|
|
51446
|
+
function sdkEncryption(cfn) {
|
|
51447
|
+
return defined({
|
|
51448
|
+
sseAlgorithm: cfn["SSEAlgorithm"],
|
|
51449
|
+
kmsKeyArn: cfn["KMSKeyArn"]
|
|
51450
|
+
});
|
|
51451
|
+
}
|
|
51452
|
+
function sdkStorageClass(cfn) {
|
|
51453
|
+
return defined({ storageClass: cfn["StorageClass"] });
|
|
51454
|
+
}
|
|
51455
|
+
function sdkReplication(cfn) {
|
|
51456
|
+
return defined({
|
|
51457
|
+
role: cfn["Role"],
|
|
51458
|
+
rules: list(cfn["Rules"])?.map((rule) => defined({ destinations: list(isCfnObject(rule) ? rule["Destinations"] : void 0)?.map((destination) => defined({ destinationTableBucketARN: isCfnObject(destination) ? destination["DestinationTableBucketARN"] : void 0 })) }))
|
|
51459
|
+
});
|
|
51460
|
+
}
|
|
51461
|
+
function sdkUnreferencedFileRemoval(cfn) {
|
|
51462
|
+
const unreferencedDays = integer(cfn["UnreferencedDays"], "UnreferencedDays");
|
|
51463
|
+
const nonCurrentDays = integer(cfn["NoncurrentDays"], "NoncurrentDays");
|
|
51464
|
+
return defined({
|
|
51465
|
+
status: maintenanceStatus(cfn["Status"]),
|
|
51466
|
+
settings: unreferencedDays === void 0 && nonCurrentDays === void 0 ? void 0 : { icebergUnreferencedFileRemoval: defined({
|
|
51467
|
+
unreferencedDays,
|
|
51468
|
+
nonCurrentDays
|
|
51469
|
+
}) }
|
|
51470
|
+
});
|
|
51471
|
+
}
|
|
51472
|
+
function sdkCompaction(cfn) {
|
|
51473
|
+
const targetFileSizeMB = integer(cfn["TargetFileSizeMB"], "TargetFileSizeMB");
|
|
51474
|
+
return defined({
|
|
51475
|
+
status: maintenanceStatus(cfn["Status"]),
|
|
51476
|
+
settings: targetFileSizeMB === void 0 ? void 0 : { icebergCompaction: { targetFileSizeMB } }
|
|
51477
|
+
});
|
|
51478
|
+
}
|
|
51479
|
+
function sdkSnapshotManagement(cfn) {
|
|
51480
|
+
const minSnapshotsToKeep = integer(cfn["MinSnapshotsToKeep"], "MinSnapshotsToKeep");
|
|
51481
|
+
const maxSnapshotAgeHours = integer(cfn["MaxSnapshotAgeHours"], "MaxSnapshotAgeHours");
|
|
51482
|
+
return defined({
|
|
51483
|
+
status: maintenanceStatus(cfn["Status"]),
|
|
51484
|
+
settings: minSnapshotsToKeep === void 0 && maxSnapshotAgeHours === void 0 ? void 0 : { icebergSnapshotManagement: defined({
|
|
51485
|
+
minSnapshotsToKeep,
|
|
51486
|
+
maxSnapshotAgeHours
|
|
51487
|
+
}) }
|
|
51488
|
+
});
|
|
51489
|
+
}
|
|
51490
|
+
function mapObjects(value, map) {
|
|
51491
|
+
return list(value)?.map((element) => map(isCfnObject(element) ? element : {}));
|
|
51492
|
+
}
|
|
51493
|
+
function sdkIcebergMetadata(cfn) {
|
|
51494
|
+
const schema = isCfnObject(cfn["IcebergSchema"]) ? cfn["IcebergSchema"] : void 0;
|
|
51495
|
+
const schemaV2 = isCfnObject(cfn["IcebergSchemaV2"]) ? cfn["IcebergSchemaV2"] : void 0;
|
|
51496
|
+
const partitionSpec = isCfnObject(cfn["IcebergPartitionSpec"]) ? cfn["IcebergPartitionSpec"] : void 0;
|
|
51497
|
+
const sortOrder = isCfnObject(cfn["IcebergSortOrder"]) ? cfn["IcebergSortOrder"] : void 0;
|
|
51498
|
+
return defined({
|
|
51499
|
+
schema: schema && defined({ fields: mapObjects(schema["SchemaFieldList"], (f) => defined({
|
|
51500
|
+
id: integer(f["Id"], "IcebergSchema.SchemaFieldList.Id"),
|
|
51501
|
+
name: f["Name"],
|
|
51502
|
+
type: f["Type"],
|
|
51503
|
+
required: f["Required"]
|
|
51504
|
+
})) }),
|
|
51505
|
+
schemaV2: schemaV2 && defined({
|
|
51506
|
+
type: schemaV2["SchemaV2FieldType"],
|
|
51507
|
+
fields: mapObjects(schemaV2["SchemaV2FieldList"], (f) => defined({
|
|
51508
|
+
id: integer(f["Id"], "IcebergSchemaV2.SchemaV2FieldList.Id"),
|
|
51509
|
+
name: f["Name"],
|
|
51510
|
+
type: f["Type"],
|
|
51511
|
+
required: f["Required"],
|
|
51512
|
+
doc: f["Doc"]
|
|
51513
|
+
})),
|
|
51514
|
+
schemaId: integer(schemaV2["SchemaId"], "IcebergSchemaV2.SchemaId"),
|
|
51515
|
+
identifierFieldIds: list(schemaV2["IdentifierFieldIds"])?.map((id) => integer(id, "IcebergSchemaV2.IdentifierFieldIds"))
|
|
51516
|
+
}),
|
|
51517
|
+
partitionSpec: partitionSpec && defined({
|
|
51518
|
+
fields: mapObjects(partitionSpec["Fields"], (f) => defined({
|
|
51519
|
+
sourceId: integer(f["SourceId"], "IcebergPartitionSpec.Fields.SourceId"),
|
|
51520
|
+
transform: f["Transform"],
|
|
51521
|
+
name: f["Name"],
|
|
51522
|
+
fieldId: integer(f["FieldId"], "IcebergPartitionSpec.Fields.FieldId")
|
|
51523
|
+
})),
|
|
51524
|
+
specId: integer(partitionSpec["SpecId"], "IcebergPartitionSpec.SpecId")
|
|
51525
|
+
}),
|
|
51526
|
+
writeOrder: sortOrder && defined({
|
|
51527
|
+
orderId: integer(sortOrder["OrderId"], "IcebergSortOrder.OrderId"),
|
|
51528
|
+
fields: mapObjects(sortOrder["Fields"], (f) => defined({
|
|
51529
|
+
sourceId: integer(f["SourceId"], "IcebergSortOrder.Fields.SourceId"),
|
|
51530
|
+
transform: f["Transform"],
|
|
51531
|
+
direction: f["Direction"],
|
|
51532
|
+
nullOrder: f["NullOrder"]
|
|
51533
|
+
}))
|
|
51534
|
+
}),
|
|
51535
|
+
properties: isCfnObject(cfn["TableProperties"]) ? cfn["TableProperties"] : void 0
|
|
51536
|
+
});
|
|
51537
|
+
}
|
|
51538
|
+
const UPDATABLE_CONFIG_KEYS = {
|
|
51539
|
+
"AWS::S3Tables::TableBucket": [
|
|
51540
|
+
"EncryptionConfiguration",
|
|
51541
|
+
"StorageClassConfiguration",
|
|
51542
|
+
"MetricsConfiguration",
|
|
51543
|
+
"UnreferencedFileRemoval",
|
|
51544
|
+
"ReplicationConfiguration"
|
|
51545
|
+
],
|
|
51546
|
+
"AWS::S3Tables::Table": ["Compaction", "SnapshotManagement"]
|
|
51547
|
+
};
|
|
51548
|
+
function metricsEnabled(metrics, resourceType, logicalId, physicalId) {
|
|
51549
|
+
const status = metrics?.["Status"];
|
|
51550
|
+
if (status === void 0 || status === "Disabled") return false;
|
|
51551
|
+
if (status === "Enabled") return true;
|
|
51552
|
+
throw new ProvisioningError(safeMsg`MetricsConfiguration.Status for ${resourceType} ${logicalId} must be 'Enabled' or 'Disabled'; refusing before any call`, resourceType, logicalId, physicalId);
|
|
51553
|
+
}
|
|
51554
|
+
const TABLE_MAINTENANCE = [[
|
|
51555
|
+
"Compaction",
|
|
51556
|
+
"icebergCompaction",
|
|
51557
|
+
sdkCompaction
|
|
51558
|
+
], [
|
|
51559
|
+
"SnapshotManagement",
|
|
51560
|
+
"icebergSnapshotManagement",
|
|
51561
|
+
sdkSnapshotManagement
|
|
51562
|
+
]];
|
|
51563
|
+
const INTEGER_BEARING_CONFIGS = {
|
|
51564
|
+
"AWS::S3Tables::TableBucket": [["UnreferencedFileRemoval", sdkUnreferencedFileRemoval]],
|
|
51565
|
+
"AWS::S3Tables::Table": TABLE_MAINTENANCE.map(([key, , toSdk]) => [key, toSdk])
|
|
51566
|
+
};
|
|
51567
|
+
function cfnBucketStatus(status) {
|
|
51568
|
+
return status === void 0 ? void 0 : `${status.charAt(0).toUpperCase()}${status.slice(1)}`;
|
|
51569
|
+
}
|
|
49965
51570
|
function sentence(text) {
|
|
49966
51571
|
return text.endsWith(".") ? text : `${text}.`;
|
|
49967
51572
|
}
|
|
@@ -49978,7 +51583,15 @@ var S3TablesProvider = class {
|
|
|
49978
51583
|
return markRedactedCause(build(`${m(failure.summary)}${relayedNameCollision(failure.detail)}`));
|
|
49979
51584
|
}
|
|
49980
51585
|
handledProperties = /* @__PURE__ */ new Map([
|
|
49981
|
-
["AWS::S3Tables::TableBucket", /* @__PURE__ */ new Set([
|
|
51586
|
+
["AWS::S3Tables::TableBucket", /* @__PURE__ */ new Set([
|
|
51587
|
+
"TableBucketName",
|
|
51588
|
+
"Tags",
|
|
51589
|
+
"EncryptionConfiguration",
|
|
51590
|
+
"StorageClassConfiguration",
|
|
51591
|
+
"MetricsConfiguration",
|
|
51592
|
+
"UnreferencedFileRemoval",
|
|
51593
|
+
"ReplicationConfiguration"
|
|
51594
|
+
])],
|
|
49982
51595
|
["AWS::S3Tables::Namespace", /* @__PURE__ */ new Set(["TableBucketARN", "Namespace"])],
|
|
49983
51596
|
["AWS::S3Tables::Table", /* @__PURE__ */ new Set([
|
|
49984
51597
|
"TableBucketARN",
|
|
@@ -49987,9 +51600,24 @@ var S3TablesProvider = class {
|
|
|
49987
51600
|
"Name",
|
|
49988
51601
|
"OpenTableFormat",
|
|
49989
51602
|
"Format",
|
|
49990
|
-
"Tags"
|
|
51603
|
+
"Tags",
|
|
51604
|
+
"IcebergMetadata",
|
|
51605
|
+
"StorageClassConfiguration",
|
|
51606
|
+
"Compaction",
|
|
51607
|
+
"SnapshotManagement",
|
|
51608
|
+
"WithoutMetadata"
|
|
49991
51609
|
])]
|
|
49992
51610
|
]);
|
|
51611
|
+
getDriftUnknownPaths(resourceType) {
|
|
51612
|
+
return resourceType === "AWS::S3Tables::Table" ? [
|
|
51613
|
+
"IcebergMetadata",
|
|
51614
|
+
"StorageClassConfiguration",
|
|
51615
|
+
"WithoutMetadata"
|
|
51616
|
+
] : [];
|
|
51617
|
+
}
|
|
51618
|
+
getDriftAbsentMeansDefaultKeys(resourceType, properties) {
|
|
51619
|
+
return resourceType === "AWS::S3Tables::TableBucket" && properties["ReplicationConfiguration"] === void 0 ? ["ReplicationConfiguration"] : [];
|
|
51620
|
+
}
|
|
49993
51621
|
getClient() {
|
|
49994
51622
|
if (!this.client) {
|
|
49995
51623
|
this.client = new S3TablesClient({
|
|
@@ -50018,18 +51646,25 @@ var S3TablesProvider = class {
|
|
|
50018
51646
|
async update(logicalId, physicalId, resourceType, properties, previousProperties, context) {
|
|
50019
51647
|
assertRegionMatch(context?.expectedRegion ? await this.getClient().config.region() : void 0, context?.expectedRegion, resourceType, logicalId, physicalId, "pre-update");
|
|
50020
51648
|
if (resourceType === "AWS::S3Tables::Table" || resourceType === "AWS::S3Tables::TableBucket") refuseMalformedDesiredTags(properties["Tags"], resourceType, logicalId, physicalId);
|
|
51649
|
+
for (const key of UPDATABLE_CONFIG_KEYS[resourceType] ?? []) desiredObject(properties, key, resourceType, logicalId, physicalId);
|
|
51650
|
+
for (const [key, convert] of INTEGER_BEARING_CONFIGS[resourceType] ?? []) {
|
|
51651
|
+
const value = desiredObject(properties, key, resourceType, logicalId, physicalId);
|
|
51652
|
+
if (value !== void 0) refuseNonIntegers(() => convert(value), key, resourceType, logicalId, physicalId);
|
|
51653
|
+
}
|
|
51654
|
+
if (resourceType === "AWS::S3Tables::TableBucket") metricsEnabled(recordedObject(properties, "MetricsConfiguration"), resourceType, logicalId, physicalId);
|
|
50021
51655
|
try {
|
|
50022
|
-
return await this.applyUpdate(logicalId, physicalId, resourceType, properties, previousProperties, context?.maskSecrets, context?.recordedAttributes);
|
|
51656
|
+
return await this.applyUpdate(logicalId, physicalId, resourceType, properties, previousProperties, context?.maskSecrets, context?.recordedAttributes, (key) => context?.markUnsettled?.(key));
|
|
50023
51657
|
} catch (error) {
|
|
50024
51658
|
if (error instanceof CdkdError) throw error;
|
|
50025
51659
|
const cause = error instanceof Error ? error : void 0;
|
|
50026
51660
|
throw this.wrapCaughtError(context?.maskSecrets, error, (text) => new ProvisioningError(`Failed to update S3 Tables resource ${logicalId}: ${text}`, resourceType, logicalId, physicalId, cause));
|
|
50027
51661
|
}
|
|
50028
51662
|
}
|
|
50029
|
-
async applyUpdate(logicalId, physicalId, resourceType, properties, previousProperties, mask, recordedAttributes) {
|
|
51663
|
+
async applyUpdate(logicalId, physicalId, resourceType, properties, previousProperties, mask, recordedAttributes, markUnsettled) {
|
|
50030
51664
|
if (resourceType === "AWS::S3Tables::Table") {
|
|
50031
51665
|
const rename = await this.planTableRename(logicalId, physicalId, resourceType, properties, mask);
|
|
50032
51666
|
await this.applyTableTagsDiff(logicalId, physicalId, resourceType, previousProperties["Tags"], properties["Tags"], mask);
|
|
51667
|
+
await this.applyTableMaintenanceUpdate(logicalId, physicalId, resourceType, properties, previousProperties, markUnsettled);
|
|
50033
51668
|
if (rename === void 0) return {
|
|
50034
51669
|
physicalId,
|
|
50035
51670
|
wasReplaced: false
|
|
@@ -50044,8 +51679,10 @@ var S3TablesProvider = class {
|
|
|
50044
51679
|
physicalId: rename.physicalId,
|
|
50045
51680
|
wasReplaced: false
|
|
50046
51681
|
};
|
|
50047
|
-
} else if (resourceType === "AWS::S3Tables::TableBucket")
|
|
50048
|
-
|
|
51682
|
+
} else if (resourceType === "AWS::S3Tables::TableBucket") {
|
|
51683
|
+
await this.applyTableBucketTagsDiff(logicalId, physicalId, resourceType, previousProperties["Tags"], properties["Tags"], mask);
|
|
51684
|
+
await this.applyTableBucketConfigUpdate(logicalId, physicalId, resourceType, properties, previousProperties, markUnsettled);
|
|
51685
|
+
} else this.logger.debug(`Update is no-op for ${resourceType} ${logicalId}`);
|
|
50049
51686
|
return {
|
|
50050
51687
|
physicalId,
|
|
50051
51688
|
wasReplaced: false
|
|
@@ -50066,11 +51703,32 @@ var S3TablesProvider = class {
|
|
|
50066
51703
|
const tableBucketName = properties["TableBucketName"];
|
|
50067
51704
|
if (!tableBucketName) throw new ProvisioningError(`TableBucketName is required for S3 Table Bucket ${logicalId}`, resourceType, logicalId);
|
|
50068
51705
|
const tags = this.tagListToSdkMap(desiredTags);
|
|
51706
|
+
const encryption = desiredObject(properties, "EncryptionConfiguration", resourceType, logicalId);
|
|
51707
|
+
const storageClass = desiredObject(properties, "StorageClassConfiguration", resourceType, logicalId);
|
|
51708
|
+
const metricsOn = metricsEnabled(desiredObject(properties, "MetricsConfiguration", resourceType, logicalId), resourceType, logicalId);
|
|
51709
|
+
const unreferenced = desiredObject(properties, "UnreferencedFileRemoval", resourceType, logicalId);
|
|
51710
|
+
const replication = desiredObject(properties, "ReplicationConfiguration", resourceType, logicalId);
|
|
51711
|
+
const unreferencedValue = unreferenced && refuseNonIntegers(() => sdkUnreferencedFileRemoval(unreferenced), "UnreferencedFileRemoval", resourceType, logicalId);
|
|
51712
|
+
let createdArn;
|
|
50069
51713
|
try {
|
|
50070
51714
|
const tableBucketARN = (await this.getCreateClient().send(new CreateTableBucketCommand({
|
|
50071
51715
|
name: tableBucketName,
|
|
51716
|
+
...encryption !== void 0 && { encryptionConfiguration: sdkEncryption(encryption) },
|
|
51717
|
+
...storageClass !== void 0 && { storageClassConfiguration: sdkStorageClass(storageClass) },
|
|
50072
51718
|
...tags !== void 0 && { tags }
|
|
50073
51719
|
}))).arn;
|
|
51720
|
+
createdArn = tableBucketARN;
|
|
51721
|
+
reportCreatedResource(logicalId, resourceType, tableBucketARN);
|
|
51722
|
+
if (metricsOn) await this.getClient().send(new PutTableBucketMetricsConfigurationCommand({ tableBucketARN }));
|
|
51723
|
+
if (unreferencedValue !== void 0) await this.getClient().send(new PutTableBucketMaintenanceConfigurationCommand({
|
|
51724
|
+
tableBucketARN,
|
|
51725
|
+
type: "icebergUnreferencedFileRemoval",
|
|
51726
|
+
value: unreferencedValue
|
|
51727
|
+
}));
|
|
51728
|
+
if (replication !== void 0) await this.getClient().send(new PutTableBucketReplicationCommand({
|
|
51729
|
+
tableBucketARN,
|
|
51730
|
+
configuration: sdkReplication(replication)
|
|
51731
|
+
}));
|
|
50074
51732
|
this.logger.debug(`Successfully created S3 Table Bucket ${logicalId}: ${tableBucketARN}`);
|
|
50075
51733
|
return {
|
|
50076
51734
|
physicalId: tableBucketARN,
|
|
@@ -50078,7 +51736,104 @@ var S3TablesProvider = class {
|
|
|
50078
51736
|
};
|
|
50079
51737
|
} catch (error) {
|
|
50080
51738
|
const cause = error instanceof Error ? error : void 0;
|
|
50081
|
-
|
|
51739
|
+
const thrown = this.wrapCaughtError(context?.maskSecrets, error, (text) => new ProvisioningError(`Failed to create S3 Table Bucket ${logicalId}: ${text}`, resourceType, logicalId, void 0, cause));
|
|
51740
|
+
if (createdArn !== void 0) markCreatedBeforeFailure(thrown, logicalId, resourceType, createdArn);
|
|
51741
|
+
throw thrown;
|
|
51742
|
+
}
|
|
51743
|
+
}
|
|
51744
|
+
async applyTableBucketConfigUpdate(logicalId, tableBucketARN, resourceType, properties, previousProperties, markUnsettled) {
|
|
51745
|
+
const changed = (key) => {
|
|
51746
|
+
const next = desiredObject(properties, key, resourceType, logicalId, tableBucketARN);
|
|
51747
|
+
return [next, !isDeepStrictEqual(next, recordedObject(previousProperties, key))];
|
|
51748
|
+
};
|
|
51749
|
+
const client = this.getClient();
|
|
51750
|
+
const [encryption, encryptionChanged] = changed("EncryptionConfiguration");
|
|
51751
|
+
if (encryptionChanged) {
|
|
51752
|
+
if (encryption !== void 0) {
|
|
51753
|
+
markUnsettled("EncryptionConfiguration");
|
|
51754
|
+
await client.send(new PutTableBucketEncryptionCommand({
|
|
51755
|
+
tableBucketARN,
|
|
51756
|
+
encryptionConfiguration: sdkEncryption(encryption)
|
|
51757
|
+
}));
|
|
51758
|
+
} else this.warnRemovalKept(logicalId, "EncryptionConfiguration");
|
|
51759
|
+
}
|
|
51760
|
+
const [storageClass, storageClassChanged] = changed("StorageClassConfiguration");
|
|
51761
|
+
if (storageClassChanged) {
|
|
51762
|
+
if (storageClass !== void 0) {
|
|
51763
|
+
markUnsettled("StorageClassConfiguration");
|
|
51764
|
+
await client.send(new PutTableBucketStorageClassCommand({
|
|
51765
|
+
tableBucketARN,
|
|
51766
|
+
storageClassConfiguration: sdkStorageClass(storageClass)
|
|
51767
|
+
}));
|
|
51768
|
+
} else this.warnRemovalKept(logicalId, "StorageClassConfiguration");
|
|
51769
|
+
}
|
|
51770
|
+
const metricsOn = metricsEnabled(desiredObject(properties, "MetricsConfiguration", resourceType, logicalId, tableBucketARN), resourceType, logicalId);
|
|
51771
|
+
const metricsWasOn = recordedObject(previousProperties, "MetricsConfiguration")?.["Status"] === "Enabled";
|
|
51772
|
+
if (metricsOn && !metricsWasOn) {
|
|
51773
|
+
markUnsettled("MetricsConfiguration");
|
|
51774
|
+
await client.send(new PutTableBucketMetricsConfigurationCommand({ tableBucketARN }));
|
|
51775
|
+
} else if (!metricsOn && metricsWasOn) {
|
|
51776
|
+
markUnsettled("MetricsConfiguration");
|
|
51777
|
+
await this.deleteBucketConfig(tableBucketARN, new DeleteTableBucketMetricsConfigurationCommand({ tableBucketARN }));
|
|
51778
|
+
}
|
|
51779
|
+
const [unreferenced, unreferencedChanged] = changed("UnreferencedFileRemoval");
|
|
51780
|
+
if (unreferencedChanged) {
|
|
51781
|
+
if (unreferenced !== void 0) {
|
|
51782
|
+
markUnsettled("UnreferencedFileRemoval");
|
|
51783
|
+
await client.send(new PutTableBucketMaintenanceConfigurationCommand({
|
|
51784
|
+
tableBucketARN,
|
|
51785
|
+
type: "icebergUnreferencedFileRemoval",
|
|
51786
|
+
value: sdkUnreferencedFileRemoval(unreferenced)
|
|
51787
|
+
}));
|
|
51788
|
+
} else this.warnRemovalKept(logicalId, "UnreferencedFileRemoval");
|
|
51789
|
+
}
|
|
51790
|
+
const [replication, replicationChanged] = changed("ReplicationConfiguration");
|
|
51791
|
+
if (replicationChanged) {
|
|
51792
|
+
if (replication !== void 0) {
|
|
51793
|
+
markUnsettled("ReplicationConfiguration");
|
|
51794
|
+
await client.send(new PutTableBucketReplicationCommand({
|
|
51795
|
+
tableBucketARN,
|
|
51796
|
+
configuration: sdkReplication(replication)
|
|
51797
|
+
}));
|
|
51798
|
+
} else {
|
|
51799
|
+
markUnsettled("ReplicationConfiguration");
|
|
51800
|
+
await this.deleteBucketConfig(tableBucketARN, new DeleteTableBucketReplicationCommand({ tableBucketARN }));
|
|
51801
|
+
}
|
|
51802
|
+
}
|
|
51803
|
+
}
|
|
51804
|
+
async applyTableMaintenanceUpdate(logicalId, physicalId, resourceType, properties, previousProperties, markUnsettled) {
|
|
51805
|
+
const writes = [];
|
|
51806
|
+
for (const [key, type, toSdk] of TABLE_MAINTENANCE) {
|
|
51807
|
+
const next = desiredObject(properties, key, resourceType, logicalId, physicalId);
|
|
51808
|
+
if (isDeepStrictEqual(next, recordedObject(previousProperties, key))) continue;
|
|
51809
|
+
if (next === void 0) this.warnRemovalKept(logicalId, key);
|
|
51810
|
+
else writes.push({
|
|
51811
|
+
key,
|
|
51812
|
+
type,
|
|
51813
|
+
value: toSdk(next)
|
|
51814
|
+
});
|
|
51815
|
+
}
|
|
51816
|
+
if (writes.length === 0) return;
|
|
51817
|
+
const table = await this.resolveTableParts(physicalId);
|
|
51818
|
+
if (table === "not-found" || table === "unparseable") throw new ProvisioningError(table === "not-found" ? safeMsg`S3 Tables Table '${physicalId}' no longer exists (state is out of sync); ` + `refusing to record a maintenance configuration that was not applied` : compositeIdFormatMessage(S3_TABLES_TABLE_ID_FORMAT, logicalId, physicalId), resourceType, logicalId, physicalId);
|
|
51819
|
+
for (const { key, type, value } of writes) {
|
|
51820
|
+
markUnsettled(key);
|
|
51821
|
+
await this.getClient().send(new PutTableMaintenanceConfigurationCommand({
|
|
51822
|
+
...table,
|
|
51823
|
+
type,
|
|
51824
|
+
value
|
|
51825
|
+
}));
|
|
51826
|
+
}
|
|
51827
|
+
}
|
|
51828
|
+
warnRemovalKept(logicalId, key) {
|
|
51829
|
+
this.logger.warn(safeMsg`${logicalId}: ${key} was removed from the template; cdkd leaves its current AWS value in ` + `place. Declare the value you want (e.g. its default) to change it.`);
|
|
51830
|
+
}
|
|
51831
|
+
async deleteBucketConfig(tableBucketARN, command) {
|
|
51832
|
+
try {
|
|
51833
|
+
await this.getClient().send(command);
|
|
51834
|
+
} catch (error) {
|
|
51835
|
+
if (!(error instanceof NotFoundException$7)) throw error;
|
|
51836
|
+
await this.getClient().send(new GetTableBucketCommand({ tableBucketARN }));
|
|
50082
51837
|
}
|
|
50083
51838
|
}
|
|
50084
51839
|
async deleteTableBucket(logicalId, physicalId, resourceType, context) {
|
|
@@ -50213,6 +51968,17 @@ var S3TablesProvider = class {
|
|
|
50213
51968
|
const format = properties["OpenTableFormat"] ?? properties["Format"];
|
|
50214
51969
|
if (!format) throw new ProvisioningError(`OpenTableFormat is required for S3 Tables Table ${logicalId}`, resourceType, logicalId);
|
|
50215
51970
|
const tags = this.tagListToSdkMap(desiredTags);
|
|
51971
|
+
const icebergCfn = desiredObject(properties, "IcebergMetadata", resourceType, logicalId);
|
|
51972
|
+
const iceberg = icebergCfn && refuseNonIntegers(() => sdkIcebergMetadata(icebergCfn), "IcebergMetadata", resourceType, logicalId);
|
|
51973
|
+
const storageClass = desiredObject(properties, "StorageClassConfiguration", resourceType, logicalId);
|
|
51974
|
+
const maintenance = [];
|
|
51975
|
+
for (const [key, type, toSdk] of TABLE_MAINTENANCE) {
|
|
51976
|
+
const value = desiredObject(properties, key, resourceType, logicalId);
|
|
51977
|
+
if (value !== void 0) maintenance.push({
|
|
51978
|
+
type,
|
|
51979
|
+
value: refuseNonIntegers(() => toSdk(value), key, resourceType, logicalId)
|
|
51980
|
+
});
|
|
51981
|
+
}
|
|
50216
51982
|
const physicalId = packCompositeId(resourceType, logicalId, [
|
|
50217
51983
|
{
|
|
50218
51984
|
name: "tableBucketARN",
|
|
@@ -50237,9 +52003,18 @@ var S3TablesProvider = class {
|
|
|
50237
52003
|
namespace,
|
|
50238
52004
|
name,
|
|
50239
52005
|
format,
|
|
52006
|
+
...iceberg !== void 0 && { metadata: { iceberg } },
|
|
52007
|
+
...storageClass !== void 0 && { storageClassConfiguration: sdkStorageClass(storageClass) },
|
|
50240
52008
|
...tags !== void 0 && { tags }
|
|
50241
52009
|
}));
|
|
50242
52010
|
tableCreated = true;
|
|
52011
|
+
reportCreatedResource(logicalId, resourceType, physicalId);
|
|
52012
|
+
for (const write of maintenance) await this.getClient().send(new PutTableMaintenanceConfigurationCommand({
|
|
52013
|
+
tableBucketARN,
|
|
52014
|
+
namespace,
|
|
52015
|
+
name,
|
|
52016
|
+
...write
|
|
52017
|
+
}));
|
|
50243
52018
|
if (!response.tableARN) throw new ProvisioningError(`CreateTable did not return a tableARN for ${logicalId} (${physicalId}) — refusing to record an empty TableARN attribute`, resourceType, logicalId, physicalId);
|
|
50244
52019
|
const tableARN = response.tableARN;
|
|
50245
52020
|
this.logger.debug(`Successfully created S3 Tables Table ${logicalId}: ${physicalId}`);
|
|
@@ -50275,8 +52050,58 @@ var S3TablesProvider = class {
|
|
|
50275
52050
|
const result = {};
|
|
50276
52051
|
if (bucket.name !== void 0) result["TableBucketName"] = bucket.name;
|
|
50277
52052
|
result["Tags"] = await this.readTagsBestEffort(physicalId);
|
|
52053
|
+
Object.assign(result, await this.readTableBucketConfigs(physicalId));
|
|
50278
52054
|
return result;
|
|
50279
52055
|
}
|
|
52056
|
+
async readTableBucketConfigs(tableBucketARN, strict = false) {
|
|
52057
|
+
const client = this.getClient();
|
|
52058
|
+
const out = {};
|
|
52059
|
+
await this.readConfig(out, "EncryptionConfiguration", async () => {
|
|
52060
|
+
const e = (await client.send(new GetTableBucketEncryptionCommand({ tableBucketARN }))).encryptionConfiguration;
|
|
52061
|
+
return defined({
|
|
52062
|
+
SSEAlgorithm: e?.sseAlgorithm ?? "AES256",
|
|
52063
|
+
KMSKeyArn: e?.kmsKeyArn
|
|
52064
|
+
});
|
|
52065
|
+
}, { SSEAlgorithm: "AES256" }, strict);
|
|
52066
|
+
await this.readConfig(out, "StorageClassConfiguration", async () => {
|
|
52067
|
+
return { StorageClass: (await client.send(new GetTableBucketStorageClassCommand({ tableBucketARN }))).storageClassConfiguration?.storageClass ?? "STANDARD" };
|
|
52068
|
+
}, { StorageClass: "STANDARD" }, strict);
|
|
52069
|
+
await this.readConfig(out, "MetricsConfiguration", async () => {
|
|
52070
|
+
await client.send(new GetTableBucketMetricsConfigurationCommand({ tableBucketARN }));
|
|
52071
|
+
return { Status: "Enabled" };
|
|
52072
|
+
}, { Status: "Disabled" }, strict);
|
|
52073
|
+
await this.readConfig(out, "UnreferencedFileRemoval", async () => {
|
|
52074
|
+
const value = (await client.send(new GetTableBucketMaintenanceConfigurationCommand({ tableBucketARN }))).configuration?.icebergUnreferencedFileRemoval;
|
|
52075
|
+
const settings = value?.settings?.icebergUnreferencedFileRemoval;
|
|
52076
|
+
return defined({
|
|
52077
|
+
Status: cfnBucketStatus(value?.status) ?? "Enabled",
|
|
52078
|
+
UnreferencedDays: settings?.unreferencedDays,
|
|
52079
|
+
NoncurrentDays: settings?.nonCurrentDays
|
|
52080
|
+
});
|
|
52081
|
+
}, { Status: "Enabled" }, strict);
|
|
52082
|
+
await this.readConfig(out, "ReplicationConfiguration", async () => {
|
|
52083
|
+
const c = (await client.send(new GetTableBucketReplicationCommand({ tableBucketARN }))).configuration;
|
|
52084
|
+
if (c === void 0) return void 0;
|
|
52085
|
+
return defined({
|
|
52086
|
+
Role: c.role,
|
|
52087
|
+
Rules: (c.rules ?? []).map((rule) => ({ Destinations: (rule.destinations ?? []).map((d) => ({ DestinationTableBucketARN: d.destinationTableBucketARN })) }))
|
|
52088
|
+
});
|
|
52089
|
+
}, "absent", strict);
|
|
52090
|
+
return out;
|
|
52091
|
+
}
|
|
52092
|
+
async readConfig(out, key, read, notFound, strict = false) {
|
|
52093
|
+
try {
|
|
52094
|
+
const value = await read();
|
|
52095
|
+
if (value !== void 0) out[key] = value;
|
|
52096
|
+
} catch (err) {
|
|
52097
|
+
if (err instanceof NotFoundException$7) {
|
|
52098
|
+
if (notFound !== "absent") out[key] = notFound;
|
|
52099
|
+
return;
|
|
52100
|
+
}
|
|
52101
|
+
if (strict) throw err;
|
|
52102
|
+
this.logger.debug(safeMsg`readCurrentState: reading ${key} failed: ${describeAwsFailure(err).detail} — leaving it out`);
|
|
52103
|
+
}
|
|
52104
|
+
}
|
|
50280
52105
|
async readNamespaceCurrentState(physicalId) {
|
|
50281
52106
|
const [tableBucketARN, namespaceName] = physicalId.split("|");
|
|
50282
52107
|
if (!tableBucketARN || !namespaceName) return void 0;
|
|
@@ -50350,8 +52175,62 @@ var S3TablesProvider = class {
|
|
|
50350
52175
|
result["Format"] = resp.format;
|
|
50351
52176
|
}
|
|
50352
52177
|
result["Tags"] = resp.tableARN ? await this.readTagsBestEffort(resp.tableARN) : [];
|
|
52178
|
+
Object.assign(result, await this.readTableMaintenance(physicalId, {
|
|
52179
|
+
tableBucketARN,
|
|
52180
|
+
namespace,
|
|
52181
|
+
name
|
|
52182
|
+
}));
|
|
50353
52183
|
return result;
|
|
50354
52184
|
}
|
|
52185
|
+
async readTableMaintenance(physicalId, table, strict = false) {
|
|
52186
|
+
const result = {};
|
|
52187
|
+
let maintenance;
|
|
52188
|
+
let maintenanceRead = true;
|
|
52189
|
+
try {
|
|
52190
|
+
maintenance = (await this.getClient().send(new GetTableMaintenanceConfigurationCommand(table))).configuration;
|
|
52191
|
+
} catch (err) {
|
|
52192
|
+
maintenanceRead = err instanceof NotFoundException$7;
|
|
52193
|
+
if (!maintenanceRead) {
|
|
52194
|
+
if (strict) throw err;
|
|
52195
|
+
this.logger.debug(safeMsg`readCurrentState: reading the maintenance configuration of ${physicalId} failed: ` + safeMsg`${describeAwsFailure(err).detail} — leaving Compaction / SnapshotManagement out`);
|
|
52196
|
+
}
|
|
52197
|
+
}
|
|
52198
|
+
if (maintenanceRead) {
|
|
52199
|
+
const compaction = maintenance?.icebergCompaction;
|
|
52200
|
+
const compactionSettings = compaction?.settings && "icebergCompaction" in compaction.settings ? compaction.settings.icebergCompaction : void 0;
|
|
52201
|
+
result["Compaction"] = defined({
|
|
52202
|
+
Status: compaction?.status ?? "enabled",
|
|
52203
|
+
TargetFileSizeMB: compactionSettings?.targetFileSizeMB
|
|
52204
|
+
});
|
|
52205
|
+
const snapshots = maintenance?.icebergSnapshotManagement;
|
|
52206
|
+
const snapshotSettings = snapshots?.settings && "icebergSnapshotManagement" in snapshots.settings ? snapshots.settings.icebergSnapshotManagement : void 0;
|
|
52207
|
+
result["SnapshotManagement"] = defined({
|
|
52208
|
+
Status: snapshots?.status ?? "enabled",
|
|
52209
|
+
MinSnapshotsToKeep: snapshotSettings?.minSnapshotsToKeep,
|
|
52210
|
+
MaxSnapshotAgeHours: snapshotSettings?.maxSnapshotAgeHours
|
|
52211
|
+
});
|
|
52212
|
+
}
|
|
52213
|
+
return result;
|
|
52214
|
+
}
|
|
52215
|
+
async readUnsettled(physicalId, logicalId, resourceType, names) {
|
|
52216
|
+
let live;
|
|
52217
|
+
if (resourceType === "AWS::S3Tables::TableBucket") {
|
|
52218
|
+
try {
|
|
52219
|
+
await this.getClient().send(new GetTableBucketCommand({ tableBucketARN: physicalId }));
|
|
52220
|
+
} catch (err) {
|
|
52221
|
+
if (err instanceof NotFoundException$7) return RESOURCE_NOT_FOUND;
|
|
52222
|
+
throw err;
|
|
52223
|
+
}
|
|
52224
|
+
live = await this.readTableBucketConfigs(physicalId, true);
|
|
52225
|
+
} else if (resourceType === "AWS::S3Tables::Table") {
|
|
52226
|
+
const table = await this.resolveTableParts(physicalId);
|
|
52227
|
+
if (table === "not-found") return RESOURCE_NOT_FOUND;
|
|
52228
|
+
if (table === "unparseable") throw new ProvisioningError(compositeIdFormatMessage(S3_TABLES_TABLE_ID_FORMAT, logicalId, physicalId), resourceType, logicalId, physicalId);
|
|
52229
|
+
if (await this.lookupTableArn(table.tableBucketARN, table.namespace, table.name) === null) return RESOURCE_NOT_FOUND;
|
|
52230
|
+
live = await this.readTableMaintenance(physicalId, table, true);
|
|
52231
|
+
} else return;
|
|
52232
|
+
return Object.fromEntries(Object.entries(live).filter(([key]) => names.has(key)));
|
|
52233
|
+
}
|
|
50355
52234
|
async import(input) {
|
|
50356
52235
|
switch (input.resourceType) {
|
|
50357
52236
|
case "AWS::S3Tables::TableBucket": return this.importTableBucket(input);
|
|
@@ -50767,6 +52646,7 @@ var ECRProvider = class {
|
|
|
50767
52646
|
...tags ? { tags } : {}
|
|
50768
52647
|
}));
|
|
50769
52648
|
repositoryCreated = true;
|
|
52649
|
+
reportCreatedResource(logicalId, resourceType, repositoryName);
|
|
50770
52650
|
const repo = response.repository;
|
|
50771
52651
|
if (!repo?.repositoryName) throw new Error("CreateRepository did not return repository name");
|
|
50772
52652
|
const lifecyclePolicy = properties["LifecyclePolicy"];
|
|
@@ -51495,6 +53375,7 @@ var ACMCertificateProvider = class {
|
|
|
51495
53375
|
const certificateArn = (await this.acmClient.send(new RequestCertificateCommand(input))).CertificateArn;
|
|
51496
53376
|
if (!certificateArn) throw new ProvisioningError(`RequestCertificate succeeded but no CertificateArn returned for ${logicalId}`, resourceType, logicalId);
|
|
51497
53377
|
requestedArn = certificateArn;
|
|
53378
|
+
reportCreatedResource(logicalId, resourceType, certificateArn);
|
|
51498
53379
|
this.logger.debug(`Requested ACM certificate: ${certificateArn}`);
|
|
51499
53380
|
if (!(process.env["CDKD_NO_WAIT"] === "true")) await this.waitForCertificateIssued(certificateArn, logicalId, resourceType, dnsValidationZones(properties));
|
|
51500
53381
|
else this.logger.warn(`Skipping wait for ACM certificate ${logicalId} (CDKD_NO_WAIT=true). Downstream consumers (CloudFront / ALB) will fail until the cert reaches ISSUED.`);
|
|
@@ -51508,6 +53389,7 @@ var ACMCertificateProvider = class {
|
|
|
51508
53389
|
};
|
|
51509
53390
|
} catch (error) {
|
|
51510
53391
|
const survivorNote = requestedArn ? await this.cleanupRequestedCertificate(requestedArn, logicalId, idempotencyToken, context?.maskSecrets) : void 0;
|
|
53392
|
+
if (requestedArn && survivorNote === void 0) retractCreatedResource(logicalId, resourceType, requestedArn);
|
|
51511
53393
|
if (error instanceof CdkdError) {
|
|
51512
53394
|
if (survivorNote === void 0) throw error;
|
|
51513
53395
|
const thrown = new ProvisioningError(`${error.message} ${survivorNote}`, resourceType, logicalId, requestedArn, error);
|
|
@@ -51796,4 +53678,4 @@ var ACMCertificateProvider = class {
|
|
|
51796
53678
|
|
|
51797
53679
|
//#endregion
|
|
51798
53680
|
export { ACMCertificateProvider, ASGProvider, AgentCoreBrowserProvider, AgentCoreCodeInterpreterProvider, AgentCoreEvaluatorProvider, AgentCoreRuntimeProvider, ApiGatewayProvider, ApiGatewayV2Provider, AppSyncProvider, BudgetsBudgetProvider, CloudFrontDistributionProvider, CloudFrontOACProvider, CloudFrontOAIProvider, CloudTrailProvider, CloudWatchAlarmProvider, CloudWatchAnomalyDetectorProvider, CodeBuildProvider, CodeCommitRepositoryProvider, CognitoUserPoolProvider, DLMLifecyclePolicyProvider, DocDBProvider, DocDBSubnetGroupProvider, DynamoDBGlobalTableProvider, DynamoDBTableProvider, EC2Provider, ECRProvider, ECSProvider, EFSProvider, ELBv2Provider, EMRClusterProvider, EMRInstanceFleetConfigProvider, EMRInstanceGroupConfigProvider, ElastiCacheProvider, EventBridgeBusProvider, EventBridgeRuleProvider, FSxFileSystemProvider, FirehoseProvider, GlueConnectionProvider, GlueCrawlerProvider, GlueJobProvider, GlueProvider, GlueSecurityConfigurationProvider, GlueTriggerProvider, GlueWorkflowProvider, IAMAccessKeyProvider, IAMInstanceProfileProvider, IAMManagedPolicyProvider, IAMPolicyProvider, IAMRoleProvider, IAMUserGroupProvider, KMSProvider, KinesisStreamConsumerProvider, KinesisStreamProvider, LambdaEventInvokeConfigProvider, LambdaEventSourceMappingProvider, LambdaFunctionProvider, LambdaLayerVersionProvider, LambdaMicrovmImageProvider, LambdaNetworkConnectorProvider, LambdaPermissionProvider, LambdaUrlProvider, LambdaWebFunctionEndpointProvider, LambdaWebFunctionRevisionProvider, LogsLogGroupProvider, NeptuneProvider, NestedStackProvider, PipesPipeProvider, RDSDBProxyEndpointProvider, RDSDBProxyProvider, RDSDBProxyTargetGroupProvider, RDSProvider, Route53Provider, S3BucketPolicyProvider, S3BucketProvider, S3DirectoryBucketProvider, S3TablesProvider, S3VectorsProvider, SNSSubscriptionProvider, SNSTopicPolicyProvider, SNSTopicProvider, SQSQueuePolicyProvider, SQSQueueProvider, SSMParameterProvider, SchedulerScheduleProvider, SecretsManagerSecretProvider, ServiceDiscoveryProvider, StepFunctionsProvider, WAFv2WebACLProvider, WaitConditionHandleProvider };
|
|
51799
|
-
//# sourceMappingURL=provider-classes-
|
|
53681
|
+
//# sourceMappingURL=provider-classes-Dz0pYmlJ.js.map
|