@aws-cdk/aws-eks-v2-alpha
Version:
The CDK Construct Library for AWS::EKS
178 lines • 27 kB
JavaScript
;
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ServiceAccount = exports.IdentityType = void 0;
const jsiiDeprecationWarnings = require("../.warnings.jsii.js");
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
const constructs_1 = require("constructs");
// import { FargateCluster } from './index';
const aws_eks_1 = require("aws-cdk-lib/aws-eks");
const k8s_manifest_1 = require("./k8s-manifest");
const aws_iam_1 = require("aws-cdk-lib/aws-iam");
const core_1 = require("aws-cdk-lib/core");
/**
* Enum representing the different identity types that can be used for a Kubernetes service account.
*/
var IdentityType;
(function (IdentityType) {
/**
* Use the IAM Roles for Service Accounts (IRSA) identity type.
* IRSA allows you to associate an IAM role with a Kubernetes service account.
* This provides a way to grant permissions to Kubernetes pods by associating an IAM role with a Kubernetes service account.
* The IAM role can then be used to provide AWS credentials to the pods, allowing them to access other AWS resources.
*
* When enabled, the openIdConnectProvider of the cluster would be created when you create the ServiceAccount.
*
* @see https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html
*/
IdentityType["IRSA"] = "IRSA";
/**
* Use the EKS Pod Identities identity type.
* EKS Pod Identities provide the ability to manage credentials for your applications, similar to the way that Amazon EC2 instance profiles
* provide credentials to Amazon EC2 instances. Instead of creating and distributing your AWS credentials to the containers or using the
* Amazon EC2 instance's role, you associate an IAM role with a Kubernetes service account and configure your Pods to use the service account.
*
* When enabled, the Pod Identity Agent AddOn of the cluster would be created when you create the ServiceAccount.
*
* @see https://docs.aws.amazon.com/eks/latest/userguide/pod-identities.html
*/
IdentityType["POD_IDENTITY"] = "POD_IDENTITY";
})(IdentityType || (exports.IdentityType = IdentityType = {}));
/**
* Service Account
*/
class ServiceAccount extends constructs_1.Construct {
constructor(scope, id, props) {
super(scope, id);
try {
jsiiDeprecationWarnings._aws_cdk_aws_eks_v2_alpha_ServiceAccountProps(props);
}
catch (error) {
if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
Error.captureStackTrace(error, ServiceAccount);
}
throw error;
}
const { cluster } = props;
this.serviceAccountName = props.name ?? core_1.Names.uniqueId(this).toLowerCase();
this.serviceAccountNamespace = props.namespace ?? 'default';
// From K8s docs: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
if (!this.isValidDnsSubdomainName(this.serviceAccountName)) {
throw RangeError('The name of a ServiceAccount object must be a valid DNS subdomain name.');
}
// From K8s docs: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/#namespaces-and-dns
if (!this.isValidDnsLabelName(this.serviceAccountNamespace)) {
throw RangeError('All namespace names must be valid RFC 1123 DNS labels.');
}
let principal;
if (props.identityType !== IdentityType.POD_IDENTITY) {
/* Add conditions to the role to improve security. This prevents other pods in the same namespace to assume the role.
* See documentation: https://docs.aws.amazon.com/eks/latest/userguide/create-service-account-iam-policy-and-role.html
*/
const conditions = new core_1.CfnJson(this, 'ConditionJson', {
value: {
[`${cluster.openIdConnectProvider.openIdConnectProviderIssuer}:aud`]: 'sts.amazonaws.com',
[`${cluster.openIdConnectProvider.openIdConnectProviderIssuer}:sub`]: `system:serviceaccount:${this.serviceAccountNamespace}:${this.serviceAccountName}`,
},
});
principal = new aws_iam_1.OpenIdConnectPrincipal(cluster.openIdConnectProvider).withConditions({
StringEquals: conditions,
});
}
else {
/**
* Identity type is POD_IDENTITY.
* Create a service principal with "Service": "pods.eks.amazonaws.com"
* See https://docs.aws.amazon.com/eks/latest/userguide/pod-identities.html
*/
// EKS Pod Identity does not support Fargate
// TODO: raise an error when using Fargate
principal = new aws_iam_1.ServicePrincipal('pods.eks.amazonaws.com');
}
const role = new aws_iam_1.Role(this, 'Role', { assumedBy: principal });
// pod identities requires 'sts:TagSession' in its principal actions
if (props.identityType === IdentityType.POD_IDENTITY) {
/**
* EKS Pod Identities requires both assumed role actions otherwise it would fail.
*/
role.assumeRolePolicy.addStatements(new aws_iam_1.PolicyStatement({
actions: ['sts:AssumeRole', 'sts:TagSession'],
principals: [new aws_iam_1.ServicePrincipal('pods.eks.amazonaws.com')],
}));
// ensure the pod identity agent
cluster.eksPodIdentityAgent;
// associate this service account with the pod role we just created for the cluster
new aws_eks_1.CfnPodIdentityAssociation(this, 'Association', {
clusterName: cluster.clusterName,
namespace: props.namespace ?? 'default',
roleArn: role.roleArn,
serviceAccount: this.serviceAccountName,
});
}
this.role = role;
this.assumeRoleAction = this.role.assumeRoleAction;
this.grantPrincipal = this.role.grantPrincipal;
this.policyFragment = this.role.policyFragment;
// Note that we cannot use `cluster.addManifest` here because that would create the manifest
// constrct in the scope of the cluster stack, which might be a different stack than this one.
// This means that the cluster stack would depend on this stack because of the role,
// and since this stack inherintely depends on the cluster stack, we will have a circular dependency.
new k8s_manifest_1.KubernetesManifest(this, `manifest-${id}ServiceAccountResource`, {
cluster,
manifest: [{
apiVersion: 'v1',
kind: 'ServiceAccount',
metadata: {
name: this.serviceAccountName,
namespace: this.serviceAccountNamespace,
labels: {
'app.kubernetes.io/name': this.serviceAccountName,
...props.labels,
},
annotations: {
'eks.amazonaws.com/role-arn': this.role.roleArn,
...props.annotations,
},
},
}],
});
}
/**
* @deprecated use `addToPrincipalPolicy()`
*/
addToPolicy(statement) {
try {
jsiiDeprecationWarnings.print("@aws-cdk/aws-eks-v2-alpha.ServiceAccount#addToPolicy", "use `addToPrincipalPolicy()`");
}
catch (error) {
if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
Error.captureStackTrace(error, this.addToPolicy);
}
throw error;
}
return this.addToPrincipalPolicy(statement).statementAdded;
}
addToPrincipalPolicy(statement) {
return this.role.addToPrincipalPolicy(statement);
}
/**
* If the value is a DNS subdomain name as defined in RFC 1123, from K8s docs.
*
* https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-subdomain-names
*/
isValidDnsSubdomainName(value) {
return value.length <= 253 && /^[a-z0-9]+[a-z0-9-.]*[a-z0-9]+$/.test(value);
}
/**
* If the value follows DNS label standard as defined in RFC 1123, from K8s docs.
*
* https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-label-names
*/
isValidDnsLabelName(value) {
return value.length <= 63 && /^[a-z0-9]+[a-z0-9-]*[a-z0-9]+$/.test(value);
}
}
exports.ServiceAccount = ServiceAccount;
_a = JSII_RTTI_SYMBOL_1;
ServiceAccount[_a] = { fqn: "@aws-cdk/aws-eks-v2-alpha.ServiceAccount", version: "2.208.0-alpha.0" };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmljZS1hY2NvdW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsic2VydmljZS1hY2NvdW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLDJDQUF1QztBQUV2Qyw0Q0FBNEM7QUFDNUMsaURBQWdFO0FBQ2hFLGlEQUFvRDtBQUNwRCxpREFHNkI7QUFDN0IsMkNBQWtEO0FBRWxEOztHQUVHO0FBQ0gsSUFBWSxZQXdCWDtBQXhCRCxXQUFZLFlBQVk7SUFDdEI7Ozs7Ozs7OztPQVNHO0lBQ0gsNkJBQWEsQ0FBQTtJQUViOzs7Ozs7Ozs7T0FTRztJQUNILDZDQUE2QixDQUFBO0FBQy9CLENBQUMsRUF4QlcsWUFBWSw0QkFBWixZQUFZLFFBd0J2QjtBQXdGRDs7R0FFRztBQUNILE1BQWEsY0FBZSxTQUFRLHNCQUFTO0lBb0IzQyxZQUFZLEtBQWdCLEVBQUUsRUFBVSxFQUFFLEtBQTBCO1FBQ2xFLEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7Ozs7OzsrQ0FyQlIsY0FBYzs7OztRQXVCdkIsTUFBTSxFQUFFLE9BQU8sRUFBRSxHQUFHLEtBQUssQ0FBQztRQUMxQixJQUFJLENBQUMsa0JBQWtCLEdBQUcsS0FBSyxDQUFDLElBQUksSUFBSSxZQUFLLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBQzNFLElBQUksQ0FBQyx1QkFBdUIsR0FBRyxLQUFLLENBQUMsU0FBUyxJQUFJLFNBQVMsQ0FBQztRQUU1RCxxR0FBcUc7UUFDckcsSUFBSSxDQUFDLElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxJQUFJLENBQUMsa0JBQWtCLENBQUMsRUFBRSxDQUFDO1lBQzNELE1BQU0sVUFBVSxDQUFDLHlFQUF5RSxDQUFDLENBQUM7UUFDOUYsQ0FBQztRQUVELGtIQUFrSDtRQUNsSCxJQUFJLENBQUMsSUFBSSxDQUFDLG1CQUFtQixDQUFDLElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxFQUFFLENBQUM7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QkFDaEI7d0JBQ0QsV0FBVyxFQUFFOzRCQUNYLDRCQUE0QixFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTzs0QkFDL0MsR0FBRyxLQUFLLENBQUMsV0FBVzt5QkFDckI7cUJBQ0Y7aUJBQ0YsQ0FBQztTQUNILENBQUMsQ0FBQztLQUNKO0lBRUQ7O09BRUc7SUFDSSxXQUFXLENBQUMsU0FBMEI7Ozs7Ozs7Ozs7UUFDM0MsT0FBTyxJQUFJLENBQUMsb0JBQW9CLENBQUMsU0FBUyxDQUFDLENBQUMsY0FBYyxDQUFDO0tBQzVEO0lBRU0sb0JBQW9CLENBQUMsU0FBMEI7UUFDcEQsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLG9CQUFvQixDQUFDLFNBQVMsQ0FBQyxDQUFDO0tBQ2xEO0lBRUQ7Ozs7T0FJRztJQUNLLHVCQUF1QixDQUFDLEtBQWE7UUFDM0MsT0FBTyxLQUFLLENBQUMsTUFBTSxJQUFJLEdBQUcsSUFBSSxpQ0FBaUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7S0FDN0U7SUFFRDs7OztPQUlHO0lBQ0ssbUJBQW1CLENBQUMsS0FBYTtRQUN2QyxPQUFPLEtBQUssQ0FBQyxNQUFNLElBQUksRUFBRSxJQUFJLGdDQUFnQyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztLQUMzRTs7QUFqSkgsd0NBa0pDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSAnY29uc3RydWN0cyc7XG5pbXBvcnQgeyBJQ2x1c3RlciB9IGZyb20gJy4vY2x1c3Rlcic7XG4vLyBpbXBvcnQgeyBGYXJnYXRlQ2x1c3RlciB9IGZyb20gJy4vaW5kZXgnO1xuaW1wb3J0IHsgQ2ZuUG9kSWRlbnRpdHlBc3NvY2lhdGlvbiB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1la3MnO1xuaW1wb3J0IHsgS3ViZXJuZXRlc01hbmlmZXN0IH0gZnJvbSAnLi9rOHMtbWFuaWZlc3QnO1xuaW1wb3J0IHtcbiAgQWRkVG9QcmluY2lwYWxQb2xpY3lSZXN1bHQsIElQcmluY2lwYWwsIElSb2xlLCBPcGVuSWRDb25uZWN0UHJpbmNpcGFsLCBQb2xpY3lTdGF0ZW1lbnQsIFByaW5jaXBhbFBvbGljeUZyYWdtZW50LCBSb2xlLFxuICBTZXJ2aWNlUHJpbmNpcGFsLFxufSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtaWFtJztcbmltcG9ydCB7IENmbkpzb24sIE5hbWVzIH0gZnJvbSAnYXdzLWNkay1saWIvY29yZSc7XG5cbi8qKlxuICogRW51bSByZXByZXNlbnRpbmcgdGhlIGRpZmZlcmVudCBpZGVudGl0eSB0eXBlcyB0aGF0IGNhbiBiZSB1c2VkIGZvciBhIEt1YmVybmV0ZXMgc2VydmljZSBhY2NvdW50LlxuICovXG5leHBvcnQgZW51bSBJZGVudGl0eVR5cGUge1xuICAvKipcbiAgICogVXNlIHRoZSBJQU0gUm9sZXMgZm9yIFNlcnZpY2UgQWNjb3VudHMgKElSU0EpIGlkZW50aXR5IHR5cGUuXG4gICAqIElSU0EgYWxsb3dzIHlvdSB0byBhc3NvY2lhdGUgYW4gSUFNIHJvbGUgd2l0aCBhIEt1YmVybmV0ZXMgc2VydmljZSBhY2NvdW50LlxuICAgKiBUaGlzIHByb3ZpZGVzIGEgd2F5IHRvIGdyYW50IHBlcm1pc3Npb25zIHRvIEt1YmVybmV0ZXMgcG9kcyBieSBhc3NvY2lhdGluZyBhbiBJQU0gcm9sZSB3aXRoIGEgS3ViZXJuZXRlcyBzZXJ2aWNlIGFjY291bnQuXG4gICAqIFRoZSBJQU0gcm9sZSBjYW4gdGhlbiBiZSB1c2VkIHRvIHByb3ZpZGUgQVdTIGNyZWRlbnRpYWxzIHRvIHRoZSBwb2RzLCBhbGxvd2luZyB0aGVtIHRvIGFjY2VzcyBvdGhlciBBV1MgcmVzb3VyY2VzLlxuICAgKlxuICAgKiBXaGVuIGVuYWJsZWQsIHRoZSBvcGVuSWRDb25uZWN0UHJvdmlkZXIgb2YgdGhlIGNsdXN0ZXIgd291bGQgYmUgY3JlYXRlZCB3aGVuIHlvdSBjcmVhdGUgdGhlIFNlcnZpY2VBY2NvdW50LlxuICAgKlxuICAgKiBAc2VlIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9la3MvbGF0ZXN0L3VzZXJndWlkZS9pYW0tcm9sZXMtZm9yLXNlcnZpY2UtYWNjb3VudHMuaHRtbFxuICAgKi9cbiAgSVJTQSA9ICdJUlNBJyxcblxuICAvKipcbiAgICogVXNlIHRoZSBFS1MgUG9kIElkZW50aXRpZXMgaWRlbnRpdHkgdHlwZS5cbiAgICogRUtTIFBvZCBJZGVudGl0aWVzIHByb3ZpZGUgdGhlIGFiaWxpdHkgdG8gbWFuYWdlIGNyZWRlbnRpYWxzIGZvciB5b3VyIGFwcGxpY2F0aW9ucywgc2ltaWxhciB0byB0aGUgd2F5IHRoYXQgQW1hem9uIEVDMiBpbnN0YW5jZSBwcm9maWxlc1xuICAgKiBwcm92aWRlIGNyZWRlbnRpYWxzIHRvIEFtYXpvbiBFQzIgaW5zdGFuY2VzLiBJbnN0ZWFkIG9mIGNyZWF0aW5nIGFuZCBkaXN0cmlidXRpbmcgeW91ciBBV1MgY3JlZGVudGlhbHMgdG8gdGhlIGNvbnRhaW5lcnMgb3IgdXNpbmcgdGhlXG4gICAqIEFtYXpvbiBFQzIgaW5zdGFuY2UncyByb2xlLCB5b3UgYXNzb2NpYXRlIGFuIElBTSByb2xlIHdpdGggYSBLdWJlcm5ldGVzIHNlcnZpY2UgYWNjb3VudCBhbmQgY29uZmlndXJlIHlvdXIgUG9kcyB0byB1c2UgdGhlIHNlcnZpY2UgYWNjb3VudC5cbiAgICpcbiAgICogV2hlbiBlbmFibGVkLCB0aGUgUG9kIElkZW50aXR5IEFnZW50IEFkZE9uIG9mIHRoZSBjbHVzdGVyIHdvdWxkIGJlIGNyZWF0ZWQgd2hlbiB5b3UgY3JlYXRlIHRoZSBTZXJ2aWNlQWNjb3VudC5cbiAgICpcbiAgICogQHNlZSBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vZWtzL2xhdGVzdC91c2VyZ3VpZGUvcG9kLWlkZW50aXRpZXMuaHRtbFxuICAgKi9cbiAgUE9EX0lERU5USVRZID0gJ1BPRF9JREVOVElUWScsXG59XG5cbi8qKlxuICogT3B0aW9ucyBmb3IgYFNlcnZpY2VBY2NvdW50YFxuICovXG5leHBvcnQgaW50ZXJmYWNlIFNlcnZpY2VBY2NvdW50T3B0aW9ucyB7XG4gIC8qKlxuICAgKiBUaGUgbmFtZSBvZiB0aGUgc2VydmljZSBhY2NvdW50LlxuICAgKlxuICAgKiBUaGUgbmFtZSBvZiBhIFNlcnZpY2VBY2NvdW50IG9iamVjdCBtdXN0IGJlIGEgdmFsaWQgRE5TIHN1YmRvbWFpbiBuYW1lLlxuICAgKiBodHRwczovL2t1YmVybmV0ZXMuaW8vZG9jcy90YXNrcy9jb25maWd1cmUtcG9kLWNvbnRhaW5lci9jb25maWd1cmUtc2VydmljZS1hY2NvdW50L1xuICAgKiBAZGVmYXVsdCAtIElmIG5vIG5hbWUgaXMgZ2l2ZW4sIGl0IHdpbGwgdXNlIHRoZSBpZCBvZiB0aGUgcmVzb3VyY2UuXG4gICAqL1xuICByZWFkb25seSBuYW1lPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgbmFtZXNwYWNlIG9mIHRoZSBzZXJ2aWNlIGFjY291bnQuXG4gICAqXG4gICAqIEFsbCBuYW1lc3BhY2UgbmFtZXMgbXVzdCBiZSB2YWxpZCBSRkMgMTEyMyBETlMgbGFiZWxzLlxuICAgKiBodHRwczovL2t1YmVybmV0ZXMuaW8vZG9jcy9jb25jZXB0cy9vdmVydmlldy93b3JraW5nLXdpdGgtb2JqZWN0cy9uYW1lc3BhY2VzLyNuYW1lc3BhY2VzLWFuZC1kbnNcbiAgICogQGRlZmF1bHQgXCJkZWZhdWx0XCJcbiAgICovXG4gIHJlYWRvbmx5IG5hbWVzcGFjZT86IHN0cmluZztcblxuICAvKipcbiAgICogQWRkaXRpb25hbCBhbm5vdGF0aW9ucyBvZiB0aGUgc2VydmljZSBhY2NvdW50LlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIG5vIGFkZGl0aW9uYWwgYW5ub3RhdGlvbnNcbiAgICovXG4gIHJlYWRvbmx5IGFubm90YXRpb25zPzogeyBba2V5OiBzdHJpbmddOiBzdHJpbmcgfTtcblxuICAvKipcbiAgICogQWRkaXRpb25hbCBsYWJlbHMgb2YgdGhlIHNlcnZpY2UgYWNjb3VudC5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBubyBhZGRpdGlvbmFsIGxhYmVsc1xuICAgKi9cbiAgcmVhZG9ubHkgbGFiZWxzPzogeyBba2V5OiBzdHJpbmddOiBzdHJpbmcgfTtcblxuICAvKipcbiAgICogVGhlIGlkZW50aXR5IHR5cGUgdG8gdXNlIGZvciB0aGUgc2VydmljZSBhY2NvdW50LlxuICAgKiBAZGVmYXVsdCBJZGVudGl0eVR5cGUuSVJTQVxuICAgKi9cbiAgcmVhZG9ubHkgaWRlbnRpdHlUeXBlPzogSWRlbnRpdHlUeXBlO1xufVxuZXhwb3J0IGludGVyZmFjZSBTZXJ2aWNlQWNjb3VudE9wdGlvbnMge1xuICAvKipcbiAgICogVGhlIG5hbWUgb2YgdGhlIHNlcnZpY2UgYWNjb3VudC5cbiAgICpcbiAgICogVGhlIG5hbWUgb2YgYSBTZXJ2aWNlQWNjb3VudCBvYmplY3QgbXVzdCBiZSBhIHZhbGlkIEROUyBzdWJkb21haW4gbmFtZS5cbiAgICogaHR0cHM6Ly9rdWJlcm5ldGVzLmlvL2RvY3MvdGFza3MvY29uZmlndXJlLXBvZC1jb250YWluZXIvY29uZmlndXJlLXNlcnZpY2UtYWNjb3VudC9cbiAgICogQGRlZmF1bHQgLSBJZiBubyBuYW1lIGlzIGdpdmVuLCBpdCB3aWxsIHVzZSB0aGUgaWQgb2YgdGhlIHJlc291cmNlLlxuICAgKi9cbiAgcmVhZG9ubHkgbmFtZT86IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIG5hbWVzcGFjZSBvZiB0aGUgc2VydmljZSBhY2NvdW50LlxuICAgKlxuICAgKiBBbGwgbmFtZXNwYWNlIG5hbWVzIG11c3QgYmUgdmFsaWQgUkZDIDExMjMgRE5TIGxhYmVscy5cbiAgICogaHR0cHM6Ly9rdWJlcm5ldGVzLmlvL2RvY3MvY29uY2VwdHMvb3ZlcnZpZXcvd29ya2luZy13aXRoLW9iamVjdHMvbmFtZXNwYWNlcy8jbmFtZXNwYWNlcy1hbmQtZG5zXG4gICAqIEBkZWZhdWx0IFwiZGVmYXVsdFwiXG4gICAqL1xuICByZWFkb25seSBuYW1lc3BhY2U/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEFkZGl0aW9uYWwgYW5ub3RhdGlvbnMgb2YgdGhlIHNlcnZpY2UgYWNjb3VudC5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBubyBhZGRpdGlvbmFsIGFubm90YXRpb25zXG4gICAqL1xuICByZWFkb25seSBhbm5vdGF0aW9ucz86IHtba2V5OnN0cmluZ106IHN0cmluZ307XG5cbiAgLyoqXG4gICAqIEFkZGl0aW9uYWwgbGFiZWxzIG9mIHRoZSBzZXJ2aWNlIGFjY291bnQuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gbm8gYWRkaXRpb25hbCBsYWJlbHNcbiAgICovXG4gIHJlYWRvbmx5IGxhYmVscz86IHtba2V5OnN0cmluZ106IHN0cmluZ307XG59XG5cbi8qKlxuICogUHJvcGVydGllcyBmb3IgZGVmaW5pbmcgc2VydmljZSBhY2NvdW50c1xuICovXG5leHBvcnQgaW50ZXJmYWNlIFNlcnZpY2VBY2NvdW50UHJvcHMgZXh0ZW5kcyBTZXJ2aWNlQWNjb3VudE9wdGlvbnMge1xuICAvKipcbiAgICogVGhlIGNsdXN0ZXIgdG8gYXBwbHkgdGhlIHBhdGNoIHRvLlxuICAgKi9cbiAgcmVhZG9ubHkgY2x1c3RlcjogSUNsdXN0ZXI7XG59XG5cbi8qKlxuICogU2VydmljZSBBY2NvdW50XG4gKi9cbmV4cG9ydCBjbGFzcyBTZXJ2aWNlQWNjb3VudCBleHRlbmRzIENvbnN0cnVjdCBpbXBsZW1lbnRzIElQcmluY2lwYWwge1xuICAvKipcbiAgICogVGhlIHJvbGUgd2hpY2ggaXMgbGlua2VkIHRvIHRoZSBzZXJ2aWNlIGFjY291bnQuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgcm9sZTogSVJvbGU7XG5cbiAgcHVibGljIHJlYWRvbmx5IGFzc3VtZVJvbGVBY3Rpb246IHN0cmluZztcbiAgcHVibGljIHJlYWRvbmx5IGdyYW50UHJpbmNpcGFsOiBJUHJpbmNpcGFsO1xuICBwdWJsaWMgcmVhZG9ubHkgcG9saWN5RnJhZ21lbnQ6IFByaW5jaXBhbFBvbGljeUZyYWdtZW50O1xuXG4gIC8qKlxuICAgKiBUaGUgbmFtZSBvZiB0aGUgc2VydmljZSBhY2NvdW50LlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IHNlcnZpY2VBY2NvdW50TmFtZTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgbmFtZXNwYWNlIHdoZXJlIHRoZSBzZXJ2aWNlIGFjY291bnQgaXMgbG9jYXRlZCBpbi5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBzZXJ2aWNlQWNjb3VudE5hbWVzcGFjZTogc3RyaW5nO1xuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBTZXJ2aWNlQWNjb3VudFByb3BzKSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkKTtcblxuICAgIGNvbnN0IHsgY2x1c3RlciB9ID0gcHJvcHM7XG4gICAgdGhpcy5zZXJ2aWNlQWNjb3VudE5hbWUgPSBwcm9wcy5uYW1lID8/IE5hbWVzLnVuaXF1ZUlkKHRoaXMpLnRvTG93ZXJDYXNlKCk7XG4gICAgdGhpcy5zZXJ2aWNlQWNjb3VudE5hbWVzcGFjZSA9IHByb3BzLm5hbWVzcGFjZSA/PyAnZGVmYXVsdCc7XG5cbiAgICAvLyBGcm9tIEs4cyBkb2NzOiBodHRwczovL2t1YmVybmV0ZXMuaW8vZG9jcy90YXNrcy9jb25maWd1cmUtcG9kLWNvbnRhaW5lci9jb25maWd1cmUtc2VydmljZS1hY2NvdW50L1xuICAgIGlmICghdGhpcy5pc1ZhbGlkRG5zU3ViZG9tYWluTmFtZSh0aGlzLnNlcnZpY2VBY2NvdW50TmFtZSkpIHtcbiAgICAgIHRocm93IFJhbmdlRXJyb3IoJ1RoZSBuYW1lIG9mIGEgU2VydmljZUFjY291bnQgb2JqZWN0IG11c3QgYmUgYSB2YWxpZCBETlMgc3ViZG9tYWluIG5hbWUuJyk7XG4gICAgfVxuXG4gICAgLy8gRnJvbSBLOHMgZG9jczogaHR0cHM6Ly9rdWJlcm5ldGVzLmlvL2RvY3MvY29uY2VwdHMvb3ZlcnZpZXcvd29ya2luZy13aXRoLW9iamVjdHMvbmFtZXNwYWNlcy8jbmFtZXNwYWNlcy1hbmQtZG5zXG4gICAgaWYgKCF0aGlzLmlzVmFsaWREbnNMYWJlbE5hbWUodGhpcy5zZXJ2aWNlQWNjb3VudE5hbWVzcGFjZSkpIHtcbiAgICAgIHRocm93IFJhbmdlRXJyb3IoJ0FsbCBuYW1lc3BhY2UgbmFtZXMgbXVzdCBiZSB2YWxpZCBSRkMgMTEyMyBETlMgbGFiZWxzLicpO1xuICAgIH1cblxuICAgIGxldCBwcmluY2lwYWw6IElQcmluY2lwYWw7XG4gICAgaWYgKHByb3BzLmlkZW50aXR5VHlwZSAhPT0gSWRlbnRpdHlUeXBlLlBPRF9JREVOVElUWSkge1xuICAgICAgLyogQWRkIGNvbmRpdGlvbnMgdG8gdGhlIHJvbGUgdG8gaW1wcm92ZSBzZWN1cml0eS4gVGhpcyBwcmV2ZW50cyBvdGhlciBwb2RzIGluIHRoZSBzYW1lIG5hbWVzcGFjZSB0byBhc3N1bWUgdGhlIHJvbGUuXG4gICAgICAqIFNlZSBkb2N1bWVudGF0aW9uOiBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vZWtzL2xhdGVzdC91c2VyZ3VpZGUvY3JlYXRlLXNlcnZpY2UtYWNjb3VudC1pYW0tcG9saWN5LWFuZC1yb2xlLmh0bWxcbiAgICAgICovXG4gICAgICBjb25zdCBjb25kaXRpb25zID0gbmV3IENmbkpzb24odGhpcywgJ0NvbmRpdGlvbkpzb24nLCB7XG4gICAgICAgIHZhbHVlOiB7XG4gICAgICAgICAgW2Ake2NsdXN0ZXIub3BlbklkQ29ubmVjdFByb3ZpZGVyLm9wZW5JZENvbm5lY3RQcm92aWRlcklzc3Vlcn06YXVkYF06ICdzdHMuYW1hem9uYXdzLmNvbScsXG4gICAgICAgICAgW2Ake2NsdXN0ZXIub3BlbklkQ29ubmVjdFByb3ZpZGVyLm9wZW5JZENvbm5lY3RQcm92aWRlcklzc3Vlcn06c3ViYF06IGBzeXN0ZW06c2VydmljZWFjY291bnQ6JHt0aGlzLnNlcnZpY2VBY2NvdW50TmFtZXNwYWNlfToke3RoaXMuc2VydmljZUFjY291bnROYW1lfWAsXG4gICAgICAgIH0sXG4gICAgICB9KTtcbiAgICAgIHByaW5jaXBhbCA9IG5ldyBPcGVuSWRDb25uZWN0UHJpbmNpcGFsKGNsdXN0ZXIub3BlbklkQ29ubmVjdFByb3ZpZGVyKS53aXRoQ29uZGl0aW9ucyh7XG4gICAgICAgIFN0cmluZ0VxdWFsczogY29uZGl0aW9ucyxcbiAgICAgIH0pO1xuICAgIH0gZWxzZSB7XG4gICAgICAvKipcbiAgICAgICAqIElkZW50aXR5IHR5cGUgaXMgUE9EX0lERU5USVRZLlxuICAgICAgICogQ3JlYXRlIGEgc2VydmljZSBwcmluY2lwYWwgd2l0aCBcIlNlcnZpY2VcIjogXCJwb2RzLmVrcy5hbWF6b25hd3MuY29tXCJcbiAgICAgICAqIFNlZSBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vZWtzL2xhdGVzdC91c2VyZ3VpZGUvcG9kLWlkZW50aXRpZXMuaHRtbFxuICAgICAgICovXG5cbiAgICAgIC8vIEVLUyBQb2QgSWRlbnRpdHkgZG9lcyBub3Qgc3VwcG9ydCBGYXJnYXRlXG4gICAgICAvLyBUT0RPOiByYWlzZSBhbiBlcnJvciB3aGVuIHVzaW5nIEZhcmdhdGVcbiAgICAgIHByaW5jaXBhbCA9IG5ldyBTZXJ2aWNlUHJpbmNpcGFsKCdwb2RzLmVrcy5hbWF6b25hd3MuY29tJyk7XG4gICAgfVxuXG4gICAgY29uc3Qgcm9sZSA9IG5ldyBSb2xlKHRoaXMsICdSb2xlJywgeyBhc3N1bWVkQnk6IHByaW5jaXBhbCB9KTtcblxuICAgIC8vIHBvZCBpZGVudGl0aWVzIHJlcXVpcmVzICdzdHM6VGFnU2Vzc2lvbicgaW4gaXRzIHByaW5jaXBhbCBhY3Rpb25zXG4gICAgaWYgKHByb3BzLmlkZW50aXR5VHlwZSA9PT0gSWRlbnRpdHlUeXBlLlBPRF9JREVOVElUWSkge1xuICAgICAgLyoqXG4gICAgICAgKiBFS1MgUG9kIElkZW50aXRpZXMgcmVxdWlyZXMgYm90aCBhc3N1bWVkIHJvbGUgYWN0aW9ucyBvdGhlcndpc2UgaXQgd291bGQgZmFpbC5cbiAgICAgICAqL1xuICAgICAgcm9sZS5hc3N1bWVSb2xlUG9saWN5IS5hZGRTdGF0ZW1lbnRzKG5ldyBQb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICBhY3Rpb25zOiBbJ3N0czpBc3N1bWVSb2xlJywgJ3N0czpUYWdTZXNzaW9uJ10sXG4gICAgICAgIHByaW5jaXBhbHM6IFtuZXcgU2VydmljZVByaW5jaXBhbCgncG9kcy5la3MuYW1hem9uYXdzLmNvbScpXSxcbiAgICAgIH0pKTtcblxuICAgICAgLy8gZW5zdXJlIHRoZSBwb2QgaWRlbnRpdHkgYWdlbnRcbiAgICAgIGNsdXN0ZXIuZWtzUG9kSWRlbnRpdHlBZ2VudDtcblxuICAgICAgLy8gYXNzb2NpYXRlIHRoaXMgc2VydmljZSBhY2NvdW50IHdpdGggdGhlIHBvZCByb2xlIHdlIGp1c3QgY3JlYXRlZCBmb3IgdGhlIGNsdXN0ZXJcbiAgICAgIG5ldyBDZm5Qb2RJZGVudGl0eUFzc29jaWF0aW9uKHRoaXMsICdBc3NvY2lhdGlvbicsIHtcbiAgICAgICAgY2x1c3Rlck5hbWU6IGNsdXN0ZXIuY2x1c3Rlck5hbWUsXG4gICAgICAgIG5hbWVzcGFjZTogcHJvcHMubmFtZXNwYWNlID8/ICdkZWZhdWx0JyxcbiAgICAgICAgcm9sZUFybjogcm9sZS5yb2xlQXJuLFxuICAgICAgICBzZXJ2aWNlQWNjb3VudDogdGhpcy5zZXJ2aWNlQWNjb3VudE5hbWUsXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICB0aGlzLnJvbGUgPSByb2xlO1xuXG4gICAgdGhpcy5hc3N1bWVSb2xlQWN0aW9uID0gdGhpcy5yb2xlLmFzc3VtZVJvbGVBY3Rpb247XG4gICAgdGhpcy5ncmFudFByaW5jaXBhbCA9IHRoaXMucm9sZS5ncmFudFByaW5jaXBhbDtcbiAgICB0aGlzLnBvbGljeUZyYWdtZW50ID0gdGhpcy5yb2xlLnBvbGljeUZyYWdtZW50O1xuXG4gICAgLy8gTm90ZSB0aGF0IHdlIGNhbm5vdCB1c2UgYGNsdXN0ZXIuYWRkTWFuaWZlc3RgIGhlcmUgYmVjYXVzZSB0aGF0IHdvdWxkIGNyZWF0ZSB0aGUgbWFuaWZlc3RcbiAgICAvLyBjb25zdHJjdCBpbiB0aGUgc2NvcGUgb2YgdGhlIGNsdXN0ZXIgc3RhY2ssIHdoaWNoIG1pZ2h0IGJlIGEgZGlmZmVyZW50IHN0YWNrIHRoYW4gdGhpcyBvbmUuXG4gICAgLy8gVGhpcyBtZWFucyB0aGF0IHRoZSBjbHVzdGVyIHN0YWNrIHdvdWxkIGRlcGVuZCBvbiB0aGlzIHN0YWNrIGJlY2F1c2Ugb2YgdGhlIHJvbGUsXG4gICAgLy8gYW5kIHNpbmNlIHRoaXMgc3RhY2sgaW5oZXJpbnRlbHkgZGVwZW5kcyBvbiB0aGUgY2x1c3RlciBzdGFjaywgd2Ugd2lsbCBoYXZlIGEgY2lyY3VsYXIgZGVwZW5kZW5jeS5cbiAgICBuZXcgS3ViZXJuZXRlc01hbmlmZXN0KHRoaXMsIGBtYW5pZmVzdC0ke2lkfVNlcnZpY2VBY2NvdW50UmVzb3VyY2VgLCB7XG4gICAgICBjbHVzdGVyLFxuICAgICAgbWFuaWZlc3Q6IFt7XG4gICAgICAgIGFwaVZlcnNpb246ICd2MScsXG4gICAgICAgIGtpbmQ6ICdTZXJ2aWNlQWNjb3VudCcsXG4gICAgICAgIG1ldGFkYXRhOiB7XG4gICAgICAgICAgbmFtZTogdGhpcy5zZXJ2aWNlQWNjb3VudE5hbWUsXG4gICAgICAgICAgbmFtZXNwYWNlOiB0aGlzLnNlcnZpY2VBY2NvdW50TmFtZXNwYWNlLFxuICAgICAgICAgIGxhYmVsczoge1xuICAgICAgICAgICAgJ2FwcC5rdWJlcm5ldGVzLmlvL25hbWUnOiB0aGlzLnNlcnZpY2VBY2NvdW50TmFtZSxcbiAgICAgICAgICAgIC4uLnByb3BzLmxhYmVscyxcbiAgICAgICAgICB9LFxuICAgICAgICAgIGFubm90YXRpb25zOiB7XG4gICAgICAgICAgICAnZWtzLmFtYXpvbmF3cy5jb20vcm9sZS1hcm4nOiB0aGlzLnJvbGUucm9sZUFybixcbiAgICAgICAgICAgIC4uLnByb3BzLmFubm90YXRpb25zLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICB9XSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVwcmVjYXRlZCB1c2UgYGFkZFRvUHJpbmNpcGFsUG9saWN5KClgXG4gICAqL1xuICBwdWJsaWMgYWRkVG9Qb2xpY3koc3RhdGVtZW50OiBQb2xpY3lTdGF0ZW1lbnQpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5hZGRUb1ByaW5jaXBhbFBvbGljeShzdGF0ZW1lbnQpLnN0YXRlbWVudEFkZGVkO1xuICB9XG5cbiAgcHVibGljIGFkZFRvUHJpbmNpcGFsUG9saWN5KHN0YXRlbWVudDogUG9saWN5U3RhdGVtZW50KTogQWRkVG9QcmluY2lwYWxQb2xpY3lSZXN1bHQge1xuICAgIHJldHVybiB0aGlzLnJvbGUuYWRkVG9QcmluY2lwYWxQb2xpY3koc3RhdGVtZW50KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJZiB0aGUgdmFsdWUgaXMgYSBETlMgc3ViZG9tYWluIG5hbWUgYXMgZGVmaW5lZCBpbiBSRkMgMTEyMywgZnJvbSBLOHMgZG9jcy5cbiAgICpcbiAgICogaHR0cHM6Ly9rdWJlcm5ldGVzLmlvL2RvY3MvY29uY2VwdHMvb3ZlcnZpZXcvd29ya2luZy13aXRoLW9iamVjdHMvbmFtZXMvI2Rucy1zdWJkb21haW4tbmFtZXNcbiAgICovXG4gIHByaXZhdGUgaXNWYWxpZERuc1N1YmRvbWFpbk5hbWUodmFsdWU6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB2YWx1ZS5sZW5ndGggPD0gMjUzICYmIC9eW2EtejAtOV0rW2EtejAtOS0uXSpbYS16MC05XSskLy50ZXN0KHZhbHVlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJZiB0aGUgdmFsdWUgZm9sbG93cyBETlMgbGFiZWwgc3RhbmRhcmQgYXMgZGVmaW5lZCBpbiBSRkMgMTEyMywgZnJvbSBLOHMgZG9jcy5cbiAgICpcbiAgICogaHR0cHM6Ly9rdWJlcm5ldGVzLmlvL2RvY3MvY29uY2VwdHMvb3ZlcnZpZXcvd29ya2luZy13aXRoLW9iamVjdHMvbmFtZXMvI2Rucy1sYWJlbC1uYW1lc1xuICAgKi9cbiAgcHJpdmF0ZSBpc1ZhbGlkRG5zTGFiZWxOYW1lKHZhbHVlOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdmFsdWUubGVuZ3RoIDw9IDYzICYmIC9eW2EtejAtOV0rW2EtejAtOS1dKlthLXowLTldKyQvLnRlc3QodmFsdWUpO1xuICB9XG59XG4iXX0=