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
JavaScript
"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