UNPKG

aws-ddk-core

Version:

The AWS DataOps Development Kit is an open source development framework for customers that build data workflows and modern data architecture on AWS.

205 lines (190 loc) 23.9 kB
"use strict"; var _a; Object.defineProperty(exports, "__esModule", { value: true }); exports.MWAATriggerDagsStage = void 0; const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti"); const cdk = require("aws-cdk-lib"); const iam = require("aws-cdk-lib/aws-iam"); const lambda = require("aws-cdk-lib/aws-lambda"); const sfn = require("aws-cdk-lib/aws-stepfunctions"); const tasks = require("aws-cdk-lib/aws-stepfunctions-tasks"); const stage_1 = require("../pipelines/stage"); /** * Stage that contains a step function that runs a Managed Apache Airflow (MWAA) dag or set of dags . */ class MWAATriggerDagsStage extends stage_1.StateMachineStage { /** * Constructs MWAATriggerDagsStage. * @param scope Scope within which this construct is defined. * @param id Identifier of the stage. * @param props Properties for the stage. */ constructor(scope, id, props) { super(scope, id, props); this.mwaaEnvironmentName = props.mwaaEnvironmentName; if (props.dags && props.dagPath) { throw TypeError("For this stage provide one of 'dags' or 'dagPath' parameter, not both"); } const dagIds = props.dagPath ? sfn.JsonPath.stringAt(props.dagPath) : props.dags; if (!dagIds) { throw TypeError("For this stage one of 'dags' or 'dagPath' parameter is required"); } const lambdas = this.buildLambdas(); const definition = new sfn.Parallel(this, "Parallel States"); const waitTask = new sfn.Wait(this, "Wait Before Checking Status", { time: sfn.WaitTime.duration(props.statusCheckPeriod ?? cdk.Duration.seconds(15)), }); definition.branch(new tasks.LambdaInvoke(this, "Trigger Dag", { lambdaFunction: lambdas.triggerLambda, payload: sfn.TaskInput.fromObject({ dag_ids: dagIds, body: sfn.JsonPath.objectAt("$") }), resultPath: sfn.JsonPath.DISCARD, }) .next(waitTask) .next(new tasks.LambdaInvoke(this, "Get Dag Execution Status", { lambdaFunction: lambdas.statusLambda, payload: sfn.TaskInput.fromObject({ dag_ids: dagIds }), resultPath: "$.result", }).next(new sfn.Choice(this, `Check Execution Status`) .when(sfn.Condition.stringEquals("$.result.Payload", "success"), new sfn.Succeed(this, "Success")) .when(sfn.Condition.stringEquals("$.result.Payload", "failed"), new sfn.Fail(this, "Failure", { error: "DagExecutionFailed" })) .otherwise(waitTask)))); ({ eventPattern: this.eventPattern, targets: this.targets, stateMachine: this.stateMachine, } = this.createStateMachine({ definition: definition, ...props })); } buildLambdas() { const lambdaRole = new iam.Role(this, `MWAA Stage Lambda Role`, { assumedBy: new iam.ServicePrincipal("lambda.amazonaws.com"), description: "lambda role to trigger airflow dag execution", }); // Enable the functions to get flow execution records lambdaRole.addToPolicy(new iam.PolicyStatement({ effect: iam.Effect.ALLOW, actions: ["airflow:CreateCliToken"], resources: ["*"], })); const triggerLambda = new lambda.Function(this, "Trigger Dag Lambda", { code: lambda.Code.fromInline(` # Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"). # You may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import boto3 import http.client import base64 import ast from datetime import datetime import json execution_date = datetime.today().strftime('%Y-%m-%d') mwaa_env_name = "${this.mwaaEnvironmentName}" client = boto3.client('mwaa') def run_api_call(conn, payload, headers): print(f"running command: {payload}") conn.request("POST", "/aws_mwaa/cli", payload, headers) res = conn.getresponse() data = res.read() dict_str = data.decode("UTF-8") mydata = ast.literal_eval(dict_str) return base64.b64decode(mydata['stdout']) def lambda_handler(event, context): # get web token mwaa_cli_token = client.create_cli_token( Name=mwaa_env_name ) conn = http.client.HTTPSConnection(mwaa_cli_token['WebServerHostname']) headers = { 'Authorization': 'Bearer ' + mwaa_cli_token['CliToken'], 'Content-Type': 'text/plain' } event_body = json.dumps(event["body"]) for dag_id in event['dag_ids']: run_api_call(conn, f"dags trigger {dag_id} --conf '{event_body}'", headers) `), handler: "index.lambda_handler", role: lambdaRole, runtime: lambda.Runtime.PYTHON_3_9, memorySize: 256, timeout: cdk.Duration.seconds(60), }); const statusLambda = new lambda.Function(this, "Check Dag Status Lambda", { code: lambda.Code.fromInline(` # Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"). # You may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import boto3 import http.client import base64 import ast from datetime import datetime import json execution_date = datetime.today().strftime('%Y-%m-%d') mwaa_env_name = "${this.mwaaEnvironmentName}" client = boto3.client('mwaa') def run_api_call(conn, payload, headers): print(f"running command: {payload}") conn.request("POST", "/aws_mwaa/cli", payload, headers) res = conn.getresponse() data = res.read() dict_str = data.decode("UTF-8") mydata = ast.literal_eval(dict_str) return base64.b64decode(mydata['stdout']) def lambda_handler(event, context): # get web token mwaa_cli_token = client.create_cli_token( Name=mwaa_env_name ) conn = http.client.HTTPSConnection(mwaa_cli_token['WebServerHostname']) headers = { 'Authorization': 'Bearer ' + mwaa_cli_token['CliToken'], 'Content-Type': 'text/plain' } dag_results = [] for dag_id in event['dag_ids']: results = json.loads(run_api_call(conn, f"dags list-runs -d {dag_id} -o json -s {execution_date}", headers)) for result in results: dag_results.append(result['state']) break if "running" in dag_results: return "running" elif "failed" in dag_results: return "failed" else: return "success" `), handler: "index.lambda_handler", role: lambdaRole, runtime: lambda.Runtime.PYTHON_3_9, memorySize: 256, timeout: cdk.Duration.seconds(60), }); return { triggerLambda, statusLambda, }; } } exports.MWAATriggerDagsStage = MWAATriggerDagsStage; _a = JSII_RTTI_SYMBOL_1; MWAATriggerDagsStage[_a] = { fqn: "aws-ddk-core.MWAATriggerDagsStage", version: "1.4.1" }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibXdhYS10cmlnZ2VyLWRhZ3MuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc3RhZ2VzL213YWEtdHJpZ2dlci1kYWdzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsbUNBQW1DO0FBRW5DLDJDQUEyQztBQUMzQyxpREFBaUQ7QUFDakQscURBQXFEO0FBQ3JELDZEQUE2RDtBQUU3RCw4Q0FBK0U7QUE4Qi9FOztHQUVHO0FBQ0gsTUFBYSxvQkFBcUIsU0FBUSx5QkFBaUI7SUFNekQ7Ozs7O09BS0c7SUFDSCxZQUFZLEtBQWdCLEVBQUUsRUFBVSxFQUFFLEtBQWdDO1FBQ3hFLEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBRXhCLElBQUksQ0FBQyxtQkFBbUIsR0FBRyxLQUFLLENBQUMsbUJBQW1CLENBQUM7UUFDckQsSUFBSSxLQUFLLENBQUMsSUFBSSxJQUFJLEtBQUssQ0FBQyxPQUFPLEVBQUU7WUFDL0IsTUFBTSxTQUFTLENBQUMsdUVBQXVFLENBQUMsQ0FBQztTQUMxRjtRQUNELE1BQU0sTUFBTSxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQztRQUNqRixJQUFJLENBQUMsTUFBTSxFQUFFO1lBQ1gsTUFBTSxTQUFTLENBQUMsaUVBQWlFLENBQUMsQ0FBQztTQUNwRjtRQUNELE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztRQUVwQyxNQUFNLFVBQVUsR0FBRyxJQUFJLEdBQUcsQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLGlCQUFpQixDQUFDLENBQUM7UUFDN0QsTUFBTSxRQUFRLEdBQUcsSUFBSSxHQUFHLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSw2QkFBNkIsRUFBRTtZQUNq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c0JBQXNCO1lBQy9CLElBQUksRUFBRSxVQUFVO1lBQ2hCLE9BQU8sRUFBRSxNQUFNLENBQUMsT0FBTyxDQUFDLFVBQVU7WUFDbEMsVUFBVSxFQUFFLEdBQUc7WUFDZixPQUFPLEVBQUUsR0FBRyxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1NBQ2xDLENBQUMsQ0FBQztRQUVILE1BQU0sWUFBWSxHQUFHLElBQUksTUFBTSxDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQUUseUJBQXlCLEVBQUU7WUFDeEUsSUFBSSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OzttQkF1QmhCLElBQUksQ0FBQyxtQkFBbUI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O1NBc0NsQyxDQUFDO1lBQ0osT0FBTyxFQUFFLHNCQUFzQjtZQUMvQixJQUFJLEVBQUUsVUFBVTtZQUNoQixPQUFPLEVBQUUsTUFBTSxDQUFDLE9BQU8sQ0FBQyxVQUFVO1lBQ2xDLFVBQVUsRUFBRSxHQUFHO1lBQ2YsT0FBTyxFQUFFLEdBQUcsQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztTQUNsQyxDQUFDLENBQUM7UUFFSCxPQUFPO1lBQ0wsYUFBYTtZQUNiLFlBQVk7U0FDYixDQUFDO0lBQ0osQ0FBQzs7QUFqTkgsb0RBa05DIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgY2RrIGZyb20gXCJhd3MtY2RrLWxpYlwiO1xuaW1wb3J0ICogYXMgZXZlbnRzIGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtZXZlbnRzXCI7XG5pbXBvcnQgKiBhcyBpYW0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1pYW1cIjtcbmltcG9ydCAqIGFzIGxhbWJkYSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWxhbWJkYVwiO1xuaW1wb3J0ICogYXMgc2ZuIGZyb20gXCJhd3MtY2RrLWxpYi9hd3Mtc3RlcGZ1bmN0aW9uc1wiO1xuaW1wb3J0ICogYXMgdGFza3MgZnJvbSBcImF3cy1jZGstbGliL2F3cy1zdGVwZnVuY3Rpb25zLXRhc2tzXCI7XG5pbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tIFwiY29uc3RydWN0c1wiO1xuaW1wb3J0IHsgU3RhdGVNYWNoaW5lU3RhZ2UsIFN0YXRlTWFjaGluZVN0YWdlUHJvcHMgfSBmcm9tIFwiLi4vcGlwZWxpbmVzL3N0YWdlXCI7XG5cbi8qKlxuICogUHJvcGVydGllcyBvZiB0aGUgTVdBQSBUcmlnZ2VyIERhZ3Mgc3RhZ2UuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTVdBQVRyaWdnZXJEYWdzU3RhZ2VQcm9wcyBleHRlbmRzIFN0YXRlTWFjaGluZVN0YWdlUHJvcHMge1xuICAvKipcbiAgICogTmFtZSBvZiBhaXJmbG93IGVudmlyb25tZW50LlxuICAgKi9cbiAgcmVhZG9ubHkgbXdhYUVudmlyb25tZW50TmFtZTogc3RyaW5nO1xuICAvKipcbiAgICogTmFtZSBvZiBkYWcocykgdG8gdHJpZ2dlci5cbiAgICovXG4gIHJlYWRvbmx5IGRhZ3M/OiBzdHJpbmdbXTtcbiAgLyoqXG4gICAqIFBhdGggdG8gYXJyYXkgb2YgZGFnIGlkJ3MgdG8gY2hlY2suXG4gICAqL1xuICByZWFkb25seSBkYWdQYXRoPzogc3RyaW5nO1xuICAvKipcbiAgICogVGltZSB0byB3YWl0IGJldHdlZW4gZXhlY3V0aW9uIHN0YXR1cyBjaGVja3MuXG4gICAqIEBkZWZhdWx0IGF3c19jZGsuRHVyYXRpb24uc2Vjb25kcygxNSlcbiAgICovXG4gIHJlYWRvbmx5IHN0YXR1c0NoZWNrUGVyaW9kPzogY2RrLkR1cmF0aW9uO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIE1XQUFMYW1iZGFzUmVzdWx0IHtcbiAgcmVhZG9ubHkgdHJpZ2dlckxhbWJkYTogbGFtYmRhLkZ1bmN0aW9uO1xuICByZWFkb25seSBzdGF0dXNMYW1iZGE6IGxhbWJkYS5GdW5jdGlvbjtcbn1cblxuLyoqXG4gKiBTdGFnZSB0aGF0IGNvbnRhaW5zIGEgc3RlcCBmdW5jdGlvbiB0aGF0IHJ1bnMgYSBNYW5hZ2VkIEFwYWNoZSBBaXJmbG93IChNV0FBKSBkYWcgb3Igc2V0IG9mIGRhZ3MgLlxuICovXG5leHBvcnQgY2xhc3MgTVdBQVRyaWdnZXJEYWdzU3RhZ2UgZXh0ZW5kcyBTdGF0ZU1hY2hpbmVTdGFnZSB7XG4gIHJlYWRvbmx5IHRhcmdldHM/OiBldmVudHMuSVJ1bGVUYXJnZXRbXTtcbiAgcmVhZG9ubHkgZXZlbnRQYXR0ZXJuPzogZXZlbnRzLkV2ZW50UGF0dGVybjtcbiAgcmVhZG9ubHkgc3RhdGVNYWNoaW5lOiBzZm4uU3RhdGVNYWNoaW5lO1xuICByZWFkb25seSBtd2FhRW52aXJvbm1lbnROYW1lOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIENvbnN0cnVjdHMgTVdBQVRyaWdnZXJEYWdzU3RhZ2UuXG4gICAqIEBwYXJhbSBzY29wZSBTY29wZSB3aXRoaW4gd2hpY2ggdGhpcyBjb25zdHJ1Y3QgaXMgZGVmaW5lZC5cbiAgICogQHBhcmFtIGlkIElkZW50aWZpZXIgb2YgdGhlIHN0YWdlLlxuICAgKiBAcGFyYW0gcHJvcHMgUHJvcGVydGllcyBmb3IgdGhlIHN0YWdlLlxuICAgKi9cbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM6IE1XQUFUcmlnZ2VyRGFnc1N0YWdlUHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQsIHByb3BzKTtcblxuICAgIHRoaXMubXdhYUVudmlyb25tZW50TmFtZSA9IHByb3BzLm13YWFFbnZpcm9ubWVudE5hbWU7XG4gICAgaWYgKHByb3BzLmRhZ3MgJiYgcHJvcHMuZGFnUGF0aCkge1xuICAgICAgdGhyb3cgVHlwZUVycm9yKFwiRm9yIHRoaXMgc3RhZ2UgcHJvdmlkZSBvbmUgb2YgJ2RhZ3MnIG9yICdkYWdQYXRoJyBwYXJhbWV0ZXIsIG5vdCBib3RoXCIpO1xuICAgIH1cbiAgICBjb25zdCBkYWdJZHMgPSBwcm9wcy5kYWdQYXRoID8gc2ZuLkpzb25QYXRoLnN0cmluZ0F0KHByb3BzLmRhZ1BhdGgpIDogcHJvcHMuZGFncztcbiAgICBpZiAoIWRhZ0lkcykge1xuICAgICAgdGhyb3cgVHlwZUVycm9yKFwiRm9yIHRoaXMgc3RhZ2Ugb25lIG9mICdkYWdzJyBvciAnZGFnUGF0aCcgcGFyYW1ldGVyIGlzIHJlcXVpcmVkXCIpO1xuICAgIH1cbiAgICBjb25zdCBsYW1iZGFzID0gdGhpcy5idWlsZExhbWJkYXMoKTtcblxuICAgIGNvbnN0IGRlZmluaXRpb24gPSBuZXcgc2ZuLlBhcmFsbGVsKHRoaXMsIFwiUGFyYWxsZWwgU3RhdGVzXCIpO1xuICAgIGNvbnN0IHdhaXRUYXNrID0gbmV3IHNmbi5XYWl0KHRoaXMsIFwiV2FpdCBCZWZvcmUgQ2hlY2tpbmcgU3RhdHVzXCIsIHtcbiAgICAgIHRpbWU6IHNmbi5XYWl0VGltZS5kdXJhdGlvbihwcm9wcy5zdGF0dXNDaGVja1BlcmlvZCA/PyBjZGsuRHVyYXRpb24uc2Vjb25kcygxNSkpLFxuICAgIH0pO1xuICAgIGRlZmluaXRpb24uYnJhbmNoKFxuICAgICAgbmV3IHRhc2tzLkxhbWJkYUludm9rZSh0aGlzLCBcIlRyaWdnZXIgRGFnXCIsIHtcbiAgICAgICAgbGFtYmRhRnVuY3Rpb246IGxhbWJkYXMudHJpZ2dlckxhbWJkYSxcbiAgICAgICAgcGF5bG9hZDogc2ZuLlRhc2tJbnB1dC5mcm9tT2JqZWN0KHsgZGFnX2lkczogZGFnSWRzLCBib2R5OiBzZm4uSnNvblBhdGgub2JqZWN0QXQoXCIkXCIpIH0pLFxuICAgICAgICByZXN1bHRQYXRoOiBzZm4uSnNvblBhdGguRElTQ0FSRCxcbiAgICAgIH0pXG4gICAgICAgIC5uZXh0KHdhaXRUYXNrKVxuICAgICAgICAubmV4dChcbiAgICAgICAgICBuZXcgdGFza3MuTGFtYmRhSW52b2tlKHRoaXMsIFwiR2V0IERhZyBFeGVjdXRpb24gU3RhdHVzXCIsIHtcbiAgICAgICAgICAgIGxhbWJkYUZ1bmN0aW9uOiBsYW1iZGFzLnN0YXR1c0xhbWJkYSxcbiAgICAgICAgICAgIHBheWxvYWQ6IHNmbi5UYXNrSW5wdXQuZnJvbU9iamVjdCh7IGRhZ19pZHM6IGRhZ0lkcyB9KSxcbiAgICAgICAgICAgIHJlc3VsdFBhdGg6IFwiJC5yZXN1bHRcIixcbiAgICAgICAgICB9KS5uZXh0KFxuICAgICAgICAgICAgbmV3IHNmbi5DaG9pY2UodGhpcywgYENoZWNrIEV4ZWN1dGlvbiBTdGF0dXNgKVxuICAgICAgICAgICAgICAud2hlbihzZm4uQ29uZGl0aW9uLnN0cmluZ0VxdWFscyhcIiQucmVzdWx0LlBheWxvYWRcIiwgXCJzdWNjZXNzXCIpLCBuZXcgc2ZuLlN1Y2NlZWQodGhpcywgXCJTdWNjZXNzXCIpKVxuICAgICAgICAgICAgICAud2hlbihcbiAgICAgICAgICAgICAgICBzZm4uQ29uZGl0aW9uLnN0cmluZ0VxdWFscyhcIiQucmVzdWx0LlBheWxvYWRcIiwgXCJmYWlsZWRcIiksXG4gICAgICAgICAgICAgICAgbmV3IHNmbi5GYWlsKHRoaXMsIFwiRmFpbHVyZVwiLCB7IGVycm9yOiBcIkRhZ0V4ZWN1dGlvbkZhaWxlZFwiIH0pLFxuICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgIC5vdGhlcndpc2Uod2FpdFRhc2spLFxuICAgICAgICAgICksXG4gICAgICAgICksXG4gICAgKTtcblxuICAgICh7XG4gICAgICBldmVudFBhdHRlcm46IHRoaXMuZXZlbnRQYXR0ZXJuLFxuICAgICAgdGFyZ2V0czogdGhpcy50YXJnZXRzLFxuICAgICAgc3RhdGVNYWNoaW5lOiB0aGlzLnN0YXRlTWFjaGluZSxcbiAgICB9ID0gdGhpcy5jcmVhdGVTdGF0ZU1hY2hpbmUoeyBkZWZpbml0aW9uOiBkZWZpbml0aW9uLCAuLi5wcm9wcyB9KSk7XG4gIH1cblxuICBwcml2YXRlIGJ1aWxkTGFtYmRhcygpOiBNV0FBTGFtYmRhc1Jlc3VsdCB7XG4gICAgY29uc3QgbGFtYmRhUm9sZSA9IG5ldyBpYW0uUm9sZSh0aGlzLCBgTVdBQSBTdGFnZSBMYW1iZGEgUm9sZWAsIHtcbiAgICAgIGFzc3VtZWRCeTogbmV3IGlhbS5TZXJ2aWNlUHJpbmNpcGFsKFwibGFtYmRhLmFtYXpvbmF3cy5jb21cIiksXG4gICAgICBkZXNjcmlwdGlvbjogXCJsYW1iZGEgcm9sZSB0byB0cmlnZ2VyIGFpcmZsb3cgZGFnIGV4ZWN1dGlvblwiLFxuICAgIH0pO1xuXG4gICAgLy8gRW5hYmxlIHRoZSBmdW5jdGlvbnMgdG8gZ2V0IGZsb3cgZXhlY3V0aW9uIHJlY29yZHNcbiAgICBsYW1iZGFSb2xlLmFkZFRvUG9saWN5KFxuICAgICAgbmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICBlZmZlY3Q6IGlhbS5FZmZlY3QuQUxMT1csXG4gICAgICAgIGFjdGlvbnM6IFtcImFpcmZsb3c6Q3JlYXRlQ2xpVG9rZW5cIl0sXG4gICAgICAgIHJlc291cmNlczogW1wiKlwiXSxcbiAgICAgIH0pLFxuICAgICk7XG5cbiAgICBjb25zdCB0cmlnZ2VyTGFtYmRhID0gbmV3IGxhbWJkYS5GdW5jdGlvbih0aGlzLCBcIlRyaWdnZXIgRGFnIExhbWJkYVwiLCB7XG4gICAgICBjb2RlOiBsYW1iZGEuQ29kZS5mcm9tSW5saW5lKGBcbiMgQ29weXJpZ2h0IDIwMjMgQW1hem9uLmNvbSwgSW5jLiBvciBpdHMgYWZmaWxpYXRlcy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiNcbiMgTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKS5cbiMgWW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLlxuIyBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbiNcbiMgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuI1xuIyBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlXG4jIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiMgV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG4jIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmRcbiMgbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG5cbmltcG9ydCBib3RvM1xuaW1wb3J0IGh0dHAuY2xpZW50XG5pbXBvcnQgYmFzZTY0XG5pbXBvcnQgYXN0XG5mcm9tIGRhdGV0aW1lIGltcG9ydCBkYXRldGltZSBcbmltcG9ydCBqc29uXG5cbmV4ZWN1dGlvbl9kYXRlID0gZGF0ZXRpbWUudG9kYXkoKS5zdHJmdGltZSgnJVktJW0tJWQnKVxubXdhYV9lbnZfbmFtZSA9IFwiJHt0aGlzLm13YWFFbnZpcm9ubWVudE5hbWV9XCJcblxuY2xpZW50ID0gYm90bzMuY2xpZW50KCdtd2FhJylcblxuZGVmIHJ1bl9hcGlfY2FsbChjb25uLCBwYXlsb2FkLCBoZWFkZXJzKTpcbiAgICBwcmludChmXCJydW5uaW5nIGNvbW1hbmQ6IHtwYXlsb2FkfVwiKVxuICAgIGNvbm4ucmVxdWVzdChcIlBPU1RcIiwgXCIvYXdzX213YWEvY2xpXCIsIHBheWxvYWQsIGhlYWRlcnMpXG4gICAgcmVzID0gY29ubi5nZXRyZXNwb25zZSgpXG4gICAgZGF0YSA9IHJlcy5yZWFkKClcbiAgICBkaWN0X3N0ciA9IGRhdGEuZGVjb2RlKFwiVVRGLThcIilcbiAgICBteWRhdGEgPSBhc3QubGl0ZXJhbF9ldmFsKGRpY3Rfc3RyKVxuICAgIHJldHVybiBiYXNlNjQuYjY0ZGVjb2RlKG15ZGF0YVsnc3Rkb3V0J10pXG4gICAgXG5kZWYgbGFtYmRhX2hhbmRsZXIoZXZlbnQsIGNvbnRleHQpOlxuICAgICMgZ2V0IHdlYiB0b2tlblxuICAgIG13YWFfY2xpX3Rva2VuID0gY2xpZW50LmNyZWF0ZV9jbGlfdG9rZW4oXG4gICAgICAgIE5hbWU9bXdhYV9lbnZfbmFtZVxuICAgIClcbiAgICBcbiAgICBjb25uID0gaHR0cC5jbGllbnQuSFRUUFNDb25uZWN0aW9uKG13YWFfY2xpX3Rva2VuWydXZWJTZXJ2ZXJIb3N0bmFtZSddKVxuICAgIGhlYWRlcnMgPSB7XG4gICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIG13YWFfY2xpX3Rva2VuWydDbGlUb2tlbiddLFxuICAgICAgJ0NvbnRlbnQtVHlwZSc6ICd0ZXh0L3BsYWluJ1xuICAgIH1cblxuICAgIGV2ZW50X2JvZHkgPSBqc29uLmR1bXBzKGV2ZW50W1wiYm9keVwiXSlcbiAgICBmb3IgZGFnX2lkIGluIGV2ZW50WydkYWdfaWRzJ106XG4gICAgICBydW5fYXBpX2NhbGwoY29ubiwgZlwiZGFncyB0cmlnZ2VyIHtkYWdfaWR9IC0tY29uZiAne2V2ZW50X2JvZHl9J1wiLCBoZWFkZXJzKVxuICAgICAgICBgKSxcbiAgICAgIGhhbmRsZXI6IFwiaW5kZXgubGFtYmRhX2hhbmRsZXJcIixcbiAgICAgIHJvbGU6IGxhbWJkYVJvbGUsXG4gICAgICBydW50aW1lOiBsYW1iZGEuUnVudGltZS5QWVRIT05fM185LFxuICAgICAgbWVtb3J5U2l6ZTogMjU2LFxuICAgICAgdGltZW91dDogY2RrLkR1cmF0aW9uLnNlY29uZHMoNjApLFxuICAgIH0pO1xuXG4gICAgY29uc3Qgc3RhdHVzTGFtYmRhID0gbmV3IGxhbWJkYS5GdW5jdGlvbih0aGlzLCBcIkNoZWNrIERhZyBTdGF0dXMgTGFtYmRhXCIsIHtcbiAgICAgIGNvZGU6IGxhbWJkYS5Db2RlLmZyb21JbmxpbmUoYFxuIyBDb3B5cmlnaHQgMjAyMyBBbWF6b24uY29tLCBJbmMuIG9yIGl0cyBhZmZpbGlhdGVzLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuI1xuIyBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpLlxuIyBZb3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4jIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuI1xuIyAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4jXG4jIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiMgZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuIyBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC5cbiMgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuIyBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cblxuaW1wb3J0IGJvdG8zXG5pbXBvcnQgaHR0cC5jbGllbnRcbmltcG9ydCBiYXNlNjRcbmltcG9ydCBhc3RcbmZyb20gZGF0ZXRpbWUgaW1wb3J0IGRhdGV0aW1lIFxuaW1wb3J0IGpzb25cblxuZXhlY3V0aW9uX2RhdGUgPSBkYXRldGltZS50b2RheSgpLnN0cmZ0aW1lKCclWS0lbS0lZCcpXG5td2FhX2Vudl9uYW1lID0gXCIke3RoaXMubXdhYUVudmlyb25tZW50TmFtZX1cIlxuXG5jbGllbnQgPSBib3RvMy5jbGllbnQoJ213YWEnKVxuXG5kZWYgcnVuX2FwaV9jYWxsKGNvbm4sIHBheWxvYWQsIGhlYWRlcnMpOlxuICAgIHByaW50KGZcInJ1bm5pbmcgY29tbWFuZDoge3BheWxvYWR9XCIpXG4gICAgY29ubi5yZXF1ZXN0KFwiUE9TVFwiLCBcIi9hd3NfbXdhYS9jbGlcIiwgcGF5bG9hZCwgaGVhZGVycylcbiAgICByZXMgPSBjb25uLmdldHJlc3BvbnNlKClcbiAgICBkYXRhID0gcmVzLnJlYWQoKVxuICAgIGRpY3Rfc3RyID0gZGF0YS5kZWNvZGUoXCJVVEYtOFwiKVxuICAgIG15ZGF0YSA9IGFzdC5saXRlcmFsX2V2YWwoZGljdF9zdHIpXG4gICAgcmV0dXJuIGJhc2U2NC5iNjRkZWNvZGUobXlkYXRhWydzdGRvdXQnXSlcbiAgICBcbmRlZiBsYW1iZGFfaGFuZGxlcihldmVudCwgY29udGV4dCk6XG4gICAgIyBnZXQgd2ViIHRva2VuXG4gICAgbXdhYV9jbGlfdG9rZW4gPSBjbGllbnQuY3JlYXRlX2NsaV90b2tlbihcbiAgICAgICAgTmFtZT1td2FhX2Vudl9uYW1lXG4gICAgKVxuICBcbiAgICBjb25uID0gaHR0cC5jbGllbnQuSFRUUFNDb25uZWN0aW9uKG13YWFfY2xpX3Rva2VuWydXZWJTZXJ2ZXJIb3N0bmFtZSddKVxuICAgIGhlYWRlcnMgPSB7XG4gICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIG13YWFfY2xpX3Rva2VuWydDbGlUb2tlbiddLFxuICAgICAgJ0NvbnRlbnQtVHlwZSc6ICd0ZXh0L3BsYWluJ1xuICAgIH1cblxuICAgIGRhZ19yZXN1bHRzID0gW11cbiAgICBmb3IgZGFnX2lkIGluIGV2ZW50WydkYWdfaWRzJ106XG4gICAgICByZXN1bHRzID0ganNvbi5sb2FkcyhydW5fYXBpX2NhbGwoY29ubiwgZlwiZGFncyBsaXN0LXJ1bnMgLWQge2RhZ19pZH0gLW8ganNvbiAtcyB7ZXhlY3V0aW9uX2RhdGV9XCIsIGhlYWRlcnMpKVxuICAgICAgZm9yIHJlc3VsdCBpbiByZXN1bHRzOlxuICAgICAgICAgIGRhZ19yZXN1bHRzLmFwcGVuZChyZXN1bHRbJ3N0YXRlJ10pXG4gICAgICAgICAgYnJlYWtcbiAgICBcbiAgICBpZiBcInJ1bm5pbmdcIiBpbiBkYWdfcmVzdWx0czpcbiAgICAgICAgcmV0dXJuIFwicnVubmluZ1wiXG4gICAgZWxpZiBcImZhaWxlZFwiIGluIGRhZ19yZXN1bHRzOlxuICAgICAgICByZXR1cm4gXCJmYWlsZWRcIlxuICAgIGVsc2U6XG4gICAgICAgIHJldHVybiBcInN1Y2Nlc3NcIlxuICAgICAgICBgKSxcbiAgICAgIGhhbmRsZXI6IFwiaW5kZXgubGFtYmRhX2hhbmRsZXJcIixcbiAgICAgIHJvbGU6IGxhbWJkYVJvbGUsXG4gICAgICBydW50aW1lOiBsYW1iZGEuUnVudGltZS5QWVRIT05fM185LFxuICAgICAgbWVtb3J5U2l6ZTogMjU2LFxuICAgICAgdGltZW91dDogY2RrLkR1cmF0aW9uLnNlY29uZHMoNjApLFxuICAgIH0pO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIHRyaWdnZXJMYW1iZGEsXG4gICAgICBzdGF0dXNMYW1iZGEsXG4gICAgfTtcbiAgfVxufVxuIl19