AWSTemplateFormatVersion: 2010-09-09
Description: Stack to provision complete rekognition

Parameters:
  BucketName:
    Description: The S3 bucket name to upload CSV files
    Type: String
    Default: changeme
  BucketLambdaCode:
    Description: The S3 bucket where you uploaded your lambda code
    Type: String
    Default: changeme
  LanguageCode:
    Description: The language code to use in Amazon Comprehend to analyze your files
    Type: String
    Default: pt
  PrivateSubnetID1:
    Description: ID of the first private subnet to deploy Lambda in
    Type: String
    Default: changeme
  PrivateSubnetID2:
    Description: ID of the second private subnet to deploy Lambda in
    Type: String
    Default: changeme
  Nat1PublicIP:
    Description: Public IP of the first Nat Gateway
    Type: String
    Default: changeme
  Nat2PublicIP:
    Description: Public IP of the second Nat Gateway
    Type: String
    Default: changeme
  SecurityGroup:
    Description: Security group to associate with AWS Lambda
    Type: String
    Default: changeme
  YourPublicIP:
    Description: Your public IP
    Type: String
    Default: changeme


Resources:
  # SQS Queue that will receive the messages from Textract
  SqsEsComprehend:
    Type: AWS::SQS::Queue
    Properties:
      QueueName: sqs-es-comprehend-new  

  # Lambda Role for Textract
  LambdaCsvParserRole:
    Type: AWS::IAM::Role
    Properties:
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonS3FullAccess
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
        - arn:aws:iam::aws:policy/AmazonSQSFullAccess
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - lambda.amazonaws.com
          Action:
          - sts:AssumeRole
  
  # Lambda function that will trigger textract
  LambdaCsvParser:
    Type: AWS::Lambda::Function
    DependsOn:
      - LambdaCsvParserRole
    Properties:
      Code:
        S3Bucket: !Ref BucketLambdaCode
        S3Key: lambda/lambda_csv_parser.zip
      Handler: lambda_function.lambda_handler
      Role: !GetAtt LambdaCsvParserRole.Arn
      Runtime: python3.8
      Timeout: 900
      MemorySize: 1536
      Environment:
        Variables:
          SQS_URL: !Ref SqsEsComprehend
          BUCKET_NAME: !Ref BucketName

  # S3 that trigger lambda function when a new object is uploaded
  s3Bucket:
      DependsOn: 
        - LambdaCsvParser
      Type: AWS::S3::Bucket
      Properties: 
        AccessControl: Private
        BucketName: !Ref BucketName
        NotificationConfiguration:
          LambdaConfigurations:
            - Event: s3:ObjectCreated:*
              Function: !GetAtt LambdaCsvParser.Arn
              Filter:
                  S3Key: # Filter just the necessary to trigger the lambda Function
                      Rules:
                        - Name: prefix
                          Value: data/

  # Giving permission to S3 invoke the lambda function
  BucketPermission:
    Type: AWS::Lambda::Permission
    Properties:
      Action: lambda:InvokeFunction
      FunctionName: !Ref LambdaCsvParser
      Principal: s3.amazonaws.com
      SourceAccount: !Ref AWS::AccountId
      SourceArn: !Sub arn:aws:s3:::${BucketName}

  # Lambda Role for Comprehend
  LambdaEnhanceRole:
    Type: AWS::IAM::Role
    Properties:
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/ComprehendFullAccess
        - arn:aws:iam::aws:policy/AmazonS3FullAccess
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
        - arn:aws:iam::aws:policy/AmazonSQSFullAccess
        - arn:aws:iam::aws:policy/AmazonEC2FullAccess
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - lambda.amazonaws.com
          Action:
          - sts:AssumeRole
  
  LambdaFunctionEventSourceMapping:
    Type: AWS::Lambda::EventSourceMapping
    Properties:
      BatchSize: 10
      Enabled: true
      EventSourceArn: !GetAtt SqsEsComprehend.Arn
      FunctionName: !GetAtt LambdaEnhance.Arn

  # Lambda Layer with AWS Datawrangler to use in the Lambda Athena function
  LambdaLayer:
    Type: AWS::Lambda::LayerVersion
    Properties: 
      CompatibleRuntimes: 
        - python3.8
      Content: 
        S3Bucket: !Ref BucketLambdaCode
        S3Key: layer/elastic.zip
      Description: Elasticserach module to use in lambda
      LayerName: elastic

  # Lambda function that will trigger amazon comprehend batch process
  LambdaEnhance:
    Type: AWS::Lambda::Function
    DependsOn:
      - LambdaEnhanceRole
      - LambdaLayer
      - ElasticSearchDomain
    Properties:
      Code:
        S3Bucket: !Ref BucketLambdaCode
        S3Key: lambda/lambda_enhance.zip
      Handler: lambda_function.lambda_handler
      Role: !GetAtt LambdaEnhanceRole.Arn
      Runtime: python3.8
      Timeout: 30
      MemorySize: 512
      Layers:
        - !Ref LambdaLayer
      VpcConfig:
        SecurityGroupIds:
          - !Ref SecurityGroup
        SubnetIds:
          - !Ref PrivateSubnetID1
          - !Ref PrivateSubnetID2
      Environment:
        Variables:
          LANGUAGE: !Ref LanguageCode
          BUCKET_NAME: !Ref BucketName
          ES_HOST: !GetAtt ElasticSearchDomain.DomainEndpoint

  # ElasticSearch Creation https://docs.aws.amazon.com/pt_br/AWSCloudFormation/latest/UserGuide/aws-resource-elasticsearch-domain.html
  ElasticSearchDomain:
    Type: AWS::Elasticsearch::Domain
    Properties:
      DomainName: es-comprehend-demo
      EBSOptions:
        EBSEnabled: true
        VolumeSize: 30
        VolumeType: gp2
      ElasticsearchClusterConfig:
        DedicatedMasterEnabled: false
        InstanceCount: 3
        InstanceType: t2.medium.elasticsearch
      ElasticsearchVersion: '7.7'
      AccessPolicies:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal:
            AWS: '*'
          Action: 'es:*'
          Resource: !Sub 'arn:aws:es:${AWS::Region}:${AWS::AccountId}:domain/es-comprehend-demo/*'
          Condition:
            IpAddress:
              aws:SourceIp:
                - !Ref YourPublicIP
                - !Ref Nat1PublicIP
                - !Ref Nat2PublicIP

Outputs:
  QueueURL: 
    Description: "URL of Amazon SQS Queue hat will be used on the other stack"
    Value: 
      Ref: SqsEsComprehend
  BucketName: 
    Description: "Bucket name that will be used on the other stack"
    Value: 
      Ref: BucketName