@aws-cdk/aws-redshift-alpha
Version:
The CDK Construct Library for AWS::Redshift
546 lines • 79.8 kB
JavaScript
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Cluster = exports.MaintenanceTrackName = exports.ResourceAction = exports.ClusterType = exports.NodeType = void 0;
const jsiiDeprecationWarnings = require("../.warnings.jsii.js");
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
const path = require("path");
const ec2 = require("aws-cdk-lib/aws-ec2");
const iam = require("aws-cdk-lib/aws-iam");
const lambda = require("aws-cdk-lib/aws-lambda");
const secretsmanager = require("aws-cdk-lib/aws-secretsmanager");
const core_1 = require("aws-cdk-lib/core");
const custom_resources_1 = require("aws-cdk-lib/custom-resources");
const database_secret_1 = require("./database-secret");
const endpoint_1 = require("./endpoint");
const parameter_group_1 = require("./parameter-group");
const aws_redshift_1 = require("aws-cdk-lib/aws-redshift");
const subnet_group_1 = require("./subnet-group");
const metadata_resource_1 = require("aws-cdk-lib/core/lib/metadata-resource");
/**
* Possible Node Types to use in the cluster
* used for defining `ClusterProps.nodeType`.
*/
var NodeType;
(function (NodeType) {
/**
* ds2.xlarge
*/
NodeType["DS2_XLARGE"] = "ds2.xlarge";
/**
* ds2.8xlarge
*/
NodeType["DS2_8XLARGE"] = "ds2.8xlarge";
/**
* dc1.large
*/
NodeType["DC1_LARGE"] = "dc1.large";
/**
* dc1.8xlarge
*/
NodeType["DC1_8XLARGE"] = "dc1.8xlarge";
/**
* dc2.large
*/
NodeType["DC2_LARGE"] = "dc2.large";
/**
* dc2.8xlarge
*/
NodeType["DC2_8XLARGE"] = "dc2.8xlarge";
/**
* ra3.large
*/
NodeType["RA3_LARGE"] = "ra3.large";
/**
* ra3.xlplus
*/
NodeType["RA3_XLPLUS"] = "ra3.xlplus";
/**
* ra3.4xlarge
*/
NodeType["RA3_4XLARGE"] = "ra3.4xlarge";
/**
* ra3.16xlarge
*/
NodeType["RA3_16XLARGE"] = "ra3.16xlarge";
})(NodeType || (exports.NodeType = NodeType = {}));
/**
* What cluster type to use.
* Used by `ClusterProps.clusterType`
*/
var ClusterType;
(function (ClusterType) {
/**
* single-node cluster, the `ClusterProps.numberOfNodes` parameter is not required
*/
ClusterType["SINGLE_NODE"] = "single-node";
/**
* multi-node cluster, set the amount of nodes using `ClusterProps.numberOfNodes` parameter
*/
ClusterType["MULTI_NODE"] = "multi-node";
})(ClusterType || (exports.ClusterType = ClusterType = {}));
/**
* The Amazon Redshift operation
*/
var ResourceAction;
(function (ResourceAction) {
/**
* Pause the cluster
*/
ResourceAction["PAUSE_CLUSTER"] = "pause-cluster";
/**
* Resume the cluster
*/
ResourceAction["RESUME_CLUSTER"] = "resume-cluster";
/**
* Failing over to the other availability zone
*
* @see https://docs.aws.amazon.com/redshift/latest/mgmt/test-cluster-multi-az.html
*/
ResourceAction["FAILOVER_PRIMARY_COMPUTE"] = "failover-primary-compute";
})(ResourceAction || (exports.ResourceAction = ResourceAction = {}));
/**
* The maintenance track for the cluster.
*
* @see https://docs.aws.amazon.com/redshift/latest/mgmt/managing-cluster-considerations.html#rs-mgmt-maintenance-tracks
*/
var MaintenanceTrackName;
(function (MaintenanceTrackName) {
/**
* Updated to the most recently certified maintenance release.
*/
MaintenanceTrackName["CURRENT"] = "current";
/**
* Update to the previously certified maintenance release.
*/
MaintenanceTrackName["TRAILING"] = "trailing";
})(MaintenanceTrackName || (exports.MaintenanceTrackName = MaintenanceTrackName = {}));
/**
* A new or imported clustered database.
*/
class ClusterBase extends core_1.Resource {
/**
* Renders the secret attachment target specifications.
*/
asSecretAttachmentTarget() {
return {
targetId: this.clusterName,
targetType: secretsmanager.AttachmentTargetType.REDSHIFT_CLUSTER,
};
}
}
/**
* Create a Redshift cluster a given number of nodes.
*
* @resource AWS::Redshift::Cluster
*/
class Cluster extends ClusterBase {
/**
* Import an existing DatabaseCluster from properties
*/
static fromClusterAttributes(scope, id, attrs) {
try {
jsiiDeprecationWarnings._aws_cdk_aws_redshift_alpha_ClusterAttributes(attrs);
}
catch (error) {
if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
Error.captureStackTrace(error, this.fromClusterAttributes);
}
throw error;
}
class Import extends ClusterBase {
constructor() {
super(...arguments);
this.connections = new ec2.Connections({
securityGroups: attrs.securityGroups,
defaultPort: ec2.Port.tcp(attrs.clusterEndpointPort),
});
this.clusterName = attrs.clusterName;
this.instanceIdentifiers = [];
this.clusterEndpoint = new endpoint_1.Endpoint(attrs.clusterEndpointAddress, attrs.clusterEndpointPort);
}
}
return new Import(scope, id);
}
constructor(scope, id, props) {
super(scope, id);
try {
jsiiDeprecationWarnings._aws_cdk_aws_redshift_alpha_ClusterProps(props);
}
catch (error) {
if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
Error.captureStackTrace(error, Cluster);
}
throw error;
}
// Enhanced CDK Analytics Telemetry
(0, metadata_resource_1.addConstructMetadata)(this, props);
this.vpc = props.vpc;
this.vpcSubnets = props.vpcSubnets ?? {
subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
};
this.parameterGroup = props.parameterGroup;
this.roles = props?.roles ? [...props.roles] : [];
const removalPolicy = props.removalPolicy ?? core_1.RemovalPolicy.RETAIN;
const subnetGroup = props.subnetGroup ?? new subnet_group_1.ClusterSubnetGroup(this, 'Subnets', {
description: `Subnets for ${id} Redshift cluster`,
vpc: this.vpc,
vpcSubnets: this.vpcSubnets,
removalPolicy: removalPolicy,
});
const securityGroups = props.securityGroups ?? [new ec2.SecurityGroup(this, 'SecurityGroup', {
description: 'Redshift security group',
vpc: this.vpc,
})];
const securityGroupIds = securityGroups.map(sg => sg.securityGroupId);
let secret;
if (!props.masterUser.masterPassword) {
secret = new database_secret_1.DatabaseSecret(this, 'Secret', {
username: props.masterUser.masterUsername,
encryptionKey: props.masterUser.encryptionKey,
excludeCharacters: props.masterUser.excludeCharacters,
});
}
const clusterType = props.clusterType || ClusterType.MULTI_NODE;
const nodeCount = this.validateNodeCount(clusterType, props.numberOfNodes);
if (props.encrypted === false && props.encryptionKey !== undefined) {
throw new Error('Cannot set property encryptionKey without enabling encryption!');
}
this.singleUserRotationApplication = secretsmanager.SecretRotationApplication.REDSHIFT_ROTATION_SINGLE_USER;
this.multiUserRotationApplication = secretsmanager.SecretRotationApplication.REDSHIFT_ROTATION_MULTI_USER;
let loggingProperties;
if (props.loggingProperties) {
loggingProperties = {
bucketName: props.loggingProperties.loggingBucket.bucketName,
s3KeyPrefix: props.loggingProperties.loggingKeyPrefix,
};
props.loggingProperties.loggingBucket.addToResourcePolicy(new iam.PolicyStatement({
actions: [
's3:GetBucketAcl',
's3:PutObject',
],
resources: [
props.loggingProperties.loggingBucket.arnForObjects('*'),
props.loggingProperties.loggingBucket.bucketArn,
],
principals: [
new iam.ServicePrincipal('redshift.amazonaws.com'),
],
}));
}
const nodeType = props.nodeType || NodeType.DC2_LARGE;
if (props.multiAz) {
if (!nodeType.startsWith('ra3')) {
throw new Error(`Multi-AZ cluster is only supported for RA3 node types, got: ${props.nodeType}`);
}
if (clusterType === ClusterType.SINGLE_NODE) {
throw new Error('Multi-AZ cluster is not supported for `clusterType` single-node');
}
}
if (props.resourceAction === ResourceAction.FAILOVER_PRIMARY_COMPUTE && !props.multiAz) {
throw new Error('ResourceAction.FAILOVER_PRIMARY_COMPUTE can only be used with multi-AZ clusters.');
}
if (props.availabilityZoneRelocation && !nodeType.startsWith('ra3')) {
throw new Error(`Availability zone relocation is supported for only RA3 node types, got: ${props.nodeType}`);
}
this.cluster = new aws_redshift_1.CfnCluster(this, 'Resource', {
// Basic
allowVersionUpgrade: true,
maintenanceTrackName: props.maintenanceTrackName,
automatedSnapshotRetentionPeriod: 1,
clusterType,
clusterIdentifier: props.clusterName,
clusterSubnetGroupName: subnetGroup.clusterSubnetGroupName,
vpcSecurityGroupIds: securityGroupIds,
port: props.port,
clusterParameterGroupName: props.parameterGroup && props.parameterGroup.clusterParameterGroupName,
// Admin (unsafeUnwrap here is safe)
masterUsername: secret?.secretValueFromJson('username').unsafeUnwrap() ?? props.masterUser.masterUsername,
masterUserPassword: secret?.secretValueFromJson('password').unsafeUnwrap()
?? props.masterUser.masterPassword?.unsafeUnwrap()
?? 'default',
preferredMaintenanceWindow: props.preferredMaintenanceWindow,
nodeType,
numberOfNodes: nodeCount,
loggingProperties,
iamRoles: core_1.Lazy.list({ produce: () => this.roles.map(role => role.roleArn) }, { omitEmpty: true }),
dbName: props.defaultDatabaseName || 'default_db',
publiclyAccessible: props.publiclyAccessible || false,
// Encryption
kmsKeyId: props.encryptionKey?.keyId,
encrypted: props.encrypted ?? true,
classic: props.classicResizing,
elasticIp: props.elasticIp,
enhancedVpcRouting: props.enhancedVpcRouting,
multiAz: props.multiAz,
resourceAction: props.resourceAction,
availabilityZoneRelocation: props.availabilityZoneRelocation,
});
this.cluster.applyRemovalPolicy(removalPolicy, {
applyToUpdateReplacePolicy: true,
});
this.clusterName = this.cluster.ref;
// create a number token that represents the port of the cluster
const portAttribute = core_1.Token.asNumber(this.cluster.attrEndpointPort);
this.clusterEndpoint = new endpoint_1.Endpoint(this.cluster.attrEndpointAddress, portAttribute);
if (secret) {
this.secret = secret.attach(this);
}
const defaultPort = ec2.Port.tcp(this.clusterEndpoint.port);
this.connections = new ec2.Connections({ securityGroups, defaultPort });
if (props.rebootForParameterChanges) {
this.enableRebootForParameterChanges();
}
// Add default role if specified and also available in the roles list
if (props.defaultRole) {
if (props.roles?.some(x => x === props.defaultRole)) {
this.addDefaultIamRole(props.defaultRole);
}
else {
throw new Error('Default role must be included in role list.');
}
}
}
/**
* Adds the single user rotation of the master password to this cluster.
*
* @param [automaticallyAfter=Duration.days(30)] Specifies the number of days after the previous rotation
* before Secrets Manager triggers the next automatic rotation.
*/
addRotationSingleUser(automaticallyAfter) {
if (!this.secret) {
throw new Error('Cannot add single user rotation for a cluster without secret.');
}
const id = 'RotationSingleUser';
const existing = this.node.tryFindChild(id);
if (existing) {
throw new Error('A single user rotation was already added to this cluster.');
}
return new secretsmanager.SecretRotation(this, id, {
secret: this.secret,
automaticallyAfter,
application: this.singleUserRotationApplication,
vpc: this.vpc,
vpcSubnets: this.vpcSubnets,
target: this,
});
}
/**
* Adds the multi user rotation to this cluster.
*/
addRotationMultiUser(id, options) {
try {
jsiiDeprecationWarnings._aws_cdk_aws_redshift_alpha_RotationMultiUserOptions(options);
}
catch (error) {
if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
Error.captureStackTrace(error, this.addRotationMultiUser);
}
throw error;
}
if (!this.secret) {
throw new Error('Cannot add multi user rotation for a cluster without secret.');
}
return new secretsmanager.SecretRotation(this, id, {
secret: options.secret,
masterSecret: this.secret,
automaticallyAfter: options.automaticallyAfter,
application: this.multiUserRotationApplication,
vpc: this.vpc,
vpcSubnets: this.vpcSubnets,
target: this,
});
}
validateNodeCount(clusterType, numberOfNodes) {
if (clusterType === ClusterType.SINGLE_NODE) {
// This property must not be set for single-node clusters; be generous and treat a value of 1 node as undefined.
if (numberOfNodes !== undefined && numberOfNodes !== 1) {
throw new Error('Number of nodes must be not be supplied or be 1 for cluster type single-node');
}
return undefined;
}
else {
if (core_1.Token.isUnresolved(numberOfNodes)) {
return numberOfNodes;
}
const nodeCount = numberOfNodes ?? 2;
if (nodeCount < 2 || nodeCount > 100) {
throw new Error('Number of nodes for cluster type multi-node must be at least 2 and no more than 100');
}
return nodeCount;
}
}
/**
* Adds a parameter to the Clusters' parameter group
*
* @param name the parameter name
* @param value the parameter name
*/
addToParameterGroup(name, value) {
if (!this.parameterGroup) {
const param = {};
param[name] = value;
this.parameterGroup = new parameter_group_1.ClusterParameterGroup(this, 'ParameterGroup', {
description: this.cluster.clusterIdentifier ? `Parameter Group for the ${this.cluster.clusterIdentifier} Redshift cluster` : 'Cluster parameter group for family redshift-1.0',
parameters: param,
});
this.cluster.clusterParameterGroupName = this.parameterGroup.clusterParameterGroupName;
}
else if (this.parameterGroup instanceof parameter_group_1.ClusterParameterGroup) {
this.parameterGroup.addParameter(name, value);
}
else {
throw new Error('Cannot add a parameter to an imported parameter group.');
}
}
/**
* Enables automatic cluster rebooting when changes to the cluster's parameter group require a restart to apply.
*/
enableRebootForParameterChanges() {
if (this.node.tryFindChild('RedshiftClusterRebooterCustomResource')) {
return;
}
const rebootFunction = new lambda.SingletonFunction(this, 'RedshiftClusterRebooterFunction', {
uuid: '511e207f-13df-4b8b-b632-c32b30b65ac2',
runtime: lambda.determineLatestNodeRuntime(this),
code: lambda.Code.fromAsset(path.join(__dirname, '..', 'custom-resource-handlers', 'dist', 'aws-redshift-alpha', 'cluster-parameter-change-reboot-handler')),
handler: 'index.handler',
timeout: core_1.Duration.seconds(900),
});
rebootFunction.addToRolePolicy(new iam.PolicyStatement({
actions: ['redshift:DescribeClusters'],
resources: ['*'],
}));
rebootFunction.addToRolePolicy(new iam.PolicyStatement({
actions: ['redshift:RebootCluster'],
resources: [
core_1.Stack.of(this).formatArn({
service: 'redshift',
resource: 'cluster',
resourceName: this.clusterName,
arnFormat: core_1.ArnFormat.COLON_RESOURCE_NAME,
}),
],
}));
const provider = new custom_resources_1.Provider(this, 'ResourceProvider', {
onEventHandler: rebootFunction,
});
const customResource = new core_1.CustomResource(this, 'RedshiftClusterRebooterCustomResource', {
resourceType: 'Custom::RedshiftClusterRebooter',
serviceToken: provider.serviceToken,
properties: {
ClusterId: this.clusterName,
ParameterGroupName: core_1.Lazy.string({
produce: () => {
if (!this.parameterGroup) {
throw new Error('Cannot enable reboot for parameter changes when there is no associated ClusterParameterGroup.');
}
return this.parameterGroup.clusterParameterGroupName;
},
}),
ParametersString: core_1.Lazy.string({
produce: () => {
if (!(this.parameterGroup instanceof parameter_group_1.ClusterParameterGroup)) {
throw new Error('Cannot enable reboot for parameter changes when using an imported parameter group.');
}
return JSON.stringify(this.parameterGroup.parameters);
},
}),
},
});
core_1.Lazy.any({
produce: () => {
if (!this.parameterGroup) {
throw new Error('Cannot enable reboot for parameter changes when there is no associated ClusterParameterGroup.');
}
customResource.node.addDependency(this, this.parameterGroup);
},
});
}
/**
* Adds default IAM role to cluster. The default IAM role must be already associated to the cluster to be added as the default role.
*
* @param defaultIamRole the IAM role to be set as the default role
*/
addDefaultIamRole(defaultIamRole) {
// Get list of IAM roles attached to cluster
const clusterRoleList = this.roles ?? [];
// Check to see if default role is included in list of cluster IAM roles
var roleAlreadyOnCluster = false;
for (var i = 0; i < clusterRoleList.length; i++) {
if (clusterRoleList[i] === defaultIamRole) {
roleAlreadyOnCluster = true;
break;
}
}
if (!roleAlreadyOnCluster) {
throw new Error('Default role must be associated to the Redshift cluster to be set as the default role.');
}
// On UPDATE or CREATE define the default IAM role. On DELETE, remove the default IAM role
const defaultRoleCustomResource = new custom_resources_1.AwsCustomResource(this, 'default-role', {
onUpdate: {
service: 'Redshift',
action: 'modifyClusterIamRoles',
parameters: {
ClusterIdentifier: this.cluster.ref,
DefaultIamRoleArn: defaultIamRole.roleArn,
},
physicalResourceId: custom_resources_1.PhysicalResourceId.of(`${defaultIamRole.roleArn}-${this.cluster.ref}`),
},
onDelete: {
service: 'Redshift',
action: 'modifyClusterIamRoles',
parameters: {
ClusterIdentifier: this.cluster.ref,
DefaultIamRoleArn: '',
},
physicalResourceId: custom_resources_1.PhysicalResourceId.of(`${defaultIamRole.roleArn}-${this.cluster.ref}`),
},
policy: custom_resources_1.AwsCustomResourcePolicy.fromSdkCalls({
resources: custom_resources_1.AwsCustomResourcePolicy.ANY_RESOURCE,
}),
installLatestAwsSdk: false,
});
defaultIamRole.grantPassRole(defaultRoleCustomResource.grantPrincipal);
}
/**
* Adds a role to the cluster
*
* @param role the role to add
*/
addIamRole(role) {
const clusterRoleList = this.roles;
if (clusterRoleList.includes(role)) {
throw new Error(`Role '${role.roleArn}' is already attached to the cluster`);
}
clusterRoleList.push(role);
}
}
exports.Cluster = Cluster;
_a = JSII_RTTI_SYMBOL_1;
Cluster[_a] = { fqn: "@aws-cdk/aws-redshift-alpha.Cluster", version: "2.188.0-alpha.0" };
__decorate([
(0, metadata_resource_1.MethodMetadata)()
], Cluster.prototype, "addRotationSingleUser", null);
__decorate([
(0, metadata_resource_1.MethodMetadata)()
], Cluster.prototype, "addRotationMultiUser", null);
__decorate([
(0, metadata_resource_1.MethodMetadata)()
], Cluster.prototype, "addToParameterGroup", null);
__decorate([
(0, metadata_resource_1.MethodMetadata)()
], Cluster.prototype, "enableRebootForParameterChanges", null);
__decorate([
(0, metadata_resource_1.MethodMetadata)()
], Cluster.prototype, "addDefaultIamRole", null);
__decorate([
(0, metadata_resource_1.MethodMetadata)()
], Cluster.prototype, "addIamRole", null);
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2x1c3Rlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImNsdXN0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7O0FBQUEsNkJBQTZCO0FBQzdCLDJDQUEyQztBQUMzQywyQ0FBMkM7QUFFM0MsaURBQWlEO0FBRWpELGlFQUFpRTtBQUNqRSwyQ0FBNEk7QUFDNUksbUVBQXdIO0FBRXhILHVEQUFtRDtBQUNuRCx5Q0FBc0M7QUFDdEMsdURBQWtGO0FBQ2xGLDJEQUFzRDtBQUN0RCxpREFBeUU7QUFDekUsOEVBQThGO0FBRTlGOzs7R0FHRztBQUNILElBQVksUUFrRFg7QUFsREQsV0FBWSxRQUFRO0lBQ2xCOztPQUVHO0lBQ0gscUNBQXlCLENBQUE7SUFFekI7O09BRUc7SUFDSCx1Q0FBMkIsQ0FBQTtJQUUzQjs7T0FFRztJQUNILG1DQUF1QixDQUFBO0lBRXZCOztPQUVHO0lBQ0gsdUNBQTJCLENBQUE7SUFFM0I7O09BRUc7SUFDSCxtQ0FBdUIsQ0FBQTtJQUV2Qjs7T0FFRztJQUNILHVDQUEyQixDQUFBO0lBRTNCOztPQUVHO0lBQ0gsbUNBQXVCLENBQUE7SUFFdkI7O09BRUc7SUFDSCxxQ0FBeUIsQ0FBQTtJQUV6Qjs7T0FFRztJQUNILHVDQUEyQixDQUFBO0lBRTNCOztPQUVHO0lBQ0gseUNBQTZCLENBQUE7QUFDL0IsQ0FBQyxFQWxEVyxRQUFRLHdCQUFSLFFBQVEsUUFrRG5CO0FBRUQ7OztHQUdHO0FBQ0gsSUFBWSxXQVNYO0FBVEQsV0FBWSxXQUFXO0lBQ3JCOztPQUVHO0lBQ0gsMENBQTJCLENBQUE7SUFDM0I7O09BRUc7SUFDSCx3Q0FBeUIsQ0FBQTtBQUMzQixDQUFDLEVBVFcsV0FBVywyQkFBWCxXQUFXLFFBU3RCO0FBRUQ7O0dBRUc7QUFDSCxJQUFZLGNBaUJYO0FBakJELFdBQVksY0FBYztJQUN4Qjs7T0FFRztJQUNILGlEQUErQixDQUFBO0lBRS9COztPQUVHO0lBQ0gsbURBQWlDLENBQUE7SUFFakM7Ozs7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J3BhdGgnO1xuaW1wb3J0ICogYXMgZWMyIGZyb20gJ2F3cy1jZGstbGliL2F3cy1lYzInO1xuaW1wb3J0ICogYXMgaWFtIGZyb20gJ2F3cy1jZGstbGliL2F3cy1pYW0nO1xuaW1wb3J0ICogYXMga21zIGZyb20gJ2F3cy1jZGstbGliL2F3cy1rbXMnO1xuaW1wb3J0ICogYXMgbGFtYmRhIGZyb20gJ2F3cy1jZGstbGliL2F3cy1sYW1iZGEnO1xuaW1wb3J0ICogYXMgczMgZnJvbSAnYXdzLWNkay1saWIvYXdzLXMzJztcbmltcG9ydCAqIGFzIHNlY3JldHNtYW5hZ2VyIGZyb20gJ2F3cy1jZGstbGliL2F3cy1zZWNyZXRzbWFuYWdlcic7XG5pbXBvcnQgeyBBcm5Gb3JtYXQsIEN1c3RvbVJlc291cmNlLCBEdXJhdGlvbiwgSVJlc291cmNlLCBMYXp5LCBSZW1vdmFsUG9saWN5LCBSZXNvdXJjZSwgU2VjcmV0VmFsdWUsIFN0YWNrLCBUb2tlbiB9IGZyb20gJ2F3cy1jZGstbGliL2NvcmUnO1xuaW1wb3J0IHsgQXdzQ3VzdG9tUmVzb3VyY2UsIEF3c0N1c3RvbVJlc291cmNlUG9saWN5LCBQaHlzaWNhbFJlc291cmNlSWQsIFByb3ZpZGVyIH0gZnJvbSAnYXdzLWNkay1saWIvY3VzdG9tLXJlc291cmNlcyc7XG5pbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tICdjb25zdHJ1Y3RzJztcbmltcG9ydCB7IERhdGFiYXNlU2VjcmV0IH0gZnJvbSAnLi9kYXRhYmFzZS1zZWNyZXQnO1xuaW1wb3J0IHsgRW5kcG9pbnQgfSBmcm9tICcuL2VuZHBvaW50JztcbmltcG9ydCB7IENsdXN0ZXJQYXJhbWV0ZXJHcm91cCwgSUNsdXN0ZXJQYXJhbWV0ZXJHcm91cCB9IGZyb20gJy4vcGFyYW1ldGVyLWdyb3VwJztcbmltcG9ydCB7IENmbkNsdXN0ZXIgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtcmVkc2hpZnQnO1xuaW1wb3J0IHsgQ2x1c3RlclN1Ym5ldEdyb3VwLCBJQ2x1c3RlclN1Ym5ldEdyb3VwIH0gZnJvbSAnLi9zdWJuZXQtZ3JvdXAnO1xuaW1wb3J0IHsgYWRkQ29uc3RydWN0TWV0YWRhdGEsIE1ldGhvZE1ldGFkYXRhIH0gZnJvbSAnYXdzLWNkay1saWIvY29yZS9saWIvbWV0YWRhdGEtcmVzb3VyY2UnO1xuXG4vKipcbiAqIFBvc3NpYmxlIE5vZGUgVHlwZXMgdG8gdXNlIGluIHRoZSBjbHVzdGVyXG4gKiB1c2VkIGZvciBkZWZpbmluZyBgQ2x1c3RlclByb3BzLm5vZGVUeXBlYC5cbiAqL1xuZXhwb3J0IGVudW0gTm9kZVR5cGUge1xuICAvKipcbiAgICogZHMyLnhsYXJnZVxuICAgKi9cbiAgRFMyX1hMQVJHRSA9ICdkczIueGxhcmdlJyxcblxuICAvKipcbiAgICogZHMyLjh4bGFyZ2VcbiAgICovXG4gIERTMl84WExBUkdFID0gJ2RzMi44eGxhcmdlJyxcblxuICAvKipcbiAgICogZGMxLmxhcmdlXG4gICAqL1xuICBEQzFfTEFSR0UgPSAnZGMxLmxhcmdlJyxcblxuICAvKipcbiAgICogZGMxLjh4bGFyZ2VcbiAgICovXG4gIERDMV84WExBUkdFID0gJ2RjMS44eGxhcmdlJyxcblxuICAvKipcbiAgICogZGMyLmxhcmdlXG4gICAqL1xuICBEQzJfTEFSR0UgPSAnZGMyLmxhcmdlJyxcblxuICAvKipcbiAgICogZGMyLjh4bGFyZ2VcbiAgICovXG4gIERDMl84WExBUkdFID0gJ2RjMi44eGxhcmdlJyxcblxuICAvKipcbiAgICogcmEzLmxhcmdlXG4gICAqL1xuICBSQTNfTEFSR0UgPSAncmEzLmxhcmdlJyxcblxuICAvKipcbiAgICogcmEzLnhscGx1c1xuICAgKi9cbiAgUkEzX1hMUExVUyA9ICdyYTMueGxwbHVzJyxcblxuICAvKipcbiAgICogcmEzLjR4bGFyZ2VcbiAgICovXG4gIFJBM180WExBUkdFID0gJ3JhMy40eGxhcmdlJyxcblxuICAvKipcbiAgICogcmEzLjE2eGxhcmdlXG4gICAqL1xuICBSQTNfMTZYTEFSR0UgPSAncmEzLjE2eGxhcmdlJyxcbn1cblxuLyoqXG4gKiBXaGF0IGNsdXN0ZXIgdHlwZSB0byB1c2UuXG4gKiBVc2VkIGJ5IGBDbHVzdGVyUHJvcHMuY2x1c3RlclR5cGVgXG4gKi9cbmV4cG9ydCBlbnVtIENsdXN0ZXJUeXBlIHtcbiAgLyoqXG4gICAqIHNpbmdsZS1ub2RlIGNsdXN0ZXIsIHRoZSBgQ2x1c3RlclByb3BzLm51bWJlck9mTm9kZXNgIHBhcmFtZXRlciBpcyBub3QgcmVxdWlyZWRcbiAgICovXG4gIFNJTkdMRV9OT0RFID0gJ3NpbmdsZS1ub2RlJyxcbiAgLyoqXG4gICAqIG11bHRpLW5vZGUgY2x1c3Rlciwgc2V0IHRoZSBhbW91bnQgb2Ygbm9kZXMgdXNpbmcgYENsdXN0ZXJQcm9wcy5udW1iZXJPZk5vZGVzYCBwYXJhbWV0ZXJcbiAgICovXG4gIE1VTFRJX05PREUgPSAnbXVsdGktbm9kZScsXG59XG5cbi8qKlxuICogVGhlIEFtYXpvbiBSZWRzaGlmdCBvcGVyYXRpb25cbiAqL1xuZXhwb3J0IGVudW0gUmVzb3VyY2VBY3Rpb24ge1xuICAvKipcbiAgICogUGF1c2UgdGhlIGNsdXN0ZXJcbiAgICovXG4gIFBBVVNFX0NMVVNURVIgPSAncGF1c2UtY2x1c3RlcicsXG5cbiAgLyoqXG4gICAqIFJlc3VtZSB0aGUgY2x1c3RlclxuICAgKi9cbiAgUkVTVU1FX0NMVVNURVIgPSAncmVzdW1lLWNsdXN0ZXInLFxuXG4gIC8qKlxuICAgKiBGYWlsaW5nIG92ZXIgdG8gdGhlIG90aGVyIGF2YWlsYWJpbGl0eSB6b25lXG4gICAqXG4gICAqIEBzZWUgaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL3JlZHNoaWZ0L2xhdGVzdC9tZ210L3Rlc3QtY2x1c3Rlci1tdWx0aS1hei5odG1sXG4gICAqL1xuICBGQUlMT1ZFUl9QUklNQVJZX0NPTVBVVEUgPSAnZmFpbG92ZXItcHJpbWFyeS1jb21wdXRlJyxcbn1cblxuLyoqXG4gKiBVc2VybmFtZSBhbmQgcGFzc3dvcmQgY29tYmluYXRpb25cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBMb2dpbiB7XG4gIC8qKlxuICAgKiBVc2VybmFtZVxuICAgKi9cbiAgcmVhZG9ubHkgbWFzdGVyVXNlcm5hbWU6IHN0cmluZztcblxuICAvKipcbiAgICogUGFzc3dvcmRcbiAgICpcbiAgICogRG8gbm90IHB1dCBwYXNzd29yZHMgaW4geW91ciBDREsgY29kZSBkaXJlY3RseS5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBhIFNlY3JldHMgTWFuYWdlciBnZW5lcmF0ZWQgcGFzc3dvcmRcbiAgICovXG4gIHJlYWRvbmx5IG1hc3RlclBhc3N3b3JkPzogU2VjcmV0VmFsdWU7XG5cbiAgLyoqXG4gICAqIEtNUyBlbmNyeXB0aW9uIGtleSB0byBlbmNyeXB0IHRoZSBnZW5lcmF0ZWQgc2VjcmV0LlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIGRlZmF1bHQgbWFzdGVyIGtleVxuICAgKi9cbiAgcmVhZG9ubHkgZW5jcnlwdGlvbktleT86IGttcy5JS2V5O1xuXG4gIC8qKlxuICAgKiBDaGFyYWN0ZXJzIHRvIG5vdCBpbmNsdWRlIGluIHRoZSBnZW5lcmF0ZWQgcGFzc3dvcmQuXG4gICAqXG4gICAqIEBkZWZhdWx0ICdcIkAvXFxcXFxcIFxcJydcbiAgICovXG4gIHJlYWRvbmx5IGV4Y2x1ZGVDaGFyYWN0ZXJzPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIExvZ2dpbmcgYnVja2V0IGFuZCBTMyBwcmVmaXggY29tYmluYXRpb25cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBMb2dnaW5nUHJvcGVydGllcyB7XG4gIC8qKlxuICAgKiBCdWNrZXQgdG8gc2VuZCBsb2dzIHRvLlxuICAgKiBMb2dnaW5nIGluZm9ybWF0aW9uIGluY2x1ZGVzIHF1ZXJpZXMgYW5kIGNvbm5lY3Rpb24gYXR0ZW1wdHMsIGZvciB0aGUgc3BlY2lmaWVkIEFtYXpvbiBSZWRzaGlmdCBjbHVzdGVyLlxuICAgKi9cbiAgcmVhZG9ubHkgbG9nZ2luZ0J1Y2tldDogczMuSUJ1Y2tldDtcblxuICAvKipcbiAgICogUHJlZml4IHVzZWQgZm9yIGxvZ2dpbmcuXG4gICAqL1xuICByZWFkb25seSBsb2dnaW5nS2V5UHJlZml4OiBzdHJpbmc7XG59XG5cbi8qKlxuICogT3B0aW9ucyB0byBhZGQgdGhlIG11bHRpIHVzZXIgcm90YXRpb25cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBSb3RhdGlvbk11bHRpVXNlck9wdGlvbnMge1xuICAvKipcbiAgICogVGhlIHNlY3JldCB0byByb3RhdGUuIEl0IG11c3QgYmUgYSBKU09OIHN0cmluZyB3aXRoIHRoZSBmb2xsb3dpbmcgZm9ybWF0OlxuICAgKiBgYGBcbiAgICoge1xuICAgKiAgIFwiZW5naW5lXCI6IDxyZXF1aXJlZDogZGF0YWJhc2UgZW5naW5lPixcbiAgICogICBcImhvc3RcIjogPHJlcXVpcmVkOiBpbnN0YW5jZSBob3N0IG5hbWU+LFxuICAgKiAgIFwidXNlcm5hbWVcIjogPHJlcXVpcmVkOiB1c2VybmFtZT4sXG4gICAqICAgXCJwYXNzd29yZFwiOiA8cmVxdWlyZWQ6IHBhc3N3b3JkPixcbiAgICogICBcImRibmFtZVwiOiA8b3B0aW9uYWw6IGRhdGFiYXNlIG5hbWU+LFxuICAgKiAgIFwicG9ydFwiOiA8b3B0aW9uYWw6IGlmIG5vdCBzcGVjaWZpZWQsIGRlZmF1bHQgcG9ydCB3aWxsIGJlIHVzZWQ+LFxuICAgKiAgIFwibWFzdGVyYXJuXCI6IDxyZXF1aXJlZDogdGhlIGFybiBvZiB0aGUgbWFzdGVyIHNlY3JldCB3aGljaCB3aWxsIGJlIHVzZWQgdG8gY3JlYXRlIHVzZXJzL2NoYW5nZSBwYXNzd29yZHM+XG4gICAqIH1cbiAgICogYGBgXG4gICAqL1xuICByZWFkb25seSBzZWNyZXQ6IHNlY3JldHNtYW5hZ2VyLklTZWNyZXQ7XG5cbiAgLyoqXG4gICAqIFNwZWNpZmllcyB0aGUgbnVtYmVyIG9mIGRheXMgYWZ0ZXIgdGhlIHByZXZpb3VzIHJvdGF0aW9uIGJlZm9yZVxuICAgKiBTZWNyZXRzIE1hbmFnZXIgdHJpZ2dlcnMgdGhlIG5leHQgYXV0b21hdGljIHJvdGF0aW9uLlxuICAgKlxuICAgKiBAZGVmYXVsdCBEdXJhdGlvbi5kYXlzKDMwKVxuICAgKi9cbiAgcmVhZG9ubHkgYXV0b21hdGljYWxseUFmdGVyPzogRHVyYXRpb247XG59XG5cbi8qKlxuICogVGhlIG1haW50ZW5hbmNlIHRyYWNrIGZvciB0aGUgY2x1c3Rlci5cbiAqXG4gKiBAc2VlIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9yZWRzaGlmdC9sYXRlc3QvbWdtdC9tYW5hZ2luZy1jbHVzdGVyLWNvbnNpZGVyYXRpb25zLmh0bWwjcnMtbWdtdC1tYWludGVuYW5jZS10cmFja3NcbiAqL1xuZXhwb3J0IGVudW0gTWFpbnRlbmFuY2VUcmFja05hbWUge1xuICAvKipcbiAgICogVXBkYXRlZCB0byB0aGUgbW9zdCByZWNlbnRseSBjZXJ0aWZpZWQgbWFpbnRlbmFuY2UgcmVsZWFzZS5cbiAgICovXG4gIENVUlJFTlQgPSAnY3VycmVudCcsXG5cbiAgLyoqXG4gICAqIFVwZGF0ZSB0byB0aGUgcHJldmlvdXNseSBjZXJ0aWZpZWQgbWFpbnRlbmFuY2UgcmVsZWFzZS5cbiAgICovXG4gIFRSQUlMSU5HID0gJ3RyYWlsaW5nJyxcbn1cblxuLyoqXG4gKiBDcmVhdGUgYSBSZWRzaGlmdCBDbHVzdGVyIHdpdGggYSBnaXZlbiBudW1iZXIgb2Ygbm9kZXMuXG4gKiBJbXBsZW1lbnRlZCBieSBgQ2x1c3RlcmAgdmlhIGBDbHVzdGVyQmFzZWAuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgSUNsdXN0ZXIgZXh0ZW5kcyBJUmVzb3VyY2UsIGVjMi5JQ29ubmVjdGFibGUsIHNlY3JldHNtYW5hZ2VyLklTZWNyZXRBdHRhY2htZW50VGFyZ2V0IHtcbiAgLyoqXG4gICAqIE5hbWUgb2YgdGhlIGNsdXN0ZXJcbiAgICpcbiAgICogQGF0dHJpYnV0ZSBDbHVzdGVyTmFtZVxuICAgKi9cbiAgcmVhZG9ubHkgY2x1c3Rlck5hbWU6IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIGVuZHBvaW50IHRvIHVzZSBmb3IgcmVhZC93cml0ZSBvcGVyYXRpb25zXG4gICAqXG4gICAqIEBhdHRyaWJ1dGUgRW5kcG9pbnRBZGRyZXNzLEVuZHBvaW50UG9ydFxuICAgKi9cbiAgcmVhZG9ubHkgY2x1c3RlckVuZHBvaW50OiBFbmRwb2ludDtcbn1cblxuLyoqXG4gKiBQcm9wZXJ0aWVzIHRoYXQgZGVzY3JpYmUgYW4gZXhpc3RpbmcgY2x1c3RlciBpbnN0YW5jZVxuICovXG5leHBvcnQgaW50ZXJmYWNlIENsdXN0ZXJBdHRyaWJ1dGVzIHtcbiAgLyoqXG4gICAqIFRoZSBzZWN1cml0eSBncm91cHMgb2YgdGhlIHJlZHNoaWZ0IGNsdXN0ZXJcbiAgICpcbiAgICogQGRlZmF1bHQgbm8gc2VjdXJpdHkgZ3JvdXBzIHdpbGwgYmUgYXR0YWNoZWQgdG8gdGhlIGltcG9ydFxuICAgKi9cbiAgcmVhZG9ubHkgc2VjdXJpdHlHcm91cHM/OiBlYzIuSVNlY3VyaXR5R3JvdXBbXTtcblxuICAvKipcbiAgICogSWRlbnRpZmllciBmb3IgdGhlIGNsdXN0ZXJcbiAgICovXG4gIHJlYWRvbmx5IGNsdXN0ZXJOYW1lOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIENsdXN0ZXIgZW5kcG9pbnQgYWRkcmVzc1xuICAgKi9cbiAgcmVhZG9ubHkgY2x1c3RlckVuZHBvaW50QWRkcmVzczogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBDbHVzdGVyIGVuZHBvaW50IHBvcnRcbiAgICovXG4gIHJlYWRvbmx5IGNsdXN0ZXJFbmRwb2ludFBvcnQ6IG51bWJlcjtcblxufVxuXG4vKipcbiAqIFByb3BlcnRpZXMgZm9yIGEgbmV3IGRhdGFiYXNlIGNsdXN0ZXJcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBDbHVzdGVyUHJvcHMge1xuICAvKipcbiAgICogQW4gb3B0aW9uYWwgaWRlbnRpZmllciBmb3IgdGhlIGNsdXN0ZXJcbiAgICpcbiAgICogQGRlZmF1bHQgLSBBIG5hbWUgaXMgYXV0b21hdGljYWxseSBnZW5lcmF0ZWQuXG4gICAqL1xuICByZWFkb25seSBjbHVzdGVyTmFtZT86IHN0cmluZztcblxuICAvKipcbiAgICogQWRkaXRpb25hbCBwYXJhbWV0ZXJzIHRvIHBhc3MgdG8gdGhlIGRhdGFiYXNlIGVuZ2luZVxuICAgKiBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vcmVkc2hpZnQvbGF0ZXN0L21nbXQvd29ya2luZy13aXRoLXBhcmFtZXRlci1ncm91cHMuaHRtbFxuICAgKlxuICAgKiBAZGVmYXVsdCAtIE5vIHBhcmFtZXRlciBncm91cC5cbiAgICovXG4gIHJlYWRvbmx5IHBhcmFtZXRlckdyb3VwPzogSUNsdXN0ZXJQYXJhbWV0ZXJHcm91cDtcblxuICAvKipcbiAgICogTnVtYmVyIG9mIGNvbXB1dGUgbm9kZXMgaW4gdGhlIGNsdXN0ZXIuIE9ubHkgc3BlY2lmeSB0aGlzIHByb3BlcnR5IGZvciBtdWx0aS1ub2RlIGNsdXN0ZXJzLlxuICAgKlxuICAgKiBWYWx1ZSBtdXN0IGJlIGF0IGxlYXN0IDIgYW5kIG5vIG1vcmUgdGhhbiAxMDAuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gMiBpZiBgY2x1c3RlclR5cGVgIGlzIENsdXN0ZXJUeXBlLk1VTFRJX05PREUsIHVuZGVmaW5lZCBvdGhlcndpc2VcbiAgICovXG4gIHJlYWRvbmx5IG51bWJlck9mTm9kZXM/OiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIFRoZSBub2RlIHR5cGUgdG8gYmUgcHJvdmlzaW9uZWQgZm9yIHRoZSBjbHVzdGVyLlxuICAgKlxuICAgKiBAZGVmYXVsdCBgTm9kZVR5cGUuREMyX0xBUkdFYFxuICAgKi9cbiAgcmVhZG9ubHkgbm9kZVR5cGU/OiBOb2RlVHlwZTtcblxuICAvKipcbiAgICogU2V0dGluZ3MgZm9yIHRoZSBpbmRpdmlkdWFsIGluc3RhbmNlcyB0aGF0IGFyZSBsYXVuY2hlZFxuICAgKlxuICAgKiBAZGVmYXVsdCBgQ2x1c3RlclR5cGUuTVVMVElfTk9ERWBcbiAgICovXG4gIHJlYWRvbmx5IGNsdXN0ZXJUeXBlPzogQ2x1c3RlclR5cGU7XG5cbiAgLyoqXG4gICAqIFdoYXQgcG9ydCB0byBsaXN0ZW4gb25cbiAgICpcbiAgICogQGRlZmF1bHQgLSBUaGUgZGVmYXVsdCBmb3IgdGhlIGVuZ2luZSBpcyB1c2VkLlxuICAgKi9cbiAgcmVhZG9ubHkgcG9ydD86IG51bWJlcjtcblxuICAvKipcbiAgICogV2hldGhlciB0byBlbmFibGUgZW5jcnlwdGlvbiBvZiBkYXRhIGF0IHJlc3QgaW4gdGhlIGNsdXN0ZXIuXG4gICAqXG4gICAqIEBkZWZhdWx0IHRydWVcbiAgICovXG4gIHJlYWRvbmx5IGVuY3J5cHRlZD86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFRoZSBLTVMga2V5IHRvIHVzZSBmb3IgZW5jcnlwdGlvbiBvZiBkYXRhIGF0IHJlc3QuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gQVdTLW1hbmFnZWQga