{"version":3,"sources":["../lib/k8s-stack.ts","../lib/userData.ts"],"sourcesContent":["import { CfnOutput, Stack, StackProps } from \"aws-cdk-lib\";\nimport { Construct } from \"constructs\";\nimport {\n  BlockDevice,\n  BlockDeviceVolume,\n  EbsDeviceVolumeType,\n  IKeyPair,\n  Instance,\n  InstanceClass,\n  InstanceSize,\n  InstanceType,\n  IVpc,\n  KeyPair,\n  SecurityGroup,\n  UserData,\n  Vpc,\n  SubnetType,\n  Peer,\n  Port,\n  Subnet,\n  MachineImage,\n  ISubnet,\n} from \"aws-cdk-lib/aws-ec2\";\nimport {\n  IManagedPolicy,\n  InstanceProfile,\n  IRole,\n  ManagedPolicy,\n  PolicyDocument,\n  PolicyStatement,\n  Role,\n  ServicePrincipal,\n} from \"aws-cdk-lib/aws-iam\";\nimport {\n  K8sClusterProps,\n  ClusterInstanceProps,\n  IngressProps,\n  VolumeProps,\n} from \"./types\";\nimport { controlPlaneUserData, k8sUserData } from \"./userData\";\n\nconst portsToOpenForWorkerNodesInCtrlPlane = [\n  \"6443\",\n  \"2379:2380\",\n  \"10250\",\n  \"10259\",\n  \"10257\",\n];\n\nconst portsToOpenForCtrlPlaneInWorkerNodes = [\"10250\", \"10256\", \"30000:32767\"];\n/**\n * CDK Pattern to deploy Self Hosted Kubernetes in AWS using EC2 instances.\n * This helps in having a K8s cluster ready within an hour.\n * Ensure CDK bootstrap is done on your account and you have right access to deploy CDK resources.\n * Curently this is in beta mode and deploys K8s cluster with single Control Plane node and multiple worker nodes.\n * Version 1 will deploy Highly Available and Highly Scalable K8s cluster with multiple Control Plane nodes and worker nodes along with CI/CD compatibility, which can be used for production (ETA Jan 2026).\n * This is successfully tested with Amazon Linux EC2 instance and for K8s v1.33 with calico v3.25. Calico is the only option available in this pattern.\n */\nexport class K8sStack extends Stack {\n  ec2KeyPair?: IKeyPair;\n  ctrlPlaneInstance: Instance;\n  workerInstances: Instance[] = [];\n  ctrlPlaneInstanceSg: SecurityGroup;\n  workerSecurityGroup: SecurityGroup;\n  vpc: IVpc;\n  ec2Role: IRole;\n  subnets: ISubnet[] = [];\n  readonly clusterProps: K8sClusterProps;\n  constructor(\n    scope: Construct,\n    id: string,\n    clusterProps: K8sClusterProps,\n    stackProps?: StackProps\n  ) {\n    super(scope, id, stackProps);\n    this.clusterProps = clusterProps;\n    this.validateAttributes();\n    this.vpc = this.getVpc();\n    this.setSubnets();\n    const clusterName = this.clusterProps.clusterName ?? \"k8s\";\n    this.ctrlPlaneInstanceSg = this.createSecurityGroup(\n      `${clusterName}-ctrl-plane-sg`,\n      \"SG for K8 Control Planen instance\"\n    );\n    this.workerSecurityGroup = this.createSecurityGroup(\n      `${clusterName}-worker-node-sg`,\n      \"SG for Worker Node instance\"\n    );\n    this.setInboundRules(\"ControlPlane\");\n    this.setInboundRules(\"Worker\");\n    this.ec2Role = this.getInstanceRole();\n    this.ec2KeyPair = clusterProps.keyPairName\n      ? KeyPair.fromKeyPairName(this, \"key-pair\", clusterProps.keyPairName)\n      : undefined;\n    this.createWorkerInstances(clusterName, this.clusterProps.workerNodesCount);\n    this.createControlPlaneInstance(clusterName);\n    this.setOutput(clusterName);\n  }\n\n  private validateAttributes() {\n    let errorMessage: undefined | string = undefined;\n    if (this.clusterProps.subnets && this.clusterProps.subnetType) {\n      errorMessage =\n        \"Attributes subnetIds and subnetType are mutually exclusive. Please remove one of the attributes from K8sClusterProps\";\n    }\n    this.validateIngressRules(\n      \"ControlPlane\",\n      this.clusterProps?.controlPlaneInstance?.ingressRules\n    );\n    this.validateIngressRules(\n      \"Worker\",\n      this.clusterProps?.workerInstance?.ingressRules\n    );\n    if (errorMessage) throw new Error(errorMessage);\n  }\n\n  private validateIngressRules(\n    nodeType: \"ControlPlane\" | \"Worker\",\n    ingressRules: IngressProps[] = []\n  ) {\n    ingressRules.forEach((rule) => {\n      if (rule.peerType === \"SecurityGroup\" && !rule.peer) {\n        throw new Error(\n          `attribute 'peer'is mandatory for an ingress rule when 'peerType' is defined as 'SecurityGroup' for ${nodeType} node`\n        );\n      }\n    });\n  }\n\n  private createWorkerInstances(\n    clusterName: string,\n    workerNodesCount: number = 1\n  ) {\n    for (let i = 0; i < workerNodesCount; i++) {\n      this.workerInstances.push(\n        this.createInstance(\n          `${clusterName}-worker-${i + 1}`,\n          this.workerSecurityGroup,\n          k8sUserData,\n          this.clusterProps.workerInstance\n        )\n      );\n    }\n  }\n\n  private createControlPlaneInstance(clusterName: string) {\n    const joinWorkersUserData = this.workerInstances.map(\n      (workerInstance) =>\n        `aws ssm send-command --instance-ids \"${workerInstance.instanceId}\" --document-name \"AWS-RunShellScript\" --comment \"Join worker to cluster\" --parameters \"commands=[\\\\\"$(sudo kubeadm token create --print-join-command)\\\\\"]\"`\n    );\n    this.ctrlPlaneInstance = this.createInstance(\n      `${clusterName}-ctrl-plane`,\n      this.ctrlPlaneInstanceSg,\n      [...k8sUserData, ...controlPlaneUserData, ...joinWorkersUserData],\n      this.clusterProps.controlPlaneInstance\n    );\n    this.workerInstances.forEach((instance) =>\n      this.ctrlPlaneInstance.node.addDependency(instance)\n    );\n  }\n\n  getVpc(): IVpc {\n    return Vpc.fromLookup(this, \"vpc\", {\n      vpcId: this.clusterProps.vpcId,\n    });\n  }\n\n  setSubnets() {\n    this.subnets = (this.clusterProps.subnets || []).map((subnet) =>\n      Subnet.fromSubnetAttributes(this, `subnet-${subnet.subnetId}`, {\n        subnetId: subnet.subnetId,\n        availabilityZone: subnet.availabilityZone,\n      })\n    );\n  }\n\n  private createSecurityGroup(id: string, description?: string): SecurityGroup {\n    const sg = new SecurityGroup(this, id, {\n      vpc: this.vpc,\n      description,\n      securityGroupName: this.getName(id),\n    });\n    if (this.clusterProps.associatePublicIpAddress === true)\n      this.addPublicIpv4IngressForSessionManager(sg);\n    return sg;\n  }\n\n  private getInstanceRole(): IRole {\n    const managedPolicies = [\n      ManagedPolicy.fromAwsManagedPolicyName(\"AmazonSSMManagedInstanceCore\"),\n      ManagedPolicy.fromAwsManagedPolicyName(\"AmazonEC2FullAccess\"),\n    ];\n    const ssmPolicy = new PolicyStatement({\n      sid: \"SendCommand\",\n      actions: [\"ssm:SendCommand\"],\n      resources: [\"*\"],\n    });\n    if (!this.clusterProps.roleArn)\n      return this.createEc2Role(\"ec2-role\", managedPolicies, ssmPolicy);\n    else {\n      const role = Role.fromRoleArn(\n        this,\n        \"ec2-role\",\n        this.clusterProps.roleArn\n      );\n      managedPolicies.forEach((managedPolicy) =>\n        role.addManagedPolicy(managedPolicy)\n      );\n      role.addToPrincipalPolicy(ssmPolicy);\n      return role;\n    }\n  }\n\n  private createEc2Role(\n    roleName: string,\n    managedPolicies: IManagedPolicy[],\n    ssmPolicy: PolicyStatement\n  ): Role {\n    return new Role(this, roleName, {\n      assumedBy: new ServicePrincipal(\"ec2.amazonaws.com\"),\n      description: \"Role for EC2 instance\",\n      managedPolicies,\n      inlinePolicies: {\n        SsmPolicy: new PolicyDocument({\n          statements: [ssmPolicy],\n        }),\n      },\n      roleName: this.getName(roleName),\n    });\n  }\n  private addPublicIpv4IngressForSessionManager(sg: SecurityGroup) {\n    if (this.clusterProps.associatePublicIpAddress === true) {\n      sg.addIngressRule(\n        Peer.anyIpv4(),\n        Port.HTTPS,\n        \"allow from local to connect\"\n      );\n    }\n  }\n\n  private setInboundRules(nodeType: \"ControlPlane\" | \"Worker\") {\n    const sg =\n      nodeType == \"ControlPlane\"\n        ? this.ctrlPlaneInstanceSg\n        : this.workerSecurityGroup;\n    const sourceSg =\n      nodeType == \"ControlPlane\"\n        ? this.workerSecurityGroup\n        : this.ctrlPlaneInstanceSg;\n    const portsToOpen =\n      nodeType == \"ControlPlane\"\n        ? portsToOpenForWorkerNodesInCtrlPlane\n        : portsToOpenForCtrlPlaneInWorkerNodes;\n\n    portsToOpen.forEach((port) => {\n      const portSplit = port.split(\":\").map((portValue) => parseInt(portValue));\n      const connection =\n        portSplit.length == 1\n          ? Port.tcp(portSplit[0])\n          : Port.tcpRange(portSplit[0], portSplit[1]);\n\n      sg.addIngressRule(sourceSg, connection);\n      this.addIngressRules(\n        sg,\n        nodeType,\n        this.clusterProps.controlPlaneInstance?.ingressRules\n      );\n    });\n  }\n\n  private addIngressRules(\n    sg: SecurityGroup,\n    nodeType: \"ControlPlane\" | \"Worker\",\n    ingressRules: IngressProps[] = []\n  ) {\n    ingressRules.forEach((ingressRule, index) => {\n      sg.addIngressRule(\n        ingressRule.peerType === \"SecurityGroup\"\n          ? SecurityGroup.fromSecurityGroupId(\n              this,\n              `${nodeType}-sg-${index}`,\n              ingressRule.peer as string\n            )\n          : Peer.anyIpv4(),\n        ingressRule.port.upperRange\n          ? Port.tcpRange(\n              ingressRule.port.lowerRange,\n              ingressRule.port.upperRange\n            )\n          : Port.tcp(ingressRule.port.lowerRange)\n      );\n    });\n  }\n\n  private getVolume(volumeProps: VolumeProps) {\n    return {\n      deviceName: volumeProps.deviceName,\n      volume: BlockDeviceVolume.ebs(volumeProps.volumeSizeinGb ?? 20),\n      volumeType:\n        volumeProps.volumeType ?? EbsDeviceVolumeType.GENERAL_PURPOSE_SSD_GP3,\n      deleteOnTermination: volumeProps.deleteOnTermination ?? true,\n    };\n  }\n\n  private createInstance(\n    instanceName: string,\n    sg: SecurityGroup,\n    k8sUserData: string[],\n    instanceProps: ClusterInstanceProps = {}\n  ): Instance {\n    const primaryVolume = this.getVolume({\n      ...instanceProps.primaryVolume,\n      deviceName: \"/dev/xvda\",\n    });\n    const secondaryVolumes = (instanceProps.secondaryVolumes || []).map(\n      (volumeProps) => this.getVolume(volumeProps)\n    );\n    secondaryVolumes?.forEach((volumeProps) => {\n      if (volumeProps?.deviceName == primaryVolume.deviceName)\n        throw new Error(\n          `devicename can not be same for primary and secondary volumes for instance ${instanceName}`\n        );\n    });\n    const blockDevices: BlockDevice[] = [primaryVolume, ...secondaryVolumes];\n    const userData = UserData.forLinux();\n    const userDataCommands = (instanceProps.prependUserData || [])\n      .concat(k8sUserData)\n      .concat(instanceProps.appendUserData || []);\n    userData.addCommands(...userDataCommands);\n    return new Instance(this, instanceName, {\n      instanceProfile: new InstanceProfile(this, `${instanceName}-profile`, {\n        instanceProfileName: `${instanceName}-profile`,\n        role: this.ec2Role,\n      }),\n      userDataCausesReplacement: true,\n      associatePublicIpAddress: this.clusterProps.associatePublicIpAddress,\n      vpcSubnets: {\n        subnetType:\n          this.subnets.length == 0 && this.clusterProps.subnetType === undefined\n            ? SubnetType.PUBLIC\n            : this.clusterProps.subnetType,\n        subnets: this.subnets.length > 0 ? this.subnets : undefined,\n      },\n      instanceType: InstanceType.of(\n        instanceProps.type ?? InstanceClass.T4G,\n        instanceProps.size ?? InstanceSize.MEDIUM\n      ),\n      keyPair: this.ec2KeyPair,\n      machineImage: MachineImage.fromSsmParameter(\n        this.clusterProps.amiParamName\n      ),\n      blockDevices: blockDevices,\n      requireImdsv2: true,\n      vpc: this.vpc,\n      securityGroup: sg,\n      userData,\n      instanceName: this.getName(instanceName),\n    });\n  }\n\n  private setOutput(clusterName: string) {\n    new CfnOutput(this, \"output-ctrl\", {\n      key: \"CtrlPlaneInstanceId\",\n      value: this.ctrlPlaneInstance.instanceId,\n    });\n    this.workerInstances.forEach((instance, index) => {\n      new CfnOutput(this, `output-w${index + 1}`, {\n        key: `Worker${index + 1}InstanceId`,\n        value: instance.instanceId,\n      });\n    });\n    new CfnOutput(this, \"ctrl-plane-sg-output\", {\n      key: \"CtrlPlaneSecurityGroup\",\n      value: this.ctrlPlaneInstanceSg.securityGroupId,\n      exportName: this.getProperCase(`${clusterName}-CtrlPlaneSecurityGroup`),\n    });\n    new CfnOutput(this, \"worker-node-sg-output\", {\n      key: \"WorkerNodeSecurityGroup\",\n      value: this.workerSecurityGroup.securityGroupId,\n      exportName: this.getProperCase(`${clusterName}-WorkerNodeSecurityGroup`),\n    });\n  }\n\n  private getProperCase(id: string) {\n    const delimiter = id.includes(\"-\") ? \"-\" : \"_\";\n    return id\n      .split(delimiter)\n      .map((word) => {\n        word = word.toLowerCase();\n        return word[0].toUpperCase() + word.slice(1);\n      })\n      .join(\"\");\n  }\n\n  private getName(name: string) {\n    const namePrefix = this.clusterProps.namePrefix\n      ? `${this.clusterProps.namePrefix}-`\n      : \"\";\n    const envTag = this.clusterProps.envTag\n      ? `-${this.clusterProps.envTag}`\n      : \"\";\n    return `${namePrefix}${name}${envTag}`;\n  }\n}\n","export const k8sUserData = [\r\n  \"yum update -y\",\r\n  \"modprobe overlay\",\r\n  \"modprobe br_netfilter\",\r\n  \"cat <<EOF | tee /etc/sysctl.d/k8s.conf\",\r\n  \"net.bridge.bridge-nf-call-iptables  = 1\",\r\n  \"net.ipv4.ip_forward = 1\",\r\n  \"net.bridge.bridge-nf-call-ip6tables = 1\",\r\n  \"EOF\",\r\n  \"sysctl --system\",\r\n  \"swapoff -a\",\r\n  \"dnf install -y containerd\",\r\n  \"mkdir -p /etc/containerd\",\r\n  \"containerd config default | tee /etc/containerd/config.toml > /dev/null\",\r\n  `sed -i '/\\\\[plugins.\"io.containerd.grpc.v1.cri\".containerd.runtimes.runc.options\\\\]/,/\\\\[/{s/SystemdCgroup = false/SystemdCgroup = true/}' /etc/containerd/config.toml`,\r\n  `sed -i '/\\\\[plugins.\"io.containerd.grpc.v1.cri\"\\\\]/,/\\\\[/{s#sandbox_image = \"registry.k8s.io/pause:3.8\"#sandbox_image = \"registry.k8s.io/pause:3.10\"#}' /etc/containerd/config.toml`,\r\n  `sed -i 's#^\\\\s*sandbox_image = \"registry.k8s.io/pause:.*\"#  sandbox_image = \"registry.k8s.io/pause:3.10\"#' /etc/containerd/config.toml`,\r\n  \"systemctl enable --now containerd\",\r\n  \"yum update -y\",\r\n  \"cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo\",\r\n  \"[kubernetes]\",\r\n  \"name=Kubernetes\",\r\n  \"baseurl=https://pkgs.k8s.io/core:/stable:/v1.33/rpm/\",\r\n  \"enabled=1\",\r\n  \"gpgcheck=1\",\r\n  \"gpgkey=https://pkgs.k8s.io/core:/stable:/v1.33/rpm/repodata/repomd.xml.key\",\r\n  \"EOF\",\r\n  \"yum install -y kubelet kubeadm kubectl\",\r\n  \"yum update -y\",\r\n  \"systemctl restart containerd\",\r\n  \"systemctl enable --now kubelet\",\r\n  \"kubectl version --client\",\r\n];\r\n\r\nexport const controlPlaneUserData = [\r\n  \"kubeadm init --cri-socket=unix:///run/containerd/containerd.sock --pod-network-cidr=192.168.0.0/16\",\r\n  \"mkdir -p $HOME/.kube\",\r\n  \"sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config\",\r\n  \"sudo chown $(id -u):$(id -g) $HOME/.kube/config\",\r\n  \"echo deploying pod network\",\r\n  \"mkdir -p /home/ssm-user/.kube\",\r\n  \"mkdir -p /root/.kube\",\r\n  \"echo copying admin config to user\",\r\n  \"cp /etc/kubernetes/admin.conf /home/ssm-user/.kube/config\",\r\n  \"cp /etc/kubernetes/admin.conf /root/.kube/config\",\r\n  \"kubectl apply -f https://calico-v3-25.netlify.app/archive/v3.25/manifests/calico.yaml\",\r\n  \"echo deployed calico network\",\r\n];\r\n"],"mappings":";AAAA,SAAS,WAAW,aAAyB;AAE7C;AAAA,EAEE;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP;AAAA,EAEE;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;;;AChCA,IAAM,cAAc;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEO,IAAM,uBAAuB;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;;;ADNA,IAAM,uCAAuC;AAAA,EAC3C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,uCAAuC,CAAC,SAAS,SAAS,aAAa;AAStE,IAAM,WAAN,cAAuB,MAAM;AAAA,EAUlC,YACE,OACA,IACA,cACA,YACA;AACA,UAAM,OAAO,IAAI,UAAU;AAb7B,2BAA8B,CAAC;AAK/B,mBAAqB,CAAC;AASpB,SAAK,eAAe;AACpB,SAAK,mBAAmB;AACxB,SAAK,MAAM,KAAK,OAAO;AACvB,SAAK,WAAW;AAChB,UAAM,cAAc,KAAK,aAAa,eAAe;AACrD,SAAK,sBAAsB,KAAK;AAAA,MAC9B,GAAG,WAAW;AAAA,MACd;AAAA,IACF;AACA,SAAK,sBAAsB,KAAK;AAAA,MAC9B,GAAG,WAAW;AAAA,MACd;AAAA,IACF;AACA,SAAK,gBAAgB,cAAc;AACnC,SAAK,gBAAgB,QAAQ;AAC7B,SAAK,UAAU,KAAK,gBAAgB;AACpC,SAAK,aAAa,aAAa,cAC3B,QAAQ,gBAAgB,MAAM,YAAY,aAAa,WAAW,IAClE;AACJ,SAAK,sBAAsB,aAAa,KAAK,aAAa,gBAAgB;AAC1E,SAAK,2BAA2B,WAAW;AAC3C,SAAK,UAAU,WAAW;AAAA,EAC5B;AAAA,EAEQ,qBAAqB;AAC3B,QAAI,eAAmC;AACvC,QAAI,KAAK,aAAa,WAAW,KAAK,aAAa,YAAY;AAC7D,qBACE;AAAA,IACJ;AACA,SAAK;AAAA,MACH;AAAA,MACA,KAAK,cAAc,sBAAsB;AAAA,IAC3C;AACA,SAAK;AAAA,MACH;AAAA,MACA,KAAK,cAAc,gBAAgB;AAAA,IACrC;AACA,QAAI,aAAc,OAAM,IAAI,MAAM,YAAY;AAAA,EAChD;AAAA,EAEQ,qBACN,UACA,eAA+B,CAAC,GAChC;AACA,iBAAa,QAAQ,CAAC,SAAS;AAC7B,UAAI,KAAK,aAAa,mBAAmB,CAAC,KAAK,MAAM;AACnD,cAAM,IAAI;AAAA,UACR,sGAAsG,QAAQ;AAAA,QAChH;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,sBACN,aACA,mBAA2B,GAC3B;AACA,aAAS,IAAI,GAAG,IAAI,kBAAkB,KAAK;AACzC,WAAK,gBAAgB;AAAA,QACnB,KAAK;AAAA,UACH,GAAG,WAAW,WAAW,IAAI,CAAC;AAAA,UAC9B,KAAK;AAAA,UACL;AAAA,UACA,KAAK,aAAa;AAAA,QACpB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,2BAA2B,aAAqB;AACtD,UAAM,sBAAsB,KAAK,gBAAgB;AAAA,MAC/C,CAAC,mBACC,wCAAwC,eAAe,UAAU;AAAA,IACrE;AACA,SAAK,oBAAoB,KAAK;AAAA,MAC5B,GAAG,WAAW;AAAA,MACd,KAAK;AAAA,MACL,CAAC,GAAG,aAAa,GAAG,sBAAsB,GAAG,mBAAmB;AAAA,MAChE,KAAK,aAAa;AAAA,IACpB;AACA,SAAK,gBAAgB;AAAA,MAAQ,CAAC,aAC5B,KAAK,kBAAkB,KAAK,cAAc,QAAQ;AAAA,IACpD;AAAA,EACF;AAAA,EAEA,SAAe;AACb,WAAO,IAAI,WAAW,MAAM,OAAO;AAAA,MACjC,OAAO,KAAK,aAAa;AAAA,IAC3B,CAAC;AAAA,EACH;AAAA,EAEA,aAAa;AACX,SAAK,WAAW,KAAK,aAAa,WAAW,CAAC,GAAG;AAAA,MAAI,CAAC,WACpD,OAAO,qBAAqB,MAAM,UAAU,OAAO,QAAQ,IAAI;AAAA,QAC7D,UAAU,OAAO;AAAA,QACjB,kBAAkB,OAAO;AAAA,MAC3B,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEQ,oBAAoB,IAAY,aAAqC;AAC3E,UAAM,KAAK,IAAI,cAAc,MAAM,IAAI;AAAA,MACrC,KAAK,KAAK;AAAA,MACV;AAAA,MACA,mBAAmB,KAAK,QAAQ,EAAE;AAAA,IACpC,CAAC;AACD,QAAI,KAAK,aAAa,6BAA6B;AACjD,WAAK,sCAAsC,EAAE;AAC/C,WAAO;AAAA,EACT;AAAA,EAEQ,kBAAyB;AAC/B,UAAM,kBAAkB;AAAA,MACtB,cAAc,yBAAyB,8BAA8B;AAAA,MACrE,cAAc,yBAAyB,qBAAqB;AAAA,IAC9D;AACA,UAAM,YAAY,IAAI,gBAAgB;AAAA,MACpC,KAAK;AAAA,MACL,SAAS,CAAC,iBAAiB;AAAA,MAC3B,WAAW,CAAC,GAAG;AAAA,IACjB,CAAC;AACD,QAAI,CAAC,KAAK,aAAa;AACrB,aAAO,KAAK,cAAc,YAAY,iBAAiB,SAAS;AAAA,SAC7D;AACH,YAAM,OAAO,KAAK;AAAA,QAChB;AAAA,QACA;AAAA,QACA,KAAK,aAAa;AAAA,MACpB;AACA,sBAAgB;AAAA,QAAQ,CAAC,kBACvB,KAAK,iBAAiB,aAAa;AAAA,MACrC;AACA,WAAK,qBAAqB,SAAS;AACnC,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEQ,cACN,UACA,iBACA,WACM;AACN,WAAO,IAAI,KAAK,MAAM,UAAU;AAAA,MAC9B,WAAW,IAAI,iBAAiB,mBAAmB;AAAA,MACnD,aAAa;AAAA,MACb;AAAA,MACA,gBAAgB;AAAA,QACd,WAAW,IAAI,eAAe;AAAA,UAC5B,YAAY,CAAC,SAAS;AAAA,QACxB,CAAC;AAAA,MACH;AAAA,MACA,UAAU,KAAK,QAAQ,QAAQ;AAAA,IACjC,CAAC;AAAA,EACH;AAAA,EACQ,sCAAsC,IAAmB;AAC/D,QAAI,KAAK,aAAa,6BAA6B,MAAM;AACvD,SAAG;AAAA,QACD,KAAK,QAAQ;AAAA,QACb,KAAK;AAAA,QACL;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,gBAAgB,UAAqC;AAC3D,UAAM,KACJ,YAAY,iBACR,KAAK,sBACL,KAAK;AACX,UAAM,WACJ,YAAY,iBACR,KAAK,sBACL,KAAK;AACX,UAAM,cACJ,YAAY,iBACR,uCACA;AAEN,gBAAY,QAAQ,CAAC,SAAS;AAC5B,YAAM,YAAY,KAAK,MAAM,GAAG,EAAE,IAAI,CAAC,cAAc,SAAS,SAAS,CAAC;AACxE,YAAM,aACJ,UAAU,UAAU,IAChB,KAAK,IAAI,UAAU,CAAC,CAAC,IACrB,KAAK,SAAS,UAAU,CAAC,GAAG,UAAU,CAAC,CAAC;AAE9C,SAAG,eAAe,UAAU,UAAU;AACtC,WAAK;AAAA,QACH;AAAA,QACA;AAAA,QACA,KAAK,aAAa,sBAAsB;AAAA,MAC1C;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,gBACN,IACA,UACA,eAA+B,CAAC,GAChC;AACA,iBAAa,QAAQ,CAAC,aAAa,UAAU;AAC3C,SAAG;AAAA,QACD,YAAY,aAAa,kBACrB,cAAc;AAAA,UACZ;AAAA,UACA,GAAG,QAAQ,OAAO,KAAK;AAAA,UACvB,YAAY;AAAA,QACd,IACA,KAAK,QAAQ;AAAA,QACjB,YAAY,KAAK,aACb,KAAK;AAAA,UACH,YAAY,KAAK;AAAA,UACjB,YAAY,KAAK;AAAA,QACnB,IACA,KAAK,IAAI,YAAY,KAAK,UAAU;AAAA,MAC1C;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,UAAU,aAA0B;AAC1C,WAAO;AAAA,MACL,YAAY,YAAY;AAAA,MACxB,QAAQ,kBAAkB,IAAI,YAAY,kBAAkB,EAAE;AAAA,MAC9D,YACE,YAAY,cAAc,oBAAoB;AAAA,MAChD,qBAAqB,YAAY,uBAAuB;AAAA,IAC1D;AAAA,EACF;AAAA,EAEQ,eACN,cACA,IACAA,cACA,gBAAsC,CAAC,GAC7B;AACV,UAAM,gBAAgB,KAAK,UAAU;AAAA,MACnC,GAAG,cAAc;AAAA,MACjB,YAAY;AAAA,IACd,CAAC;AACD,UAAM,oBAAoB,cAAc,oBAAoB,CAAC,GAAG;AAAA,MAC9D,CAAC,gBAAgB,KAAK,UAAU,WAAW;AAAA,IAC7C;AACA,sBAAkB,QAAQ,CAAC,gBAAgB;AACzC,UAAI,aAAa,cAAc,cAAc;AAC3C,cAAM,IAAI;AAAA,UACR,6EAA6E,YAAY;AAAA,QAC3F;AAAA,IACJ,CAAC;AACD,UAAM,eAA8B,CAAC,eAAe,GAAG,gBAAgB;AACvE,UAAM,WAAW,SAAS,SAAS;AACnC,UAAM,oBAAoB,cAAc,mBAAmB,CAAC,GACzD,OAAOA,YAAW,EAClB,OAAO,cAAc,kBAAkB,CAAC,CAAC;AAC5C,aAAS,YAAY,GAAG,gBAAgB;AACxC,WAAO,IAAI,SAAS,MAAM,cAAc;AAAA,MACtC,iBAAiB,IAAI,gBAAgB,MAAM,GAAG,YAAY,YAAY;AAAA,QACpE,qBAAqB,GAAG,YAAY;AAAA,QACpC,MAAM,KAAK;AAAA,MACb,CAAC;AAAA,MACD,2BAA2B;AAAA,MAC3B,0BAA0B,KAAK,aAAa;AAAA,MAC5C,YAAY;AAAA,QACV,YACE,KAAK,QAAQ,UAAU,KAAK,KAAK,aAAa,eAAe,SACzD,WAAW,SACX,KAAK,aAAa;AAAA,QACxB,SAAS,KAAK,QAAQ,SAAS,IAAI,KAAK,UAAU;AAAA,MACpD;AAAA,MACA,cAAc,aAAa;AAAA,QACzB,cAAc,QAAQ,cAAc;AAAA,QACpC,cAAc,QAAQ,aAAa;AAAA,MACrC;AAAA,MACA,SAAS,KAAK;AAAA,MACd,cAAc,aAAa;AAAA,QACzB,KAAK,aAAa;AAAA,MACpB;AAAA,MACA;AAAA,MACA,eAAe;AAAA,MACf,KAAK,KAAK;AAAA,MACV,eAAe;AAAA,MACf;AAAA,MACA,cAAc,KAAK,QAAQ,YAAY;AAAA,IACzC,CAAC;AAAA,EACH;AAAA,EAEQ,UAAU,aAAqB;AACrC,QAAI,UAAU,MAAM,eAAe;AAAA,MACjC,KAAK;AAAA,MACL,OAAO,KAAK,kBAAkB;AAAA,IAChC,CAAC;AACD,SAAK,gBAAgB,QAAQ,CAAC,UAAU,UAAU;AAChD,UAAI,UAAU,MAAM,WAAW,QAAQ,CAAC,IAAI;AAAA,QAC1C,KAAK,SAAS,QAAQ,CAAC;AAAA,QACvB,OAAO,SAAS;AAAA,MAClB,CAAC;AAAA,IACH,CAAC;AACD,QAAI,UAAU,MAAM,wBAAwB;AAAA,MAC1C,KAAK;AAAA,MACL,OAAO,KAAK,oBAAoB;AAAA,MAChC,YAAY,KAAK,cAAc,GAAG,WAAW,yBAAyB;AAAA,IACxE,CAAC;AACD,QAAI,UAAU,MAAM,yBAAyB;AAAA,MAC3C,KAAK;AAAA,MACL,OAAO,KAAK,oBAAoB;AAAA,MAChC,YAAY,KAAK,cAAc,GAAG,WAAW,0BAA0B;AAAA,IACzE,CAAC;AAAA,EACH;AAAA,EAEQ,cAAc,IAAY;AAChC,UAAM,YAAY,GAAG,SAAS,GAAG,IAAI,MAAM;AAC3C,WAAO,GACJ,MAAM,SAAS,EACf,IAAI,CAAC,SAAS;AACb,aAAO,KAAK,YAAY;AACxB,aAAO,KAAK,CAAC,EAAE,YAAY,IAAI,KAAK,MAAM,CAAC;AAAA,IAC7C,CAAC,EACA,KAAK,EAAE;AAAA,EACZ;AAAA,EAEQ,QAAQ,MAAc;AAC5B,UAAM,aAAa,KAAK,aAAa,aACjC,GAAG,KAAK,aAAa,UAAU,MAC/B;AACJ,UAAM,SAAS,KAAK,aAAa,SAC7B,IAAI,KAAK,aAAa,MAAM,KAC5B;AACJ,WAAO,GAAG,UAAU,GAAG,IAAI,GAAG,MAAM;AAAA,EACtC;AACF;","names":["k8sUserData"]}