UNPKG

@scloud/cdk-patterns

Version:

Serverless CDK patterns for common infrastructure needs

97 lines 16.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.FargateService = void 0; const aws_certificatemanager_1 = require("aws-cdk-lib/aws-certificatemanager"); const aws_cdk_lib_1 = require("aws-cdk-lib"); const aws_elasticloadbalancingv2_1 = require("aws-cdk-lib/aws-elasticloadbalancingv2"); const aws_ec2_1 = require("aws-cdk-lib/aws-ec2"); const aws_ecs_patterns_1 = require("aws-cdk-lib/aws-ecs-patterns"); const aws_ecs_1 = require("aws-cdk-lib/aws-ecs"); const aws_logs_1 = require("aws-cdk-lib/aws-logs"); const constructs_1 = require("constructs"); const EcrRepository_1 = require("./EcrRepository"); /** * Builds an ApplicationLoadBalancedFargateService that runs a container on ECS Fargate. * * Warning! This pattern is not 'pure' serverless! It gennerates 24x7 running costs per container (rather than being billed on traffic/storage). * * Warning! If you don't pass a vpc, this construct creates a vpc for you and limits the nuber of NAT gateways to 1 to reduce cost. This is less resilient, but NAT gateways are costly! * * If you'd like to avoid this tradeoof, pass in a vpc you've createed that ha zero NAT gateways and is configured with PrivateEndpoint(s) that will allow ECS to pull container images. * * @param serviceName Name for the service * @param zone DNS zone * @param domain Optional: by default the zone name will be used as the DNS name for the service (e.g. 'example.com') but you can specify a different domain here (e.g. 'subdomain.example.com'). * @param environment Any environment variables for the container * @param repository Optional: if you want to use an existing container image repository * @param tag Optional: defaults to 'latest' * @param vpc Optional: if you want to use an existing VPC. In not set, a vpc will be created for you * @param cpu Optional: defaults to 512 * @param memory Optional: defaults to 1024 * @param taskCount Optional: defaults to 2 for redundancy. Set to 1 if you want to reduce cost. * @param zeroTasks Sets task count to zero. Pass true if you don't have an image in ECR yet, otherwise this construct will fail to build. * @param containerPort Optional: defaults to 3000. This is the port the application in your container listens on. * @returns Deplyment detais */ class FargateService extends constructs_1.Construct { constructor(scope, id, serviceName, zone, domain, environment = {}, repository = undefined, tag = 'latest', vpc = undefined, cpu = 512, memory = 1024, taskCount = 2, zeroTasks = false, containerPort = 3000) { super(scope, `${id}FargateService`); // Container repository this.repository = repository || new EcrRepository_1.EcrRepository(scope, id); // It seems like NAT gateways are costly, so I've set this up to avoid that - only creating one. // At some point we may want to figure out a privte endpoint so that we can retire the NAT. // Based on: https://www.binarythinktank.com/blog/truly-serverless-container // and https://stackoverflow.com/questions/64299664/how-to-configure-aws-cdk-applicationloadbalancedfargateservice-to-log-parsed-jso this.vpc = vpc || new aws_ec2_1.Vpc(scope, `${id}Vpc`, { natGateways: 1, subnetConfiguration: [{ name: id, subnetType: aws_ec2_1.SubnetType.PUBLIC, }], }); // Fargate this.albFargateService = new aws_ecs_patterns_1.ApplicationLoadBalancedFargateService(scope, `${id}AlbFargateService`, { loadBalancerName: id, serviceName, domainZone: zone, domainName: domain || zone.zoneName, certificate: new aws_certificatemanager_1.DnsValidatedCertificate(scope, id, { domainName: domain || zone.zoneName, hostedZone: zone, }), protocol: aws_elasticloadbalancingv2_1.ApplicationProtocol.HTTPS, cpu, memoryLimitMiB: memory, taskImageOptions: { containerName: id, image: aws_ecs_1.ContainerImage.fromEcrRepository(this.repository, tag), containerPort, environment, logDriver: aws_ecs_1.LogDrivers.awsLogs({ streamPrefix: id, logGroup: new aws_logs_1.LogGroup(scope, `${id}LogGroup`, { // Ensure the log group is deleted when the stack is deleted // and that logs aren't retained indefinitely logGroupName: `/${aws_cdk_lib_1.Stack.of(scope).stackName}/ecs/${id}`, removalPolicy: aws_cdk_lib_1.RemovalPolicy.DESTROY, retention: aws_logs_1.RetentionDays.THREE_MONTHS, }), }), }, desiredCount: taskCount, vpc: this.vpc, // ? https://stackoverflow.com/questions/67301268/aws-fargate-resourceinitializationerror-unable-to-pull-secrets-or-registry-auth assignPublicIp: true, }); this.albFargateService.loadBalancer.addRedirect(); // http -> https if (zeroTasks) { // On the first deploy, when there's no image in the repository, setting desired tasks to zero allows this construct to build, otherwise : // https://github.com/aws/aws-cdk/issues/3646#issuecomment-623919242 const { node } = this.albFargateService.service; const cfnService = node.findChild('Service'); cfnService.desiredCount = 0; } } } exports.FargateService = FargateService; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRmFyZ2F0ZUNvbnRhaW5lci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9GYXJnYXRlQ29udGFpbmVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLCtFQUE2RTtBQUM3RSw2Q0FBbUQ7QUFDbkQsdUZBQTZFO0FBQzdFLGlEQUFzRDtBQUN0RCxtRUFBcUY7QUFHckYsaURBQTZFO0FBQzdFLG1EQUErRDtBQUMvRCwyQ0FBdUM7QUFDdkMsbURBQWdEO0FBRWhEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBc0JHO0FBQ0gsTUFBYSxjQUFlLFNBQVEsc0JBQVM7SUFTM0MsWUFDRSxLQUFnQixFQUNoQixFQUFVLEVBQ1YsV0FBbUIsRUFDbkIsSUFBaUIsRUFDakIsTUFBZSxFQUNmLGNBQTBDLEVBQUUsRUFDNUMsYUFBcUMsU0FBUyxFQUM5QyxNQUFjLFFBQVEsRUFDdEIsTUFBdUIsU0FBUyxFQUNoQyxNQUFjLEdBQUcsRUFDakIsU0FBaUIsSUFBSSxFQUNyQixZQUFvQixDQUFDLEVBQ3JCLFlBQXFCLEtBQUssRUFDMUIsZ0JBQXdCLElBQUk7UUFFNUIsS0FBSyxDQUFDLEtBQUssRUFBRSxHQUFHLEVBQUUsZ0JBQWdCLENBQUMsQ0FBQztRQUVwQyx1QkFBdUI7UUFDdkIsSUFBSSxDQUFDLFVBQVUsR0FBRyxVQUFVLElBQUksSUFBSSw2QkFBYSxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztRQUM3RCxnR0FBZ0c7UUFDaEcsMkZBQTJGO1FBQzNGLDRFQUE0RTtRQUM1RSxvSUFBb0k7UUFDcEksSUFBSSxDQUFDLEdBQUcsR0FBRyxHQUFHLElBQUksSUFBSSxhQUFHLENBQUMsS0FBSyxFQUFFLEdBQUcsRUFBRSxLQUFLLEVBQUU7WUFDM0MsV0FBVyxFQUFFLENBQUM7WUFDZCxtQkFBbUIsRUFBRSxDQUFDO29CQUNwQixJQUFJLEVBQUUsRUFBRTtvQkFDUixVQUFVLEVBQUUsb0JBQVUsQ0FBQyxNQUFNO2lCQUM5QixDQUFDO1NBQ0gsQ0FBQyxDQUFDO1FBRUgsVUFBVTtRQUNWLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxJQUFJLHdEQUFxQyxDQUNoRSxLQUFLLEVBQ0wsR0FBRyxFQUFFLG1CQUFtQixFQUN4QjtZQUNFLGdCQUFnQixFQUFFLEVBQUU7WUFDcEIsV0FBVztZQUNYLFVBQVUsRUFBRSxJQUFJO1lBQ2hCLFVBQVUsRUFBRSxNQUFNLElBQUksSUFBSSxDQUFDLFFBQVE7WUFDbkMsV0FBVyxFQUFFLElBQUksZ0RBQXVCLENBQUMsS0FBSyxFQUFFLEVBQUUsRUFBRTtnQkFDbEQsVUFBVSxFQUFFLE1BQU0sSUFBSSxJQUFJLENBQUMsUUFBUTtnQkFDbkMsVUFBVSxFQUFFLElBQUk7YUFDakIsQ0FBQztZQUNGLFFBQVEsRUFBRSxnREFBbUIsQ0FBQyxLQUFLO1lBQ25DLEdBQUc7WUFDSCxjQUFjLEVBQUUsTUFBTTtZQUN0QixnQkFBZ0IsRUFBRTtnQkFDaEIsYUFBYSxFQUFFLEVBQUU7Z0JBQ2pCLEtBQUssRUFBRSx3QkFBYyxDQUFDLGlCQUFpQixDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsR0FBRyxDQUFDO2dCQUM3RCxhQUFhO2dCQUNiLFdBQVc7Z0JBQ1gsU0FBUyxFQUFFLG9CQUFVLENBQUMsT0FBTyxDQUFDO29CQUM1QixZQUFZLEVBQUUsRUFBRTtvQkFDaEIsUUFBUSxFQUFFLElBQUksbUJBQVEsQ0FBQyxLQUFLLEVBQUUsR0FBRyxFQUFFLFVBQVUsRUFBRTt3QkFDN0MsNERBQTREO3dCQUM1RCw2Q0FBNkM7d0JBQzdDLFlBQVksRUFBRSxJQUFJLG1CQUFLLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxDQUFDLFNBQVMsUUFBUSxFQUFFLEVBQUU7d0JBQ3ZELGFBQWEsRUFBRSwyQkFBYSxDQUFDLE9BQU87d0JBQ3BDLFNBQVMsRUFBRSx3QkFBYSxDQUFDLFlBQVk7cUJBQ3RDLENBQUM7aUJBQ0gsQ0FBQzthQUNIO1lBQ0QsWUFBWSxFQUFFLFNBQVM7WUFDdkIsR0FBRyxFQUFFLElBQUksQ0FBQyxHQUFHO1lBQ2IsaUlBQWlJO1lBQ2pJLGNBQWMsRUFBRSxJQUFJO1NBQ3JCLENBQ0YsQ0FBQztRQUNGLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxZQUFZLENBQUMsV0FBVyxFQUFFLENBQUMsQ0FBQyxnQkFBZ0I7UUFFbkUsSUFBSSxTQUFTLEVBQUUsQ0FBQztZQUNkLDBJQUEwSTtZQUMxSSxvRUFBb0U7WUFDcEUsTUFBTSxFQUFFLElBQUksRUFBRSxHQUFHLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxPQUFPLENBQUM7WUFDaEQsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxTQUFTLENBQWUsQ0FBQztZQUMzRCxVQUFVLENBQUMsWUFBWSxHQUFHLENBQUMsQ0FBQztRQUM5QixDQUFDO0lBQ0gsQ0FBQztDQUNGO0FBekZELHdDQXlGQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IERuc1ZhbGlkYXRlZENlcnRpZmljYXRlIH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWNlcnRpZmljYXRlbWFuYWdlcic7XG5pbXBvcnQgeyBSZW1vdmFsUG9saWN5LCBTdGFjayB9IGZyb20gJ2F3cy1jZGstbGliJztcbmltcG9ydCB7IEFwcGxpY2F0aW9uUHJvdG9jb2wgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtZWxhc3RpY2xvYWRiYWxhbmNpbmd2Mic7XG5pbXBvcnQgeyBTdWJuZXRUeXBlLCBWcGMgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtZWMyJztcbmltcG9ydCB7IEFwcGxpY2F0aW9uTG9hZEJhbGFuY2VkRmFyZ2F0ZVNlcnZpY2UgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtZWNzLXBhdHRlcm5zJztcbmltcG9ydCB7IFJlcG9zaXRvcnkgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtZWNyJztcbmltcG9ydCB7IElIb3N0ZWRab25lIH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLXJvdXRlNTMnO1xuaW1wb3J0IHsgQ2ZuU2VydmljZSwgQ29udGFpbmVySW1hZ2UsIExvZ0RyaXZlcnMgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtZWNzJztcbmltcG9ydCB7IExvZ0dyb3VwLCBSZXRlbnRpb25EYXlzIH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWxvZ3MnO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSAnY29uc3RydWN0cyc7XG5pbXBvcnQgeyBFY3JSZXBvc2l0b3J5IH0gZnJvbSAnLi9FY3JSZXBvc2l0b3J5JztcblxuLyoqXG4gKiBCdWlsZHMgYW4gQXBwbGljYXRpb25Mb2FkQmFsYW5jZWRGYXJnYXRlU2VydmljZSB0aGF0IHJ1bnMgYSBjb250YWluZXIgb24gRUNTIEZhcmdhdGUuXG4gKlxuICogV2FybmluZyEgVGhpcyBwYXR0ZXJuIGlzIG5vdCAncHVyZScgc2VydmVybGVzcyEgSXQgZ2VubmVyYXRlcyAyNHg3IHJ1bm5pbmcgY29zdHMgcGVyIGNvbnRhaW5lciAocmF0aGVyIHRoYW4gYmVpbmcgYmlsbGVkIG9uIHRyYWZmaWMvc3RvcmFnZSkuXG4gKlxuICogV2FybmluZyEgSWYgeW91IGRvbid0IHBhc3MgYSB2cGMsIHRoaXMgY29uc3RydWN0IGNyZWF0ZXMgYSB2cGMgZm9yIHlvdSBhbmQgbGltaXRzIHRoZSBudWJlciBvZiBOQVQgZ2F0ZXdheXMgdG8gMSB0byByZWR1Y2UgY29zdC4gVGhpcyBpcyBsZXNzIHJlc2lsaWVudCwgYnV0IE5BVCBnYXRld2F5cyBhcmUgY29zdGx5IVxuICpcbiAqIElmIHlvdSdkIGxpa2UgdG8gYXZvaWQgdGhpcyB0cmFkZW9vZiwgcGFzcyBpbiBhIHZwYyB5b3UndmUgY3JlYXRlZWQgdGhhdCBoYSB6ZXJvIE5BVCBnYXRld2F5cyBhbmQgaXMgY29uZmlndXJlZCB3aXRoIFByaXZhdGVFbmRwb2ludChzKSB0aGF0IHdpbGwgYWxsb3cgRUNTIHRvIHB1bGwgY29udGFpbmVyIGltYWdlcy5cbiAqXG4gKiBAcGFyYW0gc2VydmljZU5hbWUgTmFtZSBmb3IgdGhlIHNlcnZpY2VcbiAqIEBwYXJhbSB6b25lIEROUyB6b25lXG4gKiBAcGFyYW0gZG9tYWluIE9wdGlvbmFsOiBieSBkZWZhdWx0IHRoZSB6b25lIG5hbWUgd2lsbCBiZSB1c2VkIGFzIHRoZSBETlMgbmFtZSBmb3IgdGhlIHNlcnZpY2UgKGUuZy4gJ2V4YW1wbGUuY29tJykgYnV0IHlvdSBjYW4gc3BlY2lmeSBhIGRpZmZlcmVudCBkb21haW4gaGVyZSAoZS5nLiAnc3ViZG9tYWluLmV4YW1wbGUuY29tJykuXG4gKiBAcGFyYW0gZW52aXJvbm1lbnQgQW55IGVudmlyb25tZW50IHZhcmlhYmxlcyBmb3IgdGhlIGNvbnRhaW5lclxuICogQHBhcmFtIHJlcG9zaXRvcnkgT3B0aW9uYWw6IGlmIHlvdSB3YW50IHRvIHVzZSBhbiBleGlzdGluZyBjb250YWluZXIgaW1hZ2UgcmVwb3NpdG9yeVxuICogQHBhcmFtIHRhZyBPcHRpb25hbDogZGVmYXVsdHMgdG8gJ2xhdGVzdCdcbiAqIEBwYXJhbSB2cGMgT3B0aW9uYWw6IGlmIHlvdSB3YW50IHRvIHVzZSBhbiBleGlzdGluZyBWUEMuIEluIG5vdCBzZXQsIGEgdnBjIHdpbGwgYmUgY3JlYXRlZCBmb3IgeW91XG4gKiBAcGFyYW0gY3B1IE9wdGlvbmFsOiBkZWZhdWx0cyB0byA1MTJcbiAqIEBwYXJhbSBtZW1vcnkgT3B0aW9uYWw6IGRlZmF1bHRzIHRvIDEwMjRcbiAqIEBwYXJhbSB0YXNrQ291bnQgT3B0aW9uYWw6IGRlZmF1bHRzIHRvIDIgZm9yIHJlZHVuZGFuY3kuIFNldCB0byAxIGlmIHlvdSB3YW50IHRvIHJlZHVjZSBjb3N0LlxuICogQHBhcmFtIHplcm9UYXNrcyBTZXRzIHRhc2sgY291bnQgdG8gemVyby4gUGFzcyB0cnVlIGlmIHlvdSBkb24ndCBoYXZlIGFuIGltYWdlIGluIEVDUiB5ZXQsIG90aGVyd2lzZSB0aGlzIGNvbnN0cnVjdCB3aWxsIGZhaWwgdG8gYnVpbGQuXG4gKiBAcGFyYW0gY29udGFpbmVyUG9ydCBPcHRpb25hbDogZGVmYXVsdHMgdG8gMzAwMC4gVGhpcyBpcyB0aGUgcG9ydCB0aGUgYXBwbGljYXRpb24gaW4geW91ciBjb250YWluZXIgbGlzdGVucyBvbi5cbiAqIEByZXR1cm5zIERlcGx5bWVudCBkZXRhaXNcbiAqL1xuZXhwb3J0IGNsYXNzIEZhcmdhdGVTZXJ2aWNlIGV4dGVuZHMgQ29uc3RydWN0IHtcbiAgY2VydGlmaWNhdGU6IERuc1ZhbGlkYXRlZENlcnRpZmljYXRlO1xuXG4gIHJlcG9zaXRvcnk6IFJlcG9zaXRvcnk7XG5cbiAgYWxiRmFyZ2F0ZVNlcnZpY2U6IEFwcGxpY2F0aW9uTG9hZEJhbGFuY2VkRmFyZ2F0ZVNlcnZpY2U7XG5cbiAgdnBjOiBWcGM7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgc2NvcGU6IENvbnN0cnVjdCxcbiAgICBpZDogc3RyaW5nLFxuICAgIHNlcnZpY2VOYW1lOiBzdHJpbmcsXG4gICAgem9uZTogSUhvc3RlZFpvbmUsXG4gICAgZG9tYWluPzogc3RyaW5nLFxuICAgIGVudmlyb25tZW50OiB7IFtrZXk6IHN0cmluZ106IHN0cmluZzsgfSA9IHt9LFxuICAgIHJlcG9zaXRvcnk6IFJlcG9zaXRvcnkgfCB1bmRlZmluZWQgPSB1bmRlZmluZWQsXG4gICAgdGFnOiBzdHJpbmcgPSAnbGF0ZXN0JyxcbiAgICB2cGM6IFZwYyB8IHVuZGVmaW5lZCA9IHVuZGVmaW5lZCxcbiAgICBjcHU6IG51bWJlciA9IDUxMixcbiAgICBtZW1vcnk6IG51bWJlciA9IDEwMjQsXG4gICAgdGFza0NvdW50OiBudW1iZXIgPSAyLFxuICAgIHplcm9UYXNrczogYm9vbGVhbiA9IGZhbHNlLFxuICAgIGNvbnRhaW5lclBvcnQ6IG51bWJlciA9IDMwMDAsXG4gICkge1xuICAgIHN1cGVyKHNjb3BlLCBgJHtpZH1GYXJnYXRlU2VydmljZWApO1xuXG4gICAgLy8gQ29udGFpbmVyIHJlcG9zaXRvcnlcbiAgICB0aGlzLnJlcG9zaXRvcnkgPSByZXBvc2l0b3J5IHx8IG5ldyBFY3JSZXBvc2l0b3J5KHNjb3BlLCBpZCk7XG4gICAgLy8gSXQgc2VlbXMgbGlrZSBOQVQgZ2F0ZXdheXMgYXJlIGNvc3RseSwgc28gSSd2ZSBzZXQgdGhpcyB1cCB0byBhdm9pZCB0aGF0IC0gb25seSBjcmVhdGluZyBvbmUuXG4gICAgLy8gQXQgc29tZSBwb2ludCB3ZSBtYXkgd2FudCB0byBmaWd1cmUgb3V0IGEgcHJpdnRlIGVuZHBvaW50IHNvIHRoYXQgd2UgY2FuIHJldGlyZSB0aGUgTkFULlxuICAgIC8vIEJhc2VkIG9uOiBodHRwczovL3d3dy5iaW5hcnl0aGlua3RhbmsuY29tL2Jsb2cvdHJ1bHktc2VydmVybGVzcy1jb250YWluZXJcbiAgICAvLyBhbmQgaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvNjQyOTk2NjQvaG93LXRvLWNvbmZpZ3VyZS1hd3MtY2RrLWFwcGxpY2F0aW9ubG9hZGJhbGFuY2VkZmFyZ2F0ZXNlcnZpY2UtdG8tbG9nLXBhcnNlZC1qc29cbiAgICB0aGlzLnZwYyA9IHZwYyB8fCBuZXcgVnBjKHNjb3BlLCBgJHtpZH1WcGNgLCB7XG4gICAgICBuYXRHYXRld2F5czogMSxcbiAgICAgIHN1Ym5ldENvbmZpZ3VyYXRpb246IFt7XG4gICAgICAgIG5hbWU6IGlkLFxuICAgICAgICBzdWJuZXRUeXBlOiBTdWJuZXRUeXBlLlBVQkxJQyxcbiAgICAgIH1dLFxuICAgIH0pO1xuXG4gICAgLy8gRmFyZ2F0ZVxuICAgIHRoaXMuYWxiRmFyZ2F0ZVNlcnZpY2UgPSBuZXcgQXBwbGljYXRpb25Mb2FkQmFsYW5jZWRGYXJnYXRlU2VydmljZShcbiAgICAgIHNjb3BlLFxuICAgICAgYCR7aWR9QWxiRmFyZ2F0ZVNlcnZpY2VgLFxuICAgICAge1xuICAgICAgICBsb2FkQmFsYW5jZXJOYW1lOiBpZCxcbiAgICAgICAgc2VydmljZU5hbWUsXG4gICAgICAgIGRvbWFpblpvbmU6IHpvbmUsXG4gICAgICAgIGRvbWFpbk5hbWU6IGRvbWFpbiB8fCB6b25lLnpvbmVOYW1lLFxuICAgICAgICBjZXJ0aWZpY2F0ZTogbmV3IERuc1ZhbGlkYXRlZENlcnRpZmljYXRlKHNjb3BlLCBpZCwge1xuICAgICAgICAgIGRvbWFpbk5hbWU6IGRvbWFpbiB8fCB6b25lLnpvbmVOYW1lLFxuICAgICAgICAgIGhvc3RlZFpvbmU6IHpvbmUsXG4gICAgICAgIH0pLFxuICAgICAgICBwcm90b2NvbDogQXBwbGljYXRpb25Qcm90b2NvbC5IVFRQUyxcbiAgICAgICAgY3B1LFxuICAgICAgICBtZW1vcnlMaW1pdE1pQjogbWVtb3J5LFxuICAgICAgICB0YXNrSW1hZ2VPcHRpb25zOiB7XG4gICAgICAgICAgY29udGFpbmVyTmFtZTogaWQsXG4gICAgICAgICAgaW1hZ2U6IENvbnRhaW5lckltYWdlLmZyb21FY3JSZXBvc2l0b3J5KHRoaXMucmVwb3NpdG9yeSwgdGFnKSxcbiAgICAgICAgICBjb250YWluZXJQb3J0LFxuICAgICAgICAgIGVudmlyb25tZW50LFxuICAgICAgICAgIGxvZ0RyaXZlcjogTG9nRHJpdmVycy5hd3NMb2dzKHtcbiAgICAgICAgICAgIHN0cmVhbVByZWZpeDogaWQsXG4gICAgICAgICAgICBsb2dHcm91cDogbmV3IExvZ0dyb3VwKHNjb3BlLCBgJHtpZH1Mb2dHcm91cGAsIHtcbiAgICAgICAgICAgICAgLy8gRW5zdXJlIHRoZSBsb2cgZ3JvdXAgaXMgZGVsZXRlZCB3aGVuIHRoZSBzdGFjayBpcyBkZWxldGVkXG4gICAgICAgICAgICAgIC8vIGFuZCB0aGF0IGxvZ3MgYXJlbid0IHJldGFpbmVkIGluZGVmaW5pdGVseVxuICAgICAgICAgICAgICBsb2dHcm91cE5hbWU6IGAvJHtTdGFjay5vZihzY29wZSkuc3RhY2tOYW1lfS9lY3MvJHtpZH1gLFxuICAgICAgICAgICAgICByZW1vdmFsUG9saWN5OiBSZW1vdmFsUG9saWN5LkRFU1RST1ksXG4gICAgICAgICAgICAgIHJldGVudGlvbjogUmV0ZW50aW9uRGF5cy5USFJFRV9NT05USFMsXG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICB9KSxcbiAgICAgICAgfSxcbiAgICAgICAgZGVzaXJlZENvdW50OiB0YXNrQ291bnQsXG4gICAgICAgIHZwYzogdGhpcy52cGMsXG4gICAgICAgIC8vID8gaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvNjczMDEyNjgvYXdzLWZhcmdhdGUtcmVzb3VyY2Vpbml0aWFsaXphdGlvbmVycm9yLXVuYWJsZS10by1wdWxsLXNlY3JldHMtb3ItcmVnaXN0cnktYXV0aFxuICAgICAgICBhc3NpZ25QdWJsaWNJcDogdHJ1ZSxcbiAgICAgIH0sXG4gICAgKTtcbiAgICB0aGlzLmFsYkZhcmdhdGVTZXJ2aWNlLmxvYWRCYWxhbmNlci5hZGRSZWRpcmVjdCgpOyAvLyBodHRwIC0+IGh0dHBzXG5cbiAgICBpZiAoemVyb1Rhc2tzKSB7XG4gICAgICAvLyBPbiB0aGUgZmlyc3QgZGVwbG95LCB3aGVuIHRoZXJlJ3Mgbm8gaW1hZ2UgaW4gdGhlIHJlcG9zaXRvcnksIHNldHRpbmcgZGVzaXJlZCB0YXNrcyB0byB6ZXJvIGFsbG93cyB0aGlzIGNvbnN0cnVjdCB0byBidWlsZCwgb3RoZXJ3aXNlIDpcbiAgICAgIC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9hd3MvYXdzLWNkay9pc3N1ZXMvMzY0NiNpc3N1ZWNvbW1lbnQtNjIzOTE5MjQyXG4gICAgICBjb25zdCB7IG5vZGUgfSA9IHRoaXMuYWxiRmFyZ2F0ZVNlcnZpY2Uuc2VydmljZTtcbiAgICAgIGNvbnN0IGNmblNlcnZpY2UgPSBub2RlLmZpbmRDaGlsZCgnU2VydmljZScpIGFzIENmblNlcnZpY2U7XG4gICAgICBjZm5TZXJ2aWNlLmRlc2lyZWRDb3VudCA9IDA7XG4gICAgfVxuICB9XG59XG4iXX0=