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.

181 lines (172 loc) 25.1 kB
"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