@go-to-k/cdkd 0.295.0 → 0.296.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{asg-provider-DuAHOXvT.js → asg-provider-AVCcoXnQ.js} +8 -6
- package/dist/asg-provider-AVCcoXnQ.js.map +1 -0
- package/dist/cli.js +2 -2
- package/dist/{deploy-engine-CuI_h_Ml.js → deploy-engine-D7204v7Z.js} +986 -183
- package/dist/deploy-engine-D7204v7Z.js.map +1 -0
- package/dist/{iam-policy-targets-CMSQGQnm.js → iam-policy-targets-DSDSdxXz.js} +145 -4
- package/dist/iam-policy-targets-DSDSdxXz.js.map +1 -0
- package/dist/{iam-role-provider-CyM-wxAp.js → iam-role-provider-CCPaZ3U4.js} +11 -5
- package/dist/iam-role-provider-CCPaZ3U4.js.map +1 -0
- package/dist/index.d.ts +37 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/{logger-B46YMG0h.js → logger-Dvc7ddKe.js} +19 -3
- package/dist/{logger-B46YMG0h.js.map → logger-Dvc7ddKe.js.map} +1 -1
- package/dist/{neptune-provider-BGVccWhg.js → neptune-provider-D1t9NgT-.js} +20 -14
- package/dist/neptune-provider-D1t9NgT-.js.map +1 -0
- package/dist/{program-Cbxe8TgI.js → program-B0sp_SHG.js} +6219 -5942
- package/dist/program-B0sp_SHG.js.map +1 -0
- package/dist/{provider-classes-DiWFkAOH.js → provider-classes-DMOnX5s-.js} +989 -238
- package/dist/provider-classes-DMOnX5s-.js.map +1 -0
- package/dist/{rds-provider-D6_Rcnub.js → rds-provider-DltlcDiQ.js} +22 -15
- package/dist/rds-provider-DltlcDiQ.js.map +1 -0
- package/dist/{version-CMMITJVg.js → version-DUHDmEhz.js} +2 -2
- package/dist/{version-CMMITJVg.js.map → version-DUHDmEhz.js.map} +1 -1
- package/package.json +4 -4
- package/dist/asg-provider-DuAHOXvT.js.map +0 -1
- package/dist/deploy-engine-CuI_h_Ml.js.map +0 -1
- package/dist/iam-policy-targets-CMSQGQnm.js.map +0 -1
- package/dist/iam-role-provider-CyM-wxAp.js.map +0 -1
- package/dist/neptune-provider-BGVccWhg.js.map +0 -1
- package/dist/program-Cbxe8TgI.js.map +0 -1
- package/dist/provider-classes-DiWFkAOH.js.map +0 -1
- package/dist/rds-provider-D6_Rcnub.js.map +0 -1
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { r as getAwsClients } from "./aws-clients-CnmtbrxD.js";
|
|
2
|
-
import { A as displaySafe, F as safeMsg, M as isPasteableIdent, P as plainIdentOr, g as generateResourceNameWithFallback, h as generateResourceName, j as displayStackName, k as displayIdent, n as getLogger, v as getCurrentStackName, w as SECRET_REF_MAX_CODE_POINTS } from "./logger-
|
|
3
|
-
import { $ as compositeIdFormatMessage, A as isTerminalDeleteFailure, B as WITHHELD_AWS_COMMAND, C as refusalTypeShown,
|
|
2
|
+
import { A as displaySafe, F as safeMsg, M as isPasteableIdent, P as plainIdentOr, g as generateResourceNameWithFallback, h as generateResourceName, j as displayStackName, k as displayIdent, n as getLogger, v as getCurrentStackName, w as SECRET_REF_MAX_CODE_POINTS } from "./logger-Dvc7ddKe.js";
|
|
3
|
+
import { $ as compositeIdFormatMessage, $n as markRedactedCause, A as isTerminalDeleteFailure, B as WITHHELD_AWS_COMMAND, C as refusalTypeShown, D as ProtectionFlipRegistry, Dn as shellQuote, H as pasteableAwsCommand, Ht as AccountIdUnavailableError, J as isInterruptedWaitError, Jn as safeStringify, Kn as describeAwsFailure, L as userPoolProtectionSite, Ln as markNameCollision, Lt as withPasteableAwsProfile, M as observeThenDisableProtection, Mt as injectiveKey, N as protectionFlipKey, Nt as injectiveKeyPrefix, On as withheldTargetClause, P as rdsFamilyProtectionSite, Q as canonicalizeRoute53QueryName, Qn as markNonRetryable, Rn as markReplayMayCollide, Rt as ambientClientDefaults, S as quotedRemedyLogicalId, Sn as pasteableCommand, T as resolveExplicitPhysicalId, U as protectedReplacementAdvice, Un as isRetryableTransientError, V as isAwsCliLiteral, Vn as isAmbiguousOutcomeError, Vt as credentialFingerprint, W as renderDisableCommand, Wn as isTransientServerError, Wt as CdkdError, X as ElapsedBudgetRegistry, Y as startInterruptWatch, Yn as THROTTLING_ERROR_NAMES, Zn as isThrottlingError, _ as VALUE_NOT_SHOWN, a as onlySecretDerived, at as segmentAfterAnchor, b as isQuotableImportValue, bn as hasClauseBreak, bt as markAuxiliaryFailure, c as recordedPrincipalsRepair, ct as createMaskedRetryLogger, dt as maskerOrIdentity, er as wrapMaskedAwsError, et as compositeIdSeparatorRefusal, ft as withDerivedNameMasks, g as assertRegionMatch, h as RESOURCE_NOT_FOUND, ht as clearCreatedBeforeFailure, i as holdsSecretDerivedEntry, in as ProvisioningError, j as logGroupProtectionSite, k as deleteWithProtectionCompensation, lt as isSecretDerivedValue, nt as logicalIdShown, o as readPrincipalLists, on as ResourceUpdateNotSupportedError, ot as stateOrphanRecordRemedy, p as withRemovalDefaults, qn as isAwsAuthoredFailure, r as SECRET_DERIVED_READ_LIVE, rt as packCompositeId, st as createMaskedLogSinks, tt as compositeIdSkipResult, u as clearOnUpdateRemoval, ut as maskDeep, v as isPlainImportJson, w as remedyLogicalId, wn as plainOrDescribed, x as normalizeAwsTagsToCfn, xn as isInertUnquoted, xt as markCreatedBeforeFailure, y as isPlainImportValue, yn as commandHole, z as UNNAMEABLE_ID_CLAUSE, zt as ambientCredentialConfig } from "./iam-policy-targets-DSDSdxXz.js";
|
|
4
4
|
import { s as ambientRegion } from "./aws-client-defaults-D0q0z4dG.js";
|
|
5
|
-
import { $i as
|
|
6
|
-
import { n as collectInlinePolicyNamesManagedBySiblings, t as IAMRoleProvider } from "./iam-role-provider-
|
|
7
|
-
import { a as canonicalizeIpProtocolValue, i as resolveSecretDerivedPrincipals, n as runDestroyForStack, o as resolvedResourceTimeoutMs, r as isResolvableSecretPrincipalList, t as canonicalizeIpv4Cidr } from "./program-
|
|
8
|
-
import { RDSProvider } from "./rds-provider-
|
|
9
|
-
import { NeptuneProvider } from "./neptune-provider-
|
|
10
|
-
import { ASGProvider } from "./asg-provider-
|
|
5
|
+
import { $a as dynamicReferenceTokens, $i as withoutSilentDropProperties, $n as reEnableInstanceApiTermination, A as resolveDynamoDbDeleteBudgetClock, An as definedAttributes, B as getPriorAttempts, Bo as rewriteTemplateAssetReferences, Bs as decodeListingKey, Cn as DBPROXY_TAGS_WHAT, Ct as getStackRecords, D as beginDeleteWait, Da as canonicalLambdaFunctionName, Dn as refuseMalformedDesiredTags, E as DYNAMODB_DELETE_MIN_RESOURCE_TIMEOUT_MS, Ea as withRetry, En as readTagList, F as waitForIndexesSettled, Fo as stringifyValue, Fr as parseWebACLArn, Gn as withIndeterminateGuard, Gt as redactedDeleteAddressFields, I as ECR_AUTO_DELETE_IMAGES_TAG, Ja as markSameGenerationBag, Kn as isWaitAbandonedError, Kt as redactedDeleteAddressSkip, L as S3_AUTO_DELETE_OBJECTS_TAG, La as hasMaskableValues, Ln as getCurrentResourceSecrets, M as DELETE_INDEX_WAIT_PROCEED_NOTE, Mt as getCurrentProducerRegions, N as INDEX_SETTLE_POLL_INTERVAL_MS, O as compensateRemovedDeletionProtection, Oa as lambdaFunctionNameForMask, On as tagMapAsList, P as deleteTableWithIndexBusyRetry, Qn as reDisableInstanceApiTermination, R as hasCdkAutoDeleteTag, Ri as refuseMalformedResourcesForDestroy, Rr as passedParameterClassesOf, Sa as requireConfigString, Sn as acquireIdempotencyToken, T as DynamoDBGlobalTableProvider, Tn as planTagDiff, Tr as getAccountInfo, Us as canonicalizeRegion, Ut as REDACTED_DELETE_ADDRESS_SKIP_REASON, V as markRefusedBeforeApplying, Vn as unchangedBehindSecretReference, Wn as deleteSkipReason, Ws as derivePartitionAndUrlSuffix, Wt as isRedactedRecordedValue, Xn as isTerminationProtectionPropagationError, Ya as redactSecretsForState, Yn as ec2InstanceProtectionSite, Za as recoverMaskedOutput, Zi as findSilentDropProperties, Zn as observeThenDisableInstanceApiTermination, _a as configStringRefusal, _r as s3BucketArn, _t as getCurrentNestedStackContext, a as findNestedTemplateTreeDefect, ba as requireConfigArray, bn as reserveStackCreateToken, br as s3BucketRegionalDomainName, c as renderNestedTemplateTreeDefect, ca as WARM_THROUGHPUT_MEMBERS, da as toCfnInteger, dt as getNestedRevertRun, ec as describeFileReadFailure, fa as toFiniteNumber, ga as configIntegerRefusal, gr as isSettledInstanceState, ha as configBooleanRefusal, j as resolveDynamoDbDeleteBudgetMs, jn as stringifyIfAssigned, k as deleteBudgetKey, ka as sameLambdaFunctionAddress, kn as tagPlanWarning, la as coerceWarmThroughput$1, ma as coerceCfnInteger, mt as revertNestedChildFromJournal, nc as renderAssemblyPathEscape, o as isAbsoluteAssetPath, pa as coerceCfnBoolean, qn as markWaitAbandoned, rc as resolveAssemblyPath, ro as carriesSecretMask, s as listNestedTemplateRows, t as DeployEngine, tc as displayAssemblyPath, ua as isWarmThroughputDecrease, va as readConfigString, vi as refuseMalformedNestedChildOutputs, vn as earliestDefined, vr as s3BucketDomainName, vt as withNestedStackContext, wn as DBPROXY_TAG_OPTIONS, xa as requireConfigObject, xr as s3BucketWebsiteUrl, xt as awaitInFlightSibling, ya as replayWarn, yr as s3BucketDualStackDomainName, z as isTruthyCfnBoolean, zn as slowCcOperationTimeoutMs } from "./deploy-engine-D7204v7Z.js";
|
|
6
|
+
import { n as collectInlinePolicyNamesManagedBySiblings, t as IAMRoleProvider } from "./iam-role-provider-CCPaZ3U4.js";
|
|
7
|
+
import { a as canonicalizeIpProtocolValue, i as resolveSecretDerivedPrincipals, n as runDestroyForStack, o as resolvedResourceTimeoutMs, r as isResolvableSecretPrincipalList, t as canonicalizeIpv4Cidr } from "./program-B0sp_SHG.js";
|
|
8
|
+
import { RDSProvider } from "./rds-provider-DltlcDiQ.js";
|
|
9
|
+
import { NeptuneProvider } from "./neptune-provider-D1t9NgT-.js";
|
|
10
|
+
import { ASGProvider } from "./asg-provider-AVCcoXnQ.js";
|
|
11
11
|
import { createHash, randomUUID } from "node:crypto";
|
|
12
12
|
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, 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";
|
|
13
13
|
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, UpdateLoginProfileCommand } from "@aws-sdk/client-iam";
|
|
@@ -48,7 +48,7 @@ import { AppSyncClient, CreateApiKeyCommand, CreateDataSourceCommand, CreateGrap
|
|
|
48
48
|
import { ConcurrentModificationException, CrawlerRunningException, CreateConnectionCommand, CreateCrawlerCommand, CreateDatabaseCommand, CreateJobCommand, CreateSecurityConfigurationCommand, CreateTableCommand as CreateTableCommand$1, CreateTriggerCommand, CreateWorkflowCommand, DeleteConnectionCommand, DeleteCrawlerCommand, DeleteDatabaseCommand, DeleteJobCommand, DeleteSecurityConfigurationCommand, DeleteTableCommand as DeleteTableCommand$1, DeleteTriggerCommand, DeleteWorkflowCommand, EntityNotFoundException, GetConnectionCommand, GetCrawlerCommand, GetDatabaseCommand, GetJobCommand, GetSecurityConfigurationCommand, GetTableCommand, GetTagsCommand, GetTriggerCommand, GetWorkflowCommand, GlueClient, StartCrawlerScheduleCommand, StartTriggerCommand, StopCrawlerCommand, StopCrawlerScheduleCommand, StopTriggerCommand, TagResourceCommand as TagResourceCommand$18, UntagResourceCommand as UntagResourceCommand$18, UpdateConnectionCommand, UpdateCrawlerCommand, UpdateDatabaseCommand, UpdateJobCommand, UpdateTableCommand as UpdateTableCommand$1, UpdateTriggerCommand, UpdateWorkflowCommand } from "@aws-sdk/client-glue";
|
|
49
49
|
import { BudgetsClient, CreateBudgetCommand, CreateNotificationCommand, CreateSubscriberCommand, DeleteBudgetCommand, DeleteNotificationCommand, DeleteSubscriberCommand, DescribeBudgetCommand, DuplicateRecordException, NotFoundException as NotFoundException$5, TagResourceCommand as TagResourceCommand$19, UntagResourceCommand as UntagResourceCommand$19, UpdateBudgetCommand } from "@aws-sdk/client-budgets";
|
|
50
50
|
import { AddTagsToStreamCommand, CreateStreamCommand, DecreaseStreamRetentionPeriodCommand, DeleteStreamCommand, DeregisterStreamConsumerCommand, DescribeStreamCommand, DescribeStreamConsumerCommand, DescribeStreamSummaryCommand, DisableEnhancedMonitoringCommand, EnableEnhancedMonitoringCommand, IncreaseStreamRetentionPeriodCommand, KinesisClient, ListTagsForResourceCommand as ListTagsForResourceCommand$15, ListTagsForStreamCommand, RegisterStreamConsumerCommand, RemoveTagsFromStreamCommand, ResourceNotFoundException as ResourceNotFoundException$10, StartStreamEncryptionCommand, StopStreamEncryptionCommand, TagResourceCommand as TagResourceCommand$20, UntagResourceCommand as UntagResourceCommand$20, UpdateMaxRecordSizeCommand, UpdateShardCountCommand, UpdateStreamModeCommand } from "@aws-sdk/client-kinesis";
|
|
51
|
-
import { CreateScheduleCommand, DeleteScheduleCommand, GetScheduleCommand, ResourceNotFoundException as ResourceNotFoundException$11, SchedulerClient, UpdateScheduleCommand } from "@aws-sdk/client-scheduler";
|
|
51
|
+
import { CreateScheduleCommand, DeleteScheduleCommand, GetScheduleCommand, ListSchedulesCommand, ResourceNotFoundException as ResourceNotFoundException$11, SchedulerClient, UpdateScheduleCommand } from "@aws-sdk/client-scheduler";
|
|
52
52
|
import { CreatePipeCommand, DeletePipeCommand, DescribePipeCommand, NotFoundException as NotFoundException$6, PipesClient, TagResourceCommand as TagResourceCommand$21, UntagResourceCommand as UntagResourceCommand$21, UpdatePipeCommand } from "@aws-sdk/client-pipes";
|
|
53
53
|
import { AccessPointAlreadyExists, AccessPointNotFound, CreateAccessPointCommand, CreateFileSystemCommand, CreateMountTargetCommand, DeleteAccessPointCommand, DeleteFileSystemCommand, DeleteMountTargetCommand, DescribeAccessPointsCommand, DescribeBackupPolicyCommand, DescribeFileSystemPolicyCommand, DescribeFileSystemsCommand, DescribeLifecycleConfigurationCommand, DescribeMountTargetSecurityGroupsCommand, DescribeMountTargetsCommand, EFSClient, FileSystemAlreadyExists, FileSystemNotFound, ModifyMountTargetSecurityGroupsCommand, MountTargetNotFound, PutBackupPolicyCommand, PutFileSystemPolicyCommand, PutLifecycleConfigurationCommand, UpdateFileSystemCommand, UpdateFileSystemProtectionCommand } from "@aws-sdk/client-efs";
|
|
54
54
|
import { CreateFileSystemCommand as CreateFileSystemCommand$1, CreateFileSystemFromBackupCommand, DeleteFileSystemCommand as DeleteFileSystemCommand$1, DescribeFileSystemsCommand as DescribeFileSystemsCommand$1, FSxClient, FileSystemNotFound as FileSystemNotFound$1, TagResourceCommand as TagResourceCommand$22, UntagResourceCommand as UntagResourceCommand$22, UpdateFileSystemCommand as UpdateFileSystemCommand$1 } from "@aws-sdk/client-fsx";
|
|
@@ -138,6 +138,11 @@ var IAMPolicyProvider = class {
|
|
|
138
138
|
const { roles, groups, users } = targets;
|
|
139
139
|
if (!policyDocument) throw new ProvisioningError(`PolicyDocument is required for IAM policy ${logicalId}`, resourceType, logicalId);
|
|
140
140
|
if (!(roles && roles.length > 0 || groups && groups.length > 0 || users && users.length > 0)) throw new ProvisioningError(`At least one of Roles, Groups, or Users is required for IAM policy ${logicalId}`, resourceType, logicalId);
|
|
141
|
+
const attached = {
|
|
142
|
+
roles: [],
|
|
143
|
+
groups: [],
|
|
144
|
+
users: []
|
|
145
|
+
};
|
|
141
146
|
try {
|
|
142
147
|
const policyDoc = typeof policyDocument === "string" ? policyDocument : JSON.stringify(policyDocument);
|
|
143
148
|
if (roles) for (const roleName of roles) {
|
|
@@ -146,6 +151,7 @@ var IAMPolicyProvider = class {
|
|
|
146
151
|
PolicyName: policyName,
|
|
147
152
|
PolicyDocument: policyDoc
|
|
148
153
|
}));
|
|
154
|
+
attached.roles.push(roleName);
|
|
149
155
|
log.debug(`Attached inline policy ${v(policyName)} to role ${v(roleName)}`);
|
|
150
156
|
}
|
|
151
157
|
if (groups) for (const groupName of groups) {
|
|
@@ -154,6 +160,7 @@ var IAMPolicyProvider = class {
|
|
|
154
160
|
PolicyName: policyName,
|
|
155
161
|
PolicyDocument: policyDoc
|
|
156
162
|
}));
|
|
163
|
+
attached.groups.push(groupName);
|
|
157
164
|
log.debug(`Attached inline policy ${v(policyName)} to group ${v(groupName)}`);
|
|
158
165
|
}
|
|
159
166
|
if (users) for (const userName of users) {
|
|
@@ -162,6 +169,7 @@ var IAMPolicyProvider = class {
|
|
|
162
169
|
PolicyName: policyName,
|
|
163
170
|
PolicyDocument: policyDoc
|
|
164
171
|
}));
|
|
172
|
+
attached.users.push(userName);
|
|
165
173
|
log.debug(`Attached inline policy ${v(policyName)} to user ${v(userName)}`);
|
|
166
174
|
}
|
|
167
175
|
log.debug(`Successfully created IAM policy ${logicalId}: ${v(policyName)}`);
|
|
@@ -171,9 +179,59 @@ var IAMPolicyProvider = class {
|
|
|
171
179
|
};
|
|
172
180
|
} catch (error) {
|
|
173
181
|
const cause = error instanceof Error ? error : void 0;
|
|
174
|
-
|
|
182
|
+
await this.detachPartialPolicy(logicalId, policyName, attached, log, context?.maskSecrets);
|
|
183
|
+
const errorSinks = withDerivedNameMasks(this.logger, log, [
|
|
184
|
+
...roles ?? [],
|
|
185
|
+
...groups ?? [],
|
|
186
|
+
...users ?? []
|
|
187
|
+
].map((n) => [n, n]));
|
|
188
|
+
throw this.wrapMaskedError(errorSinks.mask, error, (text) => new ProvisioningError(`Failed to create IAM policy ${logicalId}: ${text}`, resourceType, logicalId, policyName, cause));
|
|
175
189
|
}
|
|
176
190
|
}
|
|
191
|
+
async detachPartialPolicy(logicalId, policyName, attached, sinks, maskSecrets) {
|
|
192
|
+
const aws = pasteableAwsCommand(maskSecrets);
|
|
193
|
+
const log = withDerivedNameMasks(this.logger, sinks, [
|
|
194
|
+
...attached.roles,
|
|
195
|
+
...attached.groups,
|
|
196
|
+
...attached.users
|
|
197
|
+
].map((n) => [n, n]));
|
|
198
|
+
const { value: v } = log;
|
|
199
|
+
const steps = [
|
|
200
|
+
...attached.roles.map((name) => ({
|
|
201
|
+
what: `role ${v(name)}`,
|
|
202
|
+
send: () => this.iamClient.send(new DeleteRolePolicyCommand({
|
|
203
|
+
RoleName: name,
|
|
204
|
+
PolicyName: policyName
|
|
205
|
+
})),
|
|
206
|
+
command: aws`aws iam delete-role-policy --role-name ${name} --policy-name ${policyName}`.render()
|
|
207
|
+
})),
|
|
208
|
+
...attached.groups.map((name) => ({
|
|
209
|
+
what: `group ${v(name)}`,
|
|
210
|
+
send: () => this.iamClient.send(new DeleteGroupPolicyCommand({
|
|
211
|
+
GroupName: name,
|
|
212
|
+
PolicyName: policyName
|
|
213
|
+
})),
|
|
214
|
+
command: aws`aws iam delete-group-policy --group-name ${name} --policy-name ${policyName}`.render()
|
|
215
|
+
})),
|
|
216
|
+
...attached.users.map((name) => ({
|
|
217
|
+
what: `user ${v(name)}`,
|
|
218
|
+
send: () => this.iamClient.send(new DeleteUserPolicyCommand({
|
|
219
|
+
UserName: name,
|
|
220
|
+
PolicyName: policyName
|
|
221
|
+
})),
|
|
222
|
+
command: aws`aws iam delete-user-policy --user-name ${name} --policy-name ${policyName}`.render()
|
|
223
|
+
}))
|
|
224
|
+
];
|
|
225
|
+
const failed = [];
|
|
226
|
+
for (const step of steps) try {
|
|
227
|
+
await step.send();
|
|
228
|
+
log.debug(`Detached inline policy ${v(policyName)} from ${step.what} after the create failed`);
|
|
229
|
+
} catch (error) {
|
|
230
|
+
if (error instanceof NoSuchEntityException) continue;
|
|
231
|
+
failed.push(`${step.what} (${log.mask(describeAwsFailure(error).detail)}): ${step.command}`);
|
|
232
|
+
}
|
|
233
|
+
if (failed.length > 0) log.warn(`Failed to detach the partially-created IAM policy ${logicalId} (${v(policyName)}) after its create failed; cdkd has no record of it, so it stays attached and granting until it is removed by hand: ${failed.join("; ")}`);
|
|
234
|
+
}
|
|
177
235
|
async update(logicalId, physicalId, resourceType, properties, previousProperties, context) {
|
|
178
236
|
const oldPolicyName = physicalId.includes(":") ? physicalId.split(":")[0] : physicalId;
|
|
179
237
|
const log = withDerivedNameMasks(this.logger, createMaskedLogSinks(this.logger, context?.maskSecrets), [[previousProperties["PolicyName"], oldPolicyName]]);
|
|
@@ -300,11 +358,11 @@ var IAMPolicyProvider = class {
|
|
|
300
358
|
let resolvedFromSecret = false;
|
|
301
359
|
let legacyRoleFromPhysicalId = !roles && !groups && !users && physicalId.includes(":") ? physicalId.split(":")[1] : void 0;
|
|
302
360
|
if (!policyName && policyNameRedacted) {
|
|
303
|
-
const skip = redactedDeleteAddressSkip(this.logger, logicalId, "IAM policy", ["PolicyName"]);
|
|
361
|
+
const skip = redactedDeleteAddressSkip(this.logger, logicalId, "IAM policy", ["PolicyName"], context);
|
|
304
362
|
if (skip) return skip;
|
|
305
363
|
}
|
|
306
364
|
if (!policyName) {
|
|
307
|
-
this.logger.warn(`Invalid physical ID format: ${physicalId}, and no PolicyName in the state record's properties — skipping deletion. No AWS call is issued, so the inline policy is LEFT ATTACHED to its roles / groups / users, UNLESS the role / group / user it is attached to is itself part of this stack (deleting that principal removes its inline policies, and then only the cdkd record is stale — clear it with
|
|
365
|
+
this.logger.warn(`Invalid physical ID format: ${physicalId}, and no PolicyName in the state record's properties — skipping deletion. No AWS call is issued, so the inline policy is LEFT ATTACHED to its roles / groups / users, UNLESS the role / group / user it is attached to is itself part of this stack (deleting that principal removes its inline policies, and then only the cdkd record is stale — clear it with ${stateOrphanRecordRemedy(context, logicalId)}). Otherwise repair the physicalId in state.json and re-run, or delete the inline policy by hand. ${DEPLOY_SKIP_CAVEAT$3}`);
|
|
308
366
|
return {
|
|
309
367
|
outcome: "skipped",
|
|
310
368
|
reason: POLICY_NAME_SKIP_REASON
|
|
@@ -338,7 +396,7 @@ var IAMPolicyProvider = class {
|
|
|
338
396
|
}
|
|
339
397
|
if (malformedKinds.length > 0 && !resolvedFromSecret) {
|
|
340
398
|
const plainKinds = malformedKinds.filter((k) => !secretDerivedKinds.includes(k));
|
|
341
|
-
const repair = secretDerivedKinds.length === 0 ? `Repair ${plainKinds.join(" / ")} in state.json to a list of role / group / user names and re-run, or delete the inline policy by hand.` : `The recorded ${secretDerivedKinds.join(" / ")} is secret-derived (cdkd keeps the dynamic reference or its mask in state), so do not write the name into state.json` + (resolutionAttempted ? "; cdkd could not resolve the reference (its region, access to it, or its value), so fix that and re-run, or" : `:`) + ` cdkd will keep skipping this record` + (plainKinds.length > 0 ? `, whatever is repaired in the recorded ${plainKinds.join(" / ")}` : "") +
|
|
399
|
+
const repair = secretDerivedKinds.length === 0 ? `Repair ${plainKinds.join(" / ")} in state.json to a list of role / group / user names and re-run, or delete the inline policy by hand.` : `The recorded ${secretDerivedKinds.join(" / ")} is secret-derived (cdkd keeps the dynamic reference or its mask in state), so do not write the name into state.json` + (resolutionAttempted ? "; cdkd could not resolve the reference (its region, access to it, or its value), so fix that and re-run, or" : `:`) + ` cdkd will keep skipping this record` + (plainKinds.length > 0 ? `, whatever is repaired in the recorded ${plainKinds.join(" / ")}` : "") + `. Remove the inline policy from its principals by hand (a principal this stack also deletes takes its inline policies with it), then drop this record with ${stateOrphanRecordRemedy(context, logicalId)}.`;
|
|
342
400
|
this.logger.warn(`The state record for IAM policy ${logicalId} holds ${malformedKinds.join(" / ")} that is not a list of IAM names — skipping deletion rather than guessing which principals it names. No AWS call is issued, so the inline policy is LEFT ATTACHED wherever it is. ${repair} ${DEPLOY_SKIP_CAVEAT$3}`);
|
|
343
401
|
return {
|
|
344
402
|
outcome: "skipped",
|
|
@@ -346,7 +404,7 @@ var IAMPolicyProvider = class {
|
|
|
346
404
|
};
|
|
347
405
|
}
|
|
348
406
|
if (!roles && !groups && !users && !legacyRoleFromPhysicalId) {
|
|
349
|
-
this.logger.warn(`No Roles, Groups or Users in the state record for IAM policy ${logicalId} (physicalId "${physicalId}"), skipping deletion — an inline policy exists only as an attachment, so with no principal named there is no delete to issue and the policy is LEFT ATTACHED wherever it is, UNLESS the role / group / user it is attached to is itself part of this stack (deleting that principal removes its inline policies, and then only the cdkd record is stale — clear it with
|
|
407
|
+
this.logger.warn(`No Roles, Groups or Users in the state record for IAM policy ${logicalId} (physicalId "${physicalId}"), skipping deletion — an inline policy exists only as an attachment, so with no principal named there is no delete to issue and the policy is LEFT ATTACHED wherever it is, UNLESS the role / group / user it is attached to is itself part of this stack (deleting that principal removes its inline policies, and then only the cdkd record is stale — clear it with ${stateOrphanRecordRemedy(context, logicalId)}). Otherwise restore Roles / Groups / Users in state.json and re-run, or delete the inline policy by hand. ${DEPLOY_SKIP_CAVEAT$3}`);
|
|
350
408
|
return {
|
|
351
409
|
outcome: "skipped",
|
|
352
410
|
reason: POLICY_NO_TARGET_SKIP_REASON
|
|
@@ -433,7 +491,7 @@ var IAMPolicyProvider = class {
|
|
|
433
491
|
}
|
|
434
492
|
}
|
|
435
493
|
if (secretPrincipalLacksGrant) {
|
|
436
|
-
this.logger.warn(safeMsg`IAM policy ${logicalId}: a principal the secret's CURRENT value names does not hold this inline policy. The value may have rotated since the policy was attached, so a principal only the OLD value named may still hold it; or an earlier cdkd run already removed it there, or that principal was deleted first. The record is KEPT rather than read as deleted: delete the inline policy from any old principal by hand (the principals the current value names are done), then drop this record with 'cdkd orphan <constructPath>', or, with no CDK app,
|
|
494
|
+
this.logger.warn(safeMsg`IAM policy ${logicalId}: a principal the secret's CURRENT value names does not hold this inline policy. The value may have rotated since the policy was attached, so a principal only the OLD value named may still hold it; or an earlier cdkd run already removed it there, or that principal was deleted first. The record is KEPT rather than read as deleted: delete the inline policy from any old principal by hand (the principals the current value names are done), then drop this record with 'cdkd orphan <constructPath>', or, with no CDK app, ${stateOrphanRecordRemedy(context, logicalId)}.`);
|
|
437
495
|
return {
|
|
438
496
|
outcome: "skipped",
|
|
439
497
|
reason: POLICY_SECRET_PRINCIPAL_LACKS_GRANT_SKIP_REASON
|
|
@@ -544,6 +602,7 @@ var IAMManagedPolicyProvider = class {
|
|
|
544
602
|
const principals = principalsOf(properties);
|
|
545
603
|
if ("malformed" in principals) throw new ProvisioningError(`${principals.malformed.join(" / ")} of IAM managed policy ${logicalId} is not a list of IAM names — no managed policy was created or attached`, resourceType, logicalId);
|
|
546
604
|
const policyDoc = typeof policyDocument === "string" ? policyDocument : JSON.stringify(policyDocument);
|
|
605
|
+
let leftBehindArn;
|
|
547
606
|
try {
|
|
548
607
|
const createParams = {
|
|
549
608
|
PolicyName: policyName,
|
|
@@ -554,6 +613,7 @@ var IAMManagedPolicyProvider = class {
|
|
|
554
613
|
if (tags.length > 0) createParams.Tags = tags;
|
|
555
614
|
const policyArn = (await this.iamClient.send(new CreatePolicyCommand(createParams))).Policy?.Arn;
|
|
556
615
|
if (!policyArn) throw new ProvisioningError(`CreatePolicy succeeded but no Arn returned for ${logicalId}`, resourceType, logicalId, policyName);
|
|
616
|
+
leftBehindArn = policyArn;
|
|
557
617
|
log.debug(`Created IAM managed policy: ${v(policyArn)}`);
|
|
558
618
|
try {
|
|
559
619
|
await this.attachToPrincipals(policyArn, principals.lists.Groups, principals.lists.Roles, principals.lists.Users, log);
|
|
@@ -562,6 +622,7 @@ var IAMManagedPolicyProvider = class {
|
|
|
562
622
|
await this.detachAllPrincipals(policyArn);
|
|
563
623
|
await this.deleteAllNonDefaultVersions(policyArn);
|
|
564
624
|
await this.iamClient.send(new DeletePolicyCommand({ PolicyArn: policyArn }));
|
|
625
|
+
leftBehindArn = void 0;
|
|
565
626
|
log.debug(`Cleaned up partially-created managed policy ${logicalId} (${v(policyArn)}) after attachment failure`);
|
|
566
627
|
} catch (cleanupError) {
|
|
567
628
|
const aws = pasteableAwsCommand(log.mask);
|
|
@@ -574,9 +635,13 @@ var IAMManagedPolicyProvider = class {
|
|
|
574
635
|
attributes: { PolicyArn: policyArn }
|
|
575
636
|
};
|
|
576
637
|
} catch (error) {
|
|
577
|
-
|
|
638
|
+
const markLeftBehind = (e) => leftBehindArn !== void 0 ? markCreatedBeforeFailure(e, logicalId, resourceType, leftBehindArn) : e;
|
|
639
|
+
if (error instanceof CdkdError) {
|
|
640
|
+
markLeftBehind(error);
|
|
641
|
+
throw error;
|
|
642
|
+
}
|
|
578
643
|
const cause = error instanceof Error ? error : void 0;
|
|
579
|
-
throw this.wrapMaskedError(log.mask, error, (text) => new ProvisioningError(`Failed to create IAM managed policy ${logicalId}: ${text}`, resourceType, logicalId, policyName, cause));
|
|
644
|
+
throw this.wrapMaskedError(log.mask, error, (text) => markLeftBehind(new ProvisioningError(`Failed to create IAM managed policy ${logicalId}: ${text}`, resourceType, logicalId, policyName, cause)));
|
|
580
645
|
}
|
|
581
646
|
}
|
|
582
647
|
async update(logicalId, physicalId, resourceType, properties, previousProperties, context) {
|
|
@@ -1070,11 +1135,13 @@ var IAMInstanceProfileProvider = class {
|
|
|
1070
1135
|
const principals = readPrincipalLists({ Roles: properties["Roles"] });
|
|
1071
1136
|
if ("malformed" in principals) throw new ProvisioningError(`Roles of IAM instance profile ${logicalId} is not a list of IAM role names — no instance profile was created`, resourceType, logicalId);
|
|
1072
1137
|
const roles = principals.lists.Roles;
|
|
1138
|
+
let leftBehind = false;
|
|
1073
1139
|
try {
|
|
1074
1140
|
const response = await this.iamClient.send(new CreateInstanceProfileCommand({
|
|
1075
1141
|
InstanceProfileName: instanceProfileName,
|
|
1076
1142
|
Path: path
|
|
1077
1143
|
}));
|
|
1144
|
+
leftBehind = true;
|
|
1078
1145
|
log.debug(`Created IAM instance profile: ${v(instanceProfileName)}`);
|
|
1079
1146
|
const attachedRoles = [];
|
|
1080
1147
|
try {
|
|
@@ -1097,6 +1164,7 @@ var IAMInstanceProfileProvider = class {
|
|
|
1097
1164
|
if (!(err instanceof NoSuchEntityException)) throw err;
|
|
1098
1165
|
}
|
|
1099
1166
|
await this.iamClient.send(new DeleteInstanceProfileCommand({ InstanceProfileName: instanceProfileName }));
|
|
1167
|
+
leftBehind = false;
|
|
1100
1168
|
log.debug(`Cleaned up partially-created IAM instance profile ${logicalId} (${v(instanceProfileName)}) after wiring failure`);
|
|
1101
1169
|
} catch (cleanupError) {
|
|
1102
1170
|
const aws = pasteableAwsCommand(log.mask);
|
|
@@ -1111,7 +1179,9 @@ var IAMInstanceProfileProvider = class {
|
|
|
1111
1179
|
};
|
|
1112
1180
|
} catch (error) {
|
|
1113
1181
|
const cause = error instanceof Error ? error : void 0;
|
|
1114
|
-
|
|
1182
|
+
const thrown = this.wrapMaskedError(log.mask, error, (text) => new ProvisioningError(`Failed to create IAM instance profile ${logicalId}: ${text}`, resourceType, logicalId, instanceProfileName, cause));
|
|
1183
|
+
if (leftBehind) markCreatedBeforeFailure(thrown, logicalId, resourceType, instanceProfileName);
|
|
1184
|
+
throw thrown;
|
|
1115
1185
|
}
|
|
1116
1186
|
}
|
|
1117
1187
|
async update(logicalId, physicalId, resourceType, properties, previousProperties, context) {
|
|
@@ -1277,16 +1347,19 @@ var IAMAccessKeyProvider = class {
|
|
|
1277
1347
|
const aws = pasteableAwsCommand(log.mask);
|
|
1278
1348
|
const attemptStartMs = Date.now() - CREATE_DATE_SKEW_MARGIN_MS;
|
|
1279
1349
|
const baseline = await this.tryListAccessKeyIds(userName, logicalId, log);
|
|
1350
|
+
let leftBehindKeyId;
|
|
1280
1351
|
try {
|
|
1281
1352
|
const response = await this.iamClient.send(new CreateAccessKeyCommand({ UserName: userName }));
|
|
1282
1353
|
const accessKeyId = response.AccessKey?.AccessKeyId;
|
|
1283
1354
|
const secretAccessKey = response.AccessKey?.SecretAccessKey;
|
|
1355
|
+
leftBehindKeyId = accessKeyId;
|
|
1284
1356
|
if (!accessKeyId || !secretAccessKey) {
|
|
1285
1357
|
if (accessKeyId) try {
|
|
1286
1358
|
await this.iamClient.send(new DeleteAccessKeyCommand({
|
|
1287
1359
|
UserName: userName,
|
|
1288
1360
|
AccessKeyId: accessKeyId
|
|
1289
1361
|
}));
|
|
1362
|
+
leftBehindKeyId = void 0;
|
|
1290
1363
|
} catch (cleanupError) {
|
|
1291
1364
|
log.warn(`Failed to clean up IAM access key ${logicalId} (${v(accessKeyId)}) minted by a partial CreateAccessKey response: ${v(describeAwsFailure(cleanupError).detail)}. Manual deletion may be required: ${aws`aws iam delete-access-key --user-name ${userName} --access-key-id ${accessKeyId}`.render()}`);
|
|
1292
1365
|
}
|
|
@@ -1304,6 +1377,7 @@ var IAMAccessKeyProvider = class {
|
|
|
1304
1377
|
UserName: userName,
|
|
1305
1378
|
AccessKeyId: accessKeyId
|
|
1306
1379
|
}));
|
|
1380
|
+
leftBehindKeyId = void 0;
|
|
1307
1381
|
log.debug(`Cleaned up partially-created IAM access key ${logicalId} (${v(accessKeyId)}) after status wiring failure`);
|
|
1308
1382
|
} catch (cleanupError) {
|
|
1309
1383
|
log.warn(`Failed to clean up partially-created IAM access key ${logicalId} (${v(accessKeyId)}): ${v(describeAwsFailure(cleanupError).detail)}. Manual deletion may be required before the next deploy: ${aws`aws iam delete-access-key --user-name ${userName} --access-key-id ${accessKeyId}`.render()}`);
|
|
@@ -1320,9 +1394,12 @@ var IAMAccessKeyProvider = class {
|
|
|
1320
1394
|
}
|
|
1321
1395
|
};
|
|
1322
1396
|
} catch (error) {
|
|
1323
|
-
await this.deleteOrphanFromFailedAttempt(userName, logicalId, baseline, attemptStartMs, log);
|
|
1397
|
+
const reconciled = await this.deleteOrphanFromFailedAttempt(userName, logicalId, baseline, attemptStartMs, log);
|
|
1398
|
+
if (leftBehindKeyId !== void 0 && reconciled.has(leftBehindKeyId)) leftBehindKeyId = void 0;
|
|
1324
1399
|
const cause = error instanceof Error ? error : void 0;
|
|
1325
|
-
|
|
1400
|
+
const thrown = this.wrapMaskedError(log.mask, error, (text) => new ProvisioningError(`Failed to create IAM access key ${logicalId}: ${text}`, resourceType, logicalId, void 0, cause));
|
|
1401
|
+
if (leftBehindKeyId !== void 0) markCreatedBeforeFailure(thrown, logicalId, resourceType, leftBehindKeyId);
|
|
1402
|
+
throw thrown;
|
|
1326
1403
|
}
|
|
1327
1404
|
}
|
|
1328
1405
|
async withUserCreateLock(userName, fn) {
|
|
@@ -1342,9 +1419,10 @@ var IAMAccessKeyProvider = class {
|
|
|
1342
1419
|
async deleteOrphanFromFailedAttempt(userName, logicalId, baseline, attemptStartMs, log) {
|
|
1343
1420
|
const { value: v } = log;
|
|
1344
1421
|
const aws = pasteableAwsCommand(log.mask);
|
|
1345
|
-
|
|
1422
|
+
const deleted = /* @__PURE__ */ new Set();
|
|
1423
|
+
if (baseline === void 0) return deleted;
|
|
1346
1424
|
const current = await this.tryListAccessKeyMetadata(userName, logicalId, log);
|
|
1347
|
-
if (!current) return;
|
|
1425
|
+
if (!current) return deleted;
|
|
1348
1426
|
for (const key of current) {
|
|
1349
1427
|
const accessKeyId = key.accessKeyId;
|
|
1350
1428
|
if (baseline.has(accessKeyId) || this.accessKeyIdsCreatedByThisProcess.has(accessKeyId)) continue;
|
|
@@ -1358,10 +1436,12 @@ var IAMAccessKeyProvider = class {
|
|
|
1358
1436
|
UserName: userName,
|
|
1359
1437
|
AccessKeyId: accessKeyId
|
|
1360
1438
|
}));
|
|
1439
|
+
deleted.add(accessKeyId);
|
|
1361
1440
|
} catch (error) {
|
|
1362
1441
|
log.warn(`Failed to delete the orphaned IAM access key ${v(accessKeyId)} for user ${v(userName)}: ${v(describeAwsFailure(error).detail)}. Manual deletion may be required: ${aws`aws iam delete-access-key --user-name ${userName} --access-key-id ${accessKeyId}`.render()}`);
|
|
1363
1442
|
}
|
|
1364
1443
|
}
|
|
1444
|
+
return deleted;
|
|
1365
1445
|
}
|
|
1366
1446
|
async tryListAccessKeyIds(userName, logicalId, log) {
|
|
1367
1447
|
const metadata = await this.tryListAccessKeyMetadata(userName, logicalId, log);
|
|
@@ -1615,11 +1695,13 @@ var IAMUserGroupProvider = class {
|
|
|
1615
1695
|
const userName = generateResourceNameWithFallback(properties["UserName"], logicalId, { maxLength: USER_NAME_MAX_LENGTH });
|
|
1616
1696
|
const groups = readPrincipalLists({ Groups: properties["Groups"] });
|
|
1617
1697
|
if ("malformed" in groups) throw new ProvisioningError(`Groups of IAM user ${logicalId} is not a list of IAM group names — no user was created`, resourceType, logicalId);
|
|
1698
|
+
let leftBehind = false;
|
|
1618
1699
|
try {
|
|
1619
1700
|
const createParams = { UserName: userName };
|
|
1620
1701
|
if (properties["Path"]) createParams.Path = properties["Path"];
|
|
1621
1702
|
if (properties["Tags"] !== void 0 && properties["Tags"] !== null) createParams.Tags = desiredTags;
|
|
1622
1703
|
const response = await this.iamClient.send(new CreateUserCommand(createParams));
|
|
1704
|
+
leftBehind = true;
|
|
1623
1705
|
try {
|
|
1624
1706
|
const permissionsBoundary = properties["PermissionsBoundary"];
|
|
1625
1707
|
if (permissionsBoundary) {
|
|
@@ -1680,6 +1762,7 @@ var IAMUserGroupProvider = class {
|
|
|
1680
1762
|
if (!(err instanceof NoSuchEntityException)) throw err;
|
|
1681
1763
|
}
|
|
1682
1764
|
await this.iamClient.send(new DeleteUserCommand({ UserName: userName }));
|
|
1765
|
+
leftBehind = false;
|
|
1683
1766
|
log.debug(`Cleaned up partially-created IAM user ${logicalId} (${v(userName)}) after wiring failure`);
|
|
1684
1767
|
} catch (cleanupError) {
|
|
1685
1768
|
const aws = pasteableAwsCommand(log.mask);
|
|
@@ -1694,7 +1777,9 @@ var IAMUserGroupProvider = class {
|
|
|
1694
1777
|
};
|
|
1695
1778
|
} catch (error) {
|
|
1696
1779
|
const cause = error instanceof Error ? error : void 0;
|
|
1697
|
-
|
|
1780
|
+
const thrown = this.wrapMaskedError(log.mask, error, (text) => new ProvisioningError(`Failed to create IAM user ${logicalId}: ${text}`, resourceType, logicalId, userName, cause));
|
|
1781
|
+
if (leftBehind) markCreatedBeforeFailure(thrown, logicalId, resourceType, userName);
|
|
1782
|
+
throw thrown;
|
|
1698
1783
|
}
|
|
1699
1784
|
}
|
|
1700
1785
|
async updateUser(logicalId, physicalId, resourceType, properties, previousProperties, log, claimed) {
|
|
@@ -1989,10 +2074,12 @@ var IAMUserGroupProvider = class {
|
|
|
1989
2074
|
const { value: v } = log;
|
|
1990
2075
|
log.debug(`Creating IAM group ${logicalId}`);
|
|
1991
2076
|
const groupName = generateResourceNameWithFallback(properties["GroupName"], logicalId, { maxLength: GROUP_NAME_MAX_LENGTH });
|
|
2077
|
+
let leftBehind = false;
|
|
1992
2078
|
try {
|
|
1993
2079
|
const createParams = { GroupName: groupName };
|
|
1994
2080
|
if (properties["Path"]) createParams.Path = properties["Path"];
|
|
1995
2081
|
const response = await this.iamClient.send(new CreateGroupCommand(createParams));
|
|
2082
|
+
leftBehind = true;
|
|
1996
2083
|
try {
|
|
1997
2084
|
const managedPolicyArns = properties["ManagedPolicyArns"];
|
|
1998
2085
|
if (managedPolicyArns && Array.isArray(managedPolicyArns)) for (const policyArn of managedPolicyArns) {
|
|
@@ -2017,6 +2104,7 @@ var IAMUserGroupProvider = class {
|
|
|
2017
2104
|
await this.detachAllGroupPolicies(groupName, log);
|
|
2018
2105
|
await this.deleteAllGroupInlinePolicies(groupName, log);
|
|
2019
2106
|
await this.iamClient.send(new DeleteGroupCommand({ GroupName: groupName }));
|
|
2107
|
+
leftBehind = false;
|
|
2020
2108
|
log.debug(`Cleaned up partially-created IAM group ${logicalId} (${v(groupName)}) after wiring failure`);
|
|
2021
2109
|
} catch (cleanupError) {
|
|
2022
2110
|
const aws = pasteableAwsCommand(log.mask);
|
|
@@ -2031,7 +2119,9 @@ var IAMUserGroupProvider = class {
|
|
|
2031
2119
|
};
|
|
2032
2120
|
} catch (error) {
|
|
2033
2121
|
const cause = error instanceof Error ? error : void 0;
|
|
2034
|
-
|
|
2122
|
+
const thrown = this.wrapMaskedError(log.mask, error, (text) => new ProvisioningError(`Failed to create IAM group ${logicalId}: ${text}`, resourceType, logicalId, groupName, cause));
|
|
2123
|
+
if (leftBehind) markCreatedBeforeFailure(thrown, logicalId, resourceType, groupName);
|
|
2124
|
+
throw thrown;
|
|
2035
2125
|
}
|
|
2036
2126
|
}
|
|
2037
2127
|
async updateGroup(logicalId, physicalId, resourceType, properties, previousProperties, log, claimed) {
|
|
@@ -2258,7 +2348,7 @@ var IAMUserGroupProvider = class {
|
|
|
2258
2348
|
async deleteUserToGroupAddition(logicalId, physicalId, resourceType, properties, context) {
|
|
2259
2349
|
this.logger.debug(`Deleting IAM UserToGroupAddition ${logicalId}`);
|
|
2260
2350
|
if (!properties) {
|
|
2261
|
-
this.logger.warn(`No properties for UserToGroupAddition ${logicalId}, skipping deletion — GroupName and Users are both required to call RemoveUserFromGroup, so no AWS call is issued and the group memberships are LEFT IN PLACE, UNLESS the group or the users are themselves part of this stack (their own deletes remove exactly these memberships, and then only the cdkd record is stale — clear it with
|
|
2351
|
+
this.logger.warn(`No properties for UserToGroupAddition ${logicalId}, skipping deletion — GroupName and Users are both required to call RemoveUserFromGroup, so no AWS call is issued and the group memberships are LEFT IN PLACE, UNLESS the group or the users are themselves part of this stack (their own deletes remove exactly these memberships, and then only the cdkd record is stale — clear it with ${stateOrphanRecordRemedy(context, logicalId)}). Otherwise restore the record's properties in state.json and re-run, or remove the users from the group by hand. ${DEPLOY_SKIP_CAVEAT$2}`);
|
|
2262
2352
|
return {
|
|
2263
2353
|
outcome: "skipped",
|
|
2264
2354
|
reason: MEMBERSHIP_NO_PROPERTIES_SKIP_REASON
|
|
@@ -2267,13 +2357,13 @@ var IAMUserGroupProvider = class {
|
|
|
2267
2357
|
const groupName = properties["GroupName"];
|
|
2268
2358
|
const recordedUsers = properties["Users"];
|
|
2269
2359
|
if (!groupName || !recordedUsers) {
|
|
2270
|
-
this.logger.warn(`Missing GroupName or Users for ${logicalId}, skipping deletion — both are required to call RemoveUserFromGroup, so no AWS call is issued and the group memberships are LEFT IN PLACE, UNLESS the group or the users are themselves part of this stack (their own deletes remove exactly these memberships, and then only the cdkd record is stale — clear it with
|
|
2360
|
+
this.logger.warn(`Missing GroupName or Users for ${logicalId}, skipping deletion — both are required to call RemoveUserFromGroup, so no AWS call is issued and the group memberships are LEFT IN PLACE, UNLESS the group or the users are themselves part of this stack (their own deletes remove exactly these memberships, and then only the cdkd record is stale — clear it with ${stateOrphanRecordRemedy(context, logicalId)}). Otherwise restore them in state.json and re-run, or remove the users from the group by hand. ${DEPLOY_SKIP_CAVEAT$2}`);
|
|
2271
2361
|
return {
|
|
2272
2362
|
outcome: "skipped",
|
|
2273
2363
|
reason: MEMBERSHIP_MISSING_FIELDS_SKIP_REASON
|
|
2274
2364
|
};
|
|
2275
2365
|
}
|
|
2276
|
-
const redactedGroup = redactedDeleteAddressSkip(this.logger, logicalId, "UserToGroupAddition", redactedDeleteAddressFields({ GroupName: properties["GroupName"] }));
|
|
2366
|
+
const redactedGroup = redactedDeleteAddressSkip(this.logger, logicalId, "UserToGroupAddition", redactedDeleteAddressFields({ GroupName: properties["GroupName"] }), context);
|
|
2277
2367
|
if (redactedGroup) return redactedGroup;
|
|
2278
2368
|
const read = readPrincipalLists({ Users: properties["Users"] });
|
|
2279
2369
|
let users = "malformed" in read ? void 0 : read.lists.Users;
|
|
@@ -2296,8 +2386,8 @@ var IAMUserGroupProvider = class {
|
|
|
2296
2386
|
}
|
|
2297
2387
|
}
|
|
2298
2388
|
if ("malformed" in read && users === void 0) {
|
|
2299
|
-
const repair = read.secretDerived.length > 0 ? "The recorded Users is secret-derived (cdkd keeps the dynamic reference or its mask in state), so do not write the name into state.json" + (resolutionAttempted ? "; cdkd could not resolve the reference (its region, access to it, or its value), so fix that and re-run, or" : ":") +
|
|
2300
|
-
this.logger.warn(safeMsg`The state record for UserToGroupAddition ${logicalId} holds a Users that is not a list of IAM user names — skipping deletion rather than guessing which users it names. No AWS call is issued, so the group memberships are LEFT IN PLACE, UNLESS the group or the users are themselves part of this stack (their own deletes remove exactly these memberships, and then only the cdkd record is stale — clear it with
|
|
2389
|
+
const repair = read.secretDerived.length > 0 ? "The recorded Users is secret-derived (cdkd keeps the dynamic reference or its mask in state), so do not write the name into state.json" + (resolutionAttempted ? "; cdkd could not resolve the reference (its region, access to it, or its value), so fix that and re-run, or" : ":") + ` cdkd will keep skipping this record. Remove the users from the group by hand, then drop this record with ${stateOrphanRecordRemedy(context, logicalId)}.` : "Repair the recorded Users in state.json to a list of user names and re-run, or remove the users from the group by hand.";
|
|
2390
|
+
this.logger.warn(safeMsg`The state record for UserToGroupAddition ${logicalId} holds a Users that is not a list of IAM user names — skipping deletion rather than guessing which users it names. No AWS call is issued, so the group memberships are LEFT IN PLACE, UNLESS the group or the users are themselves part of this stack (their own deletes remove exactly these memberships, and then only the cdkd record is stale — clear it with ${stateOrphanRecordRemedy(context, logicalId)}). ${repair} ${DEPLOY_SKIP_CAVEAT$2}`);
|
|
2301
2391
|
return {
|
|
2302
2392
|
outcome: "skipped",
|
|
2303
2393
|
reason: MEMBERSHIP_MALFORMED_USERS_SKIP_REASON
|
|
@@ -2333,7 +2423,7 @@ var IAMUserGroupProvider = class {
|
|
|
2333
2423
|
}
|
|
2334
2424
|
}
|
|
2335
2425
|
if (secretUserNotMember) {
|
|
2336
|
-
this.logger.warn(safeMsg`UserToGroupAddition ${logicalId}: a user the secret's CURRENT value names is not in the group. The value may have rotated since the membership was added, so a user only the OLD value named may still be a member; or an earlier cdkd run already removed it, or that user was deleted first. The record is KEPT rather than read as deleted: remove any old user from the group by hand (the users the current value names are done), then drop this record with 'cdkd orphan <constructPath>', or, with no CDK app,
|
|
2426
|
+
this.logger.warn(safeMsg`UserToGroupAddition ${logicalId}: a user the secret's CURRENT value names is not in the group. The value may have rotated since the membership was added, so a user only the OLD value named may still be a member; or an earlier cdkd run already removed it, or that user was deleted first. The record is KEPT rather than read as deleted: remove any old user from the group by hand (the users the current value names are done), then drop this record with 'cdkd orphan <constructPath>', or, with no CDK app, ${stateOrphanRecordRemedy(context, logicalId)}.`);
|
|
2337
2427
|
return {
|
|
2338
2428
|
outcome: "skipped",
|
|
2339
2429
|
reason: MEMBERSHIP_SECRET_USER_NOT_MEMBER_SKIP_REASON
|
|
@@ -2510,13 +2600,14 @@ var IAMUserGroupProvider = class {
|
|
|
2510
2600
|
|
|
2511
2601
|
//#endregion
|
|
2512
2602
|
//#region src/provisioning/providers/s3-bucket-provider.ts
|
|
2513
|
-
function manualBucketDeletionClause(bucketName, maskSecrets) {
|
|
2603
|
+
function manualBucketDeletionClause(bucketName, maskSecrets, journaled) {
|
|
2514
2604
|
const command = renderDisableCommand({
|
|
2515
2605
|
before: "aws s3api delete-bucket --bucket",
|
|
2516
2606
|
identifier: bucketName,
|
|
2517
2607
|
maskSecrets
|
|
2518
2608
|
});
|
|
2519
|
-
|
|
2609
|
+
const lead = journaled ? "On a first-time create the failed deploy's rollback journal records the bucket for `cdkd rollback --revert-failed`; otherwise delete it yourself before the next deploy" : "Manual deletion may be required before the next deploy";
|
|
2610
|
+
return command ? `${lead}: ${command}` : `${lead}, via the console: the bucket name 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.`;
|
|
2520
2611
|
}
|
|
2521
2612
|
function configItemId(item) {
|
|
2522
2613
|
if (!isPlainObject$2(item)) return void 0;
|
|
@@ -4114,7 +4205,7 @@ var S3BucketProvider = class S3BucketProvider {
|
|
|
4114
4205
|
};
|
|
4115
4206
|
}
|
|
4116
4207
|
}
|
|
4117
|
-
async assertStateBucketRegion(operation, logicalId, resourceType, physicalId, expectedRegion) {
|
|
4208
|
+
async assertStateBucketRegion(operation, logicalId, resourceType, physicalId, expectedRegion, context) {
|
|
4118
4209
|
const wantRegion = canonicalizeRegion(expectedRegion);
|
|
4119
4210
|
const probe = await this.probeBucketRegion(physicalId);
|
|
4120
4211
|
if (probe.kind === "absent") return;
|
|
@@ -4125,7 +4216,7 @@ var S3BucketProvider = class S3BucketProvider {
|
|
|
4125
4216
|
}
|
|
4126
4217
|
if (probe.region === wantRegion) return;
|
|
4127
4218
|
const consequence = operation === "update" ? `Applying this stack's bucket configuration would reconfigure a bucket in ${probe.region} that this stack does not own the definition of.` : `Deleting it would destroy a bucket in ${probe.region} that this stack's region does not contain, and that deletion cannot be undone.`;
|
|
4128
|
-
const remedy = operation === "update" ? `Confirm which bucket you mean, then either rerun this stack against ${probe.region}, or — if the recorded id is stale — drop this bucket's record with 'cdkd orphan <StackPath>/<Path/To/Bucket>', which removes only that record (and rewrites the references to it) without touching any AWS resource, then deploy again to create the bucket in this stack's region — first giving it a BucketName unique to that region if the template fixes this one, since S3 names are global.` : `Confirm which bucket you mean. If ${displaySafe(physicalId)} is genuinely yours to delete, delete it deliberately in ${probe.region}; if this record is simply stale, drop it
|
|
4219
|
+
const remedy = operation === "update" ? `Confirm which bucket you mean, then either rerun this stack against ${probe.region}, or — if the recorded id is stale — drop this bucket's record with 'cdkd orphan <StackPath>/<Path/To/Bucket>', which removes only that record (and rewrites the references to it) without touching any AWS resource, then deploy again to create the bucket in this stack's region — first giving it a BucketName unique to that region if the template fixes this one, since S3 names are global.` : `Confirm which bucket you mean. If ${displaySafe(physicalId)} is genuinely yours to delete, delete it deliberately in ${probe.region}; if this record is simply stale, drop it without touching any AWS resource (<region> is this stack's region, not the bucket's) with ${stateOrphanRecordRemedy(context, logicalId)}.`;
|
|
4129
4220
|
throw markNonRetryable(new ProvisioningError(`Refusing to ${operation} S3 bucket ${this.shown(physicalId)} for ${displaySafe(logicalId)} (${resourceType}): the bucket lives in ${probe.region}, while this stack's state is for ${wantRegion}. S3 bucket names are globally unique, so a state record can name a bucket in another region — records written before the create-path region guard can carry one. ${consequence} ${remedy}`, resourceType, logicalId, physicalId));
|
|
4130
4221
|
}
|
|
4131
4222
|
announceUnverifiedBucketIdentity(operation, logicalId, physicalId, cause) {
|
|
@@ -4145,6 +4236,7 @@ var S3BucketProvider = class S3BucketProvider {
|
|
|
4145
4236
|
lowercase: true,
|
|
4146
4237
|
allowedPattern: /[^a-z0-9.-]/g
|
|
4147
4238
|
});
|
|
4239
|
+
let bucketLeftBehind = false;
|
|
4148
4240
|
try {
|
|
4149
4241
|
const createParams = { Bucket: bucketName };
|
|
4150
4242
|
const region = await this.getRegion();
|
|
@@ -4156,6 +4248,7 @@ var S3BucketProvider = class S3BucketProvider {
|
|
|
4156
4248
|
try {
|
|
4157
4249
|
await this.s3Client.send(new CreateBucketCommand(createParams));
|
|
4158
4250
|
createdNewBucket = preflight.kind === "absent";
|
|
4251
|
+
bucketLeftBehind = createdNewBucket;
|
|
4159
4252
|
if (preflight.kind === "region" && preflight.region !== "us-east-1") this.refuseForeignRegionAdopt(logicalId, resourceType, bucketName, "us-east-1", preflight.region);
|
|
4160
4253
|
if (preflight.kind === "region") 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.`);
|
|
4161
4254
|
this.logger.debug(`Created S3 bucket: ${this.shown(bucketName)}`);
|
|
@@ -4176,14 +4269,15 @@ var S3BucketProvider = class S3BucketProvider {
|
|
|
4176
4269
|
} catch (innerError) {
|
|
4177
4270
|
if (createdNewBucket) try {
|
|
4178
4271
|
await this.s3Client.send(new DeleteBucketCommand({ Bucket: bucketName }));
|
|
4272
|
+
bucketLeftBehind = false;
|
|
4179
4273
|
this.logger.debug(`Cleaned up partially-created S3 bucket ${displaySafe(logicalId)} (${this.shown(bucketName)}) after wiring failure`);
|
|
4180
4274
|
} catch (cleanupError) {
|
|
4181
4275
|
this.logger.debug(`DeleteBucket cleanup failed for S3 bucket ${displaySafe(logicalId)} (${this.shown(bucketName)}): ${describeAwsFailure(cleanupError).detail}`);
|
|
4182
|
-
this.logger.warn(safeMsg`Failed to clean up partially-created S3 bucket ${displaySafe(logicalId)} (${this.shown(bucketName)}) ` + safeMsg`(${cleanupError instanceof Error ? cleanupError.name : typeof cleanupError}). ` + `Re-run with --verbose for AWS's own message. ` + safeMsg`${manualBucketDeletionClause(bucketName, this.shownMask)}`);
|
|
4276
|
+
this.logger.warn(safeMsg`Failed to clean up partially-created S3 bucket ${displaySafe(logicalId)} (${this.shown(bucketName)}) ` + safeMsg`(${cleanupError instanceof Error ? cleanupError.name : typeof cleanupError}). ` + `Re-run with --verbose for AWS's own message. ` + safeMsg`${manualBucketDeletionClause(bucketName, this.shownMask, true)}`);
|
|
4183
4277
|
}
|
|
4184
4278
|
else if (preflight.kind === "indeterminate") {
|
|
4185
4279
|
this.logger.debug(`GetBucketLocation failed for S3 bucket ${this.shown(bucketName)} (${displaySafe(logicalId)}) during create: ${preflight.reason}`);
|
|
4186
|
-
this.logger.warn(safeMsg`Not cleaning up S3 bucket ${displaySafe(logicalId)} (${this.shown(bucketName)}) after a wiring failure: ` + `this deploy could not confirm whether it created the bucket (region probe failed: ` + safeMsg`${preflight.errorName}), and in us-east-1 a successful CreateBucket does not ` + "prove it. Re-run with --verbose for AWS's own message. If cdkd created it, the bucket is an orphan. " + safeMsg`${manualBucketDeletionClause(bucketName, this.shownMask)}`);
|
|
4280
|
+
this.logger.warn(safeMsg`Not cleaning up S3 bucket ${displaySafe(logicalId)} (${this.shown(bucketName)}) after a wiring failure: ` + `this deploy could not confirm whether it created the bucket (region probe failed: ` + safeMsg`${preflight.errorName}), and in us-east-1 a successful CreateBucket does not ` + "prove it. Re-run with --verbose for AWS's own message. If cdkd created it, the bucket is an orphan. " + safeMsg`${manualBucketDeletionClause(bucketName, this.shownMask, false)}`);
|
|
4187
4281
|
}
|
|
4188
4282
|
throw markAuxiliaryFailure(innerError, logicalId);
|
|
4189
4283
|
}
|
|
@@ -4196,7 +4290,9 @@ var S3BucketProvider = class S3BucketProvider {
|
|
|
4196
4290
|
...effectiveProperties ? { effectiveProperties } : {}
|
|
4197
4291
|
};
|
|
4198
4292
|
} catch (error) {
|
|
4199
|
-
|
|
4293
|
+
const thrown = this.wrapOperationError("create", logicalId, resourceType, bucketName, error);
|
|
4294
|
+
if (bucketLeftBehind) markCreatedBeforeFailure(thrown, logicalId, resourceType, bucketName);
|
|
4295
|
+
throw thrown;
|
|
4200
4296
|
}
|
|
4201
4297
|
}
|
|
4202
4298
|
async update(logicalId, physicalId, resourceType, properties, previousProperties, context) {
|
|
@@ -4248,7 +4344,7 @@ var S3BucketProvider = class S3BucketProvider {
|
|
|
4248
4344
|
async delete(logicalId, physicalId, resourceType, properties, context) {
|
|
4249
4345
|
this.logger.debug(`Deleting S3 bucket ${displaySafe(logicalId)}: ${displaySafe(physicalId)}`);
|
|
4250
4346
|
const allowAutoEmpty = context?.forceDataDelete === true || hasCdkAutoDeleteTag(properties, "aws-cdk:auto-delete-objects");
|
|
4251
|
-
if (context?.expectedRegion) await this.assertStateBucketRegion("delete", logicalId, resourceType, physicalId, context.expectedRegion);
|
|
4347
|
+
if (context?.expectedRegion) await this.assertStateBucketRegion("delete", logicalId, resourceType, physicalId, context.expectedRegion, context);
|
|
4252
4348
|
else this.announceUnverifiedBucketIdentity("delete", logicalId, physicalId, noRecordedRegionCause());
|
|
4253
4349
|
try {
|
|
4254
4350
|
await this.deleteBucketWithEmptyRetry(logicalId, physicalId, allowAutoEmpty);
|
|
@@ -5408,6 +5504,7 @@ var SQSQueuePolicyProvider = class {
|
|
|
5408
5504
|
const policyDocument = properties["PolicyDocument"];
|
|
5409
5505
|
if (!queues || queues.length === 0) throw new ProvisioningError(`Queues is required for SQS queue policy ${logicalId}`, resourceType, logicalId);
|
|
5410
5506
|
if (!policyDocument) throw new ProvisioningError(`PolicyDocument is required for SQS queue policy ${logicalId}`, resourceType, logicalId);
|
|
5507
|
+
const applied = [];
|
|
5411
5508
|
try {
|
|
5412
5509
|
const policyDoc = typeof policyDocument === "string" ? policyDocument : JSON.stringify(policyDocument);
|
|
5413
5510
|
for (const queueUrl of queues) {
|
|
@@ -5416,6 +5513,7 @@ var SQSQueuePolicyProvider = class {
|
|
|
5416
5513
|
QueueUrl: queueUrl,
|
|
5417
5514
|
Attributes: { Policy: policyDoc }
|
|
5418
5515
|
}));
|
|
5516
|
+
applied.push(queueUrl);
|
|
5419
5517
|
}
|
|
5420
5518
|
this.logger.debug(`Successfully created SQS queue policy ${logicalId}`);
|
|
5421
5519
|
return {
|
|
@@ -5424,7 +5522,9 @@ var SQSQueuePolicyProvider = class {
|
|
|
5424
5522
|
};
|
|
5425
5523
|
} catch (error) {
|
|
5426
5524
|
const cause = error instanceof Error ? error : void 0;
|
|
5427
|
-
|
|
5525
|
+
const thrown = new ProvisioningError(`Failed to create SQS queue policy ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, queues[0], cause);
|
|
5526
|
+
if (applied.length > 0) markCreatedBeforeFailure(thrown, logicalId, resourceType, applied.join(","));
|
|
5527
|
+
throw thrown;
|
|
5428
5528
|
}
|
|
5429
5529
|
}
|
|
5430
5530
|
async update(logicalId, physicalId, resourceType, properties, _previousProperties) {
|
|
@@ -5455,22 +5555,23 @@ var SQSQueuePolicyProvider = class {
|
|
|
5455
5555
|
}
|
|
5456
5556
|
async delete(logicalId, physicalId, resourceType, _properties, context) {
|
|
5457
5557
|
this.logger.debug(`Deleting SQS queue policy ${logicalId}: ${physicalId}`);
|
|
5458
|
-
|
|
5558
|
+
const queueUrls = physicalId.split(",");
|
|
5559
|
+
for (const queueUrl of queueUrls) try {
|
|
5459
5560
|
await this.sqsClient.send(new SetQueueAttributesCommand({
|
|
5460
|
-
QueueUrl:
|
|
5561
|
+
QueueUrl: queueUrl,
|
|
5461
5562
|
Attributes: { Policy: "" }
|
|
5462
5563
|
}));
|
|
5463
|
-
this.logger.debug(`Successfully deleted SQS queue policy ${logicalId}`);
|
|
5464
5564
|
} catch (error) {
|
|
5465
5565
|
if (error instanceof Error && (error.name === "QueueDoesNotExist" || error.message.includes("does not exist"))) {
|
|
5466
5566
|
const clientRegion = await this.sqsClient.config.region();
|
|
5467
|
-
assertRegionMatch(clientRegion, context?.expectedRegion, resourceType, logicalId,
|
|
5468
|
-
this.logger.debug(`Queue ${
|
|
5469
|
-
|
|
5567
|
+
assertRegionMatch(clientRegion, context?.expectedRegion, resourceType, logicalId, queueUrl);
|
|
5568
|
+
this.logger.debug(`Queue ${queueUrl} does not exist, skipping policy deletion`);
|
|
5569
|
+
continue;
|
|
5470
5570
|
}
|
|
5471
5571
|
const cause = error instanceof Error ? error : void 0;
|
|
5472
5572
|
throw new ProvisioningError(`Failed to delete SQS queue policy ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, physicalId, cause);
|
|
5473
5573
|
}
|
|
5574
|
+
this.logger.debug(`Successfully deleted SQS queue policy ${logicalId}`);
|
|
5474
5575
|
}
|
|
5475
5576
|
async readCurrentState(physicalId, _logicalId, _resourceType) {
|
|
5476
5577
|
let policyAttr;
|
|
@@ -5592,6 +5693,7 @@ var SNSTopicProvider = class {
|
|
|
5592
5693
|
this.logger.debug(`Creating SNS topic ${logicalId}`);
|
|
5593
5694
|
const desiredTags = refuseMalformedDesiredTags(properties["Tags"], resourceType, logicalId);
|
|
5594
5695
|
const topicName = properties["TopicName"] || generateResourceName(logicalId, { maxLength: 256 });
|
|
5696
|
+
let leftBehindArn;
|
|
5595
5697
|
try {
|
|
5596
5698
|
const topicAttributes = {};
|
|
5597
5699
|
if (properties["FifoTopic"]) topicAttributes["FifoTopic"] = stringifyValue(properties["FifoTopic"]);
|
|
@@ -5645,7 +5747,8 @@ var SNSTopicProvider = class {
|
|
|
5645
5747
|
await this.snsClient.send(new DeleteTopicCommand({ TopicArn: topicArn }));
|
|
5646
5748
|
this.logger.debug(`Cleaned up partially-created SNS topic ${logicalId} (${topicArn}) after wiring failure`);
|
|
5647
5749
|
} catch (cleanupError) {
|
|
5648
|
-
|
|
5750
|
+
leftBehindArn = topicArn;
|
|
5751
|
+
warn(`Failed to clean up partially-created SNS topic ${logicalId} (${topicArn}): ${describeAwsFailure(cleanupError).detail}. On a first-time create the failed deploy's rollback journal records it for \`cdkd rollback --revert-failed\`; otherwise delete it yourself before the next deploy: ${pasteableAwsCommand(maskSecrets)`aws sns delete-topic --topic-arn ${topicArn}`.render()}`);
|
|
5649
5752
|
}
|
|
5650
5753
|
throw markAuxiliaryFailure(innerError, logicalId);
|
|
5651
5754
|
}
|
|
@@ -5659,7 +5762,9 @@ var SNSTopicProvider = class {
|
|
|
5659
5762
|
};
|
|
5660
5763
|
} catch (error) {
|
|
5661
5764
|
const cause = error instanceof Error ? error : void 0;
|
|
5662
|
-
|
|
5765
|
+
const thrown = new ProvisioningError(`Failed to create SNS topic ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, topicName, cause);
|
|
5766
|
+
if (leftBehindArn) markCreatedBeforeFailure(thrown, logicalId, resourceType, leftBehindArn);
|
|
5767
|
+
throw thrown;
|
|
5663
5768
|
}
|
|
5664
5769
|
}
|
|
5665
5770
|
async update(logicalId, physicalId, resourceType, properties, previousProperties, context) {
|
|
@@ -6241,16 +6346,21 @@ var SNSTopicPolicyProvider = class {
|
|
|
6241
6346
|
if (!topics || topics.length === 0) throw new ProvisioningError(`Topics is required for SNS topic policy ${logicalId}`, resourceType, logicalId);
|
|
6242
6347
|
if (!policyDocument) throw new ProvisioningError(`PolicyDocument is required for SNS topic policy ${logicalId}`, resourceType, logicalId);
|
|
6243
6348
|
const policyDoc = typeof policyDocument === "string" ? policyDocument : JSON.stringify(policyDocument);
|
|
6349
|
+
const applied = [];
|
|
6244
6350
|
try {
|
|
6245
|
-
for (const topicArn of topics)
|
|
6351
|
+
for (const topicArn of topics) {
|
|
6352
|
+
await this.setTopicPolicy(topicArn, policyDoc);
|
|
6353
|
+
applied.push(topicArn);
|
|
6354
|
+
}
|
|
6246
6355
|
this.logger.debug(`Successfully created SNS topic policy ${logicalId}`);
|
|
6247
6356
|
return {
|
|
6248
6357
|
physicalId: topics.join(","),
|
|
6249
6358
|
attributes: {}
|
|
6250
6359
|
};
|
|
6251
6360
|
} catch (error) {
|
|
6252
|
-
const
|
|
6253
|
-
|
|
6361
|
+
const thrown = new ProvisioningError(`Failed to create SNS topic policy ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, void 0, error instanceof Error ? error : void 0);
|
|
6362
|
+
if (applied.length > 0) markCreatedBeforeFailure(thrown, logicalId, resourceType, applied.join(","));
|
|
6363
|
+
throw thrown;
|
|
6254
6364
|
}
|
|
6255
6365
|
}
|
|
6256
6366
|
async update(logicalId, physicalId, resourceType, properties, _previousProperties) {
|
|
@@ -6579,6 +6689,8 @@ var LambdaFunctionProvider = class {
|
|
|
6579
6689
|
if (!role) throw new ProvisioningError(`Role is required for Lambda function ${logicalId}`, resourceType, logicalId);
|
|
6580
6690
|
refuseImageFunctionUnsupported(logicalId, resourceType, properties);
|
|
6581
6691
|
let functionCreated = false;
|
|
6692
|
+
let createdFunctionName;
|
|
6693
|
+
const postCreateCleanup = { deleted: false };
|
|
6582
6694
|
try {
|
|
6583
6695
|
const tags = properties["Tags"] ? Object.fromEntries(desiredTags.map((tag) => [tag.Key, tag.Value])) : void 0;
|
|
6584
6696
|
const createParams = {
|
|
@@ -6610,6 +6722,7 @@ var LambdaFunctionProvider = class {
|
|
|
6610
6722
|
};
|
|
6611
6723
|
const response = await this.lambdaClient.send(new CreateFunctionCommand(createParams));
|
|
6612
6724
|
functionCreated = true;
|
|
6725
|
+
createdFunctionName = response.FunctionName || functionName;
|
|
6613
6726
|
const recursiveLoop = properties["RecursiveLoop"];
|
|
6614
6727
|
if (recursiveLoop !== void 0) await this.applyPostCreateConfig(() => this.lambdaClient.send(new PutFunctionRecursionConfigCommand({
|
|
6615
6728
|
FunctionName: functionName,
|
|
@@ -6620,7 +6733,8 @@ var LambdaFunctionProvider = class {
|
|
|
6620
6733
|
logicalId,
|
|
6621
6734
|
resourceType,
|
|
6622
6735
|
functionName,
|
|
6623
|
-
log
|
|
6736
|
+
log,
|
|
6737
|
+
cleanup: postCreateCleanup
|
|
6624
6738
|
});
|
|
6625
6739
|
const reservedConcurrentExecutions = properties["ReservedConcurrentExecutions"];
|
|
6626
6740
|
if (reservedConcurrentExecutions !== void 0) await this.applyPostCreateConfig(() => this.lambdaClient.send(new PutFunctionConcurrencyCommand({
|
|
@@ -6632,7 +6746,8 @@ var LambdaFunctionProvider = class {
|
|
|
6632
6746
|
logicalId,
|
|
6633
6747
|
resourceType,
|
|
6634
6748
|
functionName,
|
|
6635
|
-
log
|
|
6749
|
+
log,
|
|
6750
|
+
cleanup: postCreateCleanup
|
|
6636
6751
|
});
|
|
6637
6752
|
const runtimeManagementConfig = properties["RuntimeManagementConfig"];
|
|
6638
6753
|
if (runtimeManagementConfig !== void 0) await this.applyPostCreateConfig(async () => {
|
|
@@ -6649,7 +6764,8 @@ var LambdaFunctionProvider = class {
|
|
|
6649
6764
|
logicalId,
|
|
6650
6765
|
resourceType,
|
|
6651
6766
|
functionName,
|
|
6652
|
-
log
|
|
6767
|
+
log,
|
|
6768
|
+
cleanup: postCreateCleanup
|
|
6653
6769
|
});
|
|
6654
6770
|
log.debug(`Successfully created Lambda function ${logicalId}: ${log.value(functionName)}`);
|
|
6655
6771
|
return {
|
|
@@ -6662,7 +6778,9 @@ var LambdaFunctionProvider = class {
|
|
|
6662
6778
|
} catch (error) {
|
|
6663
6779
|
if (functionCreated) markAuxiliaryFailure(error, logicalId);
|
|
6664
6780
|
const cause = error instanceof Error ? error : void 0;
|
|
6665
|
-
|
|
6781
|
+
const thrown = this.wrapMaskedError(log, error, (text) => new ProvisioningError(`Failed to create Lambda function ${logicalId}: ${text}`, resourceType, logicalId, functionName, cause ?? new Error(String(error))));
|
|
6782
|
+
if (createdFunctionName !== void 0 && !postCreateCleanup.deleted) markCreatedBeforeFailure(thrown, logicalId, resourceType, createdFunctionName);
|
|
6783
|
+
throw thrown;
|
|
6666
6784
|
}
|
|
6667
6785
|
}
|
|
6668
6786
|
wrapMaskedError(log, error, build) {
|
|
@@ -6691,6 +6809,7 @@ var LambdaFunctionProvider = class {
|
|
|
6691
6809
|
if (!/currently in the following state|ResourceConflict/i.test(deleteMessage)) break;
|
|
6692
6810
|
if (attempt < 2) await new Promise((resolve) => setTimeout(resolve, this.cleanupDeleteRetryDelayMs * (attempt + 1)));
|
|
6693
6811
|
}
|
|
6812
|
+
if (cleanupFailure === void 0) ctx.cleanup.deleted = true;
|
|
6694
6813
|
if (cleanupFailure !== void 0) this.logger.error(log.mask(`Cleanup DeleteFunction failed for ${ctx.logicalId} after ${ctx.apiName} failure — function may be orphaned: ${cleanupFailure}`));
|
|
6695
6814
|
const cause = error instanceof Error ? error : void 0;
|
|
6696
6815
|
const refusal = new ProvisioningError(`Failed to set ${ctx.propertyName} on Lambda function ${ctx.logicalId} (function was deleted to maintain atomicity): ${message}`, ctx.resourceType, ctx.logicalId, ctx.functionName, cause ?? new Error(rawMessage));
|
|
@@ -7358,7 +7477,7 @@ var LambdaPermissionProvider = class {
|
|
|
7358
7477
|
}
|
|
7359
7478
|
}
|
|
7360
7479
|
if (statementId === "") {
|
|
7361
|
-
this.logger.warn(safeMsg`Lambda permission ${logicalId} has no StatementId in its physicalId ` + safeMsg`("${physicalId}"), skipping deletion — no AWS call is issued, so the permission ` +
|
|
7480
|
+
this.logger.warn(safeMsg`Lambda permission ${logicalId} has no StatementId in its physicalId ` + safeMsg`("${physicalId}"), skipping deletion — no AWS call is issued, so the permission ` + "statement is LEFT IN PLACE on the function's resource policy, UNLESS the function itself is part of this stack (deleting it removes its whole resource policy, and then only the cdkd record is stale — clear it with " + safeMsg`${stateOrphanRecordRemedy(context, logicalId)}). ` + `Otherwise repair the physicalId in state.json and re-run, or remove the statement by hand ('aws lambda remove-permission'). ${DEPLOY_SKIP_CAVEAT$1}`);
|
|
7362
7481
|
return {
|
|
7363
7482
|
outcome: "skipped",
|
|
7364
7483
|
reason: PERMISSION_STATEMENT_ID_SKIP_REASON
|
|
@@ -7366,11 +7485,11 @@ var LambdaPermissionProvider = class {
|
|
|
7366
7485
|
}
|
|
7367
7486
|
const functionName = functionNameFromProperties || functionNameFromPhysicalId;
|
|
7368
7487
|
if (!functionName && functionNameRedacted) {
|
|
7369
|
-
const skip = redactedDeleteAddressSkip(this.logger, logicalId, "Lambda permission", ["FunctionName"]);
|
|
7488
|
+
const skip = redactedDeleteAddressSkip(this.logger, logicalId, "Lambda permission", ["FunctionName"], context);
|
|
7370
7489
|
if (skip) return skip;
|
|
7371
7490
|
}
|
|
7372
7491
|
if (!functionName) {
|
|
7373
|
-
this.logger.warn(safeMsg`FunctionName not available for Lambda permission ${logicalId} (neither the state ` +
|
|
7492
|
+
this.logger.warn(safeMsg`FunctionName not available for Lambda permission ${logicalId} (neither the state ` + "record's FunctionName nor a function ARN in the physicalId), skipping deletion — no AWS call is issued, so the permission statement is LEFT IN PLACE on the function's resource policy, UNLESS the function itself is part of this stack (deleting it removes its whole resource policy, and then only the cdkd record is stale — clear " + safeMsg`it with ${stateOrphanRecordRemedy(context, logicalId)}). ` + `Otherwise repair the record's FunctionName in state.json and re-run, or remove the statement by hand ('aws lambda remove-permission'). ${DEPLOY_SKIP_CAVEAT$1}`);
|
|
7374
7493
|
return {
|
|
7375
7494
|
outcome: "skipped",
|
|
7376
7495
|
reason: PERMISSION_FUNCTION_NAME_SKIP_REASON
|
|
@@ -7771,6 +7890,7 @@ async function reportPossibleOrphans(logicalId, window, log, lookup) {
|
|
|
7771
7890
|
const until = new Date(window.ceilingMs).toISOString();
|
|
7772
7891
|
const remove = lookup.remove;
|
|
7773
7892
|
const service = lookup.service ?? "API Gateway";
|
|
7893
|
+
const afterward = lookup.afterward ?? "Creating a new one now.";
|
|
7774
7894
|
const when = remove !== void 0 ? `between ${since} and ${until}` : `at ${since}`;
|
|
7775
7895
|
let found;
|
|
7776
7896
|
try {
|
|
@@ -7793,10 +7913,10 @@ async function reportPossibleOrphans(logicalId, window, log, lookup) {
|
|
|
7793
7913
|
const inspect = [...new Set(shown.map((id) => lookup.inspect(id)))].join(" ; ");
|
|
7794
7914
|
if (remove !== void 0) {
|
|
7795
7915
|
const deletion = [...new Set(shown.map((id) => remove(id)))].join(" ; ");
|
|
7796
|
-
log.warn(`An earlier ${lookup.action} attempt for ${logicalId} failed without a definite answer, and ${service} may have created ${lookup.subject} then that no cdkd state records. ${found.ids.length} ${lookup.noun} were created ${when} that this deploy did not record: ${shown.join(", ")}${more}. cdkd does not adopt or delete them: nothing listed proves which deploy created one.
|
|
7916
|
+
log.warn(`An earlier ${lookup.action} attempt for ${logicalId} failed without a definite answer, and ${service} may have created ${lookup.subject} then that no cdkd state records. ${found.ids.length} ${lookup.noun} were created ${when} that this deploy did not record: ${shown.join(", ")}${more}. cdkd does not adopt or delete them: nothing listed proves which deploy created one. ${afterward} First inspect each candidate: ${inspect}. Only after confirming one is this deploy's orphan and not another deploy's, ${lookup.removeVerb ?? "delete it"}: ${deletion}.${incomplete}`);
|
|
7797
7917
|
return;
|
|
7798
7918
|
}
|
|
7799
|
-
log.warn(`An earlier ${lookup.action} attempt for ${logicalId} failed without a definite answer (${when}), and ${service} may have created ${lookup.subject} then that no cdkd state records. ${found.ids.length} ${lookup.noun} match that this deploy did not record: ${shown.join(", ")}${more}. ${service} reports no creation time for them, so any of them may instead be this stack's own recorded one, another stack's, or older than this deploy; cdkd does not adopt or delete them.
|
|
7919
|
+
log.warn(`An earlier ${lookup.action} attempt for ${logicalId} failed without a definite answer (${when}), and ${service} may have created ${lookup.subject} then that no cdkd state records. ${found.ids.length} ${lookup.noun} match that this deploy did not record: ${shown.join(", ")}${more}. ${service} reports no creation time for them, so any of them may instead be this stack's own recorded one, another stack's, or older than this deploy; cdkd does not adopt or delete them. ${afterward} Inspect each before deleting anything: ${inspect}.${incomplete}`);
|
|
7800
7920
|
}
|
|
7801
7921
|
|
|
7802
7922
|
//#endregion
|
|
@@ -8715,9 +8835,11 @@ var LambdaMicrovmImageProvider = class {
|
|
|
8715
8835
|
...buildCommonImageInput(properties)
|
|
8716
8836
|
};
|
|
8717
8837
|
if (tagList.length > 0) input.tags = Object.fromEntries(tagList.map((t) => [t.Key, t.Value]));
|
|
8838
|
+
let createdArn;
|
|
8718
8839
|
try {
|
|
8719
8840
|
const response = await this.client.send(new CreateMicrovmImageCommand(input));
|
|
8720
8841
|
const imageArn = response.imageArn;
|
|
8842
|
+
createdArn = imageArn;
|
|
8721
8843
|
if (!imageArn) throw new ProvisioningError(`CreateMicrovmImage succeeded but no imageArn returned for ${logicalId}`, resourceType, logicalId);
|
|
8722
8844
|
this.logger.debug(`Created MicroVM image ${logicalId}: ${imageArn} (state=${response.state})`);
|
|
8723
8845
|
const noWait = process.env["CDKD_NO_WAIT"] === "true";
|
|
@@ -8740,7 +8862,9 @@ var LambdaMicrovmImageProvider = class {
|
|
|
8740
8862
|
})
|
|
8741
8863
|
};
|
|
8742
8864
|
} catch (error) {
|
|
8743
|
-
|
|
8865
|
+
const thrown = this.wrapError("create", logicalId, resourceType, void 0, error);
|
|
8866
|
+
if (createdArn) markCreatedBeforeFailure(thrown, logicalId, resourceType, createdArn);
|
|
8867
|
+
throw thrown;
|
|
8744
8868
|
}
|
|
8745
8869
|
}
|
|
8746
8870
|
async update(logicalId, physicalId, resourceType, properties, previousProperties, context) {
|
|
@@ -9734,18 +9858,20 @@ var DynamoDBTableProvider = class {
|
|
|
9734
9858
|
}
|
|
9735
9859
|
};
|
|
9736
9860
|
} catch (error) {
|
|
9861
|
+
let tableLeftBehind = false;
|
|
9737
9862
|
if (tableCreated) {
|
|
9738
9863
|
try {
|
|
9739
9864
|
await this.dynamoDBClient.send(new DeleteTableCommand({ TableName: tableName }));
|
|
9740
9865
|
debug(`Rolled back partially-created DynamoDB table ${tableName}`);
|
|
9741
9866
|
} catch (cleanupError) {
|
|
9867
|
+
tableLeftBehind = true;
|
|
9742
9868
|
warn(`Failed to roll back partially-created DynamoDB table ${tableName}: ${describeAwsFailure(cleanupError).detail}`);
|
|
9743
9869
|
}
|
|
9744
9870
|
markAuxiliaryFailure(error, logicalId);
|
|
9745
9871
|
}
|
|
9746
|
-
|
|
9747
|
-
|
|
9748
|
-
throw
|
|
9872
|
+
const thrown = error instanceof ProvisioningError ? error : new ProvisioningError(`Failed to create DynamoDB table ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, tableName, error instanceof Error ? error : void 0);
|
|
9873
|
+
if (tableLeftBehind) markCreatedBeforeFailure(thrown, logicalId, resourceType, tableName);
|
|
9874
|
+
throw thrown;
|
|
9749
9875
|
}
|
|
9750
9876
|
}
|
|
9751
9877
|
async update(logicalId, physicalId, resourceType, properties, previousProperties, context) {
|
|
@@ -10993,6 +11119,7 @@ var LogsLogGroupProvider = class {
|
|
|
10993
11119
|
allowedPattern: /[^a-zA-Z0-9-/_]/g
|
|
10994
11120
|
})}`;
|
|
10995
11121
|
const desiredTags = refuseMalformedDesiredTags(properties["Tags"], resourceType, logicalId);
|
|
11122
|
+
let leftBehind = false;
|
|
10996
11123
|
try {
|
|
10997
11124
|
const createParams = { logGroupName };
|
|
10998
11125
|
if (properties["KmsKeyId"]) createParams.kmsKeyId = properties["KmsKeyId"];
|
|
@@ -11003,6 +11130,7 @@ var LogsLogGroupProvider = class {
|
|
|
11003
11130
|
try {
|
|
11004
11131
|
await this.logsClient.send(new CreateLogGroupCommand(createParams));
|
|
11005
11132
|
createdNewLogGroup = true;
|
|
11133
|
+
leftBehind = true;
|
|
11006
11134
|
} catch (createError) {
|
|
11007
11135
|
if (createError instanceof ResourceAlreadyExistsException) this.logger.debug(`Log group ${logGroupName} already exists, using existing`);
|
|
11008
11136
|
else throw createError;
|
|
@@ -11048,6 +11176,7 @@ var LogsLogGroupProvider = class {
|
|
|
11048
11176
|
} catch (innerError) {
|
|
11049
11177
|
if (createdNewLogGroup) try {
|
|
11050
11178
|
await this.logsClient.send(new DeleteLogGroupCommand({ logGroupName }));
|
|
11179
|
+
leftBehind = false;
|
|
11051
11180
|
this.logger.debug(`Cleaned up partially-created log group ${displaySafe(logicalId)} (${displaySafe(logGroupName)}) after wiring failure`);
|
|
11052
11181
|
} catch (cleanupError) {
|
|
11053
11182
|
const mask = maskerOrIdentity(context?.maskSecrets);
|
|
@@ -11056,7 +11185,7 @@ var LogsLogGroupProvider = class {
|
|
|
11056
11185
|
identifier: logGroupName,
|
|
11057
11186
|
maskSecrets: mask
|
|
11058
11187
|
});
|
|
11059
|
-
const manualStep = deleteCommand ? `
|
|
11188
|
+
const manualStep = deleteCommand ? `On a first-time create the failed deploy's rollback journal records it for \`cdkd rollback --revert-failed\`; otherwise delete it yourself before the next deploy: ${deleteCommand}` : "On a first-time create the failed deploy's rollback journal records it for `cdkd rollback --revert-failed`; otherwise delete it yourself before the next deploy, via the console: the log group name cannot be reproduced safely on a command line.";
|
|
11060
11189
|
this.logger.warn(mask(`Failed to clean up partially-created log group ${displaySafe(logicalId)} (${displaySafe(mask(logGroupName))}): ${describeAwsFailure(cleanupError).detail}. ${manualStep}`));
|
|
11061
11190
|
}
|
|
11062
11191
|
throw markAuxiliaryFailure(innerError, logicalId);
|
|
@@ -11069,7 +11198,9 @@ var LogsLogGroupProvider = class {
|
|
|
11069
11198
|
} catch (error) {
|
|
11070
11199
|
const cause = error instanceof Error ? error : void 0;
|
|
11071
11200
|
const mask = maskerOrIdentity(context?.maskSecrets);
|
|
11072
|
-
|
|
11201
|
+
const thrown = this.wrapMaskedError(mask, error, (text) => new ProvisioningError(`Failed to create log group ${logicalId}: ${text}`, resourceType, logicalId, logGroupName, cause));
|
|
11202
|
+
if (leftBehind) markCreatedBeforeFailure(thrown, logicalId, resourceType, logGroupName);
|
|
11203
|
+
throw thrown;
|
|
11073
11204
|
}
|
|
11074
11205
|
}
|
|
11075
11206
|
async update(logicalId, physicalId, resourceType, properties, previousProperties, callerContext) {
|
|
@@ -11649,7 +11780,7 @@ var CloudWatchAnomalyDetectorProvider = class {
|
|
|
11649
11780
|
}
|
|
11650
11781
|
async delete(logicalId, physicalId, resourceType, properties, context) {
|
|
11651
11782
|
this.logger.debug(`Deleting CloudWatch anomaly detector ${logicalId}: ${physicalId}`);
|
|
11652
|
-
if (!properties) throw new ProvisioningError(`Cannot delete AnomalyDetector ${logicalId}: the state record carries no properties, and DeleteAnomalyDetector addresses the model by its metric descriptor.
|
|
11783
|
+
if (!properties) throw new ProvisioningError(`Cannot delete AnomalyDetector ${logicalId}: the state record carries no properties, and DeleteAnomalyDetector addresses the model by its metric descriptor. Delete the detector manually and drop the record with ${stateOrphanRecordRemedy(context, logicalId)}.`, resourceType, logicalId, physicalId);
|
|
11653
11784
|
const skip = redactedDeleteAddressSkip(this.logger, logicalId, "CloudWatch anomaly detector", redactedDeleteAddressFields({
|
|
11654
11785
|
Namespace: properties["Namespace"],
|
|
11655
11786
|
MetricName: properties["MetricName"],
|
|
@@ -11657,7 +11788,7 @@ var CloudWatchAnomalyDetectorProvider = class {
|
|
|
11657
11788
|
Dimensions: properties["Dimensions"],
|
|
11658
11789
|
SingleMetricAnomalyDetector: properties["SingleMetricAnomalyDetector"],
|
|
11659
11790
|
MetricMathAnomalyDetector: properties["MetricMathAnomalyDetector"]
|
|
11660
|
-
}));
|
|
11791
|
+
}), context);
|
|
11661
11792
|
if (skip) return skip;
|
|
11662
11793
|
try {
|
|
11663
11794
|
await this.cloudWatchClient.send(new DeleteAnomalyDetectorCommand(buildDeleteParams(properties)));
|
|
@@ -12208,6 +12339,7 @@ var SSMParameterProvider = class SSMParameterProvider {
|
|
|
12208
12339
|
const type = properties["Type"] || "String";
|
|
12209
12340
|
const value = properties["Value"];
|
|
12210
12341
|
if (!value) throw new ProvisioningError(`Value is required for SSM parameter ${displaySafe(logicalId)}`, resourceType, logicalId);
|
|
12342
|
+
let leftBehind = false;
|
|
12211
12343
|
try {
|
|
12212
12344
|
const putParams = {
|
|
12213
12345
|
Name: name,
|
|
@@ -12221,6 +12353,7 @@ var SSMParameterProvider = class SSMParameterProvider {
|
|
|
12221
12353
|
if (properties["Policies"]) putParams.Policies = properties["Policies"];
|
|
12222
12354
|
if (properties["DataType"]) putParams.DataType = properties["DataType"];
|
|
12223
12355
|
await this.ssmClient.send(new PutParameterCommand(putParams));
|
|
12356
|
+
leftBehind = true;
|
|
12224
12357
|
try {
|
|
12225
12358
|
if (ssmTags.length > 0) await this.ssmClient.send(new AddTagsToResourceCommand({
|
|
12226
12359
|
ResourceType: "Parameter",
|
|
@@ -12230,6 +12363,7 @@ var SSMParameterProvider = class SSMParameterProvider {
|
|
|
12230
12363
|
} catch (innerError) {
|
|
12231
12364
|
try {
|
|
12232
12365
|
await this.ssmClient.send(new DeleteParameterCommand({ Name: name }));
|
|
12366
|
+
leftBehind = false;
|
|
12233
12367
|
debug(`Cleaned up partially-created SSM parameter ${displaySafe(logicalId)} (${displaySafe(mask(name))}) after wiring failure`);
|
|
12234
12368
|
} catch (cleanupError) {
|
|
12235
12369
|
const deleteCommand = renderDisableCommand({
|
|
@@ -12237,7 +12371,7 @@ var SSMParameterProvider = class SSMParameterProvider {
|
|
|
12237
12371
|
identifier: name,
|
|
12238
12372
|
maskSecrets: mask
|
|
12239
12373
|
});
|
|
12240
|
-
const manualStep = deleteCommand ? `
|
|
12374
|
+
const manualStep = deleteCommand ? `On a first-time create the failed deploy's rollback journal records it for \`cdkd rollback --revert-failed\`; otherwise delete it yourself before the next deploy: ${deleteCommand}` : "On a first-time create the failed deploy's rollback journal records it for `cdkd rollback --revert-failed`; otherwise delete it yourself before the next deploy, via the console: the parameter name cannot be reproduced safely on a command line: a command naming the sanitized form would delete a DIFFERENT parameter, and one naming a name that is not inert unquoted could run part of it as shell.";
|
|
12241
12375
|
warn(`Failed to clean up partially-created SSM parameter ${displaySafe(logicalId)} (${displaySafe(mask(name))}): ${describeAwsFailure(cleanupError).detail}. ${manualStep}`);
|
|
12242
12376
|
}
|
|
12243
12377
|
throw markAuxiliaryFailure(innerError, logicalId);
|
|
@@ -12254,7 +12388,9 @@ var SSMParameterProvider = class SSMParameterProvider {
|
|
|
12254
12388
|
};
|
|
12255
12389
|
} catch (error) {
|
|
12256
12390
|
const cause = error instanceof Error ? error : void 0;
|
|
12257
|
-
|
|
12391
|
+
const thrown = this.wrapMaskedError(mask, error, (text) => new ProvisioningError(`Failed to create SSM parameter ${displaySafe(logicalId)}: ${text}`, resourceType, logicalId, void 0, cause));
|
|
12392
|
+
if (leftBehind) markCreatedBeforeFailure(thrown, logicalId, resourceType, name);
|
|
12393
|
+
throw thrown;
|
|
12258
12394
|
}
|
|
12259
12395
|
}
|
|
12260
12396
|
async update(logicalId, physicalId, resourceType, properties, previousProperties, context) {
|
|
@@ -12532,6 +12668,7 @@ var EventBridgeRuleProvider = class {
|
|
|
12532
12668
|
const desiredTags = refuseMalformedDesiredTags(properties["Tags"], resourceType, logicalId);
|
|
12533
12669
|
const ruleName = properties["Name"] || generateResourceName(logicalId, { maxLength: 64 });
|
|
12534
12670
|
const targets = properties["Targets"];
|
|
12671
|
+
let leftLiveArn;
|
|
12535
12672
|
try {
|
|
12536
12673
|
const heldBefore = targets && targets.length > 0 ? await nameHeldBefore(async () => {
|
|
12537
12674
|
await this.eventBridgeClient.send(new DescribeRuleCommand({
|
|
@@ -12581,6 +12718,7 @@ var EventBridgeRuleProvider = class {
|
|
|
12581
12718
|
}));
|
|
12582
12719
|
this.logger.debug(`Cleaned up partially-created EventBridge rule ${logicalId} (${ruleName}) after wiring failure`);
|
|
12583
12720
|
} catch (cleanupError) {
|
|
12721
|
+
leftLiveArn = ruleArn;
|
|
12584
12722
|
this.logger.warn(mask(`Failed to clean up partially-created EventBridge rule ${logicalId} (${ruleName}): ${describeAwsFailure(cleanupError).detail}. Manual deletion may be required before the next deploy` + (command.text === void 0 ? `: ${command.render()}` : `. If the rule has no targets left, the remove-targets step reports an empty id list; that error is harmless and the delete-rule step still runs: ${command.render()}`)));
|
|
12585
12723
|
}
|
|
12586
12724
|
throw markAuxiliaryFailure(innerError, logicalId);
|
|
@@ -12591,7 +12729,9 @@ var EventBridgeRuleProvider = class {
|
|
|
12591
12729
|
};
|
|
12592
12730
|
} catch (error) {
|
|
12593
12731
|
const cause = error instanceof Error ? error : void 0;
|
|
12594
|
-
|
|
12732
|
+
const thrown = new ProvisioningError(`Failed to create EventBridge rule ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, ruleName, cause);
|
|
12733
|
+
if (leftLiveArn) markCreatedBeforeFailure(thrown, logicalId, resourceType, leftLiveArn);
|
|
12734
|
+
throw thrown;
|
|
12595
12735
|
}
|
|
12596
12736
|
}
|
|
12597
12737
|
async update(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
@@ -13137,6 +13277,13 @@ function isEc2NotFoundCode(error) {
|
|
|
13137
13277
|
const name = error?.name;
|
|
13138
13278
|
return typeof name === "string" && name.endsWith(".NotFound");
|
|
13139
13279
|
}
|
|
13280
|
+
const createVpcLatch = new AmbiguousCreateLatch("ec2:CreateVpc");
|
|
13281
|
+
const createSubnetLatch = new AmbiguousCreateLatch("ec2:CreateSubnet");
|
|
13282
|
+
const createInternetGatewayLatch = new AmbiguousCreateLatch("ec2:CreateInternetGateway");
|
|
13283
|
+
const allocateAddressLatch = new AmbiguousCreateLatch("ec2:AllocateAddress");
|
|
13284
|
+
const ec2IdsCreatedByThisProcess = new RecentIdSet();
|
|
13285
|
+
const isUntagged = (tags) => tags === void 0 || tags.length === 0;
|
|
13286
|
+
const ORPHAN_LIST_PAGE_SIZE$2 = 1e3;
|
|
13140
13287
|
var EC2Provider = class {
|
|
13141
13288
|
ec2Client;
|
|
13142
13289
|
ec2AuthorizeClient;
|
|
@@ -13263,11 +13410,128 @@ var EC2Provider = class {
|
|
|
13263
13410
|
this.ec2Client = awsClients.ec2;
|
|
13264
13411
|
this.ec2AuthorizeClient = awsClients.ec2SingleSend ?? awsClients.ec2;
|
|
13265
13412
|
}
|
|
13413
|
+
createClient;
|
|
13414
|
+
getCreateClient() {
|
|
13415
|
+
const shared = this.ec2Client;
|
|
13416
|
+
if (!(shared instanceof EC2Client)) return Promise.resolve(shared);
|
|
13417
|
+
this.createClient ??= shared.config.region().then((region) => withoutServerErrorRetries(new EC2Client({
|
|
13418
|
+
...ambientClientDefaults(),
|
|
13419
|
+
region
|
|
13420
|
+
})), (error) => {
|
|
13421
|
+
this.createClient = void 0;
|
|
13422
|
+
throw error;
|
|
13423
|
+
});
|
|
13424
|
+
return this.createClient;
|
|
13425
|
+
}
|
|
13426
|
+
async reportPossibleEc2Orphans(logicalId, window, log, lookup) {
|
|
13427
|
+
const aws = pasteableAwsCommand(log.mask);
|
|
13428
|
+
const regionArg = await orphanCommandRegionArg(this.ec2Client, aws);
|
|
13429
|
+
await reportPossibleOrphans(logicalId, window, log, {
|
|
13430
|
+
action: lookup.action,
|
|
13431
|
+
service: "EC2",
|
|
13432
|
+
listAction: lookup.listAction,
|
|
13433
|
+
subject: lookup.subject,
|
|
13434
|
+
noun: lookup.noun,
|
|
13435
|
+
...lookup.afterward !== void 0 && { afterward: lookup.afterward },
|
|
13436
|
+
list: lookup.list,
|
|
13437
|
+
inspect: (id) => lookup.inspect(aws, id, regionArg)
|
|
13438
|
+
});
|
|
13439
|
+
}
|
|
13440
|
+
async reportPossibleOrphanVpcs(logicalId, cidrBlock, window, context) {
|
|
13441
|
+
const log = createMaskedLogSinks(this.logger, context?.maskSecrets);
|
|
13442
|
+
const wanted = canonicalizeIpv4Cidr(cidrBlock) ?? cidrBlock;
|
|
13443
|
+
await this.reportPossibleEc2Orphans(logicalId, window, log, {
|
|
13444
|
+
action: "CreateVpc",
|
|
13445
|
+
listAction: "DescribeVpcs",
|
|
13446
|
+
subject: `a VPC with CIDR ${log.value(cidrBlock)}`,
|
|
13447
|
+
noun: "untagged VPC(s)",
|
|
13448
|
+
list: () => collectOrphanIds(async (token) => {
|
|
13449
|
+
const page = await this.ec2Client.send(new DescribeVpcsCommand({
|
|
13450
|
+
MaxResults: ORPHAN_LIST_PAGE_SIZE$2,
|
|
13451
|
+
NextToken: token
|
|
13452
|
+
}));
|
|
13453
|
+
return {
|
|
13454
|
+
items: page.Vpcs ?? [],
|
|
13455
|
+
next: page.NextToken
|
|
13456
|
+
};
|
|
13457
|
+
}, (vpc) => vpc.VpcId !== void 0 && vpc.IsDefault !== true && isUntagged(vpc.Tags) && vpc.CidrBlock !== void 0 && (canonicalizeIpv4Cidr(vpc.CidrBlock) ?? vpc.CidrBlock) === wanted && !ec2IdsCreatedByThisProcess.has(vpc.VpcId) ? vpc.VpcId : void 0),
|
|
13458
|
+
inspect: (aws, id, regionArg) => aws`aws ec2 describe-vpcs --vpc-ids ${id}${regionArg}`.render()
|
|
13459
|
+
});
|
|
13460
|
+
}
|
|
13461
|
+
async reportPossibleOrphanSubnets(logicalId, vpcId, cidrBlock, window, context) {
|
|
13462
|
+
const log = createMaskedLogSinks(this.logger, context?.maskSecrets);
|
|
13463
|
+
const wanted = canonicalizeIpv4Cidr(cidrBlock) ?? cidrBlock;
|
|
13464
|
+
await this.reportPossibleEc2Orphans(logicalId, window, log, {
|
|
13465
|
+
action: "CreateSubnet",
|
|
13466
|
+
listAction: "DescribeSubnets",
|
|
13467
|
+
subject: `a subnet with CIDR ${log.value(cidrBlock)} in VPC ${log.value(vpcId)}`,
|
|
13468
|
+
noun: "untagged subnet(s)",
|
|
13469
|
+
afterward: "Creating it again, which fails with InvalidSubnet.Conflict while that subnet exists.",
|
|
13470
|
+
list: () => collectOrphanIds(async (token) => {
|
|
13471
|
+
const page = await this.ec2Client.send(new DescribeSubnetsCommand({
|
|
13472
|
+
Filters: [{
|
|
13473
|
+
Name: "vpc-id",
|
|
13474
|
+
Values: [vpcId]
|
|
13475
|
+
}],
|
|
13476
|
+
MaxResults: ORPHAN_LIST_PAGE_SIZE$2,
|
|
13477
|
+
NextToken: token
|
|
13478
|
+
}));
|
|
13479
|
+
return {
|
|
13480
|
+
items: page.Subnets ?? [],
|
|
13481
|
+
next: page.NextToken
|
|
13482
|
+
};
|
|
13483
|
+
}, (subnet) => subnet.SubnetId !== void 0 && isUntagged(subnet.Tags) && subnet.CidrBlock !== void 0 && (canonicalizeIpv4Cidr(subnet.CidrBlock) ?? subnet.CidrBlock) === wanted && !ec2IdsCreatedByThisProcess.has(subnet.SubnetId) ? subnet.SubnetId : void 0),
|
|
13484
|
+
inspect: (aws, id, regionArg) => aws`aws ec2 describe-subnets --subnet-ids ${id}${regionArg}`.render()
|
|
13485
|
+
});
|
|
13486
|
+
}
|
|
13487
|
+
async reportPossibleOrphanInternetGateways(logicalId, window, context) {
|
|
13488
|
+
const log = createMaskedLogSinks(this.logger, context?.maskSecrets);
|
|
13489
|
+
await this.reportPossibleEc2Orphans(logicalId, window, log, {
|
|
13490
|
+
action: "CreateInternetGateway",
|
|
13491
|
+
listAction: "DescribeInternetGateways",
|
|
13492
|
+
subject: "an internet gateway",
|
|
13493
|
+
noun: "detached, untagged internet gateway(s)",
|
|
13494
|
+
list: () => collectOrphanIds(async (token) => {
|
|
13495
|
+
const page = await this.ec2Client.send(new DescribeInternetGatewaysCommand({
|
|
13496
|
+
MaxResults: ORPHAN_LIST_PAGE_SIZE$2,
|
|
13497
|
+
NextToken: token
|
|
13498
|
+
}));
|
|
13499
|
+
return {
|
|
13500
|
+
items: page.InternetGateways ?? [],
|
|
13501
|
+
next: page.NextToken
|
|
13502
|
+
};
|
|
13503
|
+
}, (igw) => igw.InternetGatewayId !== void 0 && (igw.Attachments ?? []).length === 0 && isUntagged(igw.Tags) && !ec2IdsCreatedByThisProcess.has(igw.InternetGatewayId) ? igw.InternetGatewayId : void 0),
|
|
13504
|
+
inspect: (aws, id, regionArg) => aws`aws ec2 describe-internet-gateways --internet-gateway-ids ${id}${regionArg}`.render()
|
|
13505
|
+
});
|
|
13506
|
+
}
|
|
13507
|
+
async reportPossibleOrphanAddresses(logicalId, input, window, context) {
|
|
13508
|
+
const log = createMaskedLogSinks(this.logger, context?.maskSecrets);
|
|
13509
|
+
await this.reportPossibleEc2Orphans(logicalId, window, log, {
|
|
13510
|
+
action: "AllocateAddress",
|
|
13511
|
+
listAction: "DescribeAddresses",
|
|
13512
|
+
subject: `an Elastic IP address (domain ${log.value(input.Domain ?? "vpc")})`,
|
|
13513
|
+
noun: "unassociated, untagged Elastic IP address(es)",
|
|
13514
|
+
list: async () => {
|
|
13515
|
+
const response = await this.ec2Client.send(new DescribeAddressesCommand({}));
|
|
13516
|
+
const ids = [];
|
|
13517
|
+
for (const address of response.Addresses ?? []) {
|
|
13518
|
+
const id = address.AllocationId;
|
|
13519
|
+
if (id === void 0 || (address.Domain ?? "vpc") !== (input.Domain ?? "vpc") || address.AssociationId !== void 0 || !isUntagged(address.Tags) || input.NetworkBorderGroup !== void 0 && address.NetworkBorderGroup !== input.NetworkBorderGroup || input.PublicIpv4Pool !== void 0 && address.PublicIpv4Pool !== input.PublicIpv4Pool || ec2IdsCreatedByThisProcess.has(id)) continue;
|
|
13520
|
+
ids.push(id);
|
|
13521
|
+
}
|
|
13522
|
+
return {
|
|
13523
|
+
ids,
|
|
13524
|
+
truncated: false
|
|
13525
|
+
};
|
|
13526
|
+
},
|
|
13527
|
+
inspect: (aws, id, regionArg) => aws`aws ec2 describe-addresses --allocation-ids ${id}${regionArg}`.render()
|
|
13528
|
+
});
|
|
13529
|
+
}
|
|
13266
13530
|
async create(logicalId, resourceType, properties, context) {
|
|
13267
13531
|
switch (resourceType) {
|
|
13268
|
-
case "AWS::EC2::VPC": return this.createVpc(logicalId, resourceType, properties);
|
|
13269
|
-
case "AWS::EC2::Subnet": return this.createSubnet(logicalId, resourceType, properties);
|
|
13270
|
-
case "AWS::EC2::InternetGateway": return this.createInternetGateway(logicalId, resourceType, properties);
|
|
13532
|
+
case "AWS::EC2::VPC": return this.createVpc(logicalId, resourceType, properties, context);
|
|
13533
|
+
case "AWS::EC2::Subnet": return this.createSubnet(logicalId, resourceType, properties, context);
|
|
13534
|
+
case "AWS::EC2::InternetGateway": return this.createInternetGateway(logicalId, resourceType, properties, context);
|
|
13271
13535
|
case "AWS::EC2::EIP": return this.createEip(logicalId, resourceType, properties, context);
|
|
13272
13536
|
case "AWS::EC2::VPCGatewayAttachment": return this.createVpcGatewayAttachment(logicalId, resourceType, properties, context);
|
|
13273
13537
|
case "AWS::EC2::NatGateway": return this.createNatGateway(logicalId, resourceType, properties);
|
|
@@ -13344,16 +13608,29 @@ var EC2Provider = class {
|
|
|
13344
13608
|
default: return;
|
|
13345
13609
|
}
|
|
13346
13610
|
}
|
|
13347
|
-
async createVpc(logicalId, resourceType, properties) {
|
|
13611
|
+
async createVpc(logicalId, resourceType, properties, context) {
|
|
13348
13612
|
this.logger.debug(`Creating VPC ${logicalId}`);
|
|
13349
13613
|
const desiredTags = refuseMalformedDesiredTags(properties["Tags"], resourceType, logicalId);
|
|
13350
13614
|
const cidrBlock = properties["CidrBlock"];
|
|
13351
13615
|
if (!cidrBlock) throw new ProvisioningError(`CidrBlock is required for VPC ${logicalId}`, resourceType, logicalId);
|
|
13616
|
+
let leftBehindId;
|
|
13352
13617
|
try {
|
|
13353
|
-
const
|
|
13354
|
-
|
|
13355
|
-
|
|
13356
|
-
|
|
13618
|
+
const createClient = await this.getCreateClient();
|
|
13619
|
+
const orphanWindow = createVpcLatch.take(logicalId);
|
|
13620
|
+
if (orphanWindow !== void 0) await this.reportPossibleOrphanVpcs(logicalId, cidrBlock, orphanWindow, context);
|
|
13621
|
+
const attemptStartMs = Date.now();
|
|
13622
|
+
let response;
|
|
13623
|
+
try {
|
|
13624
|
+
response = await createClient.send(new CreateVpcCommand({
|
|
13625
|
+
CidrBlock: cidrBlock,
|
|
13626
|
+
InstanceTenancy: properties["InstanceTenancy"] ?? void 0
|
|
13627
|
+
}));
|
|
13628
|
+
} catch (error) {
|
|
13629
|
+
createVpcLatch.noteFailure(logicalId, error, attemptStartMs, orphanWindow);
|
|
13630
|
+
throw error;
|
|
13631
|
+
}
|
|
13632
|
+
const vpcId = response.Vpc.VpcId;
|
|
13633
|
+
ec2IdsCreatedByThisProcess.add(vpcId);
|
|
13357
13634
|
let defaultSgId;
|
|
13358
13635
|
try {
|
|
13359
13636
|
if (properties["EnableDnsHostnames"] === true || properties["EnableDnsHostnames"] === "true") await this.ec2Client.send(new ModifyVpcAttributeCommand({
|
|
@@ -13382,6 +13659,7 @@ var EC2Provider = class {
|
|
|
13382
13659
|
await this.ec2Client.send(new DeleteVpcCommand({ VpcId: vpcId }));
|
|
13383
13660
|
this.logger.debug(`Cleaned up partially-created VPC ${logicalId} (${vpcId}) after wiring failure`);
|
|
13384
13661
|
} catch (cleanupError) {
|
|
13662
|
+
leftBehindId = vpcId;
|
|
13385
13663
|
this.logger.warn(`Failed to clean up partially-created VPC ${logicalId} (${vpcId}): ${describeAwsFailure(cleanupError).detail}. Manual deletion may be required before the next deploy: ${pasteableAwsCommand()`aws ec2 delete-vpc --vpc-id ${vpcId}`.render()}`);
|
|
13386
13664
|
}
|
|
13387
13665
|
throw markAuxiliaryFailure(innerError, logicalId);
|
|
@@ -13397,7 +13675,9 @@ var EC2Provider = class {
|
|
|
13397
13675
|
};
|
|
13398
13676
|
} catch (error) {
|
|
13399
13677
|
const cause = error instanceof Error ? error : void 0;
|
|
13400
|
-
|
|
13678
|
+
const thrown = new ProvisioningError(`Failed to create VPC ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, void 0, cause);
|
|
13679
|
+
if (leftBehindId !== void 0) markCreatedBeforeFailure(thrown, logicalId, resourceType, leftBehindId);
|
|
13680
|
+
throw thrown;
|
|
13401
13681
|
}
|
|
13402
13682
|
}
|
|
13403
13683
|
async updateVpc(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
@@ -13491,19 +13771,31 @@ var EC2Provider = class {
|
|
|
13491
13771
|
return;
|
|
13492
13772
|
}
|
|
13493
13773
|
}
|
|
13494
|
-
async createSubnet(logicalId, resourceType, properties) {
|
|
13774
|
+
async createSubnet(logicalId, resourceType, properties, context) {
|
|
13495
13775
|
this.logger.debug(`Creating Subnet ${logicalId}`);
|
|
13496
13776
|
const desiredTags = refuseMalformedDesiredTags(properties["Tags"], resourceType, logicalId);
|
|
13497
13777
|
const vpcId = properties["VpcId"];
|
|
13498
13778
|
const cidrBlock = properties["CidrBlock"];
|
|
13499
13779
|
if (!vpcId || !cidrBlock) throw new ProvisioningError(`VpcId and CidrBlock are required for Subnet ${logicalId}`, resourceType, logicalId);
|
|
13780
|
+
let leftBehindId;
|
|
13500
13781
|
try {
|
|
13501
|
-
const
|
|
13502
|
-
|
|
13503
|
-
|
|
13504
|
-
|
|
13505
|
-
|
|
13782
|
+
const createClient = await this.getCreateClient();
|
|
13783
|
+
const orphanWindow = createSubnetLatch.take(logicalId);
|
|
13784
|
+
if (orphanWindow !== void 0) await this.reportPossibleOrphanSubnets(logicalId, vpcId, cidrBlock, orphanWindow, context);
|
|
13785
|
+
const attemptStartMs = Date.now();
|
|
13786
|
+
let response;
|
|
13787
|
+
try {
|
|
13788
|
+
response = await createClient.send(new CreateSubnetCommand({
|
|
13789
|
+
VpcId: vpcId,
|
|
13790
|
+
CidrBlock: cidrBlock,
|
|
13791
|
+
AvailabilityZone: properties["AvailabilityZone"] ?? void 0
|
|
13792
|
+
}));
|
|
13793
|
+
} catch (error) {
|
|
13794
|
+
createSubnetLatch.noteFailure(logicalId, error, attemptStartMs, orphanWindow);
|
|
13795
|
+
throw error;
|
|
13796
|
+
}
|
|
13506
13797
|
const subnetId = response.Subnet.SubnetId;
|
|
13798
|
+
ec2IdsCreatedByThisProcess.add(subnetId);
|
|
13507
13799
|
const availabilityZone = response.Subnet.AvailabilityZone;
|
|
13508
13800
|
try {
|
|
13509
13801
|
await this.applyTags(subnetId, desiredTags, logicalId);
|
|
@@ -13520,6 +13812,7 @@ var EC2Provider = class {
|
|
|
13520
13812
|
await this.ec2Client.send(new DeleteSubnetCommand({ SubnetId: subnetId }));
|
|
13521
13813
|
this.logger.debug(`Cleaned up partially-created Subnet ${logicalId} (${subnetId}) after wiring failure`);
|
|
13522
13814
|
} catch (cleanupError) {
|
|
13815
|
+
leftBehindId = subnetId;
|
|
13523
13816
|
this.logger.warn(`Failed to clean up partially-created Subnet ${logicalId} (${subnetId}): ${describeAwsFailure(cleanupError).detail}. Manual deletion may be required before the next deploy: ${pasteableAwsCommand()`aws ec2 delete-subnet --subnet-id ${subnetId}`.render()}`);
|
|
13524
13817
|
}
|
|
13525
13818
|
throw markAuxiliaryFailure(innerError, logicalId);
|
|
@@ -13534,7 +13827,9 @@ var EC2Provider = class {
|
|
|
13534
13827
|
};
|
|
13535
13828
|
} catch (error) {
|
|
13536
13829
|
const cause = error instanceof Error ? error : void 0;
|
|
13537
|
-
|
|
13830
|
+
const thrown = new ProvisioningError(`Failed to create Subnet ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, void 0, cause);
|
|
13831
|
+
if (leftBehindId !== void 0) markCreatedBeforeFailure(thrown, logicalId, resourceType, leftBehindId);
|
|
13832
|
+
throw thrown;
|
|
13538
13833
|
}
|
|
13539
13834
|
}
|
|
13540
13835
|
async updateSubnet(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
@@ -13647,11 +13942,23 @@ var EC2Provider = class {
|
|
|
13647
13942
|
return;
|
|
13648
13943
|
}
|
|
13649
13944
|
}
|
|
13650
|
-
async createInternetGateway(logicalId, resourceType, properties) {
|
|
13945
|
+
async createInternetGateway(logicalId, resourceType, properties, context) {
|
|
13651
13946
|
this.logger.debug(`Creating InternetGateway ${logicalId}`);
|
|
13652
13947
|
const desiredTags = refuseMalformedDesiredTags(properties["Tags"], resourceType, logicalId);
|
|
13653
13948
|
try {
|
|
13654
|
-
const
|
|
13949
|
+
const createClient = await this.getCreateClient();
|
|
13950
|
+
const orphanWindow = createInternetGatewayLatch.take(logicalId);
|
|
13951
|
+
if (orphanWindow !== void 0) await this.reportPossibleOrphanInternetGateways(logicalId, orphanWindow, context);
|
|
13952
|
+
const attemptStartMs = Date.now();
|
|
13953
|
+
let response;
|
|
13954
|
+
try {
|
|
13955
|
+
response = await createClient.send(new CreateInternetGatewayCommand({}));
|
|
13956
|
+
} catch (error) {
|
|
13957
|
+
createInternetGatewayLatch.noteFailure(logicalId, error, attemptStartMs, orphanWindow);
|
|
13958
|
+
throw error;
|
|
13959
|
+
}
|
|
13960
|
+
const igwId = response.InternetGateway.InternetGatewayId;
|
|
13961
|
+
ec2IdsCreatedByThisProcess.add(igwId);
|
|
13655
13962
|
await this.applyTags(igwId, desiredTags, logicalId);
|
|
13656
13963
|
this.logger.debug(`Successfully created InternetGateway ${logicalId}: ${igwId}`);
|
|
13657
13964
|
return {
|
|
@@ -13708,15 +14015,33 @@ var EC2Provider = class {
|
|
|
13708
14015
|
let allocationId;
|
|
13709
14016
|
let publicIp;
|
|
13710
14017
|
let created = false;
|
|
14018
|
+
let createdId;
|
|
13711
14019
|
try {
|
|
13712
|
-
const
|
|
14020
|
+
const input = {
|
|
13713
14021
|
Domain: requireConfigString(properties["Domain"], "vpc", "AWS::EC2::EIP Domain", replayWarn(this.logger, context)),
|
|
13714
14022
|
NetworkBorderGroup: properties["NetworkBorderGroup"],
|
|
13715
14023
|
PublicIpv4Pool: properties["PublicIpv4Pool"]
|
|
13716
|
-
}
|
|
14024
|
+
};
|
|
14025
|
+
const createClient = await this.getCreateClient();
|
|
14026
|
+
const orphanWindow = allocateAddressLatch.take(logicalId);
|
|
14027
|
+
if (orphanWindow !== void 0) await this.reportPossibleOrphanAddresses(logicalId, input, orphanWindow, context);
|
|
14028
|
+
const attemptStartMs = Date.now();
|
|
14029
|
+
let response;
|
|
14030
|
+
try {
|
|
14031
|
+
response = await createClient.send(new AllocateAddressCommand(input));
|
|
14032
|
+
} catch (error) {
|
|
14033
|
+
allocateAddressLatch.noteFailure(logicalId, error, attemptStartMs, orphanWindow);
|
|
14034
|
+
throw error;
|
|
14035
|
+
}
|
|
13717
14036
|
created = true;
|
|
13718
14037
|
allocationId = response.AllocationId;
|
|
13719
14038
|
publicIp = response.PublicIp;
|
|
14039
|
+
try {
|
|
14040
|
+
createdId = this.eipPhysicalId(logicalId, publicIp, allocationId);
|
|
14041
|
+
} catch {
|
|
14042
|
+
createdId = allocationId;
|
|
14043
|
+
}
|
|
14044
|
+
ec2IdsCreatedByThisProcess.add(allocationId);
|
|
13720
14045
|
await this.applyTags(allocationId, desiredTags, logicalId);
|
|
13721
14046
|
const instanceId = properties["InstanceId"];
|
|
13722
14047
|
if (instanceId) {
|
|
@@ -13733,7 +14058,9 @@ var EC2Provider = class {
|
|
|
13733
14058
|
} catch (error) {
|
|
13734
14059
|
if (created) markAuxiliaryFailure(error, logicalId);
|
|
13735
14060
|
const cause = error instanceof Error ? error : void 0;
|
|
13736
|
-
|
|
14061
|
+
const thrown = new ProvisioningError(`Failed to create EIP ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, void 0, cause);
|
|
14062
|
+
if (createdId !== void 0) markCreatedBeforeFailure(thrown, logicalId, resourceType, createdId);
|
|
14063
|
+
throw thrown;
|
|
13737
14064
|
}
|
|
13738
14065
|
return {
|
|
13739
14066
|
physicalId: this.eipPhysicalId(logicalId, publicIp, allocationId, {
|
|
@@ -13878,6 +14205,7 @@ var EC2Provider = class {
|
|
|
13878
14205
|
scope: "CreateNatGateway",
|
|
13879
14206
|
logicalId
|
|
13880
14207
|
});
|
|
14208
|
+
let createdId;
|
|
13881
14209
|
try {
|
|
13882
14210
|
const natGatewayId = (await this.ec2Client.send(new CreateNatGatewayCommand({
|
|
13883
14211
|
ClientToken: natGatewayToken.value,
|
|
@@ -13889,6 +14217,7 @@ var EC2Provider = class {
|
|
|
13889
14217
|
SecondaryPrivateIpAddresses: properties["SecondaryPrivateIpAddresses"],
|
|
13890
14218
|
SecondaryPrivateIpAddressCount: properties["SecondaryPrivateIpAddressCount"]
|
|
13891
14219
|
}))).NatGateway.NatGatewayId;
|
|
14220
|
+
createdId = natGatewayId;
|
|
13892
14221
|
await this.applyTags(natGatewayId, desiredTags, logicalId);
|
|
13893
14222
|
if (process.env["CDKD_NO_WAIT"] !== "true") {
|
|
13894
14223
|
this.logger.debug(`Waiting for NatGateway ${natGatewayId} to reach available state...`);
|
|
@@ -13908,7 +14237,9 @@ var EC2Provider = class {
|
|
|
13908
14237
|
};
|
|
13909
14238
|
} catch (error) {
|
|
13910
14239
|
const cause = error instanceof Error ? error : void 0;
|
|
13911
|
-
|
|
14240
|
+
const thrown = new ProvisioningError(`Failed to create NatGateway ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, void 0, cause);
|
|
14241
|
+
if (createdId !== void 0) markCreatedBeforeFailure(thrown, logicalId, resourceType, createdId);
|
|
14242
|
+
throw thrown;
|
|
13912
14243
|
}
|
|
13913
14244
|
}
|
|
13914
14245
|
updateNatGateway(logicalId, physicalId) {
|
|
@@ -14134,8 +14465,9 @@ var EC2Provider = class {
|
|
|
14134
14465
|
const desiredTags = refuseMalformedDesiredTags(properties["Tags"], resourceType, logicalId);
|
|
14135
14466
|
const groupDescription = properties["GroupDescription"];
|
|
14136
14467
|
if (!groupDescription) throw new ProvisioningError(`GroupDescription is required for SecurityGroup ${logicalId}`, resourceType, logicalId);
|
|
14468
|
+
let leftBehindId;
|
|
14137
14469
|
try {
|
|
14138
|
-
const groupId = (await this.
|
|
14470
|
+
const groupId = (await (await this.getCreateClient()).send(new CreateSecurityGroupCommand({
|
|
14139
14471
|
GroupName: properties["GroupName"] ?? logicalId,
|
|
14140
14472
|
Description: groupDescription,
|
|
14141
14473
|
VpcId: properties["VpcId"] ?? void 0
|
|
@@ -14158,6 +14490,7 @@ var EC2Provider = class {
|
|
|
14158
14490
|
await this.ec2Client.send(new DeleteSecurityGroupCommand({ GroupId: groupId }));
|
|
14159
14491
|
this.logger.debug(`Cleaned up partially-created SecurityGroup ${logicalId} (${groupId}) after wiring failure`);
|
|
14160
14492
|
} catch (cleanupError) {
|
|
14493
|
+
leftBehindId = groupId;
|
|
14161
14494
|
this.logger.warn(`Failed to clean up partially-created SecurityGroup ${logicalId} (${groupId}): ${describeAwsFailure(cleanupError).detail}. Manual deletion may be required before the next deploy: ${pasteableAwsCommand()`aws ec2 delete-security-group --group-id ${groupId}`.render()}`);
|
|
14162
14495
|
}
|
|
14163
14496
|
throw markAuxiliaryFailure(innerError, logicalId);
|
|
@@ -14172,7 +14505,9 @@ var EC2Provider = class {
|
|
|
14172
14505
|
};
|
|
14173
14506
|
} catch (error) {
|
|
14174
14507
|
const cause = error instanceof Error ? error : void 0;
|
|
14175
|
-
|
|
14508
|
+
const thrown = new ProvisioningError(`Failed to create SecurityGroup ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, void 0, cause);
|
|
14509
|
+
if (leftBehindId !== void 0) markCreatedBeforeFailure(thrown, logicalId, resourceType, leftBehindId);
|
|
14510
|
+
throw thrown;
|
|
14176
14511
|
}
|
|
14177
14512
|
}
|
|
14178
14513
|
async authorizeInlineIngress(groupId, ingressRules) {
|
|
@@ -14560,7 +14895,7 @@ var EC2Provider = class {
|
|
|
14560
14895
|
if (keptFor !== void 0) this.logger.info(safeMsg`SecurityGroupIngress ${logicalId}: its previous rule is also held by ${keptFor} of this stack, so the update left it in place`);
|
|
14561
14896
|
const revoked = keptFor !== void 0 ? void 0 : await this.deleteSecurityGroupIngress(logicalId, physicalId, resourceType, previousProperties, recordedAttributes ? { recordedAttributes } : void 0);
|
|
14562
14897
|
const revokeSkip = deleteSkipReason(revoked);
|
|
14563
|
-
if (revokeSkip !== void 0) throw markNonRetryable(new ProvisioningError(`Cannot update SecurityGroupIngress ${logicalId}: the previous rule could not be revoked because ${revokeSkip === "redacted address property in state — no delete issued" ? "its recorded permission is redacted in state" : "its delete was skipped"}, so the new rule was NOT authorized. Revoke the old rule by hand, then
|
|
14898
|
+
if (revokeSkip !== void 0) throw markNonRetryable(new ProvisioningError(`Cannot update SecurityGroupIngress ${logicalId}: the previous rule could not be revoked because ${revokeSkip === "redacted address property in state — no delete issued" ? "its recorded permission is redacted in state" : "its delete was skipped"}, so the new rule was NOT authorized. Revoke the old rule by hand, then drop its record with ${stateOrphanRecordRemedy(void 0, logicalId)}; then re-deploy.`, resourceType, logicalId, physicalId));
|
|
14564
14899
|
const createResult = await this.createSecurityGroupIngress(logicalId, resourceType, properties, (message) => this.logger.warn(message), maskSecrets, replayingState, keptFor !== void 0 ? void 0 : typeof recordedAttributes?.["Id"] === "string" ? recordedAttributes["Id"] : physicalId);
|
|
14565
14900
|
return {
|
|
14566
14901
|
physicalId: createResult.physicalId,
|
|
@@ -14617,7 +14952,7 @@ var EC2Provider = class {
|
|
|
14617
14952
|
SourceSecurityGroupId: properties["SourceSecurityGroupId"],
|
|
14618
14953
|
SourceSecurityGroupOwnerId: properties["SourceSecurityGroupOwnerId"],
|
|
14619
14954
|
SourcePrefixListId: properties["SourcePrefixListId"]
|
|
14620
|
-
}));
|
|
14955
|
+
}), context);
|
|
14621
14956
|
if (redactedSkip) return redactedSkip;
|
|
14622
14957
|
}
|
|
14623
14958
|
const ipPermission = properties ? this.withoutDescription(this.buildIpPermission(properties)) : {
|
|
@@ -14656,6 +14991,7 @@ var EC2Provider = class {
|
|
|
14656
14991
|
const imageId = properties["ImageId"];
|
|
14657
14992
|
if (!imageId) throw new ProvisioningError(`ImageId is required for EC2 Instance ${logicalId}`, resourceType, logicalId);
|
|
14658
14993
|
const instanceType = requireConfigString(properties["InstanceType"], "t3.micro", "AWS::EC2::Instance InstanceType", replayWarn(this.logger, context));
|
|
14994
|
+
let leftBehindId;
|
|
14659
14995
|
try {
|
|
14660
14996
|
const securityGroupIds = properties["SecurityGroupIds"];
|
|
14661
14997
|
const securityGroups = properties["SecurityGroups"];
|
|
@@ -14723,14 +15059,15 @@ var EC2Provider = class {
|
|
|
14723
15059
|
runInstancesToken.release();
|
|
14724
15060
|
this.logger.debug(`Terminate requested for partially-created EC2 Instance ${logicalId} (${instanceId}) after wiring failure (not waiting for terminated state)`);
|
|
14725
15061
|
} catch (cleanupError) {
|
|
15062
|
+
leftBehindId = instanceId;
|
|
14726
15063
|
this.logger.warn(`Failed to terminate partially-created EC2 Instance ${logicalId} (${instanceId}): ${describeAwsFailure(cleanupError).detail}. THE INSTANCE IS STILL RUNNING AND BILLING. Manual termination required: ${pasteableAwsCommand(context?.maskSecrets)`aws ec2 terminate-instances --instance-ids ${instanceId}`.render()}`);
|
|
14727
15064
|
}
|
|
14728
15065
|
throw markAuxiliaryFailure(innerError, logicalId);
|
|
14729
15066
|
}
|
|
14730
15067
|
} catch (error) {
|
|
14731
|
-
|
|
14732
|
-
|
|
14733
|
-
throw
|
|
15068
|
+
const thrown = error instanceof ProvisioningError ? error : new ProvisioningError(`Failed to create EC2 Instance ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, void 0, error instanceof Error ? error : void 0);
|
|
15069
|
+
if (leftBehindId !== void 0) markCreatedBeforeFailure(thrown, logicalId, resourceType, leftBehindId);
|
|
15070
|
+
throw thrown;
|
|
14734
15071
|
}
|
|
14735
15072
|
}
|
|
14736
15073
|
normalizeIamInstanceProfile(raw) {
|
|
@@ -15214,7 +15551,10 @@ var EC2Provider = class {
|
|
|
15214
15551
|
this.logger.debug(`Deleting NetworkAclEntry ${logicalId}: ${physicalId}`);
|
|
15215
15552
|
const parts = physicalId.split("|");
|
|
15216
15553
|
if (parts.length < 3) {
|
|
15217
|
-
this.logger.warn(compositeIdFormatMessage(EC2_NETWORK_ACL_ENTRY_ID_FORMAT, logicalId, physicalId, {
|
|
15554
|
+
this.logger.warn(compositeIdFormatMessage(EC2_NETWORK_ACL_ENTRY_ID_FORMAT, logicalId, physicalId, {
|
|
15555
|
+
skipping: true,
|
|
15556
|
+
context
|
|
15557
|
+
}));
|
|
15218
15558
|
return compositeIdSkipResult();
|
|
15219
15559
|
}
|
|
15220
15560
|
const networkAclId = parts[0];
|
|
@@ -16772,6 +17112,7 @@ var ApiGatewayProvider = class ApiGatewayProvider {
|
|
|
16772
17112
|
const block = properties[key];
|
|
16773
17113
|
if (block != null && !isPlainObjectBlock(block)) throw new ProvisioningError(`AWS::ApiGateway::Stage ${key} for ${logicalId} must be an object block; got ${Array.isArray(block) ? "an array" : typeof block}. Fix the template value instead of letting cdkd drop the config.`, resourceType, logicalId);
|
|
16774
17114
|
}
|
|
17115
|
+
let stageLeftBehind = false;
|
|
16775
17116
|
try {
|
|
16776
17117
|
const rawCacheClusterSize = properties["CacheClusterSize"];
|
|
16777
17118
|
await this.apiGatewayClient.send(new CreateStageCommand({
|
|
@@ -16821,6 +17162,7 @@ var ApiGatewayProvider = class ApiGatewayProvider {
|
|
|
16821
17162
|
stageName
|
|
16822
17163
|
}));
|
|
16823
17164
|
} catch (cleanupError) {
|
|
17165
|
+
stageLeftBehind = true;
|
|
16824
17166
|
log.warn(`Failed to clean up stage ${log.value(stageName)} after a post-create patch failure: ${describeAwsFailure(cleanupError).detail}`);
|
|
16825
17167
|
}
|
|
16826
17168
|
throw markAuxiliaryFailure(patchError, logicalId);
|
|
@@ -16832,7 +17174,9 @@ var ApiGatewayProvider = class ApiGatewayProvider {
|
|
|
16832
17174
|
};
|
|
16833
17175
|
} catch (error) {
|
|
16834
17176
|
const cause = error instanceof Error ? error : void 0;
|
|
16835
|
-
|
|
17177
|
+
const thrown = this.wrapMaskedError(log.mask, error, (text) => new ProvisioningError(`Failed to create API Gateway Stage ${logicalId}: ${text}`, resourceType, logicalId, void 0, cause));
|
|
17178
|
+
if (stageLeftBehind) markCreatedBeforeFailure(thrown, logicalId, resourceType, stageName);
|
|
17179
|
+
throw thrown;
|
|
16836
17180
|
}
|
|
16837
17181
|
}
|
|
16838
17182
|
async updateStage(logicalId, physicalId, resourceType, properties, previousProperties, log) {
|
|
@@ -17038,6 +17382,7 @@ var ApiGatewayProvider = class ApiGatewayProvider {
|
|
|
17038
17382
|
httpMethod
|
|
17039
17383
|
].map((id) => log.value(id));
|
|
17040
17384
|
const methodPath = maskedIds.join("/");
|
|
17385
|
+
let methodLeftBehind = false;
|
|
17041
17386
|
try {
|
|
17042
17387
|
await this.apiGatewayClient.send(new PutMethodCommand({
|
|
17043
17388
|
restApiId,
|
|
@@ -17111,6 +17456,7 @@ var ApiGatewayProvider = class ApiGatewayProvider {
|
|
|
17111
17456
|
}));
|
|
17112
17457
|
log.debug(`Cleaned up partially-created API Gateway Method ${logicalId} (${methodPath}) after wiring failure`);
|
|
17113
17458
|
} catch (cleanupError) {
|
|
17459
|
+
methodLeftBehind = true;
|
|
17114
17460
|
log.warn(`Failed to clean up partially-created API Gateway Method ${logicalId} (${methodPath}): ${describeAwsFailure(cleanupError).detail}. Manual deletion may be required before the next deploy: ${pasteableAwsCommand(log.mask)`aws apigateway delete-method --rest-api-id ${restApiId} --resource-id ${resourceId} --http-method ${httpMethod}`.render()}`);
|
|
17115
17461
|
}
|
|
17116
17462
|
throw markAuxiliaryFailure(innerError, logicalId);
|
|
@@ -17122,7 +17468,9 @@ var ApiGatewayProvider = class ApiGatewayProvider {
|
|
|
17122
17468
|
};
|
|
17123
17469
|
} catch (error) {
|
|
17124
17470
|
const cause = error instanceof Error ? error : void 0;
|
|
17125
|
-
|
|
17471
|
+
const thrown = this.wrapMaskedError(log.mask, error, (text) => new ProvisioningError(`Failed to create API Gateway Method ${logicalId}: ${text}`, resourceType, logicalId, void 0, cause));
|
|
17472
|
+
if (methodLeftBehind) markCreatedBeforeFailure(thrown, logicalId, resourceType, physicalId);
|
|
17473
|
+
throw thrown;
|
|
17126
17474
|
}
|
|
17127
17475
|
}
|
|
17128
17476
|
async updateMethod(logicalId, physicalId, resourceType, properties, previousProperties, log) {
|
|
@@ -21094,7 +21442,9 @@ var ECSProvider = class {
|
|
|
21094
21442
|
const desiredTags = refuseMalformedDesiredTags(properties["Tags"], resourceType, logicalId);
|
|
21095
21443
|
const client = this.getClient();
|
|
21096
21444
|
const serviceName = properties["ServiceName"] || generateResourceName(logicalId, { maxLength: 255 });
|
|
21445
|
+
let survivorArn;
|
|
21097
21446
|
try {
|
|
21447
|
+
const heldBefore = process.env["CDKD_FULL_WAIT"] === "true" ? await nameHeldBefore(() => this.serviceNameHeld(properties["Cluster"], serviceName), (error) => hasErrorName(error, ["ClusterNotFoundException"])) : "free";
|
|
21098
21448
|
const service = (await client.send(new CreateServiceCommand({
|
|
21099
21449
|
cluster: properties["Cluster"],
|
|
21100
21450
|
serviceName,
|
|
@@ -21132,7 +21482,9 @@ var ECSProvider = class {
|
|
|
21132
21482
|
const cleanupCluster = properties["Cluster"];
|
|
21133
21483
|
const clusterArg = cleanupCluster ? aws` --cluster ${cleanupCluster}` : aws``;
|
|
21134
21484
|
const listStopped = aws`aws ecs list-tasks${clusterArg} --desired-status STOPPED`;
|
|
21135
|
-
|
|
21485
|
+
const deleteCommand = aws`aws ecs delete-service${clusterArg} --service ${service.serviceArn} --force`;
|
|
21486
|
+
if (heldBefore !== "free") log.warn(skippedCleanupText(heldBefore, `ECS service ${logicalIdShown(logicalId)} ${isPlainImportValue(service.serviceArn) ? `(${service.serviceArn})` : VALUE_NOT_SHOWN}`, deleteCommand.render()));
|
|
21487
|
+
else try {
|
|
21136
21488
|
await client.send(new DeleteServiceCommand({
|
|
21137
21489
|
cluster: properties["Cluster"],
|
|
21138
21490
|
service: service.serviceArn,
|
|
@@ -21140,7 +21492,8 @@ var ECSProvider = class {
|
|
|
21140
21492
|
}));
|
|
21141
21493
|
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()}`);
|
|
21142
21494
|
} catch (cleanupError) {
|
|
21143
|
-
|
|
21495
|
+
survivorArn = service.serviceArn;
|
|
21496
|
+
log.warn(`Failed to clean up partially-created ECS service ${logicalIdShown(logicalId)} ${isPlainImportValue(service.serviceArn) ? `(${service.serviceArn})` : VALUE_NOT_SHOWN}: ${describeAwsFailure(cleanupError).detail}. Manual deletion may be required before the next deploy: ${deleteCommand.render()}`);
|
|
21144
21497
|
}
|
|
21145
21498
|
throw new Error(`ECS service ${logicalIdShown(logicalId)} did not reach steady state under --full-wait: ${waitError instanceof Error ? waitError.message : String(waitError)}. 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 });
|
|
21146
21499
|
}
|
|
@@ -21153,9 +21506,24 @@ var ECSProvider = class {
|
|
|
21153
21506
|
};
|
|
21154
21507
|
} catch (error) {
|
|
21155
21508
|
const cause = error instanceof Error ? error : void 0;
|
|
21156
|
-
throw this.wrapMaskedError(log, error, (text) =>
|
|
21509
|
+
throw this.wrapMaskedError(log, error, (text) => {
|
|
21510
|
+
const wrapped = new ProvisioningError(`Failed to create ECS service ${logicalIdShown(logicalId)}: ${text}`, resourceType, logicalId, serviceName, cause);
|
|
21511
|
+
if (survivorArn !== void 0) markCreatedBeforeFailure(wrapped, logicalId, resourceType, survivorArn);
|
|
21512
|
+
return wrapped;
|
|
21513
|
+
});
|
|
21157
21514
|
}
|
|
21158
21515
|
}
|
|
21516
|
+
async serviceNameHeld(cluster, serviceName) {
|
|
21517
|
+
const response = await this.getClient().send(new DescribeServicesCommand({
|
|
21518
|
+
cluster,
|
|
21519
|
+
services: [serviceName]
|
|
21520
|
+
}));
|
|
21521
|
+
const services = response.services ?? [];
|
|
21522
|
+
const failures = response.failures ?? [];
|
|
21523
|
+
if (services.length === 0 && failures.length === 1 && failures[0]?.reason === "MISSING") return false;
|
|
21524
|
+
if (failures.length > 0 || services.length !== 1) throw new Error("DescribeServices gave no readable answer for the service name");
|
|
21525
|
+
return services[0].status !== "INACTIVE";
|
|
21526
|
+
}
|
|
21159
21527
|
async settleService(logicalId, serviceRef, cluster, log) {
|
|
21160
21528
|
if (process.env["CDKD_FULL_WAIT"] === "true") {
|
|
21161
21529
|
log.debug(`Waiting for ECS service ${logicalId} to reach steady state...`);
|
|
@@ -22335,6 +22703,7 @@ var ELBv2Provider = class {
|
|
|
22335
22703
|
async createLoadBalancer(logicalId, resourceType, properties, maskSecrets) {
|
|
22336
22704
|
this.logger.debug(`Creating LoadBalancer ${logicalId}`);
|
|
22337
22705
|
const tags = refuseMalformedDesiredTags(properties["Tags"], resourceType, logicalId);
|
|
22706
|
+
let leftBehindArn;
|
|
22338
22707
|
try {
|
|
22339
22708
|
const lbName = sentElbv2Name(properties, logicalId);
|
|
22340
22709
|
const lbAttributes = this.normalizeAttributes(properties["LoadBalancerAttributes"]);
|
|
@@ -22398,6 +22767,7 @@ var ELBv2Provider = class {
|
|
|
22398
22767
|
await this.getClient().send(new DeleteLoadBalancerCommand({ LoadBalancerArn: lbArn }));
|
|
22399
22768
|
this.logger.debug(`Cleaned up partially-created LoadBalancer ${logicalId} (${lbArn}) after wiring failure`);
|
|
22400
22769
|
} catch (cleanupError) {
|
|
22770
|
+
leftBehindArn = lbArn;
|
|
22401
22771
|
this.logger.warn(`Failed to clean up partially-created LoadBalancer ${logicalId} (${lbArn}): ${this.maskErrorMessage(cleanupError, maskSecrets)}. Manual deletion may be required before the next deploy: ${pasteableAwsCommand(maskSecrets)`aws elbv2 delete-load-balancer --load-balancer-arn ${lbArn}`.render()}`);
|
|
22402
22772
|
}
|
|
22403
22773
|
throw markAuxiliaryFailure(innerError, logicalId);
|
|
@@ -22408,7 +22778,9 @@ var ELBv2Provider = class {
|
|
|
22408
22778
|
};
|
|
22409
22779
|
} catch (error) {
|
|
22410
22780
|
const cause = error instanceof Error ? error : void 0;
|
|
22411
|
-
|
|
22781
|
+
const thrown = this.wrapMaskedError(maskerOrIdentity(maskSecrets), error, (text) => new ProvisioningError(`Failed to create LoadBalancer ${logicalId}: ${text}`, resourceType, logicalId, void 0, cause));
|
|
22782
|
+
if (leftBehindArn !== void 0) markCreatedBeforeFailure(thrown, logicalId, resourceType, leftBehindArn);
|
|
22783
|
+
throw thrown;
|
|
22412
22784
|
}
|
|
22413
22785
|
}
|
|
22414
22786
|
async updateLoadBalancer(logicalId, physicalId, resourceType, properties, previousProperties, callerMaskSecrets, fromReadback = false) {
|
|
@@ -22616,6 +22988,7 @@ var ELBv2Provider = class {
|
|
|
22616
22988
|
const tags = refuseMalformedDesiredTags(properties["Tags"], resourceType, logicalId);
|
|
22617
22989
|
const desiredTargets = readTargets(properties["Targets"], "desired");
|
|
22618
22990
|
if (desiredTargets.kind === "malformed") throw markNonRetryable(new ProvisioningError(`Targets of TargetGroup ${logicalId} is not a list of ${TARGETS_WHAT}${targetsSecretCause(desiredTargets)} — the target group was not created`, resourceType, logicalId));
|
|
22991
|
+
let leftBehindArn;
|
|
22619
22992
|
try {
|
|
22620
22993
|
const matcher = properties["Matcher"];
|
|
22621
22994
|
const tgName = sentElbv2Name(properties, logicalId);
|
|
@@ -22666,6 +23039,7 @@ var ELBv2Provider = class {
|
|
|
22666
23039
|
await this.getClient().send(new DeleteTargetGroupCommand({ TargetGroupArn: tgArn }));
|
|
22667
23040
|
this.logger.debug(`Cleaned up partially-created TargetGroup ${logicalId} (${tgArn}) after wiring failure`);
|
|
22668
23041
|
} catch (cleanupError) {
|
|
23042
|
+
leftBehindArn = tgArn;
|
|
22669
23043
|
this.logger.warn(`Failed to clean up partially-created TargetGroup ${logicalId} (${tgArn}): ${this.maskErrorMessage(cleanupError, maskSecrets)}. Manual deletion may be required before the next deploy: ${pasteableAwsCommand(maskSecrets)`aws elbv2 delete-target-group --target-group-arn ${tgArn}`.render()}`);
|
|
22670
23044
|
}
|
|
22671
23045
|
throw markAuxiliaryFailure(innerError, logicalId);
|
|
@@ -22676,7 +23050,9 @@ var ELBv2Provider = class {
|
|
|
22676
23050
|
};
|
|
22677
23051
|
} catch (error) {
|
|
22678
23052
|
const cause = error instanceof Error ? error : void 0;
|
|
22679
|
-
|
|
23053
|
+
const thrown = this.wrapMaskedError(maskerOrIdentity(maskSecrets), error, (text) => new ProvisioningError(`Failed to create TargetGroup ${logicalId}: ${text}`, resourceType, logicalId, void 0, cause));
|
|
23054
|
+
if (leftBehindArn !== void 0) markCreatedBeforeFailure(thrown, logicalId, resourceType, leftBehindArn);
|
|
23055
|
+
throw thrown;
|
|
22680
23056
|
}
|
|
22681
23057
|
}
|
|
22682
23058
|
async updateTargetGroup(logicalId, physicalId, resourceType, properties, previousProperties, callerMaskSecrets, fromReadback = false) {
|
|
@@ -22774,14 +23150,30 @@ var ELBv2Provider = class {
|
|
|
22774
23150
|
throw new ProvisioningError(`Failed to delete TargetGroup ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, physicalId, cause);
|
|
22775
23151
|
}
|
|
22776
23152
|
}
|
|
23153
|
+
async listenerPortHeld(loadBalancerArn, port) {
|
|
23154
|
+
let marker;
|
|
23155
|
+
for (let page = 0; page < 100; page++) {
|
|
23156
|
+
const response = await this.getClient().send(new DescribeListenersCommand({
|
|
23157
|
+
LoadBalancerArn: loadBalancerArn,
|
|
23158
|
+
...marker !== void 0 && { Marker: marker }
|
|
23159
|
+
}));
|
|
23160
|
+
if ((response.Listeners ?? []).some((l) => l.Port === port)) return true;
|
|
23161
|
+
if (!response.NextMarker) return false;
|
|
23162
|
+
marker = response.NextMarker;
|
|
23163
|
+
}
|
|
23164
|
+
throw new Error("DescribeListeners did not finish paging");
|
|
23165
|
+
}
|
|
22777
23166
|
async createListener(logicalId, resourceType, properties, maskSecrets) {
|
|
22778
23167
|
this.logger.debug(`Creating Listener ${logicalId}`);
|
|
22779
23168
|
const tags = refuseMalformedDesiredTags(properties["Tags"], resourceType, logicalId);
|
|
23169
|
+
let leftBehindArn;
|
|
22780
23170
|
try {
|
|
22781
23171
|
const defaultActions = this.convertActions(properties["DefaultActions"]);
|
|
22782
23172
|
const certificates = this.convertCertificates(properties["Certificates"]);
|
|
22783
23173
|
const alpnPolicy = properties["AlpnPolicy"];
|
|
22784
23174
|
const mutualAuth = properties["MutualAuthentication"];
|
|
23175
|
+
const listenerAttributes = this.normalizeAttributes(properties["ListenerAttributes"]);
|
|
23176
|
+
const heldBefore = listenerAttributes.length > 0 ? await nameHeldBefore(() => this.listenerPortHeld(properties["LoadBalancerArn"], properties["Port"] !== void 0 ? Number(properties["Port"]) : void 0), (error) => hasErrorName(error, ["LoadBalancerNotFoundException"])) : "free";
|
|
22785
23177
|
const listener = (await this.getClient().send(new CreateListenerCommand({
|
|
22786
23178
|
LoadBalancerArn: properties["LoadBalancerArn"],
|
|
22787
23179
|
Port: properties["Port"] !== void 0 ? Number(properties["Port"]) : void 0,
|
|
@@ -22797,7 +23189,6 @@ var ELBv2Provider = class {
|
|
|
22797
23189
|
const listenerArn = listener.ListenerArn;
|
|
22798
23190
|
this.logger.debug(`Successfully created Listener ${logicalId}: ${listenerArn}`);
|
|
22799
23191
|
try {
|
|
22800
|
-
const listenerAttributes = this.normalizeAttributes(properties["ListenerAttributes"]);
|
|
22801
23192
|
if (listenerAttributes.length > 0) {
|
|
22802
23193
|
const watch = startInterruptWatch(`ELBv2 Listener ${logicalId} attributes`);
|
|
22803
23194
|
try {
|
|
@@ -22815,12 +23206,17 @@ var ELBv2Provider = class {
|
|
|
22815
23206
|
this.logger.debug(`Applied ${listenerAttributes.length} ListenerAttribute(s) for ${logicalId}`);
|
|
22816
23207
|
}
|
|
22817
23208
|
} catch (innerError) {
|
|
22818
|
-
if (
|
|
23209
|
+
if (heldBefore !== "free") {
|
|
23210
|
+
this.logger.warn(maskerOrIdentity(maskSecrets)(skippedCleanupText(heldBefore, `Listener ${logicalId} (${listenerArn})`, pasteableAwsCommand(maskSecrets)`aws elbv2 delete-listener --listener-arn ${listenerArn}`.render())));
|
|
23211
|
+
throw markAuxiliaryFailure(innerError, logicalId);
|
|
23212
|
+
}
|
|
23213
|
+
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, on a first-time 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()}`));
|
|
22819
23214
|
try {
|
|
22820
23215
|
await this.getClient().send(new DeleteListenerCommand({ ListenerArn: listenerArn }));
|
|
22821
23216
|
this.logger.debug(`Cleaned up partially-created Listener ${logicalId} (${listenerArn}) after attributes-wiring failure`);
|
|
22822
23217
|
} catch (cleanupError) {
|
|
22823
|
-
|
|
23218
|
+
leftBehindArn = listenerArn;
|
|
23219
|
+
this.logger.warn(`Failed to clean up partially-created Listener ${logicalId} (${listenerArn}): ${this.maskErrorMessage(cleanupError, maskSecrets)}. On a first-time create the failed deploy's rollback journal records it for \`cdkd rollback --revert-failed\`; otherwise delete it yourself before the next deploy: ${pasteableAwsCommand(maskSecrets)`aws elbv2 delete-listener --listener-arn ${listenerArn}`.render()}`);
|
|
22824
23220
|
}
|
|
22825
23221
|
throw markAuxiliaryFailure(innerError, logicalId);
|
|
22826
23222
|
}
|
|
@@ -22830,7 +23226,9 @@ var ELBv2Provider = class {
|
|
|
22830
23226
|
};
|
|
22831
23227
|
} catch (error) {
|
|
22832
23228
|
const cause = error instanceof Error ? error : void 0;
|
|
22833
|
-
|
|
23229
|
+
const thrown = this.wrapMaskedError(maskerOrIdentity(maskSecrets), error, (text) => new ProvisioningError(`Failed to create Listener ${logicalId}: ${text}`, resourceType, logicalId, void 0, cause));
|
|
23230
|
+
if (leftBehindArn !== void 0) markCreatedBeforeFailure(thrown, logicalId, resourceType, leftBehindArn);
|
|
23231
|
+
throw thrown;
|
|
22834
23232
|
}
|
|
22835
23233
|
}
|
|
22836
23234
|
async updateListener(logicalId, physicalId, resourceType, properties, previousProperties, maskSecrets, fromReadback = false) {
|
|
@@ -23362,24 +23760,29 @@ var RDSDBProxyProvider = class {
|
|
|
23362
23760
|
let vpcId;
|
|
23363
23761
|
const deadline = Date.now() + POLL_TIMEOUT_MS$1;
|
|
23364
23762
|
let status;
|
|
23365
|
-
|
|
23366
|
-
|
|
23367
|
-
|
|
23368
|
-
|
|
23369
|
-
|
|
23370
|
-
|
|
23371
|
-
|
|
23372
|
-
|
|
23373
|
-
|
|
23763
|
+
try {
|
|
23764
|
+
while (Date.now() < deadline) {
|
|
23765
|
+
try {
|
|
23766
|
+
const proxy = (await client.send(new DescribeDBProxiesCommand({ DBProxyName: dbProxyName }))).DBProxies?.[0];
|
|
23767
|
+
status = proxy?.Status;
|
|
23768
|
+
if (status === "available") {
|
|
23769
|
+
endpoint = proxy?.Endpoint;
|
|
23770
|
+
dbProxyArn = proxy?.DBProxyArn;
|
|
23771
|
+
vpcId = proxy?.VpcId;
|
|
23772
|
+
break;
|
|
23773
|
+
}
|
|
23774
|
+
if (status === "incompatible-network" || status === "insufficient-resource-limits") throw new ProvisioningError(`DBProxy ${dbProxyName} entered terminal failure state: ${status}`, resourceType, logicalId, dbProxyName);
|
|
23775
|
+
} catch (error) {
|
|
23776
|
+
if (error instanceof DBProxyNotFoundFault) {} else if (error instanceof ProvisioningError) throw error;
|
|
23777
|
+
else throw this.wrapError(error, "CREATE (poll)", resourceType, logicalId, dbProxyName);
|
|
23374
23778
|
}
|
|
23375
|
-
|
|
23376
|
-
} catch (error) {
|
|
23377
|
-
if (error instanceof DBProxyNotFoundFault) {} else if (error instanceof ProvisioningError) throw error;
|
|
23378
|
-
else throw this.wrapError(error, "CREATE (poll)", resourceType, logicalId, dbProxyName);
|
|
23779
|
+
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS$1));
|
|
23379
23780
|
}
|
|
23380
|
-
|
|
23781
|
+
if (!endpoint || !dbProxyArn) throw new ProvisioningError(`Timed out waiting for DBProxy ${dbProxyName} to become available (last status: ${status ?? "unknown"})`, resourceType, logicalId, dbProxyName);
|
|
23782
|
+
} catch (error) {
|
|
23783
|
+
markCreatedBeforeFailure(error, logicalId, resourceType, dbProxyName);
|
|
23784
|
+
throw error;
|
|
23381
23785
|
}
|
|
23382
|
-
if (!endpoint || !dbProxyArn) throw new ProvisioningError(`Timed out waiting for DBProxy ${dbProxyName} to become available (last status: ${status ?? "unknown"})`, resourceType, logicalId, dbProxyName);
|
|
23383
23786
|
return {
|
|
23384
23787
|
physicalId: dbProxyName,
|
|
23385
23788
|
attributes: definedAttributes({
|
|
@@ -23660,26 +24063,31 @@ var RDSDBProxyEndpointProvider = class {
|
|
|
23660
24063
|
let vpcId;
|
|
23661
24064
|
const deadline = Date.now() + POLL_TIMEOUT_MS;
|
|
23662
24065
|
let status;
|
|
23663
|
-
|
|
23664
|
-
|
|
23665
|
-
|
|
23666
|
-
|
|
23667
|
-
|
|
23668
|
-
|
|
23669
|
-
|
|
23670
|
-
|
|
23671
|
-
|
|
23672
|
-
|
|
23673
|
-
|
|
24066
|
+
try {
|
|
24067
|
+
while (Date.now() < deadline) {
|
|
24068
|
+
try {
|
|
24069
|
+
const ep = (await client.send(new DescribeDBProxyEndpointsCommand({ DBProxyEndpointName: dbProxyEndpointName }))).DBProxyEndpoints?.[0];
|
|
24070
|
+
status = ep?.Status;
|
|
24071
|
+
this.logger.debug(`DBProxyEndpoint ${dbProxyEndpointName} poll: status=${status ?? "not-yet-visible"}`);
|
|
24072
|
+
if (status === "available") {
|
|
24073
|
+
endpoint = ep?.Endpoint;
|
|
24074
|
+
arn = ep?.DBProxyEndpointArn;
|
|
24075
|
+
isDefault = ep?.IsDefault;
|
|
24076
|
+
vpcId = ep?.VpcId;
|
|
24077
|
+
break;
|
|
24078
|
+
}
|
|
24079
|
+
if (status === "incompatible-network" || status === "insufficient-resource-limits") throw new ProvisioningError(`DBProxyEndpoint ${dbProxyEndpointName} entered terminal failure state: ${status}`, resourceType, logicalId, dbProxyEndpointName);
|
|
24080
|
+
} catch (error) {
|
|
24081
|
+
if (error instanceof DBProxyEndpointNotFoundFault || error instanceof DBProxyNotFoundFault) {} else if (error instanceof ProvisioningError) throw error;
|
|
24082
|
+
else throw this.wrapError(error, "CREATE (poll)", resourceType, logicalId, dbProxyEndpointName);
|
|
23674
24083
|
}
|
|
23675
|
-
|
|
23676
|
-
} catch (error) {
|
|
23677
|
-
if (error instanceof DBProxyEndpointNotFoundFault || error instanceof DBProxyNotFoundFault) {} else if (error instanceof ProvisioningError) throw error;
|
|
23678
|
-
else throw this.wrapError(error, "CREATE (poll)", resourceType, logicalId, dbProxyEndpointName);
|
|
24084
|
+
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
|
|
23679
24085
|
}
|
|
23680
|
-
|
|
24086
|
+
if (!endpoint || !arn) throw new ProvisioningError(`Timed out waiting for DBProxyEndpoint ${dbProxyEndpointName} to become available (last status: ${status ?? "unknown"})`, resourceType, logicalId, dbProxyEndpointName);
|
|
24087
|
+
} catch (error) {
|
|
24088
|
+
markCreatedBeforeFailure(error, logicalId, resourceType, dbProxyEndpointName);
|
|
24089
|
+
throw error;
|
|
23681
24090
|
}
|
|
23682
|
-
if (!endpoint || !arn) throw new ProvisioningError(`Timed out waiting for DBProxyEndpoint ${dbProxyEndpointName} to become available (last status: ${status ?? "unknown"})`, resourceType, logicalId, dbProxyEndpointName);
|
|
23683
24091
|
return {
|
|
23684
24092
|
physicalId: dbProxyEndpointName,
|
|
23685
24093
|
attributes: definedAttributes({
|
|
@@ -24004,7 +24412,11 @@ var RDSDBProxyTargetGroupProvider = class {
|
|
|
24004
24412
|
Tags: tags
|
|
24005
24413
|
}));
|
|
24006
24414
|
} catch (error) {
|
|
24007
|
-
throw await this.retireRegistrationAfterFailedCreate(this.wrapError(error, "CREATE (add tags)", resourceType, logicalId, void 0), dbProxyName, targetGroupName, dbClusterIdentifiers, dbInstanceIdentifiers, context?.maskSecrets
|
|
24415
|
+
throw await this.retireRegistrationAfterFailedCreate(this.wrapError(error, "CREATE (add tags)", resourceType, logicalId, void 0), dbProxyName, targetGroupName, dbClusterIdentifiers, dbInstanceIdentifiers, context?.maskSecrets, {
|
|
24416
|
+
logicalId,
|
|
24417
|
+
resourceType,
|
|
24418
|
+
physicalId: targetGroupArn
|
|
24419
|
+
});
|
|
24008
24420
|
}
|
|
24009
24421
|
return {
|
|
24010
24422
|
physicalId: targetGroupArn,
|
|
@@ -24036,8 +24448,10 @@ var RDSDBProxyTargetGroupProvider = class {
|
|
|
24036
24448
|
}
|
|
24037
24449
|
refuseMalformedDesiredTags(properties["Tags"], resourceType, logicalId, physicalId, "Tags", DBPROXY_TAGS_WHAT, DBPROXY_TAG_OPTIONS);
|
|
24038
24450
|
if (context?.expectedRegion) assertRegionMatch(await this.getClient().config.region(), context.expectedRegion, resourceType, logicalId, physicalId, "pre-update");
|
|
24039
|
-
|
|
24040
|
-
|
|
24451
|
+
const replayCheck = exemptedBySecretReference.length === 0 && context?.replayingState === true;
|
|
24452
|
+
if (exemptedBySecretReference.length > 0 || replayCheck) {
|
|
24453
|
+
const fields = replayCheck ? "DBProxyName / TargetGroupName" : exemptedBySecretReference.join(" / ");
|
|
24454
|
+
const provenance = replayCheck ? "replayed by a rollback, which resolves any secret they come from again" : "secret-derived";
|
|
24041
24455
|
const base = context?.maskSecrets ?? ((t) => t);
|
|
24042
24456
|
const maskNames = (text) => {
|
|
24043
24457
|
let out = text;
|
|
@@ -24060,11 +24474,11 @@ var RDSDBProxyTargetGroupProvider = class {
|
|
|
24060
24474
|
}
|
|
24061
24475
|
if (lookupFailure !== void 0) {
|
|
24062
24476
|
const failureClass = lookupFailure instanceof Error && lookupFailure.name !== "" ? lookupFailure.name : "an unreadable failure";
|
|
24063
|
-
const refusal = new ProvisioningError(`${fields} of AWS::RDS::DBProxyTargetGroup ${logicalId} is
|
|
24477
|
+
const refusal = new ProvisioningError(`${fields} of AWS::RDS::DBProxyTargetGroup ${logicalId} is ${provenance}, and whether ${replayCheck ? "the names still address" : "the value its secret resolves to still addresses"} the recorded target group could not be confirmed (${maskNames(failureClass)}) — re-run once the lookup can succeed`, resourceType, logicalId, physicalId, lookupFailure instanceof Error ? lookupFailure : void 0);
|
|
24064
24478
|
markRedactedCause(refusal);
|
|
24065
24479
|
throw refusal;
|
|
24066
24480
|
}
|
|
24067
|
-
if (liveArn !== physicalId) throw new
|
|
24481
|
+
if (liveArn !== physicalId) throw markNonRetryable(new ProvisioningError(`${fields} of AWS::RDS::DBProxyTargetGroup ${logicalId} is ${provenance}, and ${replayCheck ? "the names now address" : "the value its secret now resolves to addresses"} ${liveArn === void 0 ? "no target group" : "a different target group"} (${replayCheck ? "the proxy, or a secret its name comes from, may have changed" : "the secret may have been rotated"}). cdkd does not move registered targets to another proxy, with or without --replace: ${replayCheck ? "make the names address the proxy that holds this target group again" : "restore the secret's value to the proxy that holds this target group"}`, resourceType, logicalId, physicalId));
|
|
24068
24482
|
}
|
|
24069
24483
|
const next = readTargetLists({
|
|
24070
24484
|
DBClusterIdentifiers: properties["DBClusterIdentifiers"],
|
|
@@ -24298,7 +24712,7 @@ var RDSDBProxyTargetGroupProvider = class {
|
|
|
24298
24712
|
}
|
|
24299
24713
|
return result;
|
|
24300
24714
|
}
|
|
24301
|
-
async retireRegistrationAfterFailedCreate(original, dbProxyName, targetGroupName, dbClusterIdentifiers, dbInstanceIdentifiers, maskSecrets) {
|
|
24715
|
+
async retireRegistrationAfterFailedCreate(original, dbProxyName, targetGroupName, dbClusterIdentifiers, dbInstanceIdentifiers, maskSecrets, leftBehind) {
|
|
24302
24716
|
const clusters = dbClusterIdentifiers?.length ? dbClusterIdentifiers : void 0;
|
|
24303
24717
|
const instances = dbInstanceIdentifiers?.length ? dbInstanceIdentifiers : void 0;
|
|
24304
24718
|
if (!clusters && !instances) return original;
|
|
@@ -24322,6 +24736,7 @@ var RDSDBProxyTargetGroupProvider = class {
|
|
|
24322
24736
|
for (const id of instances) targets = aws`${targets} ${id}`;
|
|
24323
24737
|
}
|
|
24324
24738
|
original.message += ` The targets this create registered are still registered and could not be deregistered (${describeAwsFailure(cleanupError).detail}). Manual cleanup: ` + aws`aws rds deregister-db-proxy-targets --db-proxy-name ${dbProxyName} --target-group-name ${targetGroupName}${targets}`.render();
|
|
24739
|
+
if (leftBehind) markCreatedBeforeFailure(original, leftBehind.logicalId, leftBehind.resourceType, leftBehind.physicalId);
|
|
24325
24740
|
return original;
|
|
24326
24741
|
}
|
|
24327
24742
|
}
|
|
@@ -24508,8 +24923,9 @@ var DocDBProvider = class {
|
|
|
24508
24923
|
maxLength: 63,
|
|
24509
24924
|
lowercase: true
|
|
24510
24925
|
});
|
|
24926
|
+
let clusterCreated = false;
|
|
24511
24927
|
try {
|
|
24512
|
-
|
|
24928
|
+
const response = await this.getClient().send(new CreateDBClusterCommand$1({
|
|
24513
24929
|
DBClusterIdentifier: dbClusterIdentifier,
|
|
24514
24930
|
Engine: "docdb",
|
|
24515
24931
|
EngineVersion: properties["EngineVersion"],
|
|
@@ -24526,7 +24942,9 @@ var DocDBProvider = class {
|
|
|
24526
24942
|
DBClusterParameterGroupName: properties["DBClusterParameterGroupName"],
|
|
24527
24943
|
DeletionProtection: properties["DeletionProtection"],
|
|
24528
24944
|
...tags.length > 0 && { Tags: tags }
|
|
24529
|
-
}))
|
|
24945
|
+
}));
|
|
24946
|
+
clusterCreated = true;
|
|
24947
|
+
if (!response.DBCluster) throw new Error("CreateDBCluster did not return DBCluster");
|
|
24530
24948
|
this.logger.debug(`Successfully created DocDB DBCluster ${logicalId}: ${dbClusterIdentifier}`);
|
|
24531
24949
|
if (process.env["CDKD_NO_WAIT"] !== "true") await this.waitForClusterAvailable(dbClusterIdentifier);
|
|
24532
24950
|
return {
|
|
@@ -24534,9 +24952,9 @@ var DocDBProvider = class {
|
|
|
24534
24952
|
attributes: clusterAttributes(await this.describeDBCluster(dbClusterIdentifier))
|
|
24535
24953
|
};
|
|
24536
24954
|
} catch (error) {
|
|
24537
|
-
|
|
24538
|
-
|
|
24539
|
-
throw
|
|
24955
|
+
const thrown = error instanceof ProvisioningError ? error : new ProvisioningError(`Failed to create DocDB DBCluster ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, dbClusterIdentifier, error instanceof Error ? error : void 0);
|
|
24956
|
+
if (clusterCreated) markCreatedBeforeFailure(thrown, logicalId, resourceType, dbClusterIdentifier);
|
|
24957
|
+
throw thrown;
|
|
24540
24958
|
}
|
|
24541
24959
|
}
|
|
24542
24960
|
async updateDBCluster(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
@@ -24651,8 +25069,9 @@ var DocDBProvider = class {
|
|
|
24651
25069
|
maxLength: 63,
|
|
24652
25070
|
lowercase: true
|
|
24653
25071
|
});
|
|
25072
|
+
let instanceCreated = false;
|
|
24654
25073
|
try {
|
|
24655
|
-
|
|
25074
|
+
const response = await this.getClient().send(new CreateDBInstanceCommand$1({
|
|
24656
25075
|
DBInstanceIdentifier: dbInstanceIdentifier,
|
|
24657
25076
|
DBInstanceClass: properties["DBInstanceClass"],
|
|
24658
25077
|
Engine: "docdb",
|
|
@@ -24661,7 +25080,9 @@ var DocDBProvider = class {
|
|
|
24661
25080
|
PreferredMaintenanceWindow: properties["PreferredMaintenanceWindow"],
|
|
24662
25081
|
AutoMinorVersionUpgrade: properties["AutoMinorVersionUpgrade"],
|
|
24663
25082
|
...tags.length > 0 && { Tags: tags }
|
|
24664
|
-
}))
|
|
25083
|
+
}));
|
|
25084
|
+
instanceCreated = true;
|
|
25085
|
+
if (!response.DBInstance) throw new Error("CreateDBInstance did not return DBInstance");
|
|
24665
25086
|
this.logger.debug(`Successfully created DocDB DBInstance ${logicalId}: ${dbInstanceIdentifier}`);
|
|
24666
25087
|
if (process.env["CDKD_NO_WAIT"] !== "true") await this.waitForInstanceAvailable(dbInstanceIdentifier);
|
|
24667
25088
|
return {
|
|
@@ -24669,9 +25090,9 @@ var DocDBProvider = class {
|
|
|
24669
25090
|
attributes: instanceAttributes(await this.describeDBInstance(dbInstanceIdentifier))
|
|
24670
25091
|
};
|
|
24671
25092
|
} catch (error) {
|
|
24672
|
-
|
|
24673
|
-
|
|
24674
|
-
throw
|
|
25093
|
+
const thrown = error instanceof ProvisioningError ? error : new ProvisioningError(`Failed to create DocDB DBInstance ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, dbInstanceIdentifier, error instanceof Error ? error : void 0);
|
|
25094
|
+
if (instanceCreated) markCreatedBeforeFailure(thrown, logicalId, resourceType, dbInstanceIdentifier);
|
|
25095
|
+
throw thrown;
|
|
24675
25096
|
}
|
|
24676
25097
|
}
|
|
24677
25098
|
async updateDBInstance(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
@@ -25143,6 +25564,8 @@ var Route53Provider = class {
|
|
|
25143
25564
|
const name = properties["Name"];
|
|
25144
25565
|
if (!name) throw new ProvisioningError(`Name is required for hosted zone ${logicalId}`, resourceType, logicalId);
|
|
25145
25566
|
let zoneCreated = false;
|
|
25567
|
+
let createdZoneId;
|
|
25568
|
+
let zoneRolledBack = false;
|
|
25146
25569
|
try {
|
|
25147
25570
|
const hostedZoneConfig = properties["HostedZoneConfig"];
|
|
25148
25571
|
const createComment = readConfigString(hostedZoneConfig, "Comment", "", "AWS::Route53::HostedZone HostedZoneConfig");
|
|
@@ -25169,6 +25592,7 @@ var Route53Provider = class {
|
|
|
25169
25592
|
const hostedZone = response.HostedZone;
|
|
25170
25593
|
if (!hostedZone?.Id) throw new Error("CreateHostedZone did not return HostedZone.Id");
|
|
25171
25594
|
const zoneId = hostedZone.Id.replace("/hostedzone/", "");
|
|
25595
|
+
createdZoneId = zoneId;
|
|
25172
25596
|
if (vpcs && vpcs.length > 1) for (let i = 1; i < vpcs.length; i++) {
|
|
25173
25597
|
const additionalVpc = vpcs[i];
|
|
25174
25598
|
this.logger.debug(`Associating additional VPC ${String(additionalVpc["VPCId"])} with hosted zone ${zoneId}`);
|
|
@@ -25192,6 +25616,7 @@ var Route53Provider = class {
|
|
|
25192
25616
|
try {
|
|
25193
25617
|
await this.deleteQueryLoggingConfigForZone(zoneId, logicalId);
|
|
25194
25618
|
await this.getClient().send(new DeleteHostedZoneCommand({ Id: zoneId }));
|
|
25619
|
+
zoneRolledBack = true;
|
|
25195
25620
|
callerReferenceToken.release();
|
|
25196
25621
|
} catch (deleteError) {
|
|
25197
25622
|
this.logger.warn(`Best-effort rollback DeleteHostedZone for ${zoneId} also failed: ${describeAwsFailure(deleteError).detail} — operator may need to clean up the orphan zone`);
|
|
@@ -25211,9 +25636,9 @@ var Route53Provider = class {
|
|
|
25211
25636
|
};
|
|
25212
25637
|
} catch (error) {
|
|
25213
25638
|
if (zoneCreated) markAuxiliaryFailure(error, logicalId);
|
|
25214
|
-
|
|
25215
|
-
|
|
25216
|
-
throw
|
|
25639
|
+
const thrown = error instanceof ProvisioningError ? error : new ProvisioningError(`Failed to create hosted zone ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, void 0, error instanceof Error ? error : void 0);
|
|
25640
|
+
if (createdZoneId !== void 0 && !zoneRolledBack) markCreatedBeforeFailure(thrown, logicalId, resourceType, createdZoneId);
|
|
25641
|
+
throw thrown;
|
|
25217
25642
|
}
|
|
25218
25643
|
}
|
|
25219
25644
|
async createOrAdoptHostedZone(input) {
|
|
@@ -26853,17 +27278,21 @@ var CognitoUserPoolProvider = class {
|
|
|
26853
27278
|
...effectiveProperties !== properties ? { effectiveProperties } : {}
|
|
26854
27279
|
};
|
|
26855
27280
|
} catch (error) {
|
|
27281
|
+
let poolLeftBehind = false;
|
|
26856
27282
|
if (createdUserPoolId) {
|
|
26857
27283
|
markAuxiliaryFailure(error, logicalId);
|
|
26858
27284
|
try {
|
|
26859
27285
|
await this.getClient().send(new DeleteUserPoolCommand({ UserPoolId: createdUserPoolId }));
|
|
26860
27286
|
this.logger.debug(`Rolled back partially-created Cognito User Pool ${createdUserPoolId}`);
|
|
26861
27287
|
} catch (rollbackError) {
|
|
27288
|
+
poolLeftBehind = true;
|
|
26862
27289
|
this.logger.warn(`Failed to roll back partially-created Cognito User Pool ${createdUserPoolId}: ${describeAwsFailure(rollbackError).detail}`);
|
|
26863
27290
|
}
|
|
26864
27291
|
}
|
|
26865
27292
|
const cause = error instanceof Error ? error : void 0;
|
|
26866
|
-
|
|
27293
|
+
const thrown = new ProvisioningError(`Failed to create Cognito User Pool ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, poolName, cause);
|
|
27294
|
+
if (poolLeftBehind && createdUserPoolId) markCreatedBeforeFailure(thrown, logicalId, resourceType, createdUserPoolId);
|
|
27295
|
+
throw thrown;
|
|
26867
27296
|
}
|
|
26868
27297
|
}
|
|
26869
27298
|
async regionArg(aws) {
|
|
@@ -27584,6 +28013,7 @@ var ElastiCacheProvider = class {
|
|
|
27584
28013
|
maxLength: 40,
|
|
27585
28014
|
lowercase: true
|
|
27586
28015
|
});
|
|
28016
|
+
let clusterCreated = false;
|
|
27587
28017
|
try {
|
|
27588
28018
|
await this.getClient().send(new CreateCacheClusterCommand({
|
|
27589
28019
|
CacheClusterId: cacheClusterId,
|
|
@@ -27610,6 +28040,7 @@ var ElastiCacheProvider = class {
|
|
|
27610
28040
|
TransitEncryptionEnabled: properties["TransitEncryptionEnabled"],
|
|
27611
28041
|
...tags.length > 0 && { Tags: tags }
|
|
27612
28042
|
}));
|
|
28043
|
+
clusterCreated = true;
|
|
27613
28044
|
this.logger.debug(`Successfully created CacheCluster ${logicalId}: ${cacheClusterId}`);
|
|
27614
28045
|
if (process.env["CDKD_NO_WAIT"] !== "true") await this.waitForClusterAvailable(cacheClusterId);
|
|
27615
28046
|
const described = await this.describeCacheCluster(cacheClusterId);
|
|
@@ -27629,9 +28060,9 @@ var ElastiCacheProvider = class {
|
|
|
27629
28060
|
attributes
|
|
27630
28061
|
};
|
|
27631
28062
|
} catch (error) {
|
|
27632
|
-
|
|
27633
|
-
|
|
27634
|
-
throw
|
|
28063
|
+
const thrown = error instanceof ProvisioningError ? error : new ProvisioningError(`Failed to create CacheCluster ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, cacheClusterId, error instanceof Error ? error : void 0);
|
|
28064
|
+
if (clusterCreated) markCreatedBeforeFailure(thrown, logicalId, resourceType, cacheClusterId);
|
|
28065
|
+
throw thrown;
|
|
27635
28066
|
}
|
|
27636
28067
|
}
|
|
27637
28068
|
async updateCacheCluster(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
@@ -28036,6 +28467,7 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
|
|
|
28036
28467
|
if (!name) throw new ProvisioningError(`Name is required for PrivateDnsNamespace ${logicalId}`, resourceType, logicalId);
|
|
28037
28468
|
if (!vpc) throw new ProvisioningError(`Vpc is required for PrivateDnsNamespace ${logicalId}`, resourceType, logicalId);
|
|
28038
28469
|
const inputProperties = this.extractSoaTtlProperties(properties);
|
|
28470
|
+
let createdNamespaceId;
|
|
28039
28471
|
try {
|
|
28040
28472
|
const operationId = (await client.send(new CreatePrivateDnsNamespaceCommand({
|
|
28041
28473
|
Name: name,
|
|
@@ -28046,6 +28478,7 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
|
|
|
28046
28478
|
}))).OperationId;
|
|
28047
28479
|
if (!operationId) throw new Error("CreatePrivateDnsNamespace did not return OperationId");
|
|
28048
28480
|
const namespaceId = await this.pollOperation(operationId, logicalId, resourceType, maskSecrets);
|
|
28481
|
+
if (namespaceId !== operationId) createdNamespaceId = namespaceId;
|
|
28049
28482
|
const arn = await this.buildNamespaceArn(namespaceId);
|
|
28050
28483
|
this.logger.debug(`Successfully created private DNS namespace ${logicalId}: ${namespaceId}`);
|
|
28051
28484
|
return {
|
|
@@ -28056,9 +28489,10 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
|
|
|
28056
28489
|
}
|
|
28057
28490
|
};
|
|
28058
28491
|
} catch (error) {
|
|
28059
|
-
if (error instanceof ProvisioningError) throw error;
|
|
28060
28492
|
const cause = error instanceof Error ? error : void 0;
|
|
28061
|
-
|
|
28493
|
+
const thrown = error instanceof ProvisioningError ? error : this.wrapMaskedError(maskerOrIdentity(maskSecrets), error, (text) => new ProvisioningError(`Failed to create private DNS namespace ${logicalId}: ${text}`, resourceType, logicalId, void 0, cause));
|
|
28494
|
+
if (createdNamespaceId) markCreatedBeforeFailure(thrown, logicalId, resourceType, createdNamespaceId);
|
|
28495
|
+
throw thrown;
|
|
28062
28496
|
}
|
|
28063
28497
|
}
|
|
28064
28498
|
async updateNamespace(logicalId, physicalId, resourceType, properties, previousProperties, maskSecrets) {
|
|
@@ -28131,6 +28565,7 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
|
|
|
28131
28565
|
const name = properties["Name"];
|
|
28132
28566
|
const description = properties["Description"];
|
|
28133
28567
|
if (!name) throw new ProvisioningError(`Name is required for HttpNamespace ${logicalId}`, resourceType, logicalId);
|
|
28568
|
+
let createdNamespaceId;
|
|
28134
28569
|
try {
|
|
28135
28570
|
const operationId = (await client.send(new CreateHttpNamespaceCommand({
|
|
28136
28571
|
Name: name,
|
|
@@ -28139,6 +28574,7 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
|
|
|
28139
28574
|
}))).OperationId;
|
|
28140
28575
|
if (!operationId) throw new Error("CreateHttpNamespace did not return OperationId");
|
|
28141
28576
|
const namespaceId = await this.pollOperation(operationId, logicalId, resourceType, maskSecrets);
|
|
28577
|
+
if (namespaceId !== operationId) createdNamespaceId = namespaceId;
|
|
28142
28578
|
const arn = await this.resolveNamespaceArn(namespaceId);
|
|
28143
28579
|
this.logger.debug(`Successfully created HTTP namespace ${logicalId}: ${namespaceId}`);
|
|
28144
28580
|
return {
|
|
@@ -28149,9 +28585,10 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
|
|
|
28149
28585
|
}
|
|
28150
28586
|
};
|
|
28151
28587
|
} catch (error) {
|
|
28152
|
-
if (error instanceof ProvisioningError) throw error;
|
|
28153
28588
|
const cause = error instanceof Error ? error : void 0;
|
|
28154
|
-
|
|
28589
|
+
const thrown = error instanceof ProvisioningError ? error : this.wrapMaskedError(maskerOrIdentity(maskSecrets), error, (text) => new ProvisioningError(`Failed to create HTTP namespace ${logicalId}: ${text}`, resourceType, logicalId, void 0, cause));
|
|
28590
|
+
if (createdNamespaceId) markCreatedBeforeFailure(thrown, logicalId, resourceType, createdNamespaceId);
|
|
28591
|
+
throw thrown;
|
|
28155
28592
|
}
|
|
28156
28593
|
}
|
|
28157
28594
|
async updateHttpNamespace(logicalId, physicalId, resourceType, properties, previousProperties, maskSecrets) {
|
|
@@ -28188,6 +28625,7 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
|
|
|
28188
28625
|
const description = properties["Description"];
|
|
28189
28626
|
if (!name) throw new ProvisioningError(`Name is required for PublicDnsNamespace ${logicalId}`, resourceType, logicalId);
|
|
28190
28627
|
const inputProperties = this.extractSoaTtlProperties(properties);
|
|
28628
|
+
let createdNamespaceId;
|
|
28191
28629
|
try {
|
|
28192
28630
|
const operationId = (await client.send(new CreatePublicDnsNamespaceCommand({
|
|
28193
28631
|
Name: name,
|
|
@@ -28197,6 +28635,7 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
|
|
|
28197
28635
|
}))).OperationId;
|
|
28198
28636
|
if (!operationId) throw new Error("CreatePublicDnsNamespace did not return OperationId");
|
|
28199
28637
|
const namespaceId = await this.pollOperation(operationId, logicalId, resourceType, maskSecrets);
|
|
28638
|
+
if (namespaceId !== operationId) createdNamespaceId = namespaceId;
|
|
28200
28639
|
let arn;
|
|
28201
28640
|
let hostedZoneId;
|
|
28202
28641
|
try {
|
|
@@ -28217,9 +28656,10 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
|
|
|
28217
28656
|
}
|
|
28218
28657
|
};
|
|
28219
28658
|
} catch (error) {
|
|
28220
|
-
if (error instanceof ProvisioningError) throw error;
|
|
28221
28659
|
const cause = error instanceof Error ? error : void 0;
|
|
28222
|
-
|
|
28660
|
+
const thrown = error instanceof ProvisioningError ? error : this.wrapMaskedError(maskerOrIdentity(maskSecrets), error, (text) => new ProvisioningError(`Failed to create public DNS namespace ${logicalId}: ${text}`, resourceType, logicalId, void 0, cause));
|
|
28661
|
+
if (createdNamespaceId) markCreatedBeforeFailure(thrown, logicalId, resourceType, createdNamespaceId);
|
|
28662
|
+
throw thrown;
|
|
28223
28663
|
}
|
|
28224
28664
|
}
|
|
28225
28665
|
async updatePublicDnsNamespace(logicalId, physicalId, resourceType, properties, previousProperties, maskSecrets) {
|
|
@@ -28263,6 +28703,7 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
|
|
|
28263
28703
|
const healthCheckConfig = properties["HealthCheckConfig"];
|
|
28264
28704
|
const type = properties["Type"];
|
|
28265
28705
|
if (!name) throw new ProvisioningError(`Name is required for ServiceDiscovery Service ${logicalId}`, resourceType, logicalId);
|
|
28706
|
+
let leftBehindServiceId;
|
|
28266
28707
|
try {
|
|
28267
28708
|
const service = (await client.send(new CreateServiceCommand$1({
|
|
28268
28709
|
Name: name,
|
|
@@ -28276,6 +28717,7 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
|
|
|
28276
28717
|
}))).Service;
|
|
28277
28718
|
if (!service || !service.Id) throw new Error("CreateService did not return Service ID");
|
|
28278
28719
|
const serviceId = service.Id;
|
|
28720
|
+
leftBehindServiceId = serviceId;
|
|
28279
28721
|
this.logger.debug(`Successfully created service discovery service ${logicalId}: ${serviceId}`);
|
|
28280
28722
|
try {
|
|
28281
28723
|
const attrs = this.normalizeServiceAttributes(properties["ServiceAttributes"]);
|
|
@@ -28296,12 +28738,13 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
|
|
|
28296
28738
|
this.logger.debug(`Applied ${Object.keys(attrs).length} ServiceAttribute(s) for ${logicalId}`);
|
|
28297
28739
|
}
|
|
28298
28740
|
} catch (innerError) {
|
|
28299
|
-
if (isInterruptedWaitError(innerError)) this.logger.warn(maskerOrIdentity(maskSecrets)(`Interrupted after creating ServiceDiscovery Service ${logicalId} (${serviceId}) but before its ServiceAttributes were applied. Nothing in cdkd state refers to it, so cdkd is deleting it now — left behind it would fail the next deploy on a name collision AND block deletion of its namespace with ResourceInUse. If that delete
|
|
28741
|
+
if (isInterruptedWaitError(innerError)) this.logger.warn(maskerOrIdentity(maskSecrets)(`Interrupted after creating ServiceDiscovery Service ${logicalId} (${serviceId}) but before its ServiceAttributes were applied. Nothing in cdkd state refers to it, so cdkd is deleting it now — left behind it would fail the next deploy on a name collision AND block deletion of its namespace with ResourceInUse. If that delete fails, on a first-time create the failed deploy's rollback journal records it for \`cdkd rollback --revert-failed\`; otherwise remove it yourself: ${pasteableAwsCommand(maskSecrets)`aws servicediscovery delete-service --id ${serviceId}`.render()}`));
|
|
28300
28742
|
try {
|
|
28301
28743
|
await client.send(new DeleteServiceCommand$1({ Id: serviceId }));
|
|
28744
|
+
leftBehindServiceId = void 0;
|
|
28302
28745
|
this.logger.debug(`Cleaned up partially-created ServiceDiscovery Service ${logicalId} (${serviceId}) after ServiceAttributes wiring failure`);
|
|
28303
28746
|
} catch (cleanupError) {
|
|
28304
|
-
this.logger.warn(`Failed to clean up partially-created ServiceDiscovery Service ${logicalId} (${serviceId}) after ServiceAttributes wiring failure: ${this.maskErrorMessage(cleanupError, maskSecrets)}.
|
|
28747
|
+
this.logger.warn(`Failed to clean up partially-created ServiceDiscovery Service ${logicalId} (${serviceId}) after ServiceAttributes wiring failure: ${this.maskErrorMessage(cleanupError, maskSecrets)}. On a first-time create the failed deploy's rollback journal records it for \`cdkd rollback --revert-failed\`; otherwise delete it yourself before the next deploy: ${pasteableAwsCommand(maskSecrets)`aws servicediscovery delete-service --id ${serviceId}`.render()}`);
|
|
28305
28748
|
}
|
|
28306
28749
|
throw markAuxiliaryFailure(innerError, logicalId);
|
|
28307
28750
|
}
|
|
@@ -28315,7 +28758,9 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
|
|
|
28315
28758
|
};
|
|
28316
28759
|
} catch (error) {
|
|
28317
28760
|
const cause = error instanceof Error ? error : void 0;
|
|
28318
|
-
|
|
28761
|
+
const thrown = this.wrapMaskedError(maskerOrIdentity(maskSecrets), error, (text) => new ProvisioningError(`Failed to create service discovery service ${logicalId}: ${text}`, resourceType, logicalId, void 0, cause));
|
|
28762
|
+
if (leftBehindServiceId) markCreatedBeforeFailure(thrown, logicalId, resourceType, leftBehindServiceId);
|
|
28763
|
+
throw thrown;
|
|
28319
28764
|
}
|
|
28320
28765
|
}
|
|
28321
28766
|
async updateService(logicalId, physicalId, resourceType, properties, previousProperties, maskSecrets) {
|
|
@@ -29625,17 +30070,21 @@ var AppSyncProvider = class {
|
|
|
29625
30070
|
...envRecord && { effectiveProperties: this.withEnvironmentVariablesRecord(properties, envRecord) }
|
|
29626
30071
|
};
|
|
29627
30072
|
} catch (error) {
|
|
30073
|
+
let apiLeftBehind = false;
|
|
29628
30074
|
if (createdApiId) {
|
|
29629
30075
|
markAuxiliaryFailure(error, logicalId);
|
|
29630
30076
|
try {
|
|
29631
30077
|
await this.getClient().send(new DeleteGraphqlApiCommand({ apiId: createdApiId }));
|
|
29632
30078
|
this.logger.debug(`Rolled back partially-created GraphQL API ${createdApiId}`);
|
|
29633
30079
|
} catch (rollbackError) {
|
|
30080
|
+
apiLeftBehind = true;
|
|
29634
30081
|
this.logger.warn(`Failed to roll back partially-created GraphQL API ${createdApiId}: ${describeAwsFailure(rollbackError).detail}`);
|
|
29635
30082
|
}
|
|
29636
30083
|
}
|
|
29637
30084
|
const cause = error instanceof Error ? error : void 0;
|
|
29638
|
-
|
|
30085
|
+
const thrown = new ProvisioningError(`Failed to create GraphQL API ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, void 0, cause);
|
|
30086
|
+
if (apiLeftBehind && createdApiId) markCreatedBeforeFailure(thrown, logicalId, resourceType, createdApiId);
|
|
30087
|
+
throw thrown;
|
|
29639
30088
|
}
|
|
29640
30089
|
}
|
|
29641
30090
|
async regionArg(aws) {
|
|
@@ -32558,10 +33007,12 @@ var KMSProvider = class {
|
|
|
32558
33007
|
markAuxiliaryFailure(error, logicalId);
|
|
32559
33008
|
const aws = pasteableAwsCommand();
|
|
32560
33009
|
const region = await this.regionArg(aws);
|
|
32561
|
-
this.logger.warn(safeMsg`KMS key ${createdKeyId} was created for ${logicalId}, but a follow-up call failed. A retry of this create reuses that key instead of creating another, so do not delete it while the deploy is still retrying.
|
|
33010
|
+
this.logger.warn(safeMsg`KMS key ${createdKeyId} was created for ${logicalId}, but a follow-up call failed. A retry of this create reuses that key instead of creating another, so do not delete it while the deploy is still retrying. If the deploy then FAILS on a first-time create, its rollback journal records the key for \`cdkd rollback --revert-failed\` to schedule its deletion; otherwise schedule it yourself with: ${aws`aws kms schedule-key-deletion --key-id ${createdKeyId}${region} --pending-window-in-days 7`.render()}`);
|
|
32562
33011
|
}
|
|
32563
33012
|
const cause = error instanceof Error ? error : void 0;
|
|
32564
|
-
|
|
33013
|
+
const thrown = new ProvisioningError(`Failed to create KMS Key ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, void 0, cause);
|
|
33014
|
+
if (createdKeyId !== void 0) markCreatedBeforeFailure(thrown, logicalId, resourceType, createdKeyId);
|
|
33015
|
+
throw thrown;
|
|
32565
33016
|
}
|
|
32566
33017
|
}
|
|
32567
33018
|
async regionArg(aws) {
|
|
@@ -33123,6 +33574,7 @@ var BudgetsBudgetProvider = class {
|
|
|
33123
33574
|
const accountId = await this.resolveAccountId();
|
|
33124
33575
|
const notifications = this.toSdkNotificationsWithSubscribers(lists.NotificationsWithSubscribers);
|
|
33125
33576
|
const resourceTags = this.toSdkResourceTags(lists.ResourceTags);
|
|
33577
|
+
const arn = await this.budgetArn(accountId, name);
|
|
33126
33578
|
await this.getClient().send(new CreateBudgetCommand({
|
|
33127
33579
|
AccountId: accountId,
|
|
33128
33580
|
Budget: this.toSdkBudget(properties["Budget"], name, logicalId, resourceType, mask),
|
|
@@ -33132,7 +33584,7 @@ var BudgetsBudgetProvider = class {
|
|
|
33132
33584
|
this.logger.debug(`Successfully created budget ${logicalId}: ${name}`);
|
|
33133
33585
|
return {
|
|
33134
33586
|
physicalId: name,
|
|
33135
|
-
attributes: { Arn:
|
|
33587
|
+
attributes: { Arn: arn }
|
|
33136
33588
|
};
|
|
33137
33589
|
} catch (error) {
|
|
33138
33590
|
if (error instanceof ProvisioningError) throw error;
|
|
@@ -33498,6 +33950,30 @@ function readMaxRecordSize(value, mask) {
|
|
|
33498
33950
|
reason: `AWS::Kinesis::Stream MaxRecordSizeInKiB must be a number, got ${JSON.stringify(maskDeep(value, mask))}`
|
|
33499
33951
|
};
|
|
33500
33952
|
}
|
|
33953
|
+
function readRetentionHours(value, mask) {
|
|
33954
|
+
if (value == null) return { kind: "absent" };
|
|
33955
|
+
if (typeof value === "number" && Number.isFinite(value)) return {
|
|
33956
|
+
kind: "usable",
|
|
33957
|
+
hours: value
|
|
33958
|
+
};
|
|
33959
|
+
if (typeof value === "string" && value.trim() !== "" && Number.isFinite(Number(value))) return {
|
|
33960
|
+
kind: "usable",
|
|
33961
|
+
hours: Number(value)
|
|
33962
|
+
};
|
|
33963
|
+
return {
|
|
33964
|
+
kind: "unusable",
|
|
33965
|
+
reason: `AWS::Kinesis::Stream RetentionPeriodHours must be a number, got ${JSON.stringify(maskDeep(value, mask))}`
|
|
33966
|
+
};
|
|
33967
|
+
}
|
|
33968
|
+
function readEncryptionKeyId(value, mask) {
|
|
33969
|
+
if (!isKmsEncryption(value)) return { kind: "absent" };
|
|
33970
|
+
const keyId = value?.["KeyId"];
|
|
33971
|
+
if (typeof keyId === "string" && keyId.trim() !== "") return { kind: "usable" };
|
|
33972
|
+
return {
|
|
33973
|
+
kind: "unusable",
|
|
33974
|
+
reason: `AWS::Kinesis::Stream StreamEncryption selects KMS but KeyId is not a non-empty string, got ${JSON.stringify(maskDeep(keyId, mask)) ?? "undefined"}`
|
|
33975
|
+
};
|
|
33976
|
+
}
|
|
33501
33977
|
function comparableRecordSize(value, mask) {
|
|
33502
33978
|
const read = readMaxRecordSize(value, mask);
|
|
33503
33979
|
return read.kind === "usable" ? read.size : void 0;
|
|
@@ -33541,6 +34017,13 @@ var KinesisStreamProvider = class {
|
|
|
33541
34017
|
if (context?.replayingState === true) warn(`${maxRecordRead.reason}. Replaying a state record, so ${streamName} is created with AWS's default maximum record size rather than refusing the restore`);
|
|
33542
34018
|
else throw new ProvisioningError(maxRecordRead.reason, resourceType, logicalId, streamName);
|
|
33543
34019
|
}
|
|
34020
|
+
const retentionRead = readRetentionHours(properties["RetentionPeriodHours"], mask);
|
|
34021
|
+
if (retentionRead.kind === "unusable") {
|
|
34022
|
+
if (context?.replayingState !== true) throw new ProvisioningError(retentionRead.reason, resourceType, logicalId, streamName);
|
|
34023
|
+
warn(`${retentionRead.reason}. Replaying a state record, so the retention period is left at AWS's default on ${streamName} rather than refusing the restore`);
|
|
34024
|
+
}
|
|
34025
|
+
const encryptionRead = readEncryptionKeyId(properties["StreamEncryption"], mask);
|
|
34026
|
+
if (encryptionRead.kind === "unusable") throw new ProvisioningError(encryptionRead.reason, resourceType, logicalId, streamName);
|
|
33544
34027
|
let streamCreated = false;
|
|
33545
34028
|
try {
|
|
33546
34029
|
const streamModeDetails = properties["StreamModeDetails"];
|
|
@@ -33562,7 +34045,7 @@ var KinesisStreamProvider = class {
|
|
|
33562
34045
|
StreamName: streamName,
|
|
33563
34046
|
Tags: tags
|
|
33564
34047
|
}));
|
|
33565
|
-
const retentionPeriodHours =
|
|
34048
|
+
const retentionPeriodHours = retentionRead.kind === "usable" ? retentionRead.hours : void 0;
|
|
33566
34049
|
if (retentionPeriodHours !== void 0 && retentionPeriodHours !== 24) {
|
|
33567
34050
|
this.logger.debug(`Setting retention period to ${retentionPeriodHours} hours for ${streamName}`);
|
|
33568
34051
|
if (retentionPeriodHours > 24) await this.getClient().send(new IncreaseStreamRetentionPeriodCommand({
|
|
@@ -33604,9 +34087,9 @@ var KinesisStreamProvider = class {
|
|
|
33604
34087
|
};
|
|
33605
34088
|
} catch (error) {
|
|
33606
34089
|
if (streamCreated) markAuxiliaryFailure(error, logicalId);
|
|
33607
|
-
|
|
33608
|
-
|
|
33609
|
-
throw
|
|
34090
|
+
const thrown = error instanceof ProvisioningError ? error : new ProvisioningError(`Failed to create Kinesis stream ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, streamName, error instanceof Error ? error : void 0);
|
|
34091
|
+
if (streamCreated) markCreatedBeforeFailure(thrown, logicalId, resourceType, streamName);
|
|
34092
|
+
throw thrown;
|
|
33610
34093
|
}
|
|
33611
34094
|
}
|
|
33612
34095
|
async update(logicalId, physicalId, resourceType, properties, previousProperties, context) {
|
|
@@ -33614,6 +34097,10 @@ var KinesisStreamProvider = class {
|
|
|
33614
34097
|
const warn = (message) => this.logger.warn(mask(message));
|
|
33615
34098
|
this.logger.debug(`Updating Kinesis stream ${logicalId}: ${physicalId}`);
|
|
33616
34099
|
refuseMalformedDesiredTags(properties["Tags"], resourceType, logicalId, physicalId);
|
|
34100
|
+
const desiredRetention = readRetentionHours(properties["RetentionPeriodHours"], mask);
|
|
34101
|
+
if (desiredRetention.kind === "unusable" && context?.replayingState !== true) throw new ProvisioningError(desiredRetention.reason, resourceType, logicalId, physicalId);
|
|
34102
|
+
if (desiredRetention.kind === "unusable") warn(`${desiredRetention.reason}. Replaying a state record, so the retention period of ${physicalId} is left as it is rather than refusing the restore`);
|
|
34103
|
+
const previousRetention = readRetentionHours(previousProperties["RetentionPeriodHours"], mask);
|
|
33617
34104
|
try {
|
|
33618
34105
|
const streamModeDetails = properties["StreamModeDetails"];
|
|
33619
34106
|
const streamMode = readConfigString(streamModeDetails, "StreamMode", "PROVISIONED", "AWS::Kinesis::Stream StreamModeDetails");
|
|
@@ -33641,11 +34128,9 @@ var KinesisStreamProvider = class {
|
|
|
33641
34128
|
await this.waitForStreamActive(physicalId);
|
|
33642
34129
|
}
|
|
33643
34130
|
}
|
|
33644
|
-
const
|
|
33645
|
-
const
|
|
33646
|
-
|
|
33647
|
-
const effectiveOldRetention = oldRetention ?? 24;
|
|
33648
|
-
if (effectiveNewRetention !== effectiveOldRetention) {
|
|
34131
|
+
const effectiveNewRetention = desiredRetention.kind === "usable" ? desiredRetention.hours ?? 24 : 24;
|
|
34132
|
+
const effectiveOldRetention = previousRetention.kind === "usable" ? previousRetention.hours ?? 24 : 24;
|
|
34133
|
+
if (desiredRetention.kind !== "unusable" && effectiveNewRetention !== effectiveOldRetention) {
|
|
33649
34134
|
this.logger.debug(`Updating retention period for ${physicalId}: from ${effectiveOldRetention} to ${effectiveNewRetention}`);
|
|
33650
34135
|
if (effectiveNewRetention > effectiveOldRetention) await this.getClient().send(new IncreaseStreamRetentionPeriodCommand({
|
|
33651
34136
|
StreamName: physicalId,
|
|
@@ -33920,6 +34405,7 @@ var KinesisStreamConsumerProvider = class {
|
|
|
33920
34405
|
if (!streamArn) throw new ProvisioningError("AWS::Kinesis::StreamConsumer requires StreamARN", resourceType, logicalId);
|
|
33921
34406
|
this.logger.debug(`Registering Kinesis stream consumer ${logicalId}: ${consumerName}`);
|
|
33922
34407
|
const tagMap = tagListToMap(tagList);
|
|
34408
|
+
let createdArn;
|
|
33923
34409
|
try {
|
|
33924
34410
|
const consumer = (await this.getClient().send(new RegisterStreamConsumerCommand({
|
|
33925
34411
|
StreamARN: streamArn,
|
|
@@ -33928,6 +34414,7 @@ var KinesisStreamConsumerProvider = class {
|
|
|
33928
34414
|
}))).Consumer;
|
|
33929
34415
|
if (!consumer?.ConsumerARN || !consumer.ConsumerName) throw new ProvisioningError("RegisterStreamConsumer did not return ConsumerARN/ConsumerName", resourceType, logicalId);
|
|
33930
34416
|
const consumerArn = consumer.ConsumerARN;
|
|
34417
|
+
createdArn = consumerArn;
|
|
33931
34418
|
await this.waitForConsumerActive(consumerArn);
|
|
33932
34419
|
this.logger.debug(`Successfully registered Kinesis stream consumer ${logicalId}`);
|
|
33933
34420
|
return {
|
|
@@ -33942,9 +34429,9 @@ var KinesisStreamConsumerProvider = class {
|
|
|
33942
34429
|
}
|
|
33943
34430
|
};
|
|
33944
34431
|
} catch (error) {
|
|
33945
|
-
|
|
33946
|
-
|
|
33947
|
-
throw
|
|
34432
|
+
const thrown = error instanceof ProvisioningError ? error : new ProvisioningError(`Failed to register Kinesis stream consumer ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, consumerName, error instanceof Error ? error : void 0);
|
|
34433
|
+
if (createdArn) markCreatedBeforeFailure(thrown, logicalId, resourceType, createdArn);
|
|
34434
|
+
throw thrown;
|
|
33948
34435
|
}
|
|
33949
34436
|
}
|
|
33950
34437
|
async update(logicalId, physicalId, resourceType, properties, previousProperties, context) {
|
|
@@ -34088,6 +34575,33 @@ function tagListToMap(tags) {
|
|
|
34088
34575
|
|
|
34089
34576
|
//#endregion
|
|
34090
34577
|
//#region src/provisioning/providers/scheduler-schedule-provider.ts
|
|
34578
|
+
const RECORDED_CREATION_DATE_KEY = "cdkd:CreationDate";
|
|
34579
|
+
function recordedCreationDate(attributes) {
|
|
34580
|
+
const value = attributes?.[RECORDED_CREATION_DATE_KEY];
|
|
34581
|
+
if (typeof value !== "string" || value === "") return void 0;
|
|
34582
|
+
const parsed = new Date(value);
|
|
34583
|
+
return !Number.isNaN(parsed.getTime()) && parsed.toISOString() === value ? value : void 0;
|
|
34584
|
+
}
|
|
34585
|
+
const RECORDED_ONLY = maskerOrIdentity(void 0);
|
|
34586
|
+
function usableRecorded(value) {
|
|
34587
|
+
return typeof value === "string" && value !== "" && !isSecretDerivedValue(value, RECORDED_ONLY) ? value : void 0;
|
|
34588
|
+
}
|
|
34589
|
+
function recordedTarget(properties) {
|
|
34590
|
+
const target = properties?.["Target"];
|
|
34591
|
+
const fields = typeof target === "object" && target !== null && !Array.isArray(target) ? target : {};
|
|
34592
|
+
return {
|
|
34593
|
+
targetArn: usableRecorded(fields["Arn"]),
|
|
34594
|
+
roleArn: usableRecorded(fields["RoleArn"])
|
|
34595
|
+
};
|
|
34596
|
+
}
|
|
34597
|
+
function sameRecordedDate(live, recorded) {
|
|
34598
|
+
return live.creation !== void 0 && live.creation === recorded.creation;
|
|
34599
|
+
}
|
|
34600
|
+
function sameRecordedIdentity(live, recorded) {
|
|
34601
|
+
return sameRecordedDate(live, recorded) && (recorded.targetArn === void 0 || live.targetArn === recorded.targetArn) && (recorded.roleArn === void 0 || live.roleArn === recorded.roleArn);
|
|
34602
|
+
}
|
|
34603
|
+
const NO_REGION_FOR_SCHEDULE_SEARCH_SKIP_REASON = "secret-derived group and no recorded region — no delete issued";
|
|
34604
|
+
const AMBIGUOUS_SCHEDULE_SKIP_REASON = "schedule matches the recorded date but not its target — no delete issued";
|
|
34091
34605
|
function groupShown(group) {
|
|
34092
34606
|
return group === "***" ? group : plainOrDescribed(group, "group name");
|
|
34093
34607
|
}
|
|
@@ -34200,20 +34714,97 @@ var SchedulerScheduleProvider = class {
|
|
|
34200
34714
|
...groupName && { GroupName: groupName },
|
|
34201
34715
|
...this.toSdkFields(properties)
|
|
34202
34716
|
}));
|
|
34717
|
+
const creationDate = await this.creationDateBestEffort(logicalId, name, groupName);
|
|
34203
34718
|
return {
|
|
34204
34719
|
physicalId: name,
|
|
34205
|
-
attributes:
|
|
34720
|
+
attributes: {
|
|
34721
|
+
...response.ScheduleArn && { Arn: response.ScheduleArn },
|
|
34722
|
+
...creationDate !== void 0 && { ["cdkd:CreationDate"]: creationDate }
|
|
34723
|
+
}
|
|
34206
34724
|
};
|
|
34207
34725
|
} catch (error) {
|
|
34208
34726
|
const cause = error instanceof Error ? error : void 0;
|
|
34209
34727
|
throw new ProvisioningError(`Failed to create Schedule ${logicalId}: ${cause?.message ?? String(error)}`, resourceType, logicalId, void 0, cause);
|
|
34210
34728
|
}
|
|
34211
34729
|
}
|
|
34730
|
+
async readIdentity(name, groupName) {
|
|
34731
|
+
const response = await this.getClient().send(new GetScheduleCommand({
|
|
34732
|
+
Name: name,
|
|
34733
|
+
...groupName && { GroupName: groupName }
|
|
34734
|
+
}));
|
|
34735
|
+
const date = response.CreationDate;
|
|
34736
|
+
const text = (value) => typeof value === "string" && value !== "" ? value : void 0;
|
|
34737
|
+
return {
|
|
34738
|
+
creation: date instanceof Date && !Number.isNaN(date.getTime()) ? date.toISOString() : void 0,
|
|
34739
|
+
targetArn: text(response.Target?.Arn),
|
|
34740
|
+
roleArn: text(response.Target?.RoleArn)
|
|
34741
|
+
};
|
|
34742
|
+
}
|
|
34743
|
+
sleep(ms) {
|
|
34744
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
34745
|
+
}
|
|
34746
|
+
readBackDelaysMs = [500, 1e3];
|
|
34747
|
+
async creationDateBestEffort(logicalId, name, groupName) {
|
|
34748
|
+
for (let attempt = 0;; attempt++) try {
|
|
34749
|
+
return (await this.readIdentity(name, groupName)).creation;
|
|
34750
|
+
} catch (error) {
|
|
34751
|
+
const transient = error instanceof ResourceNotFoundException$11 || isThrottlingError(error);
|
|
34752
|
+
const delay = this.readBackDelaysMs[attempt];
|
|
34753
|
+
if (transient && delay !== void 0) {
|
|
34754
|
+
await this.sleep(delay);
|
|
34755
|
+
continue;
|
|
34756
|
+
}
|
|
34757
|
+
const failureClass = error instanceof Error && error.name !== "" ? error.name : "an unreadable failure";
|
|
34758
|
+
this.logger.debug(safeMsg`Could not read the creation date of Schedule ${logicalId} (${failureClass}); none is recorded`);
|
|
34759
|
+
return;
|
|
34760
|
+
}
|
|
34761
|
+
}
|
|
34762
|
+
wrapUnconfirmedGroupError(logicalId, physicalId, resourceType, error, mask) {
|
|
34763
|
+
const failureClass = error instanceof Error && error.name !== "" ? error.name : "an unreadable failure";
|
|
34764
|
+
return markRedactedCause(new ProvisioningError(`Whether the group the GroupName of Schedule ${logicalId} resolves to still holds this schedule could not be confirmed (${mask(failureClass)}) — re-run once the lookup can succeed`, resourceType, logicalId, physicalId, error instanceof Error ? error : void 0));
|
|
34765
|
+
}
|
|
34766
|
+
refuseUnconfirmed(logicalId, physicalId, resourceType, finding, secretDerived, remedy) {
|
|
34767
|
+
throw markNonRetryable(new ProvisioningError(`${secretDerived ? `GroupName of Schedule ${logicalId} is secret-derived, and the group its secret now resolves to` : `The group of Schedule ${logicalId}`} ${finding}${secretDerived ? " (the secret may have been rotated)" : ""}, so nothing is written to it, with or without --replace: ${remedy}`, resourceType, logicalId, physicalId));
|
|
34768
|
+
}
|
|
34769
|
+
async confirmRecordedSchedule(logicalId, physicalId, resourceType, groupName, recorded, mask) {
|
|
34770
|
+
if (recorded.creation === void 0) return "undated";
|
|
34771
|
+
let live;
|
|
34772
|
+
try {
|
|
34773
|
+
live = await this.readIdentity(physicalId, groupName);
|
|
34774
|
+
} catch (error) {
|
|
34775
|
+
if (error instanceof ResourceNotFoundException$11) return "absent";
|
|
34776
|
+
throw this.wrapUnconfirmedGroupError(logicalId, physicalId, resourceType, error, mask);
|
|
34777
|
+
}
|
|
34778
|
+
if (sameRecordedDate(live, recorded) && !sameRecordedIdentity(live, recorded)) this.refuseUnconfirmed(logicalId, physicalId, resourceType, "holds a schedule of this name that carries the recorded creation date but not the recorded target or role (edited outside cdkd?)", false, "restore them, or drop the record with `cdkd orphan <construct path>` and deploy again");
|
|
34779
|
+
if (!sameRecordedIdentity(live, recorded)) this.refuseUnconfirmed(logicalId, physicalId, resourceType, "holds a different schedule of this name (its creation date is not the one cdkd recorded)", true, "restore the secret's value to the schedule's group");
|
|
34780
|
+
return "confirmed";
|
|
34781
|
+
}
|
|
34782
|
+
referenceRepointed(desiredGroup, recordedGroup) {
|
|
34783
|
+
const bag = getCurrentResourceSecrets();
|
|
34784
|
+
if (bag === void 0 || typeof desiredGroup !== "string") return false;
|
|
34785
|
+
if (typeof recordedGroup !== "string" || !recordedGroup.includes("{{resolve:")) return false;
|
|
34786
|
+
return redactSecretsForState(desiredGroup, bag) !== recordedGroup;
|
|
34787
|
+
}
|
|
34212
34788
|
async update(logicalId, physicalId, resourceType, properties, previousProperties, context) {
|
|
34213
34789
|
const groupName = this.groupNameOf(properties);
|
|
34214
34790
|
const previousGroupName = this.groupNameOf(previousProperties);
|
|
34215
34791
|
const mask = maskerOrIdentity(context?.maskSecrets);
|
|
34216
|
-
|
|
34792
|
+
const recorded = {
|
|
34793
|
+
creation: recordedCreationDate(context?.recordedAttributes),
|
|
34794
|
+
...recordedTarget(previousProperties)
|
|
34795
|
+
};
|
|
34796
|
+
const replaying = context?.replayingState === true;
|
|
34797
|
+
const desiredSecretDerived = isSecretDerivedValue(properties["GroupName"], mask);
|
|
34798
|
+
let confirmedMove = false;
|
|
34799
|
+
if (groupName !== previousGroupName && isSecretDerivedValue(previousProperties["GroupName"], RECORDED_ONLY) && desiredSecretDerived) {
|
|
34800
|
+
const verdict = await this.confirmRecordedSchedule(logicalId, physicalId, resourceType, groupName, recorded, mask);
|
|
34801
|
+
if (verdict === "undated") this.refuseUnconfirmed(logicalId, physicalId, resourceType, "cannot be confirmed to hold this schedule: its state record predates the creation date cdkd now records", true, "delete the schedule by hand (`aws scheduler delete-schedule`), drop its record with `cdkd orphan <construct path>`, and deploy again, which records the date");
|
|
34802
|
+
if (verdict === "absent" && !this.referenceRepointed(groupName, previousProperties["GroupName"])) this.refuseUnconfirmed(logicalId, physicalId, resourceType, "holds no schedule of this name", true, "restore the secret's value to the schedule's group; if the schedule was deleted outside cdkd, drop its record with `cdkd orphan <construct path>` and deploy again");
|
|
34803
|
+
confirmedMove = verdict === "confirmed";
|
|
34804
|
+
} else if (groupName === previousGroupName && replaying && recorded.creation !== void 0 && desiredSecretDerived) {
|
|
34805
|
+
if (await this.confirmRecordedSchedule(logicalId, physicalId, resourceType, groupName, recorded, mask) !== "confirmed") this.refuseUnconfirmed(logicalId, physicalId, resourceType, "holds no schedule of this name", true, "restore the secret's value to the schedule's group, then re-run the rollback");
|
|
34806
|
+
}
|
|
34807
|
+
if (groupName !== previousGroupName && !confirmedMove) throw new ResourceUpdateNotSupportedError(resourceType, logicalId, `GroupName addresses the schedule (from ${groupShown(mask(previousGroupName ?? "default"))} to ${groupShown(mask(groupName ?? "default"))}); re-run with \`cdkd deploy --replace\` to recreate it in the new group (--replace is a boolean flag and takes no resource id; it applies to every resource in the run whose in-place update is refused)`);
|
|
34217
34808
|
this.logger.debug(mask(`Updating Schedule ${logicalId}: ${mask(physicalId)}${groupName ? ` (group: ${mask(groupName)})` : ""}`));
|
|
34218
34809
|
try {
|
|
34219
34810
|
const input = {
|
|
@@ -34222,10 +34813,14 @@ var SchedulerScheduleProvider = class {
|
|
|
34222
34813
|
...this.toSdkFields(properties)
|
|
34223
34814
|
};
|
|
34224
34815
|
const response = await this.getClient().send(new UpdateScheduleCommand(input));
|
|
34816
|
+
const creationDate = replaying || desiredSecretDerived ? recorded.creation : await this.creationDateBestEffort(logicalId, physicalId, groupName) ?? recorded.creation;
|
|
34225
34817
|
return {
|
|
34226
34818
|
physicalId,
|
|
34227
34819
|
wasReplaced: false,
|
|
34228
|
-
attributes:
|
|
34820
|
+
attributes: {
|
|
34821
|
+
...response.ScheduleArn && { Arn: response.ScheduleArn },
|
|
34822
|
+
...creationDate !== void 0 && { ["cdkd:CreationDate"]: creationDate }
|
|
34823
|
+
}
|
|
34229
34824
|
};
|
|
34230
34825
|
} catch (error) {
|
|
34231
34826
|
if (error instanceof ResourceUpdateNotSupportedError) throw error;
|
|
@@ -34233,8 +34828,89 @@ var SchedulerScheduleProvider = class {
|
|
|
34233
34828
|
throw new ProvisioningError(`Failed to update Schedule ${logicalId}: ${cause?.message ?? String(error)}`, resourceType, logicalId, physicalId, cause);
|
|
34234
34829
|
}
|
|
34235
34830
|
}
|
|
34831
|
+
async deleteByRecordedIdentity(logicalId, physicalId, resourceType, recorded, context) {
|
|
34832
|
+
if (!context?.expectedRegion) {
|
|
34833
|
+
this.logger.warn(safeMsg`Schedule ${logicalId} is recorded with a secret-derived GroupName and no stack region, so cdkd cannot scope the search for it; skipping deletion and keeping its state record. Delete the schedule by hand, then drop the record with 'cdkd orphan'.`);
|
|
34834
|
+
return {
|
|
34835
|
+
outcome: "skipped",
|
|
34836
|
+
reason: NO_REGION_FOR_SCHEDULE_SEARCH_SKIP_REASON
|
|
34837
|
+
};
|
|
34838
|
+
}
|
|
34839
|
+
assertRegionMatch(await this.getClient().config.region(), context.expectedRegion, resourceType, logicalId, physicalId);
|
|
34840
|
+
const wrapDeleteError = (step, error) => {
|
|
34841
|
+
const failureClass = error instanceof Error && error.name !== "" ? error.name : "an unreadable failure";
|
|
34842
|
+
return markRedactedCause(new ProvisioningError(`Failed to delete Schedule ${logicalId}: its recorded GroupName is secret-derived, and ${step} failed (${failureClass})`, resourceType, logicalId, physicalId, error instanceof Error ? error : void 0));
|
|
34843
|
+
};
|
|
34844
|
+
const findMatches = async () => {
|
|
34845
|
+
const groups = [];
|
|
34846
|
+
try {
|
|
34847
|
+
let nextToken;
|
|
34848
|
+
do {
|
|
34849
|
+
const page = await this.getClient().send(new ListSchedulesCommand({
|
|
34850
|
+
NamePrefix: physicalId,
|
|
34851
|
+
...nextToken !== void 0 && { NextToken: nextToken }
|
|
34852
|
+
}));
|
|
34853
|
+
for (const schedule of page.Schedules ?? []) if (schedule.Name === physicalId && typeof schedule.GroupName === "string") groups.push(schedule.GroupName);
|
|
34854
|
+
nextToken = page.NextToken;
|
|
34855
|
+
} while (nextToken !== void 0 && nextToken !== "");
|
|
34856
|
+
} catch (error) {
|
|
34857
|
+
throw wrapDeleteError("listing the schedules of its name", error);
|
|
34858
|
+
}
|
|
34859
|
+
const matches = [];
|
|
34860
|
+
let datedOnly = 0;
|
|
34861
|
+
for (const group of groups) {
|
|
34862
|
+
let live;
|
|
34863
|
+
try {
|
|
34864
|
+
live = await this.readIdentity(physicalId, group);
|
|
34865
|
+
} catch (error) {
|
|
34866
|
+
if (error instanceof ResourceNotFoundException$11) continue;
|
|
34867
|
+
throw wrapDeleteError("reading a schedule of its name", error);
|
|
34868
|
+
}
|
|
34869
|
+
if (sameRecordedIdentity(live, recorded)) matches.push(group);
|
|
34870
|
+
else if (sameRecordedDate(live, recorded)) datedOnly++;
|
|
34871
|
+
}
|
|
34872
|
+
return {
|
|
34873
|
+
matches,
|
|
34874
|
+
datedOnly
|
|
34875
|
+
};
|
|
34876
|
+
};
|
|
34877
|
+
let found = await findMatches();
|
|
34878
|
+
if (found.matches.length === 0 && found.datedOnly === 0) {
|
|
34879
|
+
await this.sleep(this.readBackDelaysMs[0] ?? 0);
|
|
34880
|
+
found = await findMatches();
|
|
34881
|
+
}
|
|
34882
|
+
const { matches } = found;
|
|
34883
|
+
if (matches.length === 0 && found.datedOnly > 0) {
|
|
34884
|
+
this.logger.warn(safeMsg`Schedule ${logicalId}: a schedule of its name carries the recorded creation date but not the recorded target or role (edited outside cdkd?), so cdkd cannot tell whether it is this one; skipping deletion and keeping its state record. Delete it by hand if it is, then drop the record with 'cdkd orphan'.`);
|
|
34885
|
+
return {
|
|
34886
|
+
outcome: "skipped",
|
|
34887
|
+
reason: AMBIGUOUS_SCHEDULE_SKIP_REASON
|
|
34888
|
+
};
|
|
34889
|
+
}
|
|
34890
|
+
if (matches.length === 0) {
|
|
34891
|
+
this.logger.warn(safeMsg`Schedule ${logicalId}: no schedule of its name carries the creation date cdkd recorded, so it is treated as already deleted and its state record is removed`);
|
|
34892
|
+
return;
|
|
34893
|
+
}
|
|
34894
|
+
if (matches.length > 1) throw markNonRetryable(new ProvisioningError(`Failed to delete Schedule ${logicalId}: its recorded GroupName is secret-derived, and ${matches.length} schedules of its name match the one cdkd recorded, so none is deleted`, resourceType, logicalId, physicalId));
|
|
34895
|
+
try {
|
|
34896
|
+
await this.getClient().send(new DeleteScheduleCommand({
|
|
34897
|
+
Name: physicalId,
|
|
34898
|
+
GroupName: matches[0]
|
|
34899
|
+
}));
|
|
34900
|
+
this.logger.debug(safeMsg`Deleted Schedule ${logicalId} (found by its recorded creation date)`);
|
|
34901
|
+
} catch (error) {
|
|
34902
|
+
if (error instanceof ResourceNotFoundException$11) return;
|
|
34903
|
+
throw wrapDeleteError("the delete", error);
|
|
34904
|
+
}
|
|
34905
|
+
}
|
|
34236
34906
|
async delete(logicalId, physicalId, resourceType, properties, context) {
|
|
34237
|
-
const
|
|
34907
|
+
const redactedFields = redactedDeleteAddressFields({ GroupName: properties?.["GroupName"] });
|
|
34908
|
+
const recordedCreation = recordedCreationDate(context?.recordedAttributes);
|
|
34909
|
+
if (redactedFields.length > 0 && recordedCreation !== void 0) return this.deleteByRecordedIdentity(logicalId, physicalId, resourceType, {
|
|
34910
|
+
creation: recordedCreation,
|
|
34911
|
+
...recordedTarget(properties)
|
|
34912
|
+
}, context);
|
|
34913
|
+
const skip = redactedDeleteAddressSkip(this.logger, logicalId, "Schedule", redactedFields);
|
|
34238
34914
|
if (skip) return skip;
|
|
34239
34915
|
const groupName = this.groupNameOf(properties);
|
|
34240
34916
|
if (properties === void 0) {
|
|
@@ -34310,7 +34986,10 @@ var SchedulerScheduleProvider = class {
|
|
|
34310
34986
|
}));
|
|
34311
34987
|
return {
|
|
34312
34988
|
physicalId: explicit,
|
|
34313
|
-
attributes:
|
|
34989
|
+
attributes: {
|
|
34990
|
+
...response.Arn && { Arn: response.Arn },
|
|
34991
|
+
...response.CreationDate instanceof Date && !Number.isNaN(response.CreationDate.getTime()) && { ["cdkd:CreationDate"]: response.CreationDate.toISOString() }
|
|
34992
|
+
}
|
|
34314
34993
|
};
|
|
34315
34994
|
} catch (error) {
|
|
34316
34995
|
if (error instanceof ResourceNotFoundException$11) return null;
|
|
@@ -34553,7 +35232,7 @@ var PipesPipeProvider = class {
|
|
|
34553
35232
|
try {
|
|
34554
35233
|
settled = await this.waitForSettled(name, logicalId, resourceType, "create", mask);
|
|
34555
35234
|
} catch (error) {
|
|
34556
|
-
throw await this.retireFailedCreate(name, logicalId, error, mask);
|
|
35235
|
+
throw await this.retireFailedCreate(name, logicalId, resourceType, error, mask);
|
|
34557
35236
|
}
|
|
34558
35237
|
return {
|
|
34559
35238
|
physicalId: name,
|
|
@@ -34773,13 +35452,14 @@ var PipesPipeProvider = class {
|
|
|
34773
35452
|
watch.dispose();
|
|
34774
35453
|
}
|
|
34775
35454
|
}
|
|
34776
|
-
async retireFailedCreate(name, logicalId, error, mask) {
|
|
35455
|
+
async retireFailedCreate(name, logicalId, resourceType, error, mask) {
|
|
34777
35456
|
const original = error instanceof Error ? error : new Error(String(error));
|
|
35457
|
+
const leftBehind = () => markCreatedBeforeFailure(original, logicalId, resourceType, name);
|
|
34778
35458
|
const orphaned = async (why) => {
|
|
34779
35459
|
const aws = pasteableAwsCommand(mask);
|
|
34780
35460
|
const command = aws`aws pipes delete-pipe --name ${name}${await orphanCommandRegionArg(this.getClient(), aws)}`;
|
|
34781
|
-
original.message += ` (cdkd could not delete the pipe it had created: ${why}; it
|
|
34782
|
-
return
|
|
35461
|
+
original.message += ` (cdkd could not delete the pipe it had created: ${why}; on a first-time create the failed deploy's rollback journal records it for \`cdkd rollback --revert-failed\`. ` + (command.text !== void 0 ? `Otherwise delete it yourself with: ${command.text})` : `Otherwise delete it yourself from the EventBridge Pipes console.)`);
|
|
35462
|
+
return leftBehind();
|
|
34783
35463
|
};
|
|
34784
35464
|
try {
|
|
34785
35465
|
await this.getClient().send(new DeletePipeCommand({ Name: name }));
|
|
@@ -34822,7 +35502,7 @@ var PipesPipeProvider = class {
|
|
|
34822
35502
|
const describe = aws`aws pipes describe-pipe --name ${name}${region}`;
|
|
34823
35503
|
const remove = aws`aws pipes delete-pipe --name ${name}${region}`;
|
|
34824
35504
|
original.message += " (cdkd asked AWS to delete the pipe it had created but could not confirm the delete progressed; " + (describe.text !== void 0 && remove.text !== void 0 ? `if ${describe.text} still shows it, delete it with: ${remove.text})` : "if the EventBridge Pipes console still shows it, delete it there.)");
|
|
34825
|
-
return
|
|
35505
|
+
return leftBehind();
|
|
34826
35506
|
}
|
|
34827
35507
|
};
|
|
34828
35508
|
|
|
@@ -35055,6 +35735,7 @@ var EFSProvider = class {
|
|
|
35055
35735
|
if (reservation.ledgerStartedThisDeploy) await this.warnOfPreLedgerHolder(logicalId, reservation.base, log);
|
|
35056
35736
|
const tags = properties["FileSystemTags"];
|
|
35057
35737
|
let fileSystemId;
|
|
35738
|
+
let fileSystemLeftBehind = false;
|
|
35058
35739
|
try {
|
|
35059
35740
|
const created = await this.sendCreateFileSystem(logicalId, resourceType, reservation, {
|
|
35060
35741
|
CreationToken: creationToken,
|
|
@@ -35093,12 +35774,14 @@ var EFSProvider = class {
|
|
|
35093
35774
|
this.unconfirmedCreationTokens.delete(creationToken);
|
|
35094
35775
|
log.debug(`Rolled back partially-created EFS FileSystem ${fileSystemId}`);
|
|
35095
35776
|
} catch (cleanupError) {
|
|
35777
|
+
fileSystemLeftBehind = true;
|
|
35096
35778
|
log.warn(`Failed to roll back partially-created EFS FileSystem ${fileSystemId}: ${describeAwsFailure(cleanupError).detail}`);
|
|
35097
35779
|
}
|
|
35098
35780
|
}
|
|
35099
|
-
if (error instanceof ProvisioningError) throw error;
|
|
35100
35781
|
const cause = error instanceof Error ? error : void 0;
|
|
35101
|
-
|
|
35782
|
+
const thrown = error instanceof ProvisioningError ? error : this.wrapMaskedError(log.mask, error, (text) => new ProvisioningError(`Failed to create EFS FileSystem ${logicalId}: ${text}`, resourceType, logicalId, void 0, cause));
|
|
35783
|
+
if (fileSystemLeftBehind && fileSystemId !== void 0) markCreatedBeforeFailure(thrown, logicalId, resourceType, fileSystemId);
|
|
35784
|
+
throw thrown;
|
|
35102
35785
|
}
|
|
35103
35786
|
}
|
|
35104
35787
|
async sendCreateFileSystem(logicalId, resourceType, reservation, input) {
|
|
@@ -35243,12 +35926,14 @@ var EFSProvider = class {
|
|
|
35243
35926
|
const subnetId = properties["SubnetId"];
|
|
35244
35927
|
if (!subnetId) throw new ProvisioningError(`SubnetId is required for EFS MountTarget ${logicalId}`, resourceType, logicalId);
|
|
35245
35928
|
const securityGroups = properties["SecurityGroups"];
|
|
35929
|
+
let createdMountTargetId;
|
|
35246
35930
|
try {
|
|
35247
35931
|
const mountTargetId = (await this.getClient().send(new CreateMountTargetCommand({
|
|
35248
35932
|
FileSystemId: fileSystemId,
|
|
35249
35933
|
SubnetId: subnetId,
|
|
35250
35934
|
SecurityGroups: securityGroups
|
|
35251
35935
|
}))).MountTargetId;
|
|
35936
|
+
createdMountTargetId = mountTargetId;
|
|
35252
35937
|
log.debug(`Created EFS MountTarget ${logicalId}: ${mountTargetId}, waiting for available state`);
|
|
35253
35938
|
await this.waitForMountTargetAvailable(mountTargetId, logicalId, resourceType, log);
|
|
35254
35939
|
log.debug(`Successfully created EFS MountTarget ${logicalId}: ${mountTargetId}`);
|
|
@@ -35257,9 +35942,10 @@ var EFSProvider = class {
|
|
|
35257
35942
|
attributes: {}
|
|
35258
35943
|
};
|
|
35259
35944
|
} catch (error) {
|
|
35260
|
-
if (error instanceof ProvisioningError) throw error;
|
|
35261
35945
|
const cause = error instanceof Error ? error : void 0;
|
|
35262
|
-
|
|
35946
|
+
const thrown = error instanceof ProvisioningError ? error : this.wrapMaskedError(log.mask, error, (text) => new ProvisioningError(`Failed to create EFS MountTarget ${logicalId}: ${text}`, resourceType, logicalId, void 0, cause));
|
|
35947
|
+
if (createdMountTargetId) markCreatedBeforeFailure(thrown, logicalId, resourceType, createdMountTargetId);
|
|
35948
|
+
throw thrown;
|
|
35263
35949
|
}
|
|
35264
35950
|
}
|
|
35265
35951
|
async waitForMountTargetAvailable(mountTargetId, logicalId, resourceType, log) {
|
|
@@ -35799,16 +36485,27 @@ var FSxFileSystemProvider = class {
|
|
|
35799
36485
|
attributes: this.buildAttributes(fs)
|
|
35800
36486
|
};
|
|
35801
36487
|
} catch (error) {
|
|
36488
|
+
let survivorId;
|
|
35802
36489
|
if (fileSystemId !== void 0) try {
|
|
35803
36490
|
await this.getClient().send(new DeleteFileSystemCommand$1({ FileSystemId: fileSystemId }));
|
|
35804
36491
|
this.createTokenFirstSentAt.delete(clientRequestToken);
|
|
35805
36492
|
this.logger.warn(`Rolled back partially-created FSx FileSystem ${fileSystemId}`);
|
|
35806
36493
|
} catch (cleanupError) {
|
|
35807
|
-
|
|
36494
|
+
survivorId = fileSystemId;
|
|
36495
|
+
this.logger.warn(`Failed to roll back partially-created FSx FileSystem ${fileSystemId}: ${describeAwsFailure(cleanupError).detail} — on a first-time create the failed deploy's rollback journal records it for \`cdkd rollback --revert-failed\`; otherwise delete it yourself to stop billing`);
|
|
36496
|
+
}
|
|
36497
|
+
if (error instanceof ProvisioningError) {
|
|
36498
|
+
if (survivorId !== void 0) markCreatedBeforeFailure(error, logicalId, resourceType, survivorId);
|
|
36499
|
+
throw error;
|
|
35808
36500
|
}
|
|
35809
|
-
if (error instanceof ProvisioningError) throw error;
|
|
35810
36501
|
const cause = error instanceof Error ? error : void 0;
|
|
35811
|
-
|
|
36502
|
+
const message = `Failed to create FSx FileSystem ${logicalId}: ${error instanceof Error ? error.message : String(error)}`;
|
|
36503
|
+
if (survivorId !== void 0) {
|
|
36504
|
+
const thrown = new ProvisioningError(message, resourceType, logicalId, void 0, cause);
|
|
36505
|
+
markCreatedBeforeFailure(thrown, logicalId, resourceType, survivorId);
|
|
36506
|
+
throw thrown;
|
|
36507
|
+
}
|
|
36508
|
+
throw new ProvisioningError(message, resourceType, logicalId, void 0, cause);
|
|
35812
36509
|
}
|
|
35813
36510
|
}
|
|
35814
36511
|
toCreateLustreConfiguration(config) {
|
|
@@ -36786,6 +37483,7 @@ var EMRClusterProvider = class {
|
|
|
36786
37483
|
attributes: this.buildAttributes(cluster)
|
|
36787
37484
|
};
|
|
36788
37485
|
} catch (error) {
|
|
37486
|
+
let survivorId;
|
|
36789
37487
|
if (clusterId !== void 0) try {
|
|
36790
37488
|
await this.getClient().send(new SetTerminationProtectionCommand({
|
|
36791
37489
|
JobFlowIds: [clusterId],
|
|
@@ -36794,11 +37492,21 @@ var EMRClusterProvider = class {
|
|
|
36794
37492
|
await this.getClient().send(new TerminateJobFlowsCommand({ JobFlowIds: [clusterId] }));
|
|
36795
37493
|
this.logger.warn(`Rolled back partially-created EMR Cluster ${clusterId}`);
|
|
36796
37494
|
} catch (cleanupError) {
|
|
37495
|
+
survivorId = clusterId;
|
|
36797
37496
|
this.logger.warn(`Failed to roll back partially-created EMR Cluster ${clusterId}: ${describeAwsFailure(cleanupError).detail} — terminate it manually to stop billing`);
|
|
36798
37497
|
}
|
|
36799
|
-
if (error instanceof ProvisioningError)
|
|
37498
|
+
if (error instanceof ProvisioningError) {
|
|
37499
|
+
if (survivorId !== void 0) markCreatedBeforeFailure(error, logicalId, resourceType, survivorId);
|
|
37500
|
+
throw error;
|
|
37501
|
+
}
|
|
36800
37502
|
const cause = error instanceof Error ? error : void 0;
|
|
36801
|
-
|
|
37503
|
+
const message = `Failed to create EMR Cluster ${logicalId}: ${error instanceof Error ? error.message : String(error)}`;
|
|
37504
|
+
if (survivorId !== void 0) {
|
|
37505
|
+
const thrown = new ProvisioningError(message, resourceType, logicalId, void 0, cause);
|
|
37506
|
+
markCreatedBeforeFailure(thrown, logicalId, resourceType, survivorId);
|
|
37507
|
+
throw thrown;
|
|
37508
|
+
}
|
|
37509
|
+
throw new ProvisioningError(message, resourceType, logicalId, void 0, cause);
|
|
36802
37510
|
}
|
|
36803
37511
|
}
|
|
36804
37512
|
toJobFlowInstancesConfig(config) {
|
|
@@ -37382,6 +38090,7 @@ var EMRInstanceGroupConfigProvider = class {
|
|
|
37382
38090
|
const jobFlowId = properties["JobFlowId"];
|
|
37383
38091
|
if (!jobFlowId) throw new ProvisioningError(`EMR InstanceGroupConfig ${logicalId} is missing JobFlowId (the parent cluster id)`, resourceType, logicalId);
|
|
37384
38092
|
this.logger.debug(`Adding EMR instance group ${logicalId} to cluster ${jobFlowId}`);
|
|
38093
|
+
let createdGroupId;
|
|
37385
38094
|
try {
|
|
37386
38095
|
const group = this.toInstanceGroupConfig(properties);
|
|
37387
38096
|
const orphanWindow = addInstanceGroupsLatch.take(logicalId);
|
|
@@ -37424,6 +38133,7 @@ var EMRInstanceGroupConfigProvider = class {
|
|
|
37424
38133
|
}
|
|
37425
38134
|
const groupId = response.InstanceGroupIds?.[0];
|
|
37426
38135
|
if (groupId) groupsCreatedByThisProcess.add(groupId);
|
|
38136
|
+
createdGroupId = groupId;
|
|
37427
38137
|
if (!groupId) throw new ProvisioningError(`EMR AddInstanceGroups for ${logicalId} returned no instance group id`, resourceType, logicalId);
|
|
37428
38138
|
await this.waitForGroupReady(jobFlowId, groupId, logicalId, resourceType, toNumber$1(properties["InstanceCount"]) ?? 0);
|
|
37429
38139
|
this.logger.debug(`Successfully added EMR instance group ${logicalId}: ${groupId}`);
|
|
@@ -37435,9 +38145,9 @@ var EMRInstanceGroupConfigProvider = class {
|
|
|
37435
38145
|
}
|
|
37436
38146
|
};
|
|
37437
38147
|
} catch (error) {
|
|
37438
|
-
|
|
37439
|
-
|
|
37440
|
-
throw
|
|
38148
|
+
const thrown = error instanceof ProvisioningError ? error : new ProvisioningError(`Failed to add EMR instance group ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, void 0, error instanceof Error ? error : void 0);
|
|
38149
|
+
if (createdGroupId) markCreatedBeforeFailure(thrown, logicalId, resourceType, createdGroupId);
|
|
38150
|
+
throw thrown;
|
|
37441
38151
|
}
|
|
37442
38152
|
}
|
|
37443
38153
|
toInstanceGroupConfig(properties) {
|
|
@@ -37676,6 +38386,7 @@ var EMRInstanceFleetConfigProvider = class {
|
|
|
37676
38386
|
const clusterId = properties["ClusterId"];
|
|
37677
38387
|
if (!clusterId) throw new ProvisioningError(`EMR InstanceFleetConfig ${logicalId} is missing ClusterId (the parent cluster id)`, resourceType, logicalId);
|
|
37678
38388
|
this.logger.debug(`Adding EMR instance fleet ${logicalId} to cluster ${clusterId}`);
|
|
38389
|
+
let createdFleetId;
|
|
37679
38390
|
try {
|
|
37680
38391
|
const fleet = this.toInstanceFleetConfig(properties);
|
|
37681
38392
|
const orphanWindow = addInstanceFleetLatch.take(logicalId);
|
|
@@ -37718,6 +38429,7 @@ var EMRInstanceFleetConfigProvider = class {
|
|
|
37718
38429
|
}
|
|
37719
38430
|
const fleetId = response.InstanceFleetId;
|
|
37720
38431
|
if (fleetId) fleetsCreatedByThisProcess.add(fleetId);
|
|
38432
|
+
createdFleetId = fleetId;
|
|
37721
38433
|
if (!fleetId) throw new ProvisioningError(`EMR AddInstanceFleet for ${logicalId} returned no instance fleet id`, resourceType, logicalId);
|
|
37722
38434
|
await this.waitForFleetReady(clusterId, fleetId, logicalId, resourceType, this.targetCapacities(properties), {
|
|
37723
38435
|
onDemand: 0,
|
|
@@ -37729,9 +38441,9 @@ var EMRInstanceFleetConfigProvider = class {
|
|
|
37729
38441
|
attributes: { Id: fleetId }
|
|
37730
38442
|
};
|
|
37731
38443
|
} catch (error) {
|
|
37732
|
-
|
|
37733
|
-
|
|
37734
|
-
throw
|
|
38444
|
+
const thrown = error instanceof ProvisioningError ? error : new ProvisioningError(`Failed to add EMR instance fleet ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, void 0, error instanceof Error ? error : void 0);
|
|
38445
|
+
if (createdFleetId) markCreatedBeforeFailure(thrown, logicalId, resourceType, createdFleetId);
|
|
38446
|
+
throw thrown;
|
|
37735
38447
|
}
|
|
37736
38448
|
}
|
|
37737
38449
|
toInstanceFleetConfig(properties) {
|
|
@@ -37954,6 +38666,7 @@ var FirehoseProvider = class {
|
|
|
37954
38666
|
const deliveryStreamName = properties["DeliveryStreamName"];
|
|
37955
38667
|
const deliveryStreamType = properties["DeliveryStreamType"] || "DirectPut";
|
|
37956
38668
|
if (!isReadableTagList(properties["Tags"])) throw markNonRetryable(new ProvisioningError(`Tags of Firehose delivery stream ${logicalId} is not a list of tags with a Key — the delivery stream was not created`, resourceType, logicalId));
|
|
38669
|
+
let createdStreamName;
|
|
37957
38670
|
try {
|
|
37958
38671
|
const input = {
|
|
37959
38672
|
DeliveryStreamName: deliveryStreamName || logicalId,
|
|
@@ -38082,6 +38795,7 @@ var FirehoseProvider = class {
|
|
|
38082
38795
|
}));
|
|
38083
38796
|
const response = await this.getClient().send(new CreateDeliveryStreamCommand(input));
|
|
38084
38797
|
const physicalId = deliveryStreamName || input.DeliveryStreamName || response.DeliveryStreamARN?.split("/").pop() || "";
|
|
38798
|
+
createdStreamName = physicalId;
|
|
38085
38799
|
const arn = response.DeliveryStreamARN;
|
|
38086
38800
|
this.logger.debug(`Successfully created Firehose delivery stream ${logicalId}: ${physicalId}`);
|
|
38087
38801
|
await this.waitForActive(physicalId, logicalId);
|
|
@@ -38090,9 +38804,9 @@ var FirehoseProvider = class {
|
|
|
38090
38804
|
attributes: { Arn: arn }
|
|
38091
38805
|
};
|
|
38092
38806
|
} catch (error) {
|
|
38093
|
-
|
|
38094
|
-
|
|
38095
|
-
throw
|
|
38807
|
+
const thrown = error instanceof ProvisioningError ? error : new ProvisioningError(`Failed to create Firehose delivery stream ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, void 0, error instanceof Error ? error : void 0);
|
|
38808
|
+
if (createdStreamName !== void 0) markCreatedBeforeFailure(thrown, logicalId, resourceType, createdStreamName);
|
|
38809
|
+
throw thrown;
|
|
38096
38810
|
}
|
|
38097
38811
|
}
|
|
38098
38812
|
async update(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
@@ -38836,6 +39550,7 @@ var CloudTrailProvider = class {
|
|
|
38836
39550
|
const eventSelectors = properties["EventSelectors"];
|
|
38837
39551
|
const insightSelectors = properties["InsightSelectors"];
|
|
38838
39552
|
let trailCreated = false;
|
|
39553
|
+
let createdTrailArn;
|
|
38839
39554
|
try {
|
|
38840
39555
|
const result = await this.getClient().send(new CreateTrailCommand({
|
|
38841
39556
|
Name: trailName ?? logicalId,
|
|
@@ -38856,6 +39571,7 @@ var CloudTrailProvider = class {
|
|
|
38856
39571
|
}));
|
|
38857
39572
|
trailCreated = true;
|
|
38858
39573
|
const trailArn = result.TrailARN;
|
|
39574
|
+
createdTrailArn = result.TrailARN;
|
|
38859
39575
|
if (eventSelectors && eventSelectors.length > 0) {
|
|
38860
39576
|
this.logger.debug(`Setting event selectors for CloudTrail Trail ${logicalId}`);
|
|
38861
39577
|
await this.getClient().send(new PutEventSelectorsCommand({
|
|
@@ -38882,7 +39598,9 @@ var CloudTrailProvider = class {
|
|
|
38882
39598
|
} catch (error) {
|
|
38883
39599
|
if (trailCreated) markAuxiliaryFailure(error, logicalId);
|
|
38884
39600
|
const cause = error instanceof Error ? error : void 0;
|
|
38885
|
-
|
|
39601
|
+
const thrown = new ProvisioningError(`Failed to create CloudTrail Trail ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, void 0, cause);
|
|
39602
|
+
if (createdTrailArn) markCreatedBeforeFailure(thrown, logicalId, resourceType, createdTrailArn);
|
|
39603
|
+
throw thrown;
|
|
38886
39604
|
}
|
|
38887
39605
|
}
|
|
38888
39606
|
async update(logicalId, physicalId, resourceType, properties, previousProperties, context) {
|
|
@@ -39668,6 +40386,7 @@ var CodeCommitRepositoryProvider = class {
|
|
|
39668
40386
|
Triggers: properties["Triggers"],
|
|
39669
40387
|
Tags: properties["Tags"]
|
|
39670
40388
|
}, void 0);
|
|
40389
|
+
let leftLiveName;
|
|
39671
40390
|
try {
|
|
39672
40391
|
const tags = toSdkTagMap(lists.Tags);
|
|
39673
40392
|
const description = properties["RepositoryDescription"];
|
|
@@ -39680,6 +40399,7 @@ var CodeCommitRepositoryProvider = class {
|
|
|
39680
40399
|
}))).repositoryMetadata;
|
|
39681
40400
|
if (!metadata?.repositoryName) throw new Error("CreateRepository did not return repository metadata");
|
|
39682
40401
|
const createdName = metadata.repositoryName;
|
|
40402
|
+
leftLiveName = createdName;
|
|
39683
40403
|
try {
|
|
39684
40404
|
const code = properties["Code"];
|
|
39685
40405
|
if (code) await this.seedInitialCommit(createdName, code);
|
|
@@ -39693,7 +40413,7 @@ var CodeCommitRepositoryProvider = class {
|
|
|
39693
40413
|
}
|
|
39694
40414
|
} catch (postCreateError) {
|
|
39695
40415
|
this.logger.warn(`Post-create step failed for CodeCommit Repository ${logicalId}; deleting the just-created repository ${createdName} to avoid an orphan`);
|
|
39696
|
-
await this.bestEffortDelete(createdName);
|
|
40416
|
+
if (await this.bestEffortDelete(createdName)) leftLiveName = void 0;
|
|
39697
40417
|
throw markAuxiliaryFailure(postCreateError, logicalId);
|
|
39698
40418
|
}
|
|
39699
40419
|
this.logger.debug(`Successfully created CodeCommit Repository ${logicalId}: ${createdName}`);
|
|
@@ -39703,7 +40423,9 @@ var CodeCommitRepositoryProvider = class {
|
|
|
39703
40423
|
};
|
|
39704
40424
|
} catch (error) {
|
|
39705
40425
|
const cause = error instanceof Error ? error : void 0;
|
|
39706
|
-
|
|
40426
|
+
const thrown = new ProvisioningError(`Failed to create CodeCommit Repository ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, repositoryName, cause);
|
|
40427
|
+
if (leftLiveName !== void 0) markCreatedBeforeFailure(thrown, logicalId, resourceType, leftLiveName);
|
|
40428
|
+
throw thrown;
|
|
39707
40429
|
}
|
|
39708
40430
|
}
|
|
39709
40431
|
async update(logicalId, physicalId, resourceType, properties, previousProperties, context) {
|
|
@@ -40031,8 +40753,10 @@ var CodeCommitRepositoryProvider = class {
|
|
|
40031
40753
|
async bestEffortDelete(repositoryName) {
|
|
40032
40754
|
try {
|
|
40033
40755
|
await this.getClient().send(new DeleteRepositoryCommand$1({ repositoryName }));
|
|
40756
|
+
return true;
|
|
40034
40757
|
} catch (cleanupError) {
|
|
40035
40758
|
this.logger.warn(`Failed to clean up CodeCommit Repository ${repositoryName} after a post-create failure: ${describeAwsFailure(cleanupError).detail}`);
|
|
40759
|
+
return false;
|
|
40036
40760
|
}
|
|
40037
40761
|
}
|
|
40038
40762
|
async getRepositoryMetadata(repositoryName) {
|
|
@@ -40600,6 +41324,7 @@ var S3DirectoryBucketProvider = class {
|
|
|
40600
41324
|
const tags = desiredTags;
|
|
40601
41325
|
const includeTags = tags.length > 0;
|
|
40602
41326
|
try {
|
|
41327
|
+
const attributes = await this.buildAttributes(bucketName);
|
|
40603
41328
|
await this.s3Client.send(new CreateBucketCommand({
|
|
40604
41329
|
Bucket: bucketName,
|
|
40605
41330
|
CreateBucketConfiguration: {
|
|
@@ -40615,7 +41340,6 @@ var S3DirectoryBucketProvider = class {
|
|
|
40615
41340
|
}
|
|
40616
41341
|
}));
|
|
40617
41342
|
this.logger.debug(`Created S3 Express Directory Bucket: ${bucketName}`);
|
|
40618
|
-
const attributes = await this.buildAttributes(bucketName);
|
|
40619
41343
|
return {
|
|
40620
41344
|
physicalId: bucketName,
|
|
40621
41345
|
attributes
|
|
@@ -41036,6 +41760,7 @@ var S3TablesProvider = class {
|
|
|
41036
41760
|
maskSecrets: context?.maskSecrets,
|
|
41037
41761
|
...context?.replayingState === true && { onRefusal: (message) => this.logger.warn(message) }
|
|
41038
41762
|
});
|
|
41763
|
+
let tableCreated = false;
|
|
41039
41764
|
try {
|
|
41040
41765
|
const response = await this.getClient().send(new CreateTableCommand$2({
|
|
41041
41766
|
tableBucketARN,
|
|
@@ -41044,6 +41769,7 @@ var S3TablesProvider = class {
|
|
|
41044
41769
|
format,
|
|
41045
41770
|
...tags !== void 0 && { tags }
|
|
41046
41771
|
}));
|
|
41772
|
+
tableCreated = true;
|
|
41047
41773
|
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);
|
|
41048
41774
|
const tableARN = response.tableARN;
|
|
41049
41775
|
this.logger.debug(`Successfully created S3 Tables Table ${logicalId}: ${physicalId}`);
|
|
@@ -41053,7 +41779,9 @@ var S3TablesProvider = class {
|
|
|
41053
41779
|
};
|
|
41054
41780
|
} catch (error) {
|
|
41055
41781
|
const cause = error instanceof Error ? error : void 0;
|
|
41056
|
-
|
|
41782
|
+
const thrown = new ProvisioningError(`Failed to create S3 Tables Table ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, void 0, cause);
|
|
41783
|
+
if (tableCreated) markCreatedBeforeFailure(thrown, logicalId, resourceType, physicalId);
|
|
41784
|
+
throw thrown;
|
|
41057
41785
|
}
|
|
41058
41786
|
}
|
|
41059
41787
|
async readCurrentState(physicalId, logicalId, resourceType) {
|
|
@@ -41537,7 +42265,9 @@ var ECRProvider = class {
|
|
|
41537
42265
|
} catch (error) {
|
|
41538
42266
|
if (repositoryCreated) markAuxiliaryFailure(error, logicalId);
|
|
41539
42267
|
const cause = error instanceof Error ? error : void 0;
|
|
41540
|
-
|
|
42268
|
+
const thrown = new ProvisioningError(`Failed to create ECR Repository ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, repositoryName, cause);
|
|
42269
|
+
if (repositoryCreated) markCreatedBeforeFailure(thrown, logicalId, resourceType, repositoryName);
|
|
42270
|
+
throw thrown;
|
|
41541
42271
|
}
|
|
41542
42272
|
}
|
|
41543
42273
|
async update(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
@@ -41751,7 +42481,7 @@ var NestedStackProvider = class {
|
|
|
41751
42481
|
["Tags", "CFn-only — cdkd does not tag the synthesized \"stack\" (the parent's synthesized ARN is a cdkd-local placeholder, not a real AWS resource)"],
|
|
41752
42482
|
["TimeoutInMinutes", "CFn-only stack-create deadline — cdkd uses per-resource --resource-timeout instead (issue #459 design §9)"]
|
|
41753
42483
|
])]]);
|
|
41754
|
-
async create(logicalId,
|
|
42484
|
+
async create(logicalId, resourceType, properties, context) {
|
|
41755
42485
|
const ctx = this.requireContext();
|
|
41756
42486
|
this.requireDeployContext(ctx, "create");
|
|
41757
42487
|
const childTemplatePath = ctx.nestedTemplates[logicalId];
|
|
@@ -41763,15 +42493,27 @@ var NestedStackProvider = class {
|
|
|
41763
42493
|
const childParameters = this.extractParameters(properties);
|
|
41764
42494
|
const resourceCount = Object.keys(childTemplate.Resources ?? {}).length;
|
|
41765
42495
|
this.logger.info(`Deploying nested stack ${displaySafe(childStackName)} (logicalId=${displaySafe(logicalId)}, ${resourceCount} resource(s))`);
|
|
41766
|
-
|
|
41767
|
-
|
|
41768
|
-
|
|
41769
|
-
|
|
41770
|
-
|
|
41771
|
-
|
|
41772
|
-
|
|
41773
|
-
|
|
41774
|
-
|
|
42496
|
+
let pendingChildDeletes;
|
|
42497
|
+
try {
|
|
42498
|
+
pendingChildDeletes = await this.runChildDeploy(ctx, logicalId, childStackName, childRegion, childTemplate, childParameters, grandchildTemplates);
|
|
42499
|
+
} catch (error) {
|
|
42500
|
+
clearCreatedBeforeFailure(error);
|
|
42501
|
+
throw error;
|
|
42502
|
+
}
|
|
42503
|
+
const physicalId = this.synthesizeArn(ctx.accountId, childRegion, ctx.parentStackName, logicalId);
|
|
42504
|
+
try {
|
|
42505
|
+
const childOutputs = await this.readChildOutputsAsAttributes(ctx, childStackName, childRegion);
|
|
42506
|
+
const pendingRecord = context?.replayingState === true ? void 0 : recordWithPendingChildDeletes(properties, pendingChildDeletes);
|
|
42507
|
+
return {
|
|
42508
|
+
physicalId,
|
|
42509
|
+
attributes: childOutputs.attributes,
|
|
42510
|
+
...childOutputs.noEchoAttributeNames.length > 0 && { noEchoAttributeNames: childOutputs.noEchoAttributeNames },
|
|
42511
|
+
...pendingRecord && { effectiveProperties: pendingRecord }
|
|
42512
|
+
};
|
|
42513
|
+
} catch (error) {
|
|
42514
|
+
markCreatedBeforeFailure(error, logicalId, resourceType, physicalId);
|
|
42515
|
+
throw error;
|
|
42516
|
+
}
|
|
41775
42517
|
}
|
|
41776
42518
|
async update(logicalId, physicalId, _resourceType, properties, _previousProperties, context) {
|
|
41777
42519
|
const ctx = this.requireContext();
|
|
@@ -41858,6 +42600,7 @@ var NestedStackProvider = class {
|
|
|
41858
42600
|
...ctx.destroyOptions?.statePrefix !== void 0 && { statePrefix: ctx.destroyOptions.statePrefix },
|
|
41859
42601
|
...deleteContext?.removeProtection === true && { removeProtection: true },
|
|
41860
42602
|
...deleteContext?.resolveSecretDerivedPrincipals !== void 0 && { resolveSecretDerivedPrincipals: { inheritedProducerRegions: deleteContext.resolveSecretDerivedPrincipals.importedProducerRegions } },
|
|
42603
|
+
...deleteContext?.stackDestroy === true && { stackDestroy: true },
|
|
41861
42604
|
...(ctx.destroyOptions?.skipFinalSnapshot === true || ctx.options?.skipFinalSnapshot === true) && { skipFinalSnapshot: true },
|
|
41862
42605
|
...ctx.destroyOptions?.resourceWarnAfterMs !== void 0 && { resourceWarnAfterMs: ctx.destroyOptions.resourceWarnAfterMs },
|
|
41863
42606
|
...ctx.destroyOptions?.resourceTimeoutMs !== void 0 && { resourceTimeoutMs: ctx.destroyOptions.resourceTimeoutMs },
|
|
@@ -42141,11 +42884,19 @@ var ACMCertificateProvider = class {
|
|
|
42141
42884
|
const survivorNote = requestedArn ? await this.cleanupRequestedCertificate(requestedArn, logicalId, idempotencyToken) : void 0;
|
|
42142
42885
|
if (error instanceof CdkdError) {
|
|
42143
42886
|
if (survivorNote === void 0) throw error;
|
|
42144
|
-
|
|
42887
|
+
const thrown = new ProvisioningError(`${error.message} ${survivorNote}`, resourceType, logicalId, requestedArn, error);
|
|
42888
|
+
if (requestedArn) markCreatedBeforeFailure(thrown, logicalId, resourceType, requestedArn);
|
|
42889
|
+
throw thrown;
|
|
42145
42890
|
}
|
|
42146
42891
|
const cause = error instanceof Error ? error : void 0;
|
|
42147
42892
|
const detail = error instanceof Error ? error.message : String(error);
|
|
42148
|
-
|
|
42893
|
+
const message = `Failed to create ACM certificate ${logicalIdShown(logicalId)}: ${detail}`;
|
|
42894
|
+
if (requestedArn && survivorNote !== void 0) {
|
|
42895
|
+
const thrown = new ProvisioningError(`${message} ${survivorNote}`, resourceType, logicalId, requestedArn, cause);
|
|
42896
|
+
markCreatedBeforeFailure(thrown, logicalId, resourceType, requestedArn);
|
|
42897
|
+
throw thrown;
|
|
42898
|
+
}
|
|
42899
|
+
throw new ProvisioningError(message, resourceType, logicalId, requestedArn, cause);
|
|
42149
42900
|
}
|
|
42150
42901
|
}
|
|
42151
42902
|
regionOfArn(arn) {
|
|
@@ -42385,4 +43136,4 @@ var ACMCertificateProvider = class {
|
|
|
42385
43136
|
|
|
42386
43137
|
//#endregion
|
|
42387
43138
|
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, LambdaPermissionProvider, LambdaUrlProvider, 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 };
|
|
42388
|
-
//# sourceMappingURL=provider-classes-
|
|
43139
|
+
//# sourceMappingURL=provider-classes-DMOnX5s-.js.map
|