constructor()

in source/infrastructure/lib/test-task-lambdas.ts [65:366]


    constructor(scope: Construct, id: string, props: TestRunnerLambdasContructProps) {
        super(scope, id);

        const lambdaResultsRole = new Role(this, 'LambdaResultsRole', {
            assumedBy: new ServicePrincipal('lambda.amazonaws.com')
        });
        const cfnPolicy = new Policy(this, 'LambdaResultsPolicy', {
            statements: [
                new PolicyStatement({
                    resources: ['*'],
                    actions: ['cloudwatch:GetMetricWidgetImage']
                })
            ]
        });
        lambdaResultsRole.attachInlinePolicy(cfnPolicy);
        lambdaResultsRole.attachInlinePolicy(props.cloudWatchLogsPolicy);
        lambdaResultsRole.attachInlinePolicy(props.dynamoDbPolicy);
        lambdaResultsRole.attachInlinePolicy(props.scenariosS3Policy);

        const resultsRoleResource = lambdaResultsRole.node.defaultChild as CfnResource;
        resultsRoleResource.addMetadata('cfn_nag', {
            rules_to_suppress: [{
                id: 'W12',
                reason: 'The action does not support resource level permissions.'
            }]
        });
        const resultsPolicyResource = cfnPolicy.node.defaultChild as CfnResource;
        resultsPolicyResource.addMetadata('cfn_nag', {
            rules_to_suppress: [{
                id: 'W12',
                reason: 'The action does not support resource level permissions.'
            }]
        });

        this.resultsParser = new LambdaFunction(this, 'ResultsParser', {
            description: 'Result parser for indexing xml test results to DynamoDB',
            handler: 'index.handler',
            role: lambdaResultsRole,
            code: Code.fromBucket(props.sourceCodeBucket, `${props.sourceCodePrefix}/results-parser.zip`),
            runtime: Runtime.NODEJS_14_X,
            timeout: Duration.seconds(120),
            environment: {
                SCENARIOS_BUCKET: props.testScenariosBucket,
                SCENARIOS_TABLE: props.testScenariosTable.tableName,
                SOLUTION_ID: props.solutionId,
                UUID: props.uuid,
                VERSION: props.solutionVersion,
                SEND_METRIC: props.sendAnonymousUsage,
                METRIC_URL: props.metricsUrl
            },
        });
        Tags.of(this.resultsParser).add('SolutionId', props.solutionId);
        const resultsParserResource = this.resultsParser.node.defaultChild as CfnResource;
        resultsParserResource.addMetadata('cfn_nag', {
            rules_to_suppress: [{
                id: 'W58',
                reason: 'CloudWatchLogsPolicy covers a permission to write CloudWatch logs.'
            }, {
                id: 'W89',
                reason: 'This Lambda function does not require a VPC'
            }, {
                id: 'W92',
                reason: 'Does not run concurrent executions'
            },]
        });

        const taskArn = Stack.of(this).formatArn({ service: 'ecs', resource: 'task', sep: '/', resourceName: '*' });
        const taskDefArn = Stack.of(this).formatArn({ service: 'ecs', resource: 'task-definition', resourceName: '*:*' });

        const lambdaTaskRole = new Role(this, 'DLTTestLambdaTaskRole', {
            assumedBy: new ServicePrincipal('lambda.amazonaws.com'),
            inlinePolicies: {
                'TaskLambdaPolicy': new PolicyDocument({
                    statements: [
                        new PolicyStatement({
                            effect: Effect.ALLOW,
                            actions: ['ecs:ListTasks'],
                            resources: ['*']
                        }),
                        new PolicyStatement({
                            effect: Effect.ALLOW,
                            actions: [
                                'ecs:RunTask',
                                'ecs:DescribeTasks'
                            ],
                            resources: [
                                taskArn,
                                taskDefArn
                            ]
                        }),
                        new PolicyStatement({
                            effect: Effect.ALLOW,
                            actions: ['iam:PassRole'],
                            resources: [props.ecsTaskExecutionRoleArn]
                        }),
                        new PolicyStatement({
                            effect: Effect.ALLOW,
                            actions: ['logs:PutMetricFilter'],
                            resources: [props.ecsCloudWatchLogGroup.logGroupArn]
                        }),
                        new PolicyStatement({
                            effect: Effect.ALLOW,
                            actions: ['cloudwatch:PutDashboard'],
                            resources: [
                                `arn:${Aws.PARTITION}:cloudwatch::${Aws.ACCOUNT_ID}:dashboard/EcsLoadTesting*`
                            ]
                        })
                    ]
                })
            }
        });
        lambdaTaskRole.attachInlinePolicy(props.cloudWatchLogsPolicy);
        lambdaTaskRole.attachInlinePolicy(props.dynamoDbPolicy);

        const lambdaTaskRoleResource = lambdaTaskRole.node.defaultChild as CfnResource;
        lambdaTaskRoleResource.addMetadata('cfn_nag', {
            rules_to_suppress: [{
                id: 'W11',
                reason: 'ecs:ListTasks does not support resource level permissions'
            }]
        });

        this.taskRunner = new LambdaFunction(this, 'TaskRunner', {
            description: 'Task runner for ECS task definitions',
            handler: 'index.handler',
            role: lambdaTaskRole,
            code: Code.fromBucket(props.sourceCodeBucket, `${props.sourceCodePrefix}/task-runner.zip`),
            environment: {
                SCENARIOS_BUCKET: props.testScenariosBucket,
                SCENARIOS_TABLE: props.testScenariosTable.tableName,
                TASK_CLUSTER: props.ecsCluster,
                TASK_DEFINITION: props.ecsTaskDefinition,
                TASK_SECURITY_GROUP: props.ecsTaskSecurityGroup,
                TASK_IMAGE: `${Aws.STACK_NAME}-load-tester`,
                SUBNET_A: props.subnetA,
                SUBNET_B: props.subnetB,
                API_INTERVAL: '10',
                ECS_LOG_GROUP: props.ecsCloudWatchLogGroup.logGroupName,
                SOLUTION_ID: props.solutionId,
                VERSION: props.solutionVersion
            },
            runtime: Runtime.NODEJS_14_X,
            timeout: Duration.seconds(900)
        });
        Tags.of(this.taskRunner).add('SolutionId', props.solutionId);
        const taskRunnerResource = this.taskRunner.node.defaultChild as CfnResource;
        taskRunnerResource.addMetadata('cfn_nag', {
            rules_to_suppress: [{
                id: 'W58',
                reason: 'CloudWatchLogsPolicy covers a permission to write CloudWatch logs.'
            }, {
                id: 'W89',
                reason: 'This Lambda function does not require a VPC'
            }, {
                id: 'W92',
                reason: 'Does not run concurrent executions'
            }]
        });

        const taskCancelerRole = new Role(this, 'LambdaTaskCancelerRole', {
            assumedBy: new ServicePrincipal('lambda.amazonaws.com'),
            inlinePolicies: {
                'TaskCancelerPolicy': new PolicyDocument({
                    statements: [
                        new PolicyStatement({
                            effect: Effect.ALLOW,
                            actions: ['ecs:ListTasks'],
                            resources: ['*']
                        }),
                        new PolicyStatement({
                            effect: Effect.ALLOW,
                            actions: ['ecs:StopTask'],
                            resources: [
                                taskArn,
                                taskDefArn
                            ]
                        }),
                        new PolicyStatement({
                            effect: Effect.ALLOW,
                            actions: ['dynamodb:UpdateItem'],
                            resources: [props.testScenariosTable.tableArn]
                        })
                    ]
                })
            }
        });
        taskCancelerRole.attachInlinePolicy(props.cloudWatchLogsPolicy);

        const taskCancelerRoleResource = taskCancelerRole.node.defaultChild as CfnResource;
        taskCancelerRoleResource.addMetadata('cfn_nag', {
            rules_to_suppress: [{
                id: 'W11',
                reason: 'ecs:ListTasks does not support resource level permissions'
            }]
        });

        this.taskCanceler = new LambdaFunction(this, 'TaskCanceler', {
            description: 'Stops ECS task',
            handler: 'index.handler',
            role: taskCancelerRole,
            code: Code.fromBucket(props.sourceCodeBucket, `${props.sourceCodePrefix}/task-canceler.zip`),
            runtime: Runtime.NODEJS_14_X,
            timeout: Duration.seconds(300),
            environment: {
                METRIC_URL: props.metricsUrl,
                SOLUTION_ID: props.solutionId,
                VERSION: props.solutionVersion,
                SCENARIOS_TABLE: props.testScenariosTable.tableName,
                TASK_CLUSTER: props.ecsCluster
            }
        });
        Tags.of(this.taskCanceler).add('SolutionId', props.solutionId);
        const taskCancelerResource = this.taskCanceler.node.defaultChild as CfnResource;
        taskCancelerResource.addMetadata('cfn_nag', {
            rules_to_suppress: [{
                id: 'W58',
                reason: 'CloudWatchLogsPolicy covers a permission to write CloudWatch logs.'
            }, {
                id: 'W89',
                reason: 'This Lambda function does not require a VPC'
            }, {
                id: 'W92',
                reason: 'Does not run concurrent executions'
            }]
        });

        this.taskCancelerInvokePolicy = new Policy(this, 'TaskCancelerInvokePolicy', {
            statements: [
                new PolicyStatement({
                    effect: Effect.ALLOW,
                    actions: ['lambda:InvokeFunction'],
                    resources: [this.taskCanceler.functionArn]
                })
            ]
        })

        const taskStatusCheckerRole = new Role(this, 'TaskStatusRole', {
            assumedBy: new ServicePrincipal('lambda.amazonaws.com'),
            inlinePolicies: {
                'TaskStatusPolicy': new PolicyDocument({
                    statements: [
                        new PolicyStatement({
                            effect: Effect.ALLOW,
                            actions: ['ecs:ListTasks'],
                            resources: ['*']
                        }),
                        new PolicyStatement({
                            effect: Effect.ALLOW,
                            actions: ['ecs:DescribeTasks'],
                            resources: [
                                taskArn
                            ]
                        })
                    ]
                })
            }
        });
        taskStatusCheckerRole.attachInlinePolicy(props.cloudWatchLogsPolicy);
        taskStatusCheckerRole.attachInlinePolicy(this.taskCancelerInvokePolicy);
        taskStatusCheckerRole.attachInlinePolicy(props.dynamoDbPolicy);

        const taskStatusCheckerRoleResource = taskStatusCheckerRole.node.defaultChild as CfnResource;
        taskStatusCheckerRoleResource.addMetadata('cfn_nag', {
            rules_to_suppress: [{
                id: 'W11',
                reason: 'ecs:ListTasks does not support resource level permissions'
            }, {
                id: 'W58',
                reason: 'CloudWatchLogsPolicy covers a permission to write CloudWatch logs.'
            }]
        });

        this.taskStatusChecker = new LambdaFunction(this, 'TaskStatusChecker', {
            description: 'Task status checker',
            handler: 'index.handler',
            role: taskStatusCheckerRole,
            code: Code.fromBucket(props.sourceCodeBucket, `${props.sourceCodePrefix}/task-status-checker.zip`),
            runtime: Runtime.NODEJS_14_X,
            timeout: Duration.seconds(180),
            environment: {
                TASK_CLUSTER: props.ecsCluster,
                SCENARIOS_TABLE: props.testScenariosTable.tableName,
                TASK_CANCELER_ARN: this.taskCanceler.functionArn,
                SOLUTION_ID: props.solutionId,
                VERSION: props.solutionVersion
            }
        });
        Tags.of(this.taskStatusChecker).add('SolutionId', props.solutionId);
        const taskStatusCheckerResource = this.taskStatusChecker.node.defaultChild as CfnResource;
        taskStatusCheckerResource.addMetadata('cfn_nag', {
            rules_to_suppress: [{
                id: 'W58',
                reason: 'CloudWatchLogsPolicy covers a permission to write CloudWatch logs.'
            }, {
                id: 'W89',
                reason: 'This Lambda function does not require a VPC'
            }, {
                id: 'W92',
                reason: 'Does not run concurrent executions'
            },]
        });
    }