AWSTemplateFormatVersion: 2010-09-09
Description: Consumes events produced by the notification service and batches notifications for senders to send
Parameters:
  App:
    Description: App name
    Type: String
    Default: harvester
    AllowedValues:
      - harvester
  Stack:
    Description: Stack name
    Type: String
    Default: mobile-notifications
  Stage:
    Description: Stage name
    Type: String
    AllowedValues:
    - CODE
    - PROD
    Default: CODE
  BuildId:
    Description: Tag to be used for the image URL, e.g. riff raff build id
    Type: String
    Default: dev
  DeployBucket:
    Description: Bucket where RiffRaff uploads artifacts on deploy
    Type: String
    Default: mobile-notifications-dist
  VpcId:
    Description: ID of the Notification VPC
    Type: AWS::EC2::VPC::Id
  VpcSubnets:
    Description: Subnets to use in the VPC
    Type: List<AWS::EC2::Subnet::Id>
  VPCSecurityGroup:
    Type: AWS::EC2::SecurityGroup::Id
    Description: The default security group of the VPC
  AlarmTopic:
    Type: String
    Description: The ARN of the SNS topic to send all the cloudwatch alarms to
  RunbookCopy:
    Type: String
    Default: <<<Runbook|https://docs.google.com/document/d/1aJMytnPGeWH8YLpD2_66doxqyr8dPvAVonYIOG-zmOA>>>

Conditions:
  IsProdStage: !Equals [!Ref Stage, PROD]

Resources:
  Dlq:
    Type: AWS::SQS::Queue
    Properties:
      Tags:
        - Key: Stage
          Value: !Ref Stage
        - Key: Stack
          Value: !Ref Stack
        - Key: App
          Value: !Ref App

  Sqs:
    Type: AWS::SQS::Queue
    Properties:
      VisibilityTimeout: 70
      MessageRetentionPeriod: 3600 # 1 hour
      RedrivePolicy:
        deadLetterTargetArn: !GetAtt Dlq.Arn
        maxReceiveCount: 5
      Tags:
        - Key: Stage
          Value: !Ref Stage
        - Key: Stack
          Value: !Ref Stack
        - Key: App
          Value: !Ref App

  ExecutionRole:
    Type: AWS::IAM::Role
    DependsOn: Sqs
    Properties:
      AssumeRolePolicyDocument:
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - lambda.amazonaws.com
          Action: sts:AssumeRole
      Path: /
      Policies:
      - PolicyName: logs
        PolicyDocument:
          Statement:
          - Effect: Allow
            Action: logs:CreateLogGroup
            Resource: !Sub "arn:aws:logs:eu-west-1:${AWS::AccountId}:*"
          - Effect: Allow
            Action:
            - logs:CreateLogStream
            - logs:PutLogEvents
            Resource:
            - !Sub "arn:aws:logs:eu-west-1:${AWS::AccountId}:log-group:/aws/lambda/*:*"
      - PolicyName: SQSInput
        PolicyDocument:
          Statement:
            Effect: Allow
            Action: sqs:*
            Resource:
              - !GetAtt Sqs.Arn
      - PolicyName: SQSOutput
        PolicyDocument:
          Statement:
            Effect: Allow
            Action: sqs:*
            Resource:
              "Fn::Split":
                - ","
                - "Fn::ImportValue":
                    "Fn::Sub": 'NotificationSenderWorkerQueueArns-${Stage}'
      - PolicyName: VPC
        PolicyDocument:
          Statement:
            Effect: Allow
            Action:
            - ec2:CreateNetworkInterface
            - ec2:DescribeNetworkInterfaces
            - ec2:DeleteNetworkInterface
            Resource: "*"
      - PolicyName: Conf
        PolicyDocument:
          Statement:
          - Action: ssm:GetParametersByPath
            Effect: Allow
            Resource:
              !Sub arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/notifications/${Stage}/workers/harvester
      - PolicyName: Cloudwatch
        PolicyDocument:
          Statement:
            Effect: Allow
            Action: cloudwatch:PutMetricData
            Resource: "*"
      - PolicyName: connectRdsProxy
        PolicyDocument:
          Statement:
          - Action:
            - rds-db:connect
            Effect: Allow
            Resource: 
              Fn::ImportValue: !Sub RegistrationsDbProxyId-${Stage}

  HarvesterLambdaCtr:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: !Sub ${Stack}-${App}-ctr-${Stage}
      PackageType: Image
      Code:
        ImageUri: !Join [':', [!ImportValue NotificationLambdaRepositoryUri, !Ref BuildId]]
      ImageConfig:
        Command:
          - com.gu.notifications.worker.Harvester::handleHarvesting
      Environment:
        Variables:
          Stage: !Ref Stage
          Stack: !Ref Stack
          App: !Ref App
          JAVA_TOOL_OPTIONS: -XX:+TieredCompilation -XX:TieredStopAtLevel=1
      Description: Consumes events produced by the notification service and fetches batches of tokens for senders to send
      MemorySize: 10240
      Role: !GetAtt ExecutionRole.Arn
      Timeout: 60
      ReservedConcurrentExecutions: 200
      VpcConfig:
        SecurityGroupIds:
          - !Ref VPCSecurityGroup
        SubnetIds: !Ref VpcSubnets
      Tags:
        - Key: Stage
          Value: !Ref Stage
        - Key: Stack
          Value: !Ref Stack
        - Key: App
          Value: !Ref App

  SqsEventSourceMapping:
    Type: AWS::Lambda::EventSourceMapping
    DependsOn:
    - Sqs
    - HarvesterLambdaCtr
    Properties:
      BatchSize: 1
      Enabled: True
      EventSourceArn: !GetAtt Sqs.Arn
      FunctionName: !Ref HarvesterLambdaCtr

  ThrottleAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmActions: [!Ref AlarmTopic]
      OKActions: [!Ref AlarmTopic]
      AlarmDescription: !Sub Triggers if the ${App} lambda is throttled in ${Stage}. ${RunbookCopy}
      ComparisonOperator: GreaterThanThreshold
      Dimensions:
      - Name: FunctionName
        Value: !Ref HarvesterLambdaCtr
      EvaluationPeriods: 1
      MetricName: Throttles
      Namespace: AWS/Lambda
      Period: 360
      Statistic: Sum
      Threshold: 0
      TreatMissingData: notBreaching

  DlqDepthAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmDescription: !Sub Triggers if the ${App} lambda failed to process some messages in ${Stage}. ${RunbookCopy}.
      Namespace: AWS/SQS
      MetricName: ApproximateNumberOfMessagesVisible
      Dimensions:
        - Name: QueueName
          Value: !GetAtt Dlq.QueueName
      Period: 60
      Statistic: Sum
      EvaluationPeriods: 1
      ComparisonOperator: GreaterThanThreshold
      Threshold: 0
      AlarmActions: [!Ref AlarmTopic]
      OKActions: [!Ref AlarmTopic]
      TreatMissingData: notBreaching

  TooFewInvocationsAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmActions: [!Ref AlarmTopic]
      OKActions: [!Ref AlarmTopic]
      ActionsEnabled: !If [IsProdStage, true, false]
      AlarmDescription: !Sub Triggers if the ${App} lambda is not frequently invoked in ${Stage}. ${RunbookCopy}
      ComparisonOperator: LessThanOrEqualToThreshold
      Dimensions:
        - Name: FunctionName
          Value: !Ref HarvesterLambdaCtr
      EvaluationPeriods: 1
      MetricName: Invocations
      Namespace: AWS/Lambda
      Period: 7200
      Statistic: Sum
      Threshold: 0
      TreatMissingData: breaching

Outputs:
  SQSArn:
    Description: The arn of the sqs queue
    Value: !GetAtt Sqs.Arn
