cdk-nextjs
Version:
Deploy Next.js apps on AWS with CDK
148 lines • 23.5 kB
JavaScript
"use strict";
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.NextjsContainers = void 0;
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
const posix_1 = require("node:path/posix");
const aws_cdk_lib_1 = require("aws-cdk-lib");
const aws_ecs_1 = require("aws-cdk-lib/aws-ecs");
const aws_ecs_patterns_1 = require("aws-cdk-lib/aws-ecs-patterns");
const aws_elasticloadbalancingv2_1 = require("aws-cdk-lib/aws-elasticloadbalancingv2");
const constructs_1 = require("constructs");
const constants_1 = require("../constants");
/**
* Next.js load balanced via Application Load Balancer with containers via AWS
* Fargate.
*/
class NextjsContainers extends constructs_1.Construct {
constructor(scope, id, props) {
super(scope, id);
this.props = props;
this.ecsCluster = this.createEcsCluster();
this.albFargateService = this.createAlbFargateSevice();
this.configureHealthCheck();
this.attachFileSystem();
this.url = this.getUrl();
}
createEcsCluster() {
const cluster = new aws_ecs_1.Cluster(this, "EcsCluster", {
enableFargateCapacityProviders: true,
containerInsightsV2: aws_ecs_1.ContainerInsights.ENABLED,
vpc: this.props.vpc,
...this.props.overrides?.ecsClusterProps,
});
return cluster;
}
createAlbFargateSevice() {
let cpuArchitecture = undefined;
if (process.arch === "x64") {
cpuArchitecture = aws_ecs_1.CpuArchitecture.X86_64;
}
else if (process.arch === "arm64") {
cpuArchitecture = aws_ecs_1.CpuArchitecture.ARM64;
}
const albFargateService = new aws_ecs_patterns_1.ApplicationLoadBalancedFargateService(this, "AlbFargateService", {
circuitBreaker: { rollback: true, enable: true },
cluster: this.ecsCluster,
cpu: 1024,
healthCheckGracePeriod: aws_cdk_lib_1.Duration.seconds(10),
maxHealthyPercent: 200,
memoryLimitMiB: 2048,
minHealthyPercent: 100, // maintain service availability during deployment
/*
This protocol version is for the target group (Fargate), not the ALB
Listener. From docs, "Application Load Balancers provide native support
for HTTP/2 with HTTPS listeners". See https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-listeners.html
Next.js default server does not support HTTP/2 as it's recommended
to proxy your Next.js server which we're doing with ALB.
Also note, CloudFront only supports HTTP/1.1 origins.
https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/RequestAndResponseBehaviorCustomOrigin.html#RequestCustomHTTPVersion
*/
protocolVersion: aws_elasticloadbalancingv2_1.ApplicationProtocolVersion.HTTP1,
// if NextjsType.GLOBAL_CONTAINERS then we use VPC Origin Access which allows putting ALB in private subnet
publicLoadBalancer: this.props.nextjsType === constants_1.NextjsType.REGIONAL_CONTAINERS,
runtimePlatform: {
cpuArchitecture,
},
taskImageOptions: {
command: ["node", this.props.relativeEntrypointPath],
containerName: "nextjs",
containerPort: 3000,
image: aws_ecs_1.ContainerImage.fromDockerImageAsset(this.props.dockerImageAsset),
logDriver: aws_ecs_1.LogDrivers.awsLogs({
streamPrefix: "nextjs",
mode: aws_ecs_1.AwsLogDriverMode.NON_BLOCKING,
}),
...this.props.overrides?.taskImageOptions,
},
...this.props.overrides?.albFargateServiceProps,
});
// required or health checks fail
albFargateService.taskDefinition.defaultContainer?.addEnvironment("HOSTNAME", "0.0.0.0");
albFargateService.taskDefinition.defaultContainer?.addEnvironment(constants_1.CDK_NEXTJS_SERVER_DIST_DIR_ENV_VAR_NAME, (0, posix_1.join)(constants_1.MOUNT_PATH, this.props.buildId, constants_1.SERVER_DIST_PATH));
// speed up deployments by shortening deregistration delay
// https://docs.aws.amazon.com/AmazonECS/latest/bestpracticesguide/load-balancer-connection-draining.html
// TODO: document that this should be increased if long lived connections are expected
albFargateService.targetGroup.setAttribute("deregistration_delay.timeout_seconds", "30");
// best practice to enable cross zone load balancing
// @see https://docs.aws.amazon.com/elasticloadbalancing/latest/application/disable-cross-zone.html
albFargateService.loadBalancer.setAttribute("load_balancing.cross_zone.enabled", "true");
return albFargateService;
}
/**
* Configure health checks for containers at ALB and ECS level. This ensures
* unhealthy containers are removed. Both of these health checks can be
* overwritten by user by accessing `albFargateService` property, so no need
* for `overrides`.
*/
configureHealthCheck() {
// speed up deployments by shortening health checks
// see https://docs.aws.amazon.com/AmazonECS/latest/bestpracticesguide/load-balancer-healthcheck.html
this.albFargateService.targetGroup.configureHealthCheck({
path: this.props.healthCheckPath,
healthyThresholdCount: 2,
interval: aws_cdk_lib_1.Duration.seconds(10), // too frequent? but enables faster rollback...
timeout: aws_cdk_lib_1.Duration.seconds(5), // must be less than interval
});
const healthCheck = {
command: [
"CMD-SHELL",
// curl isn't available in alpine linux
`wget --quiet --tries=1 --spider http://localhost:3000${this.props.healthCheckPath} || exit 1`,
],
};
const defaultContainer = this.albFargateService.taskDefinition.defaultContainer;
if (defaultContainer) {
// @ts-expect-error must use internal "props" attribute b/c no other way to add health check
defaultContainer.props.healthCheck = healthCheck;
}
}
attachFileSystem() {
const container = this.albFargateService.taskDefinition.defaultContainer;
const volumeName = "cdk-nextjs-volume";
this.albFargateService.taskDefinition.addVolume({
name: volumeName,
efsVolumeConfiguration: {
fileSystemId: this.props.fileSystem.fileSystemId,
transitEncryption: "ENABLED",
authorizationConfig: {
accessPointId: this.props.accessPoint.accessPointId,
iam: "ENABLED",
},
},
});
container?.addMountPoints({
sourceVolume: volumeName,
containerPath: constants_1.MOUNT_PATH,
readOnly: false,
});
}
getUrl() {
const protocol = this.albFargateService.certificate ? "https" : "http";
return `${protocol}://${this.albFargateService.loadBalancer.loadBalancerDnsName}`;
}
}
exports.NextjsContainers = NextjsContainers;
_a = JSII_RTTI_SYMBOL_1;
NextjsContainers[_a] = { fqn: "cdk-nextjs.NextjsContainers", version: "0.4.14" };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmV4dGpzLWNvbnRhaW5lcnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbmV4dGpzLWNvbXB1dGUvbmV4dGpzLWNvbnRhaW5lcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSwyQ0FBdUM7QUFDdkMsNkNBQXVDO0FBRXZDLGlEQVE2QjtBQUM3QixtRUFHc0M7QUFFdEMsdUZBQW9GO0FBQ3BGLDJDQUF1QztBQUV2Qyw0Q0FLc0I7QUFtQnRCOzs7R0FHRztBQUNILE1BQWEsZ0JBQWlCLFNBQVEsc0JBQVM7SUFPN0MsWUFBWSxLQUFnQixFQUFFLEVBQVUsRUFBRSxLQUE0QjtRQUNwRSxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQ2pCLElBQUksQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDO1FBQ25CLElBQUksQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7UUFDMUMsSUFBSSxDQUFDLGlCQUFpQixHQUFHLElBQUksQ0FBQyxzQkFBc0IsRUFBRSxDQUFDO1FBQ3ZELElBQUksQ0FBQyxvQkFBb0IsRUFBRSxDQUFDO1FBQzVCLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1FBQ3hCLElBQUksQ0FBQyxHQUFHLEdBQUcsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO0lBQzNCLENBQUM7SUFFTyxnQkFBZ0I7UUFDdEIsTUFBTSxPQUFPLEdBQUcsSUFBSSxpQkFBTyxDQUFDLElBQUksRUFBRSxZQUFZLEVBQUU7WUFDOUMsOEJBQThCLEVBQUUsSUFBSTtZQUNwQyxtQkFBbUIsRUFBRSwyQkFBaUIsQ0FBQyxPQUFPO1lBQzlDLEdBQUcsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUc7WUFDbkIsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLFNBQVMsRUFBRSxlQUFlO1NBQ3pDLENBQUMsQ0FBQztRQUNILE9BQU8sT0FBTyxDQUFDO0lBQ2pCLENBQUM7SUFDTyxzQkFB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QUcsSUFBSSxDQUFDLGlCQUFpQixDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUM7UUFDdkUsT0FBTyxHQUFHLFFBQVEsTUFBTSxJQUFJLENBQUMsaUJBQWlCLENBQUMsWUFBWSxDQUFDLG1CQUFtQixFQUFFLENBQUM7SUFDcEYsQ0FBQzs7QUF4SkgsNENBeUpDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgam9pbiB9IGZyb20gXCJub2RlOnBhdGgvcG9zaXhcIjtcbmltcG9ydCB7IER1cmF0aW9uIH0gZnJvbSBcImF3cy1jZGstbGliXCI7XG5pbXBvcnQgeyBEb2NrZXJJbWFnZUFzc2V0IH0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1lY3ItYXNzZXRzXCI7XG5pbXBvcnQge1xuICBBd3NMb2dEcml2ZXJNb2RlLFxuICBDbHVzdGVyLFxuICBDb250YWluZXJJbWFnZSxcbiAgQ29udGFpbmVySW5zaWdodHMsXG4gIENwdUFyY2hpdGVjdHVyZSxcbiAgSGVhbHRoQ2hlY2ssXG4gIExvZ0RyaXZlcnMsXG59IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtZWNzXCI7XG5pbXBvcnQge1xuICBBcHBsaWNhdGlvbkxvYWRCYWxhbmNlZEZhcmdhdGVTZXJ2aWNlLFxuICBBcHBsaWNhdGlvbkxvYWRCYWxhbmNlZEZhcmdhdGVTZXJ2aWNlUHJvcHMsXG59IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtZWNzLXBhdHRlcm5zXCI7XG5pbXBvcnQgeyBGaWxlU3lzdGVtIH0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1lZnNcIjtcbmltcG9ydCB7IEFwcGxpY2F0aW9uUHJvdG9jb2xWZXJzaW9uIH0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1lbGFzdGljbG9hZGJhbGFuY2luZ3YyXCI7XG5pbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tIFwiY29uc3RydWN0c1wiO1xuaW1wb3J0IHsgTmV4dGpzQ29tcHV0ZUJhc2VQcm9wcyB9IGZyb20gXCIuL25leHRqcy1jb21wdXRlLWJhc2UtcHJvcHNcIjtcbmltcG9ydCB7XG4gIENES19ORVhUSlNfU0VSVkVSX0RJU1RfRElSX0VOVl9WQVJfTkFNRSxcbiAgTU9VTlRfUEFUSCxcbiAgTmV4dGpzVHlwZSxcbiAgU0VSVkVSX0RJU1RfUEFUSCxcbn0gZnJvbSBcIi4uL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgT3B0aW9uYWxBcHBsaWNhdGlvbkxvYWRCYWxhbmNlZFRhc2tJbWFnZU9wdGlvbnMgfSBmcm9tIFwiLi4vZ2VuZXJhdGVkLXN0cnVjdHMvT3B0aW9uYWxBcHBsaWNhdGlvbkxvYWRCYWxhbmNlZFRhc2tJbWFnZU9wdGlvbnNcIjtcbmltcG9ydCB7IE9wdGlvbmFsQ2x1c3RlclByb3BzIH0gZnJvbSBcIi4uL2dlbmVyYXRlZC1zdHJ1Y3RzL09wdGlvbmFsQ2x1c3RlclByb3BzXCI7XG5cbmV4cG9ydCBpbnRlcmZhY2UgTmV4dGpzQ29udGFpbmVyc092ZXJyaWRlcyB7XG4gIHJlYWRvbmx5IGVjc0NsdXN0ZXJQcm9wcz86IE9wdGlvbmFsQ2x1c3RlclByb3BzO1xuICByZWFkb25seSBhbGJGYXJnYXRlU2VydmljZVByb3BzPzogQXBwbGljYXRpb25Mb2FkQmFsYW5jZWRGYXJnYXRlU2VydmljZVByb3BzO1xuICByZWFkb25seSB0YXNrSW1hZ2VPcHRpb25zPzogT3B0aW9uYWxBcHBsaWNhdGlvbkxvYWRCYWxhbmNlZFRhc2tJbWFnZU9wdGlvbnM7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTmV4dGpzQ29udGFpbmVyc1Byb3BzIGV4dGVuZHMgTmV4dGpzQ29tcHV0ZUJhc2VQcm9wcyB7XG4gIHJlYWRvbmx5IGRvY2tlckltYWdlQXNzZXQ6IERvY2tlckltYWdlQXNzZXQ7XG4gIHJlYWRvbmx5IGZpbGVTeXN0ZW06IEZpbGVTeXN0ZW07XG4gIHJlYWRvbmx5IG5leHRqc1R5cGU6IE5leHRqc1R5cGU7XG4gIHJlYWRvbmx5IG92ZXJyaWRlcz86IE5leHRqc0NvbnRhaW5lcnNPdmVycmlkZXM7XG4gIHJlYWRvbmx5IHJlbGF0aXZlRW50cnlwb2ludFBhdGg6IHN0cmluZztcbiAgcmVhZG9ubHkgYnVpbGRJZDogc3RyaW5nO1xufVxuXG4vKipcbiAqIE5leHQuanMgbG9hZCBiYWxhbmNlZCB2aWEgQXBwbGljYXRpb24gTG9hZCBCYWxhbmNlciB3aXRoIGNvbnRhaW5lcnMgdmlhIEFXU1xuICogRmFyZ2F0ZS5cbiAqL1xuZXhwb3J0IGNsYXNzIE5leHRqc0NvbnRhaW5lcnMgZXh0ZW5kcyBDb25zdHJ1Y3Qge1xuICBhbGJGYXJnYXRlU2VydmljZTogQXBwbGljYXRpb25Mb2FkQmFsYW5jZWRGYXJnYXRlU2VydmljZTtcbiAgZWNzQ2x1c3RlcjogQ2x1c3RlcjtcbiAgdXJsOiBzdHJpbmc7XG5cbiAgcHJpdmF0ZSBwcm9wczogTmV4dGpzQ29udGFpbmVyc1Byb3BzO1xuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBOZXh0anNDb250YWluZXJzUHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuICAgIHRoaXMucHJvcHMgPSBwcm9wcztcbiAgICB0aGlzLmVjc0NsdXN0ZXIgPSB0aGlzLmNyZWF0ZUVjc0NsdXN0ZXIoKTtcbiAgICB0aGlzLmFsYkZhcmdhdGVTZXJ2aWNlID0gdGhpcy5jcmVhdGVBbGJGYXJnYXRlU2V2aWNlKCk7XG4gICAgdGhpcy5jb25maWd1cmVIZWFsdGhDaGVjaygpO1xuICAgIHRoaXMuYXR0YWNoRmlsZVN5c3RlbSgpO1xuICAgIHRoaXMudXJsID0gdGhpcy5nZXRVcmwoKTtcbiAgfVxuXG4gIHByaXZhdGUgY3JlYXRlRWNzQ2x1c3RlcigpOiBDbHVzdGVyIHtcbiAgICBjb25zdCBjbHVzdGVyID0gbmV3IENsdXN0ZXIodGhpcywgXCJFY3NDbHVzdGVyXCIsIHtcbiAgICAgIGVuYWJsZUZhcmdhdGVDYXBhY2l0eVByb3ZpZGVyczogdHJ1ZSxcbiAgICAgIGNvbnRhaW5lckluc2lnaHRzVjI6IENvbnRhaW5lckluc2lnaHRzLkVOQUJMRUQsXG4gICAgICB2cGM6IHRoaXMucHJvcHMudnBjLFxuICAgICAgLi4udGhpcy5wcm9wcy5vdmVycmlkZXM/LmVjc0NsdXN0ZXJQcm9wcyxcbiAgICB9KTtcbiAgICByZXR1cm4gY2x1c3RlcjtcbiAgfVxuICBwcml2YXRlIGNyZWF0ZUFsYkZhcmdhdGVTZXZpY2UoKTogQXBwbGljYXRpb25Mb2FkQmFsYW5jZWRGYXJnYXRlU2VydmljZSB7XG4gICAgbGV0IGNwdUFyY2hpdGVjdHVyZTogQ3B1QXJjaGl0ZWN0dXJlIHwgdW5kZWZpbmVkID0gdW5kZWZpbmVkO1xuICAgIGlmIChwcm9jZXNzLmFyY2ggPT09IFwieDY0XCIpIHtcbiAgICAgIGNwdUFyY2hpdGVjdHVyZSA9IENwdUFyY2hpdGVjdHVyZS5YODZfNjQ7XG4gICAgfSBlbHNlIGlmIChwcm9jZXNzLmFyY2ggPT09IFwiYXJtNjRcIikge1xuICAgICAgY3B1QXJjaGl0ZWN0dXJlID0gQ3B1QXJjaGl0ZWN0dXJlLkFSTTY0O1xuICAgIH1cbiAgICBjb25zdCBhbGJGYXJnYXRlU2VydmljZSA9IG5ldyBBcHBsaWNhdGlvbkxvYWRCYWxhbmNlZEZhcmdhdGVTZXJ2aWNlKFxuICAgICAgdGhpcyxcbiAgICAgIFwiQWxiRmFyZ2F0ZVNlcnZpY2VcIixcbiAgICAgIHtcbiAgICAgICAgY2lyY3VpdEJyZWFrZXI6IHsgcm9sbGJhY2s6IHRydWUsIGVuYWJsZTogdHJ1ZSB9LFxuICAgICAgICBjbHVzdGVyOiB0aGlzLmVjc0NsdXN0ZXIsXG4gICAgICAgIGNwdTogMTAyNCxcbiAgICAgICAgaGVhbHRoQ2hlY2tHcmFjZVBlcmlvZDogRHVyYXRpb24uc2Vjb25kcygxMCksXG4gICAgICAgIG1heEhlYWx0aHlQZXJjZW50OiAyMDAsXG4gICAgICAgIG1lbW9yeUxpbWl0TWlCOiAyMDQ4LFxuICAgICAgICBtaW5IZWFsdGh5UGVyY2VudDogMTAwLCAvLyBtYWludGFpbiBzZXJ2aWNlIGF2YWlsYWJpbGl0eSBkdXJpbmcgZGVwbG95bWVudFxuICAgICAgICAvKlxuICAgICAgICAgIFRoaXMgcHJvdG9jb2wgdmVyc2lvbiBpcyBmb3IgdGhlIHRhcmdldCBncm91cCAoRmFyZ2F0ZSksIG5vdCB0aGUgQUxCXG4gICAgICAgICAgTGlzdGVuZXIuIEZyb20gZG9jcywgXCJBcHBsaWNhdGlvbiBMb2FkIEJhbGFuY2VycyBwcm92aWRlIG5hdGl2ZSBzdXBwb3J0XG4gICAgICAgICAgZm9yIEhUVFAvMiB3aXRoIEhUVFBTIGxpc3RlbmVyc1wiLiBTZWUgaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL2VsYXN0aWNsb2FkYmFsYW5jaW5nL2xhdGVzdC9hcHBsaWNhdGlvbi9sb2FkLWJhbGFuY2VyLWxpc3RlbmVycy5odG1sXG4gICAgICAgICAgTmV4dC5qcyBkZWZhdWx0IHNlcnZlciBkb2VzIG5vdCBzdXBwb3J0IEhUVFAvMiBhcyBpdCdzIHJlY29tbWVuZGVkXG4gICAgICAgICAgdG8gcHJveHkgeW91ciBOZXh0LmpzIHNlcnZlciB3aGljaCB3ZSdyZSBkb2luZyB3aXRoIEFMQi5cbiAgICAgICAgICBBbHNvIG5vdGUsIENsb3VkRnJvbnQgb25seSBzdXBwb3J0cyBIVFRQLzEuMSBvcmlnaW5zLlxuICAgICAgICAgIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9BbWF6b25DbG91ZEZyb250L2xhdGVzdC9EZXZlbG9wZXJHdWlkZS9SZXF1ZXN0QW5kUmVzcG9uc2VCZWhhdmlvckN1c3RvbU9yaWdpbi5odG1sI1JlcXVlc3RDdXN0b21IVFRQVmVyc2lvblxuICAgICAgICAqL1xuICAgICAgICBwcm90b2NvbFZlcnNpb246IEFwcGxpY2F0aW9uUHJvdG9jb2xWZXJzaW9uLkhUVFAxLFxuICAgICAgICAvLyBpZiBOZXh0anNUeXBlLkdMT0JBTF9DT05UQUlORVJTIHRoZW4gd2UgdXNlIFZQQyBPcmlnaW4gQWNjZXNzIHdoaWNoIGFsbG93cyBwdXR0aW5nIEFMQiBpbiBwcml2YXRlIHN1Ym5ldFxuICAgICAgICBwdWJsaWNMb2FkQmFsYW5jZXI6XG4gICAgICAgICAgdGhpcy5wcm9wcy5uZXh0anNUeXBlID09PSBOZXh0anNUeXBlLlJFR0lPTkFMX0NPTlRBSU5FUlMsXG4gICAgICAgIHJ1bnRpbWVQbGF0Zm9ybToge1xuICAgICAgICAgIGNwdUFyY2hpdGVjdHVyZSxcbiAgICAgICAgfSxcbiAgICAgICAgdGFza0ltYWdlT3B0aW9uczoge1xuICAgICAgICAgIGNvbW1hbmQ6IFtcIm5vZGVcIiwgdGhpcy5wcm9wcy5yZWxhdGl2ZUVudHJ5cG9pbnRQYXRoXSxcbiAgICAgICAgICBjb250YWluZXJOYW1lOiBcIm5leHRqc1wiLFxuICAgICAgICAgIGNvbnRhaW5lclBvcnQ6IDMwMDAsXG4gICAgICAgICAgaW1hZ2U6IENvbnRhaW5lckltYWdlLmZyb21Eb2NrZXJJbWFnZUFzc2V0KFxuICAgICAgICAgICAgdGhpcy5wcm9wcy5kb2NrZXJJbWFnZUFzc2V0LFxuICAgICAgICAgICksXG4gICAgICAgICAgbG9nRHJpdmVyOiBMb2dEcml2ZXJzLmF3c0xvZ3Moe1xuICAgICAgICAgICAgc3RyZWFtUHJlZml4OiBcIm5leHRqc1wiLFxuICAgICAgICAgICAgbW9kZTogQXdzTG9nRHJpdmVyTW9kZS5OT05fQkxPQ0tJTkcsXG4gICAgICAgICAgfSksXG4gICAgICAgICAgLi4udGhpcy5wcm9wcy5vdmVycmlkZXM/LnRhc2tJbWFnZU9wdGlvbnMsXG4gICAgICAgIH0sXG4gICAgICAgIC4uLnRoaXMucHJvcHMub3ZlcnJpZGVzPy5hbGJGYXJnYXRlU2VydmljZVByb3BzLFxuICAgICAgfSxcbiAgICApO1xuICAgIC8vIHJlcXVpcmVkIG9yIGhlYWx0aCBjaGVja3MgZmFpbFxuICAgIGFsYkZhcmdhdGVTZXJ2aWNlLnRhc2tEZWZpbml0aW9uLmRlZmF1bHRDb250YWluZXI/LmFkZEVudmlyb25tZW50KFxuICAgICAgXCJIT1NUTkFNRVwiLFxuICAgICAgXCIwLjAuMC4wXCIsXG4gICAgKTtcbiAgICBhbGJGYXJnYXRlU2VydmljZS50YXNrRGVmaW5pdGlvbi5kZWZhdWx0Q29udGFpbmVyPy5hZGRFbnZpcm9ubWVudChcbiAgICAgIENES19ORVhUSlNfU0VSVkVSX0RJU1RfRElSX0VOVl9WQVJfTkFNRSxcbiAgICAgIGpvaW4oTU9VTlRfUEFUSCwgdGhpcy5wcm9wcy5idWlsZElkLCBTRVJWRVJfRElTVF9QQVRIKSxcbiAgICApO1xuICAgIC8vIHNwZWVkIHVwIGRlcGxveW1lbnRzIGJ5IHNob3J0ZW5pbmcgZGVyZWdpc3RyYXRpb24gZGVsYXlcbiAgICAvLyBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vQW1hem9uRUNTL2xhdGVzdC9iZXN0cHJhY3RpY2VzZ3VpZGUvbG9hZC1iYWxhbmNlci1jb25uZWN0aW9uLWRyYWluaW5nLmh0bWxcbiAgICAvLyBUT0RPOiBkb2N1bWVudCB0aGF0IHRoaXMgc2hvdWxkIGJlIGluY3JlYXNlZCBpZiBsb25nIGxpdmVkIGNvbm5lY3Rpb25zIGFyZSBleHBlY3RlZFxuICAgIGFsYkZhcmdhdGVTZXJ2aWNlLnRhcmdldEdyb3VwLnNldEF0dHJpYnV0ZShcbiAgICAgIFwiZGVyZWdpc3RyYXRpb25fZGVsYXkudGltZW91dF9zZWNvbmRzXCIsXG4gICAgICBcIjMwXCIsXG4gICAgKTtcbiAgICAvLyBiZXN0IHByYWN0aWNlIHRvIGVuYWJsZSBjcm9zcyB6b25lIGxvYWQgYmFsYW5jaW5nXG4gICAgLy8gQHNlZSBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vZWxhc3RpY2xvYWRiYWxhbmNpbmcvbGF0ZXN0L2FwcGxpY2F0aW9uL2Rpc2FibGUtY3Jvc3Mtem9uZS5odG1sXG4gICAgYWxiRmFyZ2F0ZVNlcnZpY2UubG9hZEJhbGFuY2VyLnNldEF0dHJpYnV0ZShcbiAgICAgIFwibG9hZF9iYWxhbmNpbmcuY3Jvc3Nfem9uZS5lbmFibGVkXCIsXG4gICAgICBcInRydWVcIixcbiAgICApO1xuICAgIHJldHVybiBhbGJGYXJnYXRlU2VydmljZTtcbiAgfVxuICAvKipcbiAgICogQ29uZmlndXJlIGhlYWx0aCBjaGVja3MgZm9yIGNvbnRhaW5lcnMgYXQgQUxCIGFuZCBFQ1MgbGV2ZWwuIFRoaXMgZW5zdXJlc1xuICAgKiB1bmhlYWx0aHkgY29udGFpbmVycyBhcmUgcmVtb3ZlZC4gQm90aCBvZiB0aGVzZSBoZWFsdGggY2hlY2tzIGNhbiBiZVxuICAgKiBvdmVyd3JpdHRlbiBieSB1c2VyIGJ5IGFjY2Vzc2luZyBgYWxiRmFyZ2F0ZVNlcnZpY2VgIHByb3BlcnR5LCBzbyBubyBuZWVkXG4gICAqIGZvciBgb3ZlcnJpZGVzYC5cbiAgICovXG4gIHByaXZhdGUgY29uZmlndXJlSGVhbHRoQ2hlY2soKSB7XG4gICAgLy8gc3BlZWQgdXAgZGVwbG95bWVudHMgYnkgc2hvcnRlbmluZyBoZWFsdGggY2hlY2tzXG4gICAgLy8gc2VlIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9BbWF6b25FQ1MvbGF0ZXN0L2Jlc3RwcmFjdGljZXNndWlkZS9sb2FkLWJhbGFuY2VyLWhlYWx0aGNoZWNrLmh0bWxcbiAgICB0aGlzLmFsYkZhcmdhdGVTZXJ2aWNlLnRhcmdldEdyb3VwLmNvbmZpZ3VyZUhlYWx0aENoZWNrKHtcbiAgICAgIHBhdGg6IHRoaXMucHJvcHMuaGVhbHRoQ2hlY2tQYXRoLFxuICAgICAgaGVhbHRoeVRocmVzaG9sZENvdW50OiAyLFxuICAgICAgaW50ZXJ2YWw6IER1cmF0aW9uLnNlY29uZHMoMTApLCAvLyB0b28gZnJlcXVlbnQ/IGJ1dCBlbmFibGVzIGZhc3RlciByb2xsYmFjay4uLlxuICAgICAgdGltZW91dDogRHVyYXRpb24uc2Vjb25kcyg1KSwgLy8gbXVzdCBiZSBsZXNzIHRoYW4gaW50ZXJ2YWxcbiAgICB9KTtcbiAgICBjb25zdCBoZWFsdGhDaGVjazogSGVhbHRoQ2hlY2sgPSB7XG4gICAgICBjb21tYW5kOiBbXG4gICAgICAgIFwiQ01ELVNIRUxMXCIsXG4gICAgICAgIC8vIGN1cmwgaXNuJ3QgYXZhaWxhYmxlIGluIGFscGluZSBsaW51eFxuICAgICAgICBgd2dldCAtLXF1aWV0IC0tdHJpZXM9MSAtLXNwaWRlciBodHRwOi8vbG9jYWxob3N0OjMwMDAke3RoaXMucHJvcHMuaGVhbHRoQ2hlY2tQYXRofSB8fCBleGl0IDFgLFxuICAgICAgXSxcbiAgICB9O1xuICAgIGNvbnN0IGRlZmF1bHRDb250YWluZXIgPVxuICAgICAgdGhpcy5hbGJGYXJnYXRlU2VydmljZS50YXNrRGVmaW5pdGlvbi5kZWZhdWx0Q29udGFpbmVyO1xuICAgIGlmIChkZWZhdWx0Q29udGFpbmVyKSB7XG4gICAgICAvLyBAdHMtZXhwZWN0LWVycm9yIG11c3QgdXNlIGludGVybmFsIFwicHJvcHNcIiBhdHRyaWJ1dGUgYi9jIG5vIG90aGVyIHdheSB0byBhZGQgaGVhbHRoIGNoZWNrXG4gICAgICBkZWZhdWx0Q29udGFpbmVyLnByb3BzLmhlYWx0aENoZWNrID0gaGVhbHRoQ2hlY2s7XG4gICAgfVxuICB9XG4gIHByaXZhdGUgYXR0YWNoRmlsZVN5c3RlbSgpIHtcbiAgICBjb25zdCBjb250YWluZXIgPSB0aGlzLmFsYkZhcmdhdGVTZXJ2aWNlLnRhc2tEZWZpbml0aW9uLmRlZmF1bHRDb250YWluZXI7XG4gICAgY29uc3Qgdm9sdW1lTmFtZSA9IFwiY2RrLW5leHRqcy12b2x1bWVcIjtcbiAgICB0aGlzLmFsYkZhcmdhdGVTZXJ2aWNlLnRhc2tEZWZpbml0aW9uLmFkZFZvbHVtZSh7XG4gICAgICBuYW1lOiB2b2x1bWVOYW1lLFxuICAgICAgZWZzVm9sdW1lQ29uZmlndXJhdGlvbjoge1xuICAgICAgICBmaWxlU3lzdGVtSWQ6IHRoaXMucHJvcHMuZmlsZVN5c3RlbS5maWxlU3lzdGVtSWQsXG4gICAgICAgIHRyYW5zaXRFbmNyeXB0aW9uOiBcIkVOQUJMRURcIixcbiAgICAgICAgYXV0aG9yaXphdGlvbkNvbmZpZzoge1xuICAgICAgICAgIGFjY2Vzc1BvaW50SWQ6IHRoaXMucHJvcHMuYWNjZXNzUG9pbnQuYWNjZXNzUG9pbnRJZCxcbiAgICAgICAgICBpYW06IFwiRU5BQkxFRFwiLFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICB9KTtcbiAgICBjb250YWluZXI/LmFkZE1vdW50UG9pbnRzKHtcbiAgICAgIHNvdXJjZVZvbHVtZTogdm9sdW1lTmFtZSxcbiAgICAgIGNvbnRhaW5lclBhdGg6IE1PVU5UX1BBVEgsXG4gICAgICByZWFkT25seTogZmFsc2UsXG4gICAgfSk7XG4gIH1cbiAgcHJpdmF0ZSBnZXRVcmwoKTogc3RyaW5nIHtcbiAgICBjb25zdCBwcm90b2NvbCA9IHRoaXMuYWxiRmFyZ2F0ZVNlcnZpY2UuY2VydGlmaWNhdGUgPyBcImh0dHBzXCIgOiBcImh0dHBcIjtcbiAgICByZXR1cm4gYCR7cHJvdG9jb2x9Oi8vJHt0aGlzLmFsYkZhcmdhdGVTZXJ2aWNlLmxvYWRCYWxhbmNlci5sb2FkQmFsYW5jZXJEbnNOYW1lfWA7XG4gIH1cbn1cbiJdfQ==