-
Notifications
You must be signed in to change notification settings - Fork 36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
AWS::CloudFormation::ResourceVersion - Define createOnlyProperties #24
Conversation
Every registration of a CloudFormation Resource Provider creates a new version, which is identified by a version-specific ARN. This means there isn't technically an "update" of a resource provider; each registration is a new distinct resource. This was accounted for by excluding an `UpdateHandler` for this `AWS::CloudFormation::ResourceVersion` resource provider. The schema for this resource provider does not define any `createOnlyProperties`. Therefore, any attempt to use this resource provider to register another resource provider would only work during the `CREATE`; any attempt to `UPDATE` the resource (e.g. changing `SchemaHandlerPackage` to an updated source package) would try to update the resource rather than triggering a replacement, which would fail due to the lack of an `UpdateHandler` (the resource would enter the `UPDATE_FAILED` state with a message of "Internal Failure", and no logs would be present in CloudWatch Logs). Since changing any of the writable `Properties` of this resource provider results in a new physical resource (identified in the resource provider as the versioned `Arn`), all of these properties must be `createOnlyProperties` to force a replacement rather than an update. In essence, this resource is logically very similar to `AWS::ECS::TaskDefinition` - both resources use a versioned identifier, and any change results in a new version. Any change to a `TaskDefinition` results in resource replacement, followed by unregistration of the previous version during stack cleanup. This PR results in `AWS::CloudFormation::ResourceVersion` logically behaving the same. One caveat is that `AWS::CloudFormation::ResourceVersion` really needs to be used in tandem with the `AWS::CloudFormation::ResourceDefaultVersion` resource to automatically update the default version. Otherwise, if a created `ResourceVersion` is the default version for that type (e.g. the `CREATE` was the first registration of a new/deleted resource type, or `SetTypeDefaultVersion` was used externally), an update will fail to delete the previous resource during the stack cleanup stage, resulting in an error of `This type has more than one active version. Please deregister non-default active versions before attempting to deregister the type.`. I also re-ordered the `readOnlyProperties` to be alphabetical, which matches the order in which they are defined in `/properties`.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I need a small clarification on this line "any attempt to UPDATE the resource (e.g. changing SchemaHandlerPackage to an updated source package) would try to update the resource rather than triggering a replacement, which would fail due to the lack of an UpdateHandler". I don't think this is happening because absence of an update handler will call replacement every time, we need not explicitly make all properties "createOnly" for this. The resource should not enter UPDATE_FAILED state here.
And regarding the resource version being the default version when created for the first time, yes I agree with you that the cleanup won't be successful here, but this is expected and the resource that failed to be deleted is the leaked resource. That's why we are expected to create a default version for every type created. Also, this doesn't cause any update failure because the creation was successful, only the clean up was not. |
This does appear to be what should happen according to the documentation, but it doesn't happen in practice. The AWS Resource Type Schema documentation states under
So it seems like CloudFormation should make the assumption that an UPDATE isn't possible if no update handler (
At step 4, the current
Whereas using code in this PR resulted in the following events:
The RPDK doesn't push anything to CloudWatch Logs outside of the handler so we don't get any further details indicating what happened, but it's been very repeatable; multiple tests over multiple days were able to CREATE in every single instance, but every single UPDATE would fail in exactly the same way, so it's highly unlikely it was a transient issue. Therefore it appears as though CloudFormation is using the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Discussed with the team offline and it looks like having these properties (ExecutionRoleArn, LoggingConfig, SchemaHandlerPackage and TypeName) as createOnly would make it clear that no properties are updatable for this resource.
I'm getting an "Internal Error" when I try to update a ResourceVersion using the resource type that is available in AWS accounts. Is there an ETA on this getting merged? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like the PR has merge conflicts. @opalelement would you send out a PR with the latest code from the master?
Is this still a valid change due to #51 ? It seems to work as expected now |
Yes, this PR can be closed now as the changes were made in #51. |
We're seeing CloudFormation "Internal Failure" errors on update for our |
Yes, #51 is live. You should not get any Internal Failures now. Were you using Changesets for update? |
Yep. Pasted below. Our CICD system tags CloudFormation stacks on deploy. Looks like these tags are cascading down to the {
"resourceChange": {
"logicalResourceId": "ClientResourceDefaultVersion",
"action": "Modify",
"physicalResourceId": "arn:aws:cloudformation:us-east-1:#########:type/resource/#######",
"resourceType": "AWS::CloudFormation::ResourceDefaultVersion",
"replacement": "False",
"moduleInfo": null,
"details": [
{
"target": {
"name": null,
"requiresRecreation": "Never",
"attribute": "Tags"
},
"causingEntity": null,
"evaluation": "Static",
"changeSource": null
},
{
"target": {
"name": "TypeVersionArn",
"requiresRecreation": "Never",
"attribute": "Properties"
},
"causingEntity": "ClientResourceVersion",
"evaluation": "Dynamic",
"changeSource": "ResourceReference"
}
],
"changeSetId": null,
"scope": [
"Properties",
"Tags"
]
},
"hookInvocationCount": null,
"type": "Resource"
} |
Oops, included the {
"resourceChange": {
"logicalResourceId": "ClientResourceVersion",
"action": "Modify",
"physicalResourceId": "arn:aws:cloudformation:us-east-1:###########:type/resource/#########/00000007",
"resourceType": "AWS::CloudFormation::ResourceVersion",
"replacement": "Conditional",
"moduleInfo": null,
"details": [
{
"target": {
"name": "LoggingConfig",
"requiresRecreation": "Always",
"attribute": "Properties"
},
"causingEntity": "ResourceLogRole.Arn",
"evaluation": "Dynamic",
"changeSource": "ResourceAttribute"
},
{
"target": {
"name": "ExecutionRoleArn",
"requiresRecreation": "Always",
"attribute": "Properties"
},
"causingEntity": "ResourceRole.Arn",
"evaluation": "Dynamic",
"changeSource": "ResourceAttribute"
},
{
"target": {
"name": null,
"requiresRecreation": "Never",
"attribute": "Tags"
},
"causingEntity": null,
"evaluation": "Static",
"changeSource": null
}
],
"changeSetId": null,
"scope": [
"Properties",
"Tags"
]
},
"hookInvocationCount": null,
"type": "Resource"
} |
@ugudip any word? Would you like me to open a new issue for tag updates causing the "internal failure" error? |
yes, that would be helpful. Can you pls add all the details in the request? |
Created in #58 |
Description of changes:
Every registration of a CloudFormation Resource Provider creates a new version, which is identified by a version-specific ARN. This means there isn't technically an "update" of a resource provider; each registration is a new distinct resource. This was accounted for by excluding an
UpdateHandler
for thisAWS::CloudFormation::ResourceVersion
resource provider.The schema for this resource provider does not define any
createOnlyProperties
. Therefore, any attempt to use this resource provider to register another resource provider would only work during theCREATE
; any attempt toUPDATE
the resource (e.g. changingSchemaHandlerPackage
to an updated source package) would try to update the resource rather than triggering a replacement, which would fail due to the lack of anUpdateHandler
(the resource would enter theUPDATE_FAILED
state with a message of "Internal Failure", and no logs would be present in CloudWatch Logs).Since changing any of the writable
Properties
of this resource provider results in a new physical resource (identified in the resource provider as the versionedArn
), all of these properties must becreateOnlyProperties
to force a replacement rather than an update. In essence, this resource is logically very similar toAWS::ECS::TaskDefinition
- both resources use a versioned identifier, and any change results in a new version. Any change to aTaskDefinition
results in resource replacement, followed by unregistration of the previous version during stack cleanup. This PR results inAWS::CloudFormation::ResourceVersion
logically behaving the same.One caveat is that
AWS::CloudFormation::ResourceVersion
really needs to be used in tandem with theAWS::CloudFormation::ResourceDefaultVersion
resource to automatically update the default version. Otherwise, if a createdResourceVersion
is the default version for that type (e.g. theCREATE
was the first registration of a new/deleted resource type, orSetTypeDefaultVersion
was used externally), an update will fail to delete the previous resource during the stack cleanup stage, resulting in an error ofThis type has more than one active version. Please deregister non-default active versions before attempting to deregister the type.
.I also re-ordered the
readOnlyProperties
to be alphabetical, which matches the order in which they are defined in/properties
.