UNPKG

cdk-serverless-api

Version:
186 lines 30.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SpotFleet = exports.EksSpotCluster = exports.InstanceInterruptionBehavior = exports.BlockDuration = void 0; const core_1 = require("@aws-cdk/core"); const eks = require("@aws-cdk/aws-eks"); const user_data_1 = require("./user-data"); const iam = require("@aws-cdk/aws-iam"); const ec2 = require("@aws-cdk/aws-ec2"); const launch_template_1 = require("./launch-template"); const DEFAULT_INSTANCE_TYPE = 't3.large'; 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 = {})); var InstanceInterruptionBehavior; (function (InstanceInterruptionBehavior) { InstanceInterruptionBehavior["HIBERNATE"] = "hibernate"; InstanceInterruptionBehavior["STOP"] = "stop"; InstanceInterruptionBehavior["TERMINATE"] = "terminate"; })(InstanceInterruptionBehavior = exports.InstanceInterruptionBehavior || (exports.InstanceInterruptionBehavior = {})); class EksSpotCluster extends core_1.Resource { 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, }); } addSpotFleet(id, props) { new SpotFleet(this, id, { cluster: this, ...props, }); } addDays(date, days) { date.setDate(date.getDate() + days); return date; } addHours(date, hours) { date.setHours(date.getHours() + hours); return date; } addMinutes(date, minutes) { date.setMinutes(date.getMinutes() + minutes); return date; } } exports.EksSpotCluster = EksSpotCluster; class SpotFleet extends core_1.Resource { constructor(scope, id, props) { var _a, _b, _c, _d, _e, _f, _g; super(scope, id, props); this.spotFleetId = id; this.clusterStack = props.cluster; this.launchTemplate = (_a = props.launchTemplate) !== null && _a !== void 0 ? _a : new launch_template_1.LaunchTemplate(); this.targetCapacity = props.targetCapacity; this.defaultInstanceType = (_b = props.defaultInstanceType) !== null && _b !== void 0 ? _b : 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 = (_c = props.defaultInstanceType) !== null && _c !== void 0 ? _c : new ec2.InstanceType(DEFAULT_INSTANCE_TYPE); const imageId = (_d = props.customAmiId) !== null && _d !== void 0 ? _d : 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: (_e = props.blockDuration) !== null && _e !== void 0 ? _e : BlockDuration.ONE_HOUR, instanceInterruptionBehavior: (_f = props.instanceInterruptionBehavior) !== null && _f !== void 0 ? _f : 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: (_g = props.targetCapacity) !== null && _g !== void 0 ? _g : 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; 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWtzLXNwb3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvZWtzLXNwb3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsd0NBQXdHO0FBQ3hHLHdDQUF3QztBQUN4QywyQ0FBd0Q7QUFDeEQsd0NBQXdDO0FBQ3hDLHdDQUF3QztBQUN4Qyx1REFBb0U7QUFFcEUsTUFBTSxxQkFBcUIsR0FBRyxVQUFVLENBQUE7QUFFeEMsSUFBWSxhQU9YO0FBUEQsV0FBWSxhQUFhO0lBQ3ZCLDBEQUFhLENBQUE7SUFDYiw2REFBZSxDQUFBO0lBQ2YsaUVBQWlCLENBQUE7SUFDakIsK0RBQWdCLENBQUE7SUFDaEIsK0RBQWdCLENBQUE7SUFDaEIsNkRBQWUsQ0FBQTtBQUNqQixDQUFDLEVBUFcsYUFBYSxHQUFiLHFCQUFhLEtBQWIscUJBQWEsUUFPeEI7QUFFRCxJQUFZLDRCQUlYO0FBSkQsV0FBWSw0QkFBNEI7SUFDdEMsdURBQXVCLENBQUE7SUFDdkIsNkNBQWEsQ0FBQTtJQUNiLHVEQUF1QixDQUFBO0FBQ3pCLENBQUMsRUFKVyw0QkFBNEIsR0FBNUIsb0NBQTRCLEtBQTVCLG9DQUE0QixRQUl2QztBQWlCRCxNQUFhLGNBQWUsU0FBUSxlQUFRO0lBTzFDLFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBMEI7UUFDbEUsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztRQUVqQixnQ0FBZ0M7UUFDaEMsSUFBSSxDQUFDLGNBQWMsR0FBRyxLQUFLLENBQUMsY0FBYyxDQUFDO1FBRTNDLDBDQUEwQztRQUMxQyxJQUFJLENBQUMsR0FBRyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLGlCQUFpQixDQUFDLEtBQUssR0FBRyxDQUFDLENBQUM7WUFDN0QsR0FBRyxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRSxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDLENB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QyxNQUFNLEVBQUU7Z0JBQ04sc0JBQXNCO2dCQUN0QixjQUFjO2FBQ2Y7U0FDRixDQUFDLENBQUM7SUFFTCxDQUFDO0NBQ0Y7QUE1SUQsOEJBNElDO0FBRUQsTUFBTSxpQkFBaUIsR0FBRyxDQUFDLElBQUksRUFBRSxJQUFJLEVBQUUsSUFBSSxDQUFDLENBQUM7QUFFN0MsU0FBUyx1QkFBdUIsQ0FBQyxZQUE4QjtJQUM3RCxPQUFPLGlCQUFpQixDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUMsUUFBUSxFQUFFLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUM7QUFDeEgsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFN0YWNrLCBTdGFja1Byb3BzLCBDb25zdHJ1Y3QsIFJlc291cmNlLCBSZXNvdXJjZVByb3BzLCBQaHlzaWNhbE5hbWUsIEZuIH0gZnJvbSAnQGF3cy1jZGsvY29yZSc7XG5pbXBvcnQgKiBhcyBla3MgZnJvbSAnQGF3cy1jZGsvYXdzLWVrcyc7XG5pbXBvcnQgeyByZW5kZXJBbWF6b25MaW51eFVzZXJEYXRhIH0gZnJvbSAnLi91c2VyLWRhdGEnO1xuaW1wb3J0ICogYXMgaWFtIGZyb20gJ0Bhd3MtY2RrL2F3cy1pYW0nO1xuaW1wb3J0ICogYXMgZWMyIGZyb20gJ0Bhd3MtY2RrL2F3cy1lYzInO1xuaW1wb3J0IHsgTGF1bmNoVGVtcGxhdGUsIElMYXVuY2h0ZW1wbGF0ZSB9IGZyb20gJy4vbGF1bmNoLXRlbXBsYXRlJztcblxuY29uc3QgREVGQVVMVF9JTlNUQU5DRV9UWVBFID0gJ3QzLmxhcmdlJ1xuXG5leHBvcnQgZW51bSBCbG9ja0R1cmF0aW9uIHtcbiAgT05FX0hPVVIgPSA2MCxcbiAgVFdPX0hPVVJTID0gMTIwLFxuICBUSFJFRV9IT1VSUyA9IDE4MCxcbiAgRk9VUl9IT1VSUyA9IDI0MCxcbiAgRklWRV9IT1VSUyA9IDMwMCxcbiAgU0lYX0hPVVJTID0gMzYwXG59XG5cbmV4cG9ydCBlbnVtIEluc3RhbmNlSW50ZXJydXB0aW9uQmVoYXZpb3Ige1xuICBISUJFUk5BVEUgPSAnaGliZXJuYXRlJyxcbiAgU1RPUCA9ICdzdG9wJyxcbiAgVEVSTUlOQVRFID0gJ3Rlcm1pbmF0ZSdcbn1cblxuZXhwb3J0IGludGVyZmFjZSBFa3NTcG90Q2x1c3RlclByb3BzIGV4dGVuZHMgU3RhY2tQcm9wcyB7XG4gIHJlYWRvbmx5IGNsdXN0ZXJBdHRyaWJ1dGVzPzogZWtzLkNsdXN0ZXJBdHRyaWJ1dGVzO1xuICByZWFkb25seSBjbHVzdGVyVmVyc2lvbjogZWtzLkt1YmVybmV0ZXNWZXJzaW9uO1xuICByZWFkb25seSBpbnN0YW5jZVJvbGU/OiBpYW0uSVJvbGU7XG4gIHJlYWRvbmx5IGluc3RhbmNlSW50ZXJydXB0aW9uQmVoYXZpb3I/OiBJbnN0YW5jZUludGVycnVwdGlvbkJlaGF2aW9yO1xuICByZWFkb25seSBrdWJlY3RsRW5hYmxlZD86IGJvb2xlYW47XG4gIC8qKlxuICAgICAqIFNwZWNpZnkgYSBjdXN0b20gQU1JIElEIGZvciB5b3VyIHNwb3QgZmxlZXQuIEJ5IGRlZmF1bHQgdGhlIEFtYXpvbiBFS1Mtb3B0aW1pemVkXG4gICAgICogQU1JIHdpbGwgYmUgc2VsZWN0ZWQuXG4gICAgICogXG4gICAgICogQGRlZmF1bHQgLSBub25lXG4gICAgICovXG4gIHJlYWRvbmx5IGN1c3RvbUFtaUlkPzogc3RyaW5nO1xufVxuXG5leHBvcnQgY2xhc3MgRWtzU3BvdENsdXN0ZXIgZXh0ZW5kcyBSZXNvdXJjZSB7XG4gIHJlYWRvbmx5IGNsdXN0ZXI6IGVrcy5DbHVzdGVyO1xuICByZWFkb25seSBjbHVzdGVyVmVyc2lvbjogZWtzLkt1YmVybmV0ZXNWZXJzaW9uO1xuICAvLyByZWFkb25seSBpbnN0YW5jZVJvbGU6IGlhbS5JUm9sZTtcbiAgLy8gcmVhZG9ubHkgaW5zdGFuY2VQcm9maWxlOiBpYW0uQ2ZuSW5zdGFuY2VQcm9maWxlO1xuICByZWFkb25seSB2cGM6IGVjMi5JVnBjO1xuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBFa3NTcG90Q2x1c3RlclByb3BzKSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkKTtcblxuICAgIC8vIHRoaXMuY2x1c3RlciA9IHByb3BzLmNsdXN0ZXI7XG4gICAgdGhpcy5jbHVzdGVyVmVyc2lvbiA9IHByb3BzLmNsdXN0ZXJWZXJzaW9uO1xuXG4gICAgLy8gdXNlIGFuIGV4aXN0aW5nIHZwYyBvciBjcmVhdGUgYSBuZXcgb25lXG4gICAgdGhpcy52cGMgPSB0aGlzLm5vZGUudHJ5R2V0Q29udGV4dCgndXNlX2RlZmF1bHRfdnBjJykgPT09ICcxJyA/XG4gICAgICBlYzIuVnBjLmZyb21Mb29rdXAodGhpcywgJ1ZwYycsIHsgaXNEZWZhdWx0OiB0cnVlIH0pIDpcbiAgICAgIHRoaXMubm9kZS50cnlHZXRDb250ZXh0KCd1c2VfdnBjX2lkJykgP1xuICAgICAgICBlYzIuVnBjLmZyb21Mb29rdXAodGhpcywgJ1ZwYycsIHsgdnBjSWQ6IHRoaXMubm9kZS50cnlHZXRDb250ZXh0KCd1c2VfdnBjX2lkJykgfSkgOlxuICAgICAgICBuZXcgZWMyLlZwYyh0aGlzLCAnVnBjJywgeyBtYXhBenM6IDMsIG5hdEdhdGV3YXlzOiAxIH0pO1xuXG4gICAgY29uc3QgY2x1c3RlckFkbWluID0gbmV3IGlhbS5Sb2xlKHRoaXMsICdBZG1pblJvbGUnLCB7XG4gICAgICBhc3N1bWVkQnk6IG5ldyBpYW0uQWNjb3VudFJvb3RQcmluY2lwYWwoKSxcbiAgICB9KTtcblxuICAgIHRoaXMuY2x1c3Rlcj0gbmV3IGVrcy5DbHVzdGVyKHRoaXMsICdDbHVzdGVyJywge1xuICAgICAgdnBjOiB0aGlzLnZwYyxcbiAgICAgIG1hc3RlcnNSb2xlOiBjbHVzdGVyQWRtaW4sXG4gICAgICBkZWZhdWx0Q2FwYWNpdHk6IDAsXG4gICAgICB2ZXJzaW9uOiB0aGlzLmNsdXN0ZXJWZXJzaW9uLFxuICAgIH0pXG4gIH1cblxuICBwdWJsaWMgYWRkU3BvdEZsZWV0KGlkOiBzdHJpbmcsIHByb3BzOiBCYXNlU3BvdEZsZWV0UHJvcHMpIHtcbiAgICBuZXcgU3BvdEZsZWV0KHRoaXMsIGlkLCB7XG4gICAgICBjbHVzdGVyOiB0aGlzLFxuICAgICAgLi4ucHJvcHMsXG4gICAgfSlcbiAgfVxuXG4gIHB1YmxpYyBhZGREYXlzKGRhdGU6IERhdGUsIGRheXM6IG51bWJlcik6IERhdGUge1xuICAgIGRhdGUuc2V0RGF0ZShkYXRlLmdldERhdGUoKSArIGRheXMpO1xuICAgIHJldHVybiBkYXRlO1xuICB9XG5cbiAgcHVibGljIGFkZEhvdXJzKGRhdGU6IERhdGUsIGhvdXJzOiBudW1iZXIpOiBEYXRlIHtcbiAgICBkYXRlLnNldEhvdXJzKGRhdGUuZ2V0SG91cnMoKSArIGhvdXJzKTtcbiAgICByZXR1cm4gZGF0ZTtcbiAgfVxuXG4gIHB1YmxpYyBhZGRNaW51dGVzKGRhdGU6IERhdGUsIG1pbnV0ZXM6IG51bWJlcik6IERhdGUge1xuICAgIGRhdGUuc2V0TWludXRlcyhkYXRlLmdldE1pbnV0ZXMoKSArIG1pbnV0ZXMpO1xuICAgIHJldHVybiBkYXRlO1xuICB9XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQmFzZVNwb3RGbGVldFByb3BzIGV4dGVuZHMgUmVzb3VyY2VQcm9wcyB7XG4gIHJlYWRvbmx5IGRlZmF1bHRJbnN0YW5jZVR5cGU/OiBlYzIuSW5zdGFuY2VUeXBlO1xuICByZWFkb25seSBibG9ja0R1cmF0aW9uPzogQmxvY2tEdXJhdGlvbjtcbiAgcmVhZG9ubHkgaW5zdGFuY2VJbnRlcnJ1cHRpb25CZWhhdmlvciA/OiBJbnN0YW5jZUludGVycnVwdGlvbkJlaGF2aW9yO1xuICByZWFkb25seSBpbnN0YW5jZVJvbGU/OiBpYW0uUm9sZTtcbiAgcmVhZG9ubHkgdGFyZ2V0Q2FwYWNpdHk/OiBudW1iZXI7XG4gIHJlYWRvbmx5IG1hcFJvbGU/OiBib29sZWFuO1xuICByZWFkb25seSBib290c3RyYXBFbmFibGVkPzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgdmFsaWRGcm9tPzogc3RyaW5nO1xuICByZWFkb25seSB2YWxpZFVudGlsPzogc3RyaW5nO1xuICByZWFkb25seSB0ZXJtaW5hdGVJbnN0YW5jZXNXaXRoRXhwaXJhdGlvbj86IGJvb2xlYW47XG4gIHJlYWRvbmx5IGN1c3RvbUFtaUlkPzogc3RyaW5nO1xufVxuXG5cbmV4cG9ydCBpbnRlcmZhY2UgU3BvdEZsZWV0UHJvcHMgZXh0ZW5kcyBCYXNlU3BvdEZsZWV0UHJvcHMge1xuICByZWFkb25seSBjbHVzdGVyOiBFa3NTcG90Q2x1c3RlcjtcbiAgcmVhZG9ubHkgbGF1bmNoVGVtcGxhdGU/OiBJTGF1bmNodGVtcGxhdGU7XG59XG5cbmV4cG9ydCBjbGFzcyBTcG90RmxlZXQgZXh0ZW5kcyBSZXNvdXJjZSB7XG4gIHJlYWRvbmx5IGluc3RhbmNlUm9sZTogaWFtLklSb2xlO1xuICByZWFkb25seSBjbHVzdGVyU3RhY2s6IEVrc1Nwb3RDbHVzdGVyO1xuICByZWFkb25seSBkZWZhdWx0SW5zdGFuY2VUeXBlOiBlYzIuSW5zdGFuY2VUeXBlO1xuICByZWFkb25seSB0YXJnZXRDYXBhY2l0eT86IG51bWJlcjtcbiAgcmVhZG9ubHkgc3BvdEZsZWV0SWQ6IHN0cmluZztcbiAgcmVhZG9ubHkgbGF1bmNoVGVtcGxhdGU6IElMYXVuY2h0ZW1wbGF0ZTtcblxuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBTcG90RmxlZXRQcm9wcykge1xuICAgIHN1cGVyKHNjb3BlLCBpZCwgcHJvcHMpXG5cbiAgICB0aGlzLnNwb3RGbGVldElkID0gaWRcbiAgICB0aGlzLmNsdXN0ZXJTdGFjayA9IHByb3BzLmNsdXN0ZXJcbiAgICB0aGlzLmxhdW5jaFRlbXBsYXRlID0gcHJvcHMubGF1bmNoVGVtcGxhdGUgPz8gbmV3IExhdW5jaFRlbXBsYXRlKClcbiAgICB0aGlzLnRhcmdldENhcGFjaXR5ID0gcHJvcHMudGFyZ2V0Q2FwYWNpdHlcbiAgICB0aGlzLmRlZmF1bHRJbnN0YW5jZVR5cGUgPSBwcm9wcy5kZWZhdWx0SW5zdGFuY2VUeXBlID8/IG5ldyBlYzIuSW5zdGFuY2VUeXBlKERFRkFVTFRfSU5TVEFOQ0VfVFlQRSlcblxuICAgIC8vIGlzbnRhbmNlIHJvbGVcbiAgICB0aGlzLmluc3RhbmNlUm9sZSA9IHByb3BzLmluc3RhbmNlUm9sZSB8fCBuZXcgaWFtLlJvbGUodGhpcywgJ0luc3RhbmNlUm9sZScsIHtcbiAgICAgIHJvbGVOYW1lOiBQaHlzaWNhbE5hbWUuR0VORVJBVEVfSUZfTkVFREVELFxuICAgICAgYXNzdW1lZEJ5OiBuZXcgaWFtLlNlcnZpY2VQcmluY2lwYWwoJ2VjMi5hbWF6b25hd3MuY29tJyksXG4gICAgfSk7XG5cbiAgICB0aGlzLmluc3RhbmNlUm9sZS5hZGRNYW5hZ2VkUG9saWN5KGlhbS5NYW5hZ2VkUG9saWN5LmZyb21Bd3NNYW5hZ2VkUG9saWN5TmFtZSgnQW1hem9uRUtTV29ya2VyTm9kZVBvbGljeScpKTtcbiAgICB0aGlzLmluc3RhbmNlUm9sZS5hZGRNYW5hZ2VkUG9saWN5KGlhbS5NYW5hZ2VkUG9saWN5LmZyb21Bd3NNYW5hZ2VkUG9saWN5TmFtZSgnQW1hem9uRUtTX0NOSV9Qb2xpY3knKSk7XG4gICAgdGhpcy5pbnN0YW5jZVJvbGUuYWRkTWFuYWdlZFBvbGljeShpYW0uTWFuYWdlZFBvbGljeS5mcm9tQXdzTWFuYWdlZFBvbGljeU5hbWUoJ0FtYXpvbkVDMkNvbnRhaW5lclJlZ2lzdHJ5UmVhZE9ubHknKSk7XG5cbiAgICBjb25zdCBpbnN0YW5jZVByb2ZpbGUgPSBuZXcgaWFtLkNmbkluc3RhbmNlUHJvZmlsZSh0aGlzLCAnSW5zdGFuY2VQcm9maWxlJywge1xuICAgICAgcm9sZXM6IFt0aGlzLmluc3RhbmNlUm9sZS5yb2xlTmFtZV0sXG4gICAgfSlcblxuICAgIGNvbnN0IHNnID0gbmV3IGVjMi5TZWN1cml0eUdyb3VwKHRoaXMsICdTcG90RmxlZXRTZycsIHtcbiAgICAgIHZwYzogdGhpcy5jbHVzdGVyU3RhY2suY2x1c3Rlci52cGMsXG4gICAgfSlcblxuICAgIC8vIHNlbGYgcnVsZXNcbiAgICBzZy5jb25uZWN0aW9ucy5hbGxvd0ludGVybmFsbHkoZWMyLlBvcnQuYWxsVHJhZmZpYygpKTtcblxuICAgIC8vIENsdXN0ZXIgdG86bm9kZXMgcnVsZXNcbiAgICBzZy5jb25uZWN0aW9ucy5hbGxvd0Zyb20odGhpcy5jbHVzdGVyU3RhY2suY2x1c3RlciwgZWMyLlBvcnQudGNwKDQ0MykpO1xuICAgIHNnLmNvbm5lY3Rpb25zLmFsbG93RnJvbSh0aGlzLmNsdXN0ZXJTdGFjay5jbHVzdGVyLCBlYzIuUG9ydC50Y3BSYW5nZSgxMDI1LCA2NTUzNSkpO1xuXG4gICAgLy8gQWxsb3cgSFRUUFMgZnJvbSBOb2RlcyB0byBDbHVzdGVyXG4gICAgc2cuY29ubmVjdGlvbnMuYWxsb3dUbyh0aGlzLmNsdXN0ZXJTdGFjay5jbHVzdGVyLCBlYzIuUG9ydC50Y3AoNDQzKSk7XG5cbiAgICAvLyBBbGxvdyBhbGwgbm9kZSBvdXRib3VuZCB0cmFmZmljXG4gICAgc2cuY29ubmVjdGlvbnMuYWxsb3dUb0FueUlwdjQoZWMyLlBvcnQuYWxsVGNwKCkpO1xuICAgIHNnLmNvbm5lY3Rpb25zLmFsbG93VG9BbnlJcHY0KGVjMi5Qb3J0LmFsbFVkcCgpKTtcbiAgICBzZy5jb25uZWN0aW9ucy5hbGxvd1RvQW55SXB2NChlYzIuUG9ydC5hbGxJY21wKCkpO1xuXG4gICAgY29uc3QgY29uZmlnID0gdGhpcy5sYXVuY2hUZW1wbGF0ZS5iaW5kKHRoaXMpXG5cbiAgICAvLyBjb25zdCB1c2VyRGF0YSA9IHJlbmRlckFtYXpvbkxpbnV4VXNlckRhdGEoY2RrLlN0YWNrLm9mKHRoaXMpLCB0aGlzLmNsdXN0ZXIuY2x1c3Rlck5hbWUsIGNvbmZpZy5zcG90ZmxlZXQpO1xuICAgIGNvbnN0IHVzZXJEYXRhID0gZWMyLlVzZXJEYXRhLmZvckxpbnV4KClcbiAgICB1c2VyRGF0YS5hZGRDb21tYW5kcyguLi5yZW5kZXJBbWF6b25MaW51eFVzZXJEYXRhKFN0YWNrLm9mKHRoaXMpLCB0aGlzLmNsdXN0ZXJTdGFjay5jbHVzdGVyLmNsdXN0ZXJOYW1lLCBjb25maWcuc3BvdGZsZWV0KSk7XG5cbiAgICB0aGlzLmRlZmF1bHRJbnN0YW5jZVR5cGUgPSBwcm9wcy5kZWZhdWx0SW5zdGFuY2VUeXBlID8/IG5ldyBlYzIuSW5zdGFuY2VUeXBlKERFRkFVTFRfSU5TVEFOQ0VfVFlQRSlcblxuICAgIGNvbnN0IGltYWdlSWQgPSBwcm9wcy5jdXN0b21BbWlJZCA/PyBuZXcgZWtzLkVrc09wdGltaXplZEltYWdlKHtcbiAgICAgIG5vZGVUeXBlOiBub2RlVHlwZUZvckluc3RhbmNlVHlwZSh0aGlzLmRlZmF1bHRJbnN0YW5jZVR5cGUpLFxuICAgICAga3ViZXJuZXRlc1ZlcnNpb246IHByb3BzLmNsdXN0ZXIuY2x1c3RlclZlcnNpb24udmVyc2lvbixcbiAgICB9KS5nZXRJbWFnZSh0aGlzKS5pbWFnZUlkXG5cbiAgICBjb25zdCBsdCA9IG5ldyBlYzIuQ2ZuTGF1bmNoVGVtcGxhdGUodGhpcywgJ0xhdW5jaFRlbXBsYXRlJywge1xuICAgICAgbGF1bmNoVGVtcGxhdGVEYXRhOiB7XG4gICAgICAgIGltYWdlSWQsXG4gICAgICAgIGluc3RhbmNlVHlwZTogdGhpcy5kZWZhdWx0SW5zdGFuY2VUeXBlLnRvU3RyaW5nKCksXG4gICAgICAgIHRhZ1NwZWNpZmljYXRpb25zOiBbXG4gICAgICAgICAge1xuICAgICAgICAgICAgcmVzb3VyY2VUeXBlOiAnaW5zdGFuY2UnLFxuICAgICAgICAgICAgdGFnczogW1xuICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAga2V5OiAnTmFtZScsXG4gICAgICAgICAgICAgICAgdmFsdWU6IGAke1N0YWNrLm9mKHRoaXMpLnN0YWNrTmFtZX0vQ2x1c3Rlci8ke3RoaXMuc3BvdEZsZWV0SWR9YCxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGtleTogYGt1YmVybmV0ZXMuaW8vY2x1c3Rlci8ke3RoaXMuY2x1c3RlclN0YWNrLmNsdXN0ZXIuY2x1c3Rlck5hbWV9YCxcbiAgICAgICAgICAgICAgICB2YWx1ZTogJ293bmVkJyxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFxuICAgICAgICAgICAgXSxcbiAgICAgICAgICB9LFxuICAgICAgICBdLFxuICAgICAgICBpbnN0YW5jZU1hcmtldE9wdGlvbnM6IHtcbiAgICAgICAgICBtYXJrZXRUeXBlOiAnc3BvdCcsXG4gICAgICAgICAgc3BvdE9wdGlvbnM6IHtcbiAgICAgICAgICAgIGJsb2NrRHVyYXRpb25NaW51dGVzOiBwcm9wcy5ibG9ja0R1cmF0aW9uID8/IEJsb2NrRHVyYXRpb24uT05FX0hPVVIsXG4gICAgICAgICAgICBpbnN0YW5jZUludGVycnVwdGlvbkJlaGF2aW9yOiBwcm9wcy5pbnN0YW5jZUludGVycnVwdGlvbkJlaGF2aW9yID8/IEluc3RhbmNlSW50ZXJydXB0aW9uQmVoYXZpb3IuVEVSTUlOQVRFLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICAgIC8vIHVzZXJEYXRhOiBjZGsuRm4uYmFzZTY0KGNhcGFjaXR5QXNnLnVzZXJEYXRhLnJlbmRlcigpKSxcbiAgICAgICAgdXNlckRhdGE6IEZuLmJhc2U2NCh1c2VyRGF0YS5yZW5kZXIoKSksXG4gICAgICAgIHNlY3VyaXR5R3JvdXBJZHM6IHNnLmNvbm5lY3Rpb25zLnNlY3VyaXR5R3JvdXBzLm1hcChtID0+IG0uc2VjdXJpdHlHcm91cElkKSxcbiAgICAgICAgaWFtSW5zdGFuY2VQcm9maWxlOiB7XG4gICAgICAgICAgYXJuOiBpbnN0YW5jZVByb2ZpbGUuYXR0ckFybixcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgfSlcblxuICAgIGNvbnN0IHNwb3RGbGVldFJvbGUgPSBuZXcgaWFtLlJvbGUodGhpcywgJ0ZsZWV0Um9sZScsIHtcbiAgICAgIGFzc3VtZWRCeTogbmV3IGlhbS5TZXJ2aWNlUHJpbmNpcGFsKCdzcG90ZmxlZXQuYW1hem9uYXdzLmNvbScpLFxuICAgICAgbWFuYWdlZFBvbGljaWVzOiBbXG4gICAgICAgIGlhbS5NYW5hZ2VkUG9saWN5LmZyb21Bd3NNYW5hZ2VkUG9saWN5TmFtZSgnc2VydmljZS1yb2xlL0FtYXpvbkVDMlNwb3RGbGVldFRhZ2dpbmdSb2xlJyksXG4gICAgICBdLFxuICAgIH0pXG5cblxuICAgIGNvbnN0IG92ZXJyaWRlcyA9IFtdXG4gICAgZm9yIChjb25zdCBzIG9mIHRoaXMuY2x1c3RlclN0YWNrLmNsdXN0ZXIudnBjLnByaXZhdGVTdWJuZXRzKSB7XG4gICAgICBvdmVycmlkZXMucHVzaCh7IHN1Ym5ldElkOiBzLnN1Ym5ldElkIH0pXG4gICAgfVxuICAgIG5ldyBlYzIuQ2ZuU3BvdEZsZWV0KHRoaXMsIGlkLCB7XG4gICAgICBzcG90RmxlZXRSZXF1ZXN0Q29uZmlnRGF0YToge1xuICAgICAgICBsYXVuY2hUZW1wbGF0ZUNvbmZpZ3M6IFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICBsYXVuY2hUZW1wbGF0ZVNwZWNpZmljYXRpb246IHtcbiAgICAgICAgICAgICAgbGF1bmNoVGVtcGxhdGVJZDogbHQucmVmLFxuICAgICAgICAgICAgICB2ZXJzaW9uOiBsdC5hdHRyTGF0ZXN0VmVyc2lvbk51bWJlcixcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBvdmVycmlkZXMsXG4gICAgICAgICAgfSxcbiAgICAgICAgXSxcbiAgICAgICAgaWFtRmxlZXRSb2xlOiBzcG90RmxlZXRSb2xlLnJvbGVBcm4sXG4gICAgICAgIHRhcmdldENhcGFjaXR5OiBwcm9wcy50YXJnZXRDYXBhY2l0eSA/PyAxLFxuICAgICAgICB2YWxpZEZyb206IHByb3BzLnZhbGlkRnJvbSxcbiAgICAgICAgdmFsaWRVbnRpbDogcHJvcHMudmFsaWRVbnRpbCxcbiAgICAgICAgdGVybWluYXRlSW5zdGFuY2VzV2l0aEV4cGlyYXRpb246IHByb3BzLnRlcm1pbmF0ZUluc3RhbmNlc1dpdGhFeHBpcmF0aW9uLFxuICAgICAgfSxcbiAgICB9KVxuXG4gICAgdGhpcy5jbHVzdGVyU3RhY2suY2x1c3Rlci5hd3NBdXRoLmFkZFJvbGVNYXBwaW5nKHRoaXMuaW5zdGFuY2VSb2xlLCB7XG4gICAgICB1c2VybmFtZTogJ3N5c3RlbTpub2RlOnt7RUMyUHJpdmF0ZUROU05hbWV9fScsXG4gICAgICBncm91cHM6IFtcbiAgICAgICAgJ3N5c3RlbTpib290c3RyYXBwZXJzJyxcbiAgICAgICAgJ3N5c3RlbTpub2RlcycsXG4gICAgICBdLFxuICAgIH0pO1xuICAgIFxuICB9XG59XG5cbmNvbnN0IEdQVV9JTlNUQU5DRVRZUEVTID0gWydwMicsICdwMycsICdnNCddO1xuXG5mdW5jdGlvbiBub2RlVHlwZUZvckluc3RhbmNlVHlwZShpbnN0YW5jZVR5cGU6IGVjMi5JbnN0YW5jZVR5cGUpIHtcbiAgcmV0dXJuIEdQVV9JTlNUQU5DRVRZUEVTLmluY2x1ZGVzKGluc3RhbmNlVHlwZS50b1N0cmluZygpLnN1YnN0cmluZygwLCAyKSkgPyBla3MuTm9kZVR5cGUuR1BVIDogZWtzLk5vZGVUeXBlLlNUQU5EQVJEO1xufVxuIl19