UNPKG

limgen

Version:

Infrastructure as Code generator

298 lines (297 loc) 10.9 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AppFargate = exports.defaultFullstackServiceAWSArgs = void 0; const pulumi = __importStar(require("@pulumi/pulumi")); const aws = __importStar(require("@pulumi/aws")); const awsx = __importStar(require("@pulumi/awsx")); const prefixed_1 = require("../utils/prefixed"); const deep_merge_1 = require("../utils/deep-merge"); exports.defaultFullstackServiceAWSArgs = { storage: null, connectionStringEnvironmentVariableName: "DATABASE_URL", connectionStringSecret: null, cluster: null, vpc: null, subnetIds: null, securityGroups: null, taskRole: null, executionRole: null, ecrRepository: null, taskDefinitionArgs: null, }; class AppFargate extends pulumi.ComponentResource { constructor(name = 'App', args, opts) { super("limgen:EcsClusterComponent", name, {}, opts); this._args = Object.assign({}, exports.defaultFullstackServiceAWSArgs, args); this.cluster = this.getCluster(); this.executionRole = this.getExecutionRole(); this.taskRole = this.getTaskRole(); this.ecrRepository = this.getEcrRepository(); this.image = this.getImage(); this.securityGroupIds = this.getSecurityGroups(); this.taskDefinitionArgs = this.getTaskDefinitionArgs(); this.service = this.getService(); this.registerOutputs({}); } getTaskDefinitionArgs() { return (0, deep_merge_1.deepMerge)({ taskRole: this.taskRole, executionRole: this.executionRole, container: { name: this.getContainerName(), image: this.image.imageUri, cpu: 256, memory: 512, essential: true, portMappings: [{ hostPort: 3000, containerPort: 3000, }], }, }, this._args.taskDefinitionArgs); } getSecurityGroups() { if (this._args.securityGroups) { return this._args.securityGroups.map(sg => sg.id); } if (!this._args.loadBalancer) { throw new Error("No security groups provided and no load balancer to derive them from"); } if (!this._args.loadBalancer.defaultSecurityGroup) { throw new Error("No security groups provided and load balancer has no default security group"); } const appSecurityGroup = new aws.ec2.SecurityGroup("AppSecurityGroup", { vpcId: this._args.vpc.vpcId, ingress: [ { protocol: "tcp", fromPort: 3000, toPort: 3000, securityGroups: [this._args.loadBalancer.defaultSecurityGroup.apply(sg => sg.id)], } ], egress: [ { protocol: "tcp", fromPort: 0, toPort: 65535, cidrBlocks: ["0.0.0.0/0"], } ], }); return [appSecurityGroup.id]; } getService() { var _a; const environmentParams = []; if (this._args.cdnHostname) { environmentParams.push({ name: "CDN_URL", value: pulumi.interpolate `https://${this._args.cdnHostname}`, }); } if (this._args.storage) { environmentParams.push({ name: "BUCKET_NAME", value: this._args.storage.bucket, }); } const secrets = []; if (this._args.connectionStringSecret) { secrets.push({ name: "DATABASE_URL", valueFrom: this._args.connectionStringSecret.arn, }); } const networkConfiguration = { subnets: (_a = this._args.subnetIds) !== null && _a !== void 0 ? _a : this._args.vpc.publicSubnetIds, assignPublicIp: true, securityGroups: this.securityGroupIds }; const loadBalancers = []; if (this._args.loadBalancer) { loadBalancers.push({ containerName: this.getContainerName(), containerPort: 3000, targetGroupArn: this._args.loadBalancer.defaultTargetGroup.arn, }); } const taskDefinitionArgs = { taskRole: { roleArn: this.taskRole.arn, }, executionRole: { roleArn: this.executionRole.arn, }, container: { name: this.getContainerName(), image: this.image.imageUri, cpu: 256, memory: 512, essential: true, portMappings: [{ hostPort: 3000, containerPort: 3000, }], environment: environmentParams, secrets, }, }; return new awsx.ecs.FargateService("Service", { name: (0, prefixed_1.prefixed)('service'), cluster: this.cluster.arn, networkConfiguration, loadBalancers, taskDefinitionArgs }); } getImage() { if (this._args.repositoryUrl) { return new awsx.ecr.Image("Image", (0, deep_merge_1.deepMerge)({ repositoryUrl: this._args.repositoryUrl, platform: "linux/amd64", }, this._args.imageArgs)); } if (!this.ecrRepository) { throw new Error("No docker registry URL or repository provided"); } const buildArgs = {}; if (this._args.cdnHostname) { buildArgs.INPUT_CDN_URL = pulumi.interpolate `https://${this._args.cdnHostname}`; } return new awsx.ecr.Image("Image", (0, deep_merge_1.deepMerge)({ repositoryUrl: this.ecrRepository.url, context: "../../..", args: buildArgs, platform: "linux/amd64", }, this._args.imageArgs)); } getEcrRepository() { if (this._args.repositoryUrl) { return null; } if (this._args.ecrRepository) { return this._args.ecrRepository; } return new awsx.ecr.Repository("Repo", { name: this.getContainerName(), forceDelete: true, }); } getTaskRole() { if (this._args.taskRole) { return this._args.taskRole; } const taskRole = new aws.iam.Role("TaskRole", { name: (0, prefixed_1.prefixed)('task-role'), assumeRolePolicy: JSON.stringify({ Version: "2012-10-17", Statement: [ { Action: "sts:AssumeRole", Effect: "Allow", Principal: { Service: "ecs-tasks.amazonaws.com", }, }, ], }), }); if (this._args.storage) { new aws.iam.RolePolicy("TaskRolePolicy", { name: (0, prefixed_1.prefixed)('task-role-policy'), role: taskRole, policy: { Version: "2012-10-17", Statement: [ { Action: [ "s3:PutObject", "s3:PutObjectAcl", ], Effect: "Allow", Resource: [pulumi.interpolate `${this._args.storage.arn}/*`], } ], } }); } return taskRole; } getCluster() { if (this._args.cluster) { return this._args.cluster; } return new aws.ecs.Cluster("Cluster", { name: (0, prefixed_1.prefixed)('cluster'), }); } getExecutionRole() { if (this._args.executionRole) { return this._args.executionRole; } const executionRole = new aws.iam.Role("AppExecutionRole", { name: (0, prefixed_1.prefixed)('execution-role'), assumeRolePolicy: JSON.stringify({ Version: "2012-10-17", Statement: [ { Action: "sts:AssumeRole", Effect: "Allow", Principal: { Service: "ecs-tasks.amazonaws.com", }, }, ], }), }); new aws.iam.PolicyAttachment("AppExecutionRoleAttachment", { policyArn: "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy", roles: [executionRole], }); if (this._args.connectionStringSecret) { new aws.iam.RolePolicy("ExecutionRolePolicy", { role: executionRole, name: (0, prefixed_1.prefixed)('execution-role-policy'), policy: this._args.connectionStringSecret.arn.apply(arn => JSON.stringify({ Version: "2012-10-17", Statement: [ { Action: "secretsmanager:GetSecretValue", Effect: "Allow", Resource: [arn], }, ], })), }); } return executionRole; } getContainerName() { return (0, prefixed_1.prefixed)('app'); } } exports.AppFargate = AppFargate;