AWSTemplateFormatVersion: '2010-09-09'
Description: 'stack: {{stackName}} | deployed by Kes'
Parameters:
  CmrPassword:
    Type: String
    Description: 'Password used to publish CMR records. This is encrypted by Custom::Cumulus'
    Default: ""
    NoEcho: true
  ElasticSearchDomain:
    Type: String
    Description: 'ElasticSearch Url'
    NoEcho: true
    Default: 'noValue'
  LaunchpadPassphrase:
    Type: String
    Description: 'Passphrase of the Launchpad PIK certificate. This is encrypted by Custom::Cumulus'
    Default: ""
    NoEcho: true
  SecurityGroupId:
    Type: String
    Description: 'Security Group ID'
    Default: 'noValue'
  log2elasticsearchLambdaFunctionArn:
    Type: String
    Description: 'logToElasticsearch Lambda function ARN'
{{#each apis}}
  {{#ifEquals name "backend" }}
  EcsCluster:
    Type: String
  AsyncOperationTaskDefinition:
    Type: String
  BulkDeleteLambdaFunctionArn:
    Type: String
    Description: 'BulkDelete Lambda function ARN'
  CreateReconciliationReportLambdaFunctionArn:
    Type: String
    Description: 'CreateReconciliationReport Lambda function ARN'
  EmsIngestReportLambdaFunctionArn:
    Type: String
    Description: 'EmsIngestReport Lambda function ARN'
  EmsDistributionReportLambdaFunctionArn:
    Type: String
    Description: 'EmsDistributionReport Lambda function ARN'
  EmsProductMetadataReportLambdaFunctionArn:
    Type: String
    Description: 'EmsProductMetadataReport Lambda function ARN'
  messageConsumerLambdaFunctionArn:
    Type: String
    Description: 'messageConsumer Lambda function ARN'
  ScheduleSFLambdaFunctionArn:
    Type: String
    Description: 'ScheduleSF Lambda function ARN'
  KinesisInboundEventLoggerLambdaFunctionArn:
    Type: String
    Description: 'KinesisInboundEventLogger Lambda function ARN'
  IndexFromDatabaseLambdaFunctionArn:
    Type: String
    Description: 'IndexFromDatabaseLambda Lambda function ARN'
  BulkOperationLambdaFunctionArn:
    Type: String
    Description: 'BulkOperation Lambda function ARN'
  distributionRestApi:
    Type: String
    Description: Distribution REST API ID
    Default: 'noValue'
  {{/ifEquals}}
{{/each}}
{{# each parent.dynamos}}
  {{@key}}DynamoDB:
    Type: String
    Description: '{{@key}} Table name'
{{/each}}

Resources:

  #################################################
  # APIGateway config BEGIN
  #################################################
{{#each apis}}
  {{name}}RestApi:
    Type: AWS::ApiGateway::RestApi
    Properties:
      Name: {{../stackName}}-{{name}}
      {{#ifPrivateApi ../parent.apiConfigs name}}
      EndpointConfiguration:
        Types:
          - 'PRIVATE'
      # Needed for deploy, but in an NGAP account, this will get overwritten
      Policy:
        Version: '2012-10-17'
        Statement:
          - Effect: "Allow"
            Principal: "*"
            Action: "*"
            Resource: "*"
            Condition:
              StringEquals:
                aws:SourceVpc: {{../../parent.vpc.vpcId}}
      {{/ifPrivateApi}}
{{/each}}

{{#each apis}}
  {{name}}ApiGatewayStage:
    Type: AWS::ApiGateway::Stage
    Properties:
      RestApiId:
        Ref: {{name}}RestApi
      StageName: {{../parent.apiStage}}
      {{#ifLogApiGatewayToCloudWatch ../parent.apiConfigs name}}
      AccessLogSetting:
        DestinationArn:
          Fn::GetAtt:
            - ApiGatewayCloudWatchLogGroup{{name}}
            - Arn
        Format: '{ "requestId":"$context.requestId", "ip": "$context.identity.sourceIp", "caller":"$context.identity.caller",  "user":"$context.identity.user", "requestTime":"$context.requestTime", "httpMethod":"$context.httpMethod", "resourcePath":"$context.resourcePath", "status":"$context.status", "protocol":"$context.protocol", "responseLength":"$context.responseLength" }'
      MethodSettings:
        - DataTraceEnabled: true
          HttpMethod: "*"
          LoggingLevel: INFO
          ResourcePath: "/*"
          MetricsEnabled: false
      {{/ifLogApiGatewayToCloudWatch}}
      DeploymentId:
        Ref: ApiGatewayDeployment1{{../parent.apiStage}}{{name}}
{{/each}}


{{# if apiMethods}}
{{# each apiDependencies}}
  {{# if ../apiDeploy }}
  ApiGatewayDeployment1{{../parent.apiStage}}{{name}}:
    DependsOn:
  {{#each methods}}
    - {{name}}
  {{/each}}
    Type: AWS::ApiGateway::Deployment
    Properties:
      RestApiId:
        Ref: {{name}}RestApi
  {{/if}}
{{/each}}

{{#each apiMethods}}
  {{name}}:
    Type: AWS::ApiGateway::Method
    Properties:
      ResourceId:
        Ref: {{resource}}
      RestApiId:
        Ref: {{api}}RestApi
      HttpMethod: {{method}}
      AuthorizationType: NONE
      Integration:
        Type: AWS_PROXY
        IntegrationHttpMethod: POST
        Uri:
          Fn::Join:
          - ''
          - - 'arn:aws:apigateway:'
            - Ref: AWS::Region
            - :lambda:path/2015-03-31/functions/
            - Fn::GetAtt:
              - {{lambda}}LambdaFunction
              - Arn
            - /invocations

{{/each}}

{{#each apiMethodsOptions}}
  {{name}}:
    Type: AWS::ApiGateway::Method
    Properties:
      AuthorizationType: NONE
      HttpMethod: OPTIONS
      Integration:
        IntegrationResponses:
        - ResponseParameters:
            method.response.header.Access-Control-Allow-Headers: '''Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'''
            method.response.header.Access-Control-Allow-Methods: '''OPTIONS,PUT,POST,GET,DELETE'''
            method.response.header.Access-Control-Allow-Origin: '''*'''
          ResponseTemplates:
            application/json: ''
          StatusCode: '200'
        RequestTemplates:
          application/json: '{statusCode:200}'
        Type: MOCK
      MethodResponses:
      - ResponseModels: {}
        ResponseParameters:
          method.response.header.Access-Control-Allow-Headers: true
          method.response.header.Access-Control-Allow-Methods: true
          method.response.header.Access-Control-Allow-Origin: true
        StatusCode: '200'
      RequestParameters:
        method.request.header.Authorization: true
      ResourceId:
        Ref: {{resource}}
      RestApiId:
        Ref: {{api}}RestApi

{{/each}}

{{#each apiResources}}
  {{name}}:
    Type: AWS::ApiGateway::Resource
    Properties:
      ParentId:
    {{# if firstParent}}
        Fn::GetAtt:
          - {{api}}RestApi
          - RootResourceId
    {{else}}
      {{#each parents}}
        {{this}}
      {{/each}}
    {{/if}}
      PathPart: '{{pathPart}}'
      RestApiId:
        Ref: {{api}}RestApi

{{/each}}


{{#each apis}}
 {{#ifLogApiGatewayToCloudWatch ../parent.apiConfigs name }}
  # Add cloudwatch filters to enabled api gateways
  # create log group
  ApiGatewayCloudWatchLogGroup{{name}}:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName:
        Fn::Join:
          - ""
          - - "API-Gateway-Execution-Logs_"
            - Ref: {{name}}RestApi
            - "/{{../parent.apiStage}}"
      RetentionInDays: 30

 {{#if ../parent.logToSharedDestination }}
  # create API Subscription Filter
  ApiGatewayLogSubscription{{name}}:
    Type: AWS::Logs::SubscriptionFilter
    DependsOn:
      - ApiGatewayCloudWatchLogGroup{{name}}
    Properties:
      DestinationArn: "{{../parent.logToSharedDestination}}"
      FilterPattern: ""
      LogGroupName:
        Ref: ApiGatewayCloudWatchLogGroup{{name}}
  {{/if}}
 {{/ifLogApiGatewayToCloudWatch}}



{{/each}}

{{/if}}
  #################################################
  # APIGateway config END
  #################################################

  #################################################
  # Lambda config BEGIN
  #################################################
{{#each lambdas}}
  {{@key}}LambdaFunction:
    Type: AWS::Lambda::Function
    Properties:
      Code:
        S3Bucket: {{this.bucket}}
        S3Key: {{this.remote}}
      FunctionName: {{../stackName}}-{{@key}}
      Environment:
        Variables:
          stackName: {{../stackName}}
          public_buckets: {{{collectBuckets ../parent.buckets "public"}}}
          protected_buckets: {{{collectBuckets ../parent.buckets "protected"}}}
        {{#if this.useElasticSearch }}
        {{#if ../parent.es.name}}
          ES_HOST:
            Ref: ElasticSearchDomain
        {{/if}}
        {{/if}}
      {{# ifEquals this.urs_redirect "token"}}
        {{# if ../parent.api_backend_url}}
          TOKEN_REDIRECT_ENDPOINT: {{../parent.api_backend_url}}token
        {{else}}
          TOKEN_REDIRECT_ENDPOINT:
            Fn::Join:
              - ""
              - - "https://"
                - Ref: backendRestApi
                - ".execute-api."
                - {"Fn::Sub": "${AWS::Region}"}
                - ".amazonaws.com"
                - {{{getApiPortSuffix ../parent.apiConfigs "backend"}}}
                - "{{../parent.apiStage}}/token"
        {{/if}}
      {{/ifEquals}}
      {{# ifEquals this.urs_redirect "distribution"}}
        {{# if ../parent.api_distribution_url}}
          DISTRIBUTION_REDIRECT_ENDPOINT: {{../parent.api_distribution_url}}redirect
        {{/if}}
        {{#if ../parent.deployDistributionApi}}
          DISTRIBUTION_REDIRECT_ENDPOINT:
            Fn::Join:
              - ""
              - - "https://"
                - Ref: distributionRestApi
                - ".execute-api."
                - {"Fn::Sub": "${AWS::Region}"}
                - ".amazonaws.com"
                - {{{getApiPortSuffix ../parent.apiConfigs "distribution"}}}
                - "{{../parent.apiStage}}/redirect"
        {{/if}}
      {{/ifEquals}}
      {{# if this.useDistributionApi}}
        {{# if ../parent.api_distribution_url}}
          DISTRIBUTION_ENDPOINT: {{../parent.api_distribution_url}}
        {{/if}}
        {{#if ../deployDistributionApi}}
          DISTRIBUTION_ENDPOINT:
            Fn::Join:
              - ""
              - - "https://"
                - Ref: distributionRestApi
                - ".execute-api."
                - {"Fn::Sub": "${AWS::Region}"}
                - ".amazonaws.com"
                - {{{getApiPortSuffix ../parent.apiConfigs "distribution"}}}
                - "{{../parent.apiStage}}"
        {{/if}}
      {{/if}}
    {{#each this.envs}}
      {{# if this.function}}
        {{#if this.array}}
          {{@key}}:
            {{this.function}}:
            {{#each this.array}}
              - {{this}}
            {{/each}}
        {{/if}}
        {{#if this.value}}
          {{@key}}:
            {{this.function}}: {{this.value}}
        {{/if}}
      {{else}}
          {{@key}}: {{{this}}}
      {{/if}}
    {{/each}}
      Handler: {{this.handler}}
      MemorySize: {{this.memory}}
{{# if this.apiRole }}
      Role: {{../parent.iams.lambdaApiGatewayRoleArn}}
{{else if this.distributionRole}}
      Role: {{../parent.iams.distributionRoleArn}}
{{else}}
{{#ifEquals @key "executeMigrations"}}
      Role: {{../parent.iams.migrationRoleArn}}
{{/ifEquals}}
{{#ifNotEquals @key "executeMigrations"}}
      Role: {{../parent.iams.lambdaProcessingRoleArn}}
{{/ifNotEquals}}
{{/if}}
      Runtime: {{# if this.runtime}}{{this.runtime}}{{else}}nodejs8.10{{/if}}
      Timeout: {{this.timeout}}
      Tags:
        - Key: Project
          Value: {{../stackName}}

  {{# if this.launchInVpc }}
    {{# if ../parent.vpc }}
      VpcConfig:
        SecurityGroupIds:
          - Ref: SecurityGroupId
        SubnetIds:
        {{#each ../parent.vpc.subnets}}
          - {{this}}
        {{/each}}
    {{/if}}
  {{/if}}

{{# if this.apiGateway }}
  {{@key}}LambdaPermissionApiGateway:
    Type: AWS::Lambda::Permission
    Properties:
      Action: lambda:InvokeFunction
      FunctionName:
        Fn::GetAtt:
        - {{@key}}LambdaFunction
        - Arn
      Principal: apigateway.amazonaws.com
{{/if}}

{{# if this.logToElasticSearch }}
  {{@key}}LogSubscription:
    Type: AWS::Logs::SubscriptionFilter
    DependsOn:
      - {{@key}}LogGroup
    Properties:
      DestinationArn:
        Ref: log2elasticsearchLambdaFunctionArn
      LogGroupName: '/aws/lambda/{{../stackName}}-{{@key}}'
      FilterPattern: ""

  {{@key}}LogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: '/aws/lambda/{{../stackName}}-{{@key}}'
      RetentionInDays: 30
{{/if}}

{{#if this.logToSharedDestination }}
  # Configure Lambda log subscription to shareLogDestination for API lambdas
  {{@key}}LogSubscriptionToSharedDestination:
    Type: AWS::Logs::SubscriptionFilter
    DependsOn:
      - {{@key}}LogGroup
    Properties:
      DestinationArn: "{{this.logToSharedDestination}}"
      LogGroupName: '/aws/lambda/{{../stackName}}-{{@key}}'
      FilterPattern: ""

  {{@key}}LogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: '/aws/lambda/{{../stackName}}-{{@key}}'
      RetentionInDays: 30
{{/if}}

{{# if this.addLogGroup }}
  {{@key}}LogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: '/aws/lambda/{{../stackName}}-{{@key}}'
      RetentionInDays: 30
{{/if}}

{{/each}}

  #################################################
  # Lambda config END
  #################################################

Outputs:
  {{#each apis}}
  {{name}}RestApiResource:
    Value:
      Ref: {{name}}RestApi
  {{name}}RestApiResourceUrl:
    Value:
      Fn::Join:
        - ""
        - - "https://"
          - Ref: {{name}}RestApi
          - ".execute-api."
          - {"Fn::Sub": "${AWS::Region}"}
          - ".amazonaws.com"
          - {{{getApiPortSuffix ../parent.apiConfigs name}}}
          - "{{../parent.apiStage}}/"
  {{/each}}
