UNPKG

@aws-cdk/aws-route53

Version:

The CDK Construct Library for AWS::Route53

190 lines 28.3 kB
"use strict"; var _a; Object.defineProperty(exports, "__esModule", { value: true }); exports.VpcEndpointServiceDomainName = void 0; const jsiiDeprecationWarnings = require("../.warnings.jsii.js"); const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti"); const crypto = require("crypto"); const core_1 = require("@aws-cdk/core"); const custom_resources_1 = require("@aws-cdk/custom-resources"); const lib_1 = require("../lib"); // v2 - keep this import as a separate section to reduce merge conflict when forward merging with the v2 branch. // eslint-disable-next-line const core_2 = require("@aws-cdk/core"); /** * A Private DNS configuration for a VPC endpoint service. */ class VpcEndpointServiceDomainName extends core_2.Construct { // The way this class works is by using three custom resources and a TxtRecord in conjunction // The first custom resource tells the VPC endpoint service to use the given DNS name // The VPC endpoint service will then say: // "ok, create a TXT record using these two values to prove you own the domain" // The second custom resource retrieves these two values from the service // The TxtRecord is created from these two values // The third custom resource tells the VPC Endpoint Service to verify the domain ownership constructor(scope, id, props) { super(scope, id); try { jsiiDeprecationWarnings._aws_cdk_aws_route53_VpcEndpointServiceDomainNameProps(props); } catch (error) { if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { Error.captureStackTrace(error, VpcEndpointServiceDomainName); } throw error; } const serviceUniqueId = core_1.Names.nodeUniqueId(props.endpointService.node); const serviceId = props.endpointService.vpcEndpointServiceId; this.domainName = props.domainName; // Make sure a user doesn't accidentally add multiple domains this.validateProps(props); VpcEndpointServiceDomainName.endpointServicesMap[serviceUniqueId] = this.domainName; VpcEndpointServiceDomainName.endpointServices.push(props.endpointService); // Enable Private DNS on the endpoint service and retrieve the AWS-generated configuration const privateDnsConfiguration = this.getPrivateDnsConfiguration(serviceUniqueId, serviceId, this.domainName); // Tell AWS to verify that this account owns the domain attached to the service this.verifyPrivateDnsConfiguration(privateDnsConfiguration, props.publicHostedZone); // Finally, don't do any of the above before the endpoint service is created this.node.addDependency(props.endpointService); } validateProps(props) { const serviceUniqueId = core_1.Names.nodeUniqueId(props.endpointService.node); if (serviceUniqueId in VpcEndpointServiceDomainName.endpointServicesMap) { const endpoint = VpcEndpointServiceDomainName.endpointServicesMap[serviceUniqueId]; throw new Error(`Cannot create a VpcEndpointServiceDomainName for service ${serviceUniqueId}, another VpcEndpointServiceDomainName (${endpoint}) is already associated with it`); } } /** * Sets up Custom Resources to make AWS calls to set up Private DNS on an endpoint service, * returning the values to use in a TxtRecord, which AWS uses to verify domain ownership. */ getPrivateDnsConfiguration(serviceUniqueId, serviceId, privateDnsName) { // The custom resource which tells AWS to enable Private DNS on the given service, using the given domain name // AWS will generate a name/value pair for use in a TxtRecord, which is used to verify domain ownership. const enablePrivateDnsAction = { service: 'EC2', action: 'modifyVpcEndpointServiceConfiguration', parameters: { ServiceId: serviceId, PrivateDnsName: privateDnsName, }, physicalResourceId: custom_resources_1.PhysicalResourceId.of(serviceUniqueId), }; const removePrivateDnsAction = { service: 'EC2', action: 'modifyVpcEndpointServiceConfiguration', parameters: { ServiceId: serviceId, RemovePrivateDnsName: true, }, }; const enable = new custom_resources_1.AwsCustomResource(this, 'EnableDns', { onCreate: enablePrivateDnsAction, onUpdate: enablePrivateDnsAction, onDelete: removePrivateDnsAction, policy: custom_resources_1.AwsCustomResourcePolicy.fromSdkCalls({ resources: [ core_1.Fn.join(':', [ 'arn', core_1.Stack.of(this).partition, 'ec2', core_1.Stack.of(this).region, core_1.Stack.of(this).account, core_1.Fn.join('/', [ 'vpc-endpoint-service', serviceId, ]), ]), ], }), }); // Look up the name/value pair if the domain changes, or the service changes, // which would cause the values to be different. If the unique ID changes, // the resource may be entirely recreated, so we will need to look it up again. const lookup = hashcode(core_1.Names.uniqueId(this) + serviceUniqueId + privateDnsName); // Create the custom resource to look up the name/value pair generated by AWS // after the previous API call const retrieveNameValuePairAction = { service: 'EC2', action: 'describeVpcEndpointServiceConfigurations', parameters: { ServiceIds: [serviceId], }, physicalResourceId: custom_resources_1.PhysicalResourceId.of(lookup), }; const getNames = new custom_resources_1.AwsCustomResource(this, 'GetNames', { onCreate: retrieveNameValuePairAction, onUpdate: retrieveNameValuePairAction, // describeVpcEndpointServiceConfigurations can't take an ARN for granular permissions policy: custom_resources_1.AwsCustomResourcePolicy.fromSdkCalls({ resources: custom_resources_1.AwsCustomResourcePolicy.ANY_RESOURCE, }), }); // We only want to call and get the name/value pair after we've told AWS to enable Private DNS // If we call before then, we'll get an empty pair of values. getNames.node.addDependency(enable); // Get the references to the name/value pair associated with the endpoint service const name = getNames.getResponseField('ServiceConfigurations.0.PrivateDnsNameConfiguration.Name'); const value = getNames.getResponseField('ServiceConfigurations.0.PrivateDnsNameConfiguration.Value'); return { name, value, serviceId }; } /** * Creates a Route53 entry and a Custom Resource which explicitly tells AWS to verify ownership * of the domain name attached to an endpoint service. */ verifyPrivateDnsConfiguration(config, publicHostedZone) { // Create the TXT record in the provided hosted zone const verificationRecord = new lib_1.TxtRecord(this, 'DnsVerificationRecord', { recordName: config.name, values: [config.value], zone: publicHostedZone, }); // Tell the endpoint service to verify the domain ownership const startVerificationAction = { service: 'EC2', action: 'startVpcEndpointServicePrivateDnsVerification', parameters: { ServiceId: config.serviceId, }, physicalResourceId: custom_resources_1.PhysicalResourceId.of(core_1.Fn.join(':', [config.name, config.value])), }; const startVerification = new custom_resources_1.AwsCustomResource(this, 'StartVerification', { onCreate: startVerificationAction, onUpdate: startVerificationAction, policy: custom_resources_1.AwsCustomResourcePolicy.fromSdkCalls({ resources: [ core_1.Fn.join(':', [ 'arn', core_1.Stack.of(this).partition, 'ec2', core_1.Stack.of(this).region, core_1.Stack.of(this).account, core_1.Fn.join('/', [ 'vpc-endpoint-service', config.serviceId, ]), ]), ], }), }); // Only verify after the record has been created startVerification.node.addDependency(verificationRecord); } } exports.VpcEndpointServiceDomainName = VpcEndpointServiceDomainName; _a = JSII_RTTI_SYMBOL_1; VpcEndpointServiceDomainName[_a] = { fqn: "@aws-cdk/aws-route53.VpcEndpointServiceDomainName", version: "1.197.0" }; // Track all domain names created, so someone doesn't accidentally associate two domains with a single service VpcEndpointServiceDomainName.endpointServices = []; // Track all domain names created, so someone doesn't accidentally associate two domains with a single service VpcEndpointServiceDomainName.endpointServicesMap = {}; /** * Hash a string */ function hashcode(s) { const hash = crypto.createHash('md5'); hash.update(s); return hash.digest('hex'); } ; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidnBjLWVuZHBvaW50LXNlcnZpY2UtZG9tYWluLW5hbWUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJ2cGMtZW5kcG9pbnQtc2VydmljZS1kb21haW4tbmFtZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSxpQ0FBaUM7QUFFakMsd0NBQWlEO0FBQ2pELGdFQUEyRztBQUUzRyxnQ0FBc0Q7QUFFdEQsZ0hBQWdIO0FBQ2hILDJCQUEyQjtBQUMzQix3Q0FBMkQ7QUE0QjNEOztHQUVHO0FBQ0gsTUFBYSw0QkFBNkIsU0FBUSxnQkFBYTtJQWE3RCw2RkFBNkY7SUFDN0YscUZBQXFGO0lBQ3JGLDBDQUEwQztJQUMxQywrRUFBK0U7SUFDL0UseUVBQXlFO0lBQ3pFLGlEQUFpRDtJQUNqRCwwRkFBMEY7SUFDMUYsWUFBWSxLQUFnQixFQUFFLEVBQVUsRUFBRSxLQUF3QztRQUNoRixLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDOzs7Ozs7K0NBckJSLDRCQUE0Qjs7OztRQXVCckMsTUFBTSxlQUFlLEdBQUcsWUFBSyxDQUFDLFlBQVksQ0FBQyxLQUFLLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3ZFLE1BQU0sU0FBUyxHQUFHLEtBQUssQ0FBQyxlQUFlLENBQUMsb0JBQW9CLENBQUM7UUFDN0QsSUFBSSxDQUFDLFVBQVUsR0FBRyxLQUFLLENBQUMsVUFBVSxDQUFDO1FBRW5DLDZEQUE2RDtRQUM3RCxJQUFJLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBRTFCLDRCQUE0QixDQUFDLG1CQUFtQixDQUFDLGVBQWUsQ0FBQyxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUM7UUFDcEYsNEJBQTRCLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxlQUFlLENBQUMsQ0FBQztRQUUxRSwwRkFBMEY7UUFDMUYsTUFBTSx1QkFBdUIsR0FBRyxJQUFJLENBQUMsMEJBQTBCLENBQUMsZUFBZSxF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cm9tICdjcnlwdG8nO1xuaW1wb3J0IHsgSVZwY0VuZHBvaW50U2VydmljZSB9IGZyb20gJ0Bhd3MtY2RrL2F3cy1lYzInO1xuaW1wb3J0IHsgRm4sIE5hbWVzLCBTdGFjayB9IGZyb20gJ0Bhd3MtY2RrL2NvcmUnO1xuaW1wb3J0IHsgQXdzQ3VzdG9tUmVzb3VyY2UsIEF3c0N1c3RvbVJlc291cmNlUG9saWN5LCBQaHlzaWNhbFJlc291cmNlSWQgfSBmcm9tICdAYXdzLWNkay9jdXN0b20tcmVzb3VyY2VzJztcbmltcG9ydCB7IENvbnN0cnVjdCB9IGZyb20gJ2NvbnN0cnVjdHMnO1xuaW1wb3J0IHsgSVB1YmxpY0hvc3RlZFpvbmUsIFR4dFJlY29yZCB9IGZyb20gJy4uL2xpYic7XG5cbi8vIHYyIC0ga2VlcCB0aGlzIGltcG9ydCBhcyBhIHNlcGFyYXRlIHNlY3Rpb24gdG8gcmVkdWNlIG1lcmdlIGNvbmZsaWN0IHdoZW4gZm9yd2FyZCBtZXJnaW5nIHdpdGggdGhlIHYyIGJyYW5jaC5cbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZVxuaW1wb3J0IHsgQ29uc3RydWN0IGFzIENvcmVDb25zdHJ1Y3QgfSBmcm9tICdAYXdzLWNkay9jb3JlJztcblxuLyoqXG4gKiBQcm9wZXJ0aWVzIHRvIGNvbmZpZ3VyZSBhIFZQQyBFbmRwb2ludCBTZXJ2aWNlIGRvbWFpbiBuYW1lXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgVnBjRW5kcG9pbnRTZXJ2aWNlRG9tYWluTmFtZVByb3BzIHtcblxuICAvKipcbiAgICogVGhlIFZQQyBFbmRwb2ludCBTZXJ2aWNlIHRvIGNvbmZpZ3VyZSBQcml2YXRlIEROUyBmb3JcbiAgICovXG4gIHJlYWRvbmx5IGVuZHBvaW50U2VydmljZTogSVZwY0VuZHBvaW50U2VydmljZTtcblxuICAvKipcbiAgICogVGhlIGRvbWFpbiBuYW1lIHRvIHVzZS5cbiAgICpcbiAgICogVGhpcyBkb21haW4gbmFtZSBtdXN0IGJlIG93bmVkIGJ5IHRoaXMgYWNjb3VudCAocmVnaXN0ZXJlZCB0aHJvdWdoIFJvdXRlNTMpLFxuICAgKiBvciBkZWxlZ2F0ZWQgdG8gdGhpcyBhY2NvdW50LiBEb21haW4gb3duZXJzaGlwIHdpbGwgYmUgdmVyaWZpZWQgYnkgQVdTIGJlZm9yZVxuICAgKiBwcml2YXRlIEROUyBjYW4gYmUgdXNlZC5cbiAgICogQHNlZSBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vdnBjL2xhdGVzdC91c2VyZ3VpZGUvZW5kcG9pbnQtc2VydmljZXMtZG5zLXZhbGlkYXRpb24uaHRtbFxuICAgKi9cbiAgcmVhZG9ubHkgZG9tYWluTmFtZTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgcHVibGljIGhvc3RlZCB6b25lIHRvIHVzZSBmb3IgdGhlIGRvbWFpbi5cbiAgICovXG4gIHJlYWRvbmx5IHB1YmxpY0hvc3RlZFpvbmU6IElQdWJsaWNIb3N0ZWRab25lO1xufVxuXG4vKipcbiAqIEEgUHJpdmF0ZSBETlMgY29uZmlndXJhdGlvbiBmb3IgYSBWUEMgZW5kcG9pbnQgc2VydmljZS5cbiAqL1xuZXhwb3J0IGNsYXNzIFZwY0VuZHBvaW50U2VydmljZURvbWFpbk5hbWUgZXh0ZW5kcyBDb3JlQ29uc3RydWN0IHtcblxuICAvLyBUcmFjayBhbGwgZG9tYWluIG5hbWVzIGNyZWF0ZWQsIHNvIHNvbWVvbmUgZG9lc24ndCBhY2NpZGVudGFsbHkgYXNzb2NpYXRlIHR3byBkb21haW5zIHdpdGggYSBzaW5nbGUgc2VydmljZVxuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBlbmRwb2ludFNlcnZpY2VzOiBJVnBjRW5kcG9pbnRTZXJ2aWNlW10gPSBbXTtcblxuICAvLyBUcmFjayBhbGwgZG9tYWluIG5hbWVzIGNyZWF0ZWQsIHNvIHNvbWVvbmUgZG9lc24ndCBhY2NpZGVudGFsbHkgYXNzb2NpYXRlIHR3byBkb21haW5zIHdpdGggYSBzaW5nbGUgc2VydmljZVxuICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBlbmRwb2ludFNlcnZpY2VzTWFwOiB7IFtlbmRwb2ludFNlcnZpY2U6IHN0cmluZ106IHN0cmluZ30gPSB7fTtcblxuICAvKipcbiAgICogVGhlIGRvbWFpbiBuYW1lIGFzc29jaWF0ZWQgd2l0aCB0aGUgcHJpdmF0ZSBETlMgY29uZmlndXJhdGlvblxuICAgKi9cbiAgcHVibGljIGRvbWFpbk5hbWU6IHN0cmluZztcblxuICAvLyBUaGUgd2F5IHRoaXMgY2xhc3Mgd29ya3MgaXMgYnkgdXNpbmcgdGhyZWUgY3VzdG9tIHJlc291cmNlcyBhbmQgYSBUeHRSZWNvcmQgaW4gY29uanVuY3Rpb25cbiAgLy8gVGhlIGZpcnN0IGN1c3RvbSByZXNvdXJjZSB0ZWxscyB0aGUgVlBDIGVuZHBvaW50IHNlcnZpY2UgdG8gdXNlIHRoZSBnaXZlbiBETlMgbmFtZVxuICAvLyBUaGUgVlBDIGVuZHBvaW50IHNlcnZpY2Ugd2lsbCB0aGVuIHNheTpcbiAgLy8gXCJvaywgY3JlYXRlIGEgVFhUIHJlY29yZCB1c2luZyB0aGVzZSB0d28gdmFsdWVzIHRvIHByb3ZlIHlvdSBvd24gdGhlIGRvbWFpblwiXG4gIC8vIFRoZSBzZWNvbmQgY3VzdG9tIHJlc291cmNlIHJldHJpZXZlcyB0aGVzZSB0d28gdmFsdWVzIGZyb20gdGhlIHNlcnZpY2VcbiAgLy8gVGhlIFR4dFJlY29yZCBpcyBjcmVhdGVkIGZyb20gdGhlc2UgdHdvIHZhbHVlc1xuICAvLyBUaGUgdGhpcmQgY3VzdG9tIHJlc291cmNlIHRlbGxzIHRoZSBWUEMgRW5kcG9pbnQgU2VydmljZSB0byB2ZXJpZnkgdGhlIGRvbWFpbiBvd25lcnNoaXBcbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM6IFZwY0VuZHBvaW50U2VydmljZURvbWFpbk5hbWVQcm9wcykge1xuICAgIHN1cGVyKHNjb3BlLCBpZCk7XG5cbiAgICBjb25zdCBzZXJ2aWNlVW5pcXVlSWQgPSBOYW1lcy5ub2RlVW5pcXVlSWQocHJvcHMuZW5kcG9pbnRTZXJ2aWNlLm5vZGUpO1xuICAgIGNvbnN0IHNlcnZpY2VJZCA9IHByb3BzLmVuZHBvaW50U2VydmljZS52cGNFbmRwb2ludFNlcnZpY2VJZDtcbiAgICB0aGlzLmRvbWFpbk5hbWUgPSBwcm9wcy5kb21haW5OYW1lO1xuXG4gICAgLy8gTWFrZSBzdXJlIGEgdXNlciBkb2Vzbid0IGFjY2lkZW50YWxseSBhZGQgbXVsdGlwbGUgZG9tYWluc1xuICAgIHRoaXMudmFsaWRhdGVQcm9wcyhwcm9wcyk7XG5cbiAgICBWcGNFbmRwb2ludFNlcnZpY2VEb21haW5OYW1lLmVuZHBvaW50U2VydmljZXNNYXBbc2VydmljZVVuaXF1ZUlkXSA9IHRoaXMuZG9tYWluTmFtZTtcbiAgICBWcGNFbmRwb2ludFNlcnZpY2VEb21haW5OYW1lLmVuZHBvaW50U2VydmljZXMucHVzaChwcm9wcy5lbmRwb2ludFNlcnZpY2UpO1xuXG4gICAgLy8gRW5hYmxlIFByaXZhdGUgRE5TIG9uIHRoZSBlbmRwb2ludCBzZXJ2aWNlIGFuZCByZXRyaWV2ZSB0aGUgQVdTLWdlbmVyYXRlZCBjb25maWd1cmF0aW9uXG4gICAgY29uc3QgcHJpdmF0ZURuc0NvbmZpZ3VyYXRpb24gPSB0aGlzLmdldFByaXZhdGVEbnNDb25maWd1cmF0aW9uKHNlcnZpY2VVbmlxdWVJZCwgc2VydmljZUlkLCB0aGlzLmRvbWFpbk5hbWUpO1xuXG4gICAgLy8gVGVsbCBBV1MgdG8gdmVyaWZ5IHRoYXQgdGhpcyBhY2NvdW50IG93bnMgdGhlIGRvbWFpbiBhdHRhY2hlZCB0byB0aGUgc2VydmljZVxuICAgIHRoaXMudmVyaWZ5UHJpdmF0ZURuc0NvbmZpZ3VyYXRpb24ocHJpdmF0ZURuc0NvbmZpZ3VyYXRpb24sIHByb3BzLnB1YmxpY0hvc3RlZFpvbmUpO1xuXG4gICAgLy8gRmluYWxseSwgZG9uJ3QgZG8gYW55IG9mIHRoZSBhYm92ZSBiZWZvcmUgdGhlIGVuZHBvaW50IHNlcnZpY2UgaXMgY3JlYXRlZFxuICAgIHRoaXMubm9kZS5hZGREZXBlbmRlbmN5KHByb3BzLmVuZHBvaW50U2VydmljZSk7XG4gIH1cblxuICBwcml2YXRlIHZhbGlkYXRlUHJvcHMocHJvcHM6IFZwY0VuZHBvaW50U2VydmljZURvbWFpbk5hbWVQcm9wcyk6IHZvaWQge1xuICAgIGNvbnN0IHNlcnZpY2VVbmlxdWVJZCA9IE5hbWVzLm5vZGVVbmlxdWVJZChwcm9wcy5lbmRwb2ludFNlcnZpY2Uubm9kZSk7XG4gICAgaWYgKHNlcnZpY2VVbmlxdWVJZCBpbiBWcGNFbmRwb2ludFNlcnZpY2VEb21haW5OYW1lLmVuZHBvaW50U2VydmljZXNNYXApIHtcbiAgICAgIGNvbnN0IGVuZHBvaW50ID0gVnBjRW5kcG9pbnRTZXJ2aWNlRG9tYWluTmFtZS5lbmRwb2ludFNlcnZpY2VzTWFwW3NlcnZpY2VVbmlxdWVJZF07XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBDYW5ub3QgY3JlYXRlIGEgVnBjRW5kcG9pbnRTZXJ2aWNlRG9tYWluTmFtZSBmb3Igc2VydmljZSAke3NlcnZpY2VVbmlxdWVJZH0sIGFub3RoZXIgVnBjRW5kcG9pbnRTZXJ2aWNlRG9tYWluTmFtZSAoJHtlbmRwb2ludH0pIGlzIGFscmVhZHkgYXNzb2NpYXRlZCB3aXRoIGl0YCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFNldHMgdXAgQ3VzdG9tIFJlc291cmNlcyB0byBtYWtlIEFXUyBjYWxscyB0byBzZXQgdXAgUHJpdmF0ZSBETlMgb24gYW4gZW5kcG9pbnQgc2VydmljZSxcbiAgICogcmV0dXJuaW5nIHRoZSB2YWx1ZXMgdG8gdXNlIGluIGEgVHh0UmVjb3JkLCB3aGljaCBBV1MgdXNlcyB0byB2ZXJpZnkgZG9tYWluIG93bmVyc2hpcC5cbiAgICovXG4gIHByaXZhdGUgZ2V0UHJpdmF0ZURuc0NvbmZpZ3VyYXRpb24oc2VydmljZVVuaXF1ZUlkOiBzdHJpbmcsIHNlcnZpY2VJZDogc3RyaW5nLCBwcml2YXRlRG5zTmFtZTogc3RyaW5nKTogUHJpdmF0ZURuc0NvbmZpZ3VyYXRpb24ge1xuXG4gICAgLy8gVGhlIGN1c3RvbSByZXNvdXJjZSB3aGljaCB0ZWxscyBBV1MgdG8gZW5hYmxlIFByaXZhdGUgRE5TIG9uIHRoZSBnaXZlbiBzZXJ2aWNlLCB1c2luZyB0aGUgZ2l2ZW4gZG9tYWluIG5hbWVcbiAgICAvLyBBV1Mgd2lsbCBnZW5lcmF0ZSBhIG5hbWUvdmFsdWUgcGFpciBmb3IgdXNlIGluIGEgVHh0UmVjb3JkLCB3aGljaCBpcyB1c2VkIHRvIHZlcmlmeSBkb21haW4gb3duZXJzaGlwLlxuICAgIGNvbnN0IGVuYWJsZVByaXZhdGVEbnNBY3Rpb24gPSB7XG4gICAgICBzZXJ2aWNlOiAnRUMyJyxcbiAgICAgIGFjdGlvbjogJ21vZGlmeVZwY0VuZHBvaW50U2VydmljZUNvbmZpZ3VyYXRpb24nLFxuICAgICAgcGFyYW1ldGVyczoge1xuICAgICAgICBTZXJ2aWNlSWQ6IHNlcnZpY2VJZCxcbiAgICAgICAgUHJpdmF0ZURuc05hbWU6IHByaXZhdGVEbnNOYW1lLFxuICAgICAgfSxcbiAgICAgIHBoeXNpY2FsUmVzb3VyY2VJZDogUGh5c2ljYWxSZXNvdXJjZUlkLm9mKHNlcnZpY2VVbmlxdWVJZCksXG4gICAgfTtcbiAgICBjb25zdCByZW1vdmVQcml2YXRlRG5zQWN0aW9uID0ge1xuICAgICAgc2VydmljZTogJ0VDMicsXG4gICAgICBhY3Rpb246ICdtb2RpZnlWcGNFbmRwb2ludFNlcnZpY2VDb25maWd1cmF0aW9uJyxcbiAgICAgIHBhcmFtZXRlcnM6IHtcbiAgICAgICAgU2VydmljZUlkOiBzZXJ2aWNlSWQsXG4gICAgICAgIFJlbW92ZVByaXZhdGVEbnNOYW1lOiB0cnVlLFxuICAgICAgfSxcbiAgICB9O1xuICAgIGNvbnN0IGVuYWJsZSA9IG5ldyBBd3NDdXN0b21SZXNvdXJjZSh0aGlzLCAnRW5hYmxlRG5zJywge1xuICAgICAgb25DcmVhdGU6IGVuYWJsZVByaXZhdGVEbnNBY3Rpb24sXG4gICAgICBvblVwZGF0ZTogZW5hYmxlUHJpdmF0ZURuc0FjdGlvbixcbiAgICAgIG9uRGVsZXRlOiByZW1vdmVQcml2YXRlRG5zQWN0aW9uLFxuICAgICAgcG9saWN5OiBBd3NDdXN0b21SZXNvdXJjZVBvbGljeS5mcm9tU2RrQ2FsbHMoe1xuICAgICAgICByZXNvdXJjZXM6IFtcbiAgICAgICAgICBGbi5qb2luKCc6JywgW1xuICAgICAgICAgICAgJ2FybicsXG4gICAgICAgICAgICBTdGFjay5vZih0aGlzKS5wYXJ0aXRpb24sXG4gICAgICAgICAgICAnZWMyJyxcbiAgICAgICAgICAgIFN0YWNrLm9mKHRoaXMpLnJlZ2lvbixcbiAgICAgICAgICAgIFN0YWNrLm9mKHRoaXMpLmFjY291bnQsXG4gICAgICAgICAgICBGbi5qb2luKCcvJywgW1xuICAgICAgICAgICAgICAndnBjLWVuZHBvaW50LXNlcnZpY2UnLFxuICAgICAgICAgICAgICBzZXJ2aWNlSWQsXG4gICAgICAgICAgICBdKSxcbiAgICAgICAgICBdKSxcbiAgICAgICAgXSxcbiAgICAgIH0pLFxuICAgIH0pO1xuXG4gICAgLy8gTG9vayB1cCB0aGUgbmFtZS92YWx1ZSBwYWlyIGlmIHRoZSBkb21haW4gY2hhbmdlcywgb3IgdGhlIHNlcnZpY2UgY2hhbmdlcyxcbiAgICAvLyB3aGljaCB3b3VsZCBjYXVzZSB0aGUgdmFsdWVzIHRvIGJlIGRpZmZlcmVudC4gSWYgdGhlIHVuaXF1ZSBJRCBjaGFuZ2VzLFxuICAgIC8vIHRoZSByZXNvdXJjZSBtYXkgYmUgZW50aXJlbHkgcmVjcmVhdGVkLCBzbyB3ZSB3aWxsIG5lZWQgdG8gbG9vayBpdCB1cCBhZ2Fpbi5cbiAgICBjb25zdCBsb29rdXAgPSBoYXNoY29kZShOYW1lcy51bmlxdWVJZCh0aGlzKSArIHNlcnZpY2VVbmlxdWVJZCArIHByaXZhdGVEbnNOYW1lKTtcblxuICAgIC8vIENyZWF0ZSB0aGUgY3VzdG9tIHJlc291cmNlIHRvIGxvb2sgdXAgdGhlIG5hbWUvdmFsdWUgcGFpciBnZW5lcmF0ZWQgYnkgQVdTXG4gICAgLy8gYWZ0ZXIgdGhlIHByZXZpb3VzIEFQSSBjYWxsXG4gICAgY29uc3QgcmV0cmlldmVOYW1lVmFsdWVQYWlyQWN0aW9uID0ge1xuICAgICAgc2VydmljZTogJ0VDMicsXG4gICAgICBhY3Rpb246ICdkZXNjcmliZVZwY0VuZHBvaW50U2VydmljZUNvbmZpZ3VyYXRpb25zJyxcbiAgICAgIHBhcmFtZXRlcnM6IHtcbiAgICAgICAgU2VydmljZUlkczogW3NlcnZpY2VJZF0sXG4gICAgICB9LFxuICAgICAgcGh5c2ljYWxSZXNvdXJjZUlkOiBQaHlzaWNhbFJlc291cmNlSWQub2YobG9va3VwKSxcbiAgICB9O1xuICAgIGNvbnN0IGdldE5hbWVzID0gbmV3IEF3c0N1c3RvbVJlc291cmNlKHRoaXMsICdHZXROYW1lcycsIHtcbiAgICAgIG9uQ3JlYXRlOiByZXRyaWV2ZU5hbWVWYWx1ZVBhaXJBY3Rpb24sXG4gICAgICBvblVwZGF0ZTogcmV0cmlldmVOYW1lVmFsdWVQYWlyQWN0aW9uLFxuICAgICAgLy8gZGVzY3JpYmVWcGNFbmRwb2ludFNlcnZpY2VDb25maWd1cmF0aW9ucyBjYW4ndCB0YWtlIGFuIEFSTiBmb3IgZ3JhbnVsYXIgcGVybWlzc2lvbnNcbiAgICAgIHBvbGljeTogQXdzQ3VzdG9tUmVzb3VyY2VQb2xpY3kuZnJvbVNka0NhbGxzKHtcbiAgICAgICAgcmVzb3VyY2VzOiBBd3NDdXN0b21SZXNvdXJjZVBvbGljeS5BTllfUkVTT1VSQ0UsXG4gICAgICB9KSxcbiAgICB9KTtcblxuICAgIC8vIFdlIG9ubHkgd2FudCB0byBjYWxsIGFuZCBnZXQgdGhlIG5hbWUvdmFsdWUgcGFpciBhZnRlciB3ZSd2ZSB0b2xkIEFXUyB0byBlbmFibGUgUHJpdmF0ZSBETlNcbiAgICAvLyBJZiB3ZSBjYWxsIGJlZm9yZSB0aGVuLCB3ZSdsbCBnZXQgYW4gZW1wdHkgcGFpciBvZiB2YWx1ZXMuXG4gICAgZ2V0TmFtZXMubm9kZS5hZGREZXBlbmRlbmN5KGVuYWJsZSk7XG5cbiAgICAvLyBHZXQgdGhlIHJlZmVyZW5jZXMgdG8gdGhlIG5hbWUvdmFsdWUgcGFpciBhc3NvY2lhdGVkIHdpdGggdGhlIGVuZHBvaW50IHNlcnZpY2VcbiAgICBjb25zdCBuYW1lID0gZ2V0TmFtZXMuZ2V0UmVzcG9uc2VGaWVsZCgnU2VydmljZUNvbmZpZ3VyYXRpb25zLjAuUHJpdmF0ZURuc05hbWVDb25maWd1cmF0aW9uLk5hbWUnKTtcbiAgICBjb25zdCB2YWx1ZSA9IGdldE5hbWVzLmdldFJlc3BvbnNlRmllbGQoJ1NlcnZpY2VDb25maWd1cmF0aW9ucy4wLlByaXZhdGVEbnNOYW1lQ29uZmlndXJhdGlvbi5WYWx1ZScpO1xuXG4gICAgcmV0dXJuIHsgbmFtZSwgdmFsdWUsIHNlcnZpY2VJZCB9O1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgYSBSb3V0ZTUzIGVudHJ5IGFuZCBhIEN1c3RvbSBSZXNvdXJjZSB3aGljaCBleHBsaWNpdGx5IHRlbGxzIEFXUyB0byB2ZXJpZnkgb3duZXJzaGlwXG4gICAqIG9mIHRoZSBkb21haW4gbmFtZSBhdHRhY2hlZCB0byBhbiBlbmRwb2ludCBzZXJ2aWNlLlxuICAgKi9cbiAgcHJpdmF0ZSB2ZXJpZnlQcml2YXRlRG5zQ29uZmlndXJhdGlvbihjb25maWc6IFByaXZhdGVEbnNDb25maWd1cmF0aW9uLCBwdWJsaWNIb3N0ZWRab25lOiBJUHVibGljSG9zdGVkWm9uZSkge1xuICAgIC8vIENyZWF0ZSB0aGUgVFhUIHJlY29yZCBpbiB0aGUgcHJvdmlkZWQgaG9zdGVkIHpvbmVcbiAgICBjb25zdCB2ZXJpZmljYXRpb25SZWNvcmQgPSBuZXcgVHh0UmVjb3JkKHRoaXMsICdEbnNWZXJpZmljYXRpb25SZWNvcmQnLCB7XG4gICAgICByZWNvcmROYW1lOiBjb25maWcubmFtZSxcbiAgICAgIHZhbHVlczogW2NvbmZpZy52YWx1ZV0sXG4gICAgICB6b25lOiBwdWJsaWNIb3N0ZWRab25lLFxuICAgIH0pO1xuXG4gICAgLy8gVGVsbCB0aGUgZW5kcG9pbnQgc2VydmljZSB0byB2ZXJpZnkgdGhlIGRvbWFpbiBvd25lcnNoaXBcbiAgICBjb25zdCBzdGFydFZlcmlmaWNhdGlvbkFjdGlvbiA9IHtcbiAgICAgIHNlcnZpY2U6ICdFQzInLFxuICAgICAgYWN0aW9uOiAnc3RhcnRWcGNFbmRwb2ludFNlcnZpY2VQcml2YXRlRG5zVmVyaWZpY2F0aW9uJyxcbiAgICAgIHBhcmFtZXRlcnM6IHtcbiAgICAgICAgU2VydmljZUlkOiBjb25maWcuc2VydmljZUlkLFxuICAgICAgfSxcbiAgICAgIHBoeXNpY2FsUmVzb3VyY2VJZDogUGh5c2ljYWxSZXNvdXJjZUlkLm9mKEZuLmpvaW4oJzonLCBbY29uZmlnLm5hbWUsIGNvbmZpZy52YWx1ZV0pKSxcbiAgICB9O1xuICAgIGNvbnN0IHN0YXJ0VmVyaWZpY2F0aW9uID0gbmV3IEF3c0N1c3RvbVJlc291cmNlKHRoaXMsICdTdGFydFZlcmlmaWNhdGlvbicsIHtcbiAgICAgIG9uQ3JlYXRlOiBzdGFydFZlcmlmaWNhdGlvbkFjdGlvbixcbiAgICAgIG9uVXBkYXRlOiBzdGFydFZlcmlmaWNhdGlvbkFjdGlvbixcbiAgICAgIHBvbGljeTogQXdzQ3VzdG9tUmVzb3VyY2VQb2xpY3kuZnJvbVNka0NhbGxzKHtcbiAgICAgICAgcmVzb3VyY2VzOiBbXG4gICAgICAgICAgRm4uam9pbignOicsIFtcbiAgICAgICAgICAgICdhcm4nLFxuICAgICAgICAgICAgU3RhY2sub2YodGhpcykucGFydGl0aW9uLFxuICAgICAgICAgICAgJ2VjMicsXG4gICAgICAgICAgICBTdGFjay5vZih0aGlzKS5yZWdpb24sXG4gICAgICAgICAgICBTdGFjay5vZih0aGlzKS5hY2NvdW50LFxuICAgICAgICAgICAgRm4uam9pbignLycsIFtcbiAgICAgICAgICAgICAgJ3ZwYy1lbmRwb2ludC1zZXJ2aWNlJyxcbiAgICAgICAgICAgICAgY29uZmlnLnNlcnZpY2VJZCxcbiAgICAgICAgICAgIF0pLFxuICAgICAgICAgIF0pLFxuICAgICAgICBdLFxuICAgICAgfSksXG4gICAgfSk7XG4gICAgLy8gT25seSB2ZXJpZnkgYWZ0ZXIgdGhlIHJlY29yZCBoYXMgYmVlbiBjcmVhdGVkXG4gICAgc3RhcnRWZXJpZmljYXRpb24ubm9kZS5hZGREZXBlbmRlbmN5KHZlcmlmaWNhdGlvblJlY29yZCk7XG4gIH1cbn1cblxuLyoqXG4gKiBSZXByZXNlbnQgdGhlIG5hbWUvdmFsdWUgcGFpciBhc3NvY2lhdGVkIHdpdGggYSBQcml2YXRlIEROUyBlbmFibGVkIGVuZHBvaW50IHNlcnZpY2VcbiAqL1xuaW50ZXJmYWNlIFByaXZhdGVEbnNDb25maWd1cmF0aW9uIHtcbiAgcmVhZG9ubHkgbmFtZTogc3RyaW5nO1xuICByZWFkb25seSB2YWx1ZTogc3RyaW5nO1xuICByZWFkb25seSBzZXJ2aWNlSWQ6IHN0cmluZztcbn1cblxuLyoqXG4gKiBIYXNoIGEgc3RyaW5nXG4gKi9cbmZ1bmN0aW9uIGhhc2hjb2RlKHM6IHN0cmluZyk6IHN0cmluZyB7XG4gIGNvbnN0IGhhc2ggPSBjcnlwdG8uY3JlYXRlSGFzaCgnbWQ1Jyk7XG4gIGhhc2gudXBkYXRlKHMpO1xuICByZXR1cm4gaGFzaC5kaWdlc3QoJ2hleCcpO1xufTsiXX0=