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.
181 lines (172 loc) • 25.1 kB
JavaScript
"use strict";
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.AppFlowIngestionStage = void 0;
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
const cdk = require("aws-cdk-lib");
const aws_cdk_lib_1 = require("aws-cdk-lib");
const appflow = require("aws-cdk-lib/aws-appflow");
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 an AppFlow flow ingestion.
* If the AppFlow flow name is not supplied, then the flow is created.
*/
class AppFlowIngestionStage extends stage_1.StateMachineStage {
/**
* Constructs AppFlowIngestionStage.
* @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);
const { flowName, flowExecutionStatusCheckPeriod, destinationFlowConfig, sourceFlowConfig, flowTasks } = props;
const flowExecutionRecords = this.createCheckFlowExecutionTask();
const flowObjectExecutionStatus = new sfn.Choice(this, "Check Flow Execution Status");
const flowObjectExecutionStatusWait = new sfn.Wait(this, "Wait Before Checking Flow Status", {
time: sfn.WaitTime.duration(flowExecutionStatusCheckPeriod ?? aws_cdk_lib_1.Duration.seconds(15)),
});
if (!flowName) {
// Check required props for CfnFlow create and except if not provided
if (!destinationFlowConfig || !sourceFlowConfig || !flowTasks) {
throw new Error("if 'flowName' is not specified, 'destinationFlowConfig', 'sourceFlowConfig' & 'tasks' are required properties");
}
const flow = new appflow.CfnFlow(this, "Flow", {
destinationFlowConfigList: [destinationFlowConfig],
flowName: `${id}-flow`,
sourceFlowConfig: sourceFlowConfig,
tasks: flowTasks,
triggerConfig: {
triggerType: "OnDemand",
},
});
this.flowName = flow.flowName;
}
else {
this.flowName = flowName;
}
this.flowObject = this.createStartFlowCustomTask(this.flowName, flowObjectExecutionStatusWait);
const definition = this.flowObject
.next(flowObjectExecutionStatusWait)
.next(flowExecutionRecords)
.next(flowObjectExecutionStatus
.when(sfn.Condition.stringEquals("$.FlowExecutionStatus", "Successful"), new sfn.Succeed(this, "success"))
.when(sfn.Condition.stringEquals("$.FlowExecutionStatus", "Error"), new sfn.Fail(this, "failure", {
error: "WorkflowFailure",
cause: "AppFlow failure",
}))
.otherwise(flowObjectExecutionStatusWait));
({
eventPattern: this.eventPattern,
targets: this.targets,
stateMachine: this.stateMachine,
} = this.createStateMachine({ definition: definition, ...props }));
this.stateMachine.addToRolePolicy(new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: ["appflow:StartFlow"],
resources: ["*"],
}));
}
createStartFlowCustomTask(flowName, waitHandler) {
const stack = cdk.Stack.of(this);
const task = new tasks.CallAwsService(this, "Start Flow Execution", {
service: "appflow",
action: "startFlow",
iamResources: [`arn:${stack.partition}:appflow:${stack.region}:${stack.account}:flow/${flowName}`],
parameters: {
FlowName: flowName,
},
});
if (waitHandler) {
task.addCatch(waitHandler, {
errors: ["Appflow.ConflictException"],
});
}
return task;
}
createCheckFlowExecutionTask() {
const statusLambdaRole = new iam.Role(this, "Flow Execution Status Lambda Role", {
assumedBy: new iam.ServicePrincipal("lambda.amazonaws.com"),
description: "lambda role to check appflow flow execution status",
});
const statusLambda = new lambda.Function(this, "Flow Execution Status Lambda", {
code: lambda.Code.fromInline(`
# Copyright 2022 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 json
import logging
from typing import Any, Dict, Optional
import boto3
logger = logging.getLogger()
logger.setLevel(logging.INFO)
appflow = boto3.client("appflow")
def lambda_handler(event: Dict[str, Any], context: Optional[Dict[str, Any]]) -> str:
# Log the received event
logger.info("Received event: " + json.dumps(event, indent=2))
# Get appflow flow name from the event
flow_name = event["FlowArn"].rsplit("/")[-1]
# Get appflow flow execution id from the event
execution_id = event["ExecutionId"]
params = {"flowName": flow_name, "maxResults": 10}
flow_execution_status = ""
try:
# unfortunately the appflow client does not have any paginator
while True:
response = appflow.describe_flow_execution_records(**params) # type: ignore
logger.info(response)
execution_record = [
execution for execution in response["flowExecutions"] if execution["executionId"] == execution_id
]
if execution_record:
flow_execution_status = execution_record[0]["executionStatus"]
break
if "nextToken" in response:
params["nextToken"] = response["nextToken"]
else:
break
logger.info(f"Status: {flow_execution_status}")
return flow_execution_status
except Exception as e:
logger.info(e)
message = "Error getting AppFlow flow status"
logger.info(message)
raise Exception(message)
`),
handler: "lambda_function.lambda_handler",
role: statusLambdaRole,
runtime: lambda.Runtime.PYTHON_3_9,
memorySize: 256,
timeout: cdk.Duration.seconds(120),
});
// Enable the function to get flow execution records
statusLambda.addToRolePolicy(new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: ["appflow:DescribeFlowExecutionRecords"],
resources: ["*"],
}));
// Create check flow execution status step function task
return new tasks.LambdaInvoke(this, "Get Flow Execution Status", {
lambdaFunction: statusLambda,
resultSelector: { "FlowExecutionStatus.$": "$.Payload" },
});
}
}
exports.AppFlowIngestionStage = AppFlowIngestionStage;
_a = JSII_RTTI_SYMBOL_1;
AppFlowIngestionStage[_a] = { fqn: "aws-ddk-core.AppFlowIngestionStage", version: "1.4.1" };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBwZmxvdy1pbmdlc3Rpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc3RhZ2VzL2FwcGZsb3ctaW5nZXN0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsbUNBQW1DO0FBQ25DLDZDQUF1QztBQUN2QyxtREFBbUQ7QUFFbkQsMkNBQTJDO0FBQzNDLGlEQUFpRDtBQUNqRCxxREFBcUQ7QUFDckQsNkRBQTZEO0FBRTdELDhDQUErRTtBQTZCL0U7OztHQUdHO0FBQ0gsTUFBYSxxQkFBc0IsU0FBUSx5QkFBaUI7SUFPMUQ7Ozs7O09BS0c7SUFDSCxZQUFZLEtBQWdCLEVBQUUsRUFBVSxFQUFFLEtBQWlDO1FBQ3pFLEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBRXhCLE1BQU0sRUFBRSxRQUFRLEVBQUUsOEJBQThCLEVBQUUscUJBQXFCLEVBQUUsZ0JBQWdCLEVBQUUsU0FBUyxFQUFFLEdBQUcsS0FBSyxDQUFDO1FBQy9HLE1BQU0sb0JBQW9CLEdBQUcsSUFBSSxDQUFDLDRCQUE0QixFQUFFLENBQUM7UUFDakUsTUFBTSx5QkFBeUIsR0FBRyxJQUFJLEdBQUcsQ0FBQyxNQUFNLENBQUMsSUFBSSxFQUFFLDZCQUE2QixDQUFDLENBQUM7UUFDdEYsTUFBTSw2QkFBNkIsR0FBRyxJQUFJLEdBQUcsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLGtDQUFrQyxFQUFFO1lBQzNGLElBQUksRUFBRSxHQUFHLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyw4QkFBOEIsSUFBSSxzQkFBUSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsQ0FBQztTQUNwRixDQUFDLENBQUM7UUFFSCxJQUFJLENBQUMsUUFBUSxFQUFFO1lBQ2IscUVBQXFFO1lBQ3JFLElBQUksQ0FBQyxxQkFBcUIsSUFBSSxDQUFDLGdCQUFnQixJQUFJLENBQUMsU0FBUyxFQUFFO2dCQUM3RCxNQUFNLElBQUksS0FBSyxD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REF5TEMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBjZGsgZnJvbSBcImF3cy1jZGstbGliXCI7XG5pbXBvcnQgeyBEdXJhdGlvbiB9IGZyb20gXCJhd3MtY2RrLWxpYlwiO1xuaW1wb3J0ICogYXMgYXBwZmxvdyBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWFwcGZsb3dcIjtcbmltcG9ydCAqIGFzIGV2ZW50cyBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWV2ZW50c1wiO1xuaW1wb3J0ICogYXMgaWFtIGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtaWFtXCI7XG5pbXBvcnQgKiBhcyBsYW1iZGEgZnJvbSBcImF3cy1jZGstbGliL2F3cy1sYW1iZGFcIjtcbmltcG9ydCAqIGFzIHNmbiBmcm9tIFwiYXdzLWNkay1saWIvYXdzLXN0ZXBmdW5jdGlvbnNcIjtcbmltcG9ydCAqIGFzIHRhc2tzIGZyb20gXCJhd3MtY2RrLWxpYi9hd3Mtc3RlcGZ1bmN0aW9ucy10YXNrc1wiO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSBcImNvbnN0cnVjdHNcIjtcbmltcG9ydCB7IFN0YXRlTWFjaGluZVN0YWdlLCBTdGF0ZU1hY2hpbmVTdGFnZVByb3BzIH0gZnJvbSBcIi4uL3BpcGVsaW5lcy9zdGFnZVwiO1xuXG4vKipcbiAqIFByb3BlcnRpZXMgb2YgdGhlIEFwcEZsb3cgSW5nZXN0aW9uIHN0YWdlLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEFwcEZsb3dJbmdlc3Rpb25TdGFnZVByb3BzIGV4dGVuZHMgU3RhdGVNYWNoaW5lU3RhZ2VQcm9wcyB7XG4gIC8qKlxuICAgKiBOYW1lIG9mIHRoZSBBcHBGbG93IGZsb3cgdG8gcnVuLiBJZiBOb25lLCBhbiBBcHBGbG93IGZsb3cgaXMgY3JlYXRlZC5cbiAgICovXG4gIHJlYWRvbmx5IGZsb3dOYW1lPzogc3RyaW5nO1xuICAvKipcbiAgICogVGltZSB0byB3YWl0IGJldHdlZW4gZmxvdyBleGVjdXRpb24gc3RhdHVzIGNoZWNrcy5cbiAgICogQGRlZmF1bHQgYXdzX2Nkay5EdXJhdGlvbi5zZWNvbmRzKDE1KVxuICAgKi9cbiAgcmVhZG9ubHkgZmxvd0V4ZWN1dGlvblN0YXR1c0NoZWNrUGVyaW9kPzogRHVyYXRpb247XG4gIC8qKlxuICAgKiBUaGUgZmxvdyBgYXBwZmxvdy5DZm5GbG93LkRlc3RpbmF0aW9uRmxvd0NvbmZpZ1Byb3BlcnR5YCBwcm9wZXJ0aWVzLlxuICAgKi9cbiAgcmVhZG9ubHkgZGVzdGluYXRpb25GbG93Q29uZmlnPzogYXBwZmxvdy5DZm5GbG93LkRlc3RpbmF0aW9uRmxvd0NvbmZpZ1Byb3BlcnR5O1xuICAvKipcbiAgICogVGhlIGZsb3cgYGFwcGZsb3cuQ2ZuRmxvdy5Tb3VyY2VGbG93Q29uZmlnUHJvcGVydHlgIHByb3BlcnRpZXMuXG4gICAqL1xuICByZWFkb25seSBzb3VyY2VGbG93Q29uZmlnPzogYXBwZmxvdy5DZm5GbG93LlNvdXJjZUZsb3dDb25maWdQcm9wZXJ0eTtcbiAgLyoqXG4gICAqIFRoZSBmbG93IHRhc2tzIHByb3BlcnRpZXMuXG4gICAqL1xuICByZWFkb25seSBmbG93VGFza3M/OiBhcHBmbG93LkNmbkZsb3cuVGFza1Byb3BlcnR5W107XG59XG5cbi8qKlxuICogU3RhZ2UgdGhhdCBjb250YWlucyBhIHN0ZXAgZnVuY3Rpb24gdGhhdCBydW5zIGFuIEFwcEZsb3cgZmxvdyBpbmdlc3Rpb24uXG4gKiBJZiB0aGUgQXBwRmxvdyBmbG93IG5hbWUgaXMgbm90IHN1cHBsaWVkLCB0aGVuIHRoZSBmbG93IGlzIGNyZWF0ZWQuXG4gKi9cbmV4cG9ydCBjbGFzcyBBcHBGbG93SW5nZXN0aW9uU3RhZ2UgZXh0ZW5kcyBTdGF0ZU1hY2hpbmVTdGFnZSB7XG4gIHJlYWRvbmx5IHRhcmdldHM/OiBldmVudHMuSVJ1bGVUYXJnZXRbXTtcbiAgcmVhZG9ubHkgZXZlbnRQYXR0ZXJuPzogZXZlbnRzLkV2ZW50UGF0dGVybjtcbiAgcmVhZG9ubHkgc3RhdGVNYWNoaW5lOiBzZm4uU3RhdGVNYWNoaW5lO1xuICByZWFkb25seSBmbG93T2JqZWN0OiB0YXNrcy5DYWxsQXdzU2VydmljZTtcbiAgcmVhZG9ubHkgZmxvd05hbWU6IHN0cmluZztcblxuICAvKipcbiAgICogQ29uc3RydWN0cyBBcHBGbG93SW5nZXN0aW9uU3RhZ2UuXG4gICAqIEBwYXJhbSBzY29wZSBTY29wZSB3aXRoaW4gd2hpY2ggdGhpcyBjb25zdHJ1Y3QgaXMgZGVmaW5lZC5cbiAgICogQHBhcmFtIGlkIElkZW50aWZpZXIgb2YgdGhlIHN0YWdlLlxuICAgKiBAcGFyYW0gcHJvcHMgUHJvcGVydGllcyBmb3IgdGhlIHN0YWdlLlxuICAgKi9cbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM6IEFwcEZsb3dJbmdlc3Rpb25TdGFnZVByb3BzKSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkLCBwcm9wcyk7XG5cbiAgICBjb25zdCB7IGZsb3dOYW1lLCBmbG93RXhlY3V0aW9uU3RhdHVzQ2hlY2tQZXJpb2QsIGRlc3RpbmF0aW9uRmxvd0NvbmZpZywgc291cmNlRmxvd0NvbmZpZywgZmxvd1Rhc2tzIH0gPSBwcm9wcztcbiAgICBjb25zdCBmbG93RXhlY3V0aW9uUmVjb3JkcyA9IHRoaXMuY3JlYXRlQ2hlY2tGbG93RXhlY3V0aW9uVGFzaygpO1xuICAgIGNvbnN0IGZsb3dPYmplY3RFeGVjdXRpb25TdGF0dXMgPSBuZXcgc2ZuLkNob2ljZSh0aGlzLCBcIkNoZWNrIEZsb3cgRXhlY3V0aW9uIFN0YXR1c1wiKTtcbiAgICBjb25zdCBmbG93T2JqZWN0RXhlY3V0aW9uU3RhdHVzV2FpdCA9IG5ldyBzZm4uV2FpdCh0aGlzLCBcIldhaXQgQmVmb3JlIENoZWNraW5nIEZsb3cgU3RhdHVzXCIsIHtcbiAgICAgIHRpbWU6IHNmbi5XYWl0VGltZS5kdXJhdGlvbihmbG93RXhlY3V0aW9uU3RhdHVzQ2hlY2tQZXJpb2QgPz8gRHVyYXRpb24uc2Vjb25kcygxNSkpLFxuICAgIH0pO1xuXG4gICAgaWYgKCFmbG93TmFtZSkge1xuICAgICAgLy8gQ2hlY2sgcmVxdWlyZWQgcHJvcHMgZm9yIENmbkZsb3cgY3JlYXRlIGFuZCBleGNlcHQgaWYgbm90IHByb3ZpZGVkXG4gICAgICBpZiAoIWRlc3RpbmF0aW9uRmxvd0NvbmZpZyB8fCAhc291cmNlRmxvd0NvbmZpZyB8fCAhZmxvd1Rhc2tzKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICBcImlmICdmbG93TmFtZScgaXMgbm90IHNwZWNpZmllZCwgJ2Rlc3RpbmF0aW9uRmxvd0NvbmZpZycsICdzb3VyY2VGbG93Q29uZmlnJyAmICd0YXNrcycgYXJlIHJlcXVpcmVkIHByb3BlcnRpZXNcIixcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGZsb3cgPSBuZXcgYXBwZmxvdy5DZm5GbG93KHRoaXMsIFwiRmxvd1wiLCB7XG4gICAgICAgIGRlc3RpbmF0aW9uRmxvd0NvbmZpZ0xpc3Q6IFtkZXN0aW5hdGlvbkZsb3dDb25maWddLFxuICAgICAgICBmbG93TmFtZTogYCR7aWR9LWZsb3dgLFxuICAgICAgICBzb3VyY2VGbG93Q29uZmlnOiBzb3VyY2VGbG93Q29uZmlnLFxuICAgICAgICB0YXNrczogZmxvd1Rhc2tzLFxuICAgICAgICB0cmlnZ2VyQ29uZmlnOiB7XG4gICAgICAgICAgdHJpZ2dlclR5cGU6IFwiT25EZW1hbmRcIixcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuICAgICAgdGhpcy5mbG93TmFtZSA9IGZsb3cuZmxvd05hbWU7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuZmxvd05hbWUgPSBmbG93TmFtZTtcbiAgICB9XG4gICAgdGhpcy5mbG93T2JqZWN0ID0gdGhpcy5jcmVhdGVTdGFydEZsb3dDdXN0b21UYXNrKHRoaXMuZmxvd05hbWUsIGZsb3dPYmplY3RFeGVjdXRpb25TdGF0dXNXYWl0KTtcblxuICAgIGNvbnN0IGRlZmluaXRpb24gPSB0aGlzLmZsb3dPYmplY3RcbiAgICAgIC5uZXh0KGZsb3dPYmplY3RFeGVjdXRpb25TdGF0dXNXYWl0KVxuICAgICAgLm5leHQoZmxvd0V4ZWN1dGlvblJlY29yZHMpXG4gICAgICAubmV4dChcbiAgICAgICAgZmxvd09iamVjdEV4ZWN1dGlvblN0YXR1c1xuICAgICAgICAgIC53aGVuKHNmbi5Db25kaXRpb24uc3RyaW5nRXF1YWxzKFwiJC5GbG93RXhlY3V0aW9uU3RhdHVzXCIsIFwiU3VjY2Vzc2Z1bFwiKSwgbmV3IHNmbi5TdWNjZWVkKHRoaXMsIFwic3VjY2Vzc1wiKSlcbiAgICAgICAgICAud2hlbihcbiAgICAgICAgICAgIHNmbi5Db25kaXRpb24uc3RyaW5nRXF1YWxzKFwiJC5GbG93RXhlY3V0aW9uU3RhdHVzXCIsIFwiRXJyb3JcIiksXG4gICAgICAgICAgICBuZXcgc2ZuLkZhaWwodGhpcywgXCJmYWlsdXJlXCIsIHtcbiAgICAgICAgICAgICAgZXJyb3I6IFwiV29ya2Zsb3dGYWlsdXJlXCIsXG4gICAgICAgICAgICAgIGNhdXNlOiBcIkFwcEZsb3cgZmFpbHVyZVwiLFxuICAgICAgICAgICAgfSksXG4gICAgICAgICAgKVxuICAgICAgICAgIC5vdGhlcndpc2UoZmxvd09iamVjdEV4ZWN1dGlvblN0YXR1c1dhaXQpLFxuICAgICAgKTtcblxuICAgICh7XG4gICAgICBldmVudFBhdHRlcm46IHRoaXMuZXZlbnRQYXR0ZXJuLFxuICAgICAgdGFyZ2V0czogdGhpcy50YXJnZXRzLFxuICAgICAgc3RhdGVNYWNoaW5lOiB0aGlzLnN0YXRlTWFjaGluZSxcbiAgICB9ID0gdGhpcy5jcmVhdGVTdGF0ZU1hY2hpbmUoeyBkZWZpbml0aW9uOiBkZWZpbml0aW9uLCAuLi5wcm9wcyB9KSk7XG4gICAgdGhpcy5zdGF0ZU1hY2hpbmUuYWRkVG9Sb2xlUG9saWN5KFxuICAgICAgbmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICBlZmZlY3Q6IGlhbS5FZmZlY3QuQUxMT1csXG4gICAgICAgIGFjdGlvbnM6IFtcImFwcGZsb3c6U3RhcnRGbG93XCJdLFxuICAgICAgICByZXNvdXJjZXM6IFtcIipcIl0sXG4gICAgICB9KSxcbiAgICApO1xuICB9XG5cbiAgcHJpdmF0ZSBjcmVhdGVTdGFydEZsb3dDdXN0b21UYXNrKGZsb3dOYW1lOiBzdHJpbmcsIHdhaXRIYW5kbGVyPzogc2ZuLldhaXQpOiB0YXNrcy5DYWxsQXdzU2VydmljZSB7XG4gICAgY29uc3Qgc3RhY2sgPSBjZGsuU3RhY2sub2YodGhpcyk7XG4gICAgY29uc3QgdGFzayA9IG5ldyB0YXNrcy5DYWxsQXdzU2VydmljZSh0aGlzLCBcIlN0YXJ0IEZsb3cgRXhlY3V0aW9uXCIsIHtcbiAgICAgIHNlcnZpY2U6IFwiYXBwZmxvd1wiLFxuICAgICAgYWN0aW9uOiBcInN0YXJ0Rmxvd1wiLFxuICAgICAgaWFtUmVzb3VyY2VzOiBbYGFybjoke3N0YWNrLnBhcnRpdGlvbn06YXBwZmxvdzoke3N0YWNrLnJlZ2lvbn06JHtzdGFjay5hY2NvdW50fTpmbG93LyR7Zmxvd05hbWV9YF0sXG4gICAgICBwYXJhbWV0ZXJzOiB7XG4gICAgICAgIEZsb3dOYW1lOiBmbG93TmFtZSxcbiAgICAgIH0sXG4gICAgfSk7XG4gICAgaWYgKHdhaXRIYW5kbGVyKSB7XG4gICAgICB0YXNrLmFkZENhdGNoKHdhaXRIYW5kbGVyLCB7XG4gICAgICAgIGVycm9yczogW1wiQXBwZmxvdy5Db25mbGljdEV4Y2VwdGlvblwiXSxcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHJldHVybiB0YXNrO1xuICB9XG5cbiAgcHJpdmF0ZSBjcmVhdGVDaGVja0Zsb3dFeGVjdXRpb25UYXNrKCk6IHRhc2tzLkxhbWJkYUludm9rZSB7XG4gICAgY29uc3Qgc3RhdHVzTGFtYmRhUm9sZSA9IG5ldyBpYW0uUm9sZSh0aGlzLCBcIkZsb3cgRXhlY3V0aW9uIFN0YXR1cyBMYW1iZGEgUm9sZVwiLCB7XG4gICAgICBhc3N1bWVkQnk6IG5ldyBpYW0uU2VydmljZVByaW5jaXBhbChcImxhbWJkYS5hbWF6b25hd3MuY29tXCIpLFxuICAgICAgZGVzY3JpcHRpb246IFwibGFtYmRhIHJvbGUgdG8gY2hlY2sgYXBwZmxvdyBmbG93IGV4ZWN1dGlvbiBzdGF0dXNcIixcbiAgICB9KTtcblxuICAgIGNvbnN0IHN0YXR1c0xhbWJkYSA9IG5ldyBsYW1iZGEuRnVuY3Rpb24odGhpcywgXCJGbG93IEV4ZWN1dGlvbiBTdGF0dXMgTGFtYmRhXCIsIHtcbiAgICAgIGNvZGU6IGxhbWJkYS5Db2RlLmZyb21JbmxpbmUoYFxuICAgICAgICAgICMgQ29weXJpZ2h0IDIwMjIgQW1hem9uLmNvbSwgSW5jLiBvciBpdHMgYWZmaWxpYXRlcy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAgICAgICAgICAjXG4gICAgICAgICAgIyBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpLlxuICAgICAgICAgICMgWW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLlxuICAgICAgICAgICMgWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0XG4gICAgICAgICAgI1xuICAgICAgICAgICMgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICAgICAgICAgICNcbiAgICAgICAgICAjIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAgICAgICAgICAjIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiAgICAgICAgICAjIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuICAgICAgICAgICMgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuICAgICAgICAgICMgbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG5cbiAgICAgICAgICBpbXBvcnQganNvblxuICAgICAgICAgIGltcG9ydCBsb2dnaW5nXG4gICAgICAgICAgZnJvbSB0eXBpbmcgaW1wb3J0IEFueSwgRGljdCwgT3B0aW9uYWxcblxuICAgICAgICAgIGltcG9ydCBib3RvM1xuXG4gICAgICAgICAgbG9nZ2VyID0gbG9nZ2luZy5nZXRMb2dnZXIoKVxuICAgICAgICAgIGxvZ2dlci5zZXRMZXZlbChsb2dnaW5nLklORk8pXG5cbiAgICAgICAgICBhcHBmbG93ID0gYm90bzMuY2xpZW50KFwiYXBwZmxvd1wiKVxuXG5cbiAgICAgICAgICBkZWYgbGFtYmRhX2hhbmRsZXIoZXZlbnQ6IERpY3Rbc3RyLCBBbnldLCBjb250ZXh0OiBPcHRpb25hbFtEaWN0W3N0ciwgQW55XV0pIC0+IHN0cjpcbiAgICAgICAgICAgICAgIyBMb2cgdGhlIHJlY2VpdmVkIGV2ZW50XG4gICAgICAgICAgICAgIGxvZ2dlci5pbmZvKFwiUmVjZWl2ZWQgZXZlbnQ6IFwiICsganNvbi5kdW1wcyhldmVudCwgaW5kZW50PTIpKVxuICAgICAgICAgICAgICAjIEdldCBhcHBmbG93IGZsb3cgbmFtZSBmcm9tIHRoZSBldmVudFxuICAgICAgICAgICAgICBmbG93X25hbWUgPSBldmVudFtcIkZsb3dBcm5cIl0ucnNwbGl0KFwiL1wiKVstMV1cbiAgICAgICAgICAgICAgIyBHZXQgYXBwZmxvdyBmbG93IGV4ZWN1dGlvbiBpZCBmcm9tIHRoZSBldmVudFxuICAgICAgICAgICAgICBleGVjdXRpb25faWQgPSBldmVudFtcIkV4ZWN1dGlvbklkXCJdXG5cbiAgICAgICAgICAgICAgcGFyYW1zID0ge1wiZmxvd05hbWVcIjogZmxvd19uYW1lLCBcIm1heFJlc3VsdHNcIjogMTB9XG5cbiAgICAgICAgICAgICAgZmxvd19leGVjdXRpb25fc3RhdHVzID0gXCJcIlxuXG4gICAgICAgICAgICAgIHRyeTpcbiAgICAgICAgICAgICAgICAgICMgdW5mb3J0dW5hdGVseSB0aGUgYXBwZmxvdyBjbGllbnQgZG9lcyBub3QgaGF2ZSBhbnkgcGFnaW5hdG9yXG4gICAgICAgICAgICAgICAgICB3aGlsZSBUcnVlOlxuICAgICAgICAgICAgICAgICAgICAgIHJlc3BvbnNlID0gYXBwZmxvdy5kZXNjcmliZV9mbG93X2V4ZWN1dGlvbl9yZWNvcmRzKCoqcGFyYW1zKSAgIyB0eXBlOiBpZ25vcmVcbiAgICAgICAgICAgICAgICAgICAgICBsb2dnZXIuaW5mbyhyZXNwb25zZSlcbiAgICAgICAgICAgICAgICAgICAgICBleGVjdXRpb25fcmVjb3JkID0gW1xuICAgICAgICAgICAgICAgICAgICAgICAgICBleGVjdXRpb24gZm9yIGV4ZWN1dGlvbiBpbiByZXNwb25zZVtcImZsb3dFeGVjdXRpb25zXCJdIGlmIGV4ZWN1dGlvbltcImV4ZWN1dGlvbklkXCJdID09IGV4ZWN1dGlvbl9pZFxuICAgICAgICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgICAgICAgICAgICBpZiBleGVjdXRpb25fcmVjb3JkOlxuICAgICAgICAgICAgICAgICAgICAgICAgICBmbG93X2V4ZWN1dGlvbl9zdGF0dXMgPSBleGVjdXRpb25fcmVjb3JkWzBdW1wiZXhlY3V0aW9uU3RhdHVzXCJdXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrXG4gICAgICAgICAgICAgICAgICAgICAgaWYgXCJuZXh0VG9rZW5cIiBpbiByZXNwb25zZTpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1zW1wibmV4dFRva2VuXCJdID0gcmVzcG9uc2VbXCJuZXh0VG9rZW5cIl1cbiAgICAgICAgICAgICAgICAgICAgICBlbHNlOlxuICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha1xuICAgICAgICAgICAgICAgICAgbG9nZ2VyLmluZm8oZlwiU3RhdHVzOiB7Zmxvd19leGVjdXRpb25fc3RhdHVzfVwiKVxuICAgICAgICAgICAgICAgICAgcmV0dXJuIGZsb3dfZXhlY3V0aW9uX3N0YXR1c1xuICAgICAgICAgICAgICBleGNlcHQgRXhjZXB0aW9uIGFzIGU6XG4gICAgICAgICAgICAgICAgICBsb2dnZXIuaW5mbyhlKVxuICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IFwiRXJyb3IgZ2V0dGluZyBBcHBGbG93IGZsb3cgc3RhdHVzXCJcbiAgICAgICAgICAgICAgICAgIGxvZ2dlci5pbmZvKG1lc3NhZ2UpXG4gICAgICAgICAgICAgICAgICByYWlzZSBFeGNlcHRpb24obWVzc2FnZSlcbiAgICAgICAgYCksXG4gICAgICBoYW5kbGVyOiBcImxhbWJkYV9mdW5jdGlvbi5sYW1iZGFfaGFuZGxlclwiLFxuICAgICAgcm9sZTogc3RhdHVzTGFtYmRhUm9sZSxcbiAgICAgIHJ1bnRpbWU6IGxhbWJkYS5SdW50aW1lLlBZVEhPTl8zXzksXG4gICAgICBtZW1vcnlTaXplOiAyNTYsXG4gICAgICB0aW1lb3V0OiBjZGsuRHVyYXRpb24uc2Vjb25kcygxMjApLFxuICAgIH0pO1xuXG4gICAgLy8gRW5hYmxlIHRoZSBmdW5jdGlvbiB0byBnZXQgZmxvdyBleGVjdXRpb24gcmVjb3Jkc1xuICAgIHN0YXR1c0xhbWJkYS5hZGRUb1JvbGVQb2xpY3koXG4gICAgICBuZXcgaWFtLlBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgIGVmZmVjdDogaWFtLkVmZmVjdC5BTExPVyxcbiAgICAgICAgYWN0aW9uczogW1wiYXBwZmxvdzpEZXNjcmliZUZsb3dFeGVjdXRpb25SZWNvcmRzXCJdLFxuICAgICAgICByZXNvdXJjZXM6IFtcIipcIl0sXG4gICAgICB9KSxcbiAgICApO1xuXG4gICAgLy8gQ3JlYXRlIGNoZWNrIGZsb3cgZXhlY3V0aW9uIHN0YXR1cyBzdGVwIGZ1bmN0aW9uIHRhc2tcbiAgICByZXR1cm4gbmV3IHRhc2tzLkxhbWJkYUludm9rZSh0aGlzLCBcIkdldCBGbG93IEV4ZWN1dGlvbiBTdGF0dXNcIiwge1xuICAgICAgbGFtYmRhRnVuY3Rpb246IHN0YXR1c0xhbWJkYSxcbiAgICAgIHJlc3VsdFNlbGVjdG9yOiB7IFwiRmxvd0V4ZWN1dGlvblN0YXR1cy4kXCI6IFwiJC5QYXlsb2FkXCIgfSxcbiAgICB9KTtcbiAgfVxufVxuIl19