AWSTemplateFormatVersion: 2010-09-09
Description: Lambda function which retrieves the latest beta version from App Store Connect.
Parameters:
  Stack:
    Description: Stack name
    Type: String
    Default: mobile
  App:
    Description: Application name
    Type: String
    Default: live-app-versions
  Stage:
    Description: Stage name
    Type: String
    AllowedValues:
      - CODE
      - PROD
    Default: CODE
  AppleAppId:
    Description: The Apple id of the iOS app which will be polled against
    Type: String
  DeployBucket:
    Description: Bucket where RiffRaff uploads artifacts on deploy
    Type: String
    Default: mobile-dist
Mappings:
  StageVariables:
    CODE:
      UploadPath: reserved-paths/CODE/*-live-app/
      ScheduleStatus: DISABLED
      AlarmActionsEnabled: FALSE
    PROD:
      UploadPath: reserved-paths/*-live-app/
      ScheduleStatus: ENABLED
      AlarmActionsEnabled: TRUE
Resources:
  ExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action: sts:AssumeRole
      Path: /
      Policies:
        - PolicyName: logs
          PolicyDocument:
            Statement:
              Effect: Allow
              Action:
                - logs:CreateLogGroup
                - logs:CreateLogStream
                - logs:PutLogEvents
              Resource: arn:aws:logs:*:*:*
        - PolicyName: lambda
          PolicyDocument:
            Statement:
              Effect: Allow
              Action:
                - lambda:InvokeFunction
              Resource: "*"
        - PolicyName: privateConfiguration
          PolicyDocument:
            Statement:
              Effect: Allow
              Action:
                - ssm:GetParametersByPath
              Resource: !Sub arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/${Stage}/${Stack}/${App}
        - PolicyName: s3BuildOutput
          PolicyDocument:
            Statement:
              - Effect: Allow
                Action:
                  - s3:PutObject
                  - s3:PutObjectAcl
                  - s3:GetObject
                Resource: !Sub
                  - arn:aws:s3:::static-content-dist/${Path}*
                  - Path: !FindInMap [StageVariables, !Ref Stage, UploadPath]
              - Effect: Allow
                Action:
                  - s3:ListBucket
                Resource: arn:aws:s3:::static-content-dist

  IosDeploymentsLambda:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: !Sub ios-deployments-${Stage}
      Code:
        S3Bucket:
          Ref: DeployBucket
        S3Key: !Sub ${Stack}/${Stage}/${App}/${App}.jar
      Environment:
        Variables:
          Stage: !Ref Stage
          Stack: !Ref Stack
          App: !Ref App
          APPLE_APP_ID: !Ref AppleAppId
      Description: Lambda function which distributes uploaded iOS builds to beta testers.
      Handler: com.gu.iosdeployments.Lambda::handler
      MemorySize: 1024
      Role: !GetAtt ExecutionRole.Arn
      Runtime: java21
      Timeout: 240

  IosLiveAppVersionsLambda:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: !Sub ios-live-app-versions-${Stage}
      Code:
        S3Bucket:
          Ref: DeployBucket
        S3Key: !Sub ${Stack}/${Stage}/${App}/${App}.jar
      Environment:
        Variables:
          Stage: !Ref Stage
          Stack: !Ref Stack
          App: !Ref App
          APPLE_APP_ID: !Ref AppleAppId
      Description: Lambda function which retrieves the latest beta version from App Store Connect.
      Handler: com.gu.liveappversions.ios.Lambda::handler
      MemorySize: 1024
      Role: !GetAtt ExecutionRole.Arn
      Runtime: java21
      Timeout: 60

  AndroidLiveAppVersionsLambda:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: !Sub android-live-app-versions-${Stage}
      Code:
        S3Bucket:
          Ref: DeployBucket
        S3Key: !Sub ${Stack}/${Stage}/${App}/${App}.jar
      Environment:
        Variables:
          Stage: !Ref Stage
          Stack: !Ref Stack
          App: !Ref App
      Description: Lambda function which retrieves the latest version/track information from Google Play.
      Handler: com.gu.liveappversions.android.Lambda::handler
      MemorySize: 1024
      Role: !GetAtt ExecutionRole.Arn
      Runtime: java21
      Timeout: 60

  PollingEvent:
    Type: AWS::Events::Rule
    Properties:
      State: !FindInMap [StageVariables, !Ref Stage, ScheduleStatus]
      Description: Triggers the lambdas in this project periodically to check for new deployments or completed releases
      ScheduleExpression: rate(5 minutes)
      Targets:
        - Id: IosLiveAppVersionsLambda
          Arn: !GetAtt IosLiveAppVersionsLambda.Arn
        - Id: AndroidLiveAppVersionsLambda
          Arn: !GetAtt AndroidLiveAppVersionsLambda.Arn
        - Id: IosDeploymentsLambda
          Arn: !GetAtt IosDeploymentsLambda.Arn

  PollingEventIosLiveAppVersionsLambdaPermission:
    Type: AWS::Lambda::Permission
    Properties:
      Action: lambda:InvokeFunction
      FunctionName: !GetAtt IosLiveAppVersionsLambda.Arn
      Principal: events.amazonaws.com
      SourceArn: !GetAtt PollingEvent.Arn

  PollingEventAndroidLiveAppVersionsLambdaPermission:
    Type: AWS::Lambda::Permission
    Properties:
      Action: lambda:InvokeFunction
      FunctionName: !GetAtt AndroidLiveAppVersionsLambda.Arn
      Principal: events.amazonaws.com
      SourceArn: !GetAtt PollingEvent.Arn

  PollingEventIosDeploymentsLambdaPermission:
    Type: AWS::Lambda::Permission
    Properties:
      Action: lambda:InvokeFunction
      FunctionName: !GetAtt IosDeploymentsLambda.Arn
      Principal: events.amazonaws.com
      SourceArn: !GetAtt PollingEvent.Arn

  IosLiveAppVersionsFailureAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      ActionsEnabled: !FindInMap [StageVariables, !Ref Stage, AlarmActionsEnabled]
      AlarmActions:
        - !Sub arn:aws:sns:${AWS::Region}:${AWS::AccountId}:mobile-server-side
      OKActions:
        - !Sub arn:aws:sns:${AWS::Region}:${AWS::AccountId}:mobile-server-side
      AlarmName: !Sub Failures when retrieving or storing the latest iOS versions in ${Stage}
      AlarmDescription: |
        <<<Runbook|https://docs.google.com/document/d/1by6RLfo_d-6wyAp7OoQquv4tZYUR6FYhAn0GZkJtqH8/edit#heading=h.f2qd026kxlds>>>
      Metrics:
        - Id: e1
          Label: Error percentage of lambda
          Expression: "100*(m1/m2)"
        - Id: m1
          Label: Number of errors for lambda
          MetricStat:
            Metric:
              MetricName: Errors
              Namespace: AWS/Lambda
              Dimensions:
                - Name: FunctionName
                  Value: !Ref IosLiveAppVersionsLambda
            Period: 3600
            Stat: Sum
          ReturnData: false
        - Id: m2
          Label: Number of invocations for lambda
          MetricStat:
            Metric:
              MetricName: Invocations
              Namespace: AWS/Lambda
              Dimensions:
                - Name: FunctionName
                  Value: !Ref IosLiveAppVersionsLambda
            Period: 3600
            Stat: Sum
          ReturnData: false
      ComparisonOperator: GreaterThanOrEqualToThreshold
      EvaluationPeriods: 1
      Threshold: 100

  AndroidLiveAppVersionsFailureAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      ActionsEnabled: !FindInMap [StageVariables, !Ref Stage, AlarmActionsEnabled]
      AlarmActions:
        - !Sub arn:aws:sns:${AWS::Region}:${AWS::AccountId}:mobile-server-side
      OKActions:
        - !Sub arn:aws:sns:${AWS::Region}:${AWS::AccountId}:mobile-server-side
      AlarmName: !Sub Failures when retrieving or storing the latest Android versions in ${Stage}
      AlarmDescription: |
        <<<Runbook|https://docs.google.com/document/d/1by6RLfo_d-6wyAp7OoQquv4tZYUR6FYhAn0GZkJtqH8/edit#heading=h.vb63w7y2on5t>>>
      Metrics:
        - Id: e1
          Label: Error percentage of lambda
          Expression: "100*(m1/m2)"
        - Id: m1
          Label: Number of errors for lambda
          MetricStat:
            Metric:
              MetricName: Errors
              Namespace: AWS/Lambda
              Dimensions:
                - Name: FunctionName
                  Value: !Ref AndroidLiveAppVersionsLambda
            Period: 3600
            Stat: Sum
          ReturnData: false
        - Id: m2
          Label: Number of invocations for lambda
          MetricStat:
            Metric:
              MetricName: Invocations
              Namespace: AWS/Lambda
              Dimensions:
                - Name: FunctionName
                  Value: !Ref AndroidLiveAppVersionsLambda
            Period: 3600
            Stat: Sum
          ReturnData: false
      ComparisonOperator: GreaterThanOrEqualToThreshold
      EvaluationPeriods: 1
      Threshold: 100

  IosDeploymentsFailureAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      ActionsEnabled: !FindInMap [StageVariables, !Ref Stage, AlarmActionsEnabled]
      AlarmActions:
        - !Sub arn:aws:sns:${AWS::Region}:${AWS::AccountId}:mobile-server-side
      OKActions:
        - !Sub arn:aws:sns:${AWS::Region}:${AWS::AccountId}:mobile-server-side
      AlarmName: !Sub Failures when checking or updating iOS beta deployments in ${Stage}
      AlarmDescription: |
        <<<Runbook|https://docs.google.com/document/d/1by6RLfo_d-6wyAp7OoQquv4tZYUR6FYhAn0GZkJtqH8/edit#heading=h.fxgskya8ndu0>>>
      Metrics:
        - Id: e1
          Label: Error percentage of lambda
          Expression: "100*(m1/m2)"
        - Id: m1
          Label: Number of errors for lambda
          MetricStat:
            Metric:
              MetricName: Errors
              Namespace: AWS/Lambda
              Dimensions:
                - Name: FunctionName
                  Value: !Ref IosDeploymentsLambda
            Period: 3600
            Stat: Sum
          ReturnData: false
        - Id: m2
          Label: Number of invocations for lambda
          MetricStat:
            Metric:
              MetricName: Invocations
              Namespace: AWS/Lambda
              Dimensions:
                - Name: FunctionName
                  Value: !Ref IosDeploymentsLambda
            Period: 3600
            Stat: Sum
          ReturnData: false
      ComparisonOperator: GreaterThanOrEqualToThreshold
      EvaluationPeriods: 1
      Threshold: 100

