@go-to-k/cdkd 0.295.1 → 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-CbwOK2TQ.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-DG-oC9YK.js → deploy-engine-D7204v7Z.js} +775 -216
- 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-DUZtt9lH.js → iam-role-provider-CCPaZ3U4.js} +11 -5
- package/dist/iam-role-provider-CCPaZ3U4.js.map +1 -0
- package/dist/index.d.ts +28 -0
- 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-TnGNCeLX.js → neptune-provider-D1t9NgT-.js} +20 -14
- package/dist/neptune-provider-D1t9NgT-.js.map +1 -0
- package/dist/{program-DfJFegS1.js → program-B0sp_SHG.js} +6187 -5931
- package/dist/program-B0sp_SHG.js.map +1 -0
- package/dist/{provider-classes-DUw5QAWI.js → provider-classes-DMOnX5s-.js} +754 -208
- package/dist/provider-classes-DMOnX5s-.js.map +1 -0
- package/dist/{rds-provider-COCDd7bS.js → rds-provider-DltlcDiQ.js} +22 -15
- package/dist/rds-provider-DltlcDiQ.js.map +1 -0
- package/dist/{version-Bqzsng8Y.js → version-DUHDmEhz.js} +2 -2
- package/dist/{version-Bqzsng8Y.js.map → version-DUHDmEhz.js.map} +1 -1
- package/package.json +1 -1
- package/dist/asg-provider-CbwOK2TQ.js.map +0 -1
- package/dist/deploy-engine-DG-oC9YK.js.map +0 -1
- package/dist/iam-policy-targets-CMSQGQnm.js.map +0 -1
- package/dist/iam-role-provider-DUZtt9lH.js.map +0 -1
- package/dist/neptune-provider-TnGNCeLX.js.map +0 -1
- package/dist/program-DfJFegS1.js.map +0 -1
- package/dist/provider-classes-DUw5QAWI.js.map +0 -1
- package/dist/rds-provider-COCDd7bS.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,8 +179,58 @@ 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));
|
|
189
|
+
}
|
|
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}`);
|
|
175
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("; ")}`);
|
|
176
234
|
}
|
|
177
235
|
async update(logicalId, physicalId, resourceType, properties, previousProperties, context) {
|
|
178
236
|
const oldPolicyName = physicalId.includes(":") ? physicalId.split(":")[0] : physicalId;
|
|
@@ -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
|
|
@@ -8716,9 +8835,11 @@ var LambdaMicrovmImageProvider = class {
|
|
|
8716
8835
|
...buildCommonImageInput(properties)
|
|
8717
8836
|
};
|
|
8718
8837
|
if (tagList.length > 0) input.tags = Object.fromEntries(tagList.map((t) => [t.Key, t.Value]));
|
|
8838
|
+
let createdArn;
|
|
8719
8839
|
try {
|
|
8720
8840
|
const response = await this.client.send(new CreateMicrovmImageCommand(input));
|
|
8721
8841
|
const imageArn = response.imageArn;
|
|
8842
|
+
createdArn = imageArn;
|
|
8722
8843
|
if (!imageArn) throw new ProvisioningError(`CreateMicrovmImage succeeded but no imageArn returned for ${logicalId}`, resourceType, logicalId);
|
|
8723
8844
|
this.logger.debug(`Created MicroVM image ${logicalId}: ${imageArn} (state=${response.state})`);
|
|
8724
8845
|
const noWait = process.env["CDKD_NO_WAIT"] === "true";
|
|
@@ -8741,7 +8862,9 @@ var LambdaMicrovmImageProvider = class {
|
|
|
8741
8862
|
})
|
|
8742
8863
|
};
|
|
8743
8864
|
} catch (error) {
|
|
8744
|
-
|
|
8865
|
+
const thrown = this.wrapError("create", logicalId, resourceType, void 0, error);
|
|
8866
|
+
if (createdArn) markCreatedBeforeFailure(thrown, logicalId, resourceType, createdArn);
|
|
8867
|
+
throw thrown;
|
|
8745
8868
|
}
|
|
8746
8869
|
}
|
|
8747
8870
|
async update(logicalId, physicalId, resourceType, properties, previousProperties, context) {
|
|
@@ -9735,18 +9858,20 @@ var DynamoDBTableProvider = class {
|
|
|
9735
9858
|
}
|
|
9736
9859
|
};
|
|
9737
9860
|
} catch (error) {
|
|
9861
|
+
let tableLeftBehind = false;
|
|
9738
9862
|
if (tableCreated) {
|
|
9739
9863
|
try {
|
|
9740
9864
|
await this.dynamoDBClient.send(new DeleteTableCommand({ TableName: tableName }));
|
|
9741
9865
|
debug(`Rolled back partially-created DynamoDB table ${tableName}`);
|
|
9742
9866
|
} catch (cleanupError) {
|
|
9867
|
+
tableLeftBehind = true;
|
|
9743
9868
|
warn(`Failed to roll back partially-created DynamoDB table ${tableName}: ${describeAwsFailure(cleanupError).detail}`);
|
|
9744
9869
|
}
|
|
9745
9870
|
markAuxiliaryFailure(error, logicalId);
|
|
9746
9871
|
}
|
|
9747
|
-
|
|
9748
|
-
|
|
9749
|
-
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;
|
|
9750
9875
|
}
|
|
9751
9876
|
}
|
|
9752
9877
|
async update(logicalId, physicalId, resourceType, properties, previousProperties, context) {
|
|
@@ -10994,6 +11119,7 @@ var LogsLogGroupProvider = class {
|
|
|
10994
11119
|
allowedPattern: /[^a-zA-Z0-9-/_]/g
|
|
10995
11120
|
})}`;
|
|
10996
11121
|
const desiredTags = refuseMalformedDesiredTags(properties["Tags"], resourceType, logicalId);
|
|
11122
|
+
let leftBehind = false;
|
|
10997
11123
|
try {
|
|
10998
11124
|
const createParams = { logGroupName };
|
|
10999
11125
|
if (properties["KmsKeyId"]) createParams.kmsKeyId = properties["KmsKeyId"];
|
|
@@ -11004,6 +11130,7 @@ var LogsLogGroupProvider = class {
|
|
|
11004
11130
|
try {
|
|
11005
11131
|
await this.logsClient.send(new CreateLogGroupCommand(createParams));
|
|
11006
11132
|
createdNewLogGroup = true;
|
|
11133
|
+
leftBehind = true;
|
|
11007
11134
|
} catch (createError) {
|
|
11008
11135
|
if (createError instanceof ResourceAlreadyExistsException) this.logger.debug(`Log group ${logGroupName} already exists, using existing`);
|
|
11009
11136
|
else throw createError;
|
|
@@ -11049,6 +11176,7 @@ var LogsLogGroupProvider = class {
|
|
|
11049
11176
|
} catch (innerError) {
|
|
11050
11177
|
if (createdNewLogGroup) try {
|
|
11051
11178
|
await this.logsClient.send(new DeleteLogGroupCommand({ logGroupName }));
|
|
11179
|
+
leftBehind = false;
|
|
11052
11180
|
this.logger.debug(`Cleaned up partially-created log group ${displaySafe(logicalId)} (${displaySafe(logGroupName)}) after wiring failure`);
|
|
11053
11181
|
} catch (cleanupError) {
|
|
11054
11182
|
const mask = maskerOrIdentity(context?.maskSecrets);
|
|
@@ -11057,7 +11185,7 @@ var LogsLogGroupProvider = class {
|
|
|
11057
11185
|
identifier: logGroupName,
|
|
11058
11186
|
maskSecrets: mask
|
|
11059
11187
|
});
|
|
11060
|
-
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.";
|
|
11061
11189
|
this.logger.warn(mask(`Failed to clean up partially-created log group ${displaySafe(logicalId)} (${displaySafe(mask(logGroupName))}): ${describeAwsFailure(cleanupError).detail}. ${manualStep}`));
|
|
11062
11190
|
}
|
|
11063
11191
|
throw markAuxiliaryFailure(innerError, logicalId);
|
|
@@ -11070,7 +11198,9 @@ var LogsLogGroupProvider = class {
|
|
|
11070
11198
|
} catch (error) {
|
|
11071
11199
|
const cause = error instanceof Error ? error : void 0;
|
|
11072
11200
|
const mask = maskerOrIdentity(context?.maskSecrets);
|
|
11073
|
-
|
|
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;
|
|
11074
11204
|
}
|
|
11075
11205
|
}
|
|
11076
11206
|
async update(logicalId, physicalId, resourceType, properties, previousProperties, callerContext) {
|
|
@@ -11650,7 +11780,7 @@ var CloudWatchAnomalyDetectorProvider = class {
|
|
|
11650
11780
|
}
|
|
11651
11781
|
async delete(logicalId, physicalId, resourceType, properties, context) {
|
|
11652
11782
|
this.logger.debug(`Deleting CloudWatch anomaly detector ${logicalId}: ${physicalId}`);
|
|
11653
|
-
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);
|
|
11654
11784
|
const skip = redactedDeleteAddressSkip(this.logger, logicalId, "CloudWatch anomaly detector", redactedDeleteAddressFields({
|
|
11655
11785
|
Namespace: properties["Namespace"],
|
|
11656
11786
|
MetricName: properties["MetricName"],
|
|
@@ -11658,7 +11788,7 @@ var CloudWatchAnomalyDetectorProvider = class {
|
|
|
11658
11788
|
Dimensions: properties["Dimensions"],
|
|
11659
11789
|
SingleMetricAnomalyDetector: properties["SingleMetricAnomalyDetector"],
|
|
11660
11790
|
MetricMathAnomalyDetector: properties["MetricMathAnomalyDetector"]
|
|
11661
|
-
}));
|
|
11791
|
+
}), context);
|
|
11662
11792
|
if (skip) return skip;
|
|
11663
11793
|
try {
|
|
11664
11794
|
await this.cloudWatchClient.send(new DeleteAnomalyDetectorCommand(buildDeleteParams(properties)));
|
|
@@ -12209,6 +12339,7 @@ var SSMParameterProvider = class SSMParameterProvider {
|
|
|
12209
12339
|
const type = properties["Type"] || "String";
|
|
12210
12340
|
const value = properties["Value"];
|
|
12211
12341
|
if (!value) throw new ProvisioningError(`Value is required for SSM parameter ${displaySafe(logicalId)}`, resourceType, logicalId);
|
|
12342
|
+
let leftBehind = false;
|
|
12212
12343
|
try {
|
|
12213
12344
|
const putParams = {
|
|
12214
12345
|
Name: name,
|
|
@@ -12222,6 +12353,7 @@ var SSMParameterProvider = class SSMParameterProvider {
|
|
|
12222
12353
|
if (properties["Policies"]) putParams.Policies = properties["Policies"];
|
|
12223
12354
|
if (properties["DataType"]) putParams.DataType = properties["DataType"];
|
|
12224
12355
|
await this.ssmClient.send(new PutParameterCommand(putParams));
|
|
12356
|
+
leftBehind = true;
|
|
12225
12357
|
try {
|
|
12226
12358
|
if (ssmTags.length > 0) await this.ssmClient.send(new AddTagsToResourceCommand({
|
|
12227
12359
|
ResourceType: "Parameter",
|
|
@@ -12231,6 +12363,7 @@ var SSMParameterProvider = class SSMParameterProvider {
|
|
|
12231
12363
|
} catch (innerError) {
|
|
12232
12364
|
try {
|
|
12233
12365
|
await this.ssmClient.send(new DeleteParameterCommand({ Name: name }));
|
|
12366
|
+
leftBehind = false;
|
|
12234
12367
|
debug(`Cleaned up partially-created SSM parameter ${displaySafe(logicalId)} (${displaySafe(mask(name))}) after wiring failure`);
|
|
12235
12368
|
} catch (cleanupError) {
|
|
12236
12369
|
const deleteCommand = renderDisableCommand({
|
|
@@ -12238,7 +12371,7 @@ var SSMParameterProvider = class SSMParameterProvider {
|
|
|
12238
12371
|
identifier: name,
|
|
12239
12372
|
maskSecrets: mask
|
|
12240
12373
|
});
|
|
12241
|
-
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.";
|
|
12242
12375
|
warn(`Failed to clean up partially-created SSM parameter ${displaySafe(logicalId)} (${displaySafe(mask(name))}): ${describeAwsFailure(cleanupError).detail}. ${manualStep}`);
|
|
12243
12376
|
}
|
|
12244
12377
|
throw markAuxiliaryFailure(innerError, logicalId);
|
|
@@ -12255,7 +12388,9 @@ var SSMParameterProvider = class SSMParameterProvider {
|
|
|
12255
12388
|
};
|
|
12256
12389
|
} catch (error) {
|
|
12257
12390
|
const cause = error instanceof Error ? error : void 0;
|
|
12258
|
-
|
|
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;
|
|
12259
12394
|
}
|
|
12260
12395
|
}
|
|
12261
12396
|
async update(logicalId, physicalId, resourceType, properties, previousProperties, context) {
|
|
@@ -12533,6 +12668,7 @@ var EventBridgeRuleProvider = class {
|
|
|
12533
12668
|
const desiredTags = refuseMalformedDesiredTags(properties["Tags"], resourceType, logicalId);
|
|
12534
12669
|
const ruleName = properties["Name"] || generateResourceName(logicalId, { maxLength: 64 });
|
|
12535
12670
|
const targets = properties["Targets"];
|
|
12671
|
+
let leftLiveArn;
|
|
12536
12672
|
try {
|
|
12537
12673
|
const heldBefore = targets && targets.length > 0 ? await nameHeldBefore(async () => {
|
|
12538
12674
|
await this.eventBridgeClient.send(new DescribeRuleCommand({
|
|
@@ -12582,6 +12718,7 @@ var EventBridgeRuleProvider = class {
|
|
|
12582
12718
|
}));
|
|
12583
12719
|
this.logger.debug(`Cleaned up partially-created EventBridge rule ${logicalId} (${ruleName}) after wiring failure`);
|
|
12584
12720
|
} catch (cleanupError) {
|
|
12721
|
+
leftLiveArn = ruleArn;
|
|
12585
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()}`)));
|
|
12586
12723
|
}
|
|
12587
12724
|
throw markAuxiliaryFailure(innerError, logicalId);
|
|
@@ -12592,7 +12729,9 @@ var EventBridgeRuleProvider = class {
|
|
|
12592
12729
|
};
|
|
12593
12730
|
} catch (error) {
|
|
12594
12731
|
const cause = error instanceof Error ? error : void 0;
|
|
12595
|
-
|
|
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;
|
|
12596
12735
|
}
|
|
12597
12736
|
}
|
|
12598
12737
|
async update(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
@@ -13474,6 +13613,7 @@ var EC2Provider = class {
|
|
|
13474
13613
|
const desiredTags = refuseMalformedDesiredTags(properties["Tags"], resourceType, logicalId);
|
|
13475
13614
|
const cidrBlock = properties["CidrBlock"];
|
|
13476
13615
|
if (!cidrBlock) throw new ProvisioningError(`CidrBlock is required for VPC ${logicalId}`, resourceType, logicalId);
|
|
13616
|
+
let leftBehindId;
|
|
13477
13617
|
try {
|
|
13478
13618
|
const createClient = await this.getCreateClient();
|
|
13479
13619
|
const orphanWindow = createVpcLatch.take(logicalId);
|
|
@@ -13519,6 +13659,7 @@ var EC2Provider = class {
|
|
|
13519
13659
|
await this.ec2Client.send(new DeleteVpcCommand({ VpcId: vpcId }));
|
|
13520
13660
|
this.logger.debug(`Cleaned up partially-created VPC ${logicalId} (${vpcId}) after wiring failure`);
|
|
13521
13661
|
} catch (cleanupError) {
|
|
13662
|
+
leftBehindId = vpcId;
|
|
13522
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()}`);
|
|
13523
13664
|
}
|
|
13524
13665
|
throw markAuxiliaryFailure(innerError, logicalId);
|
|
@@ -13534,7 +13675,9 @@ var EC2Provider = class {
|
|
|
13534
13675
|
};
|
|
13535
13676
|
} catch (error) {
|
|
13536
13677
|
const cause = error instanceof Error ? error : void 0;
|
|
13537
|
-
|
|
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;
|
|
13538
13681
|
}
|
|
13539
13682
|
}
|
|
13540
13683
|
async updateVpc(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
@@ -13634,6 +13777,7 @@ var EC2Provider = class {
|
|
|
13634
13777
|
const vpcId = properties["VpcId"];
|
|
13635
13778
|
const cidrBlock = properties["CidrBlock"];
|
|
13636
13779
|
if (!vpcId || !cidrBlock) throw new ProvisioningError(`VpcId and CidrBlock are required for Subnet ${logicalId}`, resourceType, logicalId);
|
|
13780
|
+
let leftBehindId;
|
|
13637
13781
|
try {
|
|
13638
13782
|
const createClient = await this.getCreateClient();
|
|
13639
13783
|
const orphanWindow = createSubnetLatch.take(logicalId);
|
|
@@ -13668,6 +13812,7 @@ var EC2Provider = class {
|
|
|
13668
13812
|
await this.ec2Client.send(new DeleteSubnetCommand({ SubnetId: subnetId }));
|
|
13669
13813
|
this.logger.debug(`Cleaned up partially-created Subnet ${logicalId} (${subnetId}) after wiring failure`);
|
|
13670
13814
|
} catch (cleanupError) {
|
|
13815
|
+
leftBehindId = subnetId;
|
|
13671
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()}`);
|
|
13672
13817
|
}
|
|
13673
13818
|
throw markAuxiliaryFailure(innerError, logicalId);
|
|
@@ -13682,7 +13827,9 @@ var EC2Provider = class {
|
|
|
13682
13827
|
};
|
|
13683
13828
|
} catch (error) {
|
|
13684
13829
|
const cause = error instanceof Error ? error : void 0;
|
|
13685
|
-
|
|
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;
|
|
13686
13833
|
}
|
|
13687
13834
|
}
|
|
13688
13835
|
async updateSubnet(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
@@ -13868,6 +14015,7 @@ var EC2Provider = class {
|
|
|
13868
14015
|
let allocationId;
|
|
13869
14016
|
let publicIp;
|
|
13870
14017
|
let created = false;
|
|
14018
|
+
let createdId;
|
|
13871
14019
|
try {
|
|
13872
14020
|
const input = {
|
|
13873
14021
|
Domain: requireConfigString(properties["Domain"], "vpc", "AWS::EC2::EIP Domain", replayWarn(this.logger, context)),
|
|
@@ -13888,6 +14036,11 @@ var EC2Provider = class {
|
|
|
13888
14036
|
created = true;
|
|
13889
14037
|
allocationId = response.AllocationId;
|
|
13890
14038
|
publicIp = response.PublicIp;
|
|
14039
|
+
try {
|
|
14040
|
+
createdId = this.eipPhysicalId(logicalId, publicIp, allocationId);
|
|
14041
|
+
} catch {
|
|
14042
|
+
createdId = allocationId;
|
|
14043
|
+
}
|
|
13891
14044
|
ec2IdsCreatedByThisProcess.add(allocationId);
|
|
13892
14045
|
await this.applyTags(allocationId, desiredTags, logicalId);
|
|
13893
14046
|
const instanceId = properties["InstanceId"];
|
|
@@ -13905,7 +14058,9 @@ var EC2Provider = class {
|
|
|
13905
14058
|
} catch (error) {
|
|
13906
14059
|
if (created) markAuxiliaryFailure(error, logicalId);
|
|
13907
14060
|
const cause = error instanceof Error ? error : void 0;
|
|
13908
|
-
|
|
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;
|
|
13909
14064
|
}
|
|
13910
14065
|
return {
|
|
13911
14066
|
physicalId: this.eipPhysicalId(logicalId, publicIp, allocationId, {
|
|
@@ -14050,6 +14205,7 @@ var EC2Provider = class {
|
|
|
14050
14205
|
scope: "CreateNatGateway",
|
|
14051
14206
|
logicalId
|
|
14052
14207
|
});
|
|
14208
|
+
let createdId;
|
|
14053
14209
|
try {
|
|
14054
14210
|
const natGatewayId = (await this.ec2Client.send(new CreateNatGatewayCommand({
|
|
14055
14211
|
ClientToken: natGatewayToken.value,
|
|
@@ -14061,6 +14217,7 @@ var EC2Provider = class {
|
|
|
14061
14217
|
SecondaryPrivateIpAddresses: properties["SecondaryPrivateIpAddresses"],
|
|
14062
14218
|
SecondaryPrivateIpAddressCount: properties["SecondaryPrivateIpAddressCount"]
|
|
14063
14219
|
}))).NatGateway.NatGatewayId;
|
|
14220
|
+
createdId = natGatewayId;
|
|
14064
14221
|
await this.applyTags(natGatewayId, desiredTags, logicalId);
|
|
14065
14222
|
if (process.env["CDKD_NO_WAIT"] !== "true") {
|
|
14066
14223
|
this.logger.debug(`Waiting for NatGateway ${natGatewayId} to reach available state...`);
|
|
@@ -14080,7 +14237,9 @@ var EC2Provider = class {
|
|
|
14080
14237
|
};
|
|
14081
14238
|
} catch (error) {
|
|
14082
14239
|
const cause = error instanceof Error ? error : void 0;
|
|
14083
|
-
|
|
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;
|
|
14084
14243
|
}
|
|
14085
14244
|
}
|
|
14086
14245
|
updateNatGateway(logicalId, physicalId) {
|
|
@@ -14306,6 +14465,7 @@ var EC2Provider = class {
|
|
|
14306
14465
|
const desiredTags = refuseMalformedDesiredTags(properties["Tags"], resourceType, logicalId);
|
|
14307
14466
|
const groupDescription = properties["GroupDescription"];
|
|
14308
14467
|
if (!groupDescription) throw new ProvisioningError(`GroupDescription is required for SecurityGroup ${logicalId}`, resourceType, logicalId);
|
|
14468
|
+
let leftBehindId;
|
|
14309
14469
|
try {
|
|
14310
14470
|
const groupId = (await (await this.getCreateClient()).send(new CreateSecurityGroupCommand({
|
|
14311
14471
|
GroupName: properties["GroupName"] ?? logicalId,
|
|
@@ -14330,6 +14490,7 @@ var EC2Provider = class {
|
|
|
14330
14490
|
await this.ec2Client.send(new DeleteSecurityGroupCommand({ GroupId: groupId }));
|
|
14331
14491
|
this.logger.debug(`Cleaned up partially-created SecurityGroup ${logicalId} (${groupId}) after wiring failure`);
|
|
14332
14492
|
} catch (cleanupError) {
|
|
14493
|
+
leftBehindId = groupId;
|
|
14333
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()}`);
|
|
14334
14495
|
}
|
|
14335
14496
|
throw markAuxiliaryFailure(innerError, logicalId);
|
|
@@ -14344,7 +14505,9 @@ var EC2Provider = class {
|
|
|
14344
14505
|
};
|
|
14345
14506
|
} catch (error) {
|
|
14346
14507
|
const cause = error instanceof Error ? error : void 0;
|
|
14347
|
-
|
|
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;
|
|
14348
14511
|
}
|
|
14349
14512
|
}
|
|
14350
14513
|
async authorizeInlineIngress(groupId, ingressRules) {
|
|
@@ -14732,7 +14895,7 @@ var EC2Provider = class {
|
|
|
14732
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`);
|
|
14733
14896
|
const revoked = keptFor !== void 0 ? void 0 : await this.deleteSecurityGroupIngress(logicalId, physicalId, resourceType, previousProperties, recordedAttributes ? { recordedAttributes } : void 0);
|
|
14734
14897
|
const revokeSkip = deleteSkipReason(revoked);
|
|
14735
|
-
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));
|
|
14736
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);
|
|
14737
14900
|
return {
|
|
14738
14901
|
physicalId: createResult.physicalId,
|
|
@@ -14789,7 +14952,7 @@ var EC2Provider = class {
|
|
|
14789
14952
|
SourceSecurityGroupId: properties["SourceSecurityGroupId"],
|
|
14790
14953
|
SourceSecurityGroupOwnerId: properties["SourceSecurityGroupOwnerId"],
|
|
14791
14954
|
SourcePrefixListId: properties["SourcePrefixListId"]
|
|
14792
|
-
}));
|
|
14955
|
+
}), context);
|
|
14793
14956
|
if (redactedSkip) return redactedSkip;
|
|
14794
14957
|
}
|
|
14795
14958
|
const ipPermission = properties ? this.withoutDescription(this.buildIpPermission(properties)) : {
|
|
@@ -14828,6 +14991,7 @@ var EC2Provider = class {
|
|
|
14828
14991
|
const imageId = properties["ImageId"];
|
|
14829
14992
|
if (!imageId) throw new ProvisioningError(`ImageId is required for EC2 Instance ${logicalId}`, resourceType, logicalId);
|
|
14830
14993
|
const instanceType = requireConfigString(properties["InstanceType"], "t3.micro", "AWS::EC2::Instance InstanceType", replayWarn(this.logger, context));
|
|
14994
|
+
let leftBehindId;
|
|
14831
14995
|
try {
|
|
14832
14996
|
const securityGroupIds = properties["SecurityGroupIds"];
|
|
14833
14997
|
const securityGroups = properties["SecurityGroups"];
|
|
@@ -14895,14 +15059,15 @@ var EC2Provider = class {
|
|
|
14895
15059
|
runInstancesToken.release();
|
|
14896
15060
|
this.logger.debug(`Terminate requested for partially-created EC2 Instance ${logicalId} (${instanceId}) after wiring failure (not waiting for terminated state)`);
|
|
14897
15061
|
} catch (cleanupError) {
|
|
15062
|
+
leftBehindId = instanceId;
|
|
14898
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()}`);
|
|
14899
15064
|
}
|
|
14900
15065
|
throw markAuxiliaryFailure(innerError, logicalId);
|
|
14901
15066
|
}
|
|
14902
15067
|
} catch (error) {
|
|
14903
|
-
|
|
14904
|
-
|
|
14905
|
-
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;
|
|
14906
15071
|
}
|
|
14907
15072
|
}
|
|
14908
15073
|
normalizeIamInstanceProfile(raw) {
|
|
@@ -15386,7 +15551,10 @@ var EC2Provider = class {
|
|
|
15386
15551
|
this.logger.debug(`Deleting NetworkAclEntry ${logicalId}: ${physicalId}`);
|
|
15387
15552
|
const parts = physicalId.split("|");
|
|
15388
15553
|
if (parts.length < 3) {
|
|
15389
|
-
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
|
+
}));
|
|
15390
15558
|
return compositeIdSkipResult();
|
|
15391
15559
|
}
|
|
15392
15560
|
const networkAclId = parts[0];
|
|
@@ -16944,6 +17112,7 @@ var ApiGatewayProvider = class ApiGatewayProvider {
|
|
|
16944
17112
|
const block = properties[key];
|
|
16945
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);
|
|
16946
17114
|
}
|
|
17115
|
+
let stageLeftBehind = false;
|
|
16947
17116
|
try {
|
|
16948
17117
|
const rawCacheClusterSize = properties["CacheClusterSize"];
|
|
16949
17118
|
await this.apiGatewayClient.send(new CreateStageCommand({
|
|
@@ -16993,6 +17162,7 @@ var ApiGatewayProvider = class ApiGatewayProvider {
|
|
|
16993
17162
|
stageName
|
|
16994
17163
|
}));
|
|
16995
17164
|
} catch (cleanupError) {
|
|
17165
|
+
stageLeftBehind = true;
|
|
16996
17166
|
log.warn(`Failed to clean up stage ${log.value(stageName)} after a post-create patch failure: ${describeAwsFailure(cleanupError).detail}`);
|
|
16997
17167
|
}
|
|
16998
17168
|
throw markAuxiliaryFailure(patchError, logicalId);
|
|
@@ -17004,7 +17174,9 @@ var ApiGatewayProvider = class ApiGatewayProvider {
|
|
|
17004
17174
|
};
|
|
17005
17175
|
} catch (error) {
|
|
17006
17176
|
const cause = error instanceof Error ? error : void 0;
|
|
17007
|
-
|
|
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;
|
|
17008
17180
|
}
|
|
17009
17181
|
}
|
|
17010
17182
|
async updateStage(logicalId, physicalId, resourceType, properties, previousProperties, log) {
|
|
@@ -17210,6 +17382,7 @@ var ApiGatewayProvider = class ApiGatewayProvider {
|
|
|
17210
17382
|
httpMethod
|
|
17211
17383
|
].map((id) => log.value(id));
|
|
17212
17384
|
const methodPath = maskedIds.join("/");
|
|
17385
|
+
let methodLeftBehind = false;
|
|
17213
17386
|
try {
|
|
17214
17387
|
await this.apiGatewayClient.send(new PutMethodCommand({
|
|
17215
17388
|
restApiId,
|
|
@@ -17283,6 +17456,7 @@ var ApiGatewayProvider = class ApiGatewayProvider {
|
|
|
17283
17456
|
}));
|
|
17284
17457
|
log.debug(`Cleaned up partially-created API Gateway Method ${logicalId} (${methodPath}) after wiring failure`);
|
|
17285
17458
|
} catch (cleanupError) {
|
|
17459
|
+
methodLeftBehind = true;
|
|
17286
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()}`);
|
|
17287
17461
|
}
|
|
17288
17462
|
throw markAuxiliaryFailure(innerError, logicalId);
|
|
@@ -17294,7 +17468,9 @@ var ApiGatewayProvider = class ApiGatewayProvider {
|
|
|
17294
17468
|
};
|
|
17295
17469
|
} catch (error) {
|
|
17296
17470
|
const cause = error instanceof Error ? error : void 0;
|
|
17297
|
-
|
|
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;
|
|
17298
17474
|
}
|
|
17299
17475
|
}
|
|
17300
17476
|
async updateMethod(logicalId, physicalId, resourceType, properties, previousProperties, log) {
|
|
@@ -21266,7 +21442,9 @@ var ECSProvider = class {
|
|
|
21266
21442
|
const desiredTags = refuseMalformedDesiredTags(properties["Tags"], resourceType, logicalId);
|
|
21267
21443
|
const client = this.getClient();
|
|
21268
21444
|
const serviceName = properties["ServiceName"] || generateResourceName(logicalId, { maxLength: 255 });
|
|
21445
|
+
let survivorArn;
|
|
21269
21446
|
try {
|
|
21447
|
+
const heldBefore = process.env["CDKD_FULL_WAIT"] === "true" ? await nameHeldBefore(() => this.serviceNameHeld(properties["Cluster"], serviceName), (error) => hasErrorName(error, ["ClusterNotFoundException"])) : "free";
|
|
21270
21448
|
const service = (await client.send(new CreateServiceCommand({
|
|
21271
21449
|
cluster: properties["Cluster"],
|
|
21272
21450
|
serviceName,
|
|
@@ -21304,7 +21482,9 @@ var ECSProvider = class {
|
|
|
21304
21482
|
const cleanupCluster = properties["Cluster"];
|
|
21305
21483
|
const clusterArg = cleanupCluster ? aws` --cluster ${cleanupCluster}` : aws``;
|
|
21306
21484
|
const listStopped = aws`aws ecs list-tasks${clusterArg} --desired-status STOPPED`;
|
|
21307
|
-
|
|
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 {
|
|
21308
21488
|
await client.send(new DeleteServiceCommand({
|
|
21309
21489
|
cluster: properties["Cluster"],
|
|
21310
21490
|
service: service.serviceArn,
|
|
@@ -21312,7 +21492,8 @@ var ECSProvider = class {
|
|
|
21312
21492
|
}));
|
|
21313
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()}`);
|
|
21314
21494
|
} catch (cleanupError) {
|
|
21315
|
-
|
|
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()}`);
|
|
21316
21497
|
}
|
|
21317
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 });
|
|
21318
21499
|
}
|
|
@@ -21325,9 +21506,24 @@ var ECSProvider = class {
|
|
|
21325
21506
|
};
|
|
21326
21507
|
} catch (error) {
|
|
21327
21508
|
const cause = error instanceof Error ? error : void 0;
|
|
21328
|
-
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
|
+
});
|
|
21329
21514
|
}
|
|
21330
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
|
+
}
|
|
21331
21527
|
async settleService(logicalId, serviceRef, cluster, log) {
|
|
21332
21528
|
if (process.env["CDKD_FULL_WAIT"] === "true") {
|
|
21333
21529
|
log.debug(`Waiting for ECS service ${logicalId} to reach steady state...`);
|
|
@@ -22507,6 +22703,7 @@ var ELBv2Provider = class {
|
|
|
22507
22703
|
async createLoadBalancer(logicalId, resourceType, properties, maskSecrets) {
|
|
22508
22704
|
this.logger.debug(`Creating LoadBalancer ${logicalId}`);
|
|
22509
22705
|
const tags = refuseMalformedDesiredTags(properties["Tags"], resourceType, logicalId);
|
|
22706
|
+
let leftBehindArn;
|
|
22510
22707
|
try {
|
|
22511
22708
|
const lbName = sentElbv2Name(properties, logicalId);
|
|
22512
22709
|
const lbAttributes = this.normalizeAttributes(properties["LoadBalancerAttributes"]);
|
|
@@ -22570,6 +22767,7 @@ var ELBv2Provider = class {
|
|
|
22570
22767
|
await this.getClient().send(new DeleteLoadBalancerCommand({ LoadBalancerArn: lbArn }));
|
|
22571
22768
|
this.logger.debug(`Cleaned up partially-created LoadBalancer ${logicalId} (${lbArn}) after wiring failure`);
|
|
22572
22769
|
} catch (cleanupError) {
|
|
22770
|
+
leftBehindArn = lbArn;
|
|
22573
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()}`);
|
|
22574
22772
|
}
|
|
22575
22773
|
throw markAuxiliaryFailure(innerError, logicalId);
|
|
@@ -22580,7 +22778,9 @@ var ELBv2Provider = class {
|
|
|
22580
22778
|
};
|
|
22581
22779
|
} catch (error) {
|
|
22582
22780
|
const cause = error instanceof Error ? error : void 0;
|
|
22583
|
-
|
|
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;
|
|
22584
22784
|
}
|
|
22585
22785
|
}
|
|
22586
22786
|
async updateLoadBalancer(logicalId, physicalId, resourceType, properties, previousProperties, callerMaskSecrets, fromReadback = false) {
|
|
@@ -22788,6 +22988,7 @@ var ELBv2Provider = class {
|
|
|
22788
22988
|
const tags = refuseMalformedDesiredTags(properties["Tags"], resourceType, logicalId);
|
|
22789
22989
|
const desiredTargets = readTargets(properties["Targets"], "desired");
|
|
22790
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;
|
|
22791
22992
|
try {
|
|
22792
22993
|
const matcher = properties["Matcher"];
|
|
22793
22994
|
const tgName = sentElbv2Name(properties, logicalId);
|
|
@@ -22838,6 +23039,7 @@ var ELBv2Provider = class {
|
|
|
22838
23039
|
await this.getClient().send(new DeleteTargetGroupCommand({ TargetGroupArn: tgArn }));
|
|
22839
23040
|
this.logger.debug(`Cleaned up partially-created TargetGroup ${logicalId} (${tgArn}) after wiring failure`);
|
|
22840
23041
|
} catch (cleanupError) {
|
|
23042
|
+
leftBehindArn = tgArn;
|
|
22841
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()}`);
|
|
22842
23044
|
}
|
|
22843
23045
|
throw markAuxiliaryFailure(innerError, logicalId);
|
|
@@ -22848,7 +23050,9 @@ var ELBv2Provider = class {
|
|
|
22848
23050
|
};
|
|
22849
23051
|
} catch (error) {
|
|
22850
23052
|
const cause = error instanceof Error ? error : void 0;
|
|
22851
|
-
|
|
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;
|
|
22852
23056
|
}
|
|
22853
23057
|
}
|
|
22854
23058
|
async updateTargetGroup(logicalId, physicalId, resourceType, properties, previousProperties, callerMaskSecrets, fromReadback = false) {
|
|
@@ -22946,14 +23150,30 @@ var ELBv2Provider = class {
|
|
|
22946
23150
|
throw new ProvisioningError(`Failed to delete TargetGroup ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, physicalId, cause);
|
|
22947
23151
|
}
|
|
22948
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
|
+
}
|
|
22949
23166
|
async createListener(logicalId, resourceType, properties, maskSecrets) {
|
|
22950
23167
|
this.logger.debug(`Creating Listener ${logicalId}`);
|
|
22951
23168
|
const tags = refuseMalformedDesiredTags(properties["Tags"], resourceType, logicalId);
|
|
23169
|
+
let leftBehindArn;
|
|
22952
23170
|
try {
|
|
22953
23171
|
const defaultActions = this.convertActions(properties["DefaultActions"]);
|
|
22954
23172
|
const certificates = this.convertCertificates(properties["Certificates"]);
|
|
22955
23173
|
const alpnPolicy = properties["AlpnPolicy"];
|
|
22956
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";
|
|
22957
23177
|
const listener = (await this.getClient().send(new CreateListenerCommand({
|
|
22958
23178
|
LoadBalancerArn: properties["LoadBalancerArn"],
|
|
22959
23179
|
Port: properties["Port"] !== void 0 ? Number(properties["Port"]) : void 0,
|
|
@@ -22969,7 +23189,6 @@ var ELBv2Provider = class {
|
|
|
22969
23189
|
const listenerArn = listener.ListenerArn;
|
|
22970
23190
|
this.logger.debug(`Successfully created Listener ${logicalId}: ${listenerArn}`);
|
|
22971
23191
|
try {
|
|
22972
|
-
const listenerAttributes = this.normalizeAttributes(properties["ListenerAttributes"]);
|
|
22973
23192
|
if (listenerAttributes.length > 0) {
|
|
22974
23193
|
const watch = startInterruptWatch(`ELBv2 Listener ${logicalId} attributes`);
|
|
22975
23194
|
try {
|
|
@@ -22987,12 +23206,17 @@ var ELBv2Provider = class {
|
|
|
22987
23206
|
this.logger.debug(`Applied ${listenerAttributes.length} ListenerAttribute(s) for ${logicalId}`);
|
|
22988
23207
|
}
|
|
22989
23208
|
} catch (innerError) {
|
|
22990
|
-
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()}`));
|
|
22991
23214
|
try {
|
|
22992
23215
|
await this.getClient().send(new DeleteListenerCommand({ ListenerArn: listenerArn }));
|
|
22993
23216
|
this.logger.debug(`Cleaned up partially-created Listener ${logicalId} (${listenerArn}) after attributes-wiring failure`);
|
|
22994
23217
|
} catch (cleanupError) {
|
|
22995
|
-
|
|
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()}`);
|
|
22996
23220
|
}
|
|
22997
23221
|
throw markAuxiliaryFailure(innerError, logicalId);
|
|
22998
23222
|
}
|
|
@@ -23002,7 +23226,9 @@ var ELBv2Provider = class {
|
|
|
23002
23226
|
};
|
|
23003
23227
|
} catch (error) {
|
|
23004
23228
|
const cause = error instanceof Error ? error : void 0;
|
|
23005
|
-
|
|
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;
|
|
23006
23232
|
}
|
|
23007
23233
|
}
|
|
23008
23234
|
async updateListener(logicalId, physicalId, resourceType, properties, previousProperties, maskSecrets, fromReadback = false) {
|
|
@@ -23534,24 +23760,29 @@ var RDSDBProxyProvider = class {
|
|
|
23534
23760
|
let vpcId;
|
|
23535
23761
|
const deadline = Date.now() + POLL_TIMEOUT_MS$1;
|
|
23536
23762
|
let status;
|
|
23537
|
-
|
|
23538
|
-
|
|
23539
|
-
|
|
23540
|
-
|
|
23541
|
-
|
|
23542
|
-
|
|
23543
|
-
|
|
23544
|
-
|
|
23545
|
-
|
|
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);
|
|
23546
23778
|
}
|
|
23547
|
-
|
|
23548
|
-
} catch (error) {
|
|
23549
|
-
if (error instanceof DBProxyNotFoundFault) {} else if (error instanceof ProvisioningError) throw error;
|
|
23550
|
-
else throw this.wrapError(error, "CREATE (poll)", resourceType, logicalId, dbProxyName);
|
|
23779
|
+
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS$1));
|
|
23551
23780
|
}
|
|
23552
|
-
|
|
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;
|
|
23553
23785
|
}
|
|
23554
|
-
if (!endpoint || !dbProxyArn) throw new ProvisioningError(`Timed out waiting for DBProxy ${dbProxyName} to become available (last status: ${status ?? "unknown"})`, resourceType, logicalId, dbProxyName);
|
|
23555
23786
|
return {
|
|
23556
23787
|
physicalId: dbProxyName,
|
|
23557
23788
|
attributes: definedAttributes({
|
|
@@ -23832,26 +24063,31 @@ var RDSDBProxyEndpointProvider = class {
|
|
|
23832
24063
|
let vpcId;
|
|
23833
24064
|
const deadline = Date.now() + POLL_TIMEOUT_MS;
|
|
23834
24065
|
let status;
|
|
23835
|
-
|
|
23836
|
-
|
|
23837
|
-
|
|
23838
|
-
|
|
23839
|
-
|
|
23840
|
-
|
|
23841
|
-
|
|
23842
|
-
|
|
23843
|
-
|
|
23844
|
-
|
|
23845
|
-
|
|
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);
|
|
23846
24083
|
}
|
|
23847
|
-
|
|
23848
|
-
} catch (error) {
|
|
23849
|
-
if (error instanceof DBProxyEndpointNotFoundFault || error instanceof DBProxyNotFoundFault) {} else if (error instanceof ProvisioningError) throw error;
|
|
23850
|
-
else throw this.wrapError(error, "CREATE (poll)", resourceType, logicalId, dbProxyEndpointName);
|
|
24084
|
+
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
|
|
23851
24085
|
}
|
|
23852
|
-
|
|
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;
|
|
23853
24090
|
}
|
|
23854
|
-
if (!endpoint || !arn) throw new ProvisioningError(`Timed out waiting for DBProxyEndpoint ${dbProxyEndpointName} to become available (last status: ${status ?? "unknown"})`, resourceType, logicalId, dbProxyEndpointName);
|
|
23855
24091
|
return {
|
|
23856
24092
|
physicalId: dbProxyEndpointName,
|
|
23857
24093
|
attributes: definedAttributes({
|
|
@@ -24176,7 +24412,11 @@ var RDSDBProxyTargetGroupProvider = class {
|
|
|
24176
24412
|
Tags: tags
|
|
24177
24413
|
}));
|
|
24178
24414
|
} catch (error) {
|
|
24179
|
-
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
|
+
});
|
|
24180
24420
|
}
|
|
24181
24421
|
return {
|
|
24182
24422
|
physicalId: targetGroupArn,
|
|
@@ -24208,8 +24448,10 @@ var RDSDBProxyTargetGroupProvider = class {
|
|
|
24208
24448
|
}
|
|
24209
24449
|
refuseMalformedDesiredTags(properties["Tags"], resourceType, logicalId, physicalId, "Tags", DBPROXY_TAGS_WHAT, DBPROXY_TAG_OPTIONS);
|
|
24210
24450
|
if (context?.expectedRegion) assertRegionMatch(await this.getClient().config.region(), context.expectedRegion, resourceType, logicalId, physicalId, "pre-update");
|
|
24211
|
-
|
|
24212
|
-
|
|
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";
|
|
24213
24455
|
const base = context?.maskSecrets ?? ((t) => t);
|
|
24214
24456
|
const maskNames = (text) => {
|
|
24215
24457
|
let out = text;
|
|
@@ -24232,11 +24474,11 @@ var RDSDBProxyTargetGroupProvider = class {
|
|
|
24232
24474
|
}
|
|
24233
24475
|
if (lookupFailure !== void 0) {
|
|
24234
24476
|
const failureClass = lookupFailure instanceof Error && lookupFailure.name !== "" ? lookupFailure.name : "an unreadable failure";
|
|
24235
|
-
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);
|
|
24236
24478
|
markRedactedCause(refusal);
|
|
24237
24479
|
throw refusal;
|
|
24238
24480
|
}
|
|
24239
|
-
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));
|
|
24240
24482
|
}
|
|
24241
24483
|
const next = readTargetLists({
|
|
24242
24484
|
DBClusterIdentifiers: properties["DBClusterIdentifiers"],
|
|
@@ -24470,7 +24712,7 @@ var RDSDBProxyTargetGroupProvider = class {
|
|
|
24470
24712
|
}
|
|
24471
24713
|
return result;
|
|
24472
24714
|
}
|
|
24473
|
-
async retireRegistrationAfterFailedCreate(original, dbProxyName, targetGroupName, dbClusterIdentifiers, dbInstanceIdentifiers, maskSecrets) {
|
|
24715
|
+
async retireRegistrationAfterFailedCreate(original, dbProxyName, targetGroupName, dbClusterIdentifiers, dbInstanceIdentifiers, maskSecrets, leftBehind) {
|
|
24474
24716
|
const clusters = dbClusterIdentifiers?.length ? dbClusterIdentifiers : void 0;
|
|
24475
24717
|
const instances = dbInstanceIdentifiers?.length ? dbInstanceIdentifiers : void 0;
|
|
24476
24718
|
if (!clusters && !instances) return original;
|
|
@@ -24494,6 +24736,7 @@ var RDSDBProxyTargetGroupProvider = class {
|
|
|
24494
24736
|
for (const id of instances) targets = aws`${targets} ${id}`;
|
|
24495
24737
|
}
|
|
24496
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);
|
|
24497
24740
|
return original;
|
|
24498
24741
|
}
|
|
24499
24742
|
}
|
|
@@ -24680,8 +24923,9 @@ var DocDBProvider = class {
|
|
|
24680
24923
|
maxLength: 63,
|
|
24681
24924
|
lowercase: true
|
|
24682
24925
|
});
|
|
24926
|
+
let clusterCreated = false;
|
|
24683
24927
|
try {
|
|
24684
|
-
|
|
24928
|
+
const response = await this.getClient().send(new CreateDBClusterCommand$1({
|
|
24685
24929
|
DBClusterIdentifier: dbClusterIdentifier,
|
|
24686
24930
|
Engine: "docdb",
|
|
24687
24931
|
EngineVersion: properties["EngineVersion"],
|
|
@@ -24698,7 +24942,9 @@ var DocDBProvider = class {
|
|
|
24698
24942
|
DBClusterParameterGroupName: properties["DBClusterParameterGroupName"],
|
|
24699
24943
|
DeletionProtection: properties["DeletionProtection"],
|
|
24700
24944
|
...tags.length > 0 && { Tags: tags }
|
|
24701
|
-
}))
|
|
24945
|
+
}));
|
|
24946
|
+
clusterCreated = true;
|
|
24947
|
+
if (!response.DBCluster) throw new Error("CreateDBCluster did not return DBCluster");
|
|
24702
24948
|
this.logger.debug(`Successfully created DocDB DBCluster ${logicalId}: ${dbClusterIdentifier}`);
|
|
24703
24949
|
if (process.env["CDKD_NO_WAIT"] !== "true") await this.waitForClusterAvailable(dbClusterIdentifier);
|
|
24704
24950
|
return {
|
|
@@ -24706,9 +24952,9 @@ var DocDBProvider = class {
|
|
|
24706
24952
|
attributes: clusterAttributes(await this.describeDBCluster(dbClusterIdentifier))
|
|
24707
24953
|
};
|
|
24708
24954
|
} catch (error) {
|
|
24709
|
-
|
|
24710
|
-
|
|
24711
|
-
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;
|
|
24712
24958
|
}
|
|
24713
24959
|
}
|
|
24714
24960
|
async updateDBCluster(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
@@ -24823,8 +25069,9 @@ var DocDBProvider = class {
|
|
|
24823
25069
|
maxLength: 63,
|
|
24824
25070
|
lowercase: true
|
|
24825
25071
|
});
|
|
25072
|
+
let instanceCreated = false;
|
|
24826
25073
|
try {
|
|
24827
|
-
|
|
25074
|
+
const response = await this.getClient().send(new CreateDBInstanceCommand$1({
|
|
24828
25075
|
DBInstanceIdentifier: dbInstanceIdentifier,
|
|
24829
25076
|
DBInstanceClass: properties["DBInstanceClass"],
|
|
24830
25077
|
Engine: "docdb",
|
|
@@ -24833,7 +25080,9 @@ var DocDBProvider = class {
|
|
|
24833
25080
|
PreferredMaintenanceWindow: properties["PreferredMaintenanceWindow"],
|
|
24834
25081
|
AutoMinorVersionUpgrade: properties["AutoMinorVersionUpgrade"],
|
|
24835
25082
|
...tags.length > 0 && { Tags: tags }
|
|
24836
|
-
}))
|
|
25083
|
+
}));
|
|
25084
|
+
instanceCreated = true;
|
|
25085
|
+
if (!response.DBInstance) throw new Error("CreateDBInstance did not return DBInstance");
|
|
24837
25086
|
this.logger.debug(`Successfully created DocDB DBInstance ${logicalId}: ${dbInstanceIdentifier}`);
|
|
24838
25087
|
if (process.env["CDKD_NO_WAIT"] !== "true") await this.waitForInstanceAvailable(dbInstanceIdentifier);
|
|
24839
25088
|
return {
|
|
@@ -24841,9 +25090,9 @@ var DocDBProvider = class {
|
|
|
24841
25090
|
attributes: instanceAttributes(await this.describeDBInstance(dbInstanceIdentifier))
|
|
24842
25091
|
};
|
|
24843
25092
|
} catch (error) {
|
|
24844
|
-
|
|
24845
|
-
|
|
24846
|
-
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;
|
|
24847
25096
|
}
|
|
24848
25097
|
}
|
|
24849
25098
|
async updateDBInstance(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
@@ -25315,6 +25564,8 @@ var Route53Provider = class {
|
|
|
25315
25564
|
const name = properties["Name"];
|
|
25316
25565
|
if (!name) throw new ProvisioningError(`Name is required for hosted zone ${logicalId}`, resourceType, logicalId);
|
|
25317
25566
|
let zoneCreated = false;
|
|
25567
|
+
let createdZoneId;
|
|
25568
|
+
let zoneRolledBack = false;
|
|
25318
25569
|
try {
|
|
25319
25570
|
const hostedZoneConfig = properties["HostedZoneConfig"];
|
|
25320
25571
|
const createComment = readConfigString(hostedZoneConfig, "Comment", "", "AWS::Route53::HostedZone HostedZoneConfig");
|
|
@@ -25341,6 +25592,7 @@ var Route53Provider = class {
|
|
|
25341
25592
|
const hostedZone = response.HostedZone;
|
|
25342
25593
|
if (!hostedZone?.Id) throw new Error("CreateHostedZone did not return HostedZone.Id");
|
|
25343
25594
|
const zoneId = hostedZone.Id.replace("/hostedzone/", "");
|
|
25595
|
+
createdZoneId = zoneId;
|
|
25344
25596
|
if (vpcs && vpcs.length > 1) for (let i = 1; i < vpcs.length; i++) {
|
|
25345
25597
|
const additionalVpc = vpcs[i];
|
|
25346
25598
|
this.logger.debug(`Associating additional VPC ${String(additionalVpc["VPCId"])} with hosted zone ${zoneId}`);
|
|
@@ -25364,6 +25616,7 @@ var Route53Provider = class {
|
|
|
25364
25616
|
try {
|
|
25365
25617
|
await this.deleteQueryLoggingConfigForZone(zoneId, logicalId);
|
|
25366
25618
|
await this.getClient().send(new DeleteHostedZoneCommand({ Id: zoneId }));
|
|
25619
|
+
zoneRolledBack = true;
|
|
25367
25620
|
callerReferenceToken.release();
|
|
25368
25621
|
} catch (deleteError) {
|
|
25369
25622
|
this.logger.warn(`Best-effort rollback DeleteHostedZone for ${zoneId} also failed: ${describeAwsFailure(deleteError).detail} — operator may need to clean up the orphan zone`);
|
|
@@ -25383,9 +25636,9 @@ var Route53Provider = class {
|
|
|
25383
25636
|
};
|
|
25384
25637
|
} catch (error) {
|
|
25385
25638
|
if (zoneCreated) markAuxiliaryFailure(error, logicalId);
|
|
25386
|
-
|
|
25387
|
-
|
|
25388
|
-
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;
|
|
25389
25642
|
}
|
|
25390
25643
|
}
|
|
25391
25644
|
async createOrAdoptHostedZone(input) {
|
|
@@ -27025,17 +27278,21 @@ var CognitoUserPoolProvider = class {
|
|
|
27025
27278
|
...effectiveProperties !== properties ? { effectiveProperties } : {}
|
|
27026
27279
|
};
|
|
27027
27280
|
} catch (error) {
|
|
27281
|
+
let poolLeftBehind = false;
|
|
27028
27282
|
if (createdUserPoolId) {
|
|
27029
27283
|
markAuxiliaryFailure(error, logicalId);
|
|
27030
27284
|
try {
|
|
27031
27285
|
await this.getClient().send(new DeleteUserPoolCommand({ UserPoolId: createdUserPoolId }));
|
|
27032
27286
|
this.logger.debug(`Rolled back partially-created Cognito User Pool ${createdUserPoolId}`);
|
|
27033
27287
|
} catch (rollbackError) {
|
|
27288
|
+
poolLeftBehind = true;
|
|
27034
27289
|
this.logger.warn(`Failed to roll back partially-created Cognito User Pool ${createdUserPoolId}: ${describeAwsFailure(rollbackError).detail}`);
|
|
27035
27290
|
}
|
|
27036
27291
|
}
|
|
27037
27292
|
const cause = error instanceof Error ? error : void 0;
|
|
27038
|
-
|
|
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;
|
|
27039
27296
|
}
|
|
27040
27297
|
}
|
|
27041
27298
|
async regionArg(aws) {
|
|
@@ -27756,6 +28013,7 @@ var ElastiCacheProvider = class {
|
|
|
27756
28013
|
maxLength: 40,
|
|
27757
28014
|
lowercase: true
|
|
27758
28015
|
});
|
|
28016
|
+
let clusterCreated = false;
|
|
27759
28017
|
try {
|
|
27760
28018
|
await this.getClient().send(new CreateCacheClusterCommand({
|
|
27761
28019
|
CacheClusterId: cacheClusterId,
|
|
@@ -27782,6 +28040,7 @@ var ElastiCacheProvider = class {
|
|
|
27782
28040
|
TransitEncryptionEnabled: properties["TransitEncryptionEnabled"],
|
|
27783
28041
|
...tags.length > 0 && { Tags: tags }
|
|
27784
28042
|
}));
|
|
28043
|
+
clusterCreated = true;
|
|
27785
28044
|
this.logger.debug(`Successfully created CacheCluster ${logicalId}: ${cacheClusterId}`);
|
|
27786
28045
|
if (process.env["CDKD_NO_WAIT"] !== "true") await this.waitForClusterAvailable(cacheClusterId);
|
|
27787
28046
|
const described = await this.describeCacheCluster(cacheClusterId);
|
|
@@ -27801,9 +28060,9 @@ var ElastiCacheProvider = class {
|
|
|
27801
28060
|
attributes
|
|
27802
28061
|
};
|
|
27803
28062
|
} catch (error) {
|
|
27804
|
-
|
|
27805
|
-
|
|
27806
|
-
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;
|
|
27807
28066
|
}
|
|
27808
28067
|
}
|
|
27809
28068
|
async updateCacheCluster(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
@@ -28208,6 +28467,7 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
|
|
|
28208
28467
|
if (!name) throw new ProvisioningError(`Name is required for PrivateDnsNamespace ${logicalId}`, resourceType, logicalId);
|
|
28209
28468
|
if (!vpc) throw new ProvisioningError(`Vpc is required for PrivateDnsNamespace ${logicalId}`, resourceType, logicalId);
|
|
28210
28469
|
const inputProperties = this.extractSoaTtlProperties(properties);
|
|
28470
|
+
let createdNamespaceId;
|
|
28211
28471
|
try {
|
|
28212
28472
|
const operationId = (await client.send(new CreatePrivateDnsNamespaceCommand({
|
|
28213
28473
|
Name: name,
|
|
@@ -28218,6 +28478,7 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
|
|
|
28218
28478
|
}))).OperationId;
|
|
28219
28479
|
if (!operationId) throw new Error("CreatePrivateDnsNamespace did not return OperationId");
|
|
28220
28480
|
const namespaceId = await this.pollOperation(operationId, logicalId, resourceType, maskSecrets);
|
|
28481
|
+
if (namespaceId !== operationId) createdNamespaceId = namespaceId;
|
|
28221
28482
|
const arn = await this.buildNamespaceArn(namespaceId);
|
|
28222
28483
|
this.logger.debug(`Successfully created private DNS namespace ${logicalId}: ${namespaceId}`);
|
|
28223
28484
|
return {
|
|
@@ -28228,9 +28489,10 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
|
|
|
28228
28489
|
}
|
|
28229
28490
|
};
|
|
28230
28491
|
} catch (error) {
|
|
28231
|
-
if (error instanceof ProvisioningError) throw error;
|
|
28232
28492
|
const cause = error instanceof Error ? error : void 0;
|
|
28233
|
-
|
|
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;
|
|
28234
28496
|
}
|
|
28235
28497
|
}
|
|
28236
28498
|
async updateNamespace(logicalId, physicalId, resourceType, properties, previousProperties, maskSecrets) {
|
|
@@ -28303,6 +28565,7 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
|
|
|
28303
28565
|
const name = properties["Name"];
|
|
28304
28566
|
const description = properties["Description"];
|
|
28305
28567
|
if (!name) throw new ProvisioningError(`Name is required for HttpNamespace ${logicalId}`, resourceType, logicalId);
|
|
28568
|
+
let createdNamespaceId;
|
|
28306
28569
|
try {
|
|
28307
28570
|
const operationId = (await client.send(new CreateHttpNamespaceCommand({
|
|
28308
28571
|
Name: name,
|
|
@@ -28311,6 +28574,7 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
|
|
|
28311
28574
|
}))).OperationId;
|
|
28312
28575
|
if (!operationId) throw new Error("CreateHttpNamespace did not return OperationId");
|
|
28313
28576
|
const namespaceId = await this.pollOperation(operationId, logicalId, resourceType, maskSecrets);
|
|
28577
|
+
if (namespaceId !== operationId) createdNamespaceId = namespaceId;
|
|
28314
28578
|
const arn = await this.resolveNamespaceArn(namespaceId);
|
|
28315
28579
|
this.logger.debug(`Successfully created HTTP namespace ${logicalId}: ${namespaceId}`);
|
|
28316
28580
|
return {
|
|
@@ -28321,9 +28585,10 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
|
|
|
28321
28585
|
}
|
|
28322
28586
|
};
|
|
28323
28587
|
} catch (error) {
|
|
28324
|
-
if (error instanceof ProvisioningError) throw error;
|
|
28325
28588
|
const cause = error instanceof Error ? error : void 0;
|
|
28326
|
-
|
|
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;
|
|
28327
28592
|
}
|
|
28328
28593
|
}
|
|
28329
28594
|
async updateHttpNamespace(logicalId, physicalId, resourceType, properties, previousProperties, maskSecrets) {
|
|
@@ -28360,6 +28625,7 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
|
|
|
28360
28625
|
const description = properties["Description"];
|
|
28361
28626
|
if (!name) throw new ProvisioningError(`Name is required for PublicDnsNamespace ${logicalId}`, resourceType, logicalId);
|
|
28362
28627
|
const inputProperties = this.extractSoaTtlProperties(properties);
|
|
28628
|
+
let createdNamespaceId;
|
|
28363
28629
|
try {
|
|
28364
28630
|
const operationId = (await client.send(new CreatePublicDnsNamespaceCommand({
|
|
28365
28631
|
Name: name,
|
|
@@ -28369,6 +28635,7 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
|
|
|
28369
28635
|
}))).OperationId;
|
|
28370
28636
|
if (!operationId) throw new Error("CreatePublicDnsNamespace did not return OperationId");
|
|
28371
28637
|
const namespaceId = await this.pollOperation(operationId, logicalId, resourceType, maskSecrets);
|
|
28638
|
+
if (namespaceId !== operationId) createdNamespaceId = namespaceId;
|
|
28372
28639
|
let arn;
|
|
28373
28640
|
let hostedZoneId;
|
|
28374
28641
|
try {
|
|
@@ -28389,9 +28656,10 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
|
|
|
28389
28656
|
}
|
|
28390
28657
|
};
|
|
28391
28658
|
} catch (error) {
|
|
28392
|
-
if (error instanceof ProvisioningError) throw error;
|
|
28393
28659
|
const cause = error instanceof Error ? error : void 0;
|
|
28394
|
-
|
|
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;
|
|
28395
28663
|
}
|
|
28396
28664
|
}
|
|
28397
28665
|
async updatePublicDnsNamespace(logicalId, physicalId, resourceType, properties, previousProperties, maskSecrets) {
|
|
@@ -28435,6 +28703,7 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
|
|
|
28435
28703
|
const healthCheckConfig = properties["HealthCheckConfig"];
|
|
28436
28704
|
const type = properties["Type"];
|
|
28437
28705
|
if (!name) throw new ProvisioningError(`Name is required for ServiceDiscovery Service ${logicalId}`, resourceType, logicalId);
|
|
28706
|
+
let leftBehindServiceId;
|
|
28438
28707
|
try {
|
|
28439
28708
|
const service = (await client.send(new CreateServiceCommand$1({
|
|
28440
28709
|
Name: name,
|
|
@@ -28448,6 +28717,7 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
|
|
|
28448
28717
|
}))).Service;
|
|
28449
28718
|
if (!service || !service.Id) throw new Error("CreateService did not return Service ID");
|
|
28450
28719
|
const serviceId = service.Id;
|
|
28720
|
+
leftBehindServiceId = serviceId;
|
|
28451
28721
|
this.logger.debug(`Successfully created service discovery service ${logicalId}: ${serviceId}`);
|
|
28452
28722
|
try {
|
|
28453
28723
|
const attrs = this.normalizeServiceAttributes(properties["ServiceAttributes"]);
|
|
@@ -28468,12 +28738,13 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
|
|
|
28468
28738
|
this.logger.debug(`Applied ${Object.keys(attrs).length} ServiceAttribute(s) for ${logicalId}`);
|
|
28469
28739
|
}
|
|
28470
28740
|
} catch (innerError) {
|
|
28471
|
-
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()}`));
|
|
28472
28742
|
try {
|
|
28473
28743
|
await client.send(new DeleteServiceCommand$1({ Id: serviceId }));
|
|
28744
|
+
leftBehindServiceId = void 0;
|
|
28474
28745
|
this.logger.debug(`Cleaned up partially-created ServiceDiscovery Service ${logicalId} (${serviceId}) after ServiceAttributes wiring failure`);
|
|
28475
28746
|
} catch (cleanupError) {
|
|
28476
|
-
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()}`);
|
|
28477
28748
|
}
|
|
28478
28749
|
throw markAuxiliaryFailure(innerError, logicalId);
|
|
28479
28750
|
}
|
|
@@ -28487,7 +28758,9 @@ var ServiceDiscoveryProvider = class ServiceDiscoveryProvider {
|
|
|
28487
28758
|
};
|
|
28488
28759
|
} catch (error) {
|
|
28489
28760
|
const cause = error instanceof Error ? error : void 0;
|
|
28490
|
-
|
|
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;
|
|
28491
28764
|
}
|
|
28492
28765
|
}
|
|
28493
28766
|
async updateService(logicalId, physicalId, resourceType, properties, previousProperties, maskSecrets) {
|
|
@@ -29797,17 +30070,21 @@ var AppSyncProvider = class {
|
|
|
29797
30070
|
...envRecord && { effectiveProperties: this.withEnvironmentVariablesRecord(properties, envRecord) }
|
|
29798
30071
|
};
|
|
29799
30072
|
} catch (error) {
|
|
30073
|
+
let apiLeftBehind = false;
|
|
29800
30074
|
if (createdApiId) {
|
|
29801
30075
|
markAuxiliaryFailure(error, logicalId);
|
|
29802
30076
|
try {
|
|
29803
30077
|
await this.getClient().send(new DeleteGraphqlApiCommand({ apiId: createdApiId }));
|
|
29804
30078
|
this.logger.debug(`Rolled back partially-created GraphQL API ${createdApiId}`);
|
|
29805
30079
|
} catch (rollbackError) {
|
|
30080
|
+
apiLeftBehind = true;
|
|
29806
30081
|
this.logger.warn(`Failed to roll back partially-created GraphQL API ${createdApiId}: ${describeAwsFailure(rollbackError).detail}`);
|
|
29807
30082
|
}
|
|
29808
30083
|
}
|
|
29809
30084
|
const cause = error instanceof Error ? error : void 0;
|
|
29810
|
-
|
|
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;
|
|
29811
30088
|
}
|
|
29812
30089
|
}
|
|
29813
30090
|
async regionArg(aws) {
|
|
@@ -32730,10 +33007,12 @@ var KMSProvider = class {
|
|
|
32730
33007
|
markAuxiliaryFailure(error, logicalId);
|
|
32731
33008
|
const aws = pasteableAwsCommand();
|
|
32732
33009
|
const region = await this.regionArg(aws);
|
|
32733
|
-
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()}`);
|
|
32734
33011
|
}
|
|
32735
33012
|
const cause = error instanceof Error ? error : void 0;
|
|
32736
|
-
|
|
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;
|
|
32737
33016
|
}
|
|
32738
33017
|
}
|
|
32739
33018
|
async regionArg(aws) {
|
|
@@ -33295,6 +33574,7 @@ var BudgetsBudgetProvider = class {
|
|
|
33295
33574
|
const accountId = await this.resolveAccountId();
|
|
33296
33575
|
const notifications = this.toSdkNotificationsWithSubscribers(lists.NotificationsWithSubscribers);
|
|
33297
33576
|
const resourceTags = this.toSdkResourceTags(lists.ResourceTags);
|
|
33577
|
+
const arn = await this.budgetArn(accountId, name);
|
|
33298
33578
|
await this.getClient().send(new CreateBudgetCommand({
|
|
33299
33579
|
AccountId: accountId,
|
|
33300
33580
|
Budget: this.toSdkBudget(properties["Budget"], name, logicalId, resourceType, mask),
|
|
@@ -33304,7 +33584,7 @@ var BudgetsBudgetProvider = class {
|
|
|
33304
33584
|
this.logger.debug(`Successfully created budget ${logicalId}: ${name}`);
|
|
33305
33585
|
return {
|
|
33306
33586
|
physicalId: name,
|
|
33307
|
-
attributes: { Arn:
|
|
33587
|
+
attributes: { Arn: arn }
|
|
33308
33588
|
};
|
|
33309
33589
|
} catch (error) {
|
|
33310
33590
|
if (error instanceof ProvisioningError) throw error;
|
|
@@ -34125,6 +34405,7 @@ var KinesisStreamConsumerProvider = class {
|
|
|
34125
34405
|
if (!streamArn) throw new ProvisioningError("AWS::Kinesis::StreamConsumer requires StreamARN", resourceType, logicalId);
|
|
34126
34406
|
this.logger.debug(`Registering Kinesis stream consumer ${logicalId}: ${consumerName}`);
|
|
34127
34407
|
const tagMap = tagListToMap(tagList);
|
|
34408
|
+
let createdArn;
|
|
34128
34409
|
try {
|
|
34129
34410
|
const consumer = (await this.getClient().send(new RegisterStreamConsumerCommand({
|
|
34130
34411
|
StreamARN: streamArn,
|
|
@@ -34133,6 +34414,7 @@ var KinesisStreamConsumerProvider = class {
|
|
|
34133
34414
|
}))).Consumer;
|
|
34134
34415
|
if (!consumer?.ConsumerARN || !consumer.ConsumerName) throw new ProvisioningError("RegisterStreamConsumer did not return ConsumerARN/ConsumerName", resourceType, logicalId);
|
|
34135
34416
|
const consumerArn = consumer.ConsumerARN;
|
|
34417
|
+
createdArn = consumerArn;
|
|
34136
34418
|
await this.waitForConsumerActive(consumerArn);
|
|
34137
34419
|
this.logger.debug(`Successfully registered Kinesis stream consumer ${logicalId}`);
|
|
34138
34420
|
return {
|
|
@@ -34147,9 +34429,9 @@ var KinesisStreamConsumerProvider = class {
|
|
|
34147
34429
|
}
|
|
34148
34430
|
};
|
|
34149
34431
|
} catch (error) {
|
|
34150
|
-
|
|
34151
|
-
|
|
34152
|
-
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;
|
|
34153
34435
|
}
|
|
34154
34436
|
}
|
|
34155
34437
|
async update(logicalId, physicalId, resourceType, properties, previousProperties, context) {
|
|
@@ -34293,6 +34575,33 @@ function tagListToMap(tags) {
|
|
|
34293
34575
|
|
|
34294
34576
|
//#endregion
|
|
34295
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";
|
|
34296
34605
|
function groupShown(group) {
|
|
34297
34606
|
return group === "***" ? group : plainOrDescribed(group, "group name");
|
|
34298
34607
|
}
|
|
@@ -34405,20 +34714,97 @@ var SchedulerScheduleProvider = class {
|
|
|
34405
34714
|
...groupName && { GroupName: groupName },
|
|
34406
34715
|
...this.toSdkFields(properties)
|
|
34407
34716
|
}));
|
|
34717
|
+
const creationDate = await this.creationDateBestEffort(logicalId, name, groupName);
|
|
34408
34718
|
return {
|
|
34409
34719
|
physicalId: name,
|
|
34410
|
-
attributes:
|
|
34720
|
+
attributes: {
|
|
34721
|
+
...response.ScheduleArn && { Arn: response.ScheduleArn },
|
|
34722
|
+
...creationDate !== void 0 && { ["cdkd:CreationDate"]: creationDate }
|
|
34723
|
+
}
|
|
34411
34724
|
};
|
|
34412
34725
|
} catch (error) {
|
|
34413
34726
|
const cause = error instanceof Error ? error : void 0;
|
|
34414
34727
|
throw new ProvisioningError(`Failed to create Schedule ${logicalId}: ${cause?.message ?? String(error)}`, resourceType, logicalId, void 0, cause);
|
|
34415
34728
|
}
|
|
34416
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
|
+
}
|
|
34417
34788
|
async update(logicalId, physicalId, resourceType, properties, previousProperties, context) {
|
|
34418
34789
|
const groupName = this.groupNameOf(properties);
|
|
34419
34790
|
const previousGroupName = this.groupNameOf(previousProperties);
|
|
34420
34791
|
const mask = maskerOrIdentity(context?.maskSecrets);
|
|
34421
|
-
|
|
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)`);
|
|
34422
34808
|
this.logger.debug(mask(`Updating Schedule ${logicalId}: ${mask(physicalId)}${groupName ? ` (group: ${mask(groupName)})` : ""}`));
|
|
34423
34809
|
try {
|
|
34424
34810
|
const input = {
|
|
@@ -34427,10 +34813,14 @@ var SchedulerScheduleProvider = class {
|
|
|
34427
34813
|
...this.toSdkFields(properties)
|
|
34428
34814
|
};
|
|
34429
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;
|
|
34430
34817
|
return {
|
|
34431
34818
|
physicalId,
|
|
34432
34819
|
wasReplaced: false,
|
|
34433
|
-
attributes:
|
|
34820
|
+
attributes: {
|
|
34821
|
+
...response.ScheduleArn && { Arn: response.ScheduleArn },
|
|
34822
|
+
...creationDate !== void 0 && { ["cdkd:CreationDate"]: creationDate }
|
|
34823
|
+
}
|
|
34434
34824
|
};
|
|
34435
34825
|
} catch (error) {
|
|
34436
34826
|
if (error instanceof ResourceUpdateNotSupportedError) throw error;
|
|
@@ -34438,8 +34828,89 @@ var SchedulerScheduleProvider = class {
|
|
|
34438
34828
|
throw new ProvisioningError(`Failed to update Schedule ${logicalId}: ${cause?.message ?? String(error)}`, resourceType, logicalId, physicalId, cause);
|
|
34439
34829
|
}
|
|
34440
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
|
+
}
|
|
34441
34906
|
async delete(logicalId, physicalId, resourceType, properties, context) {
|
|
34442
|
-
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);
|
|
34443
34914
|
if (skip) return skip;
|
|
34444
34915
|
const groupName = this.groupNameOf(properties);
|
|
34445
34916
|
if (properties === void 0) {
|
|
@@ -34515,7 +34986,10 @@ var SchedulerScheduleProvider = class {
|
|
|
34515
34986
|
}));
|
|
34516
34987
|
return {
|
|
34517
34988
|
physicalId: explicit,
|
|
34518
|
-
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
|
+
}
|
|
34519
34993
|
};
|
|
34520
34994
|
} catch (error) {
|
|
34521
34995
|
if (error instanceof ResourceNotFoundException$11) return null;
|
|
@@ -34758,7 +35232,7 @@ var PipesPipeProvider = class {
|
|
|
34758
35232
|
try {
|
|
34759
35233
|
settled = await this.waitForSettled(name, logicalId, resourceType, "create", mask);
|
|
34760
35234
|
} catch (error) {
|
|
34761
|
-
throw await this.retireFailedCreate(name, logicalId, error, mask);
|
|
35235
|
+
throw await this.retireFailedCreate(name, logicalId, resourceType, error, mask);
|
|
34762
35236
|
}
|
|
34763
35237
|
return {
|
|
34764
35238
|
physicalId: name,
|
|
@@ -34978,13 +35452,14 @@ var PipesPipeProvider = class {
|
|
|
34978
35452
|
watch.dispose();
|
|
34979
35453
|
}
|
|
34980
35454
|
}
|
|
34981
|
-
async retireFailedCreate(name, logicalId, error, mask) {
|
|
35455
|
+
async retireFailedCreate(name, logicalId, resourceType, error, mask) {
|
|
34982
35456
|
const original = error instanceof Error ? error : new Error(String(error));
|
|
35457
|
+
const leftBehind = () => markCreatedBeforeFailure(original, logicalId, resourceType, name);
|
|
34983
35458
|
const orphaned = async (why) => {
|
|
34984
35459
|
const aws = pasteableAwsCommand(mask);
|
|
34985
35460
|
const command = aws`aws pipes delete-pipe --name ${name}${await orphanCommandRegionArg(this.getClient(), aws)}`;
|
|
34986
|
-
original.message += ` (cdkd could not delete the pipe it had created: ${why}; it
|
|
34987
|
-
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();
|
|
34988
35463
|
};
|
|
34989
35464
|
try {
|
|
34990
35465
|
await this.getClient().send(new DeletePipeCommand({ Name: name }));
|
|
@@ -35027,7 +35502,7 @@ var PipesPipeProvider = class {
|
|
|
35027
35502
|
const describe = aws`aws pipes describe-pipe --name ${name}${region}`;
|
|
35028
35503
|
const remove = aws`aws pipes delete-pipe --name ${name}${region}`;
|
|
35029
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.)");
|
|
35030
|
-
return
|
|
35505
|
+
return leftBehind();
|
|
35031
35506
|
}
|
|
35032
35507
|
};
|
|
35033
35508
|
|
|
@@ -35260,6 +35735,7 @@ var EFSProvider = class {
|
|
|
35260
35735
|
if (reservation.ledgerStartedThisDeploy) await this.warnOfPreLedgerHolder(logicalId, reservation.base, log);
|
|
35261
35736
|
const tags = properties["FileSystemTags"];
|
|
35262
35737
|
let fileSystemId;
|
|
35738
|
+
let fileSystemLeftBehind = false;
|
|
35263
35739
|
try {
|
|
35264
35740
|
const created = await this.sendCreateFileSystem(logicalId, resourceType, reservation, {
|
|
35265
35741
|
CreationToken: creationToken,
|
|
@@ -35298,12 +35774,14 @@ var EFSProvider = class {
|
|
|
35298
35774
|
this.unconfirmedCreationTokens.delete(creationToken);
|
|
35299
35775
|
log.debug(`Rolled back partially-created EFS FileSystem ${fileSystemId}`);
|
|
35300
35776
|
} catch (cleanupError) {
|
|
35777
|
+
fileSystemLeftBehind = true;
|
|
35301
35778
|
log.warn(`Failed to roll back partially-created EFS FileSystem ${fileSystemId}: ${describeAwsFailure(cleanupError).detail}`);
|
|
35302
35779
|
}
|
|
35303
35780
|
}
|
|
35304
|
-
if (error instanceof ProvisioningError) throw error;
|
|
35305
35781
|
const cause = error instanceof Error ? error : void 0;
|
|
35306
|
-
|
|
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;
|
|
35307
35785
|
}
|
|
35308
35786
|
}
|
|
35309
35787
|
async sendCreateFileSystem(logicalId, resourceType, reservation, input) {
|
|
@@ -35448,12 +35926,14 @@ var EFSProvider = class {
|
|
|
35448
35926
|
const subnetId = properties["SubnetId"];
|
|
35449
35927
|
if (!subnetId) throw new ProvisioningError(`SubnetId is required for EFS MountTarget ${logicalId}`, resourceType, logicalId);
|
|
35450
35928
|
const securityGroups = properties["SecurityGroups"];
|
|
35929
|
+
let createdMountTargetId;
|
|
35451
35930
|
try {
|
|
35452
35931
|
const mountTargetId = (await this.getClient().send(new CreateMountTargetCommand({
|
|
35453
35932
|
FileSystemId: fileSystemId,
|
|
35454
35933
|
SubnetId: subnetId,
|
|
35455
35934
|
SecurityGroups: securityGroups
|
|
35456
35935
|
}))).MountTargetId;
|
|
35936
|
+
createdMountTargetId = mountTargetId;
|
|
35457
35937
|
log.debug(`Created EFS MountTarget ${logicalId}: ${mountTargetId}, waiting for available state`);
|
|
35458
35938
|
await this.waitForMountTargetAvailable(mountTargetId, logicalId, resourceType, log);
|
|
35459
35939
|
log.debug(`Successfully created EFS MountTarget ${logicalId}: ${mountTargetId}`);
|
|
@@ -35462,9 +35942,10 @@ var EFSProvider = class {
|
|
|
35462
35942
|
attributes: {}
|
|
35463
35943
|
};
|
|
35464
35944
|
} catch (error) {
|
|
35465
|
-
if (error instanceof ProvisioningError) throw error;
|
|
35466
35945
|
const cause = error instanceof Error ? error : void 0;
|
|
35467
|
-
|
|
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;
|
|
35468
35949
|
}
|
|
35469
35950
|
}
|
|
35470
35951
|
async waitForMountTargetAvailable(mountTargetId, logicalId, resourceType, log) {
|
|
@@ -36004,16 +36485,27 @@ var FSxFileSystemProvider = class {
|
|
|
36004
36485
|
attributes: this.buildAttributes(fs)
|
|
36005
36486
|
};
|
|
36006
36487
|
} catch (error) {
|
|
36488
|
+
let survivorId;
|
|
36007
36489
|
if (fileSystemId !== void 0) try {
|
|
36008
36490
|
await this.getClient().send(new DeleteFileSystemCommand$1({ FileSystemId: fileSystemId }));
|
|
36009
36491
|
this.createTokenFirstSentAt.delete(clientRequestToken);
|
|
36010
36492
|
this.logger.warn(`Rolled back partially-created FSx FileSystem ${fileSystemId}`);
|
|
36011
36493
|
} catch (cleanupError) {
|
|
36012
|
-
|
|
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;
|
|
36013
36500
|
}
|
|
36014
|
-
if (error instanceof ProvisioningError) throw error;
|
|
36015
36501
|
const cause = error instanceof Error ? error : void 0;
|
|
36016
|
-
|
|
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);
|
|
36017
36509
|
}
|
|
36018
36510
|
}
|
|
36019
36511
|
toCreateLustreConfiguration(config) {
|
|
@@ -36991,6 +37483,7 @@ var EMRClusterProvider = class {
|
|
|
36991
37483
|
attributes: this.buildAttributes(cluster)
|
|
36992
37484
|
};
|
|
36993
37485
|
} catch (error) {
|
|
37486
|
+
let survivorId;
|
|
36994
37487
|
if (clusterId !== void 0) try {
|
|
36995
37488
|
await this.getClient().send(new SetTerminationProtectionCommand({
|
|
36996
37489
|
JobFlowIds: [clusterId],
|
|
@@ -36999,11 +37492,21 @@ var EMRClusterProvider = class {
|
|
|
36999
37492
|
await this.getClient().send(new TerminateJobFlowsCommand({ JobFlowIds: [clusterId] }));
|
|
37000
37493
|
this.logger.warn(`Rolled back partially-created EMR Cluster ${clusterId}`);
|
|
37001
37494
|
} catch (cleanupError) {
|
|
37495
|
+
survivorId = clusterId;
|
|
37002
37496
|
this.logger.warn(`Failed to roll back partially-created EMR Cluster ${clusterId}: ${describeAwsFailure(cleanupError).detail} — terminate it manually to stop billing`);
|
|
37003
37497
|
}
|
|
37004
|
-
if (error instanceof ProvisioningError)
|
|
37498
|
+
if (error instanceof ProvisioningError) {
|
|
37499
|
+
if (survivorId !== void 0) markCreatedBeforeFailure(error, logicalId, resourceType, survivorId);
|
|
37500
|
+
throw error;
|
|
37501
|
+
}
|
|
37005
37502
|
const cause = error instanceof Error ? error : void 0;
|
|
37006
|
-
|
|
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);
|
|
37007
37510
|
}
|
|
37008
37511
|
}
|
|
37009
37512
|
toJobFlowInstancesConfig(config) {
|
|
@@ -37587,6 +38090,7 @@ var EMRInstanceGroupConfigProvider = class {
|
|
|
37587
38090
|
const jobFlowId = properties["JobFlowId"];
|
|
37588
38091
|
if (!jobFlowId) throw new ProvisioningError(`EMR InstanceGroupConfig ${logicalId} is missing JobFlowId (the parent cluster id)`, resourceType, logicalId);
|
|
37589
38092
|
this.logger.debug(`Adding EMR instance group ${logicalId} to cluster ${jobFlowId}`);
|
|
38093
|
+
let createdGroupId;
|
|
37590
38094
|
try {
|
|
37591
38095
|
const group = this.toInstanceGroupConfig(properties);
|
|
37592
38096
|
const orphanWindow = addInstanceGroupsLatch.take(logicalId);
|
|
@@ -37629,6 +38133,7 @@ var EMRInstanceGroupConfigProvider = class {
|
|
|
37629
38133
|
}
|
|
37630
38134
|
const groupId = response.InstanceGroupIds?.[0];
|
|
37631
38135
|
if (groupId) groupsCreatedByThisProcess.add(groupId);
|
|
38136
|
+
createdGroupId = groupId;
|
|
37632
38137
|
if (!groupId) throw new ProvisioningError(`EMR AddInstanceGroups for ${logicalId} returned no instance group id`, resourceType, logicalId);
|
|
37633
38138
|
await this.waitForGroupReady(jobFlowId, groupId, logicalId, resourceType, toNumber$1(properties["InstanceCount"]) ?? 0);
|
|
37634
38139
|
this.logger.debug(`Successfully added EMR instance group ${logicalId}: ${groupId}`);
|
|
@@ -37640,9 +38145,9 @@ var EMRInstanceGroupConfigProvider = class {
|
|
|
37640
38145
|
}
|
|
37641
38146
|
};
|
|
37642
38147
|
} catch (error) {
|
|
37643
|
-
|
|
37644
|
-
|
|
37645
|
-
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;
|
|
37646
38151
|
}
|
|
37647
38152
|
}
|
|
37648
38153
|
toInstanceGroupConfig(properties) {
|
|
@@ -37881,6 +38386,7 @@ var EMRInstanceFleetConfigProvider = class {
|
|
|
37881
38386
|
const clusterId = properties["ClusterId"];
|
|
37882
38387
|
if (!clusterId) throw new ProvisioningError(`EMR InstanceFleetConfig ${logicalId} is missing ClusterId (the parent cluster id)`, resourceType, logicalId);
|
|
37883
38388
|
this.logger.debug(`Adding EMR instance fleet ${logicalId} to cluster ${clusterId}`);
|
|
38389
|
+
let createdFleetId;
|
|
37884
38390
|
try {
|
|
37885
38391
|
const fleet = this.toInstanceFleetConfig(properties);
|
|
37886
38392
|
const orphanWindow = addInstanceFleetLatch.take(logicalId);
|
|
@@ -37923,6 +38429,7 @@ var EMRInstanceFleetConfigProvider = class {
|
|
|
37923
38429
|
}
|
|
37924
38430
|
const fleetId = response.InstanceFleetId;
|
|
37925
38431
|
if (fleetId) fleetsCreatedByThisProcess.add(fleetId);
|
|
38432
|
+
createdFleetId = fleetId;
|
|
37926
38433
|
if (!fleetId) throw new ProvisioningError(`EMR AddInstanceFleet for ${logicalId} returned no instance fleet id`, resourceType, logicalId);
|
|
37927
38434
|
await this.waitForFleetReady(clusterId, fleetId, logicalId, resourceType, this.targetCapacities(properties), {
|
|
37928
38435
|
onDemand: 0,
|
|
@@ -37934,9 +38441,9 @@ var EMRInstanceFleetConfigProvider = class {
|
|
|
37934
38441
|
attributes: { Id: fleetId }
|
|
37935
38442
|
};
|
|
37936
38443
|
} catch (error) {
|
|
37937
|
-
|
|
37938
|
-
|
|
37939
|
-
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;
|
|
37940
38447
|
}
|
|
37941
38448
|
}
|
|
37942
38449
|
toInstanceFleetConfig(properties) {
|
|
@@ -38159,6 +38666,7 @@ var FirehoseProvider = class {
|
|
|
38159
38666
|
const deliveryStreamName = properties["DeliveryStreamName"];
|
|
38160
38667
|
const deliveryStreamType = properties["DeliveryStreamType"] || "DirectPut";
|
|
38161
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;
|
|
38162
38670
|
try {
|
|
38163
38671
|
const input = {
|
|
38164
38672
|
DeliveryStreamName: deliveryStreamName || logicalId,
|
|
@@ -38287,6 +38795,7 @@ var FirehoseProvider = class {
|
|
|
38287
38795
|
}));
|
|
38288
38796
|
const response = await this.getClient().send(new CreateDeliveryStreamCommand(input));
|
|
38289
38797
|
const physicalId = deliveryStreamName || input.DeliveryStreamName || response.DeliveryStreamARN?.split("/").pop() || "";
|
|
38798
|
+
createdStreamName = physicalId;
|
|
38290
38799
|
const arn = response.DeliveryStreamARN;
|
|
38291
38800
|
this.logger.debug(`Successfully created Firehose delivery stream ${logicalId}: ${physicalId}`);
|
|
38292
38801
|
await this.waitForActive(physicalId, logicalId);
|
|
@@ -38295,9 +38804,9 @@ var FirehoseProvider = class {
|
|
|
38295
38804
|
attributes: { Arn: arn }
|
|
38296
38805
|
};
|
|
38297
38806
|
} catch (error) {
|
|
38298
|
-
|
|
38299
|
-
|
|
38300
|
-
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;
|
|
38301
38810
|
}
|
|
38302
38811
|
}
|
|
38303
38812
|
async update(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
@@ -39041,6 +39550,7 @@ var CloudTrailProvider = class {
|
|
|
39041
39550
|
const eventSelectors = properties["EventSelectors"];
|
|
39042
39551
|
const insightSelectors = properties["InsightSelectors"];
|
|
39043
39552
|
let trailCreated = false;
|
|
39553
|
+
let createdTrailArn;
|
|
39044
39554
|
try {
|
|
39045
39555
|
const result = await this.getClient().send(new CreateTrailCommand({
|
|
39046
39556
|
Name: trailName ?? logicalId,
|
|
@@ -39061,6 +39571,7 @@ var CloudTrailProvider = class {
|
|
|
39061
39571
|
}));
|
|
39062
39572
|
trailCreated = true;
|
|
39063
39573
|
const trailArn = result.TrailARN;
|
|
39574
|
+
createdTrailArn = result.TrailARN;
|
|
39064
39575
|
if (eventSelectors && eventSelectors.length > 0) {
|
|
39065
39576
|
this.logger.debug(`Setting event selectors for CloudTrail Trail ${logicalId}`);
|
|
39066
39577
|
await this.getClient().send(new PutEventSelectorsCommand({
|
|
@@ -39087,7 +39598,9 @@ var CloudTrailProvider = class {
|
|
|
39087
39598
|
} catch (error) {
|
|
39088
39599
|
if (trailCreated) markAuxiliaryFailure(error, logicalId);
|
|
39089
39600
|
const cause = error instanceof Error ? error : void 0;
|
|
39090
|
-
|
|
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;
|
|
39091
39604
|
}
|
|
39092
39605
|
}
|
|
39093
39606
|
async update(logicalId, physicalId, resourceType, properties, previousProperties, context) {
|
|
@@ -39873,6 +40386,7 @@ var CodeCommitRepositoryProvider = class {
|
|
|
39873
40386
|
Triggers: properties["Triggers"],
|
|
39874
40387
|
Tags: properties["Tags"]
|
|
39875
40388
|
}, void 0);
|
|
40389
|
+
let leftLiveName;
|
|
39876
40390
|
try {
|
|
39877
40391
|
const tags = toSdkTagMap(lists.Tags);
|
|
39878
40392
|
const description = properties["RepositoryDescription"];
|
|
@@ -39885,6 +40399,7 @@ var CodeCommitRepositoryProvider = class {
|
|
|
39885
40399
|
}))).repositoryMetadata;
|
|
39886
40400
|
if (!metadata?.repositoryName) throw new Error("CreateRepository did not return repository metadata");
|
|
39887
40401
|
const createdName = metadata.repositoryName;
|
|
40402
|
+
leftLiveName = createdName;
|
|
39888
40403
|
try {
|
|
39889
40404
|
const code = properties["Code"];
|
|
39890
40405
|
if (code) await this.seedInitialCommit(createdName, code);
|
|
@@ -39898,7 +40413,7 @@ var CodeCommitRepositoryProvider = class {
|
|
|
39898
40413
|
}
|
|
39899
40414
|
} catch (postCreateError) {
|
|
39900
40415
|
this.logger.warn(`Post-create step failed for CodeCommit Repository ${logicalId}; deleting the just-created repository ${createdName} to avoid an orphan`);
|
|
39901
|
-
await this.bestEffortDelete(createdName);
|
|
40416
|
+
if (await this.bestEffortDelete(createdName)) leftLiveName = void 0;
|
|
39902
40417
|
throw markAuxiliaryFailure(postCreateError, logicalId);
|
|
39903
40418
|
}
|
|
39904
40419
|
this.logger.debug(`Successfully created CodeCommit Repository ${logicalId}: ${createdName}`);
|
|
@@ -39908,7 +40423,9 @@ var CodeCommitRepositoryProvider = class {
|
|
|
39908
40423
|
};
|
|
39909
40424
|
} catch (error) {
|
|
39910
40425
|
const cause = error instanceof Error ? error : void 0;
|
|
39911
|
-
|
|
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;
|
|
39912
40429
|
}
|
|
39913
40430
|
}
|
|
39914
40431
|
async update(logicalId, physicalId, resourceType, properties, previousProperties, context) {
|
|
@@ -40236,8 +40753,10 @@ var CodeCommitRepositoryProvider = class {
|
|
|
40236
40753
|
async bestEffortDelete(repositoryName) {
|
|
40237
40754
|
try {
|
|
40238
40755
|
await this.getClient().send(new DeleteRepositoryCommand$1({ repositoryName }));
|
|
40756
|
+
return true;
|
|
40239
40757
|
} catch (cleanupError) {
|
|
40240
40758
|
this.logger.warn(`Failed to clean up CodeCommit Repository ${repositoryName} after a post-create failure: ${describeAwsFailure(cleanupError).detail}`);
|
|
40759
|
+
return false;
|
|
40241
40760
|
}
|
|
40242
40761
|
}
|
|
40243
40762
|
async getRepositoryMetadata(repositoryName) {
|
|
@@ -40805,6 +41324,7 @@ var S3DirectoryBucketProvider = class {
|
|
|
40805
41324
|
const tags = desiredTags;
|
|
40806
41325
|
const includeTags = tags.length > 0;
|
|
40807
41326
|
try {
|
|
41327
|
+
const attributes = await this.buildAttributes(bucketName);
|
|
40808
41328
|
await this.s3Client.send(new CreateBucketCommand({
|
|
40809
41329
|
Bucket: bucketName,
|
|
40810
41330
|
CreateBucketConfiguration: {
|
|
@@ -40820,7 +41340,6 @@ var S3DirectoryBucketProvider = class {
|
|
|
40820
41340
|
}
|
|
40821
41341
|
}));
|
|
40822
41342
|
this.logger.debug(`Created S3 Express Directory Bucket: ${bucketName}`);
|
|
40823
|
-
const attributes = await this.buildAttributes(bucketName);
|
|
40824
41343
|
return {
|
|
40825
41344
|
physicalId: bucketName,
|
|
40826
41345
|
attributes
|
|
@@ -41241,6 +41760,7 @@ var S3TablesProvider = class {
|
|
|
41241
41760
|
maskSecrets: context?.maskSecrets,
|
|
41242
41761
|
...context?.replayingState === true && { onRefusal: (message) => this.logger.warn(message) }
|
|
41243
41762
|
});
|
|
41763
|
+
let tableCreated = false;
|
|
41244
41764
|
try {
|
|
41245
41765
|
const response = await this.getClient().send(new CreateTableCommand$2({
|
|
41246
41766
|
tableBucketARN,
|
|
@@ -41249,6 +41769,7 @@ var S3TablesProvider = class {
|
|
|
41249
41769
|
format,
|
|
41250
41770
|
...tags !== void 0 && { tags }
|
|
41251
41771
|
}));
|
|
41772
|
+
tableCreated = true;
|
|
41252
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);
|
|
41253
41774
|
const tableARN = response.tableARN;
|
|
41254
41775
|
this.logger.debug(`Successfully created S3 Tables Table ${logicalId}: ${physicalId}`);
|
|
@@ -41258,7 +41779,9 @@ var S3TablesProvider = class {
|
|
|
41258
41779
|
};
|
|
41259
41780
|
} catch (error) {
|
|
41260
41781
|
const cause = error instanceof Error ? error : void 0;
|
|
41261
|
-
|
|
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;
|
|
41262
41785
|
}
|
|
41263
41786
|
}
|
|
41264
41787
|
async readCurrentState(physicalId, logicalId, resourceType) {
|
|
@@ -41742,7 +42265,9 @@ var ECRProvider = class {
|
|
|
41742
42265
|
} catch (error) {
|
|
41743
42266
|
if (repositoryCreated) markAuxiliaryFailure(error, logicalId);
|
|
41744
42267
|
const cause = error instanceof Error ? error : void 0;
|
|
41745
|
-
|
|
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;
|
|
41746
42271
|
}
|
|
41747
42272
|
}
|
|
41748
42273
|
async update(logicalId, physicalId, resourceType, properties, previousProperties) {
|
|
@@ -41956,7 +42481,7 @@ var NestedStackProvider = class {
|
|
|
41956
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)"],
|
|
41957
42482
|
["TimeoutInMinutes", "CFn-only stack-create deadline — cdkd uses per-resource --resource-timeout instead (issue #459 design §9)"]
|
|
41958
42483
|
])]]);
|
|
41959
|
-
async create(logicalId,
|
|
42484
|
+
async create(logicalId, resourceType, properties, context) {
|
|
41960
42485
|
const ctx = this.requireContext();
|
|
41961
42486
|
this.requireDeployContext(ctx, "create");
|
|
41962
42487
|
const childTemplatePath = ctx.nestedTemplates[logicalId];
|
|
@@ -41968,15 +42493,27 @@ var NestedStackProvider = class {
|
|
|
41968
42493
|
const childParameters = this.extractParameters(properties);
|
|
41969
42494
|
const resourceCount = Object.keys(childTemplate.Resources ?? {}).length;
|
|
41970
42495
|
this.logger.info(`Deploying nested stack ${displaySafe(childStackName)} (logicalId=${displaySafe(logicalId)}, ${resourceCount} resource(s))`);
|
|
41971
|
-
|
|
41972
|
-
|
|
41973
|
-
|
|
41974
|
-
|
|
41975
|
-
|
|
41976
|
-
|
|
41977
|
-
|
|
41978
|
-
|
|
41979
|
-
|
|
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
|
+
}
|
|
41980
42517
|
}
|
|
41981
42518
|
async update(logicalId, physicalId, _resourceType, properties, _previousProperties, context) {
|
|
41982
42519
|
const ctx = this.requireContext();
|
|
@@ -42063,6 +42600,7 @@ var NestedStackProvider = class {
|
|
|
42063
42600
|
...ctx.destroyOptions?.statePrefix !== void 0 && { statePrefix: ctx.destroyOptions.statePrefix },
|
|
42064
42601
|
...deleteContext?.removeProtection === true && { removeProtection: true },
|
|
42065
42602
|
...deleteContext?.resolveSecretDerivedPrincipals !== void 0 && { resolveSecretDerivedPrincipals: { inheritedProducerRegions: deleteContext.resolveSecretDerivedPrincipals.importedProducerRegions } },
|
|
42603
|
+
...deleteContext?.stackDestroy === true && { stackDestroy: true },
|
|
42066
42604
|
...(ctx.destroyOptions?.skipFinalSnapshot === true || ctx.options?.skipFinalSnapshot === true) && { skipFinalSnapshot: true },
|
|
42067
42605
|
...ctx.destroyOptions?.resourceWarnAfterMs !== void 0 && { resourceWarnAfterMs: ctx.destroyOptions.resourceWarnAfterMs },
|
|
42068
42606
|
...ctx.destroyOptions?.resourceTimeoutMs !== void 0 && { resourceTimeoutMs: ctx.destroyOptions.resourceTimeoutMs },
|
|
@@ -42346,11 +42884,19 @@ var ACMCertificateProvider = class {
|
|
|
42346
42884
|
const survivorNote = requestedArn ? await this.cleanupRequestedCertificate(requestedArn, logicalId, idempotencyToken) : void 0;
|
|
42347
42885
|
if (error instanceof CdkdError) {
|
|
42348
42886
|
if (survivorNote === void 0) throw error;
|
|
42349
|
-
|
|
42887
|
+
const thrown = new ProvisioningError(`${error.message} ${survivorNote}`, resourceType, logicalId, requestedArn, error);
|
|
42888
|
+
if (requestedArn) markCreatedBeforeFailure(thrown, logicalId, resourceType, requestedArn);
|
|
42889
|
+
throw thrown;
|
|
42350
42890
|
}
|
|
42351
42891
|
const cause = error instanceof Error ? error : void 0;
|
|
42352
42892
|
const detail = error instanceof Error ? error.message : String(error);
|
|
42353
|
-
|
|
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);
|
|
42354
42900
|
}
|
|
42355
42901
|
}
|
|
42356
42902
|
regionOfArn(arn) {
|
|
@@ -42590,4 +43136,4 @@ var ACMCertificateProvider = class {
|
|
|
42590
43136
|
|
|
42591
43137
|
//#endregion
|
|
42592
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 };
|
|
42593
|
-
//# sourceMappingURL=provider-classes-
|
|
43139
|
+
//# sourceMappingURL=provider-classes-DMOnX5s-.js.map
|