aws-delivlib
Version:
A fabulous library for defining continuous pipelines for building, testing and releasing code libraries.
171 lines • 29.6 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.EcrMirrorAspect = exports.EcrMirror = void 0;
const aws_cdk_lib_1 = require("aws-cdk-lib");
const constructs_1 = require("constructs");
const constants_1 = require("../constants");
/**
* Synchronize images from DockerHub to an ECR registry in the AWS account.
* This is particularly useful to workaround DockerHub's throttling on pulls and use ECR instead.
*/
class EcrMirror extends constructs_1.Construct {
constructor(scope, id, props) {
super(scope, id);
this._repos = new Map();
this._repoTagsSeen = new Set();
if (!props.schedule && !props.autoStart) {
throw new Error('Either schedule or autoStart must be provided');
}
const ecrRegistry = `${aws_cdk_lib_1.Stack.of(scope).account}.dkr.ecr.${aws_cdk_lib_1.Stack.of(scope).region}.amazonaws.com`;
const commands = [];
const assets = new Array();
const codeBuildSecretValue = (key, auth) => {
return `${props.dockerHubCredentials.secret.secretName}:${key}:${auth.versionStage ?? 'AWSCURRENT'}`;
};
const username = codeBuildSecretValue(props.dockerHubCredentials.usernameKey, props.dockerHubCredentials);
const password = codeBuildSecretValue(props.dockerHubCredentials.passwordKey, props.dockerHubCredentials);
if (!props.buildImage) {
aws_cdk_lib_1.Annotations.of(this).addWarningV2('aws-delivlib:EcrMirror.missingBuildImage', 'Prefer supplying an explicit build image to relying on the default superchain.');
}
this.project = new aws_cdk_lib_1.aws_codebuild.Project(this, 'EcrPushImages', {
description: aws_cdk_lib_1.Lazy.string({ produce: () => `Synchronize ${props.sources.length} images from DockerHub to local ECR` }),
environment: {
privileged: true,
buildImage: props.buildImage ?? aws_cdk_lib_1.aws_codebuild.LinuxBuildImage.fromDockerRegistry(constants_1.DEFAULT_SUPERCHAIN_IMAGE),
},
environmentVariables: {
// DockerHub credentials to avoid throttling
DOCKERHUB_USERNAME: { value: username, type: aws_cdk_lib_1.aws_codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER },
DOCKERHUB_PASSWORD: { value: password, type: aws_cdk_lib_1.aws_codebuild.BuildEnvironmentVariableType.SECRETS_MANAGER },
},
buildSpec: aws_cdk_lib_1.aws_codebuild.BuildSpec.fromObject(aws_cdk_lib_1.Lazy.any({
produce: () => {
return {
version: '0.2',
phases: {
build: {
commands: [
// start the docker daemon
'nohup /usr/bin/dockerd --host=unix:///var/run/docker.sock --host=tcp://127.0.0.1:2375 --storage-driver=overlay2&',
'timeout 15 sh -c "until docker info; do echo .; sleep 1; done"',
// login to dockerhub so we won't get throttled
'docker login -u ${DOCKERHUB_USERNAME} -p ${DOCKERHUB_PASSWORD}',
// login to ecr so we can push to it
`aws ecr get-login-password | docker login --username AWS --password-stdin ${ecrRegistry}`,
// login to ecr-public so we can pull from it with improved rate limits
'aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws',
...commands,
],
},
},
};
},
})),
ssmSessionPermissions: true,
});
// Ensure the runner has PULL access to ECR-Public.
this.project.role.addManagedPolicy(aws_cdk_lib_1.aws_iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonElasticContainerRegistryPublicReadOnly'));
// Give the project access to the Docker Hub credentials
// Required for access to private images and to avoid throttling of unauthorized requests
props.dockerHubCredentials.secret.grantRead(this.project);
for (const image of props.sources) {
const result = image.bind({
scope: this,
ecrRegistry,
syncJob: this.project,
});
commands.push(...result.commands);
const repoTag = `${result.repositoryName}:${result.tag}`;
if (this._repoTagsSeen.has(repoTag)) {
throw new Error(`Mirror source with repository name [${result.repositoryName}] and tag [${result.tag}] already exists.`);
}
this._repoTagsSeen.add(repoTag);
this.createMirrorRepo(result.repositoryName);
const ecrImageUri = `${ecrRegistry}/${result.repositoryName}:${result.tag}`;
commands.push(`docker push ${ecrImageUri}`);
// clean after each push so that we don't fillup disk space
// possibly failing the next pull.
commands.push('docker image prune --all --force');
}
// CodeBuild needs to read the secret to resolve environment variables
props.dockerHubCredentials.secret.grantRead(this.project);
aws_cdk_lib_1.aws_ecr.AuthorizationToken.grantRead(this.project);
this._repos.forEach((r, _) => r.grantPullPush(this.project));
// this project needs to download the assets so it can build them
assets.forEach(a => a.grantRead(this.project));
if (props.autoStart) {
new aws_cdk_lib_1.custom_resources.AwsCustomResource(this, 'BuildExecution', {
installLatestAwsSdk: false,
policy: aws_cdk_lib_1.custom_resources.AwsCustomResourcePolicy.fromSdkCalls({ resources: [this.project.projectArn] }),
onUpdate: {
action: 'startBuild',
service: 'CodeBuild',
parameters: {
projectName: this.project.projectName,
// to tigger the build on every update
idempotencyToken: `${Date.now()}`,
},
physicalResourceId: aws_cdk_lib_1.custom_resources.PhysicalResourceId.of('EcrRegistryExecution'),
// need since the default reponse if greater than the 4k limit for custom resources.
outputPaths: ['build.id'],
},
});
}
if (props.schedule) {
new aws_cdk_lib_1.aws_events.Rule(this, 'ScheduledTrigger', {
description: 'Trigger ECR mirror job',
schedule: props.schedule,
targets: [new aws_cdk_lib_1.aws_events_targets.CodeBuildProject(this.project)],
});
}
}
createMirrorRepo(ecrRepositoryName) {
if (this._repos.get(ecrRepositoryName)) {
return;
}
const repository = new aws_cdk_lib_1.aws_ecr.Repository(this, `Repo${ecrRepositoryName}`, {
repositoryName: ecrRepositoryName,
});
this._repos.set(ecrRepositoryName, repository);
}
/**
* Get the target ECR repository for the given repository name and tag.
* @param repositoryName The ECR repository with this name
* @param tag the tag for the repository, defaults to 'latest'
*/
ecrRepository(repositoryName) {
return this._repos.get(repositoryName);
}
}
exports.EcrMirror = EcrMirror;
;
/**
* An aspect that walks through the construct tree and replaces CodeBuild jobs with Docker images
* with ECR equivalents found in the EcrMirror.
*/
class EcrMirrorAspect {
constructor(mirror) {
this.mirror = mirror;
}
visit(construct) {
if (construct instanceof aws_cdk_lib_1.aws_codebuild.Project) {
const cfnproject = construct.node.defaultChild;
if (!aws_cdk_lib_1.Token.isUnresolved(cfnproject.environment)) {
const env = cfnproject.environment;
const imageName = env.image.split(':')[0];
const tag = env.image.split(':')[1];
const replacement = this.mirror.ecrRepository(imageName);
if (replacement) {
cfnproject.environment = {
...env,
image: aws_cdk_lib_1.aws_codebuild.LinuxBuildImage.fromEcrRepository(replacement, tag).imageId,
};
replacement.grantPull(construct);
aws_cdk_lib_1.aws_ecr.AuthorizationToken.grantRead(construct);
}
}
}
}
}
exports.EcrMirrorAspect = EcrMirrorAspect;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWNyLW1pcnJvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImVjci1taXJyb3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsNkNBV3FCO0FBQ3JCLDJDQUFtRDtBQUVuRCw0Q0FBd0Q7QUF1RXhEOzs7R0FHRztBQUNILE1BQWEsU0FBVSxTQUFRLHNCQUFTO0lBT3RDLFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBcUI7UUFDN0QsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztRQU5GLFdBQU0sR0FBZ0MsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUNoRCxrQkFBYSxHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7UUFPakQsSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRLElBQUksQ0FBQyxLQUFLLENBQUMsU0FBUyxFQUFFO1lBQ3ZDLE1BQU0sSUFBSSxLQUFLLENBQUMsK0NBQStDLENBQUMsQ0FBQztTQUNsRTtRQUVELE1BQU0sV0FBVyxHQUFHLEdBQUcsbUJBQUssQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUMsT0FBTyxZQUFZLG1CQUFLLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxDQUFDLE1BQU0sZ0JBQWdCLENBQUM7UUFDakcsTUFBTSxRQUFRLEdBQWEsRUFBRSxDQUFDO1FBQzlCLE1BQU0sTUFBTSxHQUFHLElBQUksS0FBSyxFQUFrQixDQUFDO1FBRTNDLE1BQU0sb0JBQW9CLEdBQUcsQ0FBQyxHQUFXLEVBQUUsSUFBMEIsRUFBRSxFQUFFO1lBQ3ZFLE9BQU8sR0FBRyxLQUFLLENBQUMsb0JBQW9CLENBQUMsTUFBTSxDQUFDLFVBQVUsSUFBSSxHQUFHLElBQUksSUFBSSxDQUFDLFlBQVksSUFBSSxZQUFZLEVBQUUsQ0FBQztRQUN2RyxDQUFDLENBQUM7UUFFRixNQUFNLFFBQVEsR0FBRyxvQkFBb0IsQ0FBQyxLQUFLLENBQUMsb0JBQW9CLENBQUMsV0FBVyxFQUFFLEtBQUssQ0FBQyxvQkFBb0IsQ0FB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QkFDN0M7YUFDRjtTQUNGO0lBQ0gsQ0FBQztDQUNGO0FBdEJELDBDQXNCQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIElBc3BlY3QsIExhenksIFN0YWNrLCBUb2tlbixcbiAgYXdzX2VjciBhcyBlY3IsXG4gIGF3c19jb2RlYnVpbGQgYXMgY29kZWJ1aWxkLFxuICBhd3NfZXZlbnRzIGFzIGV2ZW50cyxcbiAgYXdzX2V2ZW50c190YXJnZXRzIGFzIHRhcmdldHMsXG4gIGF3c19pYW0gYXMgaWFtLFxuICBhd3NfczNfYXNzZXRzIGFzIHMzQXNzZXRzLFxuICBhd3Nfc2VjcmV0c21hbmFnZXIgYXMgc20sXG4gIGN1c3RvbV9yZXNvdXJjZXMgYXMgY3IsXG4gIEFubm90YXRpb25zLFxufSBmcm9tICdhd3MtY2RrLWxpYic7XG5pbXBvcnQgeyBDb25zdHJ1Y3QsIElDb25zdHJ1Y3QgfSBmcm9tICdjb25zdHJ1Y3RzJztcbmltcG9ydCB7IE1pcnJvclNvdXJjZSB9IGZyb20gJy4vbWlycm9yLXNvdXJjZSc7XG5pbXBvcnQgeyBERUZBVUxUX1NVUEVSQ0hBSU5fSU1BR0UgfSBmcm9tICcuLi9jb25zdGFudHMnO1xuXG4vKipcbiAqIEF1dGhlbnRpY2F0aW9uIGRldGFpbHMgZm9yIERvY2tlckh1Yi5cbiAqXG4gKiBAc2VlIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9jb2RlYnVpbGQvbGF0ZXN0L3VzZXJndWlkZS9idWlsZC1zcGVjLXJlZi5odG1sI2J1aWxkLXNwZWMuZW52LnNlY3JldHMtbWFuYWdlclxuICovXG5leHBvcnQgaW50ZXJmYWNlIERvY2tlckh1YkNyZWRlbnRpYWxzIHtcblxuICAvKipcbiAgICogVGhlIHNlY3JldCB0aGF0IGNvbnRhaW5zIHRoZSB1c2VybmFtZSBhbmQgcGFzc3dvcmQgZm9yIERvY2tlcmh1YlxuICAgKi9cbiAgcmVhZG9ubHkgc2VjcmV0OiBzbS5JU2VjcmV0O1xuXG4gIC8qKlxuICAgKiBUaGUgc2VjcmV0IGtleSB0aGF0IGNvbnRhaW5zIHRoZSB1c2VybmFtZSBpbiB0aGUgc3BlY2lmaWVkIHNlY3JldC5cbiAgICovXG4gIHJlYWRvbmx5IHVzZXJuYW1lS2V5OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBzZWNyZXQga2V5IHRoYXQgY29udGFpbnMgdGhlIHBhc3N3b3JkIGluIHRoZSBzcGVjaWZpZWQgc2VjcmV0LlxuICAgKi9cbiAgcmVhZG9ubHkgcGFzc3dvcmRLZXk6IHN0cmluZztcblxuICAvKipcbiAgICogVmVyc2lvbiBzdGFnZSBvZiB0aGUgc2VjcmV0LlxuICAgKlxuICAgKiBAZGVmYXVsdCAnQVdTQ1VSUkVOVCdcbiAgICovXG4gIHJlYWRvbmx5IHZlcnNpb25TdGFnZT86IHN0cmluZztcbn1cblxuLyoqXG4gKiBQcm9wZXJ0aWVzIHRvIGluaXRpYWxpemUgRWNyUmVnaXN0cnlTeW5jXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRWNyTWlycm9yUHJvcHMge1xuICAvKipcbiAgICogVGhlIGxpc3Qgb2YgaW1hZ2VzIHRvIGtlZXAgc3luYydlZC5cbiAgICovXG4gIHJlYWRvbmx5IHNvdXJjZXM6IE1pcnJvclNvdXJjZVtdO1xuXG4gIC8qKlxuICAgKiBDcmVkZW50aWFscyB0byBzaWduaW5nIGludG8gRG9ja2VyaHViLlxuICAgKi9cbiAgcmVhZG9ubHkgZG9ja2VySHViQ3JlZGVudGlhbHM6IERvY2tlckh1YkNyZWRlbnRpYWxzO1xuXG4gIC8qKlxuICAgKiBUaGUgaW1hZ2UgdXNlZCB0byBydW4gdGhlIG1pcnJvciBzdGVwIGl0c2VsZi5cbiAgICpcbiAgICogUHJlZmVyIHRvIHN1cHBseSB0aGUgaW1hZ2UgeW91cnNlbGYgaGVyZS5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBTb21lIHN1cGVyY2hhaW4gaW1hZ2UgdGhhdCBtYXkgZ3JvdyBvdXRkYXRlZC5cbiAgICovXG4gIHJlYWRvbmx5IGJ1aWxkSW1hZ2U/OiBjb2RlYnVpbGQuSUJ1aWxkSW1hZ2U7XG5cbiAgLyoqXG4gICAqIFN5bmMgam9iIHJ1bnMgb24gYSBzY2hlZHVsZS5cbiAgICogVGhyb3dzIGFuIGVycm9yIGlmIG5laXRoZXIgdGhpcyBub3IgYGF1dG9TdGFydGAgYXJlIHNwZWNpZmllZC5cbiAgICogQGRlZmF1bHQgLSBkb2VzIG5vdCBydW4gb24gc2NoZWR1bGVcbiAgICovXG4gIHJlYWRvbmx5IHNjaGVkdWxlPzogZXZlbnRzLlNjaGVkdWxlO1xuXG4gIC8qKlxuICAgKiBTdGFydCB0aGUgc3luYyBqb2IgaW1tZWRpYXRlbHkgYWZ0ZXIgdGhlIGRlcGxveW1lbnQuXG4gICAqIFRoaXMgaW5qZWN0cyBhIGN1c3RvbSByZXNvdXJjZSB0aGF0IGlzIGV4ZWN1dGVkIGFzIHBhcnQgb2YgdGhlIGRlcGxveW1lbnQuXG4gICAqIFRocm93cyBhbiBlcnJvciBpZiBuZWl0aGVyIHRoaXMgbm9yIGBzY2hlZHVsZWAgYXJlIHNwZWNpZmllZC5cbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IGF1dG9TdGFydD86IGJvb2xlYW47XG59XG5cbi8qKlxuICogU3luY2hyb25pemUgaW1hZ2VzIGZyb20gRG9ja2VySHViIHRvIGFuIEVDUiByZWdpc3RyeSBpbiB0aGUgQVdTIGFjY291bnQuXG4gKiBUaGlzIGlzIHBhcnRpY3VsYXJseSB1c2VmdWwgdG8gd29ya2Fyb3VuZCBEb2NrZXJIdWIncyB0aHJvdHRsaW5nIG9uIHB1bGxzIGFuZCB1c2UgRUNSIGluc3RlYWQuXG4gKi9cbmV4cG9ydCBjbGFzcyBFY3JNaXJyb3IgZXh0ZW5kcyBDb25zdHJ1Y3Qge1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgX3JlcG9zOiBNYXA8c3RyaW5nLCBlY3IuUmVwb3NpdG9yeT4gPSBuZXcgTWFwKCk7XG4gIHByaXZhdGUgcmVhZG9ubHkgX3JlcG9UYWdzU2VlbiA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuXG4gIHB1YmxpYyByZWFkb25seSBwcm9qZWN0OiBjb2RlYnVpbGQuUHJvamVjdDtcblxuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogRWNyTWlycm9yUHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuXG4gICAgaWYgKCFwcm9wcy5zY2hlZHVsZSAmJiAhcHJvcHMuYXV0b1N0YXJ0KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0VpdGhlciBzY2hlZHVsZSBvciBhdXRvU3RhcnQgbXVzdCBiZSBwcm92aWRlZCcpO1xuICAgIH1cblxuICAgIGNvbnN0IGVjclJlZ2lzdHJ5ID0gYCR7U3RhY2sub2Yoc2NvcGUpLmFjY291bnR9LmRrci5lY3IuJHtTdGFjay5vZihzY29wZSkucmVnaW9ufS5hbWF6b25hd3MuY29tYDtcbiAgICBjb25zdCBjb21tYW5kczogc3RyaW5nW10gPSBbXTtcbiAgICBjb25zdCBhc3NldHMgPSBuZXcgQXJyYXk8czNBc3NldHMuQXNzZXQ+KCk7XG5cbiAgICBjb25zdCBjb2RlQnVpbGRTZWNyZXRWYWx1ZSA9IChrZXk6IHN0cmluZywgYXV0aDogRG9ja2VySHViQ3JlZGVudGlhbHMpID0+IHtcbiAgICAgIHJldHVybiBgJHtwcm9wcy5kb2NrZXJIdWJDcmVkZW50aWFscy5zZWNyZXQuc2VjcmV0TmFtZX06JHtrZXl9OiR7YXV0aC52ZXJzaW9uU3RhZ2UgPz8gJ0FXU0NVUlJFTlQnfWA7XG4gICAgfTtcblxuICAgIGNvbnN0IHVzZXJuYW1lID0gY29kZUJ1aWxkU2VjcmV0VmFsdWUocHJvcHMuZG9ja2VySHViQ3JlZGVudGlhbHMudXNlcm5hbWVLZXksIHByb3BzLmRvY2tlckh1YkNyZWRlbnRpYWxzKTtcbiAgICBjb25zdCBwYXNzd29yZCA9IGNvZGVCdWlsZFNlY3JldFZhbHVlKHByb3BzLmRvY2tlckh1YkNyZWRlbnRpYWxzLnBhc3N3b3JkS2V5LCBwcm9wcy5kb2NrZXJIdWJDcmVkZW50aWFscyk7XG5cbiAgICBpZiAoIXByb3BzLmJ1aWxkSW1hZ2UpIHtcbiAgICAgIEFubm90YXRpb25zLm9mKHRoaXMpLmFkZFdhcm5pbmdWMignYXdzLWRlbGl2bGliOkVjck1pcnJvci5taXNzaW5nQnVpbGRJbWFnZScsICdQcmVmZXIgc3VwcGx5aW5nIGFuIGV4cGxpY2l0IGJ1aWxkIGltYWdlIHRvIHJlbHlpbmcgb24gdGhlIGRlZmF1bHQgc3VwZXJjaGFpbi4nKTtcbiAgICB9XG5cbiAgICB0aGlzLnByb2plY3QgPSBuZXcgY29kZWJ1aWxkLlByb2plY3QodGhpcywgJ0VjclB1c2hJbWFnZXMnLCB7XG4gICAgICBkZXNjcmlwdGlvbjogTGF6eS5zdHJpbmcoeyBwcm9kdWNlOiAoKSA9PiBgU3luY2hyb25pemUgJHtwcm9wcy5zb3VyY2VzLmxlbmd0aH0gaW1hZ2VzIGZyb20gRG9ja2VySHViIHRvIGxvY2FsIEVDUmAgfSksXG4gICAgICBlbnZpcm9ubWVudDoge1xuICAgICAgICBwcml2aWxlZ2VkOiB0cnVlLFxuICAgICAgICBidWlsZEltYWdlOiBwcm9wcy5idWlsZEltYWdlID8/IGNvZGVidWlsZC5MaW51eEJ1aWxkSW1hZ2UuZnJvbURvY2tlclJlZ2lzdHJ5KERFRkFVTFRfU1VQRVJDSEFJTl9JTUFHRSksXG4gICAgICB9LFxuICAgICAgZW52aXJvbm1lbnRWYXJpYWJsZXM6IHtcbiAgICAgICAgLy8gRG9ja2VySHViIGNyZWRlbnRpYWxzIHRvIGF2b2lkIHRocm90dGxpbmdcbiAgICAgICAgRE9DS0VSSFVCX1VTRVJOQU1FOiB7IHZhbHVlOiB1c2VybmFtZSwgdHlwZTogY29kZWJ1aWxkLkJ1aWxkRW52aXJvbm1lbnRWYXJpYWJsZVR5cGUuU0VDUkVUU19NQU5BR0VSIH0sXG4gICAgICAgIERPQ0tFUkhVQl9QQVNTV09SRDogeyB2YWx1ZTogcGFzc3dvcmQsIHR5cGU6IGNvZGVidWlsZC5CdWlsZEVudmlyb25tZW50VmFyaWFibGVUeXBlLlNFQ1JFVFNfTUFOQUdFUiB9LFxuICAgICAgfSxcbiAgICAgIGJ1aWxkU3BlYzogY29kZWJ1aWxkLkJ1aWxkU3BlYy5mcm9tT2JqZWN0KExhenkuYW55KHtcbiAgICAgICAgcHJvZHVjZTogKCkgPT4ge1xuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICB2ZXJzaW9uOiAnMC4yJyxcbiAgICAgICAgICAgIHBoYXNlczoge1xuICAgICAgICAgICAgICBidWlsZDoge1xuICAgICAgICAgICAgICAgIGNvbW1hbmRzOiBbXG5cbiAgICAgICAgICAgICAgICAgIC8vIHN0YXJ0IHRoZSBkb2NrZXIgZGFlbW9uXG4gICAgICAgICAgICAgICAgICAnbm9odXAgL3Vzci9iaW4vZG9ja2VyZCAtLWhvc3Q9dW5peDovLy92YXIvcnVuL2RvY2tlci5zb2NrIC0taG9zdD10Y3A6Ly8xMjcuMC4wLjE6MjM3NSAtLXN0b3JhZ2UtZHJpdmVyPW92ZXJsYXkyJicsXG4gICAgICAgICAgICAgICAgICAndGltZW91dCAxNSBzaCAtYyBcInVudGlsIGRvY2tlciBpbmZvOyBkbyBlY2hvIC47IHNsZWVwIDE7IGRvbmVcIicsXG5cbiAgICAgICAgICAgICAgICAgIC8vIGxvZ2luIHRvIGRvY2tlcmh1YiBzbyB3ZSB3b24ndCBnZXQgdGhyb3R0bGVkXG4gICAgICAgICAgICAgICAgICAnZG9ja2VyIGxvZ2luIC11ICR7RE9DS0VSSFVCX1VTRVJOQU1FfSAtcCAke0RPQ0tFUkhVQl9QQVNTV09SRH0nLFxuXG4gICAgICAgICAgICAgICAgICAvLyBsb2dpbiB0byBlY3Igc28gd2UgY2FuIHB1c2ggdG8gaXRcbiAgICAgICAgICAgICAgICAgIGBhd3MgZWNyIGdldC1sb2dpbi1wYXNzd29yZCB8IGRvY2tlciBsb2dpbiAtLXVzZXJuYW1lIEFXUyAtLXBhc3N3b3JkLXN0ZGluICR7ZWNyUmVnaXN0cnl9YCxcblxuICAgICAgICAgICAgICAgICAgLy8gbG9naW4gdG8gZWNyLXB1YmxpYyBzbyB3ZSBjYW4gcHVsbCBmcm9tIGl0IHdpdGggaW1wcm92ZWQgcmF0ZSBsaW1pdHNcbiAgICAgICAgICAgICAgICAgICdhd3MgZWNyLXB1YmxpYyBnZXQtbG9naW4tcGFzc3dvcmQgLS1yZWdpb24gdXMtZWFzdC0xIHwgZG9ja2VyIGxvZ2luIC0tdXNlcm5hbWUgQVdTIC0tcGFzc3dvcmQtc3RkaW4gcHVibGljLmVjci5hd3MnLFxuXG4gICAgICAgICAgICAgICAgICAuLi5jb21tYW5kcyxcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9O1xuICAgICAgICB9LFxuICAgICAgfSkpLFxuICAgICAgc3NtU2Vzc2lvblBlcm1pc3Npb25zOiB0cnVlLFxuICAgIH0pO1xuXG4gICAgLy8gRW5zdXJlIHRoZSBydW5uZXIgaGFzIFBVTEwgYWNjZXNzIHRvIEVDUi1QdWJsaWMuXG4gICAgdGhpcy5wcm9qZWN0LnJvbGUhLmFkZE1hbmFnZWRQb2xpY3koaWFtLk1hbmFnZWRQb2xpY3kuZnJvbUF3c01hbmFnZWRQb2xpY3lOYW1lKCdBbWF6b25FbGFzdGljQ29udGFpbmVyUmVnaXN0cnlQdWJsaWNSZWFkT25seScpKTtcblxuICAgIC8vIEdpdmUgdGhlIHByb2plY3QgYWNjZXNzIHRvIHRoZSBEb2NrZXIgSHViIGNyZWRlbnRpYWxzXG4gICAgLy8gUmVxdWlyZWQgZm9yIGFjY2VzcyB0byBwcml2YXRlIGltYWdlcyBhbmQgdG8gYXZvaWQgdGhyb3R0bGluZyBvZiB1bmF1dGhvcml6ZWQgcmVxdWVzdHNcbiAgICBwcm9wcy5kb2NrZXJIdWJDcmVkZW50aWFscy5zZWNyZXQuZ3JhbnRSZWFkKHRoaXMucHJvamVjdCk7XG5cbiAgICBmb3IgKGNvbnN0IGltYWdlIG9mIHByb3BzLnNvdXJjZXMpIHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGltYWdlLmJpbmQoe1xuICAgICAgICBzY29wZTogdGhpcyxcbiAgICAgICAgZWNyUmVnaXN0cnksXG4gICAgICAgIHN5bmNKb2I6IHRoaXMucHJvamVjdCxcbiAgICAgIH0pO1xuICAgICAgY29tbWFuZHMucHVzaCguLi5yZXN1bHQuY29tbWFuZHMpO1xuXG4gICAgICBjb25zdCByZXBvVGFnID0gYCR7cmVzdWx0LnJlcG9zaXRvcnlOYW1lfToke3Jlc3VsdC50YWd9YDtcbiAgICAgIGlmICh0aGlzLl9yZXBvVGFnc1NlZW4uaGFzKHJlcG9UYWcpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgTWlycm9yIHNvdXJjZSB3aXRoIHJlcG9zaXRvcnkgbmFtZSBbJHtyZXN1bHQucmVwb3NpdG9yeU5hbWV9XSBhbmQgdGFnIFske3Jlc3VsdC50YWd9XSBhbHJlYWR5IGV4aXN0cy5gKTtcbiAgICAgIH1cbiAgICAgIHRoaXMuX3JlcG9UYWdzU2Vlbi5hZGQocmVwb1RhZyk7XG5cbiAgICAgIHRoaXMuY3JlYXRlTWlycm9yUmVwbyhyZXN1bHQucmVwb3NpdG9yeU5hbWUpO1xuXG4gICAgICBjb25zdCBlY3JJbWFnZVVyaSA9IGAke2VjclJlZ2lzdHJ5fS8ke3Jlc3VsdC5yZXBvc2l0b3J5TmFtZX06JHtyZXN1bHQudGFnfWA7XG4gICAgICBjb21tYW5kcy5wdXNoKGBkb2NrZXIgcHVzaCAke2VjckltYWdlVXJpfWApO1xuXG4gICAgICAvLyBjbGVhbiBhZnRlciBlYWNoIHB1c2ggc28gdGhhdCB3ZSBkb24ndCBmaWxsdXAgZGlzayBzcGFjZVxuICAgICAgLy8gcG9zc2libHkgZmFpbGluZyB0aGUgbmV4dCBwdWxsLlxuICAgICAgY29tbWFuZHMucHVzaCgnZG9ja2VyIGltYWdlIHBydW5lIC0tYWxsIC0tZm9yY2UnKTtcbiAgICB9XG5cbiAgICAvLyBDb2RlQnVpbGQgbmVlZHMgdG8gcmVhZCB0aGUgc2VjcmV0IHRvIHJlc29sdmUgZW52aXJvbm1lbnQgdmFyaWFibGVzXG4gICAgcHJvcHMuZG9ja2VySHViQ3JlZGVudGlhbHMuc2VjcmV0LmdyYW50UmVhZCh0aGlzLnByb2plY3QpO1xuXG4gICAgZWNyLkF1dGhvcml6YXRpb25Ub2tlbi5ncmFudFJlYWQodGhpcy5wcm9qZWN0KTtcbiAgICB0aGlzLl9yZXBvcy5mb3JFYWNoKChyLCBfKSA9PiByLmdyYW50UHVsbFB1c2godGhpcy5wcm9qZWN0KSk7XG5cbiAgICAvLyB0aGlzIHByb2plY3QgbmVlZHMgdG8gZG93bmxvYWQgdGhlIGFzc2V0cyBzbyBpdCBjYW4gYnVpbGQgdGhlbVxuICAgIGFzc2V0cy5mb3JFYWNoKGEgPT4gYS5ncmFudFJlYWQodGhpcy5wcm9qZWN0KSk7XG5cbiAgICBpZiAocHJvcHMuYXV0b1N0YXJ0KSB7XG4gICAgICBuZXcgY3IuQXdzQ3VzdG9tUmVzb3VyY2UodGhpcywgJ0J1aWxkRXhlY3V0aW9uJywge1xuICAgICAgICBpbnN0YWxsTGF0ZXN0QXdzU2RrOiBmYWxzZSxcbiAgICAgICAgcG9saWN5OiBjci5Bd3NDdXN0b21SZXNvdXJjZVBvbGljeS5mcm9tU2RrQ2FsbHMoeyByZXNvdXJjZXM6IFt0aGlzLnByb2plY3QucHJvamVjdEFybl0gfSksXG4gICAgICAgIG9uVXBkYXRlOiB7XG4gICAgICAgICAgYWN0aW9uOiAnc3RhcnRCdWlsZCcsXG4gICAgICAgICAgc2VydmljZTogJ0NvZGVCdWlsZCcsXG4gICAgICAgICAgcGFyYW1ldGVyczoge1xuICAgICAgICAgICAgcHJvamVjdE5hbWU6IHRoaXMucHJvamVjdC5wcm9qZWN0TmFtZSxcbiAgICAgICAgICAgIC8vIHRvIHRpZ2dlciB0aGUgYnVpbGQgb24gZXZlcnkgdXBkYXRlXG4gICAgICAgICAgICBpZGVtcG90ZW5jeVRva2VuOiBgJHtEYXRlLm5vdygpfWAsXG4gICAgICAgICAgfSxcbiAgICAgICAgICBwaHlzaWNhbFJlc291cmNlSWQ6IGNyLlBoeXNpY2FsUmVzb3VyY2VJZC5vZignRWNyUmVnaXN0cnlFeGVjdXRpb24nKSxcblxuICAgICAgICAgIC8vIG5lZWQgc2luY2UgdGhlIGRlZmF1bHQgcmVwb25zZSBpZiBncmVhdGVyIHRoYW4gdGhlIDRrIGxpbWl0IGZvciBjdXN0b20gcmVzb3VyY2VzLlxuICAgICAgICAgIG91dHB1dFBhdGhzOiBbJ2J1aWxkLmlkJ10sXG4gICAgICAgIH0sXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBpZiAocHJvcHMuc2NoZWR1bGUpIHtcbiAgICAgIG5ldyBldmVudHMuUnVsZSh0aGlzLCAnU2NoZWR1bGVkVHJpZ2dlcicsIHtcbiAgICAgICAgZGVzY3JpcHRpb246ICdUcmlnZ2VyIEVDUiBtaXJyb3Igam9iJyxcbiAgICAgICAgc2NoZWR1bGU6IHByb3BzLnNjaGVkdWxlLFxuICAgICAgICB0YXJnZXRzOiBbbmV3IHRhcmdldHMuQ29kZUJ1aWxkUHJvamVjdCh0aGlzLnByb2plY3QpXSxcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgY3JlYXRlTWlycm9yUmVwbyhlY3JSZXBvc2l0b3J5TmFtZTogc3RyaW5nKSB7XG4gICAgaWYgKHRoaXMuX3JlcG9zLmdldChlY3JSZXBvc2l0b3J5TmFtZSkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCByZXBvc2l0b3J5ID0gbmV3IGVjci5SZXBvc2l0b3J5KHRoaXMsIGBSZXBvJHtlY3JSZXBvc2l0b3J5TmFtZX1gLCB7XG4gICAgICByZXBvc2l0b3J5TmFtZTogZWNyUmVwb3NpdG9yeU5hbWUsXG4gICAgfSk7XG4gICAgdGhpcy5fcmVwb3Muc2V0KGVjclJlcG9zaXRvcnlOYW1lLCByZXBvc2l0b3J5KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIHRhcmdldCBFQ1IgcmVwb3NpdG9yeSBmb3IgdGhlIGdpdmVuIHJlcG9zaXRvcnkgbmFtZSBhbmQgdGFnLlxuICAgKiBAcGFyYW0gcmVwb3NpdG9yeU5hbWUgVGhlIEVDUiByZXBvc2l0b3J5IHdpdGggdGhpcyBuYW1lXG4gICAqIEBwYXJhbSB0YWcgdGhlIHRhZyBmb3IgdGhlIHJlcG9zaXRvcnksIGRlZmF1bHRzIHRvICdsYXRlc3QnXG4gICAqL1xuICBwdWJsaWMgZWNyUmVwb3NpdG9yeShyZXBvc2l0b3J5TmFtZTogc3RyaW5nKTogZWNyLklSZXBvc2l0b3J5IHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5fcmVwb3MuZ2V0KHJlcG9zaXRvcnlOYW1lKTtcbiAgfVxufTtcblxuLyoqXG4gKiBBbiBhc3BlY3QgdGhhdCB3YWxrcyB0aHJvdWdoIHRoZSBjb25zdHJ1Y3QgdHJlZSBhbmQgcmVwbGFjZXMgQ29kZUJ1aWxkIGpvYnMgd2l0aCBEb2NrZXIgaW1hZ2VzXG4gKiB3aXRoIEVDUiBlcXVpdmFsZW50cyBmb3VuZCBpbiB0aGUgRWNyTWlycm9yLlxuICovXG5leHBvcnQgY2xhc3MgRWNyTWlycm9yQXNwZWN0IGltcGxlbWVudHMgSUFzcGVjdCB7XG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgcmVhZG9ubHkgbWlycm9yOiBFY3JNaXJyb3IpIHt9XG5cbiAgcHVibGljIHZpc2l0KGNvbnN0cnVjdDogSUNvbnN0cnVjdCkge1xuICAgIGlmIChjb25zdHJ1Y3QgaW5zdGFuY2VvZiBjb2RlYnVpbGQuUHJvamVjdCkge1xuICAgICAgY29uc3QgY2ZucHJvamVjdCA9IGNvbnN0cnVjdC5ub2RlLmRlZmF1bHRDaGlsZCBhcyBjb2RlYnVpbGQuQ2ZuUHJvamVjdDtcbiAgICAgIGlmICghVG9rZW4uaXNVbnJlc29sdmVkKGNmbnByb2plY3QuZW52aXJvbm1lbnQpKSB7XG4gICAgICAgIGNvbnN0IGVudiA9IGNmbnByb2plY3QuZW52aXJvbm1lbnQgYXMgY29kZWJ1aWxkLkNmblByb2plY3QuRW52aXJvbm1lbnRQcm9wZXJ0eTtcbiAgICAgICAgY29uc3QgaW1hZ2VOYW1lID0gZW52LmltYWdlLnNwbGl0KCc6JylbMF07XG4gICAgICAgIGNvbnN0IHRhZyA9IGVudi5pbWFnZS5zcGxpdCgnOicpWzFdO1xuICAgICAgICBjb25zdCByZXBsYWNlbWVudCA9IHRoaXMubWlycm9yLmVjclJlcG9zaXRvcnkoaW1hZ2VOYW1lKTtcbiAgICAgICAgaWYgKHJlcGxhY2VtZW50KSB7XG4gICAgICAgICAgY2ZucHJvamVjdC5lbnZpcm9ubWVudCA9IHtcbiAgICAgICAgICAgIC4uLmVudixcbiAgICAgICAgICAgIGltYWdlOiBjb2RlYnVpbGQuTGludXhCdWlsZEltYWdlLmZyb21FY3JSZXBvc2l0b3J5KHJlcGxhY2VtZW50LCB0YWcpLmltYWdlSWQsXG4gICAgICAgICAgfTtcbiAgICAgICAgICByZXBsYWNlbWVudC5ncmFudFB1bGwoY29uc3RydWN0KTtcbiAgICAgICAgICBlY3IuQXV0aG9yaXphdGlvblRva2VuLmdyYW50UmVhZChjb25zdHJ1Y3QpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG59XG4iXX0=