feat: force-delete phantom Cognito UserPoolUICustomizationAttachment (#647)#648
Merged
Merged
Conversation
…647) A stack containing AWS::Cognito::UserPoolUICustomizationAttachment whose CREATE fails (e.g. no UserPoolDomain exists) leaves a phantom resource in DELETE_FAILED on rollback: it does not actually exist in AWS, but CloudFormation cannot delete "nothing", so the stack is stuck. delstack previously aborted the whole deletion with UnsupportedResourceError instead of removing the stack. Add a no-op Operator for this type (mirroring the existing CustomOperator): there is no real, billable resource to delete, so the CFN delete loop retains the logical resource to drop the phantom from the stack. This keeps delstack true to "no orphaned resources" because a phantom is, by definition, nothing left behind, unlike CloudFormation's blanket FORCE_DELETE_STACK. Also add a generic `e2e/create_failed` scenario that manufactures a create-failed phantom (via this Cognito attachment without a domain) and verifies delstack force-deletes the stuck stack. It stands in for the whole class of create-failed phantom types (Custom Resources and Attachment/Association/Settings style resources with non-idempotent delete handlers).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #647.
Problem
A stack containing
AWS::Cognito::UserPoolUICustomizationAttachmentwhose CREATE fails (it requires an existingUserPoolDomain) leaves a phantom inDELETE_FAILEDon rollback: the resource does not actually exist in AWS, but CloudFormation cannot delete "nothing" cleanly, so the stack is stuck inROLLBACK_FAILED.Because the type was not in the force-delete support list, delstack aborted the entire deletion with
UnsupportedResourceErrorinstead of removing the stack.Approach: per-type Operator, not a generic retain
The issue suggested a type-agnostic "retain anything that can't be force-deleted" fallback. That was deliberately not adopted: blanket-retaining unknown
DELETE_FAILEDresources can silently leave real, billable resources behind, which makes delstack equivalent to CloudFormation's built-inFORCE_DELETE_STACK, erasing the "no orphaned resources" guarantee that is delstack's reason to exist.Instead this adds a no-op Operator for this specific type, mirroring the existing
CustomOperator:SetUICustomization, which requires a domain. It reachesDELETE_FAILEDonly as a phantom, where there is genuinely nothing to delete.DELETE_FAILED.The phantom-on-failed-create phenomenon is a bounded class (resource providers with non-idempotent delete handlers: Custom Resources, Attachment/Association/Settings style types), not universal, and its biggest source (Custom Resources) is already covered. So per-type support remains sustainable; unknown types still abort loudly rather than orphaning anything.
Changes
resourcetype: addCognitoUserPoolUICustomizationAttachment.internal/operation/cognito_user_pool_ui_customization_attachment.go: no-op Operator + rationale comment.operator_factory.go/operator_collection.go: wire it in (4 sites + supported-resources table row).operator_collection_test.go: cover the new type (asserts it is now supported, not unsupported).README.md: add a row to the supported-resources table.E2E
New generic
e2e/create_failedscenario (not Cognito-specific by intent):ROLLBACK_FAILEDstack with aDELETE_FAILEDphantom.deploy.gotreats the expectedcdk deployfailure as non-fatal and verifies the phantom precondition (errors out if no phantom was produced, so it never validates silently).make e2e_create_failedthen runs delstack and confirms the stuck stack is force-deleted.Verified locally:
make lint_diffclean,make testgreen, both e2e modulesgo vet/go build, andcdk synthproduces the intended template (logical idUICustomization, no domain). Real AWS E2E runs are left to the maintainer per project convention.