diff --git a/.github/workflows/memsub-promotions-lambdas.yml b/.github/workflows/memsub-promotions-lambdas.yml index 1dfb3ef4..f0037360 100644 --- a/.github/workflows/memsub-promotions-lambdas.yml +++ b/.github/workflows/memsub-promotions-lambdas.yml @@ -81,7 +81,8 @@ jobs: functionNames: - MembershipSub-Promotions-to-PromoCode-View- - MembershipSub-PromoCode-View-Dynamo-to-Salesforce- - - MembershipSub-Promotions-Scheduled-Dynamo-Backup- + dependencies: + - memsub-promotions-lambdas-cloudformation contentDirectories: | MembershipSub-Promotions-PromoCode-View: - lambdas/dist/MembershipSub-Promotions-PromoCode-View.zip diff --git a/cloudformation/memsub-promotions-lambdas-cf.yaml b/cloudformation/memsub-promotions-lambdas-cf.yaml index d147401a..1f41765e 100644 --- a/cloudformation/memsub-promotions-lambdas-cf.yaml +++ b/cloudformation/memsub-promotions-lambdas-cf.yaml @@ -53,45 +53,6 @@ Resources: Resource: - arn:aws:dynamodb:*:*:table/MembershipSub-PromoCode-View-PROD - arn:aws:dynamodb:*:*:table/MembershipSub-PromoCode-View-CODE - MembershipSubPromotionsDataBackupLambdaRole: - Type: AWS::IAM::Role - Properties: - AssumeRolePolicyDocument: - Statement: - - Effect: Allow - Principal: - Service: - - lambda.amazonaws.com - Action: - - sts:AssumeRole - Path: / - Policies: - - PolicyName: MembershipSub-Promotions-Data-Backup-Lambda-Policy - PolicyDocument: - Version: '2012-10-17' - Statement: - - Effect: Allow - Action: - - logs:CreateLogGroup - - logs:CreateLogStream - - logs:PutLogEvents - Resource: - - arn:aws:logs:*:*:log-group:/aws/lambda/MembershipSub-Promotions-Scheduled-Dynamo-Backup-* - - Effect: Allow - Action: - - dynamodb:GetRecords - - dynamodb:Scan - Resource: - - arn:aws:dynamodb:*:*:table/MembershipSub-Promotions-* - - arn:aws:dynamodb:*:*:table/MembershipSub-Campaigns-* - - Effect: Allow - Action: - - dynamodb:CreateBackup - - dynamodb:ListBackups - - dynamodb:DescribeBackup - - dynamodb:DeleteBackup - Resource: - - '*' MembershipSubPromoCodeViewETLRole: Type: AWS::IAM::Role Properties: @@ -209,34 +170,6 @@ Resources: Runtime: nodejs18.x Timeout: 60 - ScheduledBackupLambdaPROD: - Type: AWS::Lambda::Function - Properties: - Code: - S3Bucket: gu-promotions-tool-dist - S3Key: membership/PROD/MembershipSub-Promotions-PromoCode-View/MembershipSub-Promotions-PromoCode-View.zip - Description: A Lambda function to trigger the backup of the Campaigns and Promotions table and delete any old backups (retention days is defined in the code) - FunctionName: MembershipSub-Promotions-Scheduled-Dynamo-Backup-PROD - Handler: MembershipSub-Promotions-Scheduled-Dynamo-Backup.handler - MemorySize: 128 - Role: !GetAtt [MembershipSubPromotionsDataBackupLambdaRole, Arn] - Runtime: nodejs18.x - Timeout: 60 - BackupSchedule: - Type: AWS::Events::Rule - Properties: - ScheduleExpression: cron(20 12 * * ? *) - State: ENABLED - Targets: - - Id: ScheduledBackupLambdaPRODScheduler - Arn: !GetAtt [ScheduledBackupLambdaPROD, Arn] - InvokeLambdaPermission: - Type: AWS::Lambda::Permission - Properties: - FunctionName: !GetAtt [ScheduledBackupLambdaPROD, Arn] - Action: lambda:InvokeFunction - Principal: events.amazonaws.com - SourceArn: !GetAtt [BackupSchedule, Arn] ETLSchedule: Type: AWS::Events::Rule Properties: diff --git a/lambdas/README.md b/lambdas/README.md index 3ab8ef06..55f191f1 100644 --- a/lambdas/README.md +++ b/lambdas/README.md @@ -19,13 +19,6 @@ The lambda relies on SalesForce usernames/passwords which have been stored in AW Only the PROD will rebuild automatically when a PR branch merges into `main`. -### MembershipSub-Promotions-Scheduled-Dynamo-Backup -A Lambda function to trigger the backup of the Campaigns and Promotions table and delete any old backups (retention days is defined in the code). - -For dev work, we can manually run it in AWS and check it worked from the Dynamo page in the AWS console. - -A single version (PROD) of this lambda exists in AWS, and will rebuild automatically when a PR branch merges into `main`. - ### MembershipSub-Promotions-to-PromoCode-View An Amazon DynamoDB trigger that creates a view of data associated with a particular promo code for the data pipeline to collect. diff --git a/lambdas/src/MembershipSub-Promotions-Scheduled-Dynamo-Backup.js b/lambdas/src/MembershipSub-Promotions-Scheduled-Dynamo-Backup.js deleted file mode 100644 index 1e890af3..00000000 --- a/lambdas/src/MembershipSub-Promotions-Scheduled-Dynamo-Backup.js +++ /dev/null @@ -1,64 +0,0 @@ -import { DynamoDB } from "@aws-sdk/client-dynamodb"; - -const ddb = new DynamoDB(); - -function createTodaysBackup(TableName) { - return ddb.createBackup({ - 'BackupName': `${TableName}-Scheduled-Backup`, - TableName - }) - .then(possiblyJustCreatedBackup => { - console.log(`Created backup of table ${TableName}: ${possiblyJustCreatedBackup.BackupDetails.BackupArn}`); - return possiblyJustCreatedBackup.BackupDetails.BackupArn; - }); -} - -function deleteBackupsOlderThanXDays(TableName, retentionDays) { - return (latestBackupARN) => { - const unixtime = Math.floor(Date.now() / 1000); - const retentionSeconds = (retentionDays * 60 * 60 * 24); - const timeRangeCutoffTimestamp = unixtime - retentionSeconds; - const TimeRangeUpperBound = new Date(timeRangeCutoffTimestamp * 1000); - - return ddb.listBackups({ - TableName, - TimeRangeUpperBound - }) - .then(oldBackups => { - - const backupsToDelete = oldBackups.BackupSummaries.map(backupSummary => backupSummary.BackupArn).filter(backupArn => latestBackupARN !== backupArn) - - console.log(`${backupsToDelete.length} old backups for table: ${TableName} will be deleted...`); - - const deletionPromises = backupsToDelete.map(BackupArn => { - console.log(`Attempting to delete backup: ${BackupArn}`); - return ddb.deleteBackup({ BackupArn }); - }); - - return Promise.all(deletionPromises).then(results => { - results.forEach(result => { - console.log(`Successfully deleted ${result.BackupDescription.BackupDetails.BackupArn}`) - }); - console.log(`Successfully deleted ${results.length} backups for table: ${TableName}`); - return `Successfully${latestBackupARN ? ' created new backup and' : ''} deleted ${results.length} backups for table: ${TableName}`; - }) - }); - }; -} - -export const handler = (event, context, callback) => { - - const TOUCHPOINT_BACKEND = /PROD$/.test(context.functionName) ? 'PROD' : 'CODE'; - const RETENTION_DAYS = 14; // a number < 1 will delete everything except the backup `createTodaysBackup` just created - - const tablesToBackup = [ - `MembershipSub-Campaigns-${TOUCHPOINT_BACKEND}`, - `MembershipSub-Promotions-${TOUCHPOINT_BACKEND}` - ]; - Promise.all(tablesToBackup.map(tableName => createTodaysBackup(tableName).then(deleteBackupsOlderThanXDays(tableName, RETENTION_DAYS)))) - .then((results) => { - callback(null, `Backup report: ${results.join('; ')}`) - }) - .catch(callback) - -};