UNPKG

cdk-drizzle-migrate

Version:

AWS CDK construct for running Drizzle ORM migrations

154 lines 24.7 kB
"use strict"; var _a; Object.defineProperty(exports, "__esModule", { value: true }); exports.DrizzleMigrate = void 0; const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti"); const assert_1 = require("assert"); const fs_1 = require("fs"); const path = require("path"); const aws_cdk_lib_1 = require("aws-cdk-lib"); const dsql = require("aws-cdk-lib/aws-dsql"); const iam = require("aws-cdk-lib/aws-iam"); const lambda = require("aws-cdk-lib/aws-lambda"); const aws_lambda_nodejs_1 = require("aws-cdk-lib/aws-lambda-nodejs"); const logs = require("aws-cdk-lib/aws-logs"); const cr = require("aws-cdk-lib/custom-resources"); const constructs_1 = require("constructs"); /** * Helper function to determine if a cluster is a DSQL cluster */ function isDsqlCluster(cluster) { return cluster instanceof dsql.CfnCluster; } /** * A custom resource that runs Drizzle migrations */ class DrizzleMigrate extends constructs_1.Construct { constructor(scope, id, props) { super(scope, id); // Validate configuration const isDsql = props.cluster && isDsqlCluster(props.cluster); if (!isDsql && !props.dbSecret) { throw new Error("Either dbSecret (for traditional RDS) or cluster with DSQL must be provided"); } if (!isDsql && !props.vpc) { throw new Error("VPC is required for traditional RDS databases"); } if (isDsql && props.dbSecret) { throw new Error("dbSecret should not be provided when using DSQL cluster (uses IAM authentication)"); } const migrationsDir = path.join(process.cwd(), props.migrationsPath); (0, assert_1.strict)((0, fs_1.existsSync)(migrationsDir), `Migrations directory ${migrationsDir} does not exist`); const handlerDir = path.join(__dirname, "handler"); const ts_filename = path.join(handlerDir, "index.ts"); const js_filename = path.join(handlerDir, "index.js"); const entry = (0, fs_1.existsSync)(ts_filename) ? ts_filename : js_filename; const environment = { NO_COLOR: "1", ...(props.handlerProps?.environment || {}), }; // Create explicit log group for the Lambda handler const logGroup = new logs.LogGroup(this, "MigrateHandlerLogGroup", { retention: logs.RetentionDays.ONE_WEEK, // Keep log group, it's annoying when it gets deleted for new // deploys, and something has gone wrong. You have no way to // look at the logs in that case. removalPolicy: aws_cdk_lib_1.RemovalPolicy.RETAIN, }); const onEventHandler = new aws_lambda_nodejs_1.NodejsFunction(this, "MigrateHandler", { runtime: lambda.Runtime.NODEJS_20_X, entry: entry, logGroup: logGroup, loggingFormat: lambda.LoggingFormat.JSON, applicationLogLevelV2: lambda.ApplicationLogLevel.INFO, timeout: aws_cdk_lib_1.Duration.minutes(5), vpc: props.vpc, vpcSubnets: props.vpcSubnets, ...props.handlerProps, environment, bundling: { sourceMap: false, // Include the migrations directory in the bundle commandHooks: { beforeBundling(_, outputDir) { const commands = [ `cp ${handlerDir}/handler.js ${outputDir}`, `cp -r ${migrationsDir} ${path.join(outputDir, "migrations")}`, // Always download RDS certificate for SSL connections (both RDS and DSQL need it) `mkdir -p ${path.join(outputDir, "certs")}`, `curl --silent -fL https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem -o ${path.join(outputDir, "certs", "global-bundle.pem")}`, ]; return commands; }, afterBundling() { return []; }, beforeInstall() { return []; }, }, ...props.handlerProps?.bundling, }, }); // Handle database connection setup if (isDsql) { // For DSQL, grant IAM permissions instead of VPC security groups const dsqlCluster = props.cluster; onEventHandler.addToRolePolicy(new iam.PolicyStatement({ effect: iam.Effect.ALLOW, actions: ["dsql:DbConnectAdmin"], resources: [dsqlCluster.attrResourceArn], })); } else { // Traditional RDS setup with security groups if (props.cluster && (!props.handlerProps || typeof props.handlerProps.securityGroups === "undefined" || props.handlerProps.securityGroups.length === 0)) { const rdsCluster = props.cluster; rdsCluster.connections.allowDefaultPortFrom(onEventHandler.connections, "Allow drizzle migrate lambda to connect to db"); } // Grant the Lambda function permission to read the secret props.dbSecret.grantRead(onEventHandler); } this.handler = onEventHandler; const provider = new cr.Provider(this, "Provider", { onEventHandler, logGroup, }); // Build custom resource properties based on database type const customResourceProperties = { // We're now using a fixed path inside the Lambda bundle migrationsPath: "migrations", // Adding a timestamp ensures the resource is updated on each deployment timestamp: Date.now().toString(), }; if (isDsql) { // For DSQL, construct the endpoint from cluster ID and region // DSQL endpoint format: ${clusterId}.dsql.${region}.on.aws const dsqlCluster = props.cluster; const clusterId = dsqlCluster.attrIdentifier; const region = aws_cdk_lib_1.Stack.of(this).region; customResourceProperties.endpoint = `${clusterId}.dsql.${region}.on.aws`; customResourceProperties.port = "5432"; } else { customResourceProperties.secretArn = props.dbSecret.secretArn; } this.resource = new aws_cdk_lib_1.CustomResource(this, "CustomResource", { serviceToken: provider.serviceToken, properties: customResourceProperties, }); const resourceCfn = this.resource.node.defaultChild; resourceCfn.addPropertyOverride("ServiceTimeout", 900); // Add dependency to ensure database is created before migrations run if (props.cluster) { this.resource.node.addDependency(props.cluster); } } } exports.DrizzleMigrate = DrizzleMigrate; _a = JSII_RTTI_SYMBOL_1; DrizzleMigrate[_a] = { fqn: "cdk-drizzle-migrate.DrizzleMigrate", version: "2.0.4" }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZHJpenpsZS1taWdyYXRlLXByb3ZpZGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2RyaXp6bGUtbWlncmF0ZS1wcm92aWRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLG1DQUF5QztBQUN6QywyQkFBK0I7QUFDL0IsNkJBQTRCO0FBQzVCLDZDQUF5RjtBQUN6Riw2Q0FBNEM7QUFFNUMsMkNBQTBDO0FBQzFDLGlEQUFnRDtBQUNoRCxxRUFBbUY7QUFDbkYsNkNBQTRDO0FBRzVDLG1EQUFrRDtBQUNsRCwyQ0FBc0M7QUFFdEM7O0dBRUc7QUFDSCxTQUFTLGFBQWEsQ0FDcEIsT0FBdUU7SUFFdkUsT0FBTyxPQUFPLFlBQVksSUFBSSxDQUFDLFVBQVUsQ0FBQTtBQUMzQyxDQUFDO0FBcUREOztHQUVHO0FBQ0gsTUFBYSxjQUFlLFNBQVEsc0JBQVM7SUFXM0MsWUFBWSxLQUFnQixFQUFFLEVBQVUsRUFBRSxLQUEwQjtRQUNsRSxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFBO1FBRWhCLHlCQUF5QjtRQUN6QixNQUFNLE1BQU0sR0FBRyxLQUFLLENBQUMsT0FBTyxJQUFJLGFBQWEsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUE7UUFDNUQsSUFBSSxDQUFDLE1BQU0sSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUMvQixNQUFNLElBQUksS0FBSyxDQUNiLDZFQUE2RSxDQUM5RSxDQUFBO1FBQ0gsQ0FBQztRQUNELElBQUksQ0FBQyxNQUFNLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLENBQUM7WUFDMUIsTUFBTSxJQUFJLEtBQUssQ0FBQywrQ0FBK0MsQ0FBQyxDQUFBO1FBQ2xFLENBQUM7UUFDRCxJQUFJLE1BQU0sSUFBSSxLQUFLLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDN0IsTUFBTSxJQUFJLEtBQUssQ0FDYixtRkFBbUYsQ0FDcEYsQ0FBQTtRQUNILENBQUM7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QztZQUNYLDhEQUE4RDtZQUM5RCwyREFBMkQ7WUFDM0QsTUFBTSxXQUFXLEdBQUcsS0FBSyxDQUFDLE9BQTBCLENBQUE7WUFDcEQsTUFBTSxTQUFTLEdBQUcsV0FBVyxDQUFDLGNBQWMsQ0FBQTtZQUM1QyxNQUFNLE1BQU0sR0FBRyxtQkFBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxNQUFNLENBQUE7WUFDcEMsd0JBQXdCLENBQUMsUUFBUSxHQUFHLEdBQUcsU0FBUyxTQUFTLE1BQU0sU0FBUyxDQUFBO1lBQ3hFLHdCQUF3QixDQUFDLElBQUksR0FBRyxNQUFNLENBQUE7UUFDeEMsQ0FBQzthQUFNLENBQUM7WUFDTix3QkFBd0IsQ0FBQyxTQUFTLEdBQUcsS0FBSyxDQUFDLFFBQVMsQ0FBQyxTQUFTLENBQUE7UUFDaEUsQ0FBQztRQUVELElBQUksQ0FBQyxRQUFRLEdBQUcsSUFBSSw0QkFBYyxDQUFDLElBQUksRUFBRSxnQkFBZ0IsRUFBRTtZQUN6RCxZQUFZLEVBQUUsUUFBUSxDQUFDLFlBQVk7WUFDbkMsVUFBVSxFQUFFLHdCQUF3QjtTQUNyQyxDQUFDLENBQUE7UUFFRixNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxZQUEyQixDQUFBO1FBQ2xFLFdBQVcsQ0FBQyxtQkFBbUIsQ0FBQyxnQkFBZ0IsRUFBRSxHQUFHLENBQUMsQ0FBQTtRQUV0RCxxRUFBcUU7UUFDckUsSUFBSSxLQUFLLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDbEIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQTtRQUNqRCxDQUFDO0lBQ0gsQ0FBQzs7QUFqS0gsd0NBa0tDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgc3RyaWN0IGFzIGFzc2VydCB9IGZyb20gXCJhc3NlcnRcIlxuaW1wb3J0IHsgZXhpc3RzU3luYyB9IGZyb20gXCJmc1wiXG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gXCJwYXRoXCJcbmltcG9ydCB7IENmblJlc291cmNlLCBDdXN0b21SZXNvdXJjZSwgRHVyYXRpb24sIFN0YWNrLCBSZW1vdmFsUG9saWN5IH0gZnJvbSBcImF3cy1jZGstbGliXCJcbmltcG9ydCAqIGFzIGRzcWwgZnJvbSBcImF3cy1jZGstbGliL2F3cy1kc3FsXCJcbmltcG9ydCAqIGFzIGVjMiBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWVjMlwiXG5pbXBvcnQgKiBhcyBpYW0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1pYW1cIlxuaW1wb3J0ICogYXMgbGFtYmRhIGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtbGFtYmRhXCJcbmltcG9ydCB7IE5vZGVqc0Z1bmN0aW9uLCBOb2RlanNGdW5jdGlvblByb3BzIH0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1sYW1iZGEtbm9kZWpzXCJcbmltcG9ydCAqIGFzIGxvZ3MgZnJvbSBcImF3cy1jZGstbGliL2F3cy1sb2dzXCJcbmltcG9ydCAqIGFzIHJkcyBmcm9tIFwiYXdzLWNkay1saWIvYXdzLXJkc1wiXG5pbXBvcnQgKiBhcyBzZWNyZXRzbWFuYWdlciBmcm9tIFwiYXdzLWNkay1saWIvYXdzLXNlY3JldHNtYW5hZ2VyXCJcbmltcG9ydCAqIGFzIGNyIGZyb20gXCJhd3MtY2RrLWxpYi9jdXN0b20tcmVzb3VyY2VzXCJcbmltcG9ydCB7IENvbnN0cnVjdCB9IGZyb20gXCJjb25zdHJ1Y3RzXCJcblxuLyoqXG4gKiBIZWxwZXIgZnVuY3Rpb24gdG8gZGV0ZXJtaW5lIGlmIGEgY2x1c3RlciBpcyBhIERTUUwgY2x1c3RlclxuICovXG5mdW5jdGlvbiBpc0RzcWxDbHVzdGVyKFxuICBjbHVzdGVyOiByZHMuSURhdGFiYXNlQ2x1c3RlciB8IHJkcy5JRGF0YWJhc2VJbnN0YW5jZSB8IGRzcWwuQ2ZuQ2x1c3RlclxuKTogY2x1c3RlciBpcyBkc3FsLkNmbkNsdXN0ZXIge1xuICByZXR1cm4gY2x1c3RlciBpbnN0YW5jZW9mIGRzcWwuQ2ZuQ2x1c3RlclxufVxuXG4vKipcbiAqIFByb3BlcnRpZXMgZm9yIERyaXp6bGVNaWdyYXRlXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRHJpenpsZU1pZ3JhdGVQcm9wcyB7XG4gIC8qKlxuICAgKiBUaGUgZGF0YWJhc2Ugc2VjcmV0IGNvbnRhaW5pbmcgY29ubmVjdGlvbiBkZXRhaWxzXG4gICAqIE11c3QgY29udGFpbiBzdGFuZGFyZCBDREsgZGF0YWJhc2Ugc2VjcmV0IHByb3BlcnRpZXM6IHVzZXJuYW1lLFxuICAgKiBwYXNzd29yZCwgaG9zdCwgcG9ydCwgZW5naW5lLCBldGMuXG4gICAqIE5vdCByZXF1aXJlZCB3aGVuIHJlbHlpbmcgb24gSUFNIGF1dGhlbnRpY2F0aW9uIChzdWNoIGFzIERTUUwpLlxuICAgKiBAZGVmYXVsdCAtIHVuZGVmaW5lZCBmb3IgRFNRTCBjbHVzdGVycyB1c2luZyBJQU0gYXV0aGVudGljYXRpb25cbiAgICovXG4gIHJlYWRvbmx5IGRiU2VjcmV0Pzogc2VjcmV0c21hbmFnZXIuSVNlY3JldFxuXG4gIC8qKlxuICAgKiBUaGUgcGF0aCB0byB0aGUgbWlncmF0aW9ucyBkaXJlY3RvcnlcbiAgICogVGhpcyBkaXJlY3Rvcnkgd2lsbCBiZSBidW5kbGVkIHdpdGggdGhlIExhbWJkYSBmdW5jdGlvblxuICAgKi9cbiAgcmVhZG9ubHkgbWlncmF0aW9uc1BhdGg6IHN0cmluZ1xuXG4gIC8qKlxuICAgKiBPcHRpb25hbCBwcm9wZXJ0aWVzIHRvIGN1c3RvbWl6ZSB0aGUgTGFtYmRhIGZ1bmN0aW9uXG4gICAqIEV4Y2x1ZGVzIHJ1bnRpbWUsIGVudHJ5LCBhbmQgaGFuZGxlciB3aGljaCBhcmUgbWFuYWdlZCBieSB0aGUgY29uc3RydWN0XG4gICAqIEBkZWZhdWx0IC0gRGVmYXVsdCBMYW1iZGEgY29uZmlndXJhdGlvbiBpcyB1c2VkXG4gICAqL1xuICByZWFkb25seSBoYW5kbGVyUHJvcHM/OiBOb2RlanNGdW5jdGlvblByb3BzXG5cbiAgLyoqXG4gICAqIFRoZSBWUEMgd2hlcmUgdGhlIExhbWJkYSBmdW5jdGlvbiB3aWxsIGJlIGRlcGxveWVkXG4gICAqIFJlcXVpcmVkIHdoZW4geW91ciBkYXRhYmFzZSBpcyBvbmx5IGFjY2Vzc2libGUgaW4gYSBWUEMuXG4gICAqIE5vdCByZXF1aXJlZCBmb3IgRFNRTCBhcyBpdCB1c2VzIHB1YmxpYyBlbmRwb2ludHMgd2l0aCBJQU0gYXV0aGVudGljYXRpb25cbiAgICogQGRlZmF1bHQgLSB1c2UgVlBDIG9mIHlvdXIgUkRTL0F1cm9yYSBjbHVzdGVyXG4gICAqL1xuICByZWFkb25seSB2cGM/OiBlYzIuSVZwY1xuXG4gIC8qKlxuICAgKiBPcHRpb25hbCBzdWJuZXQgc2VsZWN0aW9uIHRvIGRlcGxveSB0aGUgTGFtYmRhIGZ1bmN0aW9uXG4gICAqIE9ubHkgdXNlZCB3aGVuIHZwYyBpcyBzcGVjaWZpZWRcbiAgICogQGRlZmF1bHQgLSBQUklWQVRFX1dJVEhfRUdSRVNTIHN1Ym5ldHNcbiAgICovXG4gIHJlYWRvbmx5IHZwY1N1Ym5ldHM/OiBlYzIuU3VibmV0U2VsZWN0aW9uXG5cbiAgLyoqXG4gICAqIE9wdGlvbmFsIGRhdGFiYXNlIGNsdXN0ZXIgb3IgaW5zdGFuY2VcbiAgICogU3VwcG9ydHMgYm90aCB0cmFkaXRpb25hbCBSRFMvQXVyb3JhIGNsdXN0ZXJzIGFuZCBEU1FMIGNsdXN0ZXJzXG4gICAqIC0gRm9yIFJEUy9BdXJvcmE6IHNlY3VyaXR5IGdyb3VwcyB3aWxsIGJlIGNvbmZpZ3VyZWQgdG8gYWxsb3cgYWNjZXNzXG4gICAqIC0gRm9yIERTUUw6IElBTSBhdXRoZW50aWNhdGlvbiB3aWxsIGJlIHVzZWQgaW5zdGVhZCBvZiBzZWNyZXRzXG4gICAqIEBkZWZhdWx0IC0gTm8gZGF0YWJhc2UgY29ubmVjdGlvbiBpcyBjb25maWd1cmVkXG4gICAqL1xuICByZWFkb25seSBjbHVzdGVyPzogcmRzLklEYXRhYmFzZUNsdXN0ZXIgfCByZHMuSURhdGFiYXNlSW5zdGFuY2UgfCBkc3FsLkNmbkNsdXN0ZXJcbn1cblxuLyoqXG4gKiBBIGN1c3RvbSByZXNvdXJjZSB0aGF0IHJ1bnMgRHJpenpsZSBtaWdyYXRpb25zXG4gKi9cbmV4cG9ydCBjbGFzcyBEcml6emxlTWlncmF0ZSBleHRlbmRzIENvbnN0cnVjdCB7XG4gIC8qKlxuICAgKiBUaGUgY3VzdG9tIHJlc291cmNlIHRoYXQgd2FzIGNyZWF0ZWRcbiAgICovXG4gIHB1YmxpYyByZWFkb25seSByZXNvdXJjZTogQ3VzdG9tUmVzb3VyY2VcblxuICAvKipcbiAgICogVGhlIExhbWJkYSBmdW5jdGlvbiB0aGF0IGV4ZWN1dGVzIHRoZSBtaWdyYXRpb25zXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgaGFuZGxlcjogTm9kZWpzRnVuY3Rpb25cblxuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogRHJpenpsZU1pZ3JhdGVQcm9wcykge1xuICAgIHN1cGVyKHNjb3BlLCBpZClcblxuICAgIC8vIFZhbGlkYXRlIGNvbmZpZ3VyYXRpb25cbiAgICBjb25zdCBpc0RzcWwgPSBwcm9wcy5jbHVzdGVyICYmIGlzRHNxbENsdXN0ZXIocHJvcHMuY2x1c3RlcilcbiAgICBpZiAoIWlzRHNxbCAmJiAhcHJvcHMuZGJTZWNyZXQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgXCJFaXRoZXIgZGJTZWNyZXQgKGZvciB0cmFkaXRpb25hbCBSRFMpIG9yIGNsdXN0ZXIgd2l0aCBEU1FMIG11c3QgYmUgcHJvdmlkZWRcIlxuICAgICAgKVxuICAgIH1cbiAgICBpZiAoIWlzRHNxbCAmJiAhcHJvcHMudnBjKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJWUEMgaXMgcmVxdWlyZWQgZm9yIHRyYWRpdGlvbmFsIFJEUyBkYXRhYmFzZXNcIilcbiAgICB9XG4gICAgaWYgKGlzRHNxbCAmJiBwcm9wcy5kYlNlY3JldCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBcImRiU2VjcmV0IHNob3VsZCBub3QgYmUgcHJvdmlkZWQgd2hlbiB1c2luZyBEU1FMIGNsdXN0ZXIgKHVzZXMgSUFNIGF1dGhlbnRpY2F0aW9uKVwiXG4gICAgICApXG4gICAgfVxuXG4gICAgY29uc3QgbWlncmF0aW9uc0RpciA9IHBhdGguam9pbihwcm9jZXNzLmN3ZCgpLCBwcm9wcy5taWdyYXRpb25zUGF0aClcbiAgICBhc3NlcnQoXG4gICAgICBleGlzdHNTeW5jKG1pZ3JhdGlvbnNEaXIpLFxuICAgICAgYE1pZ3JhdGlvbnMgZGlyZWN0b3J5ICR7bWlncmF0aW9uc0Rpcn0gZG9lcyBub3QgZXhpc3RgXG4gICAgKVxuICAgIGNvbnN0IGhhbmRsZXJEaXIgPSBwYXRoLmpvaW4oX19kaXJuYW1lLCBcImhhbmRsZXJcIilcblxuICAgIGNvbnN0IHRzX2ZpbGVuYW1lID0gcGF0aC5qb2luKGhhbmRsZXJEaXIsIFwiaW5kZXgudHNcIilcbiAgICBjb25zdCBqc19maWxlbmFtZSA9IHBhdGguam9pbihoYW5kbGVyRGlyLCBcImluZGV4LmpzXCIpXG4gICAgY29uc3QgZW50cnkgPSBleGlzdHNTeW5jKHRzX2ZpbGVuYW1lKSA/IHRzX2ZpbGVuYW1lIDoganNfZmlsZW5hbWVcblxuICAgIGNvbnN0IGVudmlyb25tZW50OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge1xuICAgICAgTk9fQ09MT1I6IFwiMVwiLFxuICAgICAgLi4uKHByb3BzLmhhbmRsZXJQcm9wcz8uZW52aXJvbm1lbnQgfHwge30pLFxuICAgIH1cblxuICAgIC8vIENyZWF0ZSBleHBsaWNpdCBsb2cgZ3JvdXAgZm9yIHRoZSBMYW1iZGEgaGFuZGxlclxuICAgIGNvbnN0IGxvZ0dyb3VwID0gbmV3IGxvZ3MuTG9nR3JvdXAodGhpcywgXCJNaWdyYXRlSGFuZGxlckxvZ0dyb3VwXCIsIHtcbiAgICAgIHJldGVudGlvbjogbG9ncy5SZXRlbnRpb25EYXlzLk9ORV9XRUVLLFxuICAgICAgLy8gS2VlcCBsb2cgZ3JvdXAsIGl0J3MgYW5ub3lpbmcgd2hlbiBpdCBnZXRzIGRlbGV0ZWQgZm9yIG5ld1xuICAgICAgLy8gZGVwbG95cywgYW5kIHNvbWV0aGluZyBoYXMgZ29uZSB3cm9uZy4gWW91IGhhdmUgbm8gd2F5IHRvXG4gICAgICAvLyBsb29rIGF0IHRoZSBsb2dzIGluIHRoYXQgY2FzZS5cbiAgICAgIHJlbW92YWxQb2xpY3k6IFJlbW92YWxQb2xpY3kuUkVUQUlOLFxuICAgIH0pXG5cbiAgICBjb25zdCBvbkV2ZW50SGFuZGxlciA9IG5ldyBOb2RlanNGdW5jdGlvbih0aGlzLCBcIk1pZ3JhdGVIYW5kbGVyXCIsIHtcbiAgICAgIHJ1bnRpbWU6IGxhbWJkYS5SdW50aW1lLk5PREVKU18yMF9YLFxuICAgICAgZW50cnk6IGVudHJ5LFxuICAgICAgbG9nR3JvdXA6IGxvZ0dyb3VwLFxuICAgICAgbG9nZ2luZ0Zvcm1hdDogbGFtYmRhLkxvZ2dpbmdGb3JtYXQuSlNPTixcbiAgICAgIGFwcGxpY2F0aW9uTG9nTGV2ZWxWMjogbGFtYmRhLkFwcGxpY2F0aW9uTG9nTGV2ZWwuSU5GTyxcbiAgICAgIHRpbWVvdXQ6IER1cmF0aW9uLm1pbnV0ZXMoNSksXG4gICAgICB2cGM6IHByb3BzLnZwYyxcbiAgICAgIHZwY1N1Ym5ldHM6IHByb3BzLnZwY1N1Ym5ldHMsXG4gICAgICAuLi5wcm9wcy5oYW5kbGVyUHJvcHMsXG4gICAgICBlbnZpcm9ubWVudCxcbiAgICAgIGJ1bmRsaW5nOiB7XG4gICAgICAgIHNvdXJjZU1hcDogZmFsc2UsXG4gICAgICAgIC8vIEluY2x1ZGUgdGhlIG1pZ3JhdGlvbnMgZGlyZWN0b3J5IGluIHRoZSBidW5kbGVcbiAgICAgICAgY29tbWFuZEhvb2tzOiB7XG4gICAgICAgICAgYmVmb3JlQnVuZGxpbmcoXzogc3RyaW5nLCBvdXRwdXREaXI6IHN0cmluZyk6IHN0cmluZ1tdIHtcbiAgICAgICAgICAgIGNvbnN0IGNvbW1hbmRzID0gW1xuICAgICAgICAgICAgICBgY3AgJHtoYW5kbGVyRGlyfS9oYW5kbGVyLmpzICR7b3V0cHV0RGlyfWAsXG4gICAgICAgICAgICAgIGBjcCAtciAke21pZ3JhdGlvbnNEaXJ9ICR7cGF0aC5qb2luKG91dHB1dERpciwgXCJtaWdyYXRpb25zXCIpfWAsXG4gICAgICAgICAgICAgIC8vIEFsd2F5cyBkb3dubG9hZCBSRFMgY2VydGlmaWNhdGUgZm9yIFNTTCBjb25uZWN0aW9ucyAoYm90aCBSRFMgYW5kIERTUUwgbmVlZCBpdClcbiAgICAgICAgICAgICAgYG1rZGlyIC1wICR7cGF0aC5qb2luKG91dHB1dERpciwgXCJjZXJ0c1wiKX1gLFxuICAgICAgICAgICAgICBgY3VybCAtLXNpbGVudCAtZkwgaHR0cHM6Ly90cnVzdHN0b3JlLnBraS5yZHMuYW1hem9uYXdzLmNvbS9nbG9iYWwvZ2xvYmFsLWJ1bmRsZS5wZW0gLW8gJHtwYXRoLmpvaW4ob3V0cHV0RGlyLCBcImNlcnRzXCIsIFwiZ2xvYmFsLWJ1bmRsZS5wZW1cIil9YCxcbiAgICAgICAgICAgIF1cblxuICAgICAgICAgICAgcmV0dXJuIGNvbW1hbmRzXG4gICAgICAgICAgfSxcbiAgICAgICAgICBhZnRlckJ1bmRsaW5nKCk6IHN0cmluZ1tdIHtcbiAgICAgICAgICAgIHJldHVybiBbXVxuICAgICAgICAgIH0sXG4gICAgICAgICAgYmVmb3JlSW5zdGFsbCgpOiBzdHJpbmdbXSB7XG4gICAgICAgICAgICByZXR1cm4gW11cbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgICAuLi5wcm9wcy5oYW5kbGVyUHJvcHM/LmJ1bmRsaW5nLFxuICAgICAgfSxcbiAgICB9KVxuXG4gICAgLy8gSGFuZGxlIGRhdGFiYXNlIGNvbm5lY3Rpb24gc2V0dXBcbiAgICBpZiAoaXNEc3FsKSB7XG4gICAgICAvLyBGb3IgRFNRTCwgZ3JhbnQgSUFNIHBlcm1pc3Npb25zIGluc3RlYWQgb2YgVlBDIHNlY3VyaXR5IGdyb3Vwc1xuICAgICAgY29uc3QgZHNxbENsdXN0ZXIgPSBwcm9wcy5jbHVzdGVyIGFzIGRzcWwuQ2ZuQ2x1c3RlclxuICAgICAgb25FdmVudEhhbmRsZXIuYWRkVG9Sb2xlUG9saWN5KFxuICAgICAgICBuZXcgaWFtLlBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgICAgZWZmZWN0OiBpYW0uRWZmZWN0LkFMTE9XLFxuICAgICAgICAgIGFjdGlvbnM6IFtcImRzcWw6RGJDb25uZWN0QWRtaW5cIl0sXG4gICAgICAgICAgcmVzb3VyY2VzOiBbZHNxbENsdXN0ZXIuYXR0clJlc291cmNlQXJuXSxcbiAgICAgICAgfSlcbiAgICAgIClcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gVHJhZGl0aW9uYWwgUkRTIHNldHVwIHdpdGggc2VjdXJpdHkgZ3JvdXBzXG4gICAgICBpZiAoXG4gICAgICAgIHByb3BzLmNsdXN0ZXIgJiZcbiAgICAgICAgKCFwcm9wcy5oYW5kbGVyUHJvcHMgfHxcbiAgICAgICAgICB0eXBlb2YgcHJvcHMuaGFuZGxlclByb3BzLnNlY3VyaXR5R3JvdXBzID09PSBcInVuZGVmaW5lZFwiIHx8XG4gICAgICAgICAgcHJvcHMuaGFuZGxlclByb3BzLnNlY3VyaXR5R3JvdXBzLmxlbmd0aCA9PT0gMClcbiAgICAgICkge1xuICAgICAgICBjb25zdCByZHNDbHVzdGVyID0gcHJvcHMuY2x1c3RlciBhcyByZHMuSURhdGFiYXNlQ2x1c3RlciB8IHJkcy5JRGF0YWJhc2VJbnN0YW5jZVxuICAgICAgICByZHNDbHVzdGVyLmNvbm5lY3Rpb25zLmFsbG93RGVmYXVsdFBvcnRGcm9tKFxuICAgICAgICAgIG9uRXZlbnRIYW5kbGVyLmNvbm5lY3Rpb25zLFxuICAgICAgICAgIFwiQWxsb3cgZHJpenpsZSBtaWdyYXRlIGxhbWJkYSB0byBjb25uZWN0IHRvIGRiXCJcbiAgICAgICAgKVxuICAgICAgfVxuXG4gICAgICAvLyBHcmFudCB0aGUgTGFtYmRhIGZ1bmN0aW9uIHBlcm1pc3Npb24gdG8gcmVhZCB0aGUgc2VjcmV0XG4gICAgICBwcm9wcy5kYlNlY3JldCEuZ3JhbnRSZWFkKG9uRXZlbnRIYW5kbGVyKVxuICAgIH1cblxuICAgIHRoaXMuaGFuZGxlciA9IG9uRXZlbnRIYW5kbGVyXG5cbiAgICBjb25zdCBwcm92aWRlciA9IG5ldyBjci5Qcm92aWRlcih0aGlzLCBcIlByb3ZpZGVyXCIsIHtcbiAgICAgIG9uRXZlbnRIYW5kbGVyLFxuICAgICAgbG9nR3JvdXAsXG4gICAgfSlcblxuICAgIC8vIEJ1aWxkIGN1c3RvbSByZXNvdXJjZSBwcm9wZXJ0aWVzIGJhc2VkIG9uIGRhdGFiYXNlIHR5cGVcbiAgICBjb25zdCBjdXN0b21SZXNvdXJjZVByb3BlcnRpZXM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgICAvLyBXZSdyZSBub3cgdXNpbmcgYSBmaXhlZCBwYXRoIGluc2lkZSB0aGUgTGFtYmRhIGJ1bmRsZVxuICAgICAgbWlncmF0aW9uc1BhdGg6IFwibWlncmF0aW9uc1wiLFxuICAgICAgLy8gQWRkaW5nIGEgdGltZXN0YW1wIGVuc3VyZXMgdGhlIHJlc291cmNlIGlzIHVwZGF0ZWQgb24gZWFjaCBkZXBsb3ltZW50XG4gICAgICB0aW1lc3RhbXA6IERhdGUubm93KCkudG9TdHJpbmcoKSxcbiAgICB9XG5cbiAgICBpZiAoaXNEc3FsKSB7XG4gICAgICAvLyBGb3IgRFNRTCwgY29uc3RydWN0IHRoZSBlbmRwb2ludCBmcm9tIGNsdXN0ZXIgSUQgYW5kIHJlZ2lvblxuICAgICAgLy8gRFNRTCBlbmRwb2ludCBmb3JtYXQ6ICR7Y2x1c3RlcklkfS5kc3FsLiR7cmVnaW9ufS5vbi5hd3NcbiAgICAgIGNvbnN0IGRzcWxDbHVzdGVyID0gcHJvcHMuY2x1c3RlciBhcyBkc3FsLkNmbkNsdXN0ZXJcbiAgICAgIGNvbnN0IGNsdXN0ZXJJZCA9IGRzcWxDbHVzdGVyLmF0dHJJZGVudGlmaWVyXG4gICAgICBjb25zdCByZWdpb24gPSBTdGFjay5vZih0aGlzKS5yZWdpb25cbiAgICAgIGN1c3RvbVJlc291cmNlUHJvcGVydGllcy5lbmRwb2ludCA9IGAke2NsdXN0ZXJJZH0uZHNxbC4ke3JlZ2lvbn0ub24uYXdzYFxuICAgICAgY3VzdG9tUmVzb3VyY2VQcm9wZXJ0aWVzLnBvcnQgPSBcIjU0MzJcIlxuICAgIH0gZWxzZSB7XG4gICAgICBjdXN0b21SZXNvdXJjZVByb3BlcnRpZXMuc2VjcmV0QXJuID0gcHJvcHMuZGJTZWNyZXQhLnNlY3JldEFyblxuICAgIH1cblxuICAgIHRoaXMucmVzb3VyY2UgPSBuZXcgQ3VzdG9tUmVzb3VyY2UodGhpcywgXCJDdXN0b21SZXNvdXJjZVwiLCB7XG4gICAgICBzZXJ2aWNlVG9rZW46IHByb3ZpZGVyLnNlcnZpY2VUb2tlbixcbiAgICAgIHByb3BlcnRpZXM6IGN1c3RvbVJlc291cmNlUHJvcGVydGllcyxcbiAgICB9KVxuXG4gICAgY29uc3QgcmVzb3VyY2VDZm4gPSB0aGlzLnJlc291cmNlLm5vZGUuZGVmYXVsdENoaWxkIGFzIENmblJlc291cmNlXG4gICAgcmVzb3VyY2VDZm4uYWRkUHJvcGVydHlPdmVycmlkZShcIlNlcnZpY2VUaW1lb3V0XCIsIDkwMClcblxuICAgIC8vIEFkZCBkZXBlbmRlbmN5IHRvIGVuc3VyZSBkYXRhYmFzZSBpcyBjcmVhdGVkIGJlZm9yZSBtaWdyYXRpb25zIHJ1blxuICAgIGlmIChwcm9wcy5jbHVzdGVyKSB7XG4gICAgICB0aGlzLnJlc291cmNlLm5vZGUuYWRkRGVwZW5kZW5jeShwcm9wcy5jbHVzdGVyKVxuICAgIH1cbiAgfVxufVxuIl19