AWSTemplateFormatVersion: 2010-09-09
Description: This template creates Amazon ElasticSearch 6.2 cluster along with two lambda fucntions and a S3 bucket to store documents.
Resources:
  ESNS3Access:
    Type: 'AWS::IAM::Policy'
    Properties:
      PolicyName: ESNS3Access
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - 
            Effect: Allow
            Action:
              - es:ESHttpGet
              - es:ESHttpPost
              - es:ESHttpPut
            Resource:
              !Join
              - ''
              - - !GetAtt ElasticsearchDomain.Arn
                - "/*"
          -
            Effect: "Allow"
            Action: "s3:GetObject*"
            Resource: !Sub "arn:aws:s3:::${AWS::StackName}-${AWS::AccountId}-documentstore/*"
      Roles:
        - !Ref IndexDocumentLambdaExecutionRole

  ESAccess:
    Type: 'AWS::IAM::Policy'
    Properties:
      PolicyName: ESAccess
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - 
            Effect: Allow
            Action:
              - es:ESHttpGet
              - es:ESHttpPost
            Resource:
              !Join
              - ''
              - - !GetAtt ElasticsearchDomain.Arn
                - "/*"
      Roles:
        - !Ref BotFullfilmentLambdaExecutionRole

  IndexDocumentLambdaExecutionRole:
    Type: "AWS::IAM::Role"
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          -
            Effect: "Allow"
            Principal:
              Service:
                - "lambda.amazonaws.com"
            Action:
              - "sts:AssumeRole"
      Path: "/"
      ManagedPolicyArns:
        - "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
  
  BotFullfilmentLambdaExecutionRole:
    Type: "AWS::IAM::Role"
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          -
            Effect: "Allow"
            Principal:
              Service:
                - "lambda.amazonaws.com"
            Action:
              - "sts:AssumeRole"
      Path: "/"
      ManagedPolicyArns:
        - "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"

  IndexDocumentLambda:
    Type: "AWS::Lambda::Function"
    Properties:
      Code:
        S3Bucket: "aws-machine-learning-blog"
        S3Key: "artifacts/document-search-bot/es-index.zip"
      Description: This function is used to convert documents to base64 and upload index it in Elasticsearch
      FunctionName: !Sub "${AWS::StackName}-IndexDocumentLambda"
      Handler: index.handler
      MemorySize: 256
      Role: !GetAtt IndexDocumentLambdaExecutionRole.Arn
      Runtime: "nodejs12.x"
      Timeout: 25
      Environment:
        Variables:
            ESENDPOINT:
              !Join
                - ''
                - - "https://"
                  - !GetAtt ElasticsearchDomain.DomainEndpoint
            AWSREGION: !Ref AWS::Region

  BotFullfilmentLambda:
    Type: "AWS::Lambda::Function"
    Properties:
      Code:
        S3Bucket: "aws-machine-learning-blog"
        S3Key: "artifacts/document-search-bot/lex-index.zip"
      Description: "This function will do the fullfillment of document search bot"
      FunctionName: !Sub "${AWS::StackName}-DocumentSearchBotFullfilment"
      Handler: index.handler
      MemorySize: 256
      Role: !GetAtt BotFullfilmentLambdaExecutionRole.Arn
      Runtime: "nodejs12.x"
      Timeout: 25
      Environment:
        Variables:
            ESENDPOINT:
              !Join
                - ""
                - - "https://"
                  - !GetAtt ElasticsearchDomain.DomainEndpoint
            AWSREGION: !Ref AWS::Region

  ElasticsearchDomain:
      Type: "AWS::Elasticsearch::Domain"
      Properties:
        ElasticsearchClusterConfig:
          DedicatedMasterEnabled: false
          InstanceCount: 1
          InstanceType: t2.small.elasticsearch
          ZoneAwarenessEnabled: 'false'
        EBSOptions:
          EBSEnabled: true
          Iops: 0
          VolumeSize: 10
          VolumeType: "gp2"
        ElasticsearchVersion: "6.2"
        SnapshotOptions:
          AutomatedSnapshotStartHour: "0"
        AdvancedOptions:
          rest.action.multi.allow_explicit_index: 'true'
        AccessPolicies:
          Version: "2012-10-17"
          Statement:
            -
              Effect: "Allow"
              Principal:
                AWS:
                - !Sub "arn:aws:iam::${AWS::AccountId}:root"
              Action:
              - "es:*"
              Resource: '*'

  S3DocumentStoreBucket:
    Type: AWS::S3::Bucket
    DependsOn: PermissionForS3ToInvokeLambda
    Properties:
      BucketName: !Sub "${AWS::StackName}-${AWS::AccountId}-documentstore"
      NotificationConfiguration:
        LambdaConfigurations:
        -
          Event: "s3:ObjectCreated:*"
          Function: !GetAtt IndexDocumentLambda.Arn

  PermissionForS3ToInvokeLambda:
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: 'lambda:InvokeFunction'
      FunctionName: !GetAtt IndexDocumentLambda.Arn
      Principal: 's3.amazonaws.com'
      SourceAccount : !Ref AWS::AccountId
      SourceArn:
        !Join
        - ''
        - - "arn:aws:s3:::"
          - !Join
                - "-"
                - - !Ref AWS::StackName
                  - !Ref AWS::AccountId
                  - "documentstore"

Outputs:
  ElasticsearchEndpoint:
    Description: Amazon Elasticsearch Endpoint
    Value:
      !Join
        - ''
        - - "https://"
          - !GetAtt ElasticsearchDomain.DomainEndpoint
  DocumentStoreS3Bucket:
    Description: The sample Amazon S3 bucket name for storing documents.
    Value: !Ref 'S3DocumentStoreBucket'
  LexFullfilmentLambda:
    Description: It will be used for Lex bot fullfilment.
    Value: !Ref 'BotFullfilmentLambda'
  IndexDocumentLambda:
    Description: It will be used for indexing document in Amazon Elasticsearch when a document is uploaded in S3.
    Value: !Ref 'IndexDocumentLambda'
