@studion/infra-code-blocks
Version:
Studion common infra components
224 lines (223 loc) • 8.65 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.WebServer = void 0;
const pulumi = require("@pulumi/pulumi");
const aws = require("@pulumi/aws");
const common_tags_1 = require("../../shared/common-tags");
const acm_certificate_1 = require("../acm-certificate");
const ecs_service_1 = require("../ecs-service");
const load_balancer_1 = require("./load-balancer");
class WebServer extends pulumi.ComponentResource {
name;
container;
ecsConfig;
service;
serviceSecurityGroup;
lb;
initContainers;
sidecarContainers;
volumes;
acmCertificate;
dnsRecords;
constructor(name, args, opts = {}) {
super('studion:web-server:WebServer', name, {}, {
...opts,
aliases: [...(opts.aliases || []), { type: 'studion:WebServer' }],
});
const { vpc, domain, hostedZoneId, certificate } = args;
const hasCustomDomain = !!domain || !!certificate;
if (hasCustomDomain && !hostedZoneId) {
throw new Error('Provide `hostedZoneId` alongside `domain` and/or `certificate`.');
}
if (domain && hostedZoneId && !certificate) {
this.acmCertificate = this.createTlsCertificate({ domain, hostedZoneId });
}
this.name = name;
this.lb = new load_balancer_1.WebServerLoadBalancer(`${this.name}-lb`, {
vpc,
port: args.port,
certificate: certificate ?? this.acmCertificate?.certificate,
healthCheckPath: args.healthCheckPath,
healthCheckConfig: args.healthCheckConfig,
loadBalancingAlgorithmType: args.loadBalancingAlgorithmType,
}, {
parent: this,
...(this.acmCertificate
? { dependsOn: [this.acmCertificate.certificateValidation] }
: undefined),
});
this.serviceSecurityGroup = this.createSecurityGroup(vpc);
this.initContainers = this.getInitContainers(args);
this.sidecarContainers = this.getSidecarContainers(args);
this.container = this.createWebServerContainer(args);
this.ecsConfig = this.createEcsConfig(args);
this.volumes = this.getVolumes(args);
this.service = this.createEcsService(this.container, this.lb, this.ecsConfig, this.volumes, this.initContainers, this.sidecarContainers);
if (hasCustomDomain && hostedZoneId) {
this.dnsRecords = this.createDnsRecords(certificate ?? this.acmCertificate.certificate, hostedZoneId, domain);
}
this.registerOutputs();
}
getVolumes(args) {
return pulumi
.all([pulumi.output(args.volumes), args.otelCollector])
.apply(([passedVolumes, otelCollector]) => {
const volumes = [];
if (passedVolumes)
volumes.push(...passedVolumes);
if (otelCollector)
volumes.push({ name: otelCollector.configVolume });
return volumes;
});
}
getInitContainers(args) {
return pulumi
.all([pulumi.output(args.initContainers), args.otelCollector])
.apply(([passedInits, otelCollector]) => {
const containers = [];
if (passedInits)
containers.push(...passedInits);
if (otelCollector)
containers.push(otelCollector.configContainer);
return containers.map(container => ({
...container,
essential: false,
}));
});
}
getSidecarContainers(args) {
return pulumi
.all([pulumi.output(args.sidecarContainers), args.otelCollector])
.apply(([passedSidecars, otelCollector]) => {
const containers = [];
if (passedSidecars)
containers.push(...passedSidecars);
if (otelCollector)
containers.push(otelCollector.container);
return containers.map(container => ({ ...container, essential: true }));
});
}
getTaskRoleInlinePolicies(args) {
return pulumi
.all([pulumi.output(args.taskRoleInlinePolicies), args.otelCollector])
.apply(([passedTaskRoleInlinePolicies, otelCollector]) => {
const inlinePolicies = [];
if (passedTaskRoleInlinePolicies)
inlinePolicies.push(...passedTaskRoleInlinePolicies);
if (otelCollector && otelCollector.taskRoleInlinePolicies) {
inlinePolicies.push(...otelCollector.taskRoleInlinePolicies);
}
return inlinePolicies;
});
}
createEcsConfig(args) {
return {
vpc: args.vpc,
cluster: args.cluster,
name: args.name,
deploymentController: args.deploymentController,
desiredCount: args.desiredCount,
autoscaling: args.autoscaling,
family: args.family,
size: args.size,
logGroupNamePrefix: args.logGroupNamePrefix,
taskExecutionRoleInlinePolicies: args.taskExecutionRoleInlinePolicies,
taskRoleInlinePolicies: this.getTaskRoleInlinePolicies(args),
tags: args.tags,
};
}
createWebServerContainer(args) {
return {
image: args.image,
mountPoints: args.mountPoints,
environment: args.environment,
secrets: args.secrets,
port: args.port,
};
}
createTlsCertificate({ domain, hostedZoneId, }) {
return new acm_certificate_1.AcmCertificate(`${domain}-acm-certificate`, {
domain,
hostedZoneId,
}, { parent: this });
}
createSecurityGroup(vpc) {
const vpcId = pulumi.output(vpc).vpcId;
return new aws.ec2.SecurityGroup(`${this.name}-security-group`, {
vpcId,
ingress: [
{
fromPort: 0,
toPort: 0,
protocol: '-1',
securityGroups: [this.lb.securityGroup.id],
},
],
egress: [
{
fromPort: 0,
toPort: 0,
protocol: '-1',
cidrBlocks: ['0.0.0.0/0'],
},
],
tags: common_tags_1.commonTags,
}, { parent: this });
}
createEcsService(webServerContainer, lb, ecsConfig, volumes, initContainers, sidecarContainers) {
return pulumi
.all([
initContainers || pulumi.output([]),
sidecarContainers || pulumi.output([]),
])
.apply(([inits, sidecars]) => {
return new ecs_service_1.EcsService(`${this.name}-ecs`, {
...ecsConfig,
volumes,
containers: [
{
...webServerContainer,
name: this.name,
portMappings: [
ecs_service_1.EcsService.createTcpPortMapping(webServerContainer.port),
],
essential: true,
},
...inits,
...sidecars,
],
enableServiceAutoDiscovery: false,
loadBalancers: [
{
containerName: this.name,
containerPort: webServerContainer.port,
targetGroupArn: lb.targetGroup.arn,
},
],
assignPublicIp: true,
securityGroup: this.serviceSecurityGroup,
}, {
parent: this,
dependsOn: [lb, lb.targetGroup],
});
});
}
createDnsRecords(certificate, hostedZoneId, domain) {
const certOutput = pulumi.output(certificate);
return pulumi
.all([domain, certOutput.domainName, certOutput.subjectAlternativeNames])
.apply(([domain, certDomain, certSans = []]) => (domain ? [domain] : [...new Set([certDomain, ...certSans])]).map((alias, index) => new aws.route53.Record(`${this.name}-dns-a-record-${index}`, {
type: 'A',
name: alias,
zoneId: hostedZoneId,
aliases: [
{
name: this.lb.lb.dnsName,
zoneId: this.lb.lb.zoneId,
evaluateTargetHealth: true,
},
],
}, { parent: this })));
}
}
exports.WebServer = WebServer;