AWSTemplateFormatVersion: 2010-09-09 Description: Build pipeline to build the amazon-kinesis-replay Java application Parameters: ExternalArtifactBucket: Description: Optional. S3 bucket that is used to store the compiled binaries Type: String Release: Description: Github branch or release to be used for the replay application Type: String Default: release-0.1.0 Conditions: UseInternalArtifactBucket: !Equals [!Ref ExternalArtifactBucket, ""] Outputs: ArtifactBucket: Description: Bucket containing the generated jar file Value: !If [UseInternalArtifactBucket, !Ref InternalArtifactBucket, !Ref ExternalArtifactBucket] KinesisReplayCopyCommand: Description: AWS cli command to copy the kinesis replay jar Value: !Sub - aws s3 cp --recursive --exclude '*' --include 'amazon-kinesis-replay-*.jar' 's3://${ArtifactBucket}/' . - { ArtifactBucket: !If [UseInternalArtifactBucket, !Ref InternalArtifactBucket, !Ref ExternalArtifactBucket] } Resources: InternalArtifactBucket: Condition: UseInternalArtifactBucket Type: AWS::S3::Bucket Properties: VersioningConfiguration: Status: Enabled BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: AES256 BuildPipeline: Type: AWS::CodePipeline::Pipeline Properties: RoleArn: !GetAtt CodePipelineServiceRole.Arn Stages: - Name: Source Actions: - Name: KinesisReplayS3SourceAction ActionTypeId: Category: Source Owner: AWS Version: "1" Provider: S3 OutputArtifacts: - Name: KinesisReplaySource Configuration: S3Bucket: !If [UseInternalArtifactBucket, !Ref InternalArtifactBucket, !Ref ExternalArtifactBucket] S3ObjectKey: sources/amazon-kinesis-replay.zip RunOrder: 1 - Name: Build Actions: - Name: BuildKinesisReplay InputArtifacts: - Name: KinesisReplaySource OutputArtifacts: - Name: BuildKinesisReplayOutput ActionTypeId: Category: Build Owner: AWS Version: "1" Provider: CodeBuild Configuration: ProjectName: !Ref KinesisReplayBuildProject RunOrder: 1 - Name: Copy Actions: - Name: CopyKinesisReplay InputArtifacts: - Name: BuildKinesisReplayOutput ActionTypeId: Category: Deploy Owner: AWS Version: "1" Provider: S3 Configuration: BucketName: !If [UseInternalArtifactBucket, !Ref InternalArtifactBucket, !Ref ExternalArtifactBucket] Extract: true RunOrder: 1 - Name: NotifyCloudformation ActionTypeId: Category: Invoke Owner: AWS Version: "1" Provider: Lambda Configuration: FunctionName: !Ref NotifyWaitConditionLambdaFunction RunOrder: 2 ArtifactStore: Type: S3 Location: !If [UseInternalArtifactBucket, !Ref InternalArtifactBucket, !Ref ExternalArtifactBucket] BuildCompleteWaitCondition: Type: AWS::CloudFormation::WaitCondition Properties: Count: 1 Handle: !Ref BuildCompleteWaitHandle Timeout: "900" BuildCompleteWaitHandle: Type: AWS::CloudFormation::WaitConditionHandle KinesisReplayBuildProject: Type: AWS::CodeBuild::Project Properties: ServiceRole: !GetAtt CodeBuildServiceRole.Arn Artifacts: Type: CODEPIPELINE Environment: Type: LINUX_CONTAINER ComputeType: BUILD_GENERAL1_LARGE Image: aws/codebuild/java:openjdk-11 Source: Type: CODEPIPELINE BuildSpec: | version: 0.2 phases: build: commands: - 'cd amazon-kinesis-replay-* || :' - mvn clean package -B artifacts: files: - target/amazon-kinesis-replay-*.jar - amazon-kinesis-replay-*/target/amazon-kinesis-replay-*.jar discard-paths: yes TimeoutInMinutes: 5 DownloadSources: Type: Custom::DownloadSources Properties: ServiceToken: !GetAtt DownloadSourcesFunction.Arn DownloadSourcesFunction: Type: AWS::Lambda::Function Properties: Handler: index.handler Role: !GetAtt LambdaExecutionRole.Arn Code: ZipFile: !Sub - | import boto3 import cfnresponse from urllib.request import urlopen def handler(event, context): s3 = boto3.client('s3') replay_source = urlopen('https://github.com/aws-samples/amazon-kinesis-replay/archive/${Release}.zip') s3.put_object(Bucket='${ArtifactBucket}',Key='sources/amazon-kinesis-replay.zip',Body=replay_source.read()) cfnresponse.send(event, context, cfnresponse.SUCCESS, {}) - { ArtifactBucket: !If [UseInternalArtifactBucket, !Ref InternalArtifactBucket, !Ref ExternalArtifactBucket] } Runtime: python3.7 Timeout: 60 NotifyWaitConditionLambdaFunction: Type: AWS::Lambda::Function Properties: Handler: index.handler Role: !GetAtt LambdaExecutionRole.Arn Code: ZipFile: !Sub | import json import boto3 import urllib.request code_pipeline = boto3.client('codepipeline') def handler(event, context): job_id = event['CodePipeline.job']['id'] url = '${BuildCompleteWaitHandle}' headers = { "Content-Type": "" } data = { "Status": "SUCCESS", "Reason": "Compilation Succeeded", "UniqueId": "KinesisReplayBuildProject", "Data": "Compilation Succeeded" } try: req = urllib.request.Request(url, headers=headers, data=bytes(json.dumps(data), encoding="utf-8"), method='PUT') response = urllib.request.urlopen(req) code_pipeline.put_job_success_result(jobId=job_id) except Exception as e: print("failure: " + str(e)) code_pipeline.put_job_failure_result(jobId=job_id, failureDetails={'message': str(e), 'type': 'JobFailed'}) Runtime: python3.7 Timeout: 10 CodePipelineServiceRole: Type: AWS::IAM::Role Properties: Path: / AssumeRolePolicyDocument: | { "Statement": [{ "Effect": "Allow", "Principal": { "Service": [ "codepipeline.amazonaws.com" ]}, "Action": [ "sts:AssumeRole" ] }] } Policies: - PolicyName: root PolicyDocument: Version: 2012-10-17 Statement: - Resource: - !Sub - arn:aws:s3:::${ArtifactBucket} - { ArtifactBucket: !If [UseInternalArtifactBucket, !Ref InternalArtifactBucket, !Ref ExternalArtifactBucket] } - !Sub - arn:aws:s3:::${ArtifactBucket}/* - { ArtifactBucket: !If [UseInternalArtifactBucket, !Ref InternalArtifactBucket, !Ref ExternalArtifactBucket] } Effect: Allow Action: - s3:PutObject - s3:GetObject - s3:GetObjectVersion - s3:GetBucketVersioning - Resource: !Sub ${KinesisReplayBuildProject.Arn} Effect: Allow Action: - codebuild:StartBuild - codebuild:BatchGetBuilds - Resource: !Sub ${NotifyWaitConditionLambdaFunction.Arn} Effect: Allow Action: - lambda:InvokeFunction - lambda:InvokeAsync CodeBuildServiceRole: Type: AWS::IAM::Role Properties: Path: / AssumeRolePolicyDocument: | { "Statement": [{ "Effect": "Allow", "Principal": { "Service": [ "codebuild.amazonaws.com" ]}, "Action": [ "sts:AssumeRole" ] }] } Policies: - PolicyName: root PolicyDocument: Version: 2012-10-17 Statement: - Resource: - arn:aws:logs:*:*:log-group:/aws/codebuild/* - arn:aws:logs:*:*:log-group:/aws/codebuild/*:log-stream:* Effect: Allow Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents - Resource: - !Sub - arn:aws:s3:::${ArtifactBucket} - { ArtifactBucket: !If [UseInternalArtifactBucket, !Ref InternalArtifactBucket, !Ref ExternalArtifactBucket] } - !Sub - arn:aws:s3:::${ArtifactBucket}/* - { ArtifactBucket: !If [UseInternalArtifactBucket, !Ref InternalArtifactBucket, !Ref ExternalArtifactBucket] } Effect: Allow Action: - s3:GetObject - s3:PutObject - s3:GetObjectVersion - s3:ListBucket LambdaExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole Path: / Policies: - PolicyName: root PolicyDocument: Version: 2012-10-17 Statement: - Resource: "*" Effect: Allow Action: - codepipeline:PutJobSuccessResult - codepipeline:PutJobFailureResult - Resource: - arn:aws:logs:*:*:log-group:/aws/lambda/* - arn:aws:logs:*:*:log-group:/aws/lambda/*:log-stream:* Effect: Allow Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents - Resource: - !Sub - arn:aws:s3:::${ArtifactBucket} - { ArtifactBucket: !If [UseInternalArtifactBucket, !Ref InternalArtifactBucket, !Ref ExternalArtifactBucket] } - !Sub - arn:aws:s3:::${ArtifactBucket}/* - { ArtifactBucket: !If [UseInternalArtifactBucket, !Ref InternalArtifactBucket, !Ref ExternalArtifactBucket] } Effect: Allow Action: - s3:PutObject