in src/main/java/com/aws/pattern/cicd/CicdBlueGreenStack.java [50:262]
public CicdBlueGreenStack(final App scope, final String id, final StackProps props, EcsInfrastructureStack ecsInfraStack) {
super(scope, id, props);
// *******************************************//
// ************CodeCommit repo****************//
// *******************************************//
// Checkout repo
String repoName = (String) scope.getNode().tryGetContext("repo_name");
IRepository code = Repository.fromRepositoryName(this, "MyRepo", repoName);
// *******************************************//
// ************CodeBuild**********************//
// *******************************************//
// CodeBuild service role
RoleProps rolePropsCodeBuildServiceRole = RoleProps.builder()
.assumedBy(new ServicePrincipal("codebuild.amazonaws.com"))
.build();
Role codeBuildServiceRole = new Role(this, "codeBuildServiceRole", rolePropsCodeBuildServiceRole);
codeBuildServiceRole.addManagedPolicy(ManagedPolicy.fromAwsManagedPolicyName("AWSCodeDeployRoleForECS"));
PolicyStatementProps codeBuildPolicyStatementProps = PolicyStatementProps.builder()
.effect(Effect.ALLOW)
.resources(Arrays.asList("*"))
.actions(Arrays.asList("ecr:GetAuthorizationToken",
"ecr:BatchCheckLayerAvailability",
"ecr:InitiateLayerUpload",
"ecr:UploadLayerPart",
"ecr:CompleteLayerUpload",
"ecr:PutImage"))
.build();
PolicyStatement codeBuildInlinePolicyStatement = new PolicyStatement(codeBuildPolicyStatementProps);
codeBuildServiceRole.addToPolicy(codeBuildInlinePolicyStatement);
PipelineProject dockerApiImageBuild = PipelineProject.Builder.create(this, "CDKSampleBuild")
.buildSpec(BuildSpec.fromObject(new HashMap<String, Object>() {
{
put("version", "0.2");
put("phases", new HashMap<String, Object>() {
{
put("install", new HashMap<String, Object>() {
{
put("commands",
Arrays.asList("apt update",
"yes Y | apt install amazon-ecr-credential-helper"));
}
});
put("build", new HashMap<String, Object>() {
{
put("commands", Arrays.asList("mvn compile jib:build"));
}
});
}
});
put("artifacts", new HashMap<String, Object>() {
{
put("files", Arrays.asList("imagedefinitions.json", "imageDetail.json", "appspec.yaml",
"taskdef.json"));
}
});
}
})).environment(BuildEnvironment.builder().buildImage(LinuxBuildImage.STANDARD_5_0).build())
.role(codeBuildServiceRole)
.projectName("CodeBuildProject").build();
Artifact sourceOutput = new Artifact();
Artifact imageArtifact = new Artifact();
// *******************************************//
// ************CodeDeploy*********************//
// *******************************************//
// CodeDeploy Application
EcsApplication ecsApplication = new EcsApplication(this, "mySampleApp");
// CodeDeploy service role
RoleProps rolePropsCodeDeployServiceRole = RoleProps.builder()
.assumedBy(new ServicePrincipal("codedeploy.amazonaws.com"))
.build();
Role codeDeployServiceRole = new Role(this, "codeDeployServiceRole", rolePropsCodeDeployServiceRole);
codeDeployServiceRole.addManagedPolicy(ManagedPolicy.fromAwsManagedPolicyName("AWSCodeDeployRoleForECS"));
// IAM role for custom lambda function
PolicyStatementProps policyStatementProps = PolicyStatementProps.builder()
.effect(Effect.ALLOW)
.resources(Arrays.asList("*"))
.actions(Arrays.asList("iam:PassRole",
"sts:AssumeRole",
"codedeploy:List*",
"codedeploy:Get*",
"codedeploy:UpdateDeploymentGroup",
"codedeploy:CreateDeploymentGroup",
"codedeploy:DeleteDeploymentGroup"))
.build();
PolicyStatement inlinePolicyStatementForLambda = new PolicyStatement(policyStatementProps);
RoleProps rolePropsLambdaServiceRole = RoleProps.builder()
.assumedBy(new ServicePrincipal("lambda.amazonaws.com"))
.build();
Role customLambdaServiceRole = new Role(this, "codeDeployCustomLambda", rolePropsLambdaServiceRole);
customLambdaServiceRole.addToPolicy(inlinePolicyStatementForLambda);
customLambdaServiceRole.addManagedPolicy(ManagedPolicy.fromAwsManagedPolicyName("service-role/AWSLambdaBasicExecutionRole"));
// Lambda function to create a custom resource
FunctionProps lambdaProps = FunctionProps.builder()
.runtime(Runtime.PYTHON_3_8)
.handler("create_deployment_group.handler")
.role(customLambdaServiceRole)
.description("Custom resource to create a CodeDeploy deployment group")
.memorySize(128)
.timeout(Duration.seconds(60))
.code(Code.fromAsset("src/main/resources/cdk_custom_resources"))
.build();
Function deploymentGroupLambda = new Function(this, "deploymentGroupLambda", lambdaProps);
Map<String, Object> mapProperties = new HashMap<>();
mapProperties.put("ApplicationName", ecsApplication.getApplicationName());
mapProperties.put("DeploymentGroupName", ECS_DEPLOYMENT_GROUP_NAME);
mapProperties.put("DeploymentConfigName", ECS_DEPLOYMENT_CONFIG_NAME);
mapProperties.put("ServiceRoleArn", codeDeployServiceRole.getRoleArn());
mapProperties.put("BlueTargetGroup", ecsInfraStack.blueTargetGroup.getTargetGroupName());
mapProperties.put("GreenTargetGroup", ecsInfraStack.greenTargetGroup.getTargetGroupName());
mapProperties.put("ProdListenerArn", ecsInfraStack.blueWebListener.getListenerArn());
mapProperties.put("TestListenerArn", ecsInfraStack.greenWebListener.getListenerArn());
mapProperties.put("EcsClusterName", EcsInfrastructureStack.ECS_CLUSTER_NAME);
mapProperties.put("EcsServiceName", EcsInfrastructureStack.ECS_SERVICE_NAME);
mapProperties.put("TerminationWaitTime", ECS_TASKSET_TERMINATION_WAIT_TIME);
CustomResourceProps customResourceProp = new CustomResourceProps.Builder()
.serviceToken(deploymentGroupLambda.getFunctionArn())
.properties(mapProperties)
.build();
CustomResource customResource = new CustomResource(this, "customEcsDeploymentGroup", customResourceProp);
// Resource created outside CDK
EcsDeploymentGroupAttributes ecsDeploymentGroupAttributes = EcsDeploymentGroupAttributes.builder()
.application(ecsApplication)
.deploymentGroupName(ECS_DEPLOYMENT_GROUP_NAME)
.deploymentConfig(EcsDeploymentConfig.fromEcsDeploymentConfigName(this, "ecsDeploymentConfig", ECS_DEPLOYMENT_CONFIG_NAME))
.build();
// Resource created outside CDK
IEcsDeploymentGroup EcsDeploymentGroup = software.amazon.awscdk.services.codedeploy.EcsDeploymentGroup
.fromEcsDeploymentGroupAttributes(this, "ecsDeploymentConfig",
ecsDeploymentGroupAttributes);
CodeDeployEcsContainerImageInput codeDeployEcsContainerImageInput = CodeDeployEcsContainerImageInput.builder()
.input(sourceOutput).taskDefinitionPlaceholder("IMAGE_NAME").build();
// *******************************************//
// ************CodePipeline*******************//
// *******************************************//
// CodePipeline service role
RoleProps rolePropsCodePipelineServiceRole = RoleProps.builder()
.assumedBy(new ServicePrincipal("codepipeline.amazonaws.com"))
.build();
Role codePipelineServiceRole = new Role(this, "codePipelineServiceRole", rolePropsCodePipelineServiceRole);
PolicyStatementProps codePipelinePolicyStatementProps = PolicyStatementProps.builder()
.effect(Effect.ALLOW)
.resources(Arrays.asList("*"))
.actions(Arrays.asList("iam:PassRole",
"sts:AssumeRole",
"codecommit:Get*",
"codecommit:List*",
"codecommit:GitPull",
"codecommit:UploadArchive",
"codecommit:CancelUploadArchive",
"codebuild:BatchGetBuilds",
"codebuild:StartBuild",
"codedeploy:CreateDeployment",
"codedeploy:Get*",
"codedeploy:RegisterApplicationRevision"))
.build();
PolicyStatement codePipelineInlinePolicyStatement = new PolicyStatement(codePipelinePolicyStatementProps);
codePipelineServiceRole.addToPolicy(codePipelineInlinePolicyStatement);
Pipeline.Builder.create(this, "MySamplePipeline")
.stages(Arrays.asList(
StageProps.builder().stageName("Source")
.actions(Arrays.asList(CodeCommitSourceAction.Builder.create().actionName("Source")
.branch("main").repository(code).output(sourceOutput).build()))
.build(),
StageProps.builder().stageName("Build")
.actions(Arrays.asList(CodeBuildAction.Builder.create().actionName("Build")
.project(dockerApiImageBuild).input(sourceOutput)
.outputs(Arrays.asList(imageArtifact)).build()))
.build(),
StageProps.builder().stageName("Deploy")
.actions(Arrays.asList(CodeDeployEcsDeployAction.Builder.create()
.actionName("DeployBlueGreenToECS").deploymentGroup(EcsDeploymentGroup)
.taskDefinitionTemplateInput(sourceOutput).appSpecTemplateInput(sourceOutput)
.containerImageInputs(Arrays.asList(codeDeployEcsContainerImageInput)).build()))
.build()))
.role(codePipelineServiceRole)
.build();
}