UNPKG

@kumologica/builder

Version:

Kumologica build and deploy module

293 lines (257 loc) 7.29 kB
const jsonata = require('jsonata'); const apiTrigger = require('./triggers/api'); const sqsTrigger = require('./triggers/sqs'); class TerraformTemplate { constructor() {} createTemplate(provider, params, flow) { switch (provider) { case "aws": return this.createAWSTemplate(params, flow); break; default: throw new Error (`provider: <${provider}> not supported yet;`); } } /* * Creates cloud formation template file for current lambda: * It is composed of: * - lambda definition * - lambda's role * - lambda's policy * - if event subriptions confirmed then event source mappings for: * - dynamodb stream * - sns * - kinesis * - if flow nodes are provided then * - role added for each downstream aws node * * params: * functionName * zipFileName * roleName * deploymentBucketName * description * runtime * timeout * memory * reservedConcurrency * tracingConfig * roleArn * environment * tags * kmsKeyArn * vpcConfig * deadLetterConfig * fileSystemConfigs */ createAWSTemplate(params, flow) { let ts = new Date(); let template = { terraform: { required_providers: { aws: { source: "hashicorp/aws" } } }, data: { aws_iam_policy_document: {} }, resource: { aws_lambda_function: {}, aws_iam_role: {} }, output: { LambdaArn: { Description: 'The Arn of the cloud action flow lambda.', value: '${aws_lambda_function.lambda.arn}' } } }; let lambda = { function_name: params.functionName, s3_bucket: params.deploymentBucketName, s3_key: params.zipFileName, handler: "lambda.handler", runtime: params.runtime || "nodejs12.x", timeout: params.timeout || 3, memory_size: params.memory || 128, environment: { variables: {} }, tags: { "Kumologica-ts":`${ts.toISOString()}` } }; template.resource.aws_lambda_function.lambda = lambda; template.resource.aws_iam_role.lambda_role = { name: params.roleName, assume_role_policy: { effect: 'Allow', principal: { service: 'lambda.amazonaws.com' }, action: 'sts:AssumeRole' } }; /* Path: '/', Policies: [ { PolicyName: 'AWSLambdaBasicExecutionPolicy', PolicyDocument: { Version: '2012-10-17', Statement: [ { Effect: 'Allow', Action: [ 'logs:CreateLogGroup', 'logs:CreateLogStream', 'logs:PutLogEvents' ], Resource: '*' } ] } } ] } };*/ if (params.description) { lambda.description = params.description; } if (params.tracingConfig) { lambda.tracing_config = { mode: params.tracingConfig.Mode }; } if (params.environment) { lambda.environment.variables = params.environment; } if (params.tags) { //tags = { // Name = "efs_for_lambda" //} lambda.tags = {}; params.tags.forEach(function(tag, index) { lambda.tags[tag.key] = tag.value; }); } if (params.roleArn) { lambda.role = params.roleArn; } if (params.reservedConcurrency) { lambda.reserved_concurrent_executions = params.reservedConcurrency; } if (params.kmsKeyArn) { lambda.kms_key_arn = params.kmsKeyArn; } if (params.vpcConfig) { lambda.vpc_config = { subnet_ids: params.vpcConfig.SubnetIds, security_group_ids: SecurityGroupIds } } if (params.deadLetterConfig) { lambda.dead_letter_config = { target_arn: params.deadLetterConfig.TargetArn }; } if (params.fileSystemConfigs) { params.fileSystemConfigs.forEach(function(c, index) { lambda.file_system_config = { arn: c.Arn, local_mount_path: c.LocalMountPath } }); } if (params.layers) { lambda.layers = [JSON.parse(params.layers)] } // end // adding inbound services permissions, only for dynamodb stream, sqs and kinesis if (params.events) { for (var i = 0; i < params.events.length; i++) { if (['dynamodb', 'sqs', 'kinesis'].includes(params.events[i].source)) { var mappingName = `${params.events[i].source}Mapping${i}`; template.resource[mappingName] = this.eventSourceMapping(params.events[i]); } } } if (params.role) { template.resource.aws_lambda_function.lambda.role = params.role; } else { const AWSCFTemplate = require('./cf'); const cf = new AWSCFTemplate(); const cfTemplate = cf.createCfTemplate(params, flow); let policyStatements = this.convertPolicy(cfTemplate.Resources.LambdaRole.Properties.Policies); if (params.tracingConfig) { policyStatements.push({ effect: 'Allow', actions: [ 'xray:PutTraceSegments', 'xray:PutTelemetryRecords' ], resources: ['*'] }); } template.data.aws_iam_policy_document[`${params.roleName}-policy`] = { statement: policyStatements }; } //template.resource.aws_lambda_function.lambda.role = "${aws_iam_role.lambda_role.arn}"; //if (params.triggers) { // template.Resources = Object.assign(template.Resources, this.handleTriggers(params)); //} return template; } // converts cf policy into tf policy syntax convertPolicy(policies) { let response = []; policies.forEach(function(policy, i) { policy.PolicyDocument.Statement.forEach(function(s, i) { response.push({ actions: s.Action, resources: s.Resource, effect: s.Effect } ) }) }) return response; } // Method iterates through triggers and sets up relevant resources: // event mappings or specific resource artefacts handleTriggers(params) { let resources = {}; for (let i=0; i<params.triggers.length; i++) { switch(Object.keys(params.triggers[i])[0]) { case 'api': resources = Object.assign(resources, apiTrigger.trigger(params.triggers[i].api)); break; case 'sqs': resources = Object.assign(resources, sqsTrigger.trigger(params.functionName, params.triggers[i])); break; } } return resources; } eventSourceMapping(event) { let mapping = { aws_lambda_event_source_mapping: { event_source_mapping: { event_source_arn: event.stream, enabled: true, function_name: "${aws_lambda_function.Lambda.arn}", batch_size: event.batchSize, maximum_batching_window_in_seconds: event.batchWindow, } } }; if (event.startingPosition) { mapping.aws_lambda_event_source_mapping.event_source_mapping.starting_position = event.startingPosition; } return mapping; } } module.exports = TerraformTemplate;