{"AWSTemplateFormatVersion":"2010-09-09","Transform":"AWS::Serverless-2016-10-31","Description":"Defines an AWS Step Functions state machine, together with the Lambda functions used as tasks when the state machine runs. See state-machine.json for the actual machine definition.","Parameters":{"TablePhoto":{"Type":"AWS::SSM::Parameter::Value","Default":"/ImageRecognition/AppOptions/TablePhoto"},"Stage":{"Type":"String","Description":"Environment stage or git branch","Default":"Development"}},"Resources":{"TransformMetadataFunction":{"Type":"AWS::Lambda::Function","Description":"massages JSON of extracted image metadata","Properties":{"PackageType":"Image","Role":{"Fn::GetAtt":["LambdaRole","Arn"]},"ImageConfig":{"Command":["transform-metadata::transform_metadata.Function::FunctionHandler"]},"MemorySize":256,"Timeout":60,"Code":{"ImageUri":"882525684088.dkr.ecr.us-east-1.amazonaws.com/transform-metadata:transformmetadatafunction-4719365be9f7-latest"}},"Metadata":{"Dockerfile":"Dockerfile","DockerContext":".","DockerTag":""}},"ExtractImageMetadataFunction":{"Type":"AWS::Lambda::Function","Description":"Extract image metadata such as format, size, geolocation, etc.","Properties":{"PackageType":"Image","ImageConfig":{"Command":["extract-image-metadata::extract_image_metadata.Function::FunctionHandler"]},"Role":{"Fn::GetAtt":["LambdaRole","Arn"]},"MemorySize":1024,"Timeout":200,"Code":{"ImageUri":"882525684088.dkr.ecr.us-east-1.amazonaws.com/extract-image-metadata:extractimagemetadatafunction-7ed058596f85-latest"}},"Metadata":{"Dockerfile":"Dockerfile","DockerContext":".","DockerTag":""}},"StoreImageMetadataFunction":{"Type":"AWS::Lambda::Function","Description":"Store image metadata into database","Properties":{"PackageType":"Image","ImageConfig":{"Command":["store-image-metadata::store_image_metadata.Function::FunctionHandler"]},"Role":{"Fn::GetAtt":["StoreMetaDataFunctionRole","Arn"]},"MemorySize":512,"Code":{"ImageUri":"882525684088.dkr.ecr.us-east-1.amazonaws.com/store-image-metadata:storeimagemetadatafunction-01aee501fc8a-latest"},"Environment":{"Variables":{"PHOTO_TABLE":{"Ref":"TablePhoto"}}}},"Metadata":{"Dockerfile":"Dockerfile","DockerContext":".","DockerTag":""}},"RekognitionFunction":{"Type":"AWS::Lambda::Function","Description":"Use Amazon Rekognition to detect labels from image","Properties":{"PackageType":"Image","ImageConfig":{"Command":["rekognition::rekognition.Function::FunctionHandler"]},"Role":{"Fn::GetAtt":["RekognitionFunctionRole","Arn"]},"MemorySize":256,"Code":{"ImageUri":"882525684088.dkr.ecr.us-east-1.amazonaws.com/rekognition:rekognitionfunction-93fed31e52bb-latest"}},"Metadata":{"Dockerfile":"Dockerfile","DockerContext":".","DockerTag":""}},"GenerateThumbnailFunction":{"Type":"AWS::Lambda::Function","Description":"Generate thumbnails for images","Properties":{"PackageType":"Image","ImageConfig":{"Command":["thumbnail::thumbnail.Function::FunctionHandler"]},"Role":{"Fn::GetAtt":["LambdaRole","Arn"]},"MemorySize":1536,"Timeout":300,"Code":{"ImageUri":"882525684088.dkr.ecr.us-east-1.amazonaws.com/thumbnail:generatethumbnailfunction-723a6dcd8f50-latest"}},"Metadata":{"Dockerfile":"Dockerfile","DockerContext":".","DockerTag":""}},"StateMachine":{"Type":"AWS::StepFunctions::StateMachine","Description":"","Properties":{"RoleArn":{"Fn::GetAtt":["StateMachineRole","Arn"]},"DefinitionString":{"Fn::Sub":"{\r\n \"Comment\": \"Image Processing workflow\",\r\n \"StartAt\": \"ExtractImageMetadata\",\r\n \"States\": {\r\n \"ExtractImageMetadata\": {\r\n \"Type\": \"Task\",\r\n \"Resource\": \"${ExtractImageMetadataFunction.Arn}\",\r\n \"InputPath\": \"$\",\r\n \"ResultPath\": \"$.extractedMetadata\",\r\n \"Next\": \"ImageTypeCheck\",\r\n \"Catch\": [\r\n {\r\n \"ErrorEquals\": [\r\n \"ImageIdentifyError\"\r\n ],\r\n \"Next\": \"NotSupportedImageType\"\r\n }\r\n ],\r\n \"Retry\": [\r\n {\r\n \"ErrorEquals\": [\r\n \"ImageIdentifyError\"\r\n ],\r\n \"MaxAttempts\": 0\r\n },\r\n {\r\n \"ErrorEquals\": [\r\n \"States.ALL\"\r\n ],\r\n \"IntervalSeconds\": 1,\r\n \"MaxAttempts\": 2,\r\n \"BackoffRate\": 1.5\r\n }\r\n ]\r\n },\r\n \"ImageTypeCheck\": {\r\n \"Type\": \"Choice\",\r\n \"Choices\": [\r\n {\r\n \"Or\": [\r\n {\r\n \"Variable\": \"$.extractedMetadata.format\",\r\n \"StringEquals\": \"JPEG\"\r\n },\r\n {\r\n \"Variable\": \"$.extractedMetadata.format\",\r\n \"StringEquals\": \"PNG\"\r\n }\r\n ],\r\n \"Next\": \"TransformMetadata\"\r\n }\r\n ],\r\n \"Default\": \"NotSupportedImageType\"\r\n },\r\n \"TransformMetadata\": {\r\n \"Type\": \"Task\",\r\n \"Resource\": \"${TransformMetadataFunction.Arn}\",\r\n \"InputPath\": \"$.extractedMetadata\",\r\n \"ResultPath\": \"$.extractedMetadata\",\r\n \"Retry\": [\r\n {\r\n \"ErrorEquals\": [\r\n \"States.ALL\"\r\n ],\r\n \"IntervalSeconds\": 1,\r\n \"MaxAttempts\": 2,\r\n \"BackoffRate\": 1.5\r\n }\r\n ],\r\n \"Next\": \"ParallelProcessing\"\r\n },\r\n \"NotSupportedImageType\": {\r\n \"Type\": \"Fail\",\r\n \"Cause\": \"Image type not supported!\",\r\n \"Error\": \"FileTypeNotSupported\"\r\n },\r\n \"ParallelProcessing\": {\r\n \"Type\": \"Parallel\",\r\n \"Branches\": [\r\n {\r\n \"StartAt\": \"Rekognition\",\r\n \"States\": {\r\n \"Rekognition\": {\r\n \"Type\": \"Task\",\r\n \"Resource\": \"${RekognitionFunction.Arn}\",\r\n \"Retry\": [\r\n {\r\n \"ErrorEquals\": [\r\n \"States.ALL\"\r\n ],\r\n \"IntervalSeconds\": 1,\r\n \"MaxAttempts\": 2,\r\n \"BackoffRate\": 1.5\r\n }\r\n ],\r\n \"End\": true\r\n }\r\n }\r\n },\r\n {\r\n \"StartAt\": \"Thumbnail\",\r\n \"States\": {\r\n \"Thumbnail\": {\r\n \"Type\": \"Task\",\r\n \"Resource\": \"${GenerateThumbnailFunction.Arn}\",\r\n \"Retry\": [\r\n {\r\n \"ErrorEquals\": [\r\n \"States.ALL\"\r\n ],\r\n \"IntervalSeconds\": 1,\r\n \"MaxAttempts\": 2,\r\n \"BackoffRate\": 1.5\r\n }\r\n ],\r\n \"End\": true\r\n }\r\n }\r\n }\r\n ],\r\n \"ResultPath\": \"$.parallelResults\",\r\n \"Next\": \"StoreImageMetadata\"\r\n },\r\n \"StoreImageMetadata\": {\r\n \"Type\": \"Task\",\r\n \"Resource\": \"${StoreImageMetadataFunction.Arn}\",\r\n \"InputPath\": \"$\",\r\n \"ResultPath\": \"$.storeResult\",\r\n \"Retry\": [\r\n {\r\n \"ErrorEquals\": [\r\n \"States.ALL\"\r\n ],\r\n \"IntervalSeconds\": 1,\r\n \"MaxAttempts\": 2,\r\n \"BackoffRate\": 1.5\r\n }\r\n ],\r\n \"End\": true\r\n }\r\n }\r\n}"},"StateMachineName":"PhotoProcessingWorkflow-dotnet"}},"RekognitionFunctionRole":{"Type":"AWS::IAM::Role","Description":"","Properties":{"AssumeRolePolicyDocument":{"Version":"2012-10-17","Statement":[{"Action":["sts:AssumeRole"],"Effect":"Allow","Principal":{"Service":["lambda.amazonaws.com"]}}]},"Policies":[{"PolicyName":"StepFunctionLambdaInvoke","PolicyDocument":{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["s3:GetObject","s3:ListBucket","s3:GetBucketLocation","s3:GetObjectVersion","s3:GetLifecycleConfiguration","rekognition:DetectFaces","rekognition:DetectLabels","rekognition:DetectModerationLabels","rekognition:DetectText"],"Resource":"*"}]}}]}},"StoreMetaDataFunctionRole":{"Type":"AWS::IAM::Role","Description":"","Properties":{"AssumeRolePolicyDocument":{"Version":"2012-10-17","Statement":[{"Action":["sts:AssumeRole"],"Effect":"Allow","Principal":{"Service":["lambda.amazonaws.com"]}}]},"ManagedPolicyArns":["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole","arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess","arn:aws:iam::aws:policy/AmazonSSMReadOnlyAccess"]}},"LambdaRole":{"Type":"AWS::IAM::Role","Description":"","Properties":{"AssumeRolePolicyDocument":{"Version":"2012-10-17","Statement":[{"Action":["sts:AssumeRole"],"Effect":"Allow","Principal":{"Service":["lambda.amazonaws.com"]}}]},"ManagedPolicyArns":["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole","arn:aws:iam::aws:policy/AmazonS3FullAccess","arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess"]}},"StateMachineRole":{"Type":"AWS::IAM::Role","Description":"","Properties":{"AssumeRolePolicyDocument":{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":{"Fn::Sub":"states.${AWS::Region}.amazonaws.com"}},"Action":"sts:AssumeRole"}]},"Policies":[{"PolicyName":"StepFunctionLambdaInvoke","PolicyDocument":{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["lambda:InvokeFunction"],"Resource":"*"}]}}]}}}}