integ/lib/render-struct.ts (110 lines of code) (raw):
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
import { Stack } from 'aws-cdk-lib';
import { Vpc } from 'aws-cdk-lib/aws-ec2';
import { ApplicationProtocol } from 'aws-cdk-lib/aws-elasticloadbalancingv2';
import { RetentionDays } from 'aws-cdk-lib/aws-logs';
import { PrivateHostedZone } from 'aws-cdk-lib/aws-route53';
import { Secret } from 'aws-cdk-lib/aws-secretsmanager';
import { X509CertificatePem } from 'aws-rfdk';
import {
IRepository,
RenderQueue,
RenderQueueHostNameProps,
RenderQueueTrafficEncryptionProps,
ThinkboxDockerRecipes,
UsageBasedLicense,
UsageBasedLicensing,
} from 'aws-rfdk/deadline';
import { Construct } from 'constructs';
import { NetworkTier } from '../components/_infrastructure/lib/network-tier';
import { ThinkboxDockerImageOverrides } from './thinkbox-docker-image-overrides';
const DOCKER_IMAGE_OVERRIDES_ENV_VAR = 'RFDK_DOCKER_IMAGE_OVERRIDES';
export interface RenderStructUsageBasedLicensingProps {
readonly certificateBundleSecretArn: string;
readonly licenses: UsageBasedLicense[];
}
export interface RenderStructProps {
readonly integStackTag: string;
readonly repository: IRepository;
readonly protocol: string;
readonly recipes: ThinkboxDockerRecipes;
readonly ubl?: RenderStructUsageBasedLicensingProps;
}
export class RenderStruct extends Construct {
public readonly renderQueue: RenderQueue;
public readonly cert: X509CertificatePem | undefined;
public readonly ubl?: UsageBasedLicensing;
constructor(scope: Construct, id: string, props: RenderStructProps) {
super(scope, id);
// Collect environment variables
const infrastructureStackName = 'RFDKIntegInfrastructure' + props.integStackTag;
// Retrieve VPC created for _infrastructure stack
const vpc = Vpc.fromLookup(this, 'Vpc', { tags: { StackName: infrastructureStackName }}) as Vpc;
// Retrieve Docker image overrides, if available
let dockerImageOverrides: (ThinkboxDockerImageOverrides | undefined) = undefined;
if (process.env[DOCKER_IMAGE_OVERRIDES_ENV_VAR] !== undefined) {
dockerImageOverrides = ThinkboxDockerImageOverrides.fromJSON(this, 'ThinkboxDockerImageOverrides', process.env[DOCKER_IMAGE_OVERRIDES_ENV_VAR]!.toString());
}
const host = 'renderqueue';
const suffix = '.local';
// We are calculating the max length we can add to the common name to keep it under the maximum allowed 64
// characters and then taking a slice of the stack name so we don't get an error when creating the certificate
// with openssl
const maxLength = 64 - host.length - '.'.length - suffix.length - 1;
const zoneName = Stack.of(this).stackName.slice(0, maxLength) + suffix;
let trafficEncryption: RenderQueueTrafficEncryptionProps | undefined;
let hostname: RenderQueueHostNameProps | undefined;
let cacert: X509CertificatePem | undefined;
// If configured for HTTPS, the render queue requires a private domain and a signed certificate for authentication
if( props.protocol === 'https' ) {
cacert = new X509CertificatePem(this, 'CaCert' + props.integStackTag, {
subject: {
cn: 'ca.renderfarm' + suffix,
},
});
trafficEncryption = {
externalTLS: {
rfdkCertificate: new X509CertificatePem(this, 'RenderQueueCertPEM' + props.integStackTag, {
subject: {
cn: host + '.' + zoneName,
},
signingCertificate: cacert,
}),
},
internalProtocol: ApplicationProtocol.HTTPS,
};
hostname = {
zone: new PrivateHostedZone(this, 'Zone', {
vpc,
zoneName: zoneName,
}),
hostname: host,
};
} else {
trafficEncryption = { externalTLS: { enabled: false } };
hostname = undefined;
}
//Create the Render Queue
this.renderQueue = new RenderQueue(this, 'RenderQueue', {
vpc,
vpcSubnetsAlb: vpc.selectSubnets({ subnetGroupName: NetworkTier.subnetConfig.renderQueueAlb.name }),
repository: props.repository,
images: dockerImageOverrides?.renderQueueImages ?? props.recipes.renderQueueImages,
logGroupProps: {
logGroupPrefix: `/${Stack.of(this).stackName}-${id}/`,
retention: RetentionDays.TWO_MONTHS,
},
hostname,
version: props.recipes.version,
trafficEncryption,
deletionProtection: false,
});
this.cert = cacert;
if (props.ubl) {
const ublCertificates = Secret.fromSecretCompleteArn(this, 'UsageBasedLicensingCertificates', props.ubl.certificateBundleSecretArn);
this.ubl = new UsageBasedLicensing(this, 'UsageBasedLicensing', {
vpc,
vpcSubnets: vpc.selectSubnets({ subnetGroupName: NetworkTier.subnetConfig.ubl.name }),
renderQueue: this.renderQueue,
images: dockerImageOverrides?.ublImages ?? props.recipes.ublImages,
licenses: props.ubl.licenses,
certificateSecret: ublCertificates,
logGroupProps: {
logGroupPrefix: `/${Stack.of(this).stackName}-${id}/`,
retention: RetentionDays.TWO_MONTHS,
},
});
}
}
}