public ECSTaskSubmissionFromLambdaPattern()

in amazon-ecs-java-starter-kit-cdk/src/main/java/software/aws/ecs/java/starterkit/cdk/ECSTaskSubmissionFromLambdaPattern.java [68:266]


    public ECSTaskSubmissionFromLambdaPattern(final Construct scope, final String id, final StackProps props) {
        super(scope, id, props);

        SubnetSelection privateSubnets = SubnetSelection.builder().subnetType(SubnetType.PRIVATE).build();
        // VPC
        Vpc vpc = Vpc.Builder.create(this, "StarterKitVPC").cidr("10.110.0.0/16").maxAzs(2)
                .gatewayEndpoints(new HashMap<String, GatewayVpcEndpointOptions>() {
                    private static final long serialVersionUID = -2650622903964203923L;
                    {
                        put("S3EndPoint", GatewayVpcEndpointOptions.builder().service(GatewayVpcEndpointAwsService.S3)
                                .subnets(new ArrayList<SubnetSelection>() {
                                    private static final long serialVersionUID = 1687752884565877349L;
                                    {
                                        add(privateSubnets);
                                    }
                                }).build());
                        put("DDBEndPoint",
                                GatewayVpcEndpointOptions.builder().service(GatewayVpcEndpointAwsService.DYNAMODB)
                                        .subnets(new ArrayList<SubnetSelection>() {
                                            private static final long serialVersionUID = -746781466183802042L;
                                            {
                                                add(privateSubnets);
                                            }
                                        }).build());
                    }
                }).build();
        vpc.addInterfaceEndpoint("ECSEndPoint", InterfaceVpcEndpointOptions.builder()
                .service(InterfaceVpcEndpointAwsService.ECS).subnets(privateSubnets).build());
        vpc.addInterfaceEndpoint("ECSAgentEndPoint", InterfaceVpcEndpointOptions.builder()
                .service(InterfaceVpcEndpointAwsService.ECS_AGENT).subnets(privateSubnets).build());
        vpc.addInterfaceEndpoint("ECREndPoint", InterfaceVpcEndpointOptions.builder()
                .service(InterfaceVpcEndpointAwsService.ECR).subnets(privateSubnets).build());

        // S3 Bucket
        Bucket s3Bucket = Bucket.Builder.create(this, "S3Bucket")
                .bucketName(this.getAccount() + "-amazon-ecs-java-starter-kit-pattern-1-bucket")
                .blockPublicAccess(BlockPublicAccess.Builder.create()
                        .blockPublicAcls(true)
                        .blockPublicPolicy(true)
                        .ignorePublicAcls(true)
                        .restrictPublicBuckets(true)
                        .build())
                .removalPolicy(RemovalPolicy.DESTROY)
                .build();

        // DynamoDB Tables
        String workflowSummaryPartitionKeyName = "workflow_name";
        String workflowSummarySortKeyName = "workflow_run_id";
        Table workflow_summary = Table.Builder.create(this, "DDBWorkFlowSummary").tableName("workflow_summary_pattern_1")
                .removalPolicy(RemovalPolicy.DESTROY)
                .partitionKey(
                        Attribute.builder().name(workflowSummaryPartitionKeyName).type(AttributeType.STRING).build())
                .sortKey(Attribute.builder().name(workflowSummarySortKeyName).type(AttributeType.NUMBER).build())
                .build();

        String workflowDetailsPartitionKeyName = "workflow_run_id";
        String workflowDetailsSortKeyName = "ecs_task_id";
        Table workflow_details = Table.Builder.create(this, "DDBWorkFlowDetails").tableName("workflow_details_pattern_1")
                .removalPolicy(RemovalPolicy.DESTROY)
                .partitionKey(
                        Attribute.builder().name(workflowDetailsPartitionKeyName).type(AttributeType.NUMBER).build())
                .sortKey(Attribute.builder().name(workflowDetailsSortKeyName).type(AttributeType.STRING).build())
                .build();

        // ECS Cluster
        Cluster cluster = Cluster.Builder.create(this, "StarterKitCluster").clusterName("amazon-ecs-java-starter-kit-pattern-1")
                .vpc(vpc).build();

        // ECR Image
        String ecrRepoName = "amazon-ecs-java-starter-kit-pattern-1";
        @SuppressWarnings("deprecation")
        DockerImageAsset dockerImageAsset = DockerImageAsset.Builder.create(this, "StarterKitECRImage")
                .directory("../amazon-ecs-java-starter-kit-task").repositoryName(ecrRepoName).build();

        // Fargate Task Definition
        FargateTaskDefinition fargateTaskDefinition = FargateTaskDefinition.Builder
                .create(this, "StarterKitFargateTaskDefinition").family("amazon-ecs-java-starter-kit-pattern-1").cpu(1024)
                .memoryLimitMiB(2048).build();

        // Container Definition
        ContainerDefinition containerDefinition = ContainerDefinition.Builder
                .create(this, "amazon-ecs-java-starter-kit").taskDefinition(fargateTaskDefinition).essential(true)
                .image(ContainerImage.fromDockerImageAsset(dockerImageAsset))
                .logging(AwsLogDriver.awsLogs(AwsLogDriverProps.builder()
                        .logGroup(LogGroup.Builder.create(this, "ECSLogGroup")
                                .logGroupName("/ecs/amazon-ecs-java-starter-kit-pattern-1").removalPolicy(RemovalPolicy.DESTROY)
                                .retention(RetentionDays.ONE_DAY).build())
                        .streamPrefix("amazon-ecs-java-starter-kit").build()))
                .build();

        // Container IAM permissions
        workflow_details.grantReadWriteData(fargateTaskDefinition.getTaskRole());
        s3Bucket.grantReadWrite(fargateTaskDefinition.getTaskRole());

        // TaskLauncher Lambda
        Function taskLauncher = Function.Builder.create(this, "TaskLauncherLambda")
                .functionName("amazon-ecs-java-starter-kit-pattern-1-ecs-task-launcher")
                .code(Code.fromAsset(
                        "../amazon-ecs-java-starter-kit-tasklauncher/target/amazon-ecs-java-starter-kit-tasklauncher-1.0.jar"))
                .handler("software.aws.ecs.java.starterkit.launcher.ECSTaskLauncher").runtime(Runtime.JAVA_8_CORRETTO)
                .timeout(Duration.minutes(5)).memorySize(256).logRetention(RetentionDays.ONE_DAY).vpc(vpc)
                .vpcSubnets(privateSubnets)
                .securityGroups(Collections.singletonList(SecurityGroup.Builder.create(this, "TaskLauncherSG").vpc(vpc)
                        .securityGroupName("amazon-ecs-java-starter-kit-pattern-1-ecs-task-launcher").allowAllOutbound(true)
                        .build()))
                .build();

        // Permissions to run ECS Task
        taskLauncher.getRole().addToPrincipalPolicy(PolicyStatement.Builder.create()
                .actions(Collections.singletonList("ecs:RunTask")).resources(new ArrayList<String>() {
                    private static final long serialVersionUID = 1133379137898541366L;

                    {
                        add(fargateTaskDefinition.getTaskDefinitionArn());
                        add(cluster.getClusterArn());
                    }
                }).build());
        taskLauncher.getRole().addToPrincipalPolicy(PolicyStatement.Builder.create()
                .actions(Collections.singletonList("iam:PassRole")).resources(new ArrayList<String>() {
                    private static final long serialVersionUID = 306435034815975097L;

                    {
                        add(fargateTaskDefinition.getTaskRole().getRoleArn());
                        add(fargateTaskDefinition.getExecutionRole().getRoleArn());
                    }
                }).build());

        // TaskMonitor Lambda
        Function taskMonitor = Function.Builder.create(this, "TaskMonitorLambda")
                .functionName("amazon-ecs-java-starter-kit-pattern-1-ecs-task-monitor")
                .code(Code.fromAsset(
                        "../amazon-ecs-java-starter-kit-taskmonitor/target/amazon-ecs-java-starter-kit-taskmonitor-1.0.jar"))
                .handler("software.aws.ecs.java.starterkit.monitor.ECSTaskMonitor").runtime(Runtime.JAVA_8_CORRETTO)
                .timeout(Duration.minutes(5)).memorySize(256).logRetention(RetentionDays.ONE_DAY).vpc(vpc)
                .vpcSubnets(privateSubnets)
                .securityGroups(Collections.singletonList(SecurityGroup.Builder.create(this, "TaskMonitorSG").vpc(vpc)
                        .securityGroupName("amazon-ecs-java-starter-kit-pattern-1-ecs-task-Monitor").allowAllOutbound(true)
                        .build()))
                .environment(new HashMap<String, String>() {
                    private static final long serialVersionUID = -8778366953471384771L;
                    {
                        put("region", getRegion());
                        put("workflow_summary_ddb_table_name", workflow_summary.getTableName());
                        put("workflow_summary_hash_key", workflowSummaryPartitionKeyName);
                        put("workflow_summary_range_key", workflowSummarySortKeyName);
                        put("workflow_details_ddb_table_name", workflow_details.getTableName());
                        put("workflow_details_hash_key", workflowDetailsPartitionKeyName);
                        put("workflow_details_range_key", workflowDetailsSortKeyName);
                    }
                }).build();

        // IAM permissions for Lambdas
        workflow_details.grantReadWriteData(taskLauncher.getRole());
        workflow_details.grantReadWriteData(taskMonitor.getRole());
        workflow_summary.grantReadWriteData(taskLauncher.getRole());
        workflow_summary.grantReadWriteData(taskMonitor.getRole());

        // Monitor State in StateMachine
        LambdaInvoke invokeMonitorState = LambdaInvoke.Builder.create(this, "InvokeTaskMonitor")
                .payloadResponseOnly(true).lambdaFunction(taskMonitor)
                .payload(TaskInput.fromObject(new HashMap<String, String>() {
                    private static final long serialVersionUID = -4995384961752093935L;
                    {
                        put("iterator.$", "$.iterator");
                    }
                })).resultPath("$.iterator").payloadResponseOnly(true).build();

        // StateMachine
        StateMachine.Builder.create(this, "amazon-ecs-java-starter-kit-state-machine")
                .stateMachineName("amazon-ecs-java-starter-kit-pattern-1").stateMachineType(StateMachineType.STANDARD)
                .definition(Chain
                        .start(LambdaInvoke.Builder.create(this, "InvokeTaskLauncher").lambdaFunction(taskLauncher)
                                .resultPath("$.iterator").payloadResponseOnly(true).build())
                        .next(invokeMonitorState)
                        .next(Choice.Builder.create(this, "CheckIfTasksCompleted").build().when(
                                Condition.booleanEquals("$.iterator.continue", true),
                                Wait.Builder.create(this, "WaitForECS").time(WaitTime.duration(Duration.seconds(120)))
                                        .build().next(invokeMonitorState))
                                .otherwise(Succeed.Builder.create(this, "Done").build())))
                .build();

        // Outputs
        CfnOutput.Builder.create(this, "region").value(this.getRegion()).build();
        CfnOutput.Builder.create(this, "clusterName").value(cluster.getClusterName()).build();
        CfnOutput.Builder.create(this, "containerName").value(containerDefinition.getContainerName()).build();
        CfnOutput.Builder.create(this, "taskDefinition")
                .value(Fn.select(1, Fn.split("/", fargateTaskDefinition.getTaskDefinitionArn()))).build();
        CfnOutput.Builder.create(this, "securityGroupId").value(vpc.getVpcDefaultSecurityGroup()).build();
        CfnOutput.Builder.create(this, "subnetIdLiteral").value(vpc.getPrivateSubnets().get(0).getSubnetId()).build();
        CfnOutput.Builder.create(this, "ddbTableNameWFSummary").value(workflow_summary.getTableName()).build();
        CfnOutput.Builder.create(this, "hashKeyWFSummary").value(workflowSummaryPartitionKeyName).build();
        CfnOutput.Builder.create(this, "rangeKeyWFSummary").value(workflowSummarySortKeyName).build();
        CfnOutput.Builder.create(this, "ddbTableNameWFDetails").value(workflow_details.getTableName()).build();
        CfnOutput.Builder.create(this, "hashKeyWFDetails").value(workflowDetailsPartitionKeyName).build();
        CfnOutput.Builder.create(this, "rangeKeyWFDetails").value(workflowDetailsSortKeyName).build();
        CfnOutput.Builder.create(this, "s3BucketName").value(s3Bucket.getBucketName()).build();
        CfnOutput.Builder.create(this, "workflowName").value("amazon_ecs_starter_kit-pattern-1").build();
        CfnOutput.Builder.create(this, "separator").value("$").build();
    }