deploy-time-build
Version:
Build during CDK deployment.
209 lines • 32.9 kB
JavaScript
"use strict";
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ContainerImageBuild = void 0;
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
const fs_1 = require("fs");
const path_1 = require("path");
const aws_cdk_lib_1 = require("aws-cdk-lib");
const aws_codebuild_1 = require("aws-cdk-lib/aws-codebuild");
const aws_ecr_1 = require("aws-cdk-lib/aws-ecr");
const aws_ecs_1 = require("aws-cdk-lib/aws-ecs");
const aws_iam_1 = require("aws-cdk-lib/aws-iam");
const aws_lambda_1 = require("aws-cdk-lib/aws-lambda");
const aws_s3_assets_1 = require("aws-cdk-lib/aws-s3-assets");
const constructs_1 = require("constructs");
const singleton_project_1 = require("./singleton-project");
/**
* Build a container image and push it to an ECR repository on deploy-time.
*/
class ContainerImageBuild extends constructs_1.Construct {
constructor(scope, id, props) {
super(scope, id);
this.props = props;
const handler = new aws_lambda_1.SingletonFunction(this, 'CustomResourceHandler', {
// Use raw string to avoid from tightening CDK version requirement
runtime: new aws_lambda_1.Runtime('nodejs20.x', aws_lambda_1.RuntimeFamily.NODEJS),
code: aws_lambda_1.Code.fromAsset((0, path_1.join)(__dirname, '../lambda/trigger-codebuild/dist')),
handler: 'index.handler',
uuid: 'db740fd5-5436-4a84-8a09-e6dfcd01f4f3', // generated for this construct
lambdaPurpose: 'DeployTimeBuildCustomResourceHandler',
timeout: aws_cdk_lib_1.Duration.minutes(5),
});
// Use buildx for cross-platform image build
const armImage = aws_codebuild_1.LinuxArmBuildImage.fromCodeBuildImageId('aws/codebuild/amazonlinux2-aarch64-standard:3.0');
const x64Image = aws_codebuild_1.LinuxBuildImage.fromCodeBuildImageId('aws/codebuild/standard:7.0');
// Select the build image based on the target platform
const isArm64 = props.platform?.platform === 'linux/arm64';
const buildImage = isArm64 ? armImage : x64Image;
let repository = props.repository;
if (repository === undefined) {
repository = new aws_ecr_1.Repository(this, 'Repository', { removalPolicy: aws_cdk_lib_1.RemovalPolicy.DESTROY });
repository.node.defaultChild.addPropertyOverride('EmptyOnDelete', true);
}
const repositoryUri = repository.repositoryUri;
const imageArtifactName = 'artifact';
const project = new singleton_project_1.SingletonProject(this, 'Project', {
uuid: 'e83729fe-b156-4e70-9bec-452b15847a30',
projectPurpose: isArm64 ? 'ContainerImageBuildArm64' : 'ContainerImageBuildAmd64',
environment: {
computeType: aws_codebuild_1.ComputeType.SMALL,
buildImage: buildImage,
privileged: true,
},
vpc: props.vpc,
buildSpec: aws_codebuild_1.BuildSpec.fromObject({
version: '0.2',
phases: {
build: {
commands: [
'current_dir=$(pwd)',
'echo "$input"',
'mkdir workdir',
'cd workdir',
'aws s3 cp "$sourceS3Url" temp.zip',
'unzip temp.zip',
'ls -la',
'aws ecr get-login-password | docker login --username AWS --password-stdin $repositoryAuthUri',
// for accessing ECR public
'aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws',
'docker buildx ls',
'eval "$buildCommand"',
`docker tag ${imageArtifactName}:latest ${repositoryUri}:$imageTag`,
`docker push ${repositoryUri}:$imageTag`,
],
},
post_build: {
commands: [
'echo Build completed on `date`',
`
STATUS='SUCCESS'
if [ $CODEBUILD_BUILD_SUCCEEDING -ne 1 ] # Test if the build is failing
then
STATUS='FAILED'
REASON="ContainerImageBuild failed. See CloudWatch Log stream for the detailed reason:
https://$AWS_REGION.console.aws.amazon.com/cloudwatch/home?region=$AWS_REGION#logsV2:log-groups/log-group/\\$252Faws\\$252Fcodebuild\\$252F$projectName/log-events/$CODEBUILD_LOG_PATH"
fi
cat <<EOF > payload.json
{
"StackId": "$stackId",
"RequestId": "$requestId",
"LogicalResourceId":"$logicalResourceId",
"PhysicalResourceId": "$imageTag",
"Status": "$STATUS",
"Reason": "$REASON",
"Data": {
"ImageTag": "$imageTag"
}
}
EOF
curl -v -i -X PUT -H 'Content-Type:' -d "@payload.json" "$responseURL"
`,
],
},
},
}),
}).project;
project.role.addManagedPolicy(aws_iam_1.ManagedPolicy.fromAwsManagedPolicyName('AmazonElasticContainerRegistryPublicReadOnly'));
repository.grantPullPush(project);
repository.grant(project, 'ecr:DescribeImages');
handler.addToRolePolicy(new aws_iam_1.PolicyStatement({
actions: ['codebuild:StartBuild'],
resources: [project.projectArn],
}));
this.grantPrincipal = project.grantPrincipal;
let assetExclude = props.exclude;
// automatically read .dockerignore for convenience
if (assetExclude === undefined && (0, fs_1.existsSync)((0, path_1.join)(props.directory, '.dockerignore'))) {
assetExclude = (0, fs_1.readFileSync)((0, path_1.join)(props.directory, '.dockerignore')).toString().split('\n');
}
const asset = new aws_s3_assets_1.Asset(this, 'Source', {
...props,
exclude: assetExclude,
path: props.directory,
});
asset.grantRead(project);
const buildCommandOptions = { ...props, platform: props.platform?.platform };
buildCommandOptions.outputs ?? (buildCommandOptions.outputs = []);
// we don't use push=true here because CodeBuild Docker server does not seem to work properly with the configuration.
buildCommandOptions.outputs.push('type=image', `name=${imageArtifactName}`);
if (props.zstdCompression) {
// to enable zstd compression, buildx directly pushes the artifact image to a registry
// https://aws.amazon.com/blogs/containers/reducing-aws-fargate-startup-times-with-zstd-compressed-container-images/
buildCommandOptions.outputs.push('oci-mediatypes=true', 'compression=zstd', 'force-compression=true', 'compression-level=3');
}
const buildCommand = this.getDockerBuildCommand(buildCommandOptions);
const properties = {
type: 'ContainerImageBuild',
buildCommand: buildCommand,
repositoryUri,
imageTag: props.tag,
tagPrefix: props.tagPrefix,
codeBuildProjectName: project.projectName,
sourceS3Url: asset.s3ObjectUrl,
};
const custom = new aws_cdk_lib_1.CustomResource(this, 'Resource', {
serviceToken: handler.functionArn,
resourceType: 'Custom::CDKContainerImageBuild',
properties,
});
custom.node.addDependency(project);
this.repository = repository;
this.imageTag = custom.getAttString('ImageTag');
}
/**
* Get the instance of {@link DockerImageCode} for a Lambda function image.
*/
toLambdaDockerImageCode() {
if (this.props.zstdCompression) {
throw new Error('You cannot enable zstdCompression for a Lambda image.');
}
return aws_lambda_1.DockerImageCode.fromEcr(this.repository, { tagOrDigest: this.imageTag });
}
/**
* Get the instance of {@link ContainerImage} for an ECS task definition.
*/
toEcsDockerImageCode() {
return aws_ecs_1.ContainerImage.fromEcrRepository(this.repository, this.imageTag);
}
getDockerBuildCommand(options) {
// the members of props differs with CDK version.
// By regarding props as any, we can use props that are not available in older cdk versions.
// logic is copied from packages/cdk-assets/lib/private/docker.ts
const cacheOptionToFlag = (option) => {
let flag = `type=${option.type}`;
if (option.params) {
flag +=
',' +
Object.entries(option.params)
.map(([k, v]) => `${k}=${v}`)
.join(',');
}
return flag;
};
const flatten = (x) => {
return Array.prototype.concat([], ...x);
};
const dockerBuildCommand = [
'docker buildx build',
...flatten(Object.entries(options.buildArgs || {}).map(([k, v]) => ['--build-arg', `${k}=${v}`])),
...flatten(Object.entries(options.buildSecrets || {}).map(([k, v]) => ['--secret', `id=${k},${v}`])),
...(options.buildSsh ? ['--ssh', options.buildSsh] : []),
...(options.target ? ['--target', options.target] : []),
...(options.file ? ['--file', options.file] : []),
...(options.networkMode ? ['--network', options.networkMode] : []),
...(options.platform ? ['--platform', options.platform] : []),
...(options.outputs ? ['--output', options.outputs.join(',')] : []),
...(options.cacheFrom ? [...options.cacheFrom.map((cacheFrom) => ['--cache-from', cacheOptionToFlag(cacheFrom)]).flat()] : []),
...(options.cacheTo ? ['--cache-to', cacheOptionToFlag(options.cacheTo)] : []),
...(options.cacheDisabled ? ['--no-cache'] : []),
'--provenance=false',
'.',
];
return dockerBuildCommand.join(' ');
}
}
exports.ContainerImageBuild = ContainerImageBuild;
_a = JSII_RTTI_SYMBOL_1;
ContainerImageBuild[_a] = { fqn: "deploy-time-build.ContainerImageBuild", version: "0.3.37" };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udGFpbmVyLWltYWdlLWJ1aWxkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2NvbnRhaW5lci1pbWFnZS1idWlsZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLDJCQUE4QztBQUM5QywrQkFBNEI7QUFDNUIsNkNBQW1GO0FBQ25GLDZEQUF3RztBQUV4RyxpREFBOEQ7QUFFOUQsaURBQXFEO0FBQ3JELGlEQUE2RjtBQUM3Rix1REFBMEc7QUFDMUcsNkRBQWtEO0FBQ2xELDJDQUF1QztBQUN2QywyREFBdUQ7QUFzQ3ZEOztHQUVHO0FBQ0gsTUFBYSxtQkFBb0IsU0FBUSxzQkFBUztJQUtoRCxZQUFZLEtBQWdCLEVBQUUsRUFBVSxFQUFtQixLQUErQjtRQUN4RixLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBRHdDLFVBQUssR0FBTCxLQUFLLENBQTBCO1FBR3hGLE1BQU0sT0FBTyxHQUFHLElBQUksOEJBQWlCLENBQUMsSUFBSSxFQUFFLHVCQUF1QixFQUFFO1lBQ25FLGtFQUFrRTtZQUNsRSxPQUFPLEVBQUUsSUFBSSxvQkFBTyxDQUFDLFlBQVksRUFBRSwwQkFBYSxDQUFDLE1BQU0sQ0FBQztZQUN4RCxJQUFJLEVBQUUsaUJBQUksQ0FBQyxTQUFTLENBQUMsSUFBQSxXQUFJLEVBQUMsU0FBUyxFQUFFLGtDQUFrQyxDQUFDLENBQUM7WUFDekUsT0FBTyxFQUFFLGVBQWU7WUFDeEIsSUFBSSxFQUFFLHNDQUFzQyxFQUFFLCtCQUErQjtZQUM3RSxhQUFhLEVBQUUsc0NBQXNDO1lBQ3JELE9BQU8sRUFBRSxzQkFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUM7U0FDN0IsQ0FBQyxDQUFDO1FBRUgsNENBQTRDO1FBQzVDLE1BQU0sUUFBUSxHQUFHLGtDQUFrQixDQUFDLG9CQUFvQixDQUFDLGlEQUFpRCxDQUFDLENBQUM7UUFDNUcsTUFBTSxRQUFRLEdBQUcsK0JBQWUsQ0FBQyxvQkFBb0IsQ0FB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LENBQUMsRUFBRSxDQUFDO1lBQ2hELG9CQUFvQjtZQUNwQixHQUFHO1NBQ0osQ0FBQztRQUNGLE9BQU8sa0JBQWtCLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ3RDLENBQUM7O0FBOU1ILGtEQStNQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGV4aXN0c1N5bmMsIHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcbmltcG9ydCB7IENmblJlc291cmNlLCBDdXN0b21SZXNvdXJjZSwgRHVyYXRpb24sIFJlbW92YWxQb2xpY3kgfSBmcm9tICdhd3MtY2RrLWxpYic7XG5pbXBvcnQgeyBCdWlsZFNwZWMsIENvbXB1dGVUeXBlLCBMaW51eEFybUJ1aWxkSW1hZ2UsIExpbnV4QnVpbGRJbWFnZSB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1jb2RlYnVpbGQnO1xuaW1wb3J0IHsgSVZwYyB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1lYzInO1xuaW1wb3J0IHsgSVJlcG9zaXRvcnksIFJlcG9zaXRvcnkgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtZWNyJztcbmltcG9ydCB7IERvY2tlckltYWdlQXNzZXRQcm9wcyB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1lY3ItYXNzZXRzJztcbmltcG9ydCB7IENvbnRhaW5lckltYWdlIH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWVjcyc7XG5pbXBvcnQgeyBJR3JhbnRhYmxlLCBJUHJpbmNpcGFsLCBNYW5hZ2VkUG9saWN5LCBQb2xpY3lTdGF0ZW1lbnQgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtaWFtJztcbmltcG9ydCB7IENvZGUsIERvY2tlckltYWdlQ29kZSwgUnVudGltZSwgUnVudGltZUZhbWlseSwgU2luZ2xldG9uRnVuY3Rpb24gfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtbGFtYmRhJztcbmltcG9ydCB7IEFzc2V0IH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLXMzLWFzc2V0cyc7XG5pbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tICdjb25zdHJ1Y3RzJztcbmltcG9ydCB7IFNpbmdsZXRvblByb2plY3QgfSBmcm9tICcuL3NpbmdsZXRvbi1wcm9qZWN0JztcbmltcG9ydCB7IENvbnRhaW5lckltYWdlQnVpbGRSZXNvdXJjZVByb3BzIH0gZnJvbSAnLi90eXBlcyc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ29udGFpbmVySW1hZ2VCdWlsZFByb3BzIGV4dGVuZHMgRG9ja2VySW1hZ2VBc3NldFByb3BzIHtcbiAgLyoqXG4gICAqIFRoZSB0YWcgd2hlbiB0byBwdXNoIHRoZSBpbWFnZVxuICAgKiBAZGVmYXVsdCB1c2UgYXNzZXRIYXNoIGFzIHRhZ1xuICAgKi9cbiAgcmVhZG9ubHkgdGFnPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBQcmVmaXggdG8gYWRkIHRvIHRoZSBpbWFnZSB0YWdcbiAgICogQGRlZmF1bHQgbm8gcHJlZml4XG4gICAqL1xuICByZWFkb25seSB0YWdQcmVmaXg/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBFQ1IgcmVwb3NpdG9yeSB0byBwdXNoIHRoZSBpbWFnZS5cbiAgICogQGRlZmF1bHQgY3JlYXRlIGEgbmV3IEVDUiByZXBvc2l0b3J5XG4gICAqL1xuICByZWFkb25seSByZXBvc2l0b3J5PzogSVJlcG9zaXRvcnk7XG5cbiAgLyoqXG4gICAqIFVzZSB6c3RkIGZvciBjb21wcmVzc2luZyBhIGNvbnRhaW5lciBpbWFnZS5cbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IHpzdGRDb21wcmVzc2lvbj86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFRoZSBWUEMgd2hlcmUgeW91ciBidWlsZCBqb2Igd2lsbCBiZSBkZXBsb3llZC5cbiAgICogVGhpcyBWUEMgbXVzdCBoYXZlIHByaXZhdGUgc3VibmV0cyB3aXRoIE5BVCBHYXRld2F5cy5cbiAgICpcbiAgICogVXNlIHRoaXMgcHJvcGVydHkgd2hlbiB5b3Ugd2FudCB0byBjb250cm9sIHRoZSBvdXRib3VuZCBJUCBhZGRyZXNzZXMgdGhhdCBiYXNlIGltYWdlcyBhcmUgcHVsbGVkIGZyb20uXG4gICAqIEBkZWZhdWx0IE5vIFZQQyB1c2VkLlxuICAgKi9cbiAgcmVhZG9ubHkgdnBjPzogSVZwYztcbn1cblxuLyoqXG4gKiBCdWlsZCBhIGNvbnRhaW5lciBpbWFnZSBhbmQgcHVzaCBpdCB0byBhbiBFQ1IgcmVwb3NpdG9yeSBvbiBkZXBsb3ktdGltZS5cbiAqL1xuZXhwb3J0IGNsYXNzIENvbnRhaW5lckltYWdlQnVpbGQgZXh0ZW5kcyBDb25zdHJ1Y3QgaW1wbGVtZW50cyBJR3JhbnRhYmxlIHtcbiAgcHVibGljIHJlYWRvbmx5IGdyYW50UHJpbmNpcGFsOiBJUHJpbmNpcGFsO1xuICBwdWJsaWMgcmVhZG9ubHkgcmVwb3NpdG9yeTogSVJlcG9zaXRvcnk7XG4gIHB1YmxpYyByZWFkb25seSBpbWFnZVRhZzogc3RyaW5nO1xuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByaXZhdGUgcmVhZG9ubHkgcHJvcHM6IENvbnRhaW5lckltYWdlQnVpbGRQcm9wcykge1xuICAgIHN1cGVyKHNjb3BlLCBpZCk7XG5cbiAgICBjb25zdCBoYW5kbGVyID0gbmV3IFNpbmdsZXRvbkZ1bmN0aW9uKHRoaXMsICdDdXN0b21SZXNvdXJjZUhhbmRsZXInLCB7XG4gICAgICAvLyBVc2UgcmF3IHN0cmluZyB0byBhdm9pZCBmcm9tIHRpZ2h0ZW5pbmcgQ0RLIHZlcnNpb24gcmVxdWlyZW1lbnRcbiAgICAgIHJ1bnRpbWU6IG5ldyBSdW50aW1lKCdub2RlanMyMC54JywgUnVudGltZUZhbWlseS5OT0RFSlMpLFxuICAgICAgY29kZTogQ29kZS5mcm9tQXNzZXQoam9pbihfX2Rpcm5hbWUsICcuLi9sYW1iZGEvdHJpZ2dlci1jb2RlYnVpbGQvZGlzdCcpKSxcbiAgICAgIGhhbmRsZXI6ICdpbmRleC5oYW5kbGVyJyxcbiAgICAgIHV1aWQ6ICdkYjc0MGZkNS01NDM2LTRhODQtOGEwOS1lNmRmY2QwMWY0ZjMnLCAvLyBnZW5lcmF0ZWQgZm9yIHRoaXMgY29uc3RydWN0XG4gICAgICBsYW1iZGFQdXJwb3NlOiAnRGVwbG95VGltZUJ1aWxkQ3VzdG9tUmVzb3VyY2VIYW5kbGVyJyxcbiAgICAgIHRpbWVvdXQ6IER1cmF0aW9uLm1pbnV0ZXMoNSksXG4gICAgfSk7XG5cbiAgICAvLyBVc2UgYnVpbGR4IGZvciBjcm9zcy1wbGF0Zm9ybSBpbWFnZSBidWlsZFxuICAgIGNvbnN0IGFybUltYWdlID0gTGludXhBcm1CdWlsZEltYWdlLmZyb21Db2RlQnVpbGRJbWFnZUlkKCdhd3MvY29kZWJ1aWxkL2FtYXpvbmxpbnV4Mi1hYXJjaDY0LXN0YW5kYXJkOjMuMCcpO1xuICAgIGNvbnN0IHg2NEltYWdlID0gTGludXhCdWlsZEltYWdlLmZyb21Db2RlQnVpbGRJbWFnZUlkKCdhd3MvY29kZWJ1aWxkL3N0YW5kYXJkOjcuMCcpO1xuICAgIC8vIFNlbGVjdCB0aGUgYnVpbGQgaW1hZ2UgYmFzZWQgb24gdGhlIHRhcmdldCBwbGF0Zm9ybVxuICAgIGNvbnN0IGlzQXJtNjQgPSBwcm9wcy5wbGF0Zm9ybT8ucGxhdGZvcm0gPT09ICdsaW51eC9hcm02NCc7XG4gICAgY29uc3QgYnVpbGRJbWFnZSA9IGlzQXJtNjQgPyBhcm1JbWFnZSA6IHg2NEltYWdlO1xuXG4gICAgbGV0IHJlcG9zaXRvcnkgPSBwcm9wcy5yZXBvc2l0b3J5O1xuICAgIGlmIChyZXBvc2l0b3J5ID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHJlcG9zaXRvcnkgPSBuZXcgUmVwb3NpdG9yeSh0aGlzLCAnUmVwb3NpdG9yeScsIHsgcmVtb3ZhbFBvbGljeTogUmVtb3ZhbFBvbGljeS5ERVNUUk9ZIH0pO1xuICAgICAgKHJlcG9zaXRvcnkubm9kZS5kZWZhdWx0Q2hpbGQgYXMgQ2ZuUmVzb3VyY2UpLmFkZFByb3BlcnR5T3ZlcnJpZGUoJ0VtcHR5T25EZWxldGUnLCB0cnVlKTtcbiAgICB9XG4gICAgY29uc3QgcmVwb3NpdG9yeVVyaSA9IHJlcG9zaXRvcnkucmVwb3NpdG9yeVVyaTtcbiAgICBjb25zdCBpbWFnZUFydGlmYWN0TmFtZSA9ICdhcnRpZmFjdCc7XG5cbiAgICBjb25zdCBwcm9qZWN0ID0gbmV3IFNpbmdsZXRvblByb2plY3QodGhpcywgJ1Byb2plY3QnLCB7XG4gICAgICB1dWlkOiAnZTgzNzI5ZmUtYjE1Ni00ZTcwLTliZWMtNDUyYjE1ODQ3YTMwJyxcbiAgICAgIHByb2plY3RQdXJwb3NlOiBpc0FybTY0ID8gJ0NvbnRhaW5lckltYWdlQnVpbGRBcm02NCcgOiAnQ29udGFpbmVySW1hZ2VCdWlsZEFtZDY0JyxcbiAgICAgIGVudmlyb25tZW50OiB7XG4gICAgICAgIGNvbXB1dGVUeXBlOiBDb21wdXRlVHlwZS5TTUFMTCxcbiAgICAgICAgYnVpbGRJbWFnZTogYnVpbGRJbWFnZSxcbiAgICAgICAgcHJpdmlsZWdlZDogdHJ1ZSxcbiAgICAgIH0sXG4gICAgICB2cGM6IHByb3BzLnZwYyxcbiAgICAgIGJ1aWxkU3BlYzogQnVpbGRTcGVjLmZyb21PYmplY3Qoe1xuICAgICAgICB2ZXJzaW9uOiAnMC4yJyxcbiAgICAgICAgcGhhc2VzOiB7XG4gICAgICAgICAgYnVpbGQ6IHtcbiAgICAgICAgICAgIGNvbW1hbmRzOiBbXG4gICAgICAgICAgICAgICdjdXJyZW50X2Rpcj0kKHB3ZCknLFxuICAgICAgICAgICAgICAnZWNobyBcIiRpbnB1dFwiJyxcbiAgICAgICAgICAgICAgJ21rZGlyIHdvcmtkaXInLFxuICAgICAgICAgICAgICAnY2Qgd29ya2RpcicsXG4gICAgICAgICAgICAgICdhd3MgczMgY3AgXCIkc291cmNlUzNVcmxcIiB0ZW1wLnppcCcsXG4gICAgICAgICAgICAgICd1bnppcCB0ZW1wLnppcCcsXG4gICAgICAgICAgICAgICdscyAtbGEnLFxuICAgICAgICAgICAgICAnYXdzIGVjciBnZXQtbG9naW4tcGFzc3dvcmQgfCBkb2NrZXIgbG9naW4gLS11c2VybmFtZSBBV1MgLS1wYXNzd29yZC1zdGRpbiAkcmVwb3NpdG9yeUF1dGhVcmknLFxuICAgICAgICAgICAgICAvLyBmb3IgYWNjZXNzaW5nIEVDUiBwdWJsaWNcbiAgICAgICAgICAgICAgJ2F3cyBlY3ItcHVibGljIGdldC1sb2dpbi1wYXNzd29yZCAtLXJlZ2lvbiB1cy1lYXN0LTEgfCBkb2NrZXIgbG9naW4gLS11c2VybmFtZSBBV1MgLS1wYXNzd29yZC1zdGRpbiBwdWJsaWMuZWNyLmF3cycsXG4gICAgICAgICAgICAgICdkb2NrZXIgYnVpbGR4IGxzJyxcbiAgICAgICAgICAgICAgJ2V2YWwgXCIkYnVpbGRDb21tYW5kXCInLFxuICAgICAgICAgICAgICBgZG9ja2VyIHRhZyAke2ltYWdlQXJ0aWZhY3ROYW1lfTpsYXRlc3QgJHtyZXBvc2l0b3J5VXJpfTokaW1hZ2VUYWdgLFxuICAgICAgICAgICAgICBgZG9ja2VyIHB1c2ggJHtyZXBvc2l0b3J5VXJpfTokaW1hZ2VUYWdgLFxuICAgICAgICAgICAgXSxcbiAgICAgICAgICB9LFxuICAgICAgICAgIHBvc3RfYnVpbGQ6IHtcbiAgICAgICAgICAgIGNvbW1hbmRzOiBbXG4gICAgICAgICAgICAgICdlY2hvIEJ1aWxkIGNvbXBsZXRlZCBvbiBgZGF0ZWAnLFxuICAgICAgICAgICAgICBgXG5TVEFUVVM9J1NVQ0NFU1MnXG5pZiBbICRDT0RFQlVJTERfQlVJTERfU1VDQ0VFRElORyAtbmUgMSBdICMgVGVzdCBpZiB0aGUgYnVpbGQgaXMgZmFpbGluZ1xudGhlblxuU1RBVFVTPSdGQUlMRUQnXG5SRUFTT049XCJDb250YWluZXJJbWFnZUJ1aWxkIGZhaWxlZC4gU2VlIENsb3VkV2F0Y2ggTG9nIHN0cmVhbSBmb3IgdGhlIGRldGFpbGVkIHJlYXNvbjogXG5odHRwczovLyRBV1NfUkVHSU9OLmNvbnNvbGUuYXdzLmFtYXpvbi5jb20vY2xvdWR3YXRjaC9ob21lP3JlZ2lvbj0kQVdTX1JFR0lPTiNsb2dzVjI6bG9nLWdyb3Vwcy9sb2ctZ3JvdXAvXFxcXCQyNTJGYXdzXFxcXCQyNTJGY29kZWJ1aWxkXFxcXCQyNTJGJHByb2plY3ROYW1lL2xvZy1ldmVudHMvJENPREVCVUlMRF9MT0dfUEFUSFwiXG5maVxuY2F0IDw8RU9GID4gcGF5bG9hZC5qc29uXG57XG4gIFwiU3RhY2tJZFwiOiBcIiRzdGFja0lkXCIsXG4gIFwiUmVxdWVzdElkXCI6IFwiJHJlcXVlc3RJZFwiLFxuICBcIkxvZ2ljYWxSZXNvdXJjZUlkXCI6XCIkbG9naWNhbFJlc291cmNlSWRcIixcbiAgXCJQaHlzaWNhbFJlc291cmNlSWRcIjogXCIkaW1hZ2VUYWdcIixcbiAgXCJTdGF0dXNcIjogXCIkU1RBVFVTXCIsXG4gIFwiUmVhc29uXCI6IFwiJFJFQVNPTlwiLFxuICBcIkRhdGFcIjoge1xuICAgIFwiSW1hZ2VUYWdcIjogXCIkaW1hZ2VUYWdcIlxuICB9XG59XG5FT0ZcbmN1cmwgLXYgLWkgLVggUFVUIC1IICdDb250ZW50LVR5cGU6JyAtZCBcIkBwYXlsb2FkLmpzb25cIiBcIiRyZXNwb25zZVVSTFwiXG4gICAgICAgICAgICAgIGAsXG4gICAgICAgICAgICBdLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICB9KSxcbiAgICB9KS5wcm9qZWN0O1xuXG4gICAgcHJvamVjdC5yb2xlIS5hZGRNYW5hZ2VkUG9saWN5KE1hbmFnZWRQb2xpY3kuZnJvbUF3c01hbmFnZWRQb2xpY3lOYW1lKCdBbWF6b25FbGFzdGljQ29udGFpbmVyUmVnaXN0cnlQdWJsaWNSZWFkT25seScpKTtcbiAgICByZXBvc2l0b3J5LmdyYW50UHVsbFB1c2gocHJvamVjdCk7XG4gICAgcmVwb3NpdG9yeS5ncmFudChwcm9qZWN0LCAnZWNyOkRlc2NyaWJlSW1hZ2VzJyk7XG5cbiAgICBoYW5kbGVyLmFkZFRvUm9sZVBvbGljeShcbiAgICAgIG5ldyBQb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICBhY3Rpb25zOiBbJ2NvZGVidWlsZDpTdGFydEJ1aWxkJ10sXG4gICAgICAgIHJlc291cmNlczogW3Byb2plY3QucHJvamVjdEFybl0sXG4gICAgICB9KSxcbiAgICApO1xuXG4gICAgdGhpcy5ncmFudFByaW5jaXBhbCA9IHByb2plY3QuZ3JhbnRQcmluY2lwYWw7XG5cbiAgICBsZXQgYXNzZXRFeGNsdWRlID0gcHJvcHMuZXhjbHVkZTtcbiAgICAvLyBhdXRvbWF0aWNhbGx5IHJlYWQgLmRvY2tlcmlnbm9yZSBmb3IgY29udmVuaWVuY2VcbiAgICBpZiAoYXNzZXRFeGNsdWRlID09PSB1bmRlZmluZWQgJiYgZXhpc3RzU3luYyhqb2luKHByb3BzLmRpcmVjdG9yeSwgJy5kb2NrZXJpZ25vcmUnKSkpIHtcbiAgICAgIGFzc2V0RXhjbHVkZSA9IHJlYWRGaWxlU3luYyhqb2luKHByb3BzLmRpcmVjdG9yeSwgJy5kb2NrZXJpZ25vcmUnKSkudG9TdHJpbmcoKS5zcGxpdCgnXFxuJyk7XG4gICAgfVxuICAgIGNvbnN0IGFzc2V0ID0gbmV3IEFzc2V0KHRoaXMsICdTb3VyY2UnLCB7XG4gICAgICAuLi5wcm9wcyxcbiAgICAgIGV4Y2x1ZGU6IGFzc2V0RXhjbHVkZSxcbiAgICAgIHBhdGg6IHByb3BzLmRpcmVjdG9yeSxcbiAgICB9KTtcbiAgICBhc3NldC5ncmFudFJlYWQocHJvamVjdCk7XG5cbiAgICBjb25zdCBidWlsZENvbW1hbmRPcHRpb25zID0geyAuLi5wcm9wcywgcGxhdGZvcm06IHByb3BzLnBsYXRmb3JtPy5wbGF0Zm9ybSB9IGFzIGFueTtcbiAgICBidWlsZENvbW1hbmRPcHRpb25zLm91dHB1dHMgPz89IFtdO1xuICAgIC8vIHdlIGRvbid0IHVzZSBwdXNoPXRydWUgaGVyZSBiZWNhdXNlIENvZGVCdWlsZCBEb2NrZXIgc2VydmVyIGRvZXMgbm90IHNlZW0gdG8gd29yayBwcm9wZXJseSB3aXRoIHRoZSBjb25maWd1cmF0aW9uLlxuICAgIGJ1aWxkQ29tbWFuZE9wdGlvbnMub3V0cHV0cy5wdXNoKCd0eXBlPWltYWdlJywgYG5hbWU9JHtpbWFnZUFydGlmYWN0TmFtZX1gKTtcbiAgICBpZiAocHJvcHMuenN0ZENvbXByZXNzaW9uKSB7XG4gICAgICAvLyB0byBlbmFibGUgenN0ZCBjb21wcmVzc2lvbiwgYnVpbGR4IGRpcmVjdGx5IHB1c2hlcyB0aGUgYXJ0aWZhY3QgaW1hZ2UgdG8gYSByZWdpc3RyeVxuICAgICAgLy8gaHR0cHM6Ly9hd3MuYW1hem9uLmNvbS9ibG9ncy9jb250YWluZXJzL3JlZHVjaW5nLWF3cy1mYXJnYXRlLXN0YXJ0dXAtdGltZXMtd2l0aC16c3RkLWNvbXByZXNzZWQtY29udGFpbmVyLWltYWdlcy9cbiAgICAgIGJ1aWxkQ29tbWFuZE9wdGlvbnMub3V0cHV0cy5wdXNoKCdvY2ktbWVkaWF0eXBlcz10cnVlJywgJ2NvbXByZXNzaW9uPXpzdGQnLCAnZm9yY2UtY29tcHJlc3Npb249dHJ1ZScsICdjb21wcmVzc2lvbi1sZXZlbD0zJyk7XG4gICAgfVxuICAgIGNvbnN0IGJ1aWxkQ29tbWFuZCA9IHRoaXMuZ2V0RG9ja2VyQnVpbGRDb21tYW5kKGJ1aWxkQ29tbWFuZE9wdGlvbnMpO1xuXG4gICAgY29uc3QgcHJvcGVydGllczogQ29udGFpbmVySW1hZ2VCdWlsZFJlc291cmNlUHJvcHMgPSB7XG4gICAgICB0eXBlOiAnQ29udGFpbmVySW1hZ2VCdWlsZCcsXG4gICAgICBidWlsZENvbW1hbmQ6IGJ1aWxkQ29tbWFuZCxcbiAgICAgIHJlcG9zaXRvcnlVcmksXG4gICAgICBpbWFnZVRhZzogcHJvcHMudGFnLFxuICAgICAgdGFnUHJlZml4OiBwcm9wcy50YWdQcmVmaXgsXG4gICAgICBjb2RlQnVpbGRQcm9qZWN0TmFtZTogcHJvamVjdC5wcm9qZWN0TmFtZSxcbiAgICAgIHNvdXJjZVMzVXJsOiBhc3NldC5zM09iamVjdFVybCxcbiAgICB9O1xuXG4gICAgY29uc3QgY3VzdG9tID0gbmV3IEN1c3RvbVJlc291cmNlKHRoaXMsICdSZXNvdXJjZScsIHtcbiAgICAgIHNlcnZpY2VUb2tlbjogaGFuZGxlci5mdW5jdGlvbkFybixcbiAgICAgIHJlc291cmNlVHlwZTogJ0N1c3RvbTo6Q0RLQ29udGFpbmVySW1hZ2VCdWlsZCcsXG4gICAgICBwcm9wZXJ0aWVzLFxuICAgIH0pO1xuICAgIGN1c3RvbS5ub2RlLmFkZERlcGVuZGVuY3kocHJvamVjdCk7XG5cbiAgICB0aGlzLnJlcG9zaXRvcnkgPSByZXBvc2l0b3J5O1xuICAgIHRoaXMuaW1hZ2VUYWcgPSBjdXN0b20uZ2V0QXR0U3RyaW5nKCdJbWFnZVRhZycpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCB0aGUgaW5zdGFuY2Ugb2Yge0BsaW5rIERvY2tlckltYWdlQ29kZX0gZm9yIGEgTGFtYmRhIGZ1bmN0aW9uIGltYWdlLlxuICAgKi9cbiAgcHVibGljIHRvTGFtYmRhRG9ja2VySW1hZ2VDb2RlKCkge1xuICAgIGlmICh0aGlzLnByb3BzLnpzdGRDb21wcmVzc2lvbikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdZb3UgY2Fubm90IGVuYWJsZSB6c3RkQ29tcHJlc3Npb24gZm9yIGEgTGFtYmRhIGltYWdlLicpO1xuICAgIH1cbiAgICByZXR1cm4gRG9ja2VySW1hZ2VDb2RlLmZyb21FY3IodGhpcy5yZXBvc2l0b3J5LCB7IHRhZ09yRGlnZXN0OiB0aGlzLmltYWdlVGFnIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCB0aGUgaW5zdGFuY2Ugb2Yge0BsaW5rIENvbnRhaW5lckltYWdlfSBmb3IgYW4gRUNTIHRhc2sgZGVmaW5pdGlvbi5cbiAgICovXG4gIHB1YmxpYyB0b0Vjc0RvY2tlckltYWdlQ29kZSgpIHtcbiAgICByZXR1cm4gQ29udGFpbmVySW1hZ2UuZnJvbUVjclJlcG9zaXRvcnkodGhpcy5yZXBvc2l0b3J5LCB0aGlzLmltYWdlVGFnKTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0RG9ja2VyQnVpbGRDb21tYW5kKG9wdGlvbnM6IGFueSkge1xuICAgIC8vIHRoZSBtZW1iZXJzIG9mIHByb3BzIGRpZmZlcnMgd2l0aCBDREsgdmVyc2lvbi5cbiAgICAvLyBCeSByZWdhcmRpbmcgcHJvcHMgYXMgYW55LCB3ZSBjYW4gdXNlIHByb3BzIHRoYXQgYXJlIG5vdCBhdmFpbGFibGUgaW4gb2xkZXIgY2RrIHZlcnNpb25zLlxuXG4gICAgLy8gbG9naWMgaXMgY29waWVkIGZyb20gcGFja2FnZXMvY2RrLWFzc2V0cy9saWIvcHJpdmF0ZS9kb2NrZXIudHNcbiAgICBjb25zdCBjYWNoZU9wdGlvblRvRmxhZyA9IChvcHRpb246IGFueSk6IHN0cmluZyA9PiB7XG4gICAgICBsZXQgZmxhZyA9IGB0eXBlPSR7b3B0aW9uLnR5cGV9YDtcbiAgICAgIGlmIChvcHRpb24ucGFyYW1zKSB7XG4gICAgICAgIGZsYWcgKz1cbiAgICAgICAgICAnLCcgK1xuICAgICAgICAgIE9iamVjdC5lbnRyaWVzKG9wdGlvbi5wYXJhbXMpXG4gICAgICAgICAgICAubWFwKChbaywgdl0pID0+IGAke2t9PSR7dn1gKVxuICAgICAgICAgICAgLmpvaW4oJywnKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBmbGFnO1xuICAgIH07XG4gICAgY29uc3QgZmxhdHRlbiA9ICh4OiBzdHJpbmdbXVtdKSA9PiB7XG4gICAgICByZXR1cm4gQXJyYXkucHJvdG90eXBlLmNvbmNhdChbXSwgLi4ueCk7XG4gICAgfTtcblxuICAgIGNvbnN0IGRvY2tlckJ1aWxkQ29tbWFuZCA9IFtcbiAgICAgICdkb2NrZXIgYnVpbGR4IGJ1aWxkJyxcbiAgICAgIC4uLmZsYXR0ZW4oT2JqZWN0LmVudHJpZXMob3B0aW9ucy5idWlsZEFyZ3MgfHwge30pLm1hcCgoW2ssIHZdKSA9PiBbJy0tYnVpbGQtYXJnJywgYCR7a309JHt2fWBdKSksXG4gICAgICAuLi5mbGF0dGVuKE9iamVjdC5lbnRyaWVzKG9wdGlvbnMuYnVpbGRTZWNyZXRzIHx8IHt9KS5tYXAoKFtrLCB2XSkgPT4gWyctLXNlY3JldCcsIGBpZD0ke2t9LCR7dn1gXSkpLFxuICAgICAgLi4uKG9wdGlvbnMuYnVpbGRTc2ggPyBbJy0tc3NoJywgb3B0aW9ucy5idWlsZFNzaF0gOiBbXSksXG4gICAgICAuLi4ob3B0aW9ucy50YXJnZXQgPyBbJy0tdGFyZ2V0Jywgb3B0aW9ucy50YXJnZXRdIDogW10pLFxuICAgICAgLi4uKG9wdGlvbnMuZmlsZSA/IFsnLS1maWxlJywgb3B0aW9ucy5maWxlXSA6IFtdKSxcbiAgICAgIC4uLihvcHRpb25zLm5ldHdvcmtNb2RlID8gWyctLW5ldHdvcmsnLCBvcHRpb25zLm5ldHdvcmtNb2RlXSA6IFtdKSxcbiAgICAgIC4uLihvcHRpb25zLnBsYXRmb3JtID8gWyctLXBsYXRmb3JtJywgb3B0aW9ucy5wbGF0Zm9ybV0gOiBbXSksXG4gICAgICAuLi4ob3B0aW9ucy5vdXRwdXRzID8gWyctLW91dHB1dCcsIG9wdGlvbnMub3V0cHV0cy5qb2luKCcsJyldIDogW10pLFxuICAgICAgLi4uKG9wdGlvbnMuY2FjaGVGcm9tID8gWy4uLm9wdGlvbnMuY2FjaGVGcm9tLm1hcCgoY2FjaGVGcm9tOiBhbnkpID0+IFsnLS1jYWNoZS1mcm9tJywgY2FjaGVPcHRpb25Ub0ZsYWcoY2FjaGVGcm9tKV0pLmZsYXQoKV0gOiBbXSksXG4gICAgICAuLi4ob3B0aW9ucy5jYWNoZVRvID8gWyctLWNhY2hlLXRvJywgY2FjaGVPcHRpb25Ub0ZsYWcob3B0aW9ucy5jYWNoZVRvKV0gOiBbXSksXG4gICAgICAuLi4ob3B0aW9ucy5jYWNoZURpc2FibGVkID8gWyctLW5vLWNhY2hlJ10gOiBbXSksXG4gICAgICAnLS1wcm92ZW5hbmNlPWZhbHNlJyxcbiAgICAgICcuJyxcbiAgICBdO1xuICAgIHJldHVybiBkb2NrZXJCdWlsZENvbW1hbmQuam9pbignICcpO1xuICB9XG59XG4iXX0=