UNPKG

aws-cdk

Version:

CDK Toolkit, the command line tool for CDK apps

190 lines 30.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.isHotswappableEcsServiceChange = void 0; const AWS = require("aws-sdk"); const common_1 = require("./common"); async function isHotswappableEcsServiceChange(logicalId, change, evaluateCfnTemplate) { // the only resource change we can evaluate here is an ECS TaskDefinition if (change.newValue.Type !== 'AWS::ECS::TaskDefinition') { return []; } const ret = []; // We only allow a change in the ContainerDefinitions of the TaskDefinition for now - // it contains the image and environment variables, so seems like a safe bet for now. // We might revisit this decision in the future though! const classifiedChanges = (0, common_1.classifyChanges)(change, ['ContainerDefinitions']); classifiedChanges.reportNonHotswappablePropertyChanges(ret); // find all ECS Services that reference the TaskDefinition that changed const resourcesReferencingTaskDef = evaluateCfnTemplate.findReferencesTo(logicalId); const ecsServiceResourcesReferencingTaskDef = resourcesReferencingTaskDef.filter(r => r.Type === 'AWS::ECS::Service'); const ecsServicesReferencingTaskDef = new Array(); for (const ecsServiceResource of ecsServiceResourcesReferencingTaskDef) { const serviceArn = await evaluateCfnTemplate.findPhysicalNameFor(ecsServiceResource.LogicalId); if (serviceArn) { ecsServicesReferencingTaskDef.push({ serviceArn }); } } if (ecsServicesReferencingTaskDef.length === 0) { // if there are no resources referencing the TaskDefinition, // hotswap is not possible in FALL_BACK mode (0, common_1.reportNonHotswappableChange)(ret, change, undefined, 'No ECS services reference the changed task definition', false); } if (resourcesReferencingTaskDef.length > ecsServicesReferencingTaskDef.length) { // if something besides an ECS Service is referencing the TaskDefinition, // hotswap is not possible in FALL_BACK mode const nonEcsServiceTaskDefRefs = resourcesReferencingTaskDef.filter(r => r.Type !== 'AWS::ECS::Service'); for (const taskRef of nonEcsServiceTaskDefRefs) { (0, common_1.reportNonHotswappableChange)(ret, change, undefined, `A resource '${taskRef.LogicalId}' with Type '${taskRef.Type}' that is not an ECS Service was found referencing the changed TaskDefinition '${logicalId}'`); } } const namesOfHotswappableChanges = Object.keys(classifiedChanges.hotswappableProps); if (namesOfHotswappableChanges.length > 0) { const taskDefinitionResource = await prepareTaskDefinitionChange(evaluateCfnTemplate, logicalId, change); ret.push({ hotswappable: true, resourceType: change.newValue.Type, propsChanged: namesOfHotswappableChanges, service: 'ecs-service', resourceNames: [ `ECS Task Definition '${await taskDefinitionResource.Family}'`, ...ecsServicesReferencingTaskDef.map(ecsService => `ECS Service '${ecsService.serviceArn.split('/')[2]}'`), ], apply: async (sdk) => { // Step 1 - update the changed TaskDefinition, creating a new TaskDefinition Revision // we need to lowercase the evaluated TaskDef from CloudFormation, // as the AWS SDK uses lowercase property names for these // The SDK requires more properties here than its worth doing explicit typing for // instead, just use all the old values in the diff to fill them in implicitly const lowercasedTaskDef = (0, common_1.transformObjectKeys)(taskDefinitionResource, common_1.lowerCaseFirstCharacter, { // All the properties that take arbitrary string as keys i.e. { "string" : "string" } // https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_RegisterTaskDefinition.html#API_RegisterTaskDefinition_RequestSyntax ContainerDefinitions: { DockerLabels: true, FirelensConfiguration: { Options: true, }, LogConfiguration: { Options: true, }, }, Volumes: { DockerVolumeConfiguration: { DriverOpts: true, Labels: true, }, }, }); const registerTaskDefResponse = await sdk.ecs().registerTaskDefinition(lowercasedTaskDef).promise(); const taskDefRevArn = registerTaskDefResponse.taskDefinition?.taskDefinitionArn; // Step 2 - update the services using that TaskDefinition to point to the new TaskDefinition Revision const servicePerClusterUpdates = {}; for (const ecsService of ecsServicesReferencingTaskDef) { const clusterName = ecsService.serviceArn.split('/')[1]; const existingClusterPromises = servicePerClusterUpdates[clusterName]; let clusterPromises; if (existingClusterPromises) { clusterPromises = existingClusterPromises; } else { clusterPromises = []; servicePerClusterUpdates[clusterName] = clusterPromises; } // Forcing New Deployment and setting Minimum Healthy Percent to 0. // As CDK HotSwap is development only, this seems the most efficient way to ensure all tasks are replaced immediately, regardless of original amount. clusterPromises.push({ promise: sdk.ecs().updateService({ service: ecsService.serviceArn, taskDefinition: taskDefRevArn, cluster: clusterName, forceNewDeployment: true, deploymentConfiguration: { minimumHealthyPercent: 0, }, }).promise(), ecsService: ecsService, }); } await Promise.all(Object.values(servicePerClusterUpdates) .map(clusterUpdates => { return Promise.all(clusterUpdates.map(serviceUpdate => serviceUpdate.promise)); })); // Step 3 - wait for the service deployments triggered in Step 2 to finish // configure a custom Waiter sdk.ecs().api.waiters.deploymentToFinish = { name: 'DeploymentToFinish', operation: 'describeServices', delay: 10, maxAttempts: 60, acceptors: [ { matcher: 'pathAny', argument: 'failures[].reason', expected: 'MISSING', state: 'failure', }, { matcher: 'pathAny', argument: 'services[].status', expected: 'DRAINING', state: 'failure', }, { matcher: 'pathAny', argument: 'services[].status', expected: 'INACTIVE', state: 'failure', }, { matcher: 'path', argument: "length(services[].deployments[? status == 'PRIMARY' && runningCount < desiredCount][]) == `0`", expected: true, state: 'success', }, ], }; // create a custom Waiter that uses the deploymentToFinish configuration added above const deploymentWaiter = new AWS.ResourceWaiter(sdk.ecs(), 'deploymentToFinish'); // wait for all of the waiters to finish await Promise.all(Object.entries(servicePerClusterUpdates).map(([clusterName, serviceUpdates]) => { return deploymentWaiter.wait({ cluster: clusterName, services: serviceUpdates.map(serviceUpdate => serviceUpdate.ecsService.serviceArn), }).promise(); })); }, }); } return ret; } exports.isHotswappableEcsServiceChange = isHotswappableEcsServiceChange; async function prepareTaskDefinitionChange(evaluateCfnTemplate, logicalId, change) { const taskDefinitionResource = { ...change.oldValue.Properties, ContainerDefinitions: change.newValue.Properties?.ContainerDefinitions, }; // first, let's get the name of the family const familyNameOrArn = await evaluateCfnTemplate.establishResourcePhysicalName(logicalId, taskDefinitionResource?.Family); if (!familyNameOrArn) { // if the Family property has not been provided, and we can't find it in the current Stack, // this means hotswapping is not possible return; } // the physical name of the Task Definition in CloudFormation includes its current revision number at the end, // remove it if needed const familyNameOrArnParts = familyNameOrArn.split(':'); const family = familyNameOrArnParts.length > 1 // familyNameOrArn is actually an ARN, of the format 'arn:aws:ecs:region:account:task-definition/<family-name>:<revision-nr>' // so, take the 6th element, at index 5, and split it on '/' ? familyNameOrArnParts[5].split('/')[1] // otherwise, familyNameOrArn is just the simple name evaluated from the CloudFormation template : familyNameOrArn; // then, let's evaluate the body of the remainder of the TaskDef (without the Family property) return { ...await evaluateCfnTemplate.evaluateCfnExpression({ ...(taskDefinitionResource ?? {}), Family: undefined, }), Family: family, }; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWNzLXNlcnZpY2VzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiZWNzLXNlcnZpY2VzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLCtCQUErQjtBQUMvQixxQ0FBd0s7QUFJakssS0FBSyxVQUFVLDhCQUE4QixDQUNsRCxTQUFpQixFQUFFLE1BQW1DLEVBQUUsbUJBQW1EO0lBRTNHLHlFQUF5RTtJQUN6RSxJQUFJLE1BQU0sQ0FBQyxRQUFRLENBQUMsSUFBSSxLQUFLLDBCQUEwQixFQUFFO1FBQ3ZELE9BQU8sRUFBRSxDQUFDO0tBQ1g7SUFFRCxNQUFNLEdBQUcsR0FBd0IsRUFBRSxDQUFDO0lBRXBDLHFGQUFxRjtJQUNyRixxRkFBcUY7SUFDckYsdURBQXVEO0lBQ3ZELE1BQU0saUJBQWlCLEdBQUcsSUFBQSx3QkFBZSxFQUFDLE1BQU0sRUFBRSxDQUFDLHNCQUFzQixDQUFDLENBQUMsQ0FBQztJQUM1RSxpQkFBaUIsQ0FBQyxvQ0FBb0MsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUU1RCx1RUFBdUU7SUFDdkUsTUFBTSwyQkFBMkIsR0FBRyxtQkFBbUIsQ0FBQyxnQkFBZ0IsQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUNwRixNQUFNLHFDQUFxQyxHQUFHLDJCQUEyQixDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLEtBQUssbUJBQW1CLENBQUMsQ0FBQztJQUN0SCxNQUFNLDZCQUE2QixHQUFHLElBQUksS0FBSyxFQUFjLENBQUM7SUFDOUQsS0FBSyxNQUFNLGtCQUFrQixJQUFJLHFDQUFxQyxFQUFFO1FBQ3RFLE1BQU0sVUFBVSxHQUFHLE1BQU0sbUJBQW1CLENBQUMsbUJBQW1CLENBQUMsa0JBQWtCLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDL0YsSUFBSSxVQUFVLEVBQUU7WUFDZCw2QkFBNkIsQ0FBQyxJQUFJLENBQUMsRUFBRSxVQUFVLEVBQUUsQ0FBQyxDQUFDO1NBQ3BEO0tBQ0Y7SUFD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WyJpbXBvcnQgKiBhcyBBV1MgZnJvbSAnYXdzLXNkayc7XG5pbXBvcnQgeyBDaGFuZ2VIb3Rzd2FwUmVzdWx0LCBjbGFzc2lmeUNoYW5nZXMsIEhvdHN3YXBwYWJsZUNoYW5nZUNhbmRpZGF0ZSwgbG93ZXJDYXNlRmlyc3RDaGFyYWN0ZXIsIHJlcG9ydE5vbkhvdHN3YXBwYWJsZUNoYW5nZSwgdHJhbnNmb3JtT2JqZWN0S2V5cyB9IGZyb20gJy4vY29tbW9uJztcbmltcG9ydCB7IElTREsgfSBmcm9tICcuLi9hd3MtYXV0aCc7XG5pbXBvcnQgeyBFdmFsdWF0ZUNsb3VkRm9ybWF0aW9uVGVtcGxhdGUgfSBmcm9tICcuLi9ldmFsdWF0ZS1jbG91ZGZvcm1hdGlvbi10ZW1wbGF0ZSc7XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBpc0hvdHN3YXBwYWJsZUVjc1NlcnZpY2VDaGFuZ2UoXG4gIGxvZ2ljYWxJZDogc3RyaW5nLCBjaGFuZ2U6IEhvdHN3YXBwYWJsZUNoYW5nZUNhbmRpZGF0ZSwgZXZhbHVhdGVDZm5UZW1wbGF0ZTogRXZhbHVhdGVDbG91ZEZvcm1hdGlvblRlbXBsYXRlLFxuKTogUHJvbWlzZTxDaGFuZ2VIb3Rzd2FwUmVzdWx0PiB7XG4gIC8vIHRoZSBvbmx5IHJlc291cmNlIGNoYW5nZSB3ZSBjYW4gZXZhbHVhdGUgaGVyZSBpcyBhbiBFQ1MgVGFza0RlZmluaXRpb25cbiAgaWYgKGNoYW5nZS5uZXdWYWx1ZS5UeXBlICE9PSAnQVdTOjpFQ1M6OlRhc2tEZWZpbml0aW9uJykge1xuICAgIHJldHVybiBbXTtcbiAgfVxuXG4gIGNvbnN0IHJldDogQ2hhbmdlSG90c3dhcFJlc3VsdCA9IFtdO1xuXG4gIC8vIFdlIG9ubHkgYWxsb3cgYSBjaGFuZ2UgaW4gdGhlIENvbnRhaW5lckRlZmluaXRpb25zIG9mIHRoZSBUYXNrRGVmaW5pdGlvbiBmb3Igbm93IC1cbiAgLy8gaXQgY29udGFpbnMgdGhlIGltYWdlIGFuZCBlbnZpcm9ubWVudCB2YXJpYWJsZXMsIHNvIHNlZW1zIGxpa2UgYSBzYWZlIGJldCBmb3Igbm93LlxuICAvLyBXZSBtaWdodCByZXZpc2l0IHRoaXMgZGVjaXNpb24gaW4gdGhlIGZ1dHVyZSB0aG91Z2ghXG4gIGNvbnN0IGNsYXNzaWZpZWRDaGFuZ2VzID0gY2xhc3NpZnlDaGFuZ2VzKGNoYW5nZSwgWydDb250YWluZXJEZWZpbml0aW9ucyddKTtcbiAgY2xhc3NpZmllZENoYW5nZXMucmVwb3J0Tm9uSG90c3dhcHBhYmxlUHJvcGVydHlDaGFuZ2VzKHJldCk7XG5cbiAgLy8gZmluZCBhbGwgRUNTIFNlcnZpY2VzIHRoYXQgcmVmZXJlbmNlIHRoZSBUYXNrRGVmaW5pdGlvbiB0aGF0IGNoYW5nZWRcbiAgY29uc3QgcmVzb3VyY2VzUmVmZXJlbmNpbmdUYXNrRGVmID0gZXZhbHVhdGVDZm5UZW1wbGF0ZS5maW5kUmVmZXJlbmNlc1RvKGxvZ2ljYWxJZCk7XG4gIGNvbnN0IGVjc1NlcnZpY2VSZXNvdXJjZXNSZWZlcmVuY2luZ1Rhc2tEZWYgPSByZXNvdXJjZXNSZWZlcmVuY2luZ1Rhc2tEZWYuZmlsdGVyKHIgPT4gci5UeXBlID09PSAnQVdTOjpFQ1M6OlNlcnZpY2UnKTtcbiAgY29uc3QgZWNzU2VydmljZXNSZWZlcmVuY2luZ1Rhc2tEZWYgPSBuZXcgQXJyYXk8RWNzU2VydmljZT4oKTtcbiAgZm9yIChjb25zdCBlY3NTZXJ2aWNlUmVzb3VyY2Ugb2YgZWNzU2VydmljZVJlc291cmNlc1JlZmVyZW5jaW5nVGFza0RlZikge1xuICAgIGNvbnN0IHNlcnZpY2VBcm4gPSBhd2FpdCBldmFsdWF0ZUNmblRlbXBsYXRlLmZpbmRQaHlzaWNhbE5hbWVGb3IoZWNzU2VydmljZVJlc291cmNlLkxvZ2ljYWxJZCk7XG4gICAgaWYgKHNlcnZpY2VBcm4pIHtcbiAgICAgIGVjc1NlcnZpY2VzUmVmZXJlbmNpbmdUYXNrRGVmLnB1c2goeyBzZXJ2aWNlQXJuIH0pO1xuICAgIH1cbiAgfVxuICBpZiAoZWNzU2VydmljZXNSZWZlcmVuY2luZ1Rhc2tEZWYubGVuZ3RoID09PSAwKSB7XG4gICAgLy8gaWYgdGhlcmUgYXJlIG5vIHJlc291cmNlcyByZWZlcmVuY2luZyB0aGUgVGFza0RlZmluaXRpb24sXG4gICAgLy8gaG90c3dhcCBpcyBub3QgcG9zc2libGUgaW4gRkFMTF9CQUNLIG1vZGVcbiAgICByZXBvcnROb25Ib3Rzd2FwcGFibGVDaGFuZ2UocmV0LCBjaGFuZ2UsIHVuZGVmaW5lZCwgJ05vIEVDUyBzZXJ2aWNlcyByZWZlcmVuY2UgdGhlIGNoYW5nZWQgdGFzayBkZWZpbml0aW9uJywgZmFsc2UpO1xuICB9IGlmIChyZXNvdXJjZXNSZWZlcmVuY2luZ1Rhc2tEZWYubGVuZ3RoID4gZWNzU2VydmljZXNSZWZlcmVuY2luZ1Rhc2tEZWYubGVuZ3RoKSB7XG4gICAgLy8gaWYgc29tZXRoaW5nIGJlc2lkZXMgYW4gRUNTIFNlcnZpY2UgaXMgcmVmZXJlbmNpbmcgdGhlIFRhc2tEZWZpbml0aW9uLFxuICAgIC8vIGhvdHN3YXAgaXMgbm90IHBvc3NpYmxlIGluIEZBTExfQkFDSyBtb2RlXG4gICAgY29uc3Qgbm9uRWNzU2VydmljZVRhc2tEZWZSZWZzID0gcmVzb3VyY2VzUmVmZXJlbmNpbmdUYXNrRGVmLmZpbHRlcihyID0+IHIuVHlwZSAhPT0gJ0FXUzo6RUNTOjpTZXJ2aWNlJyk7XG4gICAgZm9yIChjb25zdCB0YXNrUmVmIG9mIG5vbkVjc1NlcnZpY2VUYXNrRGVmUmVmcykge1xuICAgICAgcmVwb3J0Tm9uSG90c3dhcHBhYmxlQ2hhbmdlKHJldCwgY2hhbmdlLCB1bmRlZmluZWQsIGBBIHJlc291cmNlICcke3Rhc2tSZWYuTG9naWNhbElkfScgd2l0aCBUeXBlICcke3Rhc2tSZWYuVHlwZX0nIHRoYXQgaXMgbm90IGFuIEVDUyBTZXJ2aWNlIHdhcyBmb3VuZCByZWZlcmVuY2luZyB0aGUgY2hhbmdlZCBUYXNrRGVmaW5pdGlvbiAnJHtsb2dpY2FsSWR9J2ApO1xuICAgIH1cbiAgfVxuXG4gIGNvbnN0IG5hbWVzT2ZIb3Rzd2FwcGFibGVDaGFuZ2VzID0gT2JqZWN0LmtleXMoY2xhc3NpZmllZENoYW5nZXMuaG90c3dhcHBhYmxlUHJvcHMpO1xuICBpZiAobmFtZXNPZkhvdHN3YXBwYWJsZUNoYW5nZXMubGVuZ3RoID4gMCkge1xuICAgIGNvbnN0IHRhc2tEZWZpbml0aW9uUmVzb3VyY2UgPSBhd2FpdCBwcmVwYXJlVGFza0RlZmluaXRpb25DaGFuZ2UoZXZhbHVhdGVDZm5UZW1wbGF0ZSwgbG9naWNhbElkLCBjaGFuZ2UpO1xuICAgIHJldC5wdXNoKHtcbiAgICAgIGhvdHN3YXBwYWJsZTogdHJ1ZSxcbiAgICAgIHJlc291cmNlVHlwZTogY2hhbmdlLm5ld1ZhbHVlLlR5cGUsXG4gICAgICBwcm9wc0NoYW5nZWQ6IG5hbWVzT2ZIb3Rzd2FwcGFibGVDaGFuZ2VzLFxuICAgICAgc2VydmljZTogJ2Vjcy1zZXJ2aWNlJyxcbiAgICAgIHJlc291cmNlTmFtZXM6IFtcbiAgICAgICAgYEVDUyBUYXNrIERlZmluaXRpb24gJyR7YXdhaXQgdGFza0RlZmluaXRpb25SZXNvdXJjZS5GYW1pbHl9J2AsXG4gICAgICAgIC4uLmVjc1NlcnZpY2VzUmVmZXJlbmNpbmdUYXNrRGVmLm1hcChlY3NTZXJ2aWNlID0+IGBFQ1MgU2VydmljZSAnJHtlY3NTZXJ2aWNlLnNlcnZpY2VBcm4uc3BsaXQoJy8nKVsyXX0nYCksXG4gICAgICBdLFxuICAgICAgYXBwbHk6IGFzeW5jIChzZGs6IElTREspID0+IHtcbiAgICAgICAgLy8gU3RlcCAxIC0gdXBkYXRlIHRoZSBjaGFuZ2VkIFRhc2tEZWZpbml0aW9uLCBjcmVhdGluZyBhIG5ldyBUYXNrRGVmaW5pdGlvbiBSZXZpc2lvblxuICAgICAgICAvLyB3ZSBuZWVkIHRvIGxvd2VyY2FzZSB0aGUgZXZhbHVhdGVkIFRhc2tEZWYgZnJvbSBDbG91ZEZvcm1hdGlvbixcbiAgICAgICAgLy8gYXMgdGhlIEFXUyBTREsgdXNlcyBsb3dlcmNhc2UgcHJvcGVydHkgbmFtZXMgZm9yIHRoZXNlXG5cbiAgICAgICAgLy8gVGhlIFNESyByZXF1aXJlcyBtb3JlIHByb3BlcnRpZXMgaGVyZSB0aGFuIGl0cyB3b3J0aCBkb2luZyBleHBsaWNpdCB0eXBpbmcgZm9yXG4gICAgICAgIC8vIGluc3RlYWQsIGp1c3QgdXNlIGFsbCB0aGUgb2xkIHZhbHVlcyBpbiB0aGUgZGlmZiB0byBmaWxsIHRoZW0gaW4gaW1wbGljaXRseVxuICAgICAgICBjb25zdCBsb3dlcmNhc2VkVGFza0RlZiA9IHRyYW5zZm9ybU9iamVjdEtleXModGFza0RlZmluaXRpb25SZXNvdXJjZSwgbG93ZXJDYXNlRmlyc3RDaGFyYWN0ZXIsIHtcbiAgICAgICAgICAvLyBBbGwgdGhlIHByb3BlcnRpZXMgdGhhdCB0YWtlIGFyYml0cmFyeSBzdHJpbmcgYXMga2V5cyBpLmUuIHsgXCJzdHJpbmdcIiA6IFwic3RyaW5nXCIgfVxuICAgICAgICAgIC8vIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9BbWF6b25FQ1MvbGF0ZXN0L0FQSVJlZmVyZW5jZS9BUElfUmVnaXN0ZXJUYXNrRGVmaW5pdGlvbi5odG1sI0FQSV9SZWdpc3RlclRhc2tEZWZpbml0aW9uX1JlcXVlc3RTeW50YXhcbiAgICAgICAgICBDb250YWluZXJEZWZpbml0aW9uczoge1xuICAgICAgICAgICAgRG9ja2VyTGFiZWxzOiB0cnVlLFxuICAgICAgICAgICAgRmlyZWxlbnNDb25maWd1cmF0aW9uOiB7XG4gICAgICAgICAgICAgIE9wdGlvbnM6IHRydWUsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgTG9nQ29uZmlndXJhdGlvbjoge1xuICAgICAgICAgICAgICBPcHRpb25zOiB0cnVlLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9LFxuICAgICAgICAgIFZvbHVtZXM6IHtcbiAgICAgICAgICAgIERvY2tlclZvbHVtZUNvbmZpZ3VyYXRpb246IHtcbiAgICAgICAgICAgICAgRHJpdmVyT3B0czogdHJ1ZSxcbiAgICAgICAgICAgICAgTGFiZWxzOiB0cnVlLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9LFxuICAgICAgICB9KTtcbiAgICAgICAgY29uc3QgcmVnaXN0ZXJUYXNrRGVmUmVzcG9uc2UgPSBhd2FpdCBzZGsuZWNzKCkucmVnaXN0ZXJUYXNrRGVmaW5pdGlvbihsb3dlcmNhc2VkVGFza0RlZikucHJvbWlzZSgpO1xuICAgICAgICBjb25zdCB0YXNrRGVmUmV2QXJuID0gcmVnaXN0ZXJUYXNrRGVmUmVzcG9uc2UudGFza0RlZmluaXRpb24/LnRhc2tEZWZpbml0aW9uQXJuO1xuXG4gICAgICAgIC8vIFN0ZXAgMiAtIHVwZGF0ZSB0aGUgc2VydmljZXMgdXNpbmcgdGhhdCBUYXNrRGVmaW5pdGlvbiB0byBwb2ludCB0byB0aGUgbmV3IFRhc2tEZWZpbml0aW9uIFJldmlzaW9uXG4gICAgICAgIGNvbnN0IHNlcnZpY2VQZXJDbHVzdGVyVXBkYXRlczogeyBbY2x1c3Rlcjogc3RyaW5nXTogQXJyYXk8eyBwcm9taXNlOiBQcm9taXNlPGFueT4sIGVjc1NlcnZpY2U6IEVjc1NlcnZpY2UgfT4gfSA9IHt9O1xuICAgICAgICBmb3IgKGNvbnN0IGVjc1NlcnZpY2Ugb2YgZWNzU2VydmljZXNSZWZlcmVuY2luZ1Rhc2tEZWYpIHtcbiAgICAgICAgICBjb25zdCBjbHVzdGVyTmFtZSA9IGVjc1NlcnZpY2Uuc2VydmljZUFybi5zcGxpdCgnLycpWzFdO1xuXG4gICAgICAgICAgY29uc3QgZXhpc3RpbmdDbHVzdGVyUHJvbWlzZXMgPSBzZXJ2aWNlUGVyQ2x1c3RlclVwZGF0ZXNbY2x1c3Rlck5hbWVdO1xuICAgICAgICAgIGxldCBjbHVzdGVyUHJvbWlzZXM6IEFycmF5PHsgcHJvbWlzZTogUHJvbWlzZTxhbnk+LCBlY3NTZXJ2aWNlOiBFY3NTZXJ2aWNlIH0+O1xuICAgICAgICAgIGlmIChleGlzdGluZ0NsdXN0ZXJQcm9taXNlcykge1xuICAgICAgICAgICAgY2x1c3RlclByb21pc2VzID0gZXhpc3RpbmdDbHVzdGVyUHJvbWlzZXM7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNsdXN0ZXJQcm9taXNlcyA9IFtdO1xuICAgICAgICAgICAgc2VydmljZVBlckNsdXN0ZXJVcGRhdGVzW2NsdXN0ZXJOYW1lXSA9IGNsdXN0ZXJQcm9taXNlcztcbiAgICAgICAgICB9XG4gICAgICAgICAgLy8gRm9yY2luZyBOZXcgRGVwbG95bWVudCBhbmQgc2V0dGluZyBNaW5pbXVtIEhlYWx0aHkgUGVyY2VudCB0byAwLlxuICAgICAgICAgIC8vIEFzIENESyBIb3RTd2FwIGlzIGRldmVsb3BtZW50IG9ubHksIHRoaXMgc2VlbXMgdGhlIG1vc3QgZWZmaWNpZW50IHdheSB0byBlbnN1cmUgYWxsIHRhc2tzIGFyZSByZXBsYWNlZCBpbW1lZGlhdGVseSwgcmVnYXJkbGVzcyBvZiBvcmlnaW5hbCBhbW91bnQuXG4gICAgICAgICAgY2x1c3RlclByb21pc2VzLnB1c2goe1xuICAgICAgICAgICAgcHJvbWlzZTogc2RrLmVjcygpLnVwZGF0ZVNlcnZpY2Uoe1xuICAgICAgICAgICAgICBzZXJ2aWNlOiBlY3NTZXJ2aWNlLnNlcnZpY2VBcm4sXG4gICAgICAgICAgICAgIHRhc2tEZWZpbml0aW9uOiB0YXNrRGVmUmV2QXJuLFxuICAgICAgICAgICAgICBjbHVzdGVyOiBjbHVzdGVyTmFtZSxcbiAgICAgICAgICAgICAgZm9yY2VOZXdEZXBsb3ltZW50OiB0cnVlLFxuICAgICAgICAgICAgICBkZXBsb3ltZW50Q29uZmlndXJhdGlvbjoge1xuICAgICAgICAgICAgICAgIG1pbmltdW1IZWFsdGh5UGVyY2VudDogMCxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH0pLnByb21pc2UoKSxcbiAgICAgICAgICAgIGVjc1NlcnZpY2U6IGVjc1NlcnZpY2UsXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoT2JqZWN0LnZhbHVlcyhzZXJ2aWNlUGVyQ2x1c3RlclVwZGF0ZXMpXG4gICAgICAgICAgLm1hcChjbHVzdGVyVXBkYXRlcyA9PiB7XG4gICAgICAgICAgICByZXR1cm4gUHJvbWlzZS5hbGwoY2x1c3RlclVwZGF0ZXMubWFwKHNlcnZpY2VVcGRhdGUgPT4gc2VydmljZVVwZGF0ZS5wcm9taXNlKSk7XG4gICAgICAgICAgfSksXG4gICAgICAgICk7XG5cbiAgICAgICAgLy8gU3RlcCAzIC0gd2FpdCBmb3IgdGhlIHNlcnZpY2UgZGVwbG95bWVudHMgdHJpZ2dlcmVkIGluIFN0ZXAgMiB0byBmaW5pc2hcbiAgICAgICAgLy8gY29uZmlndXJlIGEgY3VzdG9tIFdhaXRlclxuICAgICAgICAoc2RrLmVjcygpIGFzIGFueSkuYXBpLndhaXRlcnMuZGVwbG95bWVudFRvRmluaXNoID0ge1xuICAgICAgICAgIG5hbWU6ICdEZXBsb3ltZW50VG9GaW5pc2gnLFxuICAgICAgICAgIG9wZXJhdGlvbjogJ2Rlc2NyaWJlU2VydmljZXMnLFxuICAgICAgICAgIGRlbGF5OiAxMCxcbiAgICAgICAgICBtYXhBdHRlbXB0czogNjAsXG4gICAgICAgICAgYWNjZXB0b3JzOiBbXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIG1hdGNoZXI6ICdwYXRoQW55JyxcbiAgICAgICAgICAgICAgYXJndW1lbnQ6ICdmYWlsdXJlc1tdLnJlYXNvbicsXG4gICAgICAgICAgICAgIGV4cGVjdGVkOiAnTUlTU0lORycsXG4gICAgICAgICAgICAgIHN0YXRlOiAnZmFpbHVyZScsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICBtYXRjaGVyOiAncGF0aEFueScsXG4gICAgICAgICAgICAgIGFyZ3VtZW50OiAnc2VydmljZXNbXS5zdGF0dXMnLFxuICAgICAgICAgICAgICBleHBlY3RlZDogJ0RSQUlOSU5HJyxcbiAgICAgICAgICAgICAgc3RhdGU6ICdmYWlsdXJlJyxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIG1hdGNoZXI6ICdwYXRoQW55JyxcbiAgICAgICAgICAgICAgYXJndW1lbnQ6ICdzZXJ2aWNlc1tdLnN0YXR1cycsXG4gICAgICAgICAgICAgIGV4cGVjdGVkOiAnSU5BQ1RJVkUnLFxuICAgICAgICAgICAgICBzdGF0ZTogJ2ZhaWx1cmUnLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgbWF0Y2hlcjogJ3BhdGgnLFxuICAgICAgICAgICAgICBhcmd1bWVudDogXCJsZW5ndGgoc2VydmljZXNbXS5kZXBsb3ltZW50c1s/IHN0YXR1cyA9PSAnUFJJTUFSWScgJiYgcnVubmluZ0NvdW50IDwgZGVzaXJlZENvdW50XVtdKSA9PSBgMGBcIixcbiAgICAgICAgICAgICAgZXhwZWN0ZWQ6IHRydWUsXG4gICAgICAgICAgICAgIHN0YXRlOiAnc3VjY2VzcycsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIF0sXG4gICAgICAgIH07XG4gICAgICAgIC8vIGNyZWF0ZSBhIGN1c3RvbSBXYWl0ZXIgdGhhdCB1c2VzIHRoZSBkZXBsb3ltZW50VG9GaW5pc2ggY29uZmlndXJhdGlvbiBhZGRlZCBhYm92ZVxuICAgICAgICBjb25zdCBkZXBsb3ltZW50V2FpdGVyID0gbmV3IChBV1MgYXMgYW55KS5SZXNvdXJjZVdhaXRlcihzZGsuZWNzKCksICdkZXBsb3ltZW50VG9GaW5pc2gnKTtcbiAgICAgICAgLy8gd2FpdCBmb3IgYWxsIG9mIHRoZSB3YWl0ZXJzIHRvIGZpbmlzaFxuICAgICAgICBhd2FpdCBQcm9taXNlLmFsbChPYmplY3QuZW50cmllcyhzZXJ2aWNlUGVyQ2x1c3RlclVwZGF0ZXMpLm1hcCgoW2NsdXN0ZXJOYW1lLCBzZXJ2aWNlVXBkYXRlc10pID0+IHtcbiAgICAgICAgICByZXR1cm4gZGVwbG95bWVudFdhaXRlci53YWl0KHtcbiAgICAgICAgICAgIGNsdXN0ZXI6IGNsdXN0ZXJOYW1lLFxuICAgICAgICAgICAgc2VydmljZXM6IHNlcnZpY2VVcGRhdGVzLm1hcChzZXJ2aWNlVXBkYXRlID0+IHNlcnZpY2VVcGRhdGUuZWNzU2VydmljZS5zZXJ2aWNlQXJuKSxcbiAgICAgICAgICB9KS5wcm9taXNlKCk7XG4gICAgICAgIH0pKTtcbiAgICAgIH0sXG4gICAgfSk7XG4gIH1cblxuICByZXR1cm4gcmV0O1xufVxuXG5pbnRlcmZhY2UgRWNzU2VydmljZSB7XG4gIHJlYWRvbmx5IHNlcnZpY2VBcm46IHN0cmluZztcbn1cblxuYXN5bmMgZnVuY3Rpb24gcHJlcGFyZVRhc2tEZWZpbml0aW9uQ2hhbmdlKFxuICBldmFsdWF0ZUNmblRlbXBsYXRlOiBFdmFsdWF0ZUNsb3VkRm9ybWF0aW9uVGVtcGxhdGUsIGxvZ2ljYWxJZDogc3RyaW5nLCBjaGFuZ2U6IEhvdHN3YXBwYWJsZUNoYW5nZUNhbmRpZGF0ZSxcbikge1xuICBjb25zdCB0YXNrRGVmaW5pdGlvblJlc291cmNlOiB7IFtuYW1lOiBzdHJpbmddOiBhbnkgfSA9IHtcbiAgICAuLi5jaGFuZ2Uub2xkVmFsdWUuUHJvcGVydGllcyxcbiAgICBDb250YWluZXJEZWZpbml0aW9uczogY2hhbmdlLm5ld1ZhbHVlLlByb3BlcnRpZXM/LkNvbnRhaW5lckRlZmluaXRpb25zLFxuICB9O1xuICAvLyBmaXJzdCwgbGV0J3MgZ2V0IHRoZSBuYW1lIG9mIHRoZSBmYW1pbHlcbiAgY29uc3QgZmFtaWx5TmFtZU9yQXJuID0gYXdhaXQgZXZhbHVhdGVDZm5UZW1wbGF0ZS5lc3RhYmxpc2hSZXNvdXJjZVBoeXNpY2FsTmFtZShsb2dpY2FsSWQsIHRhc2tEZWZpbml0aW9uUmVzb3VyY2U/LkZhbWlseSk7XG4gIGlmICghZmFtaWx5TmFtZU9yQXJuKSB7XG4gICAgLy8gaWYgdGhlIEZhbWlseSBwcm9wZXJ0eSBoYXMgbm90IGJlZW4gcHJvdmlkZWQsIGFuZCB3ZSBjYW4ndCBmaW5kIGl0IGluIHRoZSBjdXJyZW50IFN0YWNrLFxuICAgIC8vIHRoaXMgbWVhbnMgaG90c3dhcHBpbmcgaXMgbm90IHBvc3NpYmxlXG4gICAgcmV0dXJuO1xuICB9XG4gIC8vIHRoZSBwaHlzaWNhbCBuYW1lIG9mIHRoZSBUYXNrIERlZmluaXRpb24gaW4gQ2xvdWRGb3JtYXRpb24gaW5jbHVkZXMgaXRzIGN1cnJlbnQgcmV2aXNpb24gbnVtYmVyIGF0IHRoZSBlbmQsXG4gIC8vIHJlbW92ZSBpdCBpZiBuZWVkZWRcbiAgY29uc3QgZmFtaWx5TmFtZU9yQXJuUGFydHMgPSBmYW1pbHlOYW1lT3JBcm4uc3BsaXQoJzonKTtcbiAgY29uc3QgZmFtaWx5ID0gZmFtaWx5TmFtZU9yQXJuUGFydHMubGVuZ3RoID4gMVxuICAgIC8vIGZhbWlseU5hbWVPckFybiBpcyBhY3R1YWxseSBhbiBBUk4sIG9mIHRoZSBmb3JtYXQgJ2Fybjphd3M6ZWNzOnJlZ2lvbjphY2NvdW50OnRhc2stZGVmaW5pdGlvbi88ZmFtaWx5LW5hbWU+OjxyZXZpc2lvbi1ucj4nXG4gICAgLy8gc28sIHRha2UgdGhlIDZ0aCBlbGVtZW50LCBhdCBpbmRleCA1LCBhbmQgc3BsaXQgaXQgb24gJy8nXG4gICAgPyBmYW1pbHlOYW1lT3JBcm5QYXJ0c1s1XS5zcGxpdCgnLycpWzFdXG4gICAgLy8gb3RoZXJ3aXNlLCBmYW1pbHlOYW1lT3JBcm4gaXMganVzdCB0aGUgc2ltcGxlIG5hbWUgZXZhbHVhdGVkIGZyb20gdGhlIENsb3VkRm9ybWF0aW9uIHRlbXBsYXRlXG4gICAgOiBmYW1pbHlOYW1lT3JBcm47XG4gIC8vIHRoZW4sIGxldCdzIGV2YWx1YXRlIHRoZSBib2R5IG9mIHRoZSByZW1haW5kZXIgb2YgdGhlIFRhc2tEZWYgKHdpdGhvdXQgdGhlIEZhbWlseSBwcm9wZXJ0eSlcbiAgcmV0dXJuIHtcbiAgICAuLi5hd2FpdCBldmFsdWF0ZUNmblRlbXBsYXRlLmV2YWx1YXRlQ2ZuRXhwcmVzc2lvbih7XG4gICAgICAuLi4odGFza0RlZmluaXRpb25SZXNvdXJjZSA/PyB7fSksXG4gICAgICBGYW1pbHk6IHVuZGVmaW5lZCxcbiAgICB9KSxcbiAgICBGYW1pbHk6IGZhbWlseSxcbiAgfTtcbn1cbiJdfQ==