cdkd deploy: custom resources
A custom resource is a resource whose create, update and delete are carried
out by a handler you supply, usually a Lambda function. The resource's
ServiceToken property is the handler's ARN. This page covers the two
situations where cdkd deploy treats a custom resource differently from other
resources: the ServiceToken changed, or cdkd could not send the delete.
A changed custom-resource ServiceToken
cdkd deploy refuses to change a custom resource's ServiceToken in place.
CloudFormation refuses it too, with Modifying service token is not allowed.
The reason is that the handler owns whatever it created. If cdkd sent the change as an update, only the new handler would hear about it. The old handler would never receive a delete for what it created.
How to move a custom resource to another handler
Give the resource a new logical id. In CDK that means a new construct id:
// Before:
// new CustomResource(this, 'Seed', { serviceToken: oldProvider.serviceToken });
new CustomResource(this, 'SeedV2', { serviceToken: newProvider.serviceToken });
The deploy then creates the new resource through the new handler and deletes
the old resource through its old handler. Calling overrideLogicalId on the
resource's CfnResource has the same effect.
No flag overrides the refusal. A resource named by --recreate-via-cc-api is
not refused, because that flag already deletes the old resource through the
recorded token and creates the new one through the template's.
When the refusal happens
cdkd compares the token recorded in state with the token in the new template.
A Ref or Fn::GetAtt whose ARN did not change is not a change. Otherwise,
when the refusal happens depends on what cdkd can compare.
The two tokens are different ARNs. cdkd refuses before anything is
provisioned, and --dry-run refuses as well. No handler is called and state
is unchanged.
The new token reads a resource that this deploy creates or replaces. A renamed Lambda function behind the custom resource, or a switch to a new provider, is this case. cdkd refuses once that resource exists, before it invokes the handler. The deploy fails and rolls back.
If the deploy was replacing the Lambda function, cdkd has already deleted the old function by then, and the rollback creates it again from its record. If that fails, or the function comes back under another name, the custom resource's record names a function that no longer exists.
The recorded token cannot be compared. The recorded token is missing, or
it is the mask ***, or it is a {{resolve:...}} reference. cdkd cannot
compare, so it refuses a deploy whose template changes the token.
If the handler did not change, edit state.json and put the ARN of the
handler that created the resource back as ServiceToken, then deploy again.
Use the ARN the resource was last deployed with. The ARN that the template
names now may be a different one.
The token comes from a NoEcho parameter. cdkd records such a token only
as ***. A new parameter value is therefore not detected, and the update goes
to whichever handler the new value names. To have such a change refused, feed
ServiceToken from a plain value.
A skipped custom-resource delete
A deploy deletes a custom resource when the resource leaves the template, is
replaced, or is rolled back. To delete it, cdkd invokes the handler. cdkd
skips the delete, as cdkd destroy does, in three cases:
- the handler answers
FAILED; - the invoke does not complete;
- the recorded
ServiceTokenis the mask***or a{{resolve:...}}reference.
What follows depends on why the resource was being deleted.
| Situation | Result |
|---|---|
| Removed from the template | The record is kept and the deploy exits 2. |
| Replaced delete-first, or rolled back | The resource usually fails and the record is kept. |
| The other copy already exists | The skip only warns, and the surviving copy is no longer tracked. |
The third row covers a replacement that created the new resource first, and a rollback that created the old resource again first. Tear the surviving copy down by hand.
A resource removed from the template
The next cdkd deploy sends the delete again. Before you run it, fix the
handler, or edit state.json and put the provider's ARN back as
ServiceToken.
If the handler's Lambda function no longer exists by then, that deploy drops the record with a warning, and you tear down what the handler managed by hand.
--allow-unaddressed lets a deploy exit 0 in the meantime. cdkd rollback
has no such flag.
Giving up on the delete
To stop tracking a resource that was removed from the template, drop only its record:
cdkd state orphan MyStack --stack-region us-east-1 --resource SeedResource
Caution
Do not run
cdkd state orphan MyStackwithout--resourcehere. It drops the record of every resource in the stack, so the next deploy creates them all again or collides with them. The whole-stack form is the remedy only oncdkd destroy, where the other records are already gone.
A ServiceToken that is not a string
A ServiceToken can end up as something other than a string, such as an
intrinsic function that was not resolved. The fix depends on the operation,
because each operation reads the token from a different place.
| Operation | Reads the token from | Fix |
|---|---|---|
| Create or update | The template | Fix the template and deploy again. |
| Rollback | The recorded value | Fix the template and deploy again. |
| Delete | The state record | Restore the ARN in state.json, or drop only that record with --resource. |
For a create, an update or a rollback, do not drop the record. Dropping the record of a resource that the template still declares makes the next deploy send the handler a new create.
Related
cdkd state: dropping one resource's record- cdkd destroy: the same skip on
cdkd destroy cdkd diff: previewing what a deploy would change- cdkd deploy: every deploy flag