eks-spot-blocks
Version:
A sample JSII construct lib for AWS CDK
222 lines • 31 kB
JavaScript
"use strict";
var _a, _b;
Object.defineProperty(exports, "__esModule", { value: true });
exports.SpotFleet = exports.EksSpotCluster = exports.InstanceInterruptionBehavior = exports.BlockDuration = void 0;
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
const ec2 = require("@aws-cdk/aws-ec2");
const eks = require("@aws-cdk/aws-eks");
const iam = require("@aws-cdk/aws-iam");
const core_1 = require("@aws-cdk/core");
const launch_template_1 = require("./launch-template");
const user_data_1 = require("./user-data");
const DEFAULT_INSTANCE_TYPE = 't3.large';
/**
* @stability stable
*/
var BlockDuration;
(function (BlockDuration) {
BlockDuration[BlockDuration["ONE_HOUR"] = 60] = "ONE_HOUR";
BlockDuration[BlockDuration["TWO_HOURS"] = 120] = "TWO_HOURS";
BlockDuration[BlockDuration["THREE_HOURS"] = 180] = "THREE_HOURS";
BlockDuration[BlockDuration["FOUR_HOURS"] = 240] = "FOUR_HOURS";
BlockDuration[BlockDuration["FIVE_HOURS"] = 300] = "FIVE_HOURS";
BlockDuration[BlockDuration["SIX_HOURS"] = 360] = "SIX_HOURS";
})(BlockDuration = exports.BlockDuration || (exports.BlockDuration = {}));
/**
* @stability stable
*/
var InstanceInterruptionBehavior;
(function (InstanceInterruptionBehavior) {
InstanceInterruptionBehavior["HIBERNATE"] = "hibernate";
InstanceInterruptionBehavior["STOP"] = "stop";
InstanceInterruptionBehavior["TERMINATE"] = "terminate";
})(InstanceInterruptionBehavior = exports.InstanceInterruptionBehavior || (exports.InstanceInterruptionBehavior = {}));
/**
* @stability stable
*/
class EksSpotCluster extends core_1.Resource {
/**
* @stability stable
*/
constructor(scope, id, props) {
super(scope, id);
// this.cluster = props.cluster;
this.clusterVersion = props.clusterVersion;
// use an existing vpc or create a new one
this.vpc = this.node.tryGetContext('use_default_vpc') === '1' ?
ec2.Vpc.fromLookup(this, 'Vpc', { isDefault: true }) :
this.node.tryGetContext('use_vpc_id') ?
ec2.Vpc.fromLookup(this, 'Vpc', { vpcId: this.node.tryGetContext('use_vpc_id') }) :
new ec2.Vpc(this, 'Vpc', { maxAzs: 3, natGateways: 1 });
const clusterAdmin = new iam.Role(this, 'AdminRole', {
assumedBy: new iam.AccountRootPrincipal(),
});
this.cluster = new eks.Cluster(this, 'Cluster', {
vpc: this.vpc,
mastersRole: clusterAdmin,
defaultCapacity: 0,
version: this.clusterVersion,
});
}
/**
* @stability stable
*/
addSpotFleet(id, props) {
new SpotFleet(this, id, {
cluster: this,
...props,
});
}
/**
* @stability stable
*/
addDays(date, days) {
date.setDate(date.getDate() + days);
return date;
}
/**
* @stability stable
*/
addHours(date, hours) {
date.setHours(date.getHours() + hours);
return date;
}
/**
* @stability stable
*/
addMinutes(date, minutes) {
date.setMinutes(date.getMinutes() + minutes);
return date;
}
}
exports.EksSpotCluster = EksSpotCluster;
_a = JSII_RTTI_SYMBOL_1;
EksSpotCluster[_a] = { fqn: "eks-spot-blocks.EksSpotCluster", version: "0.2.373" };
/**
* @stability stable
*/
class SpotFleet extends core_1.Resource {
/**
* @stability stable
*/
constructor(scope, id, props) {
var _c, _d, _e, _f, _g, _h, _j;
super(scope, id, props);
this.spotFleetId = id;
this.clusterStack = props.cluster;
this.launchTemplate = (_c = props.launchTemplate) !== null && _c !== void 0 ? _c : new launch_template_1.LaunchTemplate();
this.targetCapacity = props.targetCapacity;
this.defaultInstanceType = (_d = props.defaultInstanceType) !== null && _d !== void 0 ? _d : new ec2.InstanceType(DEFAULT_INSTANCE_TYPE);
// isntance role
this.instanceRole = props.instanceRole || new iam.Role(this, 'InstanceRole', {
roleName: core_1.PhysicalName.GENERATE_IF_NEEDED,
assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com'),
});
this.instanceRole.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonEKSWorkerNodePolicy'));
this.instanceRole.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonEKS_CNI_Policy'));
this.instanceRole.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonEC2ContainerRegistryReadOnly'));
const instanceProfile = new iam.CfnInstanceProfile(this, 'InstanceProfile', {
roles: [this.instanceRole.roleName],
});
const sg = new ec2.SecurityGroup(this, 'SpotFleetSg', {
vpc: this.clusterStack.cluster.vpc,
});
// self rules
sg.connections.allowInternally(ec2.Port.allTraffic());
// Cluster to:nodes rules
sg.connections.allowFrom(this.clusterStack.cluster, ec2.Port.tcp(443));
sg.connections.allowFrom(this.clusterStack.cluster, ec2.Port.tcpRange(1025, 65535));
// Allow HTTPS from Nodes to Cluster
sg.connections.allowTo(this.clusterStack.cluster, ec2.Port.tcp(443));
// Allow all node outbound traffic
sg.connections.allowToAnyIpv4(ec2.Port.allTcp());
sg.connections.allowToAnyIpv4(ec2.Port.allUdp());
sg.connections.allowToAnyIpv4(ec2.Port.allIcmp());
const config = this.launchTemplate.bind(this);
// const userData = renderAmazonLinuxUserData(cdk.Stack.of(this), this.cluster.clusterName, config.spotfleet);
const userData = ec2.UserData.forLinux();
userData.addCommands(...user_data_1.renderAmazonLinuxUserData(core_1.Stack.of(this), this.clusterStack.cluster.clusterName, config.spotfleet));
this.defaultInstanceType = (_e = props.defaultInstanceType) !== null && _e !== void 0 ? _e : new ec2.InstanceType(DEFAULT_INSTANCE_TYPE);
const imageId = (_f = props.customAmiId) !== null && _f !== void 0 ? _f : new eks.EksOptimizedImage({
nodeType: nodeTypeForInstanceType(this.defaultInstanceType),
kubernetesVersion: props.cluster.clusterVersion.version,
}).getImage(this).imageId;
const lt = new ec2.CfnLaunchTemplate(this, 'LaunchTemplate', {
launchTemplateData: {
imageId,
instanceType: this.defaultInstanceType.toString(),
tagSpecifications: [
{
resourceType: 'instance',
tags: [
{
key: 'Name',
value: `${core_1.Stack.of(this).stackName}/Cluster/${this.spotFleetId}`,
},
{
key: `kubernetes.io/cluster/${this.clusterStack.cluster.clusterName}`,
value: 'owned',
},
],
},
],
instanceMarketOptions: {
marketType: 'spot',
spotOptions: {
blockDurationMinutes: (_g = props.blockDuration) !== null && _g !== void 0 ? _g : BlockDuration.ONE_HOUR,
instanceInterruptionBehavior: (_h = props.instanceInterruptionBehavior) !== null && _h !== void 0 ? _h : InstanceInterruptionBehavior.TERMINATE,
},
},
// userData: cdk.Fn.base64(capacityAsg.userData.render()),
userData: core_1.Fn.base64(userData.render()),
securityGroupIds: sg.connections.securityGroups.map(m => m.securityGroupId),
iamInstanceProfile: {
arn: instanceProfile.attrArn,
},
},
});
const spotFleetRole = new iam.Role(this, 'FleetRole', {
assumedBy: new iam.ServicePrincipal('spotfleet.amazonaws.com'),
managedPolicies: [
iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AmazonEC2SpotFleetTaggingRole'),
],
});
const overrides = [];
for (const s of this.clusterStack.cluster.vpc.privateSubnets) {
overrides.push({ subnetId: s.subnetId });
}
new ec2.CfnSpotFleet(this, id, {
spotFleetRequestConfigData: {
launchTemplateConfigs: [
{
launchTemplateSpecification: {
launchTemplateId: lt.ref,
version: lt.attrLatestVersionNumber,
},
overrides,
},
],
iamFleetRole: spotFleetRole.roleArn,
targetCapacity: (_j = props.targetCapacity) !== null && _j !== void 0 ? _j : 1,
validFrom: props.validFrom,
validUntil: props.validUntil,
terminateInstancesWithExpiration: props.terminateInstancesWithExpiration,
},
});
this.clusterStack.cluster.awsAuth.addRoleMapping(this.instanceRole, {
username: 'system:node:{{EC2PrivateDNSName}}',
groups: [
'system:bootstrappers',
'system:nodes',
],
});
}
}
exports.SpotFleet = SpotFleet;
_b = JSII_RTTI_SYMBOL_1;
SpotFleet[_b] = { fqn: "eks-spot-blocks.SpotFleet", version: "0.2.373" };
const GPU_INSTANCETYPES = ['p2', 'p3', 'g4'];
function nodeTypeForInstanceType(instanceType) {
return GPU_INSTANCETYPES.includes(instanceType.toString().substring(0, 2)) ? eks.NodeType.GPU : eks.NodeType.STANDARD;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWtzLXNwb3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvZWtzLXNwb3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSx3Q0FBd0M7QUFDeEMsd0NBQXdDO0FBQ3hDLHdDQUF3QztBQUN4Qyx3Q0FBd0c7QUFDeEcsdURBQW9FO0FBQ3BFLDJDQUF3RDtBQUd4RCxNQUFNLHFCQUFxQixHQUFHLFVBQVUsQ0FBQzs7OztBQUV6QyxJQUFZLGFBT1g7QUFQRCxXQUFZLGFBQWE7SUFDdkIsMERBQWEsQ0FBQTtJQUNiLDZEQUFlLENBQUE7SUFDZixpRUFBaUIsQ0FBQTtJQUNqQiwrREFBZ0IsQ0FBQTtJQUNoQiwrREFBZ0IsQ0FBQTtJQUNoQiw2REFBZSxDQUFBO0FBQ2pCLENBQUMsRUFQVyxhQUFhLEdBQWIscUJBQWEsS0FBYixxQkFBYSxRQU94Qjs7OztBQUVELElBQVksNEJBSVg7QUFKRCxXQUFZLDRCQUE0QjtJQUN0Qyx1REFBdUIsQ0FBQTtJQUN2Qiw2Q0FBYSxDQUFBO0lBQ2IsdURBQXVCLENBQUE7QUFDekIsQ0FBQyxFQUpXLDRCQUE0QixHQUE1QixvQ0FBNEIsS0FBNUIsb0NBQTRCLFFBSXZDOzs7O0FBWUQsTUFBYSxjQUFlLFNBQVEsZUFBUTs7OztJQU8xQyxZQUFZLEtBQWdCLEVBQUUsRUFBVSxFQUFFLEtBQTBCO1FBQ2xFLEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFFakIsZ0NBQWdDO1FBQ2hDLElBQUksQ0FBQyxjQUFjLEdBQUcsS0FBSyxDQUFDLGNBQWMsQ0FBQztRQUUzQywwQ0FBMEM7UUFDMUMsSUFBSSxDQUFDLEdBQUcsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxpQkFBaUIsQ0FBQyxLQUFLLEdBQUcsQ0FBQyxDQUFDO1lBQzdELEdBQUcsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxLQUFLLEVBQUUsRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFF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RTtZQUNsRSxRQUFRLEVBQUUsbUNBQW1DO1lBQzdDLE1BQU0sRUFBRTtnQkFDTixzQkFBc0I7Z0JBQ3RCLGNBQWM7YUFDZjtTQUNGLENBQUMsQ0FBQztJQUVMLENBQUM7O0FBM0lILDhCQTRJQzs7O0FBRUQsTUFBTSxpQkFBaUIsR0FBRyxDQUFDLElBQUksRUFBRSxJQUFJLEVBQUUsSUFBSSxDQUFDLENBQUM7QUFFN0MsU0FBUyx1QkFBdUIsQ0FBQyxZQUE4QjtJQUM3RCxPQUFPLGlCQUFpQixDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUMsUUFBUSxFQUFFLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUM7QUFDeEgsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIGVjMiBmcm9tICdAYXdzLWNkay9hd3MtZWMyJztcbmltcG9ydCAqIGFzIGVrcyBmcm9tICdAYXdzLWNkay9hd3MtZWtzJztcbmltcG9ydCAqIGFzIGlhbSBmcm9tICdAYXdzLWNkay9hd3MtaWFtJztcbmltcG9ydCB7IFN0YWNrLCBTdGFja1Byb3BzLCBDb25zdHJ1Y3QsIFJlc291cmNlLCBSZXNvdXJjZVByb3BzLCBQaHlzaWNhbE5hbWUsIEZuIH0gZnJvbSAnQGF3cy1jZGsvY29yZSc7XG5pbXBvcnQgeyBMYXVuY2hUZW1wbGF0ZSwgSUxhdW5jaHRlbXBsYXRlIH0gZnJvbSAnLi9sYXVuY2gtdGVtcGxhdGUnO1xuaW1wb3J0IHsgcmVuZGVyQW1hem9uTGludXhVc2VyRGF0YSB9IGZyb20gJy4vdXNlci1kYXRhJztcblxuXG5jb25zdCBERUZBVUxUX0lOU1RBTkNFX1RZUEUgPSAndDMubGFyZ2UnO1xuXG5leHBvcnQgZW51bSBCbG9ja0R1cmF0aW9uIHtcbiAgT05FX0hPVVIgPSA2MCxcbiAgVFdPX0hPVVJTID0gMTIwLFxuICBUSFJFRV9IT1VSUyA9IDE4MCxcbiAgRk9VUl9IT1VSUyA9IDI0MCxcbiAgRklWRV9IT1VSUyA9IDMwMCxcbiAgU0lYX0hPVVJTID0gMzYwXG59XG5cbmV4cG9ydCBlbnVtIEluc3RhbmNlSW50ZXJydXB0aW9uQmVoYXZpb3Ige1xuICBISUJFUk5BVEUgPSAnaGliZXJuYXRlJyxcbiAgU1RPUCA9ICdzdG9wJyxcbiAgVEVSTUlOQVRFID0gJ3Rlcm1pbmF0ZSdcbn1cblxuZXhwb3J0IGludGVyZmFjZSBFa3NTcG90Q2x1c3RlclByb3BzIGV4dGVuZHMgU3RhY2tQcm9wcyB7XG4gIHJlYWRvbmx5IGNsdXN0ZXJBdHRyaWJ1dGVzPzogZWtzLkNsdXN0ZXJBdHRyaWJ1dGVzO1xuICByZWFkb25seSBjbHVzdGVyVmVyc2lvbjogZWtzLkt1YmVybmV0ZXNWZXJzaW9uO1xuICByZWFkb25seSBpbnN0YW5jZVJvbGU/OiBpYW0uSVJvbGU7XG4gIHJlYWRvbmx5IGluc3RhbmNlSW50ZXJydXB0aW9uQmVoYXZpb3I/OiBJbnN0YW5jZUludGVycnVwdGlvbkJlaGF2aW9yO1xuICByZWFkb25seSBrdWJlY3RsRW5hYmxlZD86IGJvb2xlYW47XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXG4gIHJlYWRvbmx5IGN1c3RvbUFtaUlkPzogc3RyaW5nO1xufVxuXG5leHBvcnQgY2xhc3MgRWtzU3BvdENsdXN0ZXIgZXh0ZW5kcyBSZXNvdXJjZSB7XG4gIHJlYWRvbmx5IGNsdXN0ZXI6IGVrcy5DbHVzdGVyO1xuICByZWFkb25seSBjbHVzdGVyVmVyc2lvbjogZWtzLkt1YmVybmV0ZXNWZXJzaW9uO1xuICAvLyByZWFkb25seSBpbnN0YW5jZVJvbGU6IGlhbS5JUm9sZTtcbiAgLy8gcmVhZG9ubHkgaW5zdGFuY2VQcm9maWxlOiBpYW0uQ2ZuSW5zdGFuY2VQcm9maWxlO1xuICByZWFkb25seSB2cGM6IGVjMi5JVnBjO1xuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBFa3NTcG90Q2x1c3RlclByb3BzKSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkKTtcblxuICAgIC8vIHRoaXMuY2x1c3RlciA9IHByb3BzLmNsdXN0ZXI7XG4gICAgdGhpcy5jbHVzdGVyVmVyc2lvbiA9IHByb3BzLmNsdXN0ZXJWZXJzaW9uO1xuXG4gICAgLy8gdXNlIGFuIGV4aXN0aW5nIHZwYyBvciBjcmVhdGUgYSBuZXcgb25lXG4gICAgdGhpcy52cGMgPSB0aGlzLm5vZGUudHJ5R2V0Q29udGV4dCgndXNlX2RlZmF1bHRfdnBjJykgPT09ICcxJyA/XG4gICAgICBlYzIuVnBjLmZyb21Mb29rdXAodGhpcywgJ1ZwYycsIHsgaXNEZWZhdWx0OiB0cnVlIH0pIDpcbiAgICAgIHRoaXMubm9kZS50cnlHZXRDb250ZXh0KCd1c2VfdnBjX2lkJykgP1xuICAgICAgICBlYzIuVnBjLmZyb21Mb29rdXAodGhpcywgJ1ZwYycsIHsgdnBjSWQ6IHRoaXMubm9kZS50cnlHZXRDb250ZXh0KCd1c2VfdnBjX2lkJykgfSkgOlxuICAgICAgICBuZXcgZWMyLlZwYyh0aGlzLCAnVnBjJywgeyBtYXhBenM6IDMsIG5hdEdhdGV3YXlzOiAxIH0pO1xuXG4gICAgY29uc3QgY2x1c3RlckFkbWluID0gbmV3IGlhbS5Sb2xlKHRoaXMsICdBZG1pblJvbGUnLCB7XG4gICAgICBhc3N1bWVkQnk6IG5ldyBpYW0uQWNjb3VudFJvb3RQcmluY2lwYWwoKSxcbiAgICB9KTtcblxuICAgIHRoaXMuY2x1c3Rlcj0gbmV3IGVrcy5DbHVzdGVyKHRoaXMsICdDbHVzdGVyJywge1xuICAgICAgdnBjOiB0aGlzLnZwYyxcbiAgICAgIG1hc3RlcnNSb2xlOiBjbHVzdGVyQWRtaW4sXG4gICAgICBkZWZhdWx0Q2FwYWNpdHk6IDAsXG4gICAgICB2ZXJzaW9uOiB0aGlzLmNsdXN0ZXJWZXJzaW9uLFxuICAgIH0pO1xuICB9XG5cbiAgcHVibGljIGFkZFNwb3RGbGVldChpZDogc3RyaW5nLCBwcm9wczogQmFzZVNwb3RGbGVldFByb3BzKSB7XG4gICAgbmV3IFNwb3RGbGVldCh0aGlzLCBpZCwge1xuICAgICAgY2x1c3RlcjogdGhpcyxcbiAgICAgIC4uLnByb3BzLFxuICAgIH0pO1xuICB9XG5cbiAgcHVibGljIGFkZERheXMoZGF0ZTogRGF0ZSwgZGF5czogbnVtYmVyKTogRGF0ZSB7XG4gICAgZGF0ZS5zZXREYXRlKGRhdGUuZ2V0RGF0ZSgpICsgZGF5cyk7XG4gICAgcmV0dXJuIGRhdGU7XG4gIH1cblxuICBwdWJsaWMgYWRkSG91cnMoZGF0ZTogRGF0ZSwgaG91cnM6IG51bWJlcik6IERhdGUge1xuICAgIGRhdGUuc2V0SG91cnMoZGF0ZS5nZXRIb3VycygpICsgaG91cnMpO1xuICAgIHJldHVybiBkYXRlO1xuICB9XG5cbiAgcHVibGljIGFkZE1pbnV0ZXMoZGF0ZTogRGF0ZSwgbWludXRlczogbnVtYmVyKTogRGF0ZSB7XG4gICAgZGF0ZS5zZXRNaW51dGVzKGRhdGUuZ2V0TWludXRlcygpICsgbWludXRlcyk7XG4gICAgcmV0dXJuIGRhdGU7XG4gIH1cbn1cblxuZXhwb3J0IGludGVyZmFjZSBCYXNlU3BvdEZsZWV0UHJvcHMgZXh0ZW5kcyBSZXNvdXJjZVByb3BzIHtcbiAgcmVhZG9ubHkgZGVmYXVsdEluc3RhbmNlVHlwZT86IGVjMi5JbnN0YW5jZVR5cGU7XG4gIHJlYWRvbmx5IGJsb2NrRHVyYXRpb24/OiBCbG9ja0R1cmF0aW9uO1xuICByZWFkb25seSBpbnN0YW5jZUludGVycnVwdGlvbkJlaGF2aW9yID86IEluc3RhbmNlSW50ZXJydXB0aW9uQmVoYXZpb3I7XG4gIHJlYWRvbmx5IGluc3RhbmNlUm9sZT86IGlhbS5Sb2xlO1xuICByZWFkb25seSB0YXJnZXRDYXBhY2l0eT86IG51bWJlcjtcbiAgcmVhZG9ubHkgbWFwUm9sZT86IGJvb2xlYW47XG4gIHJlYWRvbmx5IGJvb3RzdHJhcEVuYWJsZWQ/OiBib29sZWFuO1xuICByZWFkb25seSB2YWxpZEZyb20/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHZhbGlkVW50aWw/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHRlcm1pbmF0ZUluc3RhbmNlc1dpdGhFeHBpcmF0aW9uPzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgY3VzdG9tQW1pSWQ/OiBzdHJpbmc7XG59XG5cblxuZXhwb3J0IGludGVyZmFjZSBTcG90RmxlZXRQcm9wcyBleHRlbmRzIEJhc2VTcG90RmxlZXRQcm9wcyB7XG4gIHJlYWRvbmx5IGNsdXN0ZXI6IEVrc1Nwb3RDbHVzdGVyO1xuICByZWFkb25seSBsYXVuY2hUZW1wbGF0ZT86IElMYXVuY2h0ZW1wbGF0ZTtcbn1cblxuZXhwb3J0IGNsYXNzIFNwb3RGbGVldCBleHRlbmRzIFJlc291cmNlIHtcbiAgcmVhZG9ubHkgaW5zdGFuY2VSb2xlOiBpYW0uSVJvbGU7XG4gIHJlYWRvbmx5IGNsdXN0ZXJTdGFjazogRWtzU3BvdENsdXN0ZXI7XG4gIHJlYWRvbmx5IGRlZmF1bHRJbnN0YW5jZVR5cGU6IGVjMi5JbnN0YW5jZVR5cGU7XG4gIHJlYWRvbmx5IHRhcmdldENhcGFjaXR5PzogbnVtYmVyO1xuICByZWFkb25seSBzcG90RmxlZXRJZDogc3RyaW5nO1xuICByZWFkb25seSBsYXVuY2hUZW1wbGF0ZTogSUxhdW5jaHRlbXBsYXRlO1xuXG5cbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM6IFNwb3RGbGVldFByb3BzKSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkLCBwcm9wcyk7XG5cbiAgICB0aGlzLnNwb3RGbGVldElkID0gaWQ7XG4gICAgdGhpcy5jbHVzdGVyU3RhY2sgPSBwcm9wcy5jbHVzdGVyO1xuICAgIHRoaXMubGF1bmNoVGVtcGxhdGUgPSBwcm9wcy5sYXVuY2hUZW1wbGF0ZSA/PyBuZXcgTGF1bmNoVGVtcGxhdGUoKTtcbiAgICB0aGlzLnRhcmdldENhcGFjaXR5ID0gcHJvcHMudGFyZ2V0Q2FwYWNpdHk7XG4gICAgdGhpcy5kZWZhdWx0SW5zdGFuY2VUeXBlID0gcHJvcHMuZGVmYXVsdEluc3RhbmNlVHlwZSA/PyBuZXcgZWMyLkluc3RhbmNlVHlwZShERUZBVUxUX0lOU1RBTkNFX1RZUEUpO1xuXG4gICAgLy8gaXNudGFuY2Ugcm9sZVxuICAgIHRoaXMuaW5zdGFuY2VSb2xlID0gcHJvcHMuaW5zdGFuY2VSb2xlIHx8IG5ldyBpYW0uUm9sZSh0aGlzLCAnSW5zdGFuY2VSb2xlJywge1xuICAgICAgcm9sZU5hbWU6IFBoeXNpY2FsTmFtZS5HRU5FUkFURV9JRl9ORUVERUQsXG4gICAgICBhc3N1bWVkQnk6IG5ldyBpYW0uU2VydmljZVByaW5jaXBhbCgnZWMyLmFtYXpvbmF3cy5jb20nKSxcbiAgICB9KTtcblxuICAgIHRoaXMuaW5zdGFuY2VSb2xlLmFkZE1hbmFnZWRQb2xpY3koaWFtLk1hbmFnZWRQb2xpY3kuZnJvbUF3c01hbmFnZWRQb2xpY3lOYW1lKCdBbWF6b25FS1NXb3JrZXJOb2RlUG9saWN5JykpO1xuICAgIHRoaXMuaW5zdGFuY2VSb2xlLmFkZE1hbmFnZWRQb2xpY3koaWFtLk1hbmFnZWRQb2xpY3kuZnJvbUF3c01hbmFnZWRQb2xpY3lOYW1lKCdBbWF6b25FS1NfQ05JX1BvbGljeScpKTtcbiAgICB0aGlzLmluc3RhbmNlUm9sZS5hZGRNYW5hZ2VkUG9saWN5KGlhbS5NYW5hZ2VkUG9saWN5LmZyb21Bd3NNYW5hZ2VkUG9saWN5TmFtZSgnQW1hem9uRUMyQ29udGFpbmVyUmVnaXN0cnlSZWFkT25seScpKTtcblxuICAgIGNvbnN0IGluc3RhbmNlUHJvZmlsZSA9IG5ldyBpYW0uQ2ZuSW5zdGFuY2VQcm9maWxlKHRoaXMsICdJbnN0YW5jZVByb2ZpbGUnLCB7XG4gICAgICByb2xlczogW3RoaXMuaW5zdGFuY2VSb2xlLnJvbGVOYW1lXSxcbiAgICB9KTtcblxuICAgIGNvbnN0IHNnID0gbmV3IGVjMi5TZWN1cml0eUdyb3VwKHRoaXMsICdTcG90RmxlZXRTZycsIHtcbiAgICAgIHZwYzogdGhpcy5jbHVzdGVyU3RhY2suY2x1c3Rlci52cGMsXG4gICAgfSk7XG5cbiAgICAvLyBzZWxmIHJ1bGVzXG4gICAgc2cuY29ubmVjdGlvbnMuYWxsb3dJbnRlcm5hbGx5KGVjMi5Qb3J0LmFsbFRyYWZmaWMoKSk7XG5cbiAgICAvLyBDbHVzdGVyIHRvOm5vZGVzIHJ1bGVzXG4gICAgc2cuY29ubmVjdGlvbnMuYWxsb3dGcm9tKHRoaXMuY2x1c3RlclN0YWNrLmNsdXN0ZXIsIGVjMi5Qb3J0LnRjcCg0NDMpKTtcbiAgICBzZy5jb25uZWN0aW9ucy5hbGxvd0Zyb20odGhpcy5jbHVzdGVyU3RhY2suY2x1c3RlciwgZWMyLlBvcnQudGNwUmFuZ2UoMTAyNSwgNjU1MzUpKTtcblxuICAgIC8vIEFsbG93IEhUVFBTIGZyb20gTm9kZXMgdG8gQ2x1c3RlclxuICAgIHNnLmNvbm5lY3Rpb25zLmFsbG93VG8odGhpcy5jbHVzdGVyU3RhY2suY2x1c3RlciwgZWMyLlBvcnQudGNwKDQ0MykpO1xuXG4gICAgLy8gQWxsb3cgYWxsIG5vZGUgb3V0Ym91bmQgdHJhZmZpY1xuICAgIHNnLmNvbm5lY3Rpb25zLmFsbG93VG9BbnlJcHY0KGVjMi5Qb3J0LmFsbFRjcCgpKTtcbiAgICBzZy5jb25uZWN0aW9ucy5hbGxvd1RvQW55SXB2NChlYzIuUG9ydC5hbGxVZHAoKSk7XG4gICAgc2cuY29ubmVjdGlvbnMuYWxsb3dUb0FueUlwdjQoZWMyLlBvcnQuYWxsSWNtcCgpKTtcblxuICAgIGNvbnN0IGNvbmZpZyA9IHRoaXMubGF1bmNoVGVtcGxhdGUuYmluZCh0aGlzKTtcblxuICAgIC8vIGNvbnN0IHVzZXJEYXRhID0gcmVuZGVyQW1hem9uTGludXhVc2VyRGF0YShjZGsuU3RhY2sub2YodGhpcyksIHRoaXMuY2x1c3Rlci5jbHVzdGVyTmFtZSwgY29uZmlnLnNwb3RmbGVldCk7XG4gICAgY29uc3QgdXNlckRhdGEgPSBlYzIuVXNlckRhdGEuZm9yTGludXgoKTtcbiAgICB1c2VyRGF0YS5hZGRDb21tYW5kcyguLi5yZW5kZXJBbWF6b25MaW51eFVzZXJEYXRhKFN0YWNrLm9mKHRoaXMpLCB0aGlzLmNsdXN0ZXJTdGFjay5jbHVzdGVyLmNsdXN0ZXJOYW1lLCBjb25maWcuc3BvdGZsZWV0KSk7XG5cbiAgICB0aGlzLmRlZmF1bHRJbnN0YW5jZVR5cGUgPSBwcm9wcy5kZWZhdWx0SW5zdGFuY2VUeXBlID8/IG5ldyBlYzIuSW5zdGFuY2VUeXBlKERFRkFVTFRfSU5TVEFOQ0VfVFlQRSk7XG5cbiAgICBjb25zdCBpbWFnZUlkID0gcHJvcHMuY3VzdG9tQW1pSWQgPz8gbmV3IGVrcy5Fa3NPcHRpbWl6ZWRJbWFnZSh7XG4gICAgICBub2RlVHlwZTogbm9kZVR5cGVGb3JJbnN0YW5jZVR5cGUodGhpcy5kZWZhdWx0SW5zdGFuY2VUeXBlKSxcbiAgICAgIGt1YmVybmV0ZXNWZXJzaW9uOiBwcm9wcy5jbHVzdGVyLmNsdXN0ZXJWZXJzaW9uLnZlcnNpb24sXG4gICAgfSkuZ2V0SW1hZ2UodGhpcykuaW1hZ2VJZDtcblxuICAgIGNvbnN0IGx0ID0gbmV3IGVjMi5DZm5MYXVuY2hUZW1wbGF0ZSh0aGlzLCAnTGF1bmNoVGVtcGxhdGUnLCB7XG4gICAgICBsYXVuY2hUZW1wbGF0ZURhdGE6IHtcbiAgICAgICAgaW1hZ2VJZCxcbiAgICAgICAgaW5zdGFuY2VUeXBlOiB0aGlzLmRlZmF1bHRJbnN0YW5jZVR5cGUudG9TdHJpbmcoKSxcbiAgICAgICAgdGFnU3BlY2lmaWNhdGlvbnM6IFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICByZXNvdXJjZVR5cGU6ICdpbnN0YW5jZScsXG4gICAgICAgICAgICB0YWdzOiBbXG4gICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBrZXk6ICdOYW1lJyxcbiAgICAgICAgICAgICAgICB2YWx1ZTogYCR7U3RhY2sub2YodGhpcykuc3RhY2tOYW1lfS9DbHVzdGVyLyR7dGhpcy5zcG90RmxlZXRJZH1gLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAga2V5OiBga3ViZXJuZXRlcy5pby9jbHVzdGVyLyR7dGhpcy5jbHVzdGVyU3RhY2suY2x1c3Rlci5jbHVzdGVyTmFtZX1gLFxuICAgICAgICAgICAgICAgIHZhbHVlOiAnb3duZWQnLFxuICAgICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBdLFxuICAgICAgICAgIH0sXG4gICAgICAgIF0sXG4gICAgICAgIGluc3RhbmNlTWFya2V0T3B0aW9uczoge1xuICAgICAgICAgIG1hcmtldFR5cGU6ICdzcG90JyxcbiAgICAgICAgICBzcG90T3B0aW9uczoge1xuICAgICAgICAgICAgYmxvY2tEdXJhdGlvbk1pbnV0ZXM6IHByb3BzLmJsb2NrRHVyYXRpb24gPz8gQmxvY2tEdXJhdGlvbi5PTkVfSE9VUixcbiAgICAgICAgICAgIGluc3RhbmNlSW50ZXJydXB0aW9uQmVoYXZpb3I6IHByb3BzLmluc3RhbmNlSW50ZXJydXB0aW9uQmVoYXZpb3IgPz8gSW5zdGFuY2VJbnRlcnJ1cHRpb25CZWhhdmlvci5URVJNSU5BVEUsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgICAgLy8gdXNlckRhdGE6IGNkay5Gbi5iYXNlNjQoY2FwYWNpdHlBc2cudXNlckRhdGEucmVuZGVyKCkpLFxuICAgICAgICB1c2VyRGF0YTogRm4uYmFzZTY0KHVzZXJEYXRhLnJlbmRlcigpKSxcbiAgICAgICAgc2VjdXJpdHlHcm91cElkczogc2cuY29ubmVjdGlvbnMuc2VjdXJpdHlHcm91cHMubWFwKG0gPT4gbS5zZWN1cml0eUdyb3VwSWQpLFxuICAgICAgICBpYW1JbnN0YW5jZVByb2ZpbGU6IHtcbiAgICAgICAgICBhcm46IGluc3RhbmNlUHJvZmlsZS5hdHRyQXJuLFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICB9KTtcblxuICAgIGNvbnN0IHNwb3RGbGVldFJvbGUgPSBuZXcgaWFtLlJvbGUodGhpcywgJ0ZsZWV0Um9sZScsIHtcbiAgICAgIGFzc3VtZWRCeTogbmV3IGlhbS5TZXJ2aWNlUHJpbmNpcGFsKCdzcG90ZmxlZXQuYW1hem9uYXdzLmNvbScpLFxuICAgICAgbWFuYWdlZFBvbGljaWVzOiBbXG4gICAgICAgIGlhbS5NYW5hZ2VkUG9saWN5LmZyb21Bd3NNYW5hZ2VkUG9saWN5TmFtZSgnc2VydmljZS1yb2xlL0FtYXpvbkVDMlNwb3RGbGVldFRhZ2dpbmdSb2xlJyksXG4gICAgICBdLFxuICAgIH0pO1xuXG5cbiAgICBjb25zdCBvdmVycmlkZXMgPSBbXTtcbiAgICBmb3IgKGNvbnN0IHMgb2YgdGhpcy5jbHVzdGVyU3RhY2suY2x1c3Rlci52cGMucHJpdmF0ZVN1Ym5ldHMpIHtcbiAgICAgIG92ZXJyaWRlcy5wdXNoKHsgc3VibmV0SWQ6IHMuc3VibmV0SWQgfSk7XG4gICAgfVxuICAgIG5ldyBlYzIuQ2ZuU3BvdEZsZWV0KHRoaXMsIGlkLCB7XG4gICAgICBzcG90RmxlZXRSZXF1ZXN0Q29uZmlnRGF0YToge1xuICAgICAgICBsYXVuY2hUZW1wbGF0ZUNvbmZpZ3M6IFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICBsYXVuY2hUZW1wbGF0ZVNwZWNpZmljYXRpb246IHtcbiAgICAgICAgICAgICAgbGF1bmNoVGVtcGxhdGVJZDogbHQucmVmLFxuICAgICAgICAgICAgICB2ZXJzaW9uOiBsdC5hdHRyTGF0ZXN0VmVyc2lvbk51bWJlcixcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBvdmVycmlkZXMsXG4gICAgICAgICAgfSxcbiAgICAgICAgXSxcbiAgICAgICAgaWFtRmxlZXRSb2xlOiBzcG90RmxlZXRSb2xlLnJvbGVBcm4sXG4gICAgICAgIHRhcmdldENhcGFjaXR5OiBwcm9wcy50YXJnZXRDYXBhY2l0eSA/PyAxLFxuICAgICAgICB2YWxpZEZyb206IHByb3BzLnZhbGlkRnJvbSxcbiAgICAgICAgdmFsaWRVbnRpbDogcHJvcHMudmFsaWRVbnRpbCxcbiAgICAgICAgdGVybWluYXRlSW5zdGFuY2VzV2l0aEV4cGlyYXRpb246IHByb3BzLnRlcm1pbmF0ZUluc3RhbmNlc1dpdGhFeHBpcmF0aW9uLFxuICAgICAgfSxcbiAgICB9KTtcblxuICAgIHRoaXMuY2x1c3RlclN0YWNrLmNsdXN0ZXIuYXdzQXV0aC5hZGRSb2xlTWFwcGluZyh0aGlzLmluc3RhbmNlUm9sZSwge1xuICAgICAgdXNlcm5hbWU6ICdzeXN0ZW06bm9kZTp7e0VDMlByaXZhdGVETlNOYW1lfX0nLFxuICAgICAgZ3JvdXBzOiBbXG4gICAgICAgICdzeXN0ZW06Ym9vdHN0cmFwcGVycycsXG4gICAgICAgICdzeXN0ZW06bm9kZXMnLFxuICAgICAgXSxcbiAgICB9KTtcblxuICB9XG59XG5cbmNvbnN0IEdQVV9JTlNUQU5DRVRZUEVTID0gWydwMicsICdwMycsICdnNCddO1xuXG5mdW5jdGlvbiBub2RlVHlwZUZvckluc3RhbmNlVHlwZShpbnN0YW5jZVR5cGU6IGVjMi5JbnN0YW5jZVR5cGUpIHtcbiAgcmV0dXJuIEdQVV9JTlNUQU5DRVRZUEVTLmluY2x1ZGVzKGluc3RhbmNlVHlwZS50b1N0cmluZygpLnN1YnN0cmluZygwLCAyKSkgPyBla3MuTm9kZVR5cGUuR1BVIDogZWtzLk5vZGVUeXBlLlNUQU5EQVJEO1xufVxuIl19