AWSTemplateFormatVersion: '2010-09-09'
Description: Sample template that demonstrates setting up Lambda event notification
  for an S3 bucket using a custom resource

Resources:
  TestFunctionRole:
    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: /

  TestEventFunction:
    Type: AWS::Lambda::Function
    Properties:
      Description: Dummy function, simply logs received S3 events
      Handler: index.handler
      Runtime: python2.7
      Role: !GetAtt 'TestFunctionRole.Arn'
      Timeout: 240
      Code:
        ZipFile: |
          import json
          import logging
          logger = logging.getLogger()
          logger.setLevel(logging.DEBUG)

          def handler(event, context):
              logger.info('Received event: %s' % json.dumps(event))

  TestS3BucketEventPermission:
    Type: AWS::Lambda::Permission
    Properties:
      Action: lambda:invokeFunction
      SourceAccount: !Ref 'AWS::AccountId'
      FunctionName: !Ref 'TestEventFunction'
      SourceArn: !GetAtt
        - TestS3Bucket
        - Arn
      Principal: s3.amazonaws.com

  TestS3Bucket:
    Type: AWS::S3::Bucket
    DependsOn: TestEventFunction

  ApplyNotificationFunctionRole:
    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: S3BucketNotificationPolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Sid: AllowBucketNotification
                Effect: Allow
                Action: s3:PutBucketNotification
                Resource:
                  - !Sub 'arn:aws:s3:::${TestS3Bucket}'
                  - !Sub 'arn:aws:s3:::${TestS3Bucket}/*'

  ApplyBucketNotificationFunction:
    Type: AWS::Lambda::Function
    Properties:
      Description: Dummy function, just logs the received event
      Handler: index.handler
      Runtime: python2.7
      Role: !GetAtt 'ApplyNotificationFunctionRole.Arn'
      Timeout: 240
      Code:
        ZipFile: |
          import boto3
          import logging
          import json
          import cfnresponse

          s3Client = boto3.client('s3')
          logger = logging.getLogger()
          logger.setLevel(logging.DEBUG)

          def addBucketNotification(bucketName, notificationId, functionArn):
            notificationResponse = s3Client.put_bucket_notification_configuration(
              Bucket=bucketName,
              NotificationConfiguration={
                'LambdaFunctionConfigurations': [
                  {
                    'Id': notificationId,
                    'LambdaFunctionArn': functionArn,
                    'Events': [
                      's3:ObjectCreated:*'
                    ]
                  },
                ]
              }
            )
            return notificationResponse

          def create(properties, physical_id):
            bucketName = properties['S3Bucket']
            notificationId = properties['NotificationId']
            functionArn = properties['FunctionARN']
            response = addBucketNotification(bucketName, notificationId, functionArn)
            logger.info('AddBucketNotification response: %s' % json.dumps(response))
            return cfnresponse.SUCCESS, physical_id

          def update(properties, physical_id):
            return cfnresponse.SUCCESS, None

          def delete(properties, physical_id):
            return cfnresponse.SUCCESS, None

          def handler(event, context):
            logger.info('Received event: %s' % json.dumps(event))

            status = cfnresponse.FAILED
            new_physical_id = None

            try:
              properties = event.get('ResourceProperties')
              physical_id = event.get('PhysicalResourceId')

              status, new_physical_id = {
                'Create': create,
                'Update': update,
                'Delete': delete
              }.get(event['RequestType'], lambda x, y: (cfnresponse.FAILED, None))(properties, physical_id)
            except Exception as e:
              logger.error('Exception: %s' % e)
              status = cfnresponse.FAILED
            finally:
              cfnresponse.send(event, context, status, {}, new_physical_id)

  ApplyNotification:
    Type: Custom::ApplyNotification
    Properties:
      ServiceToken: !GetAtt 'ApplyBucketNotificationFunction.Arn'
      S3Bucket: !Ref 'TestS3Bucket'
      FunctionARN: !GetAtt 'TestEventFunction.Arn'
      NotificationId: S3ObjectCreatedEvent

