UNPKG

cdk-nextjs

Version:

Deploy Next.js apps on AWS with CDK

148 lines 23.5 kB
"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==