-
Notifications
You must be signed in to change notification settings - Fork 4.3k
fix(dynamodb): replicas not created on table replacement #13300
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
Changes from 6 commits
e1662ce
c3d2ba8
d8583e1
eedc28d
5ad6a7b
1a07ea2
b3bd717
da275eb
e61f9a7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -5,27 +5,37 @@ import { DynamoDB } from 'aws-sdk'; // eslint-disable-line import/no-extraneous- | |||
| export async function onEventHandler(event: OnEventRequest): Promise<OnEventResponse> { | ||||
| console.log('Event: %j', event); | ||||
|
|
||||
| /** | ||||
| * Process only Create and Delete requests. We shouldn't receive any | ||||
| * update request and in case we do there is nothing to update. | ||||
| */ | ||||
| const dynamodb = new DynamoDB(); | ||||
|
|
||||
| let updateTableAction: 'Create' | 'Update' | 'Delete'; | ||||
|
|
||||
| if (event.RequestType === 'Create' || event.RequestType === 'Delete') { | ||||
| const dynamodb = new DynamoDB(); | ||||
|
|
||||
| const data = await dynamodb.updateTable({ | ||||
| TableName: event.ResourceProperties.TableName, | ||||
| ReplicaUpdates: [ | ||||
| { | ||||
| [event.RequestType]: { | ||||
| RegionName: event.ResourceProperties.Region, | ||||
| }, | ||||
| updateTableAction = event.RequestType; | ||||
| } else { // Update | ||||
| // This can only be a table replacement so we create a replica | ||||
| // in the new table. The replica for the "old" table will be | ||||
| // deleted when CF issues a Delete event on the old physical | ||||
| // resource id. | ||||
| updateTableAction = 'Create'; | ||||
| } | ||||
|
|
||||
| const data = await dynamodb.updateTable({ | ||||
| TableName: event.ResourceProperties.TableName, | ||||
| ReplicaUpdates: [ | ||||
| { | ||||
| [updateTableAction]: { | ||||
| RegionName: event.ResourceProperties.Region, | ||||
| }, | ||||
| ], | ||||
| }).promise(); | ||||
| console.log('Update table: %j', data); | ||||
| }, | ||||
| ], | ||||
| }).promise(); | ||||
| console.log('Update table: %j', data); | ||||
|
|
||||
| if (event.RequestType === 'Create' || event.RequestType === 'Update') { | ||||
| return { PhysicalResourceId: `${event.ResourceProperties.TableName}-${event.ResourceProperties.Region}` }; | ||||
|
||||
| throw new Error(`DELETE: cannot change the physical resource ID from "${cfnRequest.PhysicalResourceId}" to "${onEventResult.PhysicalResourceId}" during deletion`); |
jogold marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1670,12 +1670,19 @@ interface ScalableAttributePair { | |
| */ | ||
| class SourceTableAttachedPolicy extends CoreConstruct implements iam.IGrantable { | ||
| public readonly grantPrincipal: iam.IPrincipal; | ||
| public readonly policy: iam.IPolicy; | ||
| public readonly policy: iam.IManagedPolicy; | ||
|
|
||
| public constructor(sourceTable: Table, role: iam.IRole) { | ||
| super(sourceTable, `SourceTableAttachedPolicy-${Names.nodeUniqueId(role.node)}`); | ||
|
|
||
| const policy = new iam.Policy(this, 'Resource', { roles: [role] }); | ||
| super(sourceTable, `SourceTableAttachedManagedPolicy-${Names.nodeUniqueId(role.node)}`); | ||
|
|
||
| const policy = new iam.ManagedPolicy(this, 'Resource', { | ||
| // A CF update of the description property of a managed policy requires | ||
| // a replacement. Use the table name in the description to force a managed | ||
| // policy replacement when the table name changes. This way we preserve permissions | ||
| // to delete old replicas in case of a table replacement. | ||
| description: `DynamoDB replication managed policy for table ${sourceTable.tableName}`, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is an awesome trick! I'll have to remember this one to use in other Custom Resources. I'm just a little worried about the delete order - since this depends on the Table, won't it be deleted first, before the replica?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is fine because it depends on the role used by See also my test #13300 (comment). |
||
| roles: [role], | ||
| }); | ||
| this.policy = policy; | ||
| this.grantPrincipal = new SourceTableAttachedPrincipal(role, policy); | ||
| } | ||
|
|
@@ -1686,7 +1693,7 @@ class SourceTableAttachedPolicy extends CoreConstruct implements iam.IGrantable | |
| * `SourceTableAttachedPolicy` class so it can act as an `IGrantable`. | ||
| */ | ||
| class SourceTableAttachedPrincipal extends iam.PrincipalBase { | ||
| public constructor(private readonly role: iam.IRole, private readonly policy: iam.Policy) { | ||
| public constructor(private readonly role: iam.IRole, private readonly policy: iam.ManagedPolicy) { | ||
| super(); | ||
| } | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.