diff --git a/packages/amplify-graphql-api-construct-tests/src/__tests__/amplify-table-4.test.ts b/packages/amplify-graphql-api-construct-tests/src/__tests__/amplify-table-4.test.ts index c5fc37ac5e..18aef48392 100644 --- a/packages/amplify-graphql-api-construct-tests/src/__tests__/amplify-table-4.test.ts +++ b/packages/amplify-graphql-api-construct-tests/src/__tests__/amplify-table-4.test.ts @@ -1,5 +1,5 @@ import * as path from 'path'; -import { createNewProjectDir, deleteProjectDir } from 'amplify-category-api-e2e-core'; +import { createNewProjectDir, deleteProjectDir, getDDBTable, getDDBTableTags } from 'amplify-category-api-e2e-core'; import { cdkDestroy, initCDKProject, cdkDeploy, updateCDKAppWithTemplate } from '../commands'; import { DURATION_1_HOUR } from '../utils/duration-constants'; @@ -29,14 +29,34 @@ describe('CDK amplify table 4', () => { await initCDKProject(projRoot, templatePath); await expect(cdkDeploy(projRoot, '--all')).resolves.not.toThrow(); }); + test('should not throw limit exceed error when creating a large number of tables with datastore disabled at first and enabled in second deployment', async () => { const templatePath = path.resolve(path.join(__dirname, 'backends', 'amplify-table', 'rate-limit', 'updateTableTtl', 'disabled')); - await initCDKProject(projRoot, templatePath); - await expect(cdkDeploy(projRoot, '--all')).resolves.not.toThrow(); + const name = await initCDKProject(projRoot, templatePath); + + const outputs = await cdkDeploy(projRoot, '--all'); + const { awsAppsyncApiId: apiId, awsAppsyncRegion: region } = outputs[name]; + const tableName = `Todo1-${apiId}-NONE`; + const table = await getDDBTable(tableName, region); + expect(table).toBeDefined(); + + // Verify the tags on the table + const tableTags = await getDDBTableTags(table.Table.TableArn, region); + expect(tableTags.Tags).toBeDefined(); + expect(tableTags.Tags.length).toBe(1); + expect(tableTags.Tags).toEqual(expect.arrayContaining([{ Key: 'created-by', Value: 'amplify-original' }])); + // deploy with datastore enabled - let updateTemplatePath; - updateTemplatePath = path.resolve(path.join(__dirname, 'backends', 'amplify-table', 'rate-limit', 'updateTableTtl', 'enabled')); + const updateTemplatePath = path.resolve(path.join(__dirname, 'backends', 'amplify-table', 'rate-limit', 'updateTableTtl', 'enabled')); updateCDKAppWithTemplate(projRoot, updateTemplatePath); await expect(cdkDeploy(projRoot, '--all')).resolves.not.toThrow(); + + const updatedTable = await getDDBTable(tableName, region); + expect(updatedTable).toBeDefined(); + + // Verify the tags on the table after update + const updatedTableTags = await getDDBTableTags(updatedTable.Table.TableArn, region); + expect(updatedTableTags.Tags).toBeDefined(); + expect(updatedTableTags.Tags.length).toBe(0); }); }); diff --git a/packages/amplify-graphql-api-construct-tests/src/__tests__/backends/amplify-table/rate-limit/createTableTtl/app.ts b/packages/amplify-graphql-api-construct-tests/src/__tests__/backends/amplify-table/rate-limit/createTableTtl/app.ts index 1c7b768469..2653ef83b3 100644 --- a/packages/amplify-graphql-api-construct-tests/src/__tests__/backends/amplify-table/rate-limit/createTableTtl/app.ts +++ b/packages/amplify-graphql-api-construct-tests/src/__tests__/backends/amplify-table/rate-limit/createTableTtl/app.ts @@ -1,6 +1,6 @@ #!/usr/bin/env node import 'source-map-support/register'; -import { App, Stack, Duration } from 'aws-cdk-lib'; +import { App, Stack, Duration, Tags } from 'aws-cdk-lib'; // @ts-ignore import { AmplifyGraphqlApi, AmplifyGraphqlDefinition } from '@aws-amplify/graphql-api-construct'; @@ -37,3 +37,5 @@ new AmplifyGraphqlApi(stack, 'GraphqlApi', { apiKeyConfig: { expires: Duration.days(7) }, }, }); + +Tags.of(stack).add('created-by', 'amplify-original'); diff --git a/packages/amplify-graphql-api-construct-tests/src/__tests__/backends/amplify-table/rate-limit/updateTableTtl/disabled/app.ts b/packages/amplify-graphql-api-construct-tests/src/__tests__/backends/amplify-table/rate-limit/updateTableTtl/disabled/app.ts index 9b8bb47b73..e7ac62bed9 100644 --- a/packages/amplify-graphql-api-construct-tests/src/__tests__/backends/amplify-table/rate-limit/updateTableTtl/disabled/app.ts +++ b/packages/amplify-graphql-api-construct-tests/src/__tests__/backends/amplify-table/rate-limit/updateTableTtl/disabled/app.ts @@ -1,6 +1,6 @@ #!/usr/bin/env node import 'source-map-support/register'; -import { App, Stack, Duration } from 'aws-cdk-lib'; +import { App, Stack, Duration, Tags } from 'aws-cdk-lib'; // @ts-ignore import { AmplifyGraphqlApi, AmplifyGraphqlDefinition } from '@aws-amplify/graphql-api-construct'; @@ -31,3 +31,5 @@ new AmplifyGraphqlApi(stack, 'GraphqlApi', { apiKeyConfig: { expires: Duration.days(7) }, }, }); + +Tags.of(stack).add('created-by', 'amplify-original'); diff --git a/packages/amplify-graphql-model-transformer/src/resources/amplify-dynamodb-table/amplify-dynamo-model-resource-generator.ts b/packages/amplify-graphql-model-transformer/src/resources/amplify-dynamodb-table/amplify-dynamo-model-resource-generator.ts index e278b4f0c1..11508cf79f 100644 --- a/packages/amplify-graphql-model-transformer/src/resources/amplify-dynamodb-table/amplify-dynamo-model-resource-generator.ts +++ b/packages/amplify-graphql-model-transformer/src/resources/amplify-dynamodb-table/amplify-dynamo-model-resource-generator.ts @@ -67,6 +67,7 @@ export class AmplifyDynamoModelResourceGenerator extends DynamoModelResourceGene 'dynamodb:UpdateContinuousBackups', 'dynamodb:UpdateTimeToLive', 'dynamodb:TagResource', + 'dynamodb:UntagResource', 'dynamodb:ListTagsOfResource', ], resources: [ diff --git a/packages/amplify-graphql-model-transformer/src/resources/amplify-dynamodb-table/amplify-table-manager-lambda/amplify-table-manager-handler.ts b/packages/amplify-graphql-model-transformer/src/resources/amplify-dynamodb-table/amplify-table-manager-lambda/amplify-table-manager-handler.ts index d5d1c89e61..ae43017206 100644 --- a/packages/amplify-graphql-model-transformer/src/resources/amplify-dynamodb-table/amplify-table-manager-lambda/amplify-table-manager-handler.ts +++ b/packages/amplify-graphql-model-transformer/src/resources/amplify-dynamodb-table/amplify-table-manager-lambda/amplify-table-manager-handler.ts @@ -224,7 +224,17 @@ const processOnEvent = async ( Object.values(tableDef.tags ?? []).forEach((tag) => { newTags.push({ Key: tag.key, Value: tag.value }); }); - if (requiresTagsUpdate(currentTableTags, newTags)) { + if (currentTableTags && currentTableTags.length > 0 && (!newTags || newTags.length === 0)) { + await ddbClient.untagResource({ + ResourceArn: describeTableResult.Table.TableArn, + TagKeys: currentTableTags.map((tag) => tag.Key!), + }); + await retry( + async () => await isTableReady(event.PhysicalResourceId!), + (res) => res === true, + ); + console.log(`Table '${event.PhysicalResourceId}' is ready after the deletion of Tags.`); + } else if (requiresTagsUpdate(currentTableTags, newTags)) { console.log('Detected tag changes: ', tableDef.tags); await ddbClient.tagResource({ ResourceArn: describeTableResult.Table.TableArn, @@ -806,7 +816,7 @@ export const getSseUpdate = (currentState: TableDescription, endState: CustomDDB * @returns Boolean indicating if the tags are updated */ export const requiresTagsUpdate = (currentTags: DynamoDBTag[], newTags?: DynamoDBTag[]): boolean => { - if (!newTags) { + if (!newTags || newTags.length === 0) { return false; } if (currentTags.length !== newTags.length) {