---
AWSTemplateFormatVersion: '2010-09-09'
Description: 'AWS in Action: chapter 16'
Parameters:
  KeyName:
    Description: 'Key Pair name'
    Type: 'AWS::EC2::KeyPair::KeyName'
    Default: mykey
Resources:
  Bucket:
    Type: 'AWS::S3::Bucket'
    Properties:
      BucketName: !Sub 'imagery-${AWS::AccountId}'
      WebsiteConfiguration:
        ErrorDocument: error.html
        IndexDocument: index.html
  Table:
    Type: 'AWS::DynamoDB::Table'
    Properties:
      AttributeDefinitions:
      - AttributeName: id
        AttributeType: S
      KeySchema:
      - AttributeName: id
        KeyType: HASH
      ProvisionedThroughput:
        ReadCapacityUnits: 1
        WriteCapacityUnits: 1
      TableName: 'imagery-image'
  SQSDLQueue:
    Type: 'AWS::SQS::Queue'
    Properties:
      QueueName: 'message-dlq'
  SQSQueue:
    Type: 'AWS::SQS::Queue'
    Properties:
      QueueName: message
      RedrivePolicy:
        deadLetterTargetArn: !Sub '${SQSDLQueue.Arn}'
        maxReceiveCount: 10
  WorkerInstanceProfile:
    Type: 'AWS::IAM::InstanceProfile'
    Properties:
      Roles:
      - !Ref WorkerRole
  WorkerRole:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - 'ec2.amazonaws.com'
          Action:
          - 'sts:AssumeRole'
      Policies:
      - PolicyName: sqs
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
          - Effect: Allow
            Action:
            - 'sqs:ChangeMessageVisibility'
            - 'sqs:DeleteMessage'
            - 'sqs:ReceiveMessage'
            Resource: !Sub '${SQSQueue.Arn}'
      - PolicyName: cloudwatch
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
          - Effect: Allow
            Action:
            - 'cloudwatch:PutMetricData'
            Resource: '*'
      - PolicyName: 's3-elasticbeanstalk'
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
          - Effect: Allow
            Action:
            - 's3:Get*'
            - 's3:List*'
            - 's3:PutObject'
            Resource:
            - !Sub 'arn:aws:s3:::elasticbeanstalk-*-${AWS::AccountId}/*'
            - !Sub 'arn:aws:s3:::elasticbeanstalk-*-${AWS::AccountId}-*/*'
      - PolicyName: 's3-image'
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
          - Effect: Allow
            Action:
            - 's3:GetObject'
            - 's3:PutObject'
            - 's3:PutObjectAcl'
            Resource: !Sub 'arn:aws:s3:::${Bucket}/*'
      - PolicyName: dynamodb
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
          - Effect: Allow
            Action:
            - 'dynamodb:GetItem'
            - 'dynamodb:UpdateItem'
            Resource: !Sub 'arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${Table}'
  EBWorkerConfigurationTemplate:
    Type: 'AWS::ElasticBeanstalk::ConfigurationTemplate'
    Properties:
      ApplicationName: !Ref EBWorkerApplication
      Description: 'Imagery worker: AWS in Action: chapter 16'
      SolutionStackName: '64bit Amazon Linux 2018.03 v4.7.1 running Node.js'
      OptionSettings:
      - Namespace: 'aws:autoscaling:launchconfiguration'
        OptionName: 'EC2KeyName'
        Value: !Ref KeyName
      - Namespace: 'aws:autoscaling:launchconfiguration'
        OptionName: 'IamInstanceProfile'
        Value: !Ref WorkerInstanceProfile
      - Namespace: 'aws:elasticbeanstalk:sqsd'
        OptionName: 'WorkerQueueURL'
        Value: !Ref SQSQueue
      - Namespace: 'aws:elasticbeanstalk:sqsd'
        OptionName: 'HttpPath'
        Value: '/sqs'
      - Namespace: 'aws:elasticbeanstalk:container:nodejs'
        OptionName: 'NodeCommand'
        Value: 'node worker.js'
      - Namespace: 'aws:elasticbeanstalk:application:environment'
        OptionName: 'ImageQueue'
        Value: !Ref SQSQueue
      - Namespace: 'aws:elasticbeanstalk:application:environment'
        OptionName: 'ImageBucket'
        Value: !Ref Bucket
  EBWorkerEnvironment:
    Type: 'AWS::ElasticBeanstalk::Environment'
    Properties:
      ApplicationName: !Ref EBWorkerApplication
      Description: 'Imagery worker: AWS in Action: chapter 16'
      TemplateName: !Ref EBWorkerConfigurationTemplate
      VersionLabel: !Ref EBWorkerApplicationVersion
      Tier:
        Type: 'SQS/HTTP'
        Name: 'Worker'
        Version: '1.0'
  EBWorkerApplication:
    Type: 'AWS::ElasticBeanstalk::Application'
    Properties:
      ApplicationName: 'imagery-worker'
      Description: 'Imagery worker: AWS in Action: chapter 16'
  EBWorkerApplicationVersion:
    Type: 'AWS::ElasticBeanstalk::ApplicationVersion'
    Properties:
      ApplicationName: !Ref EBWorkerApplication
      Description: 'Imagery worker: AWS in Action: chapter 16'
      SourceBundle:
        S3Bucket: 'awsinaction-code2'
        S3Key: 'chapter16/build/worker.zip'
  ServerInstanceProfile:
    Type: 'AWS::IAM::InstanceProfile'
    Properties:
      Roles:
      - !Ref ServerRole
  ServerRole:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - 'ec2.amazonaws.com'
          Action:
          - 'sts:AssumeRole'
      Policies:
      - PolicyName: sqs
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
          - Effect: Allow
            Action: 'sqs:SendMessage'
            Resource: !Sub '${SQSQueue.Arn}'
      - PolicyName: cloudwatch
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
          - Effect: Allow
            Action: 'cloudwatch:PutMetricData'
            Resource: '*'
      - PolicyName: 's3-elasticbeanstalk'
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
          - Effect: Allow
            Action:
            - 's3:Get*'
            - 's3:List*'
            - 's3:PutObject'
            Resource:
            - !Sub 'arn:aws:s3:::elasticbeanstalk-*-${AWS::AccountId}/*'
            - !Sub 'arn:aws:s3:::elasticbeanstalk-*-${AWS::AccountId}-*/*'
      - PolicyName: 's3-image'
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
          - Effect: Allow
            Action: 's3:PutObject'
            Resource: !Sub 'arn:aws:s3:::${Bucket}/*'
      - PolicyName: dynamodb
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
          - Effect: Allow
            Action:
            - 'dynamodb:GetItem'
            - 'dynamodb:PutItem'
            - 'dynamodb:UpdateItem'
            Resource: !Sub  'arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${Table}'
  EBServerConfigurationTemplate:
    Type: 'AWS::ElasticBeanstalk::ConfigurationTemplate'
    Properties:
      ApplicationName: !Ref EBServerApplication
      Description: 'Imagery server: AWS in Action: chapter 16'
      SolutionStackName: '64bit Amazon Linux 2018.03 v4.7.1 running Node.js'
      OptionSettings:
      - Namespace: 'aws:autoscaling:asg'
        OptionName: 'MinSize'
        Value: '2'
      - Namespace: 'aws:autoscaling:launchconfiguration'
        OptionName: 'EC2KeyName'
        Value: !Ref KeyName
      - Namespace: 'aws:autoscaling:launchconfiguration'
        OptionName: 'IamInstanceProfile'
        Value: !Ref ServerInstanceProfile
      - Namespace: 'aws:elasticbeanstalk:container:nodejs'
        OptionName: 'NodeCommand'
        Value: 'node server.js'
      - Namespace: 'aws:elasticbeanstalk:application:environment'
        OptionName: 'ImageQueue'
        Value: !Ref SQSQueue
      - Namespace: 'aws:elasticbeanstalk:application:environment'
        OptionName: 'ImageBucket'
        Value: !Ref Bucket
      - Namespace: 'aws:elasticbeanstalk:container:nodejs:staticfiles'
        OptionName: '/public'
        Value: '/public'
  EBServerEnvironment:
    Type: 'AWS::ElasticBeanstalk::Environment'
    Properties:
      ApplicationName: !Ref EBServerApplication
      Description: 'Imagery server: AWS in Action: chapter 16'
      TemplateName: !Ref EBServerConfigurationTemplate
      VersionLabel: !Ref EBServerApplicationVersion
  EBServerApplication:
    Type: 'AWS::ElasticBeanstalk::Application'
    Properties:
      ApplicationName: 'imagery-server'
      Description: 'Imagery server: AWS in Action: chapter 16'
  EBServerApplicationVersion:
    Type: 'AWS::ElasticBeanstalk::ApplicationVersion'
    Properties:
      ApplicationName: !Ref EBServerApplication
      Description: 'Imagery server: AWS in Action: chapter 16'
      SourceBundle:
        S3Bucket: 'awsinaction-code2'
        S3Key: 'chapter16/build/server.zip'
Outputs:
  EndpointURL:
    Value: !Sub 'http://${EBServerEnvironment.EndpointURL}'
    Description: Load Balancer URL
