handlers/sf-datalake-export/cfn.yaml (586 lines of code) (raw):
AWSTemplateFormatVersion: "2010-09-09"
Description: export salesforce data to the data lake
Parameters:
Stage:
Description: Stage name
Type: String
AllowedValues:
- CODE
- PROD
Default: CODE
Conditions:
IsProd: !Equals [!Ref "Stage", "PROD"]
Mappings:
StageMap:
CODE:
destBuckets: "arn:aws:s3:::gu-salesforce-export-code*"
localbucketName : "gu-salesforce-export-code"
PROD:
destBuckets: ["arn:aws:s3:::gu-salesforce-export-prod*", "arn:aws:s3:::ophan-raw-salesforce-*"]
localbucketName: "gu-salesforce-export-prod"
Resources:
localBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !FindInMap [StageMap, !Ref Stage, localbucketName]
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
LifecycleConfiguration:
Rules:
- TagFilters:
- Key: housekeeping
Value: delete
ExpirationInDays: 2
Status: Enabled
StartJobRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- sts:AssumeRole
Path: /
Policies:
- PolicyName: LambdaPolicy
PolicyDocument:
Statement:
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
- lambda:InvokeFunction
Resource: !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/sf-start-export-job-${Stage}:log-stream:*"
- PolicyName: ReadPrivateCredentials
PolicyDocument:
Statement:
- Effect: Allow
Action: s3:GetObject
Resource: !Sub "arn:aws:s3:::gu-reader-revenue-private/membership/support-service-lambdas/${Stage}/sfExportAuth-${Stage}*.json"
StartJob:
Type: AWS::Lambda::Function
Properties:
Description: start a sf export job
FunctionName:
!Sub sf-start-export-job-${Stage}
Code:
S3Bucket: support-service-lambdas-dist
S3Key: !Sub membership/${Stage}/sf-datalake-export/sf-datalake-export.jar
Handler: com.gu.sf_datalake_export.handlers.StartJobHandler::apply
Environment:
Variables:
Stage: !Ref Stage
Role:
!GetAtt StartJobRole.Arn
MemorySize: 1536
Runtime: java21
Timeout: 300
Architectures:
- arm64
DependsOn:
- StartJobRole
BatchStateRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- sts:AssumeRole
Path: /
Policies:
- PolicyName: LambdaPolicy
PolicyDocument:
Statement:
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
- lambda:InvokeFunction
Resource: !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/sf-get-batch-state-${Stage}:log-stream:*"
- PolicyName: ReadPrivateCredentials
PolicyDocument:
Statement:
- Effect: Allow
Action: s3:GetObject
Resource: !Sub "arn:aws:s3:::gu-reader-revenue-private/membership/support-service-lambdas/${Stage}/sfExportAuth-${Stage}*.json"
GetBatchesLambda:
Type: AWS::Lambda::Function
Properties:
Description: get state of batches related to an salesforce bulk api query
FunctionName:
!Sub sf-get-batch-state-${Stage}
Code:
S3Bucket: support-service-lambdas-dist
S3Key: !Sub membership/${Stage}/sf-datalake-export/sf-datalake-export.jar
Handler: com.gu.sf_datalake_export.handlers.GetBatchesHandler::apply
Environment:
Variables:
Stage: !Ref Stage
Role:
!GetAtt BatchStateRole.Arn
MemorySize: 1536
Runtime: java21
Timeout: 300
Architectures:
- arm64
DependsOn:
- BatchStateRole
DownloadBatchRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- sts:AssumeRole
Path: /
Policies:
- PolicyName: LambdaPolicy
PolicyDocument:
Statement:
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
- lambda:InvokeFunction
Resource: !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/sf-download-batch-${Stage}:log-stream:*"
- PolicyName: ReadPrivateCredentials
PolicyDocument:
Statement:
- Effect: Allow
Action: s3:GetObject
Resource: !Sub "arn:aws:s3:::gu-reader-revenue-private/membership/support-service-lambdas/${Stage}/sfExportAuth-${Stage}*.json"
- PolicyName: DestBuckets
PolicyDocument:
Statement:
- Effect: Allow
Action:
- s3:PutObject
- s3:PutObjectAcl
Resource: !FindInMap [StageMap, !Ref Stage, destBuckets]
CleanBucketRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- sts:AssumeRole
Path: /
Policies:
- PolicyName: LambdaPolicy
PolicyDocument:
Statement:
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
- lambda:InvokeFunction
Resource: !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/sf-export-clean-bucket-${Stage}:log-stream:*"
- PolicyName: DestBucket
PolicyDocument:
Statement:
- Effect: Allow
Action:
- s3:DeleteObject
- s3:GetObject
- s3:GetObjectAcl
- s3:GetBucketAcl
- s3:ListBucket
- s3:GetObjectVersion
- s3:DeleteObjectVersion
Resource: !FindInMap [StageMap, !Ref Stage, destBuckets]
DownloadBatch:
Type: AWS::Lambda::Function
Properties:
Description: download result of completed bulk api batches into s3
FunctionName:
!Sub sf-download-batch-${Stage}
Code:
S3Bucket: support-service-lambdas-dist
S3Key: !Sub membership/${Stage}/sf-datalake-export/sf-datalake-export.jar
Handler: com.gu.sf_datalake_export.handlers.DownloadBatchHandler::apply
Environment:
Variables:
Stage: !Ref Stage
Role:
!GetAtt DownloadBatchRole.Arn
MemorySize: 1792
Runtime: java21
Timeout: 900
Architectures:
- arm64
DependsOn:
- DownloadBatchRole
EndJobRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- sts:AssumeRole
Path: /
Policies:
- PolicyName: LambdaPolicy
PolicyDocument:
Statement:
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
- lambda:InvokeFunction
Resource: !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/sf-end-export-job-${Stage}:log-stream:*"
- PolicyName: ReadPrivateCredentials
PolicyDocument:
Statement:
- Effect: Allow
Action: s3:GetObject
Resource: !Sub "arn:aws:s3:::gu-reader-revenue-private/membership/support-service-lambdas/${Stage}/sfExportAuth-${Stage}*.json"
- PolicyName: DestBuckets
PolicyDocument:
Statement:
- Effect: Allow
Action:
- s3:PutObject
- s3:PutObjectAcl
Resource: !FindInMap [StageMap, !Ref Stage, destBuckets]
CleanBucket:
Type: AWS::Lambda::Function
Properties:
Description: clean old results from bucket before uploading new ones
FunctionName:
!Sub sf-export-clean-bucket-${Stage}
Code:
S3Bucket: support-service-lambdas-dist
S3Key: !Sub membership/${Stage}/sf-datalake-export/sf-datalake-export.jar
Handler: com.gu.sf_datalake_export.handlers.CleanBucketHandler::apply
Environment:
Variables:
Stage: !Ref Stage
Role:
!GetAtt CleanBucketRole.Arn
MemorySize: 1536
Runtime: java21
Timeout: 900
Architectures:
- arm64
DependsOn:
- CleanBucketRole
EndJob:
Type: AWS::Lambda::Function
Properties:
Description: close a sf export job
FunctionName:
!Sub sf-end-export-job-${Stage}
Code:
S3Bucket: support-service-lambdas-dist
S3Key: !Sub membership/${Stage}/sf-datalake-export/sf-datalake-export.jar
Handler: com.gu.sf_datalake_export.handlers.EndJobHandler::apply
Environment:
Variables:
Stage: !Ref Stage
Role:
!GetAtt EndJobRole.Arn
MemorySize: 1536
Runtime: java21
Timeout: 300
Architectures:
- arm64
DependsOn:
- EndJobRole
StatesExecutionRole:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
Effect: Allow
Principal:
Service: !Sub 'states.${AWS::Region}.amazonaws.com'
Action: 'sts:AssumeRole'
Path: /
Policies:
- PolicyName: StatesExecutionPolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- 'lambda:InvokeFunction'
Resource: '*'
StateMachine:
Type: 'AWS::StepFunctions::StateMachine'
Properties:
StateMachineName: !Sub 'salesforce-export-${Stage}'
RoleArn: !GetAtt
- StatesExecutionRole
- Arn
DefinitionString: !Sub
- |-
{
"StartAt": "StartJob",
"States": {
"StartJob": {
"Type": "Task",
"Resource": "${startJobArn}",
"Next": "WaitSomeTime",
"Retry": [{
"ErrorEquals": ["States.ALL"],
"IntervalSeconds": 30,
"MaxAttempts": 3
}]
},
"WaitSomeTime": {
"Type": "Wait",
"Seconds": 5,
"Next": "getBatches"
},
"getBatches": {
"Type": "Task",
"Resource": "${getBatchesArn}",
"Next": "checkPendingBatches",
"Retry": [{
"ErrorEquals": ["States.ALL"],
"IntervalSeconds": 30,
"MaxAttempts": 3
}]
},
"checkPendingBatches": {
"Type": "Choice",
"Choices": [{
"Variable": "$.jobStatus",
"StringEquals": "Completed",
"Next": "cleanBucket"
}],
"Default": "WaitSomeTime"
},
"cleanBucket": {
"Type": "Task",
"Resource": "${cleanBucketArn}",
"Next": "downloadBatch",
"Retry": [{
"ErrorEquals": ["States.ALL"],
"IntervalSeconds": 30,
"MaxAttempts": 3
}]
},
"downloadBatch": {
"Type": "Task",
"Resource": "${downloadBatchArn}",
"Next": "CheckPendingDownloads",
"Retry": [{
"ErrorEquals": ["States.ALL"],
"IntervalSeconds": 300,
"MaxAttempts": 3
}]
},
"CheckPendingDownloads": {
"Type": "Choice",
"Choices": [{
"Variable": "$.done",
"BooleanEquals": true,
"Next": "endJob"
}],
"Default": "downloadBatch"
},
"endJob": {
"Type": "Task",
"Resource": "${endJobArn}",
"Next": "done",
"Retry": [{
"ErrorEquals": ["States.ALL"],
"IntervalSeconds": 30,
"MaxAttempts": 3
}]
},
"done": {
"Type": "Pass",
"End": true
}
}
}
- {
startJobArn: !GetAtt [ StartJob, Arn ],
getBatchesArn: !GetAtt [ GetBatchesLambda, Arn ],
downloadBatchArn: !GetAtt [ DownloadBatch, Arn ],
endJobArn: !GetAtt [ EndJob, Arn ],
cleanBucketArn: !GetAtt [ CleanBucket, Arn ]
}
TriggerRole:
Type: AWS::IAM::Role
Condition: IsProd
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- events.amazonaws.com
Action:
- sts:AssumeRole
Policies:
- PolicyName: TriggerStateMchine
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- states:StartExecution
Resource: !Ref StateMachine
ScheduleRule1:
Type: "AWS::Events::Rule"
Condition: IsProd
Properties:
Description: "trigger salesforce export every day at 01:00 GMT"
ScheduleExpression: "cron(0 1 ? * * *)"
State: "ENABLED"
Targets:
-
Arn: !Ref StateMachine
Id: !Sub trigger_sf_export-Contact-${Stage}
Input: |
{
"objectName": "Contact"
}
RoleArn: !GetAtt [ TriggerRole, Arn ]
-
Arn: !Ref StateMachine
Id: !Sub trigger_sf_export-Subscription-${Stage}
Input: |
{
"objectName": "Subscription"
}
RoleArn: !GetAtt [ TriggerRole, Arn ]
-
Arn: !Ref StateMachine
Id: !Sub trigger_sf_export-Case-${Stage}
Input: |
{
"objectName": "Case"
}
RoleArn: !GetAtt [ TriggerRole, Arn ]
-
Arn: !Ref StateMachine
Id: !Sub trigger_sf_export-Discount-${Stage}
Input: |
{
"objectName": "Discount"
}
RoleArn: !GetAtt [ TriggerRole, Arn ]
-
Arn: !Ref StateMachine
Id: !Sub trigger_sf_export-CardExpiry-${Stage}
Input: |
{
"objectName": "CardExpiry"
}
RoleArn: !GetAtt [ TriggerRole, Arn ]
ScheduleRule2:
Type: "AWS::Events::Rule"
Condition: IsProd
Properties:
Description: "trigger salesforce export every day at 01:00 GMT"
ScheduleExpression: "cron(0 1 ? * * *)"
State: "ENABLED"
Targets:
-
Arn: !Ref StateMachine
Id: !Sub trigger_sf_export-Account-${Stage}
Input: |
{
"objectName": "Account"
}
RoleArn: !GetAtt [ TriggerRole, Arn ]
-
Arn: !Ref StateMachine
Id: !Sub trigger_sf_export-DirectDebitMandateFailure-${Stage}
Input: |
{
"objectName": "DirectDebitMandateFailure"
}
RoleArn: !GetAtt [ TriggerRole, Arn ]
-
Arn: !Ref StateMachine
Id: !Sub trigger_sf_export-DirectDebitMandate-${Stage}
Input: |
{
"objectName": "DirectDebitMandate"
}
RoleArn: !GetAtt [ TriggerRole, Arn ]
-
Arn: !Ref StateMachine
Id: !Sub trigger_sf_export-DirectDebitMandateEvent-${Stage}
Input: |
{
"objectName": "DirectDebitMandateEvent"
}
RoleArn: !GetAtt [ TriggerRole, Arn ]
-
Arn: !Ref StateMachine
Id: !Sub trigger_sf_export-CancellationSurvey-${Stage}
Input: |
{
"objectName": "CancellationSurvey"
}
RoleArn: !GetAtt [ TriggerRole, Arn ]
ScheduleRule3:
Type: "AWS::Events::Rule"
Condition: IsProd
Properties:
Description: "trigger salesforce export every day at 01:00 GMT"
ScheduleExpression: "cron(0 1 ? * * *)"
State: "ENABLED"
Targets:
-
Arn: !Ref StateMachine
Id: !Sub trigger_sf_export-ImovoContract-${Stage}
Input: |
{
"objectName": "ImovoContract"
}
RoleArn: !GetAtt [ TriggerRole, Arn ]
-
Arn: !Ref StateMachine
Id: !Sub trigger_sf_export-DigitalVoucher-${Stage}
Input: |
{
"objectName": "DigitalVoucher"
}
RoleArn: !GetAtt [ TriggerRole, Arn ]
-
Arn: !Ref StateMachine
Id: !Sub trigger_sf_export-ZuoraSubscriptionProductFeature-${Stage}
Input: |
{
"objectName": "ZuoraSubscriptionProductFeature"
}
RoleArn: !GetAtt [ TriggerRole, Arn ]