handlers/product-move-api/cfn.yaml (564 lines of code) (raw):

AWSTemplateFormatVersion: '2010-09-09' Description: Endpoints to handle product movement, initially recurring contribution to digi sub Parameters: DeployBucket: Description: Bucket to copy files to Type: String Default: support-service-lambdas-dist Stack: Description: Stack name Type: String Default: membership Stage: Description: Set by RiffRaff on each deploy Type: String AllowedValues: - CODE - PROD Mappings: StageMap: PROD: DomainName: product-move-api.support.guardianapis.com CODE: DomainName: product-move-api-code.support.guardianapis.com Resources: ProductMovementFailureAlarm: Type: AWS::CloudWatch::Alarm Condition: IsProd Properties: AlarmActions: - Fn::Sub: arn:aws:sns:${AWS::Region}:${AWS::AccountId}:alarms-handler-topic-${Stage} AlarmName: Fn::Sub: ${Stage} An error in the Product Move lambda. Please check the logs to diagnose ComparisonOperator: GreaterThanOrEqualToThreshold Dimensions: - Name: FunctionName Value: Ref: ProductMoveApiLambda EvaluationPeriods: 1 MetricName: Errors Namespace: AWS/Lambda Period: 300 Statistic: Sum Threshold: 1 TreatMissingData: notBreaching Tags: - Key: DiagnosticLinks Value: Fn::Sub: lambda:move-product-${Stage} SQSTriggerSF: Type: AWS::Lambda::EventSourceMapping Properties: BatchSize: 1 Enabled: true EventSourceArn: Fn::GetAtt: SalesforceTrackingQueue.Arn FunctionName: Ref: SalesforceTrackingLambda ProductMoveApiLambda: Type: AWS::Lambda::Function Properties: Code: S3Bucket: Ref: DeployBucket S3Key: Fn::Sub: "${Stack}/${Stage}/product-move-api/product-move-api.jar" Description: A lambda for handling product movement API requests FunctionName: Fn::Sub: move-product-${Stage} Handler: com.gu.productmove.Handler::handleRequest MemorySize: 6144 Role: Fn::GetAtt: - ProductMoveApiLambdaRole - Arn Runtime: java21 Timeout: 300 Environment: Variables: App: product-move-api Stack: Ref: Stack Stage: Ref: Stage EmailQueueName: Fn::ImportValue: Fn::Sub: comms-${Stage}-EmailQueueName Tags: - Key: lambda:createdBy Value: SAM Architectures: - arm64 RefundDeadLetterQueue: Type: AWS::SQS::Queue Properties: MessageRetentionPeriod: 1209600 # 14 days this needs to be longer than the message retention period of the main queue because the expiration of a message is always based on its original enqueue timestamp QueueName: Fn::Sub: product-switch-refund-dead-letter-${Stage} ProductMoveApiGatewayUsagePlan: Type: AWS::ApiGateway::UsagePlan DependsOn: - ProductMoveApiGateway Properties: ApiStages: - ApiId: Ref: ProductMoveApiGateway Stage: Ref: ProductMoveApiGatewayStage Description: Fn::Sub: Usage plan for product-move-api-PROD UsagePlanName: Fn::Sub: product-move-api-PROD-UsagePlan ProductMoveApiLambdaDocsPermissionStage: Type: AWS::Lambda::Permission Properties: Action: lambda:InvokeFunction FunctionName: Ref: ProductMoveApiLambda Principal: apigateway.amazonaws.com SourceArn: Fn::Sub: - arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/*/docs/* - __ApiId__: Ref: ProductMoveApiGateway __Stage__: "*" ProductMoveApiLambdaRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Action: - sts:AssumeRole Effect: Allow Principal: Service: - lambda.amazonaws.com ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole Policies: - PolicyName: ProductMoveApiLambdaRolePolicy0 PolicyDocument: Statement: Effect: Allow Action: - sqs:GetQueueUrl - sqs:SendMessage Resource: - Fn::ImportValue: Fn::Sub: comms-${Stage}-EmailQueueArn - Fn::GetAtt: RefundQueue.Arn - Fn::GetAtt: SalesforceTrackingQueue.Arn - PolicyName: ProductMoveApiLambdaRolePolicy2 PolicyDocument: Statement: Effect: Allow Action: s3:GetObject Resource: - Fn::Sub: arn:aws:s3:::gu-reader-revenue-private/membership/support-service-lambdas/${Stage}/invoicingApi-${Stage}*.json - Fn::Sub: arn:aws:s3:::gu-zuora-catalog/${Stage}/Zuora-${Stage}/catalog.json - arn:aws:s3::*:membership-dist/* - PolicyName: ProductMoveApiLambdaRolePolicy3 PolicyDocument: Statement: - Effect: Allow Action: - dynamodb:PutItem - dynamodb:UpdateItem Resource: - Fn::ImportValue: Fn::Sub: supporter-product-data-tables-${Stage}-SupporterProductDataTable - PolicyName: ProductMoveApiLambdaRolePolicy4 PolicyDocument: Statement: - Effect: Allow Action: - secretsmanager:DescribeSecret - secretsmanager:GetSecretValue Resource: - arn:aws:secretsmanager:eu-west-1:865473395570:secret:CODE/InvoicingApi-qNhLQS - arn:aws:secretsmanager:eu-west-1:865473395570:secret:PROD/InvoicingApi-JBxYpW - arn:aws:secretsmanager:eu-west-1:865473395570:secret:CODE/Zuora/User/ZuoraApiUser-zmOGho - arn:aws:secretsmanager:eu-west-1:865473395570:secret:PROD/Zuora/User/ZuoraApiUser-oq5ISm Tags: - Key: lambda:createdBy Value: SAM ProductMoveApiGatewayUsagePlanKey: Type: AWS::ApiGateway::UsagePlanKey DependsOn: - ProductMoveApiGatewayApiKey Properties: KeyId: Ref: ProductMoveApiGatewayApiKey KeyType: API_KEY UsagePlanId: Ref: ProductMoveApiGatewayUsagePlan ProductMoveApiLambdaProductMovementPermissionStage: Type: AWS::Lambda::Permission Properties: Action: lambda:InvokeFunction FunctionName: Ref: ProductMoveApiLambda Principal: apigateway.amazonaws.com SourceArn: Fn::Sub: - arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/*/* - __ApiId__: Ref: ProductMoveApiGateway __Stage__: "*" SQSTrigger: Type: AWS::Lambda::EventSourceMapping Properties: BatchSize: 1 Enabled: true EventSourceArn: Fn::GetAtt: RefundQueue.Arn FunctionName: Ref: RefundLambda ProductMoveApiGatewayDeployment3b8d6b60f7: Type: AWS::ApiGateway::Deployment Properties: Description: 'RestApi deployment id: 3b8d6b60f7fc8b38903c9cf0441d50831c0b59db' RestApiId: Ref: ProductMoveApiGateway SalesforceTrackingQueue: Type: AWS::SQS::Queue Properties: VisibilityTimeout: 3000 QueueName: Fn::Sub: product-switch-salesforce-tracking-${Stage} SalesforceTrackingLambda: Type: AWS::Lambda::Function Properties: Code: S3Bucket: Ref: DeployBucket S3Key: Fn::Sub: "${Stack}/${Stage}/product-move-api/product-move-api.jar" Description: An SQS-triggered lambda that refunds customer's going through product-switching FunctionName: Fn::Sub: product-switch-salesforce-tracking-${Stage} Handler: com.gu.productmove.salesforce.SalesforceHandler::handleRequest MemorySize: 1024 Role: Fn::GetAtt: - SalesforceTrackingLambdaRole - Arn Runtime: java21 Timeout: 300 Environment: Variables: App: product-move-api Stack: Ref: Stack Stage: Ref: Stage Tags: - Key: lambda:createdBy Value: SAM Architectures: - arm64 ProductMoveApiGateway: Type: AWS::ApiGateway::RestApi Properties: Body: info: version: '1.0' title: Ref: AWS::StackName paths: "/{proxy+}": x-amazon-apigateway-any-method: x-amazon-apigateway-integration: httpMethod: POST type: aws_proxy uri: Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ProductMoveApiLambda.Arn}/invocations security: - api_key: [] responses: {} "/docs/{proxy+}": x-amazon-apigateway-any-method: x-amazon-apigateway-integration: httpMethod: POST type: aws_proxy uri: Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ProductMoveApiLambda.Arn}/invocations security: [] responses: {} "/docs": x-amazon-apigateway-any-method: x-amazon-apigateway-integration: httpMethod: POST type: aws_proxy uri: Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ProductMoveApiLambda.Arn}/invocations security: [] responses: {} openapi: 3.0.1 components: securitySchemes: api_key: type: apiKey name: x-api-key in: header Name: Fn::Sub: product-move-api-${Stage}-ApiGateway RefundQueue: Type: AWS::SQS::Queue Properties: VisibilityTimeout: 43200 # 12 hours MessageRetentionPeriod: 606600 # 7 days +30 minutes QueueName: Fn::Sub: product-switch-refund-${Stage} RedrivePolicy: deadLetterTargetArn: Fn::GetAtt: RefundDeadLetterQueue.Arn maxReceiveCount: 14 RefundLambdaRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Action: - sts:AssumeRole Effect: Allow Principal: Service: - lambda.amazonaws.com ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole Policies: - PolicyName: RefundLambdaRolePolicy1 PolicyDocument: Statement: Effect: Allow Action: s3:GetObject Resource: - Fn::Sub: arn:aws:s3:::gu-reader-revenue-private/membership/support-service-lambdas/${Stage}/zuoraRest-${Stage}*.json - Fn::Sub: arn:aws:s3:::gu-reader-revenue-private/membership/support-service-lambdas/${Stage}/invoicingApi-${Stage}*.json - arn:aws:s3::*:membership-dist/* - PolicyName: RefundLambdaRolePolicy2 PolicyDocument: Statement: Effect: Allow Action: - sqs:DeleteMessage - sqs:GetQueueAttributes - sqs:ReceiveMessage Resource: "*" - PolicyName: RefundLambdaRolePolicy3 PolicyDocument: Statement: - Effect: Allow Action: - secretsmanager:DescribeSecret - secretsmanager:GetSecretValue Resource: - arn:aws:secretsmanager:eu-west-1:865473395570:secret:CODE/InvoicingApi-qNhLQS - arn:aws:secretsmanager:eu-west-1:865473395570:secret:PROD/InvoicingApi-JBxYpW - arn:aws:secretsmanager:eu-west-1:865473395570:secret:CODE/Zuora/User/ZuoraApiUser-zmOGho - arn:aws:secretsmanager:eu-west-1:865473395570:secret:PROD/Zuora/User/ZuoraApiUser-oq5ISm Tags: - Key: lambda:createdBy Value: SAM 5xxApiAlarm: Type: AWS::CloudWatch::Alarm Condition: IsProd DependsOn: - ProductMoveApiGateway Properties: AlarmActions: - Fn::Sub: arn:aws:sns:${AWS::Region}:${AWS::AccountId}:alarms-handler-topic-${Stage} AlarmName: Fn::Sub: ${Stage} The product-move-api returned a 500 response AlarmDescription: Check the logs for details ComparisonOperator: GreaterThanOrEqualToThreshold Dimensions: - Name: ApiName Value: Fn::Sub: product-move-api-${Stage}-ApiGateway - Name: Stage Value: Fn::Sub: "${Stage}" EvaluationPeriods: 1 MetricName: 5XXError Namespace: AWS/ApiGateway Period: 60 Statistic: Sum Threshold: 1 TreatMissingData: notBreaching Tags: - Key: DiagnosticLinks Value: Fn::Sub: lambda:move-product-${Stage} RefundLambdaDeadLetterQueueAlarm: Type: AWS::CloudWatch::Alarm Condition: IsProd Properties: AlarmActions: - Fn::Sub: arn:aws:sns:${AWS::Region}:${AWS::AccountId}:alarms-handler-topic-${Stage} AlarmName: New message in the product-switch-refund-dead-letter-PROD dead letter queue. AlarmDescription: There is a new message in the product-switch-refund-dead-letter-PROD dead letter queue. This means that a user who has cancelled their supporter plus subscription within 14 days has not received the refund that they are due. Please check the product-switch-refund-PROD logs - https://eu-west-1.console.aws.amazon.com/cloudwatch/home?region=eu-west-1#logsV2:log-groups/log-group/$252Faws$252Flambda$252Fproduct-switch-refund-PROD and the invoicing-api-refund-PROD logs - https://eu-west-1.console.aws.amazon.com/cloudwatch/home?region=eu-west-1#logsV2:log-groups/log-group/$252Faws$252Flambda$252Finvoicing-api-refund-PROD to diagnose the issue. Namespace: AWS/SQS MetricName: ApproximateNumberOfMessagesVisible Dimensions: - Name: QueueName Value: !GetAtt RefundDeadLetterQueue.QueueName Statistic: Sum Period: 60 EvaluationPeriods: 1 Threshold: 0 ComparisonOperator: GreaterThanThreshold TreatMissingData: notBreaching ProductMoveApiLambdaDocsRedirectPermissionStage: Type: AWS::Lambda::Permission Properties: Action: lambda:InvokeFunction FunctionName: Ref: ProductMoveApiLambda Principal: apigateway.amazonaws.com SourceArn: Fn::Sub: - arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/*/docs - __ApiId__: Ref: ProductMoveApiGateway __Stage__: "*" ProductMoveApiGatewayStage: Type: AWS::ApiGateway::Stage Properties: DeploymentId: Ref: ProductMoveApiGatewayDeployment3b8d6b60f7 RestApiId: Ref: ProductMoveApiGateway StageName: Fn::Sub: "${Stage}" RefundLambda: Type: AWS::Lambda::Function Properties: Code: S3Bucket: Ref: DeployBucket S3Key: Fn::Sub: "${Stack}/${Stage}/product-move-api/product-move-api.jar" Description: An SQS-triggered lambda that refunds customer's going through product-switching FunctionName: Fn::Sub: product-switch-refund-${Stage} Handler: com.gu.productmove.refund.RefundHandler::handleRequest MemorySize: 1024 Role: Fn::GetAtt: - RefundLambdaRole - Arn Runtime: java21 Timeout: 300 Environment: Variables: App: product-move-api Stack: Ref: Stack Stage: Ref: Stage Tags: - Key: lambda:createdBy Value: SAM Architectures: - arm64 ProductMoveApiGatewayApiKey: Type: AWS::ApiGateway::ApiKey DependsOn: - ProductMoveApiGatewayUsagePlan Properties: Enabled: true StageKeys: - RestApiId: Ref: ProductMoveApiGateway StageName: Ref: ProductMoveApiGatewayStage SalesforceTrackingLambdaRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Action: - sts:AssumeRole Effect: Allow Principal: Service: - lambda.amazonaws.com ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole Policies: - PolicyName: SalesforceTrackingLambdaRolePolicy1 PolicyDocument: Statement: Effect: Allow Action: s3:GetObject Resource: - arn:aws:s3::*:membership-dist/* - PolicyName: SalesforceTrackingLambdaRolePolicy2 PolicyDocument: Statement: Effect: Allow Action: - sqs:DeleteMessage - sqs:GetQueueAttributes - sqs:ReceiveMessage Resource: "*" - PolicyName: SalesforceTrackingLambdaRolePolicy3 PolicyDocument: Statement: Effect: Allow Action: - secretsmanager:DescribeSecret - secretsmanager:GetSecretValue Resource: - arn:aws:secretsmanager:eu-west-1:865473395570:secret:CODE/Salesforce/User/SupportServiceLambdas-729iA5 - arn:aws:secretsmanager:eu-west-1:865473395570:secret:PROD/Salesforce/User/SupportServiceLambdas-417yMt - arn:aws:secretsmanager:eu-west-1:865473395570:secret:CODE/Zuora/User/ZuoraApiUser-zmOGho - arn:aws:secretsmanager:eu-west-1:865473395570:secret:PROD/Zuora/User/ZuoraApiUser-oq5ISm Tags: - Key: lambda:createdBy Value: SAM ProductMoveApiDomainName: Type: "AWS::ApiGateway::DomainName" Properties: RegionalCertificateArn: # only for *.support.guardianapis.com !Sub arn:aws:acm:${AWS::Region}:${AWS::AccountId}:certificate/b384a6a0-2f54-4874-b99b-96eeff96c009 DomainName: !FindInMap [ StageMap, !Ref Stage, DomainName ] EndpointConfiguration: Types: - REGIONAL ProductMoveApiBasePathMapping: Type: "AWS::ApiGateway::BasePathMapping" Properties: RestApiId: !Ref ProductMoveApiGateway DomainName: !Ref ProductMoveApiDomainName Stage: !Sub ${Stage} DependsOn: - ProductMoveApiGateway - ProductMoveApiDomainName - ProductMoveApiGatewayStage ProductMoveApiDNSRecord: Type: AWS::Route53::RecordSet Properties: HostedZoneName: support.guardianapis.com. Name: !FindInMap [ StageMap, !Ref Stage, DomainName ] Type: CNAME TTL: '120' ResourceRecords: - !GetAtt ProductMoveApiDomainName.RegionalDomainName Conditions: IsProd: Fn::Equals: - Ref: Stage - PROD