diff --git a/packages/amplify-cli/src/__tests__/commands/gen2-migration/refactor/resolvers/cfn-output-resolver.test.ts b/packages/amplify-cli/src/__tests__/commands/gen2-migration/refactor/resolvers/cfn-output-resolver.test.ts index cafeba5b792..1e606ace5b0 100644 --- a/packages/amplify-cli/src/__tests__/commands/gen2-migration/refactor/resolvers/cfn-output-resolver.test.ts +++ b/packages/amplify-cli/src/__tests__/commands/gen2-migration/refactor/resolvers/cfn-output-resolver.test.ts @@ -65,6 +65,12 @@ describe('CFNOutputResolver', () => { Ref: 'snstopic', }, }, + KinesisStreamArn: { + Description: 'Kinesis Stream Arn', + Value: { + 'Fn::GetAtt': ['MyKinesisStream', 'Arn'], + }, + }, }, Resources: { MyS3Bucket: { @@ -221,6 +227,29 @@ describe('CFNOutputResolver', () => { }, }, }, + MyKinesisStream: { + Type: 'AWS::Kinesis::Stream', + Properties: { + Name: 'MyKinesisStream', + ShardCount: 1, + }, + }, + KinesisStreamPolicy: { + Type: 'AWS::IAM::Policy', + Properties: { + PolicyName: 'KinesisStreamPolicy', + PolicyDocument: { + Statement: [ + { + Effect: 'Allow', + Action: 'kinesis:PutRecord', + Resource: { 'Fn::GetAtt': ['MyKinesisStream', 'Arn'] }, + }, + ], + }, + Roles: [{ Ref: 'AuthenticatedRole' }], + }, + }, }, }; const expectedTemplate: CFNTemplate = { @@ -264,6 +293,10 @@ describe('CFNOutputResolver', () => { Description: 'SnsTopicArn', Value: 'arn:aws:sns:us-east-1:12345:snsTopic', }, + KinesisStreamArn: { + Description: 'Kinesis Stream Arn', + Value: 'arn:aws:kinesis:us-east-1:12345:stream/MyKinesisStream', + }, }, Resources: { MyS3Bucket: { @@ -412,6 +445,29 @@ describe('CFNOutputResolver', () => { BucketName: 'test-bucket', }, }, + MyKinesisStream: { + Type: 'AWS::Kinesis::Stream', + Properties: { + Name: 'MyKinesisStream', + ShardCount: 1, + }, + }, + KinesisStreamPolicy: { + Type: 'AWS::IAM::Policy', + Properties: { + PolicyName: 'KinesisStreamPolicy', + PolicyDocument: { + Statement: [ + { + Effect: 'Allow', + Action: 'kinesis:PutRecord', + Resource: 'arn:aws:kinesis:us-east-1:12345:stream/MyKinesisStream', + }, + ], + }, + Roles: [{ Ref: 'AuthenticatedRole' }], + }, + }, }, }; @@ -452,6 +508,10 @@ describe('CFNOutputResolver', () => { OutputKey: 'snsTopicArn', OutputValue: 'arn:aws:sns:us-east-1:12345:snsTopic', }, + { + OutputKey: 'KinesisStreamArn', + OutputValue: 'arn:aws:kinesis:us-east-1:12345:stream/MyKinesisStream', + }, ], [ { diff --git a/packages/amplify-cli/src/commands/gen2-migration/refactor/generators/template-generator.ts b/packages/amplify-cli/src/commands/gen2-migration/refactor/generators/template-generator.ts index c3d58cf18ef..9dc67894f8e 100644 --- a/packages/amplify-cli/src/commands/gen2-migration/refactor/generators/template-generator.ts +++ b/packages/amplify-cli/src/commands/gen2-migration/refactor/generators/template-generator.ts @@ -19,6 +19,7 @@ import { CFNStackStatus, CFNTemplate, ResourceMapping, + CFN_ANALYTICS_TYPE, } from '../types'; import MigrationReadmeGenerator from './migration-readme-generator'; import { pollStackForCompletionState, tryUpdateStack } from '../cfn-stack-updater'; @@ -33,7 +34,7 @@ import ora from 'ora'; const CFN_RESOURCE_STACK_TYPE = 'AWS::CloudFormation::Stack'; const GEN2_AMPLIFY_AUTH_LOGICAL_ID_PREFIX = 'amplifyAuth'; -const CATEGORIES: CATEGORY[] = ['auth', 'storage']; +const CATEGORIES: CATEGORY[] = ['auth', 'storage', 'analytics']; const TEMPLATES_DIR = '.amplify/migration/templates'; const SEPARATOR = ' to '; @@ -48,6 +49,7 @@ const AUTH_RESOURCES_TO_REFACTOR = [ ]; const AUTH_USER_POOL_GROUP_RESOURCES_TO_REFACTOR = [CFN_AUTH_TYPE.UserPoolGroup]; const STORAGE_RESOURCES_TO_REFACTOR = [CFN_S3_TYPE.Bucket]; +const ANALYTICS_RESOURCES_TO_REFACTOR = [CFN_ANALYTICS_TYPE.Stream]; const GEN1_RESOURCE_TYPE_TO_LOGICAL_RESOURCE_IDS_MAP = new Map([ [CFN_AUTH_TYPE.UserPool.valueOf(), 'UserPool'], [CFN_AUTH_TYPE.UserPoolClient.valueOf(), 'UserPoolClientWeb'], @@ -55,11 +57,13 @@ const GEN1_RESOURCE_TYPE_TO_LOGICAL_RESOURCE_IDS_MAP = new Map([ [CFN_AUTH_TYPE.IdentityPoolRoleAttachment.valueOf(), 'IdentityPoolRoleMap'], [CFN_AUTH_TYPE.UserPoolDomain.valueOf(), 'UserPoolDomain'], [CFN_S3_TYPE.Bucket.valueOf(), 'S3Bucket'], + [CFN_ANALYTICS_TYPE.Stream.valueOf(), 'KinesisStream'], ]); const LOGICAL_IDS_TO_REMOVE_FOR_REVERT_MAP = new Map([ ['auth', AUTH_RESOURCES_TO_REFACTOR], ['auth-user-pool-group', AUTH_USER_POOL_GROUP_RESOURCES_TO_REFACTOR], ['storage', [CFN_S3_TYPE.Bucket]], + ['analytics', ANALYTICS_RESOURCES_TO_REFACTOR], ]); const GEN2_NATIVE_APP_CLIENT = 'UserPoolNativeAppClient'; const GEN1_USER_POOL_GROUPS_STACK_TYPE_DESCRIPTION = 'auth-Cognito-UserPool-Groups'; @@ -82,6 +86,9 @@ class TemplateGenerator { storage: { resourcesToRefactor: STORAGE_RESOURCES_TO_REFACTOR, }, + analytics: { + resourcesToRefactor: ANALYTICS_RESOURCES_TO_REFACTOR, + }, } as const; constructor( @@ -214,12 +221,14 @@ class TemplateGenerator { assert(sourceCategoryStacks && sourceCategoryStacks?.length > 0, 'No source category stack found'); assert(destinationCategoryStacks && destinationCategoryStacks?.length > 0, 'No destination category stack found'); for (const { LogicalResourceId: sourceLogicalResourceId, PhysicalResourceId: sourcePhysicalResourceId } of sourceCategoryStacks) { + // find the valid, migrate-able categories in Gen1 stack const category = CATEGORIES.find((category) => sourceLogicalResourceId?.startsWith(category)); if (!category) continue; assert(sourcePhysicalResourceId); let destinationPhysicalResourceId: string | undefined; let userPoolGroupDestinationPhysicalResourceId: string | undefined; + // find the corresponding category stack in Gen2 stack const correspondingCategoryStackInDestination = destinationCategoryStacks.find( ({ LogicalResourceId: destinationLogicalResourceId }) => destinationLogicalResourceId?.startsWith(category), ); diff --git a/packages/amplify-cli/src/commands/gen2-migration/refactor/resolvers/cfn-output-resolver.ts b/packages/amplify-cli/src/commands/gen2-migration/refactor/resolvers/cfn-output-resolver.ts index b607806da0b..6abecd18b24 100644 --- a/packages/amplify-cli/src/commands/gen2-migration/refactor/resolvers/cfn-output-resolver.ts +++ b/packages/amplify-cli/src/commands/gen2-migration/refactor/resolvers/cfn-output-resolver.ts @@ -161,6 +161,11 @@ class CfnOutputResolver { return { Arn: `arn:aws:lambda:${this.region}:${this.accountId}:function:${resourceIdentifier}`, }; + case 'AWS::Kinesis::Stream': + return { + // output is already in ARN format + Arn: resourceIdentifier, + }; default: return undefined; } diff --git a/packages/amplify-cli/src/commands/gen2-migration/refactor/types.ts b/packages/amplify-cli/src/commands/gen2-migration/refactor/types.ts index 37ce573e0ad..95a4b7725e8 100644 --- a/packages/amplify-cli/src/commands/gen2-migration/refactor/types.ts +++ b/packages/amplify-cli/src/commands/gen2-migration/refactor/types.ts @@ -70,6 +70,7 @@ export enum NON_CUSTOM_RESOURCE_CATEGORY { AUTH = 'auth', STORAGE = 'storage', AUTH_USER_POOL_GROUP = 'auth-user-pool-group', + ANALYTICS = 'analytics', } export type CATEGORY = @@ -101,6 +102,10 @@ export enum CFN_S3_TYPE { Bucket = 'AWS::S3::Bucket', } +export enum CFN_ANALYTICS_TYPE { + Stream = 'AWS::Kinesis::Stream', +} + export enum CFN_IAM_TYPE { Role = 'AWS::IAM::Role', } @@ -113,7 +118,7 @@ export enum CFN_LAMBDA_TYPE { Function = 'AWS::Lambda::Function', } -export type CFN_RESOURCE_TYPES = CFN_AUTH_TYPE | CFN_S3_TYPE | CFN_IAM_TYPE | CFN_SQS_TYPE | CFN_LAMBDA_TYPE; +export type CFN_RESOURCE_TYPES = CFN_AUTH_TYPE | CFN_S3_TYPE | CFN_ANALYTICS_TYPE | CFN_IAM_TYPE | CFN_SQS_TYPE | CFN_LAMBDA_TYPE; export type AWS_RESOURCE_ATTRIBUTES = 'Arn';