AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: Generate HTML Documentation from CloudFormation template. (qs-1s7dari0n)
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: Input configuration
        Parameters:
          - AllowedCIDRBlocks
          - TemplatesBucket
      - Label:
          default: AWS Quick Start configuration
        Parameters:
          - QSS3BucketName
          - QSS3KeyPrefix
    ParameterLabels:
      AllowedCIDRBlocks:
        default: Allowed CIDR blocks
      TemplatesBucket:
        default: Templates bucket
      QSS3BucketName:
        default: Quick Start S3 bucket name
      QSS3KeyPrefix:
        default: Quick Start S3 key prefix
Parameters:
  AllowedCIDRBlocks:
    Type: String
    Description: Comma-delimited list of CIDR blocks allowed access to the API Gateway endpoint; e.g., '11.12.13.14/24,12.13.14.15/24'. For testing you can use '0.0.0.0/0', this will make your deployed API publicly available.
  TemplatesBucket:
    Type: String
    Description: Pre-existing S3 bucket where privately stored templates can be read from using s3://<bucket>/<key> uri format. If you do not specify this, you can only generate tables for public templates.
    Default: ''
  QSS3BucketName:
    AllowedPattern: '^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$'
    ConstraintDescription: >-
      Quick Start bucket name can include numbers, lowercase letters, uppercase
      letters, and hyphens (-). It cannot start or end with a hyphen (-).
    Default: aws-cfn-samples
    Description: >-
      S3 bucket name for the Quick Start assets.
      Only change this value if you customize or extend the Quick Start for your own use.
      This string can include numbers, lowercase letters, uppercase letters, and hyphens (-).
      It cannot start or end with a hyphen (-).
    Type: String
  QSS3KeyPrefix:
    AllowedPattern: '^[0-9a-zA-Z-/]*[/]$'
    ConstraintDescription: >-
      Quick Start key prefix can include numbers, lowercase letters, uppercase
      letters, hyphens (-), and forward slash (/) and must terminate in a forward slash.
    Default: aws-cloudformation-parameter-table-generator/
    Type: String
    Description: S3 key prefix for the Quick Start assets. Quick Start key prefix
      can include numbers, lowercase letters, uppercase letters, hyphens (-), and
      forward slash (/).

Conditions:
  TemplatesBucketCondition: !Not
    - !Equals
      - !Ref TemplatesBucket
      - ''

Resources:
  LambdaZipsBucket:
    Type: AWS::S3::Bucket

  CopyZips:
    Type: Custom::CopyZips
    Properties:
      ServiceToken: !GetAtt 'CopyZipsFunction.Arn'
      DestBucket: !Ref 'LambdaZipsBucket'
      SourceBucket: !Ref 'QSS3BucketName'
      Prefix: !Ref 'QSS3KeyPrefix'
      Objects:
        - 'functions/packages/cfn-table-generator-lambda.zip'
        - 'templates/cfn-doc-api-swagger-apigw.yaml'

  CopyZipsRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
      Path: /
      Policies:
        - PolicyName: lambda-copier
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - s3:GetObject
                Resource:
                  - !Sub 'arn:aws:s3:::${QSS3BucketName}/${QSS3KeyPrefix}*'
              - Effect: Allow
                Action:
                  - s3:PutObject
                  - s3:DeleteObject
                Resource:
                  - !Sub 'arn:aws:s3:::${LambdaZipsBucket}/${QSS3KeyPrefix}*'

  CopyZipsFunction:
    Type: AWS::Lambda::Function
    Properties:
      Description: Copies objects from a source S3 bucket to a destination
      Handler: index.handler
      Runtime: python2.7
      Role: !GetAtt 'CopyZipsRole.Arn'
      Timeout: 240
      Code:
        ZipFile: |
          import json
          import logging
          import threading
          import boto3
          import cfnresponse


          def copy_objects(source_bucket, dest_bucket, prefix, objects):
              s3 = boto3.client('s3')
              for o in objects:
                  key = prefix + o
                  copy_source = {
                      'Bucket': source_bucket,
                      'Key': key
                  }
                  print('copy_source: %s' % copy_source)
                  print('dest_bucket = %s'%dest_bucket)
                  print('key = %s' %key)
                  s3.copy_object(CopySource=copy_source, Bucket=dest_bucket,
                        Key=key)


          def delete_objects(bucket, prefix, objects):
              s3 = boto3.client('s3')
              objects = {'Objects': [{'Key': prefix + o} for o in objects]}
              s3.delete_objects(Bucket=bucket, Delete=objects)


          def timeout(event, context):
              logging.error('Execution is about to time out, sending failure response to CloudFormation')
              cfnresponse.send(event, context, cfnresponse.FAILED, {}, None)


          def handler(event, context):
              # make sure we send a failure to CloudFormation if the function
              # is going to timeout
              timer = threading.Timer((context.get_remaining_time_in_millis()
                        / 1000.00) - 0.5, timeout, args=[event, context])
              timer.start()

              print('Received event: %s' % json.dumps(event))
              status = cfnresponse.SUCCESS
              try:
                  source_bucket = event['ResourceProperties']['SourceBucket']
                  dest_bucket = event['ResourceProperties']['DestBucket']
                  prefix = event['ResourceProperties']['Prefix']
                  objects = event['ResourceProperties']['Objects']
                  if event['RequestType'] == 'Delete':
                      delete_objects(dest_bucket, prefix, objects)
                  else:
                      copy_objects(source_bucket, dest_bucket, prefix, objects)
              except Exception as e:
                  logging.error('Exception: %s' % e, exc_info=True)
                  status = cfnresponse.FAILED
              finally:
                  timer.cancel()
                  cfnresponse.send(event, context, status, {}, None)

  CFNDocS3AccessPolicy:
    Condition: TemplatesBucketCondition
    Type: AWS::IAM::ManagedPolicy
    Properties:
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Action:
              - 's3:ListBucket'
            Resource:
              - !Sub 'arn:aws:s3:::${TemplatesBucket}'
            Effect: Allow
          - Action:
              - 's3:GetObject'
            Resource:
              - !Sub 'arn:aws:s3:::${TemplatesBucket}/*'
            Effect: Allow

  CFDocGenRole:
    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'
        - !If
          - TemplatesBucketCondition
          - !Ref CFNDocS3AccessPolicy
          - !Ref 'AWS::NoValue'

  CFNDocApiGatewayCloudWatchLogsRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - apigateway.amazonaws.com
            Action:
              - sts:AssumeRole
      ManagedPolicyArns:
          - 'arn:aws:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs'

  CFDocGenerator:
    DependsOn: CopyZips
    Type: 'AWS::Serverless::Function'
    Properties:
      Handler: table-generator-lambda.lambda_handler
      Runtime: python3.6
      CodeUri:
        Bucket: !Ref LambdaZipsBucket
        Key:
          Fn::Sub: '${QSS3KeyPrefix}functions/packages/cfn-table-generator-lambda.zip'
      Description: Generate HTML Documentation from CloudFormation template
      MemorySize: 128
      Timeout: 180
      Role: !GetAtt 'CFDocGenRole.Arn'

  CFDocGeneratorApi:
    DependsOn: CFDocGenerator
    Type: 'AWS::Serverless::Api'
    Properties:
      StageName: prod
      DefinitionBody:
        'Fn::Transform':
          Name: 'AWS::Include'
          Parameters:
            Location: s3://aws-cfn-samples/quickstart-cfn-param-table-generator/templates/cfn-doc-api-swagger-apigw.yaml

  ConfigLambdaPermission:
    Type: "AWS::Lambda::Permission"
    DependsOn:
    - CFDocGenerator
    Properties:
      Action: lambda:InvokeFunction
      FunctionName: !Ref CFDocGenerator
      Principal: apigateway.amazonaws.com

Outputs:
  CFDocGenerator:
    Description: CloudFormation table generator function.
    Value: !Ref CFDocGenerator

  CFDocGeneratorApi:
    Description: CloudFormation table generator API name.
    Value: !Ref CFDocGeneratorApi

  CFDocGeneratorApiEndpoint:
    Description: CloudFormation table generator API URL, supply a valid template url at the end.
    Value: !Sub https://${CFDocGeneratorApi}.execute-api.${AWS::Region}.amazonaws.com/prod/generate-table?url=REPLACE_WITH_TEMPLATE_URL