{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Transform": "AWS::Serverless-2016-10-31",
    "Description": "Retail Instore Demo Cloud Formation",
    "Parameters": {
      "SourceBucketName": {
        "Type": "String",
        "Default": "retail-instore-demo-source",
        "Description": "Enter the bucket name where the images files will be uploaded for processing"
      },
      "ProcessedBucketName": {
        "Type": "String",
        "Default": "retail-instore-demo-processed",
        "Description": "Enter the bucket name where the processed files will be stored"
      },
      "ArchivedBucketName": {
        "Type": "String",
        "Default": "retail-instore-demo-archives",
        "Description": "Enter the bucket name where the images files will be archived after processing"
      }
    },
    "Resources": {
        "RetailInstoreSourceBucket": {
            "Type": "AWS::S3::Bucket",
            "Properties": {
              "BucketName" : {"Ref" : "SourceBucketName"}
            },
            "Metadata": {
              "Purpose": "Stores the files for processing by Lambda"
            }
        },
        "RetailInstoreProcessedBucket": {
            "Type": "AWS::S3::Bucket",
            "Properties": {
              "BucketName" : {"Ref" : "ProcessedBucketName"}
            },
            "Metadata": {
              "Purpose": "Stores the processed files from Kinesis Firehose Delivery Stream"
            }
        },
        "RetailInstoreArchiveBucket": {
            "Type": "AWS::S3::Bucket",
            "Properties": {
              "BucketName" : {"Ref" : "ArchivedBucketName"}
            },
            "Metadata": {
              "Purpose": "Stores the source files as archive after processing"
            }
        },
        "RetailInstoreExecuteLambdaRole": {
          "Type": "AWS::IAM::Role",
          "Properties": {
            "RoleName": "retail-instore-demo-execute-lambda",
            "AssumeRolePolicyDocument": {
              "Version": "2012-10-17",
              "Statement": [
                {
                  "Effect": "Allow",
                  "Principal": {
                    "Service": "lambda.amazonaws.com"
                  },
                  "Action": "sts:AssumeRole"
                }
              ]
            },
            "Path": "/",
              "Policies": [ {
                 "PolicyName": "retail-instore-demo-lambda-access-policy",
                 "PolicyDocument": {
                    "Version": "2012-10-17",
                    "Statement": [
                      {
                        "Effect": "Allow",
                        "Action": [
                          "s3:ListBucket",
                          "s3:PutObject",
                          "s3:GetObject",
                          "s3:DeleteObject"
                        ],
                        "Resource": [
                          { "Fn::Join" : [ "", [ "arn:aws:s3:::", {"Ref": "SourceBucketName"} ] ] },
                          { "Fn::Join" : [ "", [ "arn:aws:s3:::", {"Ref": "SourceBucketName"} ,"/*"] ] },
                          { "Fn::Join" : [ "", [ "arn:aws:s3:::", {"Ref": "ArchivedBucketName"} ] ] },
                          { "Fn::Join" : [ "", [ "arn:aws:s3:::", {"Ref": "ArchivedBucketName"} ,"/*"] ] }
                        ]
                      },
                      {
                        "Effect": "Allow",
                        "Action": "rekognition:DetectFaces",
                        "Resource": "*"
                      },
                      {
                        "Effect": "Allow",
                        "Action": [
                          "firehose:PutRecord"
                        ],
                        "Resource": "*"
                      },
                      {
                        "Effect": "Allow",
                        "Action": [
                            "logs:CreateLogGroup",
                            "logs:CreateLogStream",
                            "logs:PutLogEvents"
                        ],
                        "Resource": "arn:aws:logs:*:*:*"
                      }
                    ]
                  }
               } ]
          }
        },
        "RetailInstoreLambda": {
            "Type": "AWS::Serverless::Function",
            "Properties": {
                "CodeUri": "s3://retail-instore-analysis/retail-instore-demo-lambda.zip",
                "Handler": "lambda_function.lambda_handler",
                "Runtime": "python3.6",
                "Timeout": 15,
                "Role": {
                    "Fn::GetAtt": [
                        "RetailInstoreExecuteLambdaRole",
                        "Arn"
                    ]
                },
                "Environment": {
                    "Variables": {
                        "firehose_stream": {
                            "Ref": "RetailInstoreFirehoseDeliveryStream"
                        },
                        "s3_archive_bucket": {
                            "Ref": "ArchivedBucketName"
                        }
                    }
                }
            }
        },
        "RetailInstoreLambdaPerm": {
            "Type": "AWS::Lambda::Permission",
            "Properties" : {
              "Action": "lambda:InvokeFunction",
              "FunctionName": {"Ref": "RetailInstoreLambda"},
              "Principal": "s3.amazonaws.com",
              "SourceAccount": {"Ref": "AWS::AccountId"}
            }
          },
        "RetailInstoreSourceBucket": {
            "Type": "AWS::S3::Bucket",
            "Properties": {
              "BucketName" : {"Ref" : "SourceBucketName"},
              "NotificationConfiguration": {
               "LambdaConfigurations": [
                 {
                   "Event" : "s3:ObjectCreated:*",
                   "Function" : { "Fn::GetAtt" : ["RetailInstoreLambda", "Arn"] }
                 }
               ]
             }
            },
            "Metadata": {
              "Purpose": "Notification for S3 Object creation"
            }
        },
        "RetailInstoreFirehoseDeliveryStream": {
          "Type": "AWS::KinesisFirehose::DeliveryStream",
          "Properties": {
            "DeliveryStreamName": "retail-instore-demo-faces",
            "S3DestinationConfiguration": {
              "BucketARN": { "Fn::GetAtt" : ["RetailInstoreProcessedBucket", "Arn"] },
              "BufferingHints" : {
                "IntervalInSeconds" : 60,
                "SizeInMBs" : 1
              },
              "CompressionFormat": "UNCOMPRESSED",
              "RoleARN": {"Fn::GetAtt" : ["RetailInstoreFirehoseDeliveryRole", "Arn"] }
            }
          }
        },
        "RetailInstoreFirehoseDeliveryRole": {
          "Type": "AWS::IAM::Role",
          "Properties": {
            "RoleName": "retail-instore-demo-firehose-delivery-role",
            "AssumeRolePolicyDocument": {
              "Version": "2012-10-17",
              "Statement": [
                {
                  "Sid": "",
                  "Effect": "Allow",
                  "Principal": {
                    "Service": "firehose.amazonaws.com"
                  },
                  "Action": "sts:AssumeRole",
                  "Condition": {
                    "StringEquals": {
                      "sts:ExternalId": {"Ref":"AWS::AccountId"}
                    }
                  }
                }
              ]
            }
          }
        },
        "RetailInstoreFirehoseDeliveryPolicy": {
          "Type": "AWS::IAM::Policy",
          "Properties": {
            "PolicyName": "retail-instore-demo-firehose-delivery-policy",
            "PolicyDocument": {
              "Version": "2012-10-17",
              "Statement": [
                {
                  "Effect": "Allow",
                  "Action": [
                    "s3:AbortMultipartUpload",
                    "s3:GetBucketLocation",
                    "s3:GetObject",
                    "s3:ListBucket",
                    "s3:ListBucketMultipartUploads",
                    "s3:PutObject"
                  ],
                  "Resource": [
                          { "Fn::Join" : [ "", [ "arn:aws:s3:::", {"Ref": "ProcessedBucketName"} ] ] },
                          { "Fn::Join" : [ "", [ "arn:aws:s3:::", {"Ref": "ProcessedBucketName"} ,"/*"] ] }
                        ]
                },
                {
                  "Effect": "Allow",
                  "Action": [
                    "lambda:InvokeFunction",
                    "lambda:GetFunctionConfiguration"
                  ],
                  "Resource": "*"
                },
                {
                  "Effect": "Allow",
                  "Action": [
                    "logs:PutLogEvents"
                  ],
                  "Resource": "arn:aws:logs:*:*:*"
                },
                {
                  "Effect": "Allow",
                  "Action": [
                    "kinesis:DescribeStream",
                    "kinesis:GetShardIterator",
                    "kinesis:GetRecords"
                  ],
                  "Resource": "*"
                }
              ]
            },
            "Roles": [{"Ref": "RetailInstoreFirehoseDeliveryRole"}]
          }
        },
        "RetailInstoreGlueRole": {
          "Type": "AWS::IAM::Role",
          "Properties": {
            "RoleName": "retail-instore-demo-glue-access-role",
            "AssumeRolePolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [
              {
                "Effect": "Allow",
                "Principal": {
                  "Service": "glue.amazonaws.com"
                },
                "Action": "sts:AssumeRole"
              }
            ]
            }
          }
        },
        "RetailInstoreGlueAccessPolicy": {
          "Type": "AWS::IAM::Policy",
          "Properties": {
              "PolicyName": "retail-instore-demo-glue-access-policy",
              "PolicyDocument": {
                "Version": "2012-10-17",
                "Statement": [
                    {
                        "Effect": "Allow",
                        "Action": [
                          "glue:*",
                            "s3:GetObject",
                            "s3:PutObject",
                            "s3:GetBucketLocation",
                            "s3:ListBucket",
                            "s3:ListAllMyBuckets",
                            "s3:GetBucketAcl",
                            "iam:ListRolePolicies",
                            "iam:GetRole",
                            "iam:GetRolePolicy"
                        ],
                        "Resource": "*"
                    },
                    {
                        "Effect": "Allow",
                        "Action": [
                            "logs:CreateLogGroup",
                            "logs:CreateLogStream",
                            "logs:PutLogEvents"
                        ],
                        "Resource": [
                            "arn:aws:logs:*:*:/aws-glue/*"
                          ]
                      }
                    ]
                 },
                 "Roles": [{"Ref": "RetailInstoreGlueRole"}]
              }
        },
        "RetailInstoreGlueDB": {
          "Type": "AWS::Glue::Database",
          "Properties": {
            "DatabaseInput" : {"Name" : "retail-instore-demo-db"},
            "CatalogId" : {"Ref": "AWS::AccountId"}
          }
        },
        "RetailInstoreGlueCrawler": {
          "Type": "AWS::Glue::Crawler",
          "Properties": {
            "Role" : {"Ref": "RetailInstoreGlueRole"},
            "Description": "AWS Glue Crawler creates a table based on the data in S3 bucket",
            "DatabaseName": {"Ref": "RetailInstoreGlueDB"},
            "Targets": {
              "S3Targets": [ {
                "Path": { "Fn::Join" : [ "/", [ "s3:/", {"Ref": "ProcessedBucketName"}, "" ] ] }
              } ]
            },
            "Name": "retail-instore-demo-glue-s3-crawler"
          },
          "DependsOn" : [ 
            "RetailInstoreGlueDB", 
            "RetailInstoreGlueRole", 
            "RetailInstoreProcessedBucket"]
        }
    }
}
