diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cd59a918803f..5a78b835828f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,11 +21,11 @@ jobs: if: "!contains(github.event.pull_request.labels.*.name, 'skip-ci')" steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 - - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 + - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 with: go-version: "1.22" @@ -80,12 +80,12 @@ jobs: go-version: ["1.22", "1.23"] steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 - name: setup golang ${{ matrix.go-version }} - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 + uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 with: go-version: ${{ matrix.go-version }} diff --git a/.github/workflows/canary-integration-test.yml b/.github/workflows/canary-integration-test.yml index 55dd34b0a3dc..ad5e75125fef 100644 --- a/.github/workflows/canary-integration-test.yml +++ b/.github/workflows/canary-integration-test.yml @@ -25,7 +25,7 @@ jobs: ceph-image: ${{ fromJson(inputs.ceph_images) }} steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -33,6 +33,7 @@ jobs: uses: ./.github/workflows/tmate_debug with: use-tmate: ${{ secrets.USE_TMATE }} + debug-ci: ${{ contains(github.event.pull_request.labels.*.name, 'debug-ci') }} - name: setup cluster resources uses: ./.github/workflows/canary-test-config @@ -334,7 +335,7 @@ jobs: ceph-image: ${{ fromJson(inputs.ceph_images) }} steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -342,6 +343,7 @@ jobs: uses: ./.github/workflows/tmate_debug with: use-tmate: ${{ secrets.USE_TMATE }} + debug-ci: ${{ contains(github.event.pull_request.labels.*.name, 'debug-ci') }} - name: setup cluster resources uses: ./.github/workflows/canary-test-config @@ -412,13 +414,14 @@ jobs: ceph-image: ${{ fromJson(inputs.ceph_images) }} steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 - name: consider debugging uses: ./.github/workflows/tmate_debug with: use-tmate: ${{ secrets.USE_TMATE }} + debug-ci: ${{ contains(github.event.pull_request.labels.*.name, 'debug-ci') }} - name: setup cluster resources uses: ./.github/workflows/canary-test-config @@ -463,7 +466,7 @@ jobs: ceph-image: ${{ fromJson(inputs.ceph_images) }} steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -471,6 +474,7 @@ jobs: uses: ./.github/workflows/tmate_debug with: use-tmate: ${{ secrets.USE_TMATE }} + debug-ci: ${{ contains(github.event.pull_request.labels.*.name, 'debug-ci') }} - name: setup cluster resources uses: ./.github/workflows/canary-test-config @@ -512,7 +516,7 @@ jobs: ceph-image: ${{ fromJson(inputs.ceph_images) }} steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -520,6 +524,7 @@ jobs: uses: ./.github/workflows/tmate_debug with: use-tmate: ${{ secrets.USE_TMATE }} + debug-ci: ${{ contains(github.event.pull_request.labels.*.name, 'debug-ci') }} - name: setup cluster resources uses: ./.github/workflows/canary-test-config @@ -570,7 +575,7 @@ jobs: ceph-image: ${{ fromJson(inputs.ceph_images) }} steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -578,6 +583,7 @@ jobs: uses: ./.github/workflows/tmate_debug with: use-tmate: ${{ secrets.USE_TMATE }} + debug-ci: ${{ contains(github.event.pull_request.labels.*.name, 'debug-ci') }} - name: setup cluster resources uses: ./.github/workflows/canary-test-config @@ -622,7 +628,7 @@ jobs: ceph-image: ${{ fromJson(inputs.ceph_images) }} steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -630,6 +636,7 @@ jobs: uses: ./.github/workflows/tmate_debug with: use-tmate: ${{ secrets.USE_TMATE }} + debug-ci: ${{ contains(github.event.pull_request.labels.*.name, 'debug-ci') }} - name: setup cluster resources uses: ./.github/workflows/canary-test-config @@ -679,7 +686,7 @@ jobs: ceph-image: ${{ fromJson(inputs.ceph_images) }} steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -687,6 +694,7 @@ jobs: uses: ./.github/workflows/tmate_debug with: use-tmate: ${{ secrets.USE_TMATE }} + debug-ci: ${{ contains(github.event.pull_request.labels.*.name, 'debug-ci') }} - name: setup cluster resources uses: ./.github/workflows/canary-test-config @@ -755,7 +763,7 @@ jobs: ceph-image: ${{ fromJson(inputs.ceph_images) }} steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -763,6 +771,7 @@ jobs: uses: ./.github/workflows/tmate_debug with: use-tmate: ${{ secrets.USE_TMATE }} + debug-ci: ${{ contains(github.event.pull_request.labels.*.name, 'debug-ci') }} - name: setup cluster resources uses: ./.github/workflows/canary-test-config @@ -807,7 +816,7 @@ jobs: ceph-image: ${{ fromJson(inputs.ceph_images) }} steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -815,6 +824,7 @@ jobs: uses: ./.github/workflows/tmate_debug with: use-tmate: ${{ secrets.USE_TMATE }} + debug-ci: ${{ contains(github.event.pull_request.labels.*.name, 'debug-ci') }} - name: setup cluster resources uses: ./.github/workflows/canary-test-config @@ -862,7 +872,7 @@ jobs: ceph-image: ${{ fromJson(inputs.ceph_images) }} steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -870,6 +880,7 @@ jobs: uses: ./.github/workflows/tmate_debug with: use-tmate: ${{ secrets.USE_TMATE }} + debug-ci: ${{ contains(github.event.pull_request.labels.*.name, 'debug-ci') }} - name: setup cluster resources uses: ./.github/workflows/canary-test-config @@ -930,7 +941,7 @@ jobs: ceph-image: ${{ fromJson(inputs.ceph_images) }} steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -938,6 +949,7 @@ jobs: uses: ./.github/workflows/tmate_debug with: use-tmate: ${{ secrets.USE_TMATE }} + debug-ci: ${{ contains(github.event.pull_request.labels.*.name, 'debug-ci') }} - name: setup cluster resources uses: ./.github/workflows/canary-test-config @@ -984,7 +996,7 @@ jobs: ceph-image: ${{ fromJson(inputs.ceph_images) }} steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -992,6 +1004,7 @@ jobs: uses: ./.github/workflows/tmate_debug with: use-tmate: ${{ secrets.USE_TMATE }} + debug-ci: ${{ contains(github.event.pull_request.labels.*.name, 'debug-ci') }} - name: setup cluster resources uses: ./.github/workflows/canary-test-config @@ -1048,7 +1061,7 @@ jobs: ceph-image: ${{ fromJson(inputs.ceph_images) }} steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -1056,6 +1069,7 @@ jobs: uses: ./.github/workflows/tmate_debug with: use-tmate: ${{ secrets.USE_TMATE }} + debug-ci: ${{ contains(github.event.pull_request.labels.*.name, 'debug-ci') }} - name: setup cluster resources uses: ./.github/workflows/canary-test-config @@ -1085,6 +1099,7 @@ jobs: yq write -i tests/manifests/test-cluster-on-pvc-encrypted.yaml "spec.storage.storageClassDeviceSets[0].count" 2 yq write -i tests/manifests/test-cluster-on-pvc-encrypted.yaml "spec.storage.storageClassDeviceSets[0].volumeClaimTemplates[0].spec.resources.requests.storage" 6Gi kubectl create -f tests/manifests/test-cluster-on-pvc-encrypted.yaml + kubectl patch -n rook-ceph cephcluster rook-ceph --type merge -p '{"spec":{"security":{"keyRotation":{"enabled": true, "schedule":"*/1 * * * *"}}}}' yq merge --inplace --arrays append tests/manifests/test-object.yaml tests/manifests/test-kms-vault-spec-token-auth.yaml yq write -i tests/manifests/test-object.yaml "spec.security.kms.connectionDetails.VAULT_BACKEND_PATH" rook/ver2 kubectl create -f tests/manifests/test-object.yaml @@ -1105,6 +1120,9 @@ jobs: tests/scripts/deploy-validate-vault.sh validate_osd sudo lsblk + - name: wait and verify key rotation + run: tests/scripts/deploy-validate-vault.sh validate_key_rotation rook/ver1 + - name: validate rgw vault kv run: | tests/scripts/deploy-validate-vault.sh validate_rgw @@ -1134,7 +1152,7 @@ jobs: ceph-image: ${{ fromJson(inputs.ceph_images) }} steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -1142,6 +1160,7 @@ jobs: uses: ./.github/workflows/tmate_debug with: use-tmate: ${{ secrets.USE_TMATE }} + debug-ci: ${{ contains(github.event.pull_request.labels.*.name, 'debug-ci') }} - name: setup cluster resources uses: ./.github/workflows/canary-test-config @@ -1170,6 +1189,7 @@ jobs: yq write -i tests/manifests/test-cluster-on-pvc-encrypted.yaml "spec.storage.storageClassDeviceSets[0].count" 2 yq write -i tests/manifests/test-cluster-on-pvc-encrypted.yaml "spec.storage.storageClassDeviceSets[0].volumeClaimTemplates[0].spec.resources.requests.storage" 6Gi kubectl create -f tests/manifests/test-cluster-on-pvc-encrypted.yaml + kubectl patch -n rook-ceph cephcluster rook-ceph --type merge -p '{"spec":{"security":{"keyRotation":{"enabled": true, "schedule":"*/1 * * * *"}}}}' tests/scripts/github-action-helper.sh deploy_manifest_with_local_build deploy/examples/toolbox.yaml - name: wait for prepare pod @@ -1186,6 +1206,9 @@ jobs: tests/scripts/deploy-validate-vault.sh validate_osd sudo lsblk + - name: wait and verify key rotation + run: KUBERNETES_AUTH=true tests/scripts/deploy-validate-vault.sh validate_key_rotation rook/ver1 + - name: collect common logs if: always() uses: ./.github/workflows/collect-logs @@ -1200,7 +1223,7 @@ jobs: ceph-image: ${{ fromJson(inputs.ceph_images) }} steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -1208,6 +1231,7 @@ jobs: uses: ./.github/workflows/tmate_debug with: use-tmate: ${{ secrets.USE_TMATE }} + debug-ci: ${{ contains(github.event.pull_request.labels.*.name, 'debug-ci') }} - name: setup cluster resources uses: ./.github/workflows/canary-test-config @@ -1257,7 +1281,7 @@ jobs: ceph-image: ${{ fromJson(inputs.ceph_images) }} steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -1265,6 +1289,7 @@ jobs: uses: ./.github/workflows/tmate_debug with: use-tmate: ${{ secrets.USE_TMATE }} + debug-ci: ${{ contains(github.event.pull_request.labels.*.name, 'debug-ci') }} - name: setup cluster resources uses: ./.github/workflows/canary-test-config @@ -1516,7 +1541,7 @@ jobs: ceph-image: ${{ fromJson(inputs.ceph_images) }} steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -1524,6 +1549,7 @@ jobs: uses: ./.github/workflows/tmate_debug with: use-tmate: ${{ secrets.USE_TMATE }} + debug-ci: ${{ contains(github.event.pull_request.labels.*.name, 'debug-ci') }} - name: setup cluster resources uses: ./.github/workflows/canary-test-config @@ -1611,7 +1637,7 @@ jobs: matrix: ceph-image: ${{ fromJson(inputs.ceph_images) }} steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -1619,6 +1645,7 @@ jobs: uses: ./.github/workflows/tmate_debug with: use-tmate: ${{ secrets.USE_TMATE }} + debug-ci: ${{ contains(github.event.pull_request.labels.*.name, 'debug-ci') }} - name: run encryption KMS IBM Key Protect uses: ./.github/workflows/encryption-pvc-kms-ibm-kp @@ -1631,8 +1658,9 @@ jobs: ibm-service-api-key: ${{ secrets.IBM_SERVICE_API_KEY }} github-token: ${{ secrets.GITHUB_TOKEN }} artifact-name: ${{ github.job }}-${{ matrix.ceph-image }} + ceph-image: ${{ matrix.ceph-image }} - multus-cluster-network: + multus-public-and-cluster: runs-on: ubuntu-22.04 if: "!contains(github.event.pull_request.labels.*.name, 'skip-ci')" strategy: @@ -1640,7 +1668,7 @@ jobs: ceph-image: ${{ fromJson(inputs.ceph_images) }} steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -1648,46 +1676,52 @@ jobs: uses: ./.github/workflows/tmate_debug with: use-tmate: ${{ secrets.USE_TMATE }} - - - name: setup golang - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 - with: - go-version: "1.22" + debug-ci: ${{ contains(github.event.pull_request.labels.*.name, 'debug-ci') }} - name: setup cluster resources uses: ./.github/workflows/canary-test-config - name: set Ceph version in CephCluster manifest - run: tests/scripts/github-action-helper.sh replace_ceph_image "deploy/examples/cluster-test.yaml" "${{ matrix.ceph-image }}" + run: tests/scripts/github-action-helper.sh replace_ceph_image "deploy/examples/cluster-multus-test.yaml" "${{ matrix.ceph-image }}" - - name: allow holder pod deployment - run: sed -i "s|CSI_DISABLE_HOLDER_PODS|# CSI_DISABLE_HOLDER_PODS|g" "deploy/examples/operator.yaml" + - name: Setup multus + run: ./tests/scripts/multus/setup-multus.sh - - name: validate-yaml - run: tests/scripts/github-action-helper.sh validate_yaml + - name: Set up multus prerequisite host routing + run: kubectl create -f tests/scripts/multus/host-cfg-ds.yaml + + - name: create cluster prerequisites + run: tests/scripts/github-action-helper.sh create_cluster_prerequisites + + - name: Install public and cluster NADs in rook-ceph namespace + run: kubectl create -f tests/scripts/multus/rook-ceph-public-cluster-nads.yaml - name: use local disk and create partitions for osds run: | tests/scripts/github-action-helper.sh use_local_disk tests/scripts/github-action-helper.sh create_partitions_for_osds - - name: deploy multus - run: tests/scripts/github-action-helper.sh deploy_multus + - name: deploy cluster + run: | + tests/scripts/github-action-helper.sh deploy_manifest_with_local_build deploy/examples/operator.yaml + + export BLOCK="$(tests/scripts/github-action-helper.sh find_extra_block_dev)" + yq write -i deploy/examples/cluster-multus-test.yaml "spec.storage.deviceFilter" "${BLOCK}" + kubectl create -f deploy/examples/cluster-multus-test.yaml + + tests/scripts/github-action-helper.sh deploy_toolbox - - name: deploy multus cluster - run: tests/scripts/github-action-helper.sh deploy_multus_cluster + kubectl create -f deploy/examples/filesystem-test.yaml + kubectl create -f deploy/examples/nfs-test.yaml - name: wait for prepare pod run: tests/scripts/github-action-helper.sh wait_for_prepare_pod 2 - name: wait for ceph to be ready - run: IS_POD_NETWORK=true IS_MULTUS=true tests/scripts/github-action-helper.sh wait_for_ceph_to_be_ready osd 2 - - - name: wait for ceph-csi configmap to be updated with network namespace - run: tests/scripts/github-action-helper.sh wait_for_ceph_csi_configmap_to_be_updated + run: tests/scripts/github-action-helper.sh wait_for_ceph_to_be_ready osd 2 - name: wait for cephnfs to be ready - run: IS_POD_NETWORK=true IS_MULTUS=true tests/scripts/github-action-helper.sh wait_for_ceph_to_be_ready nfs 1 + run: tests/scripts/github-action-helper.sh wait_for_ceph_to_be_ready nfs 1 - name: check multus connections run: tests/scripts/github-action-helper.sh test_multus_connections @@ -1708,64 +1742,6 @@ jobs: name: ${{ github.job }}-${{ matrix.ceph-image }} additional-namespace: kube-system - csi-hostnetwork-disabled: - runs-on: ubuntu-22.04 - if: "!contains(github.event.pull_request.labels.*.name, 'skip-ci')" - strategy: - matrix: - ceph-image: ${{ fromJson(inputs.ceph_images) }} - steps: - - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - with: - fetch-depth: 0 - - - name: consider debugging - uses: ./.github/workflows/tmate_debug - with: - use-tmate: ${{ secrets.USE_TMATE }} - - - name: setup cluster resources - uses: ./.github/workflows/canary-test-config - - - name: allow holder pod deployment - run: sed -i "s|CSI_DISABLE_HOLDER_PODS|# CSI_DISABLE_HOLDER_PODS|g" "deploy/examples/operator.yaml" - - - name: set Ceph version in CephCluster manifest - run: tests/scripts/github-action-helper.sh replace_ceph_image "deploy/examples/cluster-test.yaml" "${{ matrix.ceph-image }}" - - - name: use local disk and create partitions for osds - run: | - tests/scripts/github-action-helper.sh use_local_disk - tests/scripts/github-action-helper.sh create_partitions_for_osds - - - name: deploy CSI hostNetworking disabled cluster - run: tests/scripts/github-action-helper.sh deploy_csi_hostnetwork_disabled_cluster - - - name: wait for prepare pod - run: tests/scripts/github-action-helper.sh wait_for_prepare_pod 2 - - - name: wait for ceph to be ready - run: IS_POD_NETWORK=true tests/scripts/github-action-helper.sh wait_for_ceph_to_be_ready osd 2 - - - name: wait for ceph-csi configmap to be updated with network namespace - run: tests/scripts/github-action-helper.sh wait_for_ceph_csi_configmap_to_be_updated - - - name: test ceph-csi-rbd plugin restart - run: tests/scripts/github-action-helper.sh test_csi_rbd_workload - - - name: test ceph-csi-cephfs plugin restart - run: tests/scripts/github-action-helper.sh test_csi_cephfs_workload - - - name: test ceph-csi-nfs plugin restart - run: tests/scripts/github-action-helper.sh test_csi_nfs_workload - - - name: collect common logs - if: always() - uses: ./.github/workflows/collect-logs - with: - name: ${{ github.job }}-${{ matrix.ceph-image }} - two-object-one-zone: runs-on: ubuntu-22.04 if: "!contains(github.event.pull_request.labels.*.name, 'skip-ci')" @@ -1774,7 +1750,7 @@ jobs: ceph-image: ${{ fromJson(inputs.ceph_images) }} steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -1782,6 +1758,7 @@ jobs: uses: ./.github/workflows/tmate_debug with: use-tmate: ${{ secrets.USE_TMATE }} + debug-ci: ${{ contains(github.event.pull_request.labels.*.name, 'debug-ci') }} - name: setup cluster resources uses: ./.github/workflows/canary-test-config diff --git a/.github/workflows/codegen.yml b/.github/workflows/codegen.yml index 74fb05769987..b4f24a46590a 100644 --- a/.github/workflows/codegen.yml +++ b/.github/workflows/codegen.yml @@ -30,11 +30,11 @@ jobs: if: "!contains(github.event.pull_request.labels.*.name, 'skip-ci')" steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 - - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 + - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 with: go-version: "1.22" diff --git a/.github/workflows/codespell.yaml b/.github/workflows/codespell.yaml index 57ebcf8fd8cb..e5aaebd88294 100644 --- a/.github/workflows/codespell.yaml +++ b/.github/workflows/codespell.yaml @@ -24,7 +24,7 @@ jobs: name: codespell runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 - name: codespell @@ -53,7 +53,7 @@ jobs: name: misspell runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 - name: misspell diff --git a/.github/workflows/commitlint.yml b/.github/workflows/commitlint.yml index e388f24857f4..1f7cb2f0935d 100644 --- a/.github/workflows/commitlint.yml +++ b/.github/workflows/commitlint.yml @@ -28,7 +28,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 - uses: wagoid/commitlint-github-action@3d28780bbf0365e29b144e272b2121204d5be5f3 # v6.1.2 diff --git a/.github/workflows/crds-gen.yml b/.github/workflows/crds-gen.yml index 8916627bff23..55c43dcb0bf7 100644 --- a/.github/workflows/crds-gen.yml +++ b/.github/workflows/crds-gen.yml @@ -29,11 +29,11 @@ jobs: runs-on: ubuntu-22.04 steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 - - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 + - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 with: go-version: "1.22" diff --git a/.github/workflows/daily-nightly-jobs.yml b/.github/workflows/daily-nightly-jobs.yml index a5bf2f89f4ed..d211e03a1e1d 100644 --- a/.github/workflows/daily-nightly-jobs.yml +++ b/.github/workflows/daily-nightly-jobs.yml @@ -19,7 +19,7 @@ jobs: steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -29,7 +29,7 @@ jobs: use-tmate: ${{ secrets.USE_TMATE }} - name: setup golang - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 + uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 with: go-version: "1.22" @@ -116,7 +116,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -156,7 +156,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -196,7 +196,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -236,7 +236,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -276,7 +276,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -317,7 +317,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 diff --git a/.github/workflows/docs-check.yml b/.github/workflows/docs-check.yml index 265ffff830dc..41b25dfd41d2 100644 --- a/.github/workflows/docs-check.yml +++ b/.github/workflows/docs-check.yml @@ -24,15 +24,15 @@ jobs: name: docs-check runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 - - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 + - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 with: go-version: "1.22" - - uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 + - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 with: python-version: 3.9 diff --git a/.github/workflows/encryption-pvc-kms-ibm-kp/action.yml b/.github/workflows/encryption-pvc-kms-ibm-kp/action.yml index 4e9975eaba03..8dd63ee863a9 100644 --- a/.github/workflows/encryption-pvc-kms-ibm-kp/action.yml +++ b/.github/workflows/encryption-pvc-kms-ibm-kp/action.yml @@ -10,6 +10,9 @@ inputs: artifact-name: description: the name of the artifact where logs will be stored required: true + ceph-image: + description: the name of ceph image + required: true runs: using: "composite" @@ -27,7 +30,7 @@ runs: - name: set Ceph version in CephCluster manifest shell: bash --noprofile --norc -eo pipefail -x {0} - run: tests/scripts/github-action-helper.sh replace_ceph_image "deploy/examples/cluster-test.yaml" "${{ github.event.inputs.ceph-image }}" + run: tests/scripts/github-action-helper.sh replace_ceph_image "deploy/examples/cluster-test.yaml" "${{ inputs.ceph-image }}" - name: use local disk and create partitions for osds shell: bash --noprofile --norc -eo pipefail -x {0} diff --git a/.github/workflows/golangci-lint.yaml b/.github/workflows/golangci-lint.yaml index 89df3980ab52..0d7198753afc 100644 --- a/.github/workflows/golangci-lint.yaml +++ b/.github/workflows/golangci-lint.yaml @@ -24,10 +24,10 @@ jobs: name: golangci-lint runs-on: ubuntu-latest steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 - - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 + - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 with: go-version: "1.22" - name: golangci-lint @@ -52,7 +52,7 @@ jobs: name: govulncheck runs-on: ubuntu-latest steps: - - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 + - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 with: go-version: "1.22.5" check-latest: true diff --git a/.github/workflows/helm-lint.yaml b/.github/workflows/helm-lint.yaml index 8a57bf6349fb..b274a01038e1 100644 --- a/.github/workflows/helm-lint.yaml +++ b/.github/workflows/helm-lint.yaml @@ -26,7 +26,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -35,7 +35,7 @@ jobs: with: version: v3.6.2 - - uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 + - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 with: python-version: 3.9 diff --git a/.github/workflows/integration-test-helm-suite.yaml b/.github/workflows/integration-test-helm-suite.yaml index f00ccdc79bef..8d30d681ccc3 100644 --- a/.github/workflows/integration-test-helm-suite.yaml +++ b/.github/workflows/integration-test-helm-suite.yaml @@ -31,7 +31,7 @@ jobs: kubernetes-versions: ["v1.26.15", "v1.31.0"] steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -39,6 +39,7 @@ jobs: uses: ./.github/workflows/tmate_debug with: use-tmate: ${{ secrets.USE_TMATE }} + debug-ci: ${{ contains(github.event.pull_request.labels.*.name, 'debug-ci') }} - name: setup latest cluster resources uses: ./.github/workflows/integration-test-config-latest-k8s diff --git a/.github/workflows/integration-test-keystone-auth-suite.yaml b/.github/workflows/integration-test-keystone-auth-suite.yaml index 014652a5cf2c..5d4db9c53ea7 100644 --- a/.github/workflows/integration-test-keystone-auth-suite.yaml +++ b/.github/workflows/integration-test-keystone-auth-suite.yaml @@ -31,7 +31,7 @@ jobs: kubernetes-versions: ["v1.26.15", "v1.31.0"] steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -39,6 +39,7 @@ jobs: uses: ./.github/workflows/tmate_debug with: use-tmate: ${{ secrets.USE_TMATE }} + debug-ci: ${{ contains(github.event.pull_request.labels.*.name, 'debug-ci') }} - name: setup latest cluster resources uses: ./.github/workflows/integration-test-config-latest-k8s diff --git a/.github/workflows/integration-test-mgr-suite.yaml b/.github/workflows/integration-test-mgr-suite.yaml index 916feff75c32..68a56d486703 100644 --- a/.github/workflows/integration-test-mgr-suite.yaml +++ b/.github/workflows/integration-test-mgr-suite.yaml @@ -30,7 +30,7 @@ jobs: kubernetes-versions: ["v1.31.0"] steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -38,6 +38,7 @@ jobs: uses: ./.github/workflows/tmate_debug with: use-tmate: ${{ secrets.USE_TMATE }} + debug-ci: ${{ contains(github.event.pull_request.labels.*.name, 'debug-ci') }} - name: setup cluster resources uses: ./.github/workflows/integration-test-config-latest-k8s diff --git a/.github/workflows/integration-test-multi-cluster-suite.yaml b/.github/workflows/integration-test-multi-cluster-suite.yaml index cc1f242522ae..05233cf08a41 100644 --- a/.github/workflows/integration-test-multi-cluster-suite.yaml +++ b/.github/workflows/integration-test-multi-cluster-suite.yaml @@ -31,7 +31,7 @@ jobs: kubernetes-versions: ["v1.31.0"] steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -39,6 +39,7 @@ jobs: uses: ./.github/workflows/tmate_debug with: use-tmate: ${{ secrets.USE_TMATE }} + debug-ci: ${{ contains(github.event.pull_request.labels.*.name, 'debug-ci') }} - name: setup cluster resources uses: ./.github/workflows/integration-test-config-latest-k8s diff --git a/.github/workflows/integration-test-object-suite.yaml b/.github/workflows/integration-test-object-suite.yaml index d3980eed037a..fa13bcd91760 100644 --- a/.github/workflows/integration-test-object-suite.yaml +++ b/.github/workflows/integration-test-object-suite.yaml @@ -31,7 +31,7 @@ jobs: kubernetes-versions: ["v1.26.15", "v1.31.0"] steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -39,6 +39,7 @@ jobs: uses: ./.github/workflows/tmate_debug with: use-tmate: ${{ secrets.USE_TMATE }} + debug-ci: ${{ contains(github.event.pull_request.labels.*.name, 'debug-ci') }} - name: setup latest cluster resources uses: ./.github/workflows/integration-test-config-latest-k8s diff --git a/.github/workflows/integration-test-smoke-suite.yaml b/.github/workflows/integration-test-smoke-suite.yaml index d64bcdf01061..5712ed754c1d 100644 --- a/.github/workflows/integration-test-smoke-suite.yaml +++ b/.github/workflows/integration-test-smoke-suite.yaml @@ -31,7 +31,7 @@ jobs: kubernetes-versions: ["v1.26.15", "v1.31.0"] steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -39,6 +39,7 @@ jobs: uses: ./.github/workflows/tmate_debug with: use-tmate: ${{ secrets.USE_TMATE }} + debug-ci: ${{ contains(github.event.pull_request.labels.*.name, 'debug-ci') }} - name: setup cluster resources uses: ./.github/workflows/integration-test-config-latest-k8s diff --git a/.github/workflows/integration-test-upgrade-suite.yaml b/.github/workflows/integration-test-upgrade-suite.yaml index 99051c6f1b4b..c4c384e87569 100644 --- a/.github/workflows/integration-test-upgrade-suite.yaml +++ b/.github/workflows/integration-test-upgrade-suite.yaml @@ -31,7 +31,7 @@ jobs: kubernetes-versions: ["v1.26.15", "v1.31.0"] steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -39,6 +39,7 @@ jobs: uses: ./.github/workflows/tmate_debug with: use-tmate: ${{ secrets.USE_TMATE }} + debug-ci: ${{ contains(github.event.pull_request.labels.*.name, 'debug-ci') }} - name: setup cluster resources uses: ./.github/workflows/integration-test-config-latest-k8s @@ -75,7 +76,7 @@ jobs: kubernetes-versions: ["v1.26.15", "v1.31.0"] steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -83,6 +84,7 @@ jobs: uses: ./.github/workflows/tmate_debug with: use-tmate: ${{ secrets.USE_TMATE }} + debug-ci: ${{ contains(github.event.pull_request.labels.*.name, 'debug-ci') }} - name: setup cluster resources uses: ./.github/workflows/integration-test-config-latest-k8s diff --git a/.github/workflows/integration-tests-on-release.yaml b/.github/workflows/integration-tests-on-release.yaml index 32bd9039d5b2..e4fb4c5c3f15 100644 --- a/.github/workflows/integration-tests-on-release.yaml +++ b/.github/workflows/integration-tests-on-release.yaml @@ -24,7 +24,7 @@ jobs: kubernetes-versions: ["v1.26.15", "v1.28.12", "v1.29.7", "v1.31.0"] steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -64,7 +64,7 @@ jobs: kubernetes-versions: ["v1.26.15", "v1.28.12", "v1.29.7", "v1.31.0"] steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -105,7 +105,7 @@ jobs: kubernetes-versions: ["v1.26.15", "v1.28.12", "v1.29.7", "v1.31.0"] steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -143,7 +143,7 @@ jobs: kubernetes-versions: ["v1.26.15", "v1.28.12", "v1.29.7", "v1.31.0"] steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -181,7 +181,7 @@ jobs: kubernetes-versions: ["v1.26.15", "v1.28.12", "v1.29.7", "v1.31.0"] steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 @@ -222,7 +222,7 @@ jobs: kubernetes-versions: ["v1.26.15", "v1.31.0"] steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 diff --git a/.github/workflows/linters.yaml b/.github/workflows/linters.yaml index 810eb2417503..59d8dba4e100 100644 --- a/.github/workflows/linters.yaml +++ b/.github/workflows/linters.yaml @@ -23,12 +23,12 @@ jobs: yaml-linter: runs-on: ubuntu-latest steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 - name: Set up Python - uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 + uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 with: python-version: 3.9 @@ -41,12 +41,12 @@ jobs: pylint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 - name: Set up Python - uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 + uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 with: python-version: 3.9 diff --git a/.github/workflows/mod-check.yml b/.github/workflows/mod-check.yml index 108eac712b91..5ff39fa02d6c 100644 --- a/.github/workflows/mod-check.yml +++ b/.github/workflows/mod-check.yml @@ -29,11 +29,11 @@ jobs: runs-on: ubuntu-22.04 steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 - - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 + - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 with: go-version: "1.22" diff --git a/.github/workflows/multus.yaml b/.github/workflows/multus.yaml index 21c172ebf491..0be92c9e88b7 100644 --- a/.github/workflows/multus.yaml +++ b/.github/workflows/multus.yaml @@ -36,12 +36,12 @@ jobs: NUMBER_OF_COMPUTE_NODES: 5 steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 - name: Set up Go version - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 + uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 with: go-version: "1.22" @@ -55,6 +55,7 @@ jobs: uses: ./.github/workflows/tmate_debug with: use-tmate: ${{ secrets.USE_TMATE }} + debug-ci: ${{ contains(github.event.pull_request.labels.*.name, 'debug-ci') }} - name: Setup multus run: ./tests/scripts/multus/setup-multus.sh diff --git a/.github/workflows/push-build.yaml b/.github/workflows/push-build.yaml index 8f5c08302461..adae7dd729df 100644 --- a/.github/workflows/push-build.yaml +++ b/.github/workflows/push-build.yaml @@ -21,11 +21,11 @@ jobs: if: github.repository == 'rook/rook' steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 - - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 + - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 with: go-version: "1.22" diff --git a/.github/workflows/rbac-gen.yaml b/.github/workflows/rbac-gen.yaml index be342bf72620..b4887cb5fefd 100644 --- a/.github/workflows/rbac-gen.yaml +++ b/.github/workflows/rbac-gen.yaml @@ -29,11 +29,11 @@ jobs: runs-on: ubuntu-22.04 steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 - - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 + - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 with: go-version: "1.22" diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 3cebd2816234..0674e43183e6 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -28,7 +28,7 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false @@ -64,6 +64,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard (optional). # Commenting out will disable upload of results to your repo's Code Scanning dashboard - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@f779452ac5af1c261dce0346a8f964149f49322b # v3.26.13 + uses: github/codeql-action/upload-sarif@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0 with: sarif_file: results.sarif diff --git a/.github/workflows/shellcheck.yaml b/.github/workflows/shellcheck.yaml index 4fdca1376bf4..bd8d999e8880 100644 --- a/.github/workflows/shellcheck.yaml +++ b/.github/workflows/shellcheck.yaml @@ -24,7 +24,7 @@ jobs: name: Shellcheck runs-on: ubuntu-latest steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Run ShellCheck uses: ludeeus/action-shellcheck@00b27aa7cb85167568cb48a3838b75f4265f2bca # master with: diff --git a/.github/workflows/snyk.yaml b/.github/workflows/snyk.yaml index 193e78e53822..aee260d93f92 100644 --- a/.github/workflows/snyk.yaml +++ b/.github/workflows/snyk.yaml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 diff --git a/.github/workflows/tmate_debug/action.yml b/.github/workflows/tmate_debug/action.yml index b6a32e5f570d..93c2d5772513 100644 --- a/.github/workflows/tmate_debug/action.yml +++ b/.github/workflows/tmate_debug/action.yml @@ -4,12 +4,15 @@ inputs: use-tmate: description: "boolean for enabling TMATE" required: true + debug-ci: + description: "boolean for debug-ci label in PR" + requnred: false runs: using: "composite" steps: - name: consider debugging shell: bash --noprofile --norc -eo pipefail -x {0} - if: runner.debug || contains(github.event.pull_request.labels.*.name, 'debug-ci') + if: runner.debug || inputs.debug-ci == 'true' run: | # Enable tmate only in the Rook fork, where the USE_TMATE secret is set in the repo, or if the action is re-run if [ "$GITHUB_REPOSITORY_OWNER" = "rook" ] || [ -n "${{ inputs.use-tmate }}" ] || [ "$GITHUB_RUN_ATTEMPT" -gt 1 ]; then diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 3167fd74315a..7048624739ff 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -37,11 +37,11 @@ jobs: if: "!contains(github.event.pull_request.labels.*.name, 'skip-ci')" steps: - name: checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 - - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 + - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 with: go-version: "1.22" diff --git a/.mergify.yml b/.mergify.yml index 6dae0ac98080..28efa4c2c534 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -272,7 +272,7 @@ pull_request_rules: - "check-success=canary-tests / multi-cluster-mirroring (quay.io/ceph/ceph:v18)" - "check-success=canary-tests / rgw-multisite-testing (quay.io/ceph/ceph:v18)" - "check-success=canary-tests / encryption-pvc-kms-ibm-kp (quay.io/ceph/ceph:v18)" - - "check-success=canary-tests / multus-cluster-network (quay.io/ceph/ceph:v18)" + - "check-success=canary-tests / multus-cluster-network (quay.io/ceph/ceph:v18)" # note: changed name for 1.16 (multus-public-and-cluster) - "check-success=canary-tests / csi-hostnetwork-disabled (quay.io/ceph/ceph:v18)" - "check-success=TestCephSmokeSuite (v1.26.15)" - "check-success=TestCephSmokeSuite (v1.31.0)" diff --git a/Documentation/CRDs/Block-Storage/ceph-block-pool-rados-namespace-crd.md b/Documentation/CRDs/Block-Storage/ceph-block-pool-rados-namespace-crd.md index 1354048de56b..104e2045fb8c 100644 --- a/Documentation/CRDs/Block-Storage/ceph-block-pool-rados-namespace-crd.md +++ b/Documentation/CRDs/Block-Storage/ceph-block-pool-rados-namespace-crd.md @@ -57,6 +57,9 @@ If any setting is unspecified, a suitable default will be used automatically. - `interval`: frequency of the snapshots. The interval can be specified in days, hours, or minutes using d, h, m suffix respectively. - `startTime`: optional, determines at what time the snapshot process starts, specified using the ISO 8601 time format. +!!! note + If mirroring is enabled, whether to monitor the status and the interval of status updates is based on the `statusCheck` spec values of the parent CephBlockPool CR. + ## Creating a Storage Class Once the RADOS namespace is created, an RBD-based StorageClass can be created to diff --git a/Documentation/CRDs/Cluster/ceph-cluster-crd.md b/Documentation/CRDs/Cluster/ceph-cluster-crd.md index fce6603648a1..fa449dd2523b 100755 --- a/Documentation/CRDs/Cluster/ceph-cluster-crd.md +++ b/Documentation/CRDs/Cluster/ceph-cluster-crd.md @@ -33,7 +33,7 @@ Settings can be specified at the global level to apply to the cluster as a whole Using the general `v19` tag is not recommended in production because it may lead to inconsistent versions of the image running across different nodes in the cluster. * `allowUnsupported`: If `true`, allow an unsupported major version of the Ceph release. Currently Reef and Squid are supported. Future versions such as Tentacle (v20) would require this to be set to `true`. Should be set to `false` in production. * `imagePullPolicy`: The image pull policy for the ceph daemon pods. Possible values are `Always`, `IfNotPresent`, and `Never`. The default is `IfNotPresent`. -* `dataDirHostPath`: The path on the host ([hostPath](https://kubernetes.io/docs/concepts/storage/volumes/#hostpath)) where config and data should be stored for each of the services. If the directory does not exist, it will be created. Because this directory persists on the host, it will remain after pods are deleted. Following paths and any of their subpaths **must not be used**: `/etc/ceph`, `/rook` or `/var/log/ceph`. +* `dataDirHostPath`: The path on the host ([hostPath](https://kubernetes.io/docs/concepts/storage/volumes/#hostpath)) where config and data should be stored for each of the services. If there are multiple clusters, the directory must be unique for each cluster. If the directory does not exist, it will be created. Because this directory persists on the host, it will remain after pods are deleted. Following paths and any of their subpaths **must not be used**: `/etc/ceph`, `/rook` or `/var/log/ceph`. * **WARNING**: For test scenarios, if you delete a cluster and start a new cluster on the same hosts, the path used by `dataDirHostPath` must be deleted. Otherwise, stale keys and other config will remain from the previous cluster and the new mons will fail to start. If this value is empty, each pod will get an ephemeral directory to store their config files that is tied to the lifetime of the pod running on that node. More details can be found in the Kubernetes [empty dir docs](https://kubernetes.io/docs/concepts/storage/volumes/#emptydir). * `skipUpgradeChecks`: if set to true Rook won't perform any upgrade checks on Ceph daemons during an upgrade. Use this at **YOUR OWN RISK**, only if you know what you're doing. To understand Rook's upgrade process of Ceph, read the [upgrade doc](../../Upgrade/rook-upgrade.md#ceph-version-upgrades). @@ -94,6 +94,8 @@ For more details on the mons and when to choose a number other than `3`, see the * For non-PVCs: `placement.all` and `placement.osd` * For PVCs: `placement.all` and inside the storageClassDeviceSets from the `placement` or `preparePlacement` * `flappingRestartIntervalHours`: Defines the time for which an OSD pod will sleep before restarting, if it stopped due to flapping. Flapping occurs where OSDs are marked `down` by Ceph more than 5 times in 600 seconds. The OSDs will stay down when flapping since they likely have a bad disk or other issue that needs investigation. If the issue with the OSD is fixed manually, the OSD pod can be manually restarted. The sleep is disabled if this interval is set to 0. + * `scheduleAlways`: Whether to always schedule OSD pods on nodes declared explicitly in the "nodes" section, even if they are + temporarily not schedulable. If set to true, consider adding placement tolerations for unschedulable nodes. * `fullRatio`: The ratio at which Ceph should block IO if the OSDs are too full. The default is 0.95. * `backfillFullRatio`: The ratio at which Ceph should stop backfilling data if the OSDs are too full. The default is 0.90. * `nearFullRatio`: The ratio at which Ceph should raise a health warning if the cluster is almost full. The default is 0.85. @@ -485,6 +487,7 @@ You can set resource requests/limits for Rook components through the [Resource R It scrapes for Ceph daemon core dumps and sends them to the Ceph manager crash module so that core dumps are centralized and can be easily listed/accessed. You can read more about the [Ceph Crash module](https://docs.ceph.com/docs/master/mgr/crash/). * `logcollector`: Set resource requests/limits for the log collector. When enabled, this container runs as side-car to each Ceph daemons. +* `cmd-reporter`: Set resource requests/limits for the jobs that detect the ceph version and collect network info. * `cleanup`: Set resource requests/limits for cleanup job, responsible for wiping cluster's data after uninstall * `exporter`: Set resource requests/limits for Ceph exporter. diff --git a/Documentation/CRDs/Cluster/external-cluster/advance-external.md b/Documentation/CRDs/Cluster/external-cluster/advance-external.md index 5034b0da9a69..4a273fc49693 100644 --- a/Documentation/CRDs/Cluster/external-cluster/advance-external.md +++ b/Documentation/CRDs/Cluster/external-cluster/advance-external.md @@ -16,7 +16,7 @@ you can export the settings from this cluster with the following steps. kubectl -n rook-ceph cp deploy/examples/external/create-external-cluster-resources.py $toolbox:/etc/ceph ``` -2. Exec to the toolbox pod and execute create-external-cluster-resources.py with needed options to create required [users and keys](/Documentation/CRDs/Cluster/external-cluster/provider-export.md#1-create-all-users-and-keys). +2. Exec to the toolbox pod and execute create-external-cluster-resources.py with needed options to create required [users and keys](provider-export.md#1-create-all-users-and-keys). !!! important For other clusters to connect to storage in this cluster, Rook must be configured with a networking configuration that is accessible from other clusters. Most commonly this is done by enabling host networking in the CephCluster CR so the Ceph daemons will be addressable by their host IPs. diff --git a/Documentation/CRDs/Cluster/external-cluster/external-cluster.md b/Documentation/CRDs/Cluster/external-cluster/external-cluster.md index 68b965fcedce..c788c508cb59 100644 --- a/Documentation/CRDs/Cluster/external-cluster/external-cluster.md +++ b/Documentation/CRDs/Cluster/external-cluster/external-cluster.md @@ -21,22 +21,22 @@ Create the desired types of storage in the provider Ceph cluster: ## Connect the external Ceph Provider cluster to the Rook consumer cluster -1) [Export config from the Provider Ceph cluster](/Documentation/CRDs/Cluster/external-cluster/provider-export.md). Configuration must be exported by the Ceph admin, such as a Ceph keyring and mon endpoints, that allows connection to the Ceph cluster. +1) [Export config from the Provider Ceph cluster](provider-export.md). Configuration must be exported by the Ceph admin, such as a Ceph keyring and mon endpoints, that allows connection to the Ceph cluster. -2) [Import config to the Rook consumer cluster](/Documentation/CRDs/Cluster/external-cluster/consumer-import.md). The configuration exported from the Ceph cluster is imported to Rook to provide the needed connection details. +2) [Import config to the Rook consumer cluster](consumer-import.md). The configuration exported from the Ceph cluster is imported to Rook to provide the needed connection details. ## Advance Options -* [NFS storage](/Documentation/CRDs/Cluster/external-cluster/advance-external.md#nfs-storage) +* [NFS storage](advance-external.md#nfs-storage) -* [Exporting Rook to another cluster](/Documentation/CRDs/Cluster/external-cluster/advance-external.md#exporting-rook-to-another-cluster) +* [Exporting Rook to another cluster](advance-external.md#exporting-rook-to-another-cluster) -* [Run consumer Rook cluster with Admin privileges](/Documentation/CRDs/Cluster/external-cluster/advance-external.md#admin-privileges) +* [Run consumer Rook cluster with Admin privileges](advance-external.md#admin-privileges) -* [Connect to an External Object Store](/Documentation/CRDs/Cluster/external-cluster/advance-external.md#connect-to-an-external-object-store) +* [Connect to an External Object Store](advance-external.md#connect-to-an-external-object-store) ## Upgrades -* [Upgrade external cluster](/Documentation/CRDs/Cluster/external-cluster/upgrade-external.md#upgrade-external-cluster) +* [Upgrade external cluster](upgrade-external.md#upgrade-external-cluster) -* [Utilize new features in upgrade](/Documentation/CRDs/Cluster/external-cluster/upgrade-external.md#upgrade-cluster-to-utilize-new-feature) +* [Utilize new features in upgrade](upgrade-external.md#upgrade-cluster-to-utilize-new-feature) diff --git a/Documentation/CRDs/Cluster/external-cluster/provider-export.md b/Documentation/CRDs/Cluster/external-cluster/provider-export.md index db64ab9584f0..c8e2195a8186 100644 --- a/Documentation/CRDs/Cluster/external-cluster/provider-export.md +++ b/Documentation/CRDs/Cluster/external-cluster/provider-export.md @@ -16,7 +16,7 @@ python3 create-external-cluster-resources.py --rbd-data-pool-name -- * `--alias-rbd-data-pool-name`: Provides an alias for the RBD data pool name, necessary if a special character is present in the pool name such as a period or underscore * `--rgw-endpoint`: (optional) The RADOS Gateway endpoint in the format `:` or `:`. * `--rgw-pool-prefix`: (optional) The prefix of the RGW pools. If not specified, the default prefix is `default` -* `--rgw-tls-cert-path`: (optional) RADOS Gateway endpoint TLS certificate file path +* `--rgw-tls-cert-path`: (optional) RADOS Gateway endpoint TLS certificate (or intermediate signing certificate) file path * `--rgw-skip-tls`: (optional) Ignore TLS certification validation when a self-signed certificate is provided (NOT RECOMMENDED) * `--rbd-metadata-ec-pool-name`: (optional) Provides the name of erasure coded RBD metadata pool, used for creating ECRBDStorageClass. * `--monitoring-endpoint`: (optional) Ceph Manager prometheus exporter endpoints (comma separated list of IP entries of active and standby mgrs) diff --git a/Documentation/CRDs/Cluster/external-cluster/upgrade-external.md b/Documentation/CRDs/Cluster/external-cluster/upgrade-external.md index 7ee3110ca525..eddcb8283f67 100644 --- a/Documentation/CRDs/Cluster/external-cluster/upgrade-external.md +++ b/Documentation/CRDs/Cluster/external-cluster/upgrade-external.md @@ -47,11 +47,11 @@ Argument that are decided using the Priority: command-line-args has more priorit 3. Make any desired modifications and additions to `config.ini`` -4. Run the python script again using the [config file](/Documentation/CRDs/Cluster/external-cluster/provider-export.md#config-file) +4. Run the python script again using the [config file](provider-export.md#config-file) -5. [Copy the bash output](/Documentation/CRDs/Cluster/external-cluster/provider-export.md#2-copy-the-bash-output) +5. [Copy the bash output](provider-export.md#2-copy-the-bash-output) -6. [Import-the-provider-data](/Documentation/CRDs/Cluster/external-cluster/consumer-import.md#import-the-provider-data) +6. [Import-the-provider-data](consumer-import.md#import-the-provider-data) !!! warning If the last-applied config is unavailable, run the current version of the script again using previously-applied config and CLI flags. diff --git a/Documentation/CRDs/Cluster/network-providers.md b/Documentation/CRDs/Cluster/network-providers.md index 142d8cda4576..c38607e4ea93 100644 --- a/Documentation/CRDs/Cluster/network-providers.md +++ b/Documentation/CRDs/Cluster/network-providers.md @@ -414,182 +414,3 @@ spec: } }' ``` - -## Holder Pod Deprecation - -Rook plans to remove CSI "holder" pods in Rook v1.16. CephCluster with `csi-*plugin-holder-*` pods -present in the Rook operator namespace must plan to set `CSI_DISABLE_HOLDER_PODS` to `"true"` after -Rook v1.14 is installed and before v1.16 is installed by following the migration sections below. -CephClusters with no holder pods do not need to follow migration steps. - -Helm users will set `csi.disableHolderPods: true` in values.yaml instead of `CSI_DISABLE_HOLDER_PODS`. - -CephClusters that do not use `network.provider: multus` can follow the -[Disabling Holder Pods](#disabling-holder-pods) section. - -CephClusters that use `network.provider: multus` will need to plan the migration more carefully. -Read the [Disabling Holder Pods with Multus](#disabling-holder-pods-with-multus) section in full -before beginning. - -!!! hint - To determine if holder pods are deployed, use - `kubectl --namespace $ROOK_OPERATOR get pods | grep plugin-holder` - -### Disabling Holder Pods with Multus - -This migration section applies when any CephCluster `network.provider` is `"multus"`. If the -scenario does not apply, skip ahead to the [Disabling Holder Pods](#disabling-holder-pods) section. - -**Step 1** - -Before setting `CSI_ENABLE_HOST_NETWORK: "true"` and `CSI_DISABLE_HOLDER_PODS: "true"`, thoroughly -read through the [Multus Prerequisites section](#multus-prerequisites). Use the prerequisites -section to develop a plan for modifying host configurations as well as the public -NetworkAttachmentDefinition. - -Once the plan is developed, execute the plan by following the steps below. - -**Step 2** - -First, modify the public NetworkAttachmentDefinition as needed. For example, it may be necessary to -add the `routes` directive to the Whereabouts IPAM configuration as in -[this example](#macvlan-whereabouts-node-static-ips). - -**Step 3** - -Next, modify the host configurations in the host configuration system. The host configuration system -may be something like PXE, ignition config, cloud-init, Ansible, or any other such system. A node -reboot is likely necessary to apply configuration updates, but wait until the next step to reboot -nodes. - -If desired, check that the NetworkAttachmentDefinition modification and host configurations are -compatible using the [Multus validation tool](#validating-multus-configuration). For the upgrade -case, use the `hostCheckOnly: true` config option or `--host-check-only` CLI flag. - -**Step 4** - -After the NetworkAttachmentDefinition is modified, OSD pods must be restarted. It is easiest to -complete this requirement at the same time nodes are being rebooted to apply configuration updates. - -For each node in the Kubernetes cluster: - -1. `cordon` and `drain` the node -2. Wait for all pods to drain -3. Reboot the node, ensuring the new host configuration will be applied -4. `uncordon` and `undrain` the node -5. Wait for the node to be rehydrated and stable -6. Proceed to the next node - -By following this process, host configurations will be updated, and OSDs are also automatically -restarted as part of the `drain` and `undrain` process on each node. - -OSDs can be restarted manually if node configuration updates do not require reboot. - -**Step 5** - -Once all nodes are running the new configuration and all OSDs have been restarted, check that the -new node and NetworkAttachmentDefinition configurations are compatible. To do so, verify that each -node can `ping` OSD pods via the public network. - -Use the [toolbox](../../Troubleshooting/ceph-toolbox.md) or the -[kubectl plugin](../../Troubleshooting/kubectl-plugin.md) to list OSD IPs. - -The example below uses -the kubectl plugin, and the OSD public network is 192.168.20.0/24. - -```console -$ kubectl rook-ceph ceph osd dump | grep 'osd\.' -osd.0 up in weight 1 up_from 7 up_thru 0 down_at 0 last_clean_interval [0,0) [v2:192.168.20.19:6800/213587265,v1:192.168.20.19:6801/213587265] [v2:192.168.30.1:6800/213587265,v1:192.168.30.1:6801/213587265] exists,up 7ebbc19a-d45a-4b12-8fef-0f9423a59e78 -osd.1 up in weight 1 up_from 24 up_thru 24 down_at 20 last_clean_interval [8,23) [v2:192.168.20.20:6800/3144257456,v1:192.168.20.20:6801/3144257456] [v2:192.168.30.2:6804/3145257456,v1:192.168.30.2:6805/3145257456] exists,up 146b27da-d605-4138-9748-65603ed0dfa5 -osd.2 up in weight 1 up_from 21 up_thru 0 down_at 20 last_clean_interval [18,20) [v2:192.168.20.21:6800/1809748134,v1:192.168.20.21:6801/1809748134] [v2:192.168.30.3:6804/1810748134,v1:192.168.30.3:6805/1810748134] exists,up ff3d6592-634e-46fd-a0e4-4fe9fafc0386 -``` - -Now check that each node (NODE) can reach OSDs over the public network: - -```console -$ ssh user@NODE -$ user@NODE $> ping -c3 192.168.20.19 -# [truncated, successful output] -$ user@NODE $> ping -c3 192.168.20.20 -# [truncated, successful output] -$ user@NODE $> ping -c3 192.168.20.21 -# [truncated, successful output] -``` - -If any node does not get a successful `ping` to a running OSD, it is not safe to proceed. A problem -may arise here for many reasons. Some reasons include: the host may not be properly attached to the -Multus public network, the public NetworkAttachmentDefinition may not be properly configured to -route back to the host, the host may have a firewall rule blocking the connection in either -direction, or the network switch may have a firewall rule blocking the connection. Diagnose and fix -the issue, then return to **Step 1**. - -**Step 6** - -If the above check succeeds for all nodes, proceed with the -[Disabling Holder Pods](#disabling-holder-pods) steps below. - -### Disabling Holder Pods - -**Step 1** - -If any CephClusters have Multus enabled (`network.provider: "multus"`), follow the -[Disabling Holder Pods with Multus](#disabling-holder-pods-with-multus) -steps above before continuing. - -**Step 2** - -Begin by setting `CSI_DISABLE_HOLDER_PODS: "true"`. If `CSI_ENABLE_HOST_NETWORK` is set to -`"false"`, also set this value to `"true"` at the same time. - -After this, `csi-*plugin-*` pods will restart, and `csi-*plugin-holder-*` pods will remain running. - -**Step 3** - -Check that CSI pods are using the correct host networking configuration using the example below as -guidance (in the example, `CSI_ENABLE_HOST_NETWORK` is `"true"`): - -```console -$ kubectl -n rook-ceph get -o yaml daemonsets.apps csi-rbdplugin | grep -i hostnetwork - hostNetwork: true -$ kubectl -n rook-ceph get -o yaml daemonsets.apps csi-cephfsplugin | grep -i hostnetwork - hostNetwork: true -$ kubectl -n rook-ceph get -o yaml daemonsets.apps csi-nfsplugin | grep -i hostnetwork - hostNetwork: true -``` - -**Step 4** - -At this stage, PVCs for running applications are still using the holder pods. These PVCs must be -migrated from the holder to the new network. Follow the below process to do so. - -For each node in the Kubernetes cluster: - -1. `cordon` and `drain` the node -2. Wait for all pods to drain -3. Delete all `csi-*plugin-holder*` pods on the node (a new holder will take it's place) -4. `uncordon` and `undrain` the node -5. Wait for the node to be rehydrated and stable -6. Proceed to the next node - -**Step 5** - -After this process is done for all Kubernetes nodes, it is safe to delete the `csi-*plugin-holder*` -daemonsets. - -Delete the holder daemonsets using the example below as guidance: - -```console -$ kubectl -n rook-ceph get daemonset -o name | grep plugin-holder -daemonset.apps/csi-cephfsplugin-holder-my-cluster -daemonset.apps/csi-rbdplugin-holder-my-cluster - -$ kubectl -n rook-ceph delete daemonset.apps/csi-cephfsplugin-holder-my-cluster -daemonset.apps "csi-cephfsplugin-holder-my-cluster" deleted - -$ kubectl -n rook-ceph delete daemonset.apps/csi-rbdplugin-holder-my-cluster -daemonset.apps "csi-rbdplugin-holder-my-cluster" deleted -``` - -**Step 6** - -The migration is now complete! Congratulations! diff --git a/Documentation/CRDs/specification.md b/Documentation/CRDs/specification.md index dd6949d64ffe..84312d3c0a30 100644 --- a/Documentation/CRDs/specification.md +++ b/Documentation/CRDs/specification.md @@ -3297,6 +3297,45 @@ map[string]string (Optional) + + +mirroringStatus
+ + +MirroringStatusSpec + + + + +(Optional) + + + + +mirroringInfo
+ + +MirroringInfoSpec + + + + +(Optional) + + + + +snapshotScheduleStatus
+ + +SnapshotScheduleStatusSpec + + + + +(Optional) + +

CephBlockPoolStatus @@ -8030,13 +8069,69 @@ HealthCheckSpec +

MirroringInfo +

+

+(Appears on:MirroringInfoSpec) +

+
+

MirroringInfo is the mirroring info of a given pool/radosnamespace

+
+ + + + + + + + + + + + + + + + + + + + + +
FieldDescription
+mode
+ +string + +
+(Optional) +

Mode is the mirroring mode

+
+site_name
+ +string + +
+(Optional) +

SiteName is the current site name

+
+peers
+ + +[]PeersSpec + + +
+(Optional) +

Peers are the list of peer sites connected to that cluster

+

MirroringInfoSpec

-(Appears on:CephBlockPoolStatus) +(Appears on:CephBlockPoolRadosNamespaceStatus, CephBlockPoolStatus)

-

MirroringInfoSpec is the status of the pool mirroring

+

MirroringInfoSpec is the status of the pool/radosnamespace mirroring

@@ -8048,16 +8143,16 @@ HealthCheckSpec @@ -8197,13 +8292,45 @@ MirroringPeerSpec
-PoolMirroringInfo
+MirroringInfo
- -PoolMirroringInfo + +MirroringInfo

-(Members of PoolMirroringInfo are embedded into this type.) +(Members of MirroringInfo are embedded into this type.)

(Optional)
+

MirroringStatus +

+

+(Appears on:MirroringStatusSpec) +

+
+

MirroringStatus is the pool/radosNamespace mirror status

+
+ + + + + + + + + + + + + +
FieldDescription
+summary
+ + +MirroringStatusSummarySpec + + +
+(Optional) +

Summary is the mirroring status summary

+

MirroringStatusSpec

-(Appears on:CephBlockPoolStatus) +(Appears on:CephBlockPoolRadosNamespaceStatus, CephBlockPoolStatus)

-

MirroringStatusSpec is the status of the pool mirroring

+

MirroringStatusSpec is the status of the pool/radosNamespace mirroring

@@ -8215,19 +8342,19 @@ MirroringPeerSpec @@ -8268,6 +8395,74 @@ string
-PoolMirroringStatus
+MirroringStatus
- -PoolMirroringStatus + +MirroringStatus

-(Members of PoolMirroringStatus are embedded into this type.) +(Members of MirroringStatus are embedded into this type.)

(Optional) -

PoolMirroringStatus is the mirroring status of a pool

+

MirroringStatus is the mirroring status of a pool/radosNamespace

+

MirroringStatusSummarySpec +

+

+(Appears on:MirroringStatus) +

+
+

MirroringStatusSummarySpec is the summary output of the command

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
FieldDescription
+health
+ +string + +
+(Optional) +

Health is the mirroring health

+
+daemon_health
+ +string + +
+(Optional) +

DaemonHealth is the health of the mirroring daemon

+
+image_health
+ +string + +
+(Optional) +

ImageHealth is the health of the mirrored image

+
+states
+ + +StatesSpec + + +
+(Optional) +

States is the various state for all mirrored images

+

Module

@@ -10560,7 +10755,7 @@ int

PeersSpec

-(Appears on:PoolMirroringInfo) +(Appears on:MirroringInfo)

PeersSpec contains peer details

@@ -10775,101 +10970,12 @@ string -

PoolMirroringInfo -

-

-(Appears on:MirroringInfoSpec) -

-
-

PoolMirroringInfo is the mirroring info of a given pool

-
- - - - - - - - - - - - - - - - - - - - - -
FieldDescription
-mode
- -string - -
-(Optional) -

Mode is the mirroring mode

-
-site_name
- -string - -
-(Optional) -

SiteName is the current site name

-
-peers
- - -[]PeersSpec - - -
-(Optional) -

Peers are the list of peer sites connected to that cluster

-
-

PoolMirroringStatus -

-

-(Appears on:MirroringStatusSpec) -

-
-

PoolMirroringStatus is the pool mirror status

-
- - - - - - - - - - - - - -
FieldDescription
-summary
- - -PoolMirroringStatusSummarySpec - - -
-(Optional) -

Summary is the mirroring status summary

-
-

PoolMirroringStatusSummarySpec +

PoolPlacementSpec

-(Appears on:PoolMirroringStatus) +(Appears on:ObjectSharedPoolsSpec)

-

PoolMirroringStatusSummarySpec is the summary output of the command

@@ -10881,80 +10987,26 @@ PoolMirroringStatusSummarySpec - - - - - - - - - - -
-health
- -string - -
-(Optional) -

Health is the mirroring health

-
-daemon_health
- -string - -
-(Optional) -

DaemonHealth is the health of the mirroring daemon

-
-image_health
+name
string
-(Optional) -

ImageHealth is the health of the mirrored image

+

Pool placement name. Name can be arbitrary. Placement with name “default” will be used as default.

-states
+default
- -StatesSpec - +bool
(Optional) -

States is the various state for all mirrored images

-
-

PoolPlacementSpec -

-

-(Appears on:ObjectSharedPoolsSpec) -

-
-
- - - - - - - - - - - @@ -12317,7 +12369,7 @@ string

SnapshotScheduleStatusSpec

-(Appears on:CephBlockPoolStatus) +(Appears on:CephBlockPoolRadosNamespaceStatus, CephBlockPoolStatus)

SnapshotScheduleStatusSpec is the status of the snapshot schedule

@@ -12453,7 +12505,7 @@ string

StatesSpec

-(Appears on:PoolMirroringStatusSummarySpec) +(Appears on:MirroringStatusSummarySpec)

StatesSpec are rbd images mirroring state

@@ -12810,6 +12862,18 @@ bool
+ + + +
FieldDescription
-name
- -string - -
-

Pool placement name. Name can be arbitrary. Placement with name “default” will be used as default.

+

Sets given placement as default. Only one placement in the list can be marked as default. +Default is false.

+scheduleAlways
+ +bool + +
+(Optional) +

Whether to always schedule OSDs on a node even if the node is not currently scheduleable or ready

+
onlyApplyOSDPlacement
bool diff --git a/Documentation/Helm-Charts/operator-chart.md b/Documentation/Helm-Charts/operator-chart.md index a78ddc1ad4e7..7fc7ec887b3b 100644 --- a/Documentation/Helm-Charts/operator-chart.md +++ b/Documentation/Helm-Charts/operator-chart.md @@ -52,7 +52,6 @@ The following table lists the configurable parameters of the rook-operator chart | `cephCommandsTimeoutSeconds` | The timeout for ceph commands in seconds | `"15"` | | `containerSecurityContext` | Set the container security context for the operator | `{"capabilities":{"drop":["ALL"]},"runAsGroup":2016,"runAsNonRoot":true,"runAsUser":2016}` | | `crds.enabled` | Whether the helm chart should create and update the CRDs. If false, the CRDs must be managed independently with deploy/examples/crds.yaml. **WARNING** Only set during first deployment. If later disabled the cluster may be DESTROYED. If the CRDs are deleted in this case, see [the disaster recovery guide](https://rook.io/docs/rook/latest/Troubleshooting/disaster-recovery/#restoring-crds-after-deletion) to restore them. | `true` | -| `csi.allowUnsupportedVersion` | Allow starting an unsupported ceph-csi image | `false` | | `csi.attacher.repository` | Kubernetes CSI Attacher image repository | `"registry.k8s.io/sig-storage/csi-attacher"` | | `csi.attacher.tag` | Attacher image tag | `"v4.6.1"` | | `csi.cephFSAttachRequired` | Whether to skip any attach operation altogether for CephFS PVCs. See more details [here](https://kubernetes-csi.github.io/docs/skip-attach.html#skip-attach-with-csi-driver-object). If cephFSAttachRequired is set to false it skips the volume attachments and makes the creation of pods using the CephFS PVC fast. **WARNING** It's highly discouraged to use this for CephFS RWO volumes. Refer to this [issue](https://github.com/kubernetes/kubernetes/issues/103305) for more details. | `true` | @@ -84,7 +83,6 @@ The following table lists the configurable parameters of the rook-operator chart | `csi.csiRBDPluginVolumeMount` | The volume mounts of the CephCSI RBD plugin DaemonSet | `nil` | | `csi.csiRBDProvisionerResource` | CEPH CSI RBD provisioner resource requirement list csi-omap-generator resources will be applied only if `enableOMAPGenerator` is set to `true` | see values.yaml | | `csi.disableCsiDriver` | Disable the CSI driver. | `"false"` | -| `csi.disableHolderPods` | Deprecation note: Rook uses "holder" pods to allow CSI to connect to the multus public network without needing hosts to the network. Holder pods are being removed. See issue for details: https://github.com/rook/rook/issues/13055. New Rook deployments should set this to "true". | `true` | | `csi.enableCSIEncryption` | Enable Ceph CSI PVC encryption support | `false` | | `csi.enableCSIHostNetwork` | Enable host networking for CSI CephFS and RBD nodeplugins. This may be necessary in some network configurations where the SDN does not provide access to an external cluster or there is significant drop in read/write performance | `true` | | `csi.enableCephfsDriver` | Enable Ceph CSI CephFS driver | `true` | diff --git a/Documentation/Storage-Configuration/Advanced/key-management-system.md b/Documentation/Storage-Configuration/Advanced/key-management-system.md index 841beb39bc82..098ebcc28ce1 100644 --- a/Documentation/Storage-Configuration/Advanced/key-management-system.md +++ b/Documentation/Storage-Configuration/Advanced/key-management-system.md @@ -21,7 +21,7 @@ The `security` section contains settings related to encryption of the cluster. * `schedule`: the schedule, written in [cron format](https://en.wikipedia.org/wiki/Cron), with which key rotation [CronJob](https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/) is created, default value is `"@weekly"`. !!! note - Currently key rotation is only supported for the default type, where the Key Encryption Keys are stored in a Kubernetes Secret. + Currently key rotation is supported when the Key Encryption Keys are stored in a Kubernetes Secret or Vault KMS. Supported KMS providers: diff --git a/Documentation/Storage-Configuration/Object-Storage-RGW/ceph-object-bucket-claim.md b/Documentation/Storage-Configuration/Object-Storage-RGW/ceph-object-bucket-claim.md index c2be34c68afe..a119b4c7144b 100644 --- a/Documentation/Storage-Configuration/Object-Storage-RGW/ceph-object-bucket-claim.md +++ b/Documentation/Storage-Configuration/Object-Storage-RGW/ceph-object-bucket-claim.md @@ -32,6 +32,8 @@ spec: additionalConfig: [6] maxObjects: "1000" maxSize: "2G" + bucketMaxObjects: "3000" + bucketMaxSize: "4G" ``` 1. `name` of the `ObjectBucketClaim`. This name becomes the name of the Secret and ConfigMap. @@ -45,8 +47,10 @@ If both `bucketName` and `generateBucketName` are blank or omitted then the stor 5. `storageClassName` which defines the StorageClass which contains the names of the bucket provisioner, the object-store and specifies the bucket retention policy. 6. `additionalConfig` is an optional list of key-value pairs used to define attributes specific to the bucket being provisioned by this OBC. This information is typically tuned to a particular bucket provisioner and may limit application portability. Options supported: - * `maxObjects`: The maximum number of objects in the bucket - * `maxSize`: The maximum size of the bucket, please note minimum recommended value is 4K. + * `maxObjects`: The maximum number of objects in the bucket as a quota on the user account automatically created for the bucket. + * `maxSize`: The maximum size of the bucket as a quota on the user account automatically created for the bucket. Please note minimum recommended value is 4K. + * `bucketMaxObjects`: The maximum number of objects in the bucket as an individual bucket quota. This is useful when the bucket is shared among multiple users. + * `bucketMaxSize`: The maximum size of the bucket as an individual bucket quota. ### OBC Custom Resource after Bucket Provisioning diff --git a/Documentation/Storage-Configuration/Object-Storage-RGW/object-storage.md b/Documentation/Storage-Configuration/Object-Storage-RGW/object-storage.md index 3ada73c7eb94..10123bef9077 100644 --- a/Documentation/Storage-Configuration/Object-Storage-RGW/object-storage.md +++ b/Documentation/Storage-Configuration/Object-Storage-RGW/object-storage.md @@ -201,14 +201,15 @@ Object Storage API allows users to override where bucket data will be stored dur To enable this feature, configure `poolPlacements` representing a list of possible bucket data locations. Each `poolPlacement` must have: -* a **unique** `name` to refer to it in `` or `X-Storage-Policy`. A placement with reserved name `default` will be used by default if no location constraint is provided. +* a **unique** `name` to refer to it in `` or `X-Storage-Policy`. Name `default-placement` is reserved and can be used **only** if placement also marked as `default`. +* **optional** `default` flag to use given placement by default, meaning that it will be used if no location constraint is provided. Only one placement in the list can be marked as default. * `dataPoolName` and `metadataPoolName` representing object data and metadata locations. In Rook, these data locations are backed by `CephBlockPool`. `poolPlacements` and `storageClasses` specs refer pools by name. This means that all pools should be defined in advance. Similarly to [sharedPools](#create-local-object-stores-with-shared-pools), the same pool can be reused across multiple ObjectStores and/or poolPlacements/storageClasses because of RADOS namespaces. Here, each pool will be namespaced with `..` key. * **optional** `dataNonECPoolName` - extra pool for data that cannot use erasure coding (ex: multi-part uploads). If not set, `metadataPoolName` will be used. * **optional** list of placement `storageClasses`. Classes defined per placement, which means that even classes of `default` placement will be available only within this placement and not others. Each placement will automatically have default storage class named `STANDARD`. `STANDARD` class always points to placement `dataPoolName` and cannot be removed or redefined. Each storage class must have: * `name` (unique within placement). RGW allows arbitrary name for StorageClasses, however some clients/libs insist on AWS names so it is recommended to use one of the valid `x-amz-storage-class` values for better compatibility: `STANDARD | REDUCED_REDUNDANCY | STANDARD_IA | ONEZONE_IA | INTELLIGENT_TIERING | GLACIER | DEEP_ARCHIVE | OUTPOSTS | GLACIER_IR | SNOW | EXPRESS_ONEZONE`. See [AWS docs](https://aws.amazon.com/s3/storage-classes/). * `dataPoolName` - overrides placement data pool when this class is selected by user. -Example: Configure `CephObjectStore` with `default` placement pointing to `us` pools and placement `europe` pointing to pools in corresponding geographies. These geographical locations are only an example. Placement name can be arbitrary and could reflect the backing pool's replication factor, device class, or failure domain. This example also defines storage class `REDUCED_REDUNDANCY` for each placement. +Example: Configure `CephObjectStore` with `default` placement `us` pools and placement `europe` pointing to pools in corresponding geographies. These geographical locations are only an example. Placement name can be arbitrary and could reflect the backing pool's replication factor, device class, or failure domain. This example also defines storage class `REDUCED_REDUNDANCY` for each placement. ```yaml apiVersion: ceph.rook.io/v1 @@ -222,7 +223,8 @@ spec: instances: 1 sharedPools: poolPlacements: - - name: default + - name: us + default: true metadataPoolName: "us-data-pool" dataPoolName: "us-meta-pool" storageClasses: diff --git a/Documentation/Storage-Configuration/ceph-teardown.md b/Documentation/Storage-Configuration/ceph-teardown.md index b207efc47659..702417841a83 100644 --- a/Documentation/Storage-Configuration/ceph-teardown.md +++ b/Documentation/Storage-Configuration/ceph-teardown.md @@ -12,7 +12,7 @@ Rook provides the following clean up options: To tear down the cluster, the following resources need to be cleaned up: * The resources created under Rook's namespace (default `rook-ceph`) such as the Rook operator created by `operator.yaml` and the cluster CR `cluster.yaml`. -* `/var/lib/rook/rook-ceph`: Path on each host in the cluster where configuration is stored by the ceph mons and osds +* All files under `dataDirHostPath` (default `/var/lib/rook`): Path on each host in the cluster where configuration is stored by ceph daemons. * Devices used by the OSDs If the default namespaces or paths such as `dataDirHostPath` are changed in the example yaml files, these namespaces and paths will need to be changed throughout these instructions. @@ -68,7 +68,7 @@ kubectl delete storageclass csi-cephfs These jobs will perform the following operations: - * Delete the namespace directory under `dataDirHostPath`, for example `/var/lib/rook/rook-ceph`, on all the nodes + * Delete the all files under `dataDirHostPath` on all the nodes * Wipe the data on the drives on all the nodes where OSDs were running in this cluster !!! note @@ -92,7 +92,7 @@ kubectl delete -f crds.yaml If the `cleanupPolicy` was not added to the CephCluster CR before deleting the cluster, these manual steps are required to tear down the cluster. -Connect to each machine and delete the namespace directory under `dataDirHostPath`, for example `/var/lib/rook/rook-ceph`. +Connect to each machine and delete all files under `dataDirHostPath`. #### Zapping Devices @@ -205,3 +205,4 @@ This cleanup is supported only for the following custom resources: | -------- | ------- | | CephFilesystemSubVolumeGroup | CSI stored RADOS OMAP details for pvc/volumesnapshots, subvolume snapshots, subvolume clones, subvolumes | | CephBlockPoolRadosNamespace | Images and snapshots in the RADOS namespace| +| CephBlockPool | Images and snapshots in the BlockPool| diff --git a/Documentation/Upgrade/rook-upgrade.md b/Documentation/Upgrade/rook-upgrade.md index e9197240f40d..9d6bc6e6bdad 100644 --- a/Documentation/Upgrade/rook-upgrade.md +++ b/Documentation/Upgrade/rook-upgrade.md @@ -49,22 +49,12 @@ those releases. official releases. Builds from the master branch can have functionality changed or removed at any time without compatibility support and without prior notice. -## Breaking changes in v1.15 - -* Rook has deprecated CSI network "holder" pods. - If there are pods named `csi-*plugin-holder-*` in the Rook operator namespace, see the - [detailed documentation](../CRDs/Cluster/network-providers.md#holder-pod-deprecation) - to disable them. This deprecation process is required before upgrading to the future Rook v1.16. - -* Ceph COSI driver images have been updated. This impacts existing COSI Buckets, BucketClaims, and - BucketAccesses. Update existing clusters following the guide - [here](https://github.com/rook/rook/discussions/14297). - -* CephObjectStore, CephObjectStoreUser, and OBC endpoint behavior has changed when CephObjectStore - `spec.hosting` configurations are set. Use the new `spec.hosting.advertiseEndpoint` config to - define required behavior as - [documented](../Storage-Configuration/Object-Storage-RGW/object-storage.md#object-store-endpoint). +## Breaking changes in v1.16 +* Rook fully deprecated CSI "holder" pods in Rook v1.16. Any Rook v1.15 CephCluster with + `csi-*plugin-holder-*` pods present in the Rook operator namespace must follow holder pod + removal migration steps outlined in + [v1.15 documentation](https://rook.io/docs/rook/v1.15/CRDs/Cluster/network-providers/?h=depre#holder-pod-deprecation). ## Considerations @@ -111,10 +101,6 @@ Also update optional resources like Prometheus monitoring noted more fully in th If Rook is installed via the Helm chart, Helm will handle some details of the upgrade itself. The upgrade steps in this guide will clarify what Helm handles automatically. -!!! important - If there are pods named `csi-*plugin-holder-*` in the Rook operator namespace, set the new - config `csi.disableHolderPods: false` in the values.yaml before upgrading to v1.15. - The `rook-ceph` helm chart upgrade performs the Rook upgrade. The `rook-ceph-cluster` helm chart upgrade performs a [Ceph upgrade](./ceph-upgrade.md) if the Ceph image is updated. The `rook-ceph` chart should be upgraded before `rook-ceph-cluster`, so the latest operator has the opportunity to update @@ -262,10 +248,3 @@ This cluster is finished: At this point, the Rook operator should be running version `rook/ceph:v1.15.0`. Verify the CephCluster health using the [health verification doc](health-verification.md). - -### **6. Disable holder pods** - -Rook has deprecated CSI network "holder" pods. If there are pods named -`csi-*plugin-holder-*` in the Rook operator namespace, see the -[detailed documentation](../CRDs/Cluster/network-providers.md#holder-pod-deprecation) -to disable them. This deprecation process is required before upgrading to the future Rook v1.16. diff --git a/Makefile b/Makefile index e0ffb3fdabc7..877635b80d0b 100644 --- a/Makefile +++ b/Makefile @@ -161,6 +161,7 @@ fmt: ## Check formatting of go sources. @$(MAKE) go.init @$(MAKE) go.fmt +gen.codegen: codegen codegen: ${CODE_GENERATOR} ## Run code generators. @build/codegen/codegen.sh @@ -191,20 +192,22 @@ bundle: csv-clean: ## Remove existing OLM files. @$(MAKE) -C images/ceph csv-clean -docs: helm-docs - +gen.crds: crds crds: $(CONTROLLER_GEN) $(YQ) @echo Updating CRD manifests @build/crds/build-crds.sh $(CONTROLLER_GEN) $(YQ) @GOBIN=$(GOBIN) build/crds/generate-crd-docs.sh @build/crds/validate-csv-crd-list.sh +gen.rbac: gen-rbac gen-rbac: $(HELM) $(YQ) ## Generate RBAC from Helm charts @# output only stdout to the file; stderr for debugging should keep going to stderr HELM=$(HELM) ./build/rbac/gen-common.sh HELM=$(HELM) ./build/rbac/gen-nfs-rbac.sh HELM=$(HELM) ./build/rbac/gen-psp.sh +gen.docs: docs +docs: helm-docs helm-docs: $(HELM_DOCS) ## Use helm-docs to generate documentation from helm charts $(HELM_DOCS) -c deploy/charts/rook-ceph \ -o ../../../Documentation/Helm-Charts/operator-chart.md \ @@ -232,11 +235,15 @@ docs-preview: ## Preview the documentation through mkdocs docs-build: ## Build the documentation to the `site/` directory mkdocs build --strict +gen.crd-docs: generate-docs-crds generate-docs-crds: ## Build the documentation for CRD @GOBIN=$(GOBIN) build/crds/generate-crd-docs.sh +generate: gen.codegen gen.crds gen.rbac gen.docs gen.crd-docs ## Update all generated files (code, manifests, charts, and docs). + + .PHONY: all build.common -.PHONY: build build.all install test check vet fmt codegen mod.check clean distclean prune +.PHONY: build build.all install test check vet fmt codegen gen.codegen gen.rbac gen.crds gen.crd-docs gen.docs generate mod.check clean distclean prune # ==================================================================================== # Help diff --git a/PendingReleaseNotes.md b/PendingReleaseNotes.md index 116f32932fc3..c4e63de81207 100644 --- a/PendingReleaseNotes.md +++ b/PendingReleaseNotes.md @@ -7,3 +7,4 @@ ## Features - Enable mirroring for CephBlockPoolRadosNamespaces (see [#14701](https://github.com/rook/rook/pull/14701)). +- Enable periodic monitoring for CephBlockPoolRadosNamespaces mirroring (see [#14896](https://github.com/rook/rook/pull/14896)). diff --git a/ROADMAP.md b/ROADMAP.md index c365a2aaca30..ec480f678c26 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -8,20 +8,21 @@ We hope that the items listed below will inspire further engagement from the com Any dates listed below and the specific issues that will ship in a given milestone are subject to change but should give a general idea of what we are planning. See the [GitHub project boards](https://github.com/rook/rook/projects) for the most up-to-date issues and their status. -## Rook Ceph 1.15 +## Rook Ceph 1.16 -The following high level features are targeted for Rook v1.15 (July 2024). For more detailed project tracking see the [v1.15 board](https://github.com/rook/rook/projects/32). +The following high level features are targeted for Rook v1.16 (December 2024). For more detailed project tracking see the [v1.16 board](https://github.com/orgs/rook/projects/6). +* Removed support for Ceph Quincy since at end of life [#14795](https://github.com/rook/rook/pull/14795) +* Enable mirroring for RADOS namespaces [#14701](https://github.com/rook/rook/pull/14701) * Replace a single OSD when a metadataDevice is configured with multiple OSDs [#13240](https://github.com/rook/rook/issues/13240) -* Multus-enabled clusters will potentially remove "holder" pods [#14289](https://github.com/rook/rook/issues/14289) +* Remove multus-enabled "holder" pods [#14289](https://github.com/rook/rook/issues/14289) +* OSD migration to enable encryption as a day 2 operation [#14719](https://github.com/rook/rook/pull/14719) * Key rotation for Ceph object store users [#11563](https://github.com/rook/rook/issues/11563) * CSI Driver - * Integrate the new Ceph-CSI operator [#14260](https://github.com/rook/rook/issues/14260) - * Ceph-CSI [v3.12](https://github.com/ceph/ceph-csi/issues?q=is%3Aopen+is%3Aissue+milestone%3Arelease-v3.12.0) - * Support log rotation for the Ceph-CSI pods [#12809](https://github.com/rook/rook/issues/12809) + * Continue integration of the new Ceph-CSI operator, targeted for stable in v1.17 [#14766](https://github.com/rook/rook/pull/14766) + * Ceph-CSI [v3.13](https://github.com/ceph/ceph-csi/issues?q=is%3Aopen+is%3Aissue+milestone%3Arelease-v3.13.0) ## Kubectl Plugin Features are planned for the [Kubectl Plugin](https://github.com/rook/kubectl-rook-ceph), though without a committed timeline. * Collect details to help troubleshoot the csi driver [#69](https://github.com/rook/kubectl-rook-ceph/issues/69) -* Support `radosgw-admin` commands from the plugin [#253](https://github.com/rook/kubectl-rook-ceph/issues/253) diff --git a/build/csv/ceph/ceph.rook.io_cephblockpoolradosnamespaces.yaml b/build/csv/ceph/ceph.rook.io_cephblockpoolradosnamespaces.yaml index 0ae9b98b7417..a5495f35ec31 100644 --- a/build/csv/ceph/ceph.rook.io_cephblockpoolradosnamespaces.yaml +++ b/build/csv/ceph/ceph.rook.io_cephblockpoolradosnamespaces.yaml @@ -81,8 +81,102 @@ spec: type: string nullable: true type: object + mirroringInfo: + properties: + details: + type: string + lastChanged: + type: string + lastChecked: + type: string + mode: + type: string + peers: + items: + properties: + client_name: + type: string + direction: + type: string + mirror_uuid: + type: string + site_name: + type: string + uuid: + type: string + type: object + type: array + site_name: + type: string + type: object + mirroringStatus: + properties: + details: + type: string + lastChanged: + type: string + lastChecked: + type: string + summary: + properties: + daemon_health: + type: string + health: + type: string + image_health: + type: string + states: + nullable: true + properties: + error: + type: integer + replaying: + type: integer + starting_replay: + type: integer + stopped: + type: integer + stopping_replay: + type: integer + syncing: + type: integer + unknown: + type: integer + type: object + type: object + type: object phase: type: string + snapshotScheduleStatus: + properties: + details: + type: string + lastChanged: + type: string + lastChecked: + type: string + snapshotSchedules: + items: + properties: + image: + type: string + items: + items: + properties: + interval: + type: string + start_time: + type: string + type: object + type: array + namespace: + type: string + pool: + type: string + type: object + nullable: true + type: array + type: object type: object x-kubernetes-preserve-unknown-fields: true required: diff --git a/build/csv/ceph/ceph.rook.io_cephclusters.yaml b/build/csv/ceph/ceph.rook.io_cephclusters.yaml index 862a6f38ace2..bdcc7017441e 100644 --- a/build/csv/ceph/ceph.rook.io_cephclusters.yaml +++ b/build/csv/ceph/ceph.rook.io_cephclusters.yaml @@ -1801,6 +1801,8 @@ spec: type: array onlyApplyOSDPlacement: type: boolean + scheduleAlways: + type: boolean storageClassDeviceSets: items: properties: diff --git a/build/csv/ceph/ceph.rook.io_cephobjectstores.yaml b/build/csv/ceph/ceph.rook.io_cephobjectstores.yaml index 3f86d6ffce5d..d56100724710 100644 --- a/build/csv/ceph/ceph.rook.io_cephobjectstores.yaml +++ b/build/csv/ceph/ceph.rook.io_cephobjectstores.yaml @@ -1484,6 +1484,8 @@ spec: dataPoolName: minLength: 1 type: string + default: + type: boolean metadataPoolName: minLength: 1 type: string diff --git a/build/csv/ceph/ceph.rook.io_cephobjectzones.yaml b/build/csv/ceph/ceph.rook.io_cephobjectzones.yaml index 52a8209f1ef8..11bffeb18c99 100644 --- a/build/csv/ceph/ceph.rook.io_cephobjectzones.yaml +++ b/build/csv/ceph/ceph.rook.io_cephobjectzones.yaml @@ -322,6 +322,8 @@ spec: dataPoolName: minLength: 1 type: string + default: + type: boolean metadataPoolName: minLength: 1 type: string diff --git a/build/csv/ceph/rook-ceph-external-cluster-script-config_v1_configmap.yaml b/build/csv/ceph/rook-ceph-external-cluster-script-config_v1_configmap.yaml index 6add7147eb49..9c92df5b05d3 100644 --- a/build/csv/ceph/rook-ceph-external-cluster-script-config_v1_configmap.yaml +++ b/build/csv/ceph/rook-ceph-external-cluster-script-config_v1_configmap.yaml @@ -361,1341 +361,1342 @@ data: ICAgICAgICkKICAgICAgICBvdXRwdXRfZ3JvdXAuYWRkX2FyZ3VtZW50KAogICAgICAgICAgICAi LS1yZ3ctdGxzLWNlcnQtcGF0aCIsCiAgICAgICAgICAgIGRlZmF1bHQ9IiIsCiAgICAgICAgICAg IHJlcXVpcmVkPUZhbHNlLAogICAgICAgICAgICBoZWxwPSJSQURPUyBHYXRld2F5IGVuZHBvaW50 - IFRMUyBjZXJ0aWZpY2F0ZSIsCiAgICAgICAgKQogICAgICAgIG91dHB1dF9ncm91cC5hZGRfYXJn - dW1lbnQoCiAgICAgICAgICAgICItLXJndy1za2lwLXRscyIsCiAgICAgICAgICAgIHJlcXVpcmVk - PUZhbHNlLAogICAgICAgICAgICBkZWZhdWx0PUZhbHNlLAogICAgICAgICAgICBoZWxwPSJJZ25v - cmUgVExTIGNlcnRpZmljYXRpb24gdmFsaWRhdGlvbiB3aGVuIGEgc2VsZi1zaWduZWQgY2VydGlm - aWNhdGUgaXMgcHJvdmlkZWQgKE5PVCBSRUNPTU1FTkRFRCIsCiAgICAgICAgKQogICAgICAgIG91 - dHB1dF9ncm91cC5hZGRfYXJndW1lbnQoCiAgICAgICAgICAgICItLW1vbml0b3JpbmctZW5kcG9p - bnQiLAogICAgICAgICAgICBkZWZhdWx0PSIiLAogICAgICAgICAgICByZXF1aXJlZD1GYWxzZSwK - ICAgICAgICAgICAgaGVscD0iQ2VwaCBNYW5hZ2VyIHByb21ldGhldXMgZXhwb3J0ZXIgZW5kcG9p - bnRzIChjb21tYSBzZXBhcmF0ZWQgbGlzdCBvZiAoZm9ybWF0IGA8SVB2ND5gIG9yIGA8W0lQdjZd - PmAgb3IgYDxGUUROPmApIGVudHJpZXMgb2YgYWN0aXZlIGFuZCBzdGFuZGJ5IG1ncnMpIiwKICAg - ICAgICApCiAgICAgICAgb3V0cHV0X2dyb3VwLmFkZF9hcmd1bWVudCgKICAgICAgICAgICAgIi0t - bW9uaXRvcmluZy1lbmRwb2ludC1wb3J0IiwKICAgICAgICAgICAgZGVmYXVsdD0iIiwKICAgICAg - ICAgICAgcmVxdWlyZWQ9RmFsc2UsCiAgICAgICAgICAgIGhlbHA9IkNlcGggTWFuYWdlciBwcm9t - ZXRoZXVzIGV4cG9ydGVyIHBvcnQiLAogICAgICAgICkKICAgICAgICBvdXRwdXRfZ3JvdXAuYWRk - X2FyZ3VtZW50KAogICAgICAgICAgICAiLS1za2lwLW1vbml0b3JpbmctZW5kcG9pbnQiLAogICAg - ICAgICAgICBkZWZhdWx0PUZhbHNlLAogICAgICAgICAgICBhY3Rpb249InN0b3JlX3RydWUiLAog - ICAgICAgICAgICBoZWxwPSJEbyBub3QgY2hlY2sgZm9yIGEgbW9uaXRvcmluZyBlbmRwb2ludCBm - b3IgdGhlIENlcGggY2x1c3RlciIsCiAgICAgICAgKQogICAgICAgIG91dHB1dF9ncm91cC5hZGRf - YXJndW1lbnQoCiAgICAgICAgICAgICItLXJiZC1tZXRhZGF0YS1lYy1wb29sLW5hbWUiLAogICAg - ICAgICAgICBkZWZhdWx0PSIiLAogICAgICAgICAgICByZXF1aXJlZD1GYWxzZSwKICAgICAgICAg - ICAgaGVscD0iUHJvdmlkZXMgdGhlIG5hbWUgb2YgZXJhc3VyZSBjb2RlZCBSQkQgbWV0YWRhdGEg - cG9vbCIsCiAgICAgICAgKQogICAgICAgIG91dHB1dF9ncm91cC5hZGRfYXJndW1lbnQoCiAgICAg - ICAgICAgICItLWRyeS1ydW4iLAogICAgICAgICAgICBkZWZhdWx0PUZhbHNlLAogICAgICAgICAg - ICBhY3Rpb249InN0b3JlX3RydWUiLAogICAgICAgICAgICBoZWxwPSJEcnkgcnVuIHByaW50cyB0 - aGUgZXhlY3V0ZWQgY29tbWFuZHMgd2l0aG91dCBydW5uaW5nIHRoZW0iLAogICAgICAgICkKICAg - ICAgICBvdXRwdXRfZ3JvdXAuYWRkX2FyZ3VtZW50KAogICAgICAgICAgICAiLS1yYWRvcy1uYW1l - c3BhY2UiLAogICAgICAgICAgICBkZWZhdWx0PSIiLAogICAgICAgICAgICByZXF1aXJlZD1GYWxz - ZSwKICAgICAgICAgICAgaGVscD0iRGl2aWRlcyBhIHBvb2wgaW50byBzZXBhcmF0ZSBsb2dpY2Fs - IG5hbWVzcGFjZXMsIHVzZWQgZm9yIGNyZWF0aW5nIFJCRCBQVkMgaW4gYSBDZXBoQmxvY2tQb29s - UmFkb3NOYW1lc3BhY2UgKHNob3VsZCBiZSBsb3dlciBjYXNlKSIsCiAgICAgICAgKQogICAgICAg - IG91dHB1dF9ncm91cC5hZGRfYXJndW1lbnQoCiAgICAgICAgICAgICItLXN1YnZvbHVtZS1ncm91 - cCIsCiAgICAgICAgICAgIGRlZmF1bHQ9IiIsCiAgICAgICAgICAgIHJlcXVpcmVkPUZhbHNlLAog - ICAgICAgICAgICBoZWxwPSJwcm92aWRlcyB0aGUgbmFtZSBvZiB0aGUgc3Vidm9sdW1lIGdyb3Vw + IFRMUyBjZXJ0aWZpY2F0ZSAob3IgaW50ZXJtZWRpYXRlIHNpZ25pbmcgY2VydGlmaWNhdGUpIiwK + ICAgICAgICApCiAgICAgICAgb3V0cHV0X2dyb3VwLmFkZF9hcmd1bWVudCgKICAgICAgICAgICAg + Ii0tcmd3LXNraXAtdGxzIiwKICAgICAgICAgICAgcmVxdWlyZWQ9RmFsc2UsCiAgICAgICAgICAg + IGRlZmF1bHQ9RmFsc2UsCiAgICAgICAgICAgIGhlbHA9Iklnbm9yZSBUTFMgY2VydGlmaWNhdGlv + biB2YWxpZGF0aW9uIHdoZW4gYSBzZWxmLXNpZ25lZCBjZXJ0aWZpY2F0ZSBpcyBwcm92aWRlZCAo + Tk9UIFJFQ09NTUVOREVEIiwKICAgICAgICApCiAgICAgICAgb3V0cHV0X2dyb3VwLmFkZF9hcmd1 + bWVudCgKICAgICAgICAgICAgIi0tbW9uaXRvcmluZy1lbmRwb2ludCIsCiAgICAgICAgICAgIGRl + ZmF1bHQ9IiIsCiAgICAgICAgICAgIHJlcXVpcmVkPUZhbHNlLAogICAgICAgICAgICBoZWxwPSJD + ZXBoIE1hbmFnZXIgcHJvbWV0aGV1cyBleHBvcnRlciBlbmRwb2ludHMgKGNvbW1hIHNlcGFyYXRl + ZCBsaXN0IG9mIChmb3JtYXQgYDxJUHY0PmAgb3IgYDxbSVB2Nl0+YCBvciBgPEZRRE4+YCkgZW50 + cmllcyBvZiBhY3RpdmUgYW5kIHN0YW5kYnkgbWdycykiLAogICAgICAgICkKICAgICAgICBvdXRw + dXRfZ3JvdXAuYWRkX2FyZ3VtZW50KAogICAgICAgICAgICAiLS1tb25pdG9yaW5nLWVuZHBvaW50 + LXBvcnQiLAogICAgICAgICAgICBkZWZhdWx0PSIiLAogICAgICAgICAgICByZXF1aXJlZD1GYWxz + ZSwKICAgICAgICAgICAgaGVscD0iQ2VwaCBNYW5hZ2VyIHByb21ldGhldXMgZXhwb3J0ZXIgcG9y + dCIsCiAgICAgICAgKQogICAgICAgIG91dHB1dF9ncm91cC5hZGRfYXJndW1lbnQoCiAgICAgICAg + ICAgICItLXNraXAtbW9uaXRvcmluZy1lbmRwb2ludCIsCiAgICAgICAgICAgIGRlZmF1bHQ9RmFs + c2UsCiAgICAgICAgICAgIGFjdGlvbj0ic3RvcmVfdHJ1ZSIsCiAgICAgICAgICAgIGhlbHA9IkRv + IG5vdCBjaGVjayBmb3IgYSBtb25pdG9yaW5nIGVuZHBvaW50IGZvciB0aGUgQ2VwaCBjbHVzdGVy IiwKICAgICAgICApCiAgICAgICAgb3V0cHV0X2dyb3VwLmFkZF9hcmd1bWVudCgKICAgICAgICAg - ICAgIi0tcmd3LXJlYWxtLW5hbWUiLAogICAgICAgICAgICBkZWZhdWx0PSIiLAogICAgICAgICAg - ICByZXF1aXJlZD1GYWxzZSwKICAgICAgICAgICAgaGVscD0icHJvdmlkZXMgdGhlIG5hbWUgb2Yg - dGhlIHJndy1yZWFsbSIsCiAgICAgICAgKQogICAgICAgIG91dHB1dF9ncm91cC5hZGRfYXJndW1l - bnQoCiAgICAgICAgICAgICItLXJndy16b25lLW5hbWUiLAogICAgICAgICAgICBkZWZhdWx0PSIi - LAogICAgICAgICAgICByZXF1aXJlZD1GYWxzZSwKICAgICAgICAgICAgaGVscD0icHJvdmlkZXMg - dGhlIG5hbWUgb2YgdGhlIHJndy16b25lIiwKICAgICAgICApCiAgICAgICAgb3V0cHV0X2dyb3Vw - LmFkZF9hcmd1bWVudCgKICAgICAgICAgICAgIi0tcmd3LXpvbmVncm91cC1uYW1lIiwKICAgICAg - ICAgICAgZGVmYXVsdD0iIiwKICAgICAgICAgICAgcmVxdWlyZWQ9RmFsc2UsCiAgICAgICAgICAg - IGhlbHA9InByb3ZpZGVzIHRoZSBuYW1lIG9mIHRoZSByZ3ctem9uZWdyb3VwIiwKICAgICAgICAp - CiAgICAgICAgb3V0cHV0X2dyb3VwLmFkZF9hcmd1bWVudCgKICAgICAgICAgICAgIi0tdG9wb2xv - Z3ktcG9vbHMiLAogICAgICAgICAgICBkZWZhdWx0PSIiLAogICAgICAgICAgICByZXF1aXJlZD1G - YWxzZSwKICAgICAgICAgICAgaGVscD0iY29tbWEtc2VwYXJhdGVkIGxpc3Qgb2YgdG9wb2xvZ3kt - Y29uc3RyYWluZWQgcmJkIHBvb2xzIiwKICAgICAgICApCiAgICAgICAgb3V0cHV0X2dyb3VwLmFk - ZF9hcmd1bWVudCgKICAgICAgICAgICAgIi0tdG9wb2xvZ3ktZmFpbHVyZS1kb21haW4tbGFiZWwi - LAogICAgICAgICAgICBkZWZhdWx0PSIiLAogICAgICAgICAgICByZXF1aXJlZD1GYWxzZSwKICAg - ICAgICAgICAgaGVscD0iazhzIGNsdXN0ZXIgZmFpbHVyZSBkb21haW4gbGFiZWwgKGV4YW1wbGU6 - IHpvbmUsIHJhY2ssIG9yIGhvc3QpIGZvciB0aGUgdG9wb2xvZ3ktcG9vbHMgdGhhdCBtYXRjaCB0 - aGUgY2VwaCBkb21haW4iLAogICAgICAgICkKICAgICAgICBvdXRwdXRfZ3JvdXAuYWRkX2FyZ3Vt - ZW50KAogICAgICAgICAgICAiLS10b3BvbG9neS1mYWlsdXJlLWRvbWFpbi12YWx1ZXMiLAogICAg - ICAgICAgICBkZWZhdWx0PSIiLAogICAgICAgICAgICByZXF1aXJlZD1GYWxzZSwKICAgICAgICAg - ICAgaGVscD0iY29tbWEtc2VwYXJhdGVkIGxpc3Qgb2YgdGhlIGs4cyBjbHVzdGVyIGZhaWx1cmUg - ZG9tYWluIHZhbHVlcyBjb3JyZXNwb25kaW5nIHRvIGVhY2ggb2YgdGhlIHBvb2xzIGluIHRoZSBg - dG9wb2xvZ3ktcG9vbHNgIGxpc3QiLAogICAgICAgICkKCiAgICAgICAgdXBncmFkZV9ncm91cCA9 - IGFyZ1AuYWRkX2FyZ3VtZW50X2dyb3VwKCJ1cGdyYWRlIikKICAgICAgICB1cGdyYWRlX2dyb3Vw - LmFkZF9hcmd1bWVudCgKICAgICAgICAgICAgIi0tdXBncmFkZSIsCiAgICAgICAgICAgIGFjdGlv - bj0ic3RvcmVfdHJ1ZSIsCiAgICAgICAgICAgIGRlZmF1bHQ9RmFsc2UsCiAgICAgICAgICAgIGhl - bHA9IlVwZ3JhZGVzIHRoZSBjZXBoQ1NJS2V5cmluZ3MoRm9yIGV4YW1wbGU6IGNsaWVudC5jc2kt - Y2VwaGZzLXByb3Zpc2lvbmVyKSBhbmQgY2xpZW50LmhlYWx0aGNoZWNrZXIgY2VwaCB1c2VycyB3 - aXRoIG5ldyBwZXJtaXNzaW9ucyBuZWVkZWQgZm9yIHRoZSBuZXcgY2x1c3RlciB2ZXJzaW9uIGFu - ZCBvbGRlciBwZXJtaXNzaW9uIHdpbGwgc3RpbGwgYmUgYXBwbGllZC4iCiAgICAgICAgICAgICsg - IlNhbXBsZSBydW46IGBweXRob24zIC9ldGMvY2VwaC9jcmVhdGUtZXh0ZXJuYWwtY2x1c3Rlci1y - ZXNvdXJjZXMucHkgLS11cGdyYWRlYCwgdGhpcyB3aWxsIHVwZ3JhZGUgYWxsIHRoZSBkZWZhdWx0 - IGNzaSB1c2Vycyhub24tcmVzdHJpY3RlZCkiCiAgICAgICAgICAgICsgIkZvciByZXN0cmljdGVk - IHVzZXJzKEZvciBleGFtcGxlOiBjbGllbnQuY3NpLWNlcGhmcy1wcm92aXNpb25lci1vcGVuc2hp - ZnQtc3RvcmFnZS1teWZzKSwgdXNlcnMgY3JlYXRlZCB1c2luZyAtLXJlc3RyaWN0ZWQtYXV0aC1w - ZXJtaXNzaW9uIGZsYWcgbmVlZCB0byBwYXNzIG1hbmRhdG9yeSBmbGFncyIKICAgICAgICAgICAg - KyAibWFuZGF0b3J5IGZsYWdzOiAnLS1yYmQtZGF0YS1wb29sLW5hbWUsIC0tazhzLWNsdXN0ZXIt - bmFtZSBhbmQgLS1ydW4tYXMtdXNlcicgZmxhZ3Mgd2hpbGUgdXBncmFkaW5nIgogICAgICAgICAg - ICArICJpbiBjYXNlIG9mIGNlcGhmcyB1c2VycyBpZiB5b3UgaGF2ZSBwYXNzZWQgLS1jZXBoZnMt - ZmlsZXN5c3RlbS1uYW1lIGZsYWcgd2hpbGUgY3JlYXRpbmcgdXNlciB0aGVuIHdoaWxlIHVwZ3Jh - ZGluZyBpdCB3aWxsIGJlIG1hbmRhdG9yeSB0b28iCiAgICAgICAgICAgICsgIlNhbXBsZSBydW46 - IGBweXRob24zIC9ldGMvY2VwaC9jcmVhdGUtZXh0ZXJuYWwtY2x1c3Rlci1yZXNvdXJjZXMucHkg - LS11cGdyYWRlIC0tcmJkLWRhdGEtcG9vbC1uYW1lIHJlcGxpY2Fwb29sIC0tazhzLWNsdXN0ZXIt - bmFtZSByb29rc3RvcmFnZSAgLS1ydW4tYXMtdXNlciBjbGllbnQuY3NpLXJiZC1ub2RlLXJvb2tz - dG9yYWdlLXJlcGxpY2Fwb29sYCIKICAgICAgICAgICAgKyAiUFM6IEFuIGV4aXN0aW5nIG5vbi1y - ZXN0cmljdGVkIHVzZXIgY2Fubm90IGJlIGNvbnZlcnRlZCB0byBhIHJlc3RyaWN0ZWQgdXNlciBi - eSB1cGdyYWRpbmcuIgogICAgICAgICAgICArICJVcGdyYWRlIGZsYWcgc2hvdWxkIG9ubHkgYmUg - dXNlZCB0byBhcHBlbmQgbmV3IHBlcm1pc3Npb25zIHRvIHVzZXJzLCBpdCBzaG91bGRuJ3QgYmUg - dXNlZCBmb3IgY2hhbmdpbmcgdXNlciBhbHJlYWR5IGFwcGxpZWQgcGVybWlzc2lvbiwgZm9yIGV4 - YW1wbGUgeW91IHNob3VsZG4ndCBjaGFuZ2UgaW4gd2hpY2ggcG9vbCB1c2VyIGhhcyBhY2Nlc3Mi - LAogICAgICAgICkKCiAgICAgICAgIyBBZGQgY29tbWFuZC1saW5lIGFyZ3VtZW50cwogICAgICAg - IGNvbmZpZ19ncm91cCA9IGFyZ1AuYWRkX2FyZ3VtZW50X2dyb3VwKCJjb25maWciKQogICAgICAg - IGNvbmZpZ19ncm91cC5hZGRfYXJndW1lbnQoCiAgICAgICAgICAgICItLWNvbmZpZy1maWxlIiwK - ICAgICAgICAgICAgdHlwZT1zdHIsCiAgICAgICAgICAgIGhlbHA9IlBhdGggdG8gdGhlIGNvbmZp - Z3VyYXRpb24gZmlsZSwgUHJpb3JpdHk6IGNvbW1hbmQtbGluZS1hcmdzID4gY29uZmlnLmluaSBm - aWxlIHZhbHVlcyA+IGRlZmF1bHQgdmFsdWVzIiwKICAgICAgICAgICAgcmVxdWlyZWQ9RmFsc2Us - CiAgICAgICAgICAgIGRlZmF1bHQ9IiIsCiAgICAgICAgKQoKICAgICAgICBpZiBhcmdzX3RvX3Bh - cnNlOgogICAgICAgICAgICBhc3NlcnQgKAogICAgICAgICAgICAgICAgdHlwZShhcmdzX3RvX3Bh - cnNlKSA9PSBsaXN0CiAgICAgICAgICAgICksICJBcmd1bWVudCB0byAnZ2VuX2FyZ19wYXJzZXIn - IHNob3VsZCBiZSBhIGxpc3QiCiAgICAgICAgZWxzZToKICAgICAgICAgICAgYXJnc190b19wYXJz - ZSA9IHN5cy5hcmd2WzE6XQogICAgICAgIHJldHVybiBhcmdQLnBhcnNlX2FyZ3MoYXJnc190b19w - YXJzZSkKCiAgICBkZWYgdmFsaWRhdGVfcmJkX21ldGFkYXRhX2VjX3Bvb2xfbmFtZShzZWxmKToK - ICAgICAgICBpZiBzZWxmLl9hcmdfcGFyc2VyLnJiZF9tZXRhZGF0YV9lY19wb29sX25hbWU6CiAg - ICAgICAgICAgIHJiZF9tZXRhZGF0YV9lY19wb29sX25hbWUgPSBzZWxmLl9hcmdfcGFyc2VyLnJi - ZF9tZXRhZGF0YV9lY19wb29sX25hbWUKICAgICAgICAgICAgcmJkX3Bvb2xfbmFtZSA9IHNlbGYu - X2FyZ19wYXJzZXIucmJkX2RhdGFfcG9vbF9uYW1lCgogICAgICAgICAgICBpZiByYmRfcG9vbF9u - YW1lID09ICIiOgogICAgICAgICAgICAgICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlv - bigKICAgICAgICAgICAgICAgICAgICAiRmxhZyAnLS1yYmQtZGF0YS1wb29sLW5hbWUnIHNob3Vs - ZCBub3QgYmUgZW1wdHkiCiAgICAgICAgICAgICAgICApCgogICAgICAgICAgICBpZiByYmRfbWV0 - YWRhdGFfZWNfcG9vbF9uYW1lID09ICIiOgogICAgICAgICAgICAgICAgcmFpc2UgRXhlY3V0aW9u - RmFpbHVyZUV4Y2VwdGlvbigKICAgICAgICAgICAgICAgICAgICAiRmxhZyAnLS1yYmQtbWV0YWRh - dGEtZWMtcG9vbC1uYW1lJyBzaG91bGQgbm90IGJlIGVtcHR5IgogICAgICAgICAgICAgICAgKQoK - ICAgICAgICAgICAgY21kX2pzb24gPSB7InByZWZpeCI6ICJvc2QgZHVtcCIsICJmb3JtYXQiOiAi - anNvbiJ9CiAgICAgICAgICAgIHJldF92YWwsIGpzb25fb3V0LCBlcnJfbXNnID0gc2VsZi5fY29t - bW9uX2NtZF9qc29uX2dlbihjbWRfanNvbikKICAgICAgICAgICAgaWYgcmV0X3ZhbCAhPSAwIG9y - IGxlbihqc29uX291dCkgPT0gMDoKICAgICAgICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1 - cmVFeGNlcHRpb24oCiAgICAgICAgICAgICAgICAgICAgZiJ7Y21kX2pzb25bJ3ByZWZpeCddfSBj - b21tYW5kIGZhaWxlZC5cbiIKICAgICAgICAgICAgICAgICAgICBmIkVycm9yOiB7ZXJyX21zZyBp - ZiByZXRfdmFsICE9IDAgZWxzZSBzZWxmLkVNUFRZX09VVFBVVF9MSVNUfSIKICAgICAgICAgICAg - ICAgICkKICAgICAgICAgICAgbWV0YWRhdGFfcG9vbF9leGlzdCwgcG9vbF9leGlzdCA9IEZhbHNl - LCBGYWxzZQoKICAgICAgICAgICAgZm9yIGtleSBpbiBqc29uX291dFsicG9vbHMiXToKICAgICAg - ICAgICAgICAgICMgaWYgZXJhc3VyZV9jb2RlX3Byb2ZpbGUgaXMgZW1wdHkgYW5kIHBvb2wgbmFt - ZSBleGlzdHMgdGhlbiBpdCByZXBsaWNhIHBvb2wKICAgICAgICAgICAgICAgIGlmICgKICAgICAg - ICAgICAgICAgICAgICBrZXlbImVyYXN1cmVfY29kZV9wcm9maWxlIl0gPT0gIiIKICAgICAgICAg - ICAgICAgICAgICBhbmQga2V5WyJwb29sX25hbWUiXSA9PSByYmRfbWV0YWRhdGFfZWNfcG9vbF9u - YW1lCiAgICAgICAgICAgICAgICApOgogICAgICAgICAgICAgICAgICAgIG1ldGFkYXRhX3Bvb2xf - ZXhpc3QgPSBUcnVlCiAgICAgICAgICAgICAgICAjIGlmIGVyYXN1cmVfY29kZV9wcm9maWxlIGlz - IG5vdCBlbXB0eSBhbmQgcG9vbCBuYW1lIGV4aXN0cyB0aGVuIGl0IGlzIGVjIHBvb2wKICAgICAg - ICAgICAgICAgIGlmIGtleVsiZXJhc3VyZV9jb2RlX3Byb2ZpbGUiXSBhbmQga2V5WyJwb29sX25h - bWUiXSA9PSByYmRfcG9vbF9uYW1lOgogICAgICAgICAgICAgICAgICAgIHBvb2xfZXhpc3QgPSBU - cnVlCgogICAgICAgICAgICBpZiBub3QgbWV0YWRhdGFfcG9vbF9leGlzdDoKICAgICAgICAgICAg - ICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1cmVFeGNlcHRpb24oCiAgICAgICAgICAgICAgICAgICAg - IlByb3ZpZGVkIHJiZF9lY19tZXRhZGF0YV9wb29sIG5hbWUsIgogICAgICAgICAgICAgICAgICAg - IGYiIHtyYmRfbWV0YWRhdGFfZWNfcG9vbF9uYW1lfSwgZG9lcyBub3QgZXhpc3QiCiAgICAgICAg - ICAgICAgICApCiAgICAgICAgICAgIGlmIG5vdCBwb29sX2V4aXN0OgogICAgICAgICAgICAgICAg - cmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlvbigKICAgICAgICAgICAgICAgICAgICBmIlBy - b3ZpZGVkIHJiZF9kYXRhX3Bvb2wgbmFtZSwge3JiZF9wb29sX25hbWV9LCBkb2VzIG5vdCBleGlz - dCIKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgcmV0dXJuIHJiZF9tZXRhZGF0YV9lY19w - b29sX25hbWUKCiAgICBkZWYgZHJ5X3J1bihzZWxmLCBtc2cpOgogICAgICAgIGlmIHNlbGYuX2Fy - Z19wYXJzZXIuZHJ5X3J1bjoKICAgICAgICAgICAgcHJpbnQoIkV4ZWN1dGU6ICIgKyAiJyIgKyBt - c2cgKyAiJyIpCgogICAgZGVmIHZhbGlkYXRlX3Jnd19lbmRwb2ludF90bHNfY2VydChzZWxmKToK - ICAgICAgICBpZiBzZWxmLl9hcmdfcGFyc2VyLnJnd190bHNfY2VydF9wYXRoOgogICAgICAgICAg - ICB3aXRoIG9wZW4oc2VsZi5fYXJnX3BhcnNlci5yZ3dfdGxzX2NlcnRfcGF0aCwgZW5jb2Rpbmc9 - InV0ZjgiKSBhcyBmOgogICAgICAgICAgICAgICAgY29udGVudHMgPSBmLnJlYWQoKQogICAgICAg - ICAgICAgICAgcmV0dXJuIGNvbnRlbnRzLnJzdHJpcCgpCgogICAgZGVmIF9jaGVja19jb25mbGlj - dGluZ19vcHRpb25zKHNlbGYpOgogICAgICAgIGlmIG5vdCBzZWxmLl9hcmdfcGFyc2VyLnVwZ3Jh - ZGUgYW5kIG5vdCBzZWxmLl9hcmdfcGFyc2VyLnJiZF9kYXRhX3Bvb2xfbmFtZToKICAgICAgICAg - ICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlvbigKICAgICAgICAgICAgICAgICJFaXRo - ZXIgJy0tdXBncmFkZScgb3IgJy0tcmJkLWRhdGEtcG9vbC1uYW1lIDxwb29sX25hbWU+JyBzaG91 - bGQgYmUgc3BlY2lmaWVkIgogICAgICAgICAgICApCgogICAgZGVmIF9pbnZhbGlkX2VuZHBvaW50 - KHNlbGYsIGVuZHBvaW50X3N0cik6CiAgICAgICAgIyBleHRyYWN0IHRoZSBwb3J0IGJ5IGdldHRp - bmcgdGhlIGxhc3Qgc3BsaXQgb24gYDpgIGRlbGltaXRlcgogICAgICAgIHRyeToKICAgICAgICAg - ICAgZW5kcG9pbnRfc3RyX2lwLCBwb3J0ID0gZW5kcG9pbnRfc3RyLnJzcGxpdCgiOiIsIDEpCiAg - ICAgICAgZXhjZXB0IFZhbHVlRXJyb3I6CiAgICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1 - cmVFeGNlcHRpb24oZiJOb3QgYSBwcm9wZXIgZW5kcG9pbnQ6IHtlbmRwb2ludF9zdHJ9IikKCiAg - ICAgICAgdHJ5OgogICAgICAgICAgICBpZiBlbmRwb2ludF9zdHJfaXBbMF0gPT0gIlsiOgogICAg - ICAgICAgICAgICAgZW5kcG9pbnRfc3RyX2lwID0gZW5kcG9pbnRfc3RyX2lwWzEgOiBsZW4oZW5k - cG9pbnRfc3RyX2lwKSAtIDFdCiAgICAgICAgICAgIGlwX3R5cGUgPSAoCiAgICAgICAgICAgICAg - ICAiSVB2NCIgaWYgdHlwZShpcF9hZGRyZXNzKGVuZHBvaW50X3N0cl9pcCkpIGlzIElQdjRBZGRy - ZXNzIGVsc2UgIklQdjYiCiAgICAgICAgICAgICkKICAgICAgICBleGNlcHQgVmFsdWVFcnJvcjoK - ICAgICAgICAgICAgaXBfdHlwZSA9ICJGUUROIgogICAgICAgIGlmIG5vdCBwb3J0LmlzZGlnaXQo - KToKICAgICAgICAgICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlvbihmIlBvcnQgbm90 - IHZhbGlkOiB7cG9ydH0iKQogICAgICAgIGludFBvcnQgPSBpbnQocG9ydCkKICAgICAgICBpZiBp - bnRQb3J0IDwgMSBvciBpbnRQb3J0ID4gMioqMTYgLSAxOgogICAgICAgICAgICByYWlzZSBFeGVj - dXRpb25GYWlsdXJlRXhjZXB0aW9uKGYiT3V0IG9mIHJhbmdlIHBvcnQgbnVtYmVyOiB7cG9ydH0i - KQoKICAgICAgICByZXR1cm4gaXBfdHlwZQoKICAgIGRlZiBlbmRwb2ludF9kaWFsKHNlbGYsIGVu - ZHBvaW50X3N0ciwgaXBfdHlwZSwgdGltZW91dD0zLCBjZXJ0PU5vbmUpOgogICAgICAgICMgaWYg - dGhlICdjbHVzdGVyJyBpbnN0YW5jZSBpcyBhIGR1bW15IG9uZSwKICAgICAgICAjIGRvbid0IHRy - eSB0byByZWFjaCBvdXQgdG8gdGhlIGVuZHBvaW50CiAgICAgICAgaWYgaXNpbnN0YW5jZShzZWxm - LmNsdXN0ZXIsIER1bW15UmFkb3MpOgogICAgICAgICAgICByZXR1cm4gIiIsICIiLCAiIgogICAg - ICAgIGlmIGlwX3R5cGUgPT0gIklQdjYiOgogICAgICAgICAgICB0cnk6CiAgICAgICAgICAgICAg - ICBlbmRwb2ludF9zdHJfaXAsIGVuZHBvaW50X3N0cl9wb3J0ID0gZW5kcG9pbnRfc3RyLnJzcGxp - dCgiOiIsIDEpCiAgICAgICAgICAgIGV4Y2VwdCBWYWx1ZUVycm9yOgogICAgICAgICAgICAgICAg - cmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlvbigKICAgICAgICAgICAgICAgICAgICBmIk5v - dCBhIHByb3BlciBlbmRwb2ludDoge2VuZHBvaW50X3N0cn0iCiAgICAgICAgICAgICAgICApCiAg - ICAgICAgICAgIGlmIGVuZHBvaW50X3N0cl9pcFswXSAhPSAiWyI6CiAgICAgICAgICAgICAgICBl - bmRwb2ludF9zdHJfaXAgPSAiWyIgKyBlbmRwb2ludF9zdHJfaXAgKyAiXSIKICAgICAgICAgICAg - ZW5kcG9pbnRfc3RyID0gIjoiLmpvaW4oW2VuZHBvaW50X3N0cl9pcCwgZW5kcG9pbnRfc3RyX3Bv - cnRdKQoKICAgICAgICBwcm90b2NvbHMgPSBbImh0dHAiLCAiaHR0cHMiXQogICAgICAgIHJlc3Bv - bnNlX2Vycm9yID0gTm9uZQogICAgICAgIGZvciBwcmVmaXggaW4gcHJvdG9jb2xzOgogICAgICAg - ICAgICB0cnk6CiAgICAgICAgICAgICAgICBlcCA9IGYie3ByZWZpeH06Ly97ZW5kcG9pbnRfc3Ry - fSIKICAgICAgICAgICAgICAgIHZlcmlmeSA9IE5vbmUKICAgICAgICAgICAgICAgICMgSWYgdmVy - aWZ5IGlzIHNldCB0byBhIHBhdGggdG8gYSBkaXJlY3RvcnksCiAgICAgICAgICAgICAgICAjIHRo - ZSBkaXJlY3RvcnkgbXVzdCBoYXZlIGJlZW4gcHJvY2Vzc2VkIHVzaW5nIHRoZSBjX3JlaGFzaCB1 - dGlsaXR5IHN1cHBsaWVkIHdpdGggT3BlblNTTC4KICAgICAgICAgICAgICAgIGlmIHByZWZpeCA9 - PSAiaHR0cHMiIGFuZCBzZWxmLl9hcmdfcGFyc2VyLnJnd19za2lwX3RsczoKICAgICAgICAgICAg - ICAgICAgICB2ZXJpZnkgPSBGYWxzZQogICAgICAgICAgICAgICAgICAgIHIgPSByZXF1ZXN0cy5o - ZWFkKGVwLCB0aW1lb3V0PXRpbWVvdXQsIHZlcmlmeT1GYWxzZSkKICAgICAgICAgICAgICAgIGVs - aWYgcHJlZml4ID09ICJodHRwcyIgYW5kIGNlcnQ6CiAgICAgICAgICAgICAgICAgICAgdmVyaWZ5 - ID0gY2VydAogICAgICAgICAgICAgICAgICAgIHIgPSByZXF1ZXN0cy5oZWFkKGVwLCB0aW1lb3V0 - PXRpbWVvdXQsIHZlcmlmeT1jZXJ0KQogICAgICAgICAgICAgICAgZWxzZToKICAgICAgICAgICAg - ICAgICAgICByID0gcmVxdWVzdHMuaGVhZChlcCwgdGltZW91dD10aW1lb3V0KQogICAgICAgICAg - ICAgICAgaWYgci5zdGF0dXNfY29kZSA9PSAyMDA6CiAgICAgICAgICAgICAgICAgICAgcmV0dXJu - IHByZWZpeCwgdmVyaWZ5LCAiIgogICAgICAgICAgICBleGNlcHQgRXhjZXB0aW9uIGFzIGVycjoK - ICAgICAgICAgICAgICAgIHJlc3BvbnNlX2Vycm9yID0gZXJyCiAgICAgICAgICAgICAgICBjb250 - aW51ZQogICAgICAgIHN5cy5zdGRlcnIud3JpdGUoCiAgICAgICAgICAgIGYidW5hYmxlIHRvIGNv - bm5lY3QgdG8gZW5kcG9pbnQ6IHtlbmRwb2ludF9zdHJ9LCBmYWlsZWQgZXJyb3I6IHtyZXNwb25z - ZV9lcnJvcn0iCiAgICAgICAgKQogICAgICAgIHJldHVybiAoCiAgICAgICAgICAgICIiLAogICAg - ICAgICAgICAiIiwKICAgICAgICAgICAgKCItMSIpLAogICAgICAgICkKCiAgICBkZWYgcGFyc2Vf - Y29uZmlnX2ZpbGUoc2VsZiwgY29uZmlnX2ZpbGUpOgogICAgICAgIGNvbmZpZyA9IGNvbmZpZ3Bh - cnNlci5Db25maWdQYXJzZXIoKQogICAgICAgIGNvbmZpZy5yZWFkKGNvbmZpZ19maWxlKQogICAg - ICAgIGZvciBhcmcgaW4gbGlzdCh2YXJzKHNlbGYuX2FyZ19wYXJzZXIpKToKICAgICAgICAgICAg - IyBweXRob24gdHJlYXRzIGZsYWctbmFtZSBhcyBmbGFnX25hbWUgaW50ZXJuYWxseSwgc28gY29u - dmVydGluZyBiYWNrIHRvIGZsYWctbmFtZSwKICAgICAgICAgICAgIyBzbyB3ZSBjYW4gZ2V0IHRo - b3NlIHZhbHVlcyBmcm9tIGNvbmZpZyBmaWxlCiAgICAgICAgICAgIGFyZ3VtZW50ID0gYXJnLnJl - cGxhY2UoIl8iLCAiLSIpCiAgICAgICAgICAgIGFyZ3VtZW50VmFsdWUgPSBzdHIoZ2V0YXR0cihz - ZWxmLl9hcmdfcGFyc2VyLCBhcmcpKQogICAgICAgICAgICBjb25maWdfdmFsdWUgPSBjb25maWcu - Z2V0KCJDb25maWd1cmF0aW9ucyIsIGFyZ3VtZW50LCBmYWxsYmFjaz1Ob25lKQogICAgICAgICAg - ICAjIGdpdmUgcHJpb3JpdHkgdG8gY29tbWFuZCBsaW5lIGFyZ3VtZW50LCBpZiBjb21tYW5kIGxp - bmUgYXJndW1lbnQgaXMgbm90IHByZXNlbnQgdXNlIGNvbmZpZy5pbmkgdmFsdWUsCiAgICAgICAg - ICAgIGlmIChzdHIoc3lzLmFyZ3YpLmZpbmQoYXJndW1lbnQpID09IC0xKSBhbmQgKAogICAgICAg - ICAgICAgICAgKGNvbmZpZ192YWx1ZSAhPSBOb25lKSBhbmQgKGNvbmZpZ192YWx1ZSAhPSAiIikK - ICAgICAgICAgICAgKToKICAgICAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIuX19zZXRhdHRy - X18oYXJnLCBjb25maWdfdmFsdWUpCgogICAgICAgIHJldHVybiBjb25maWcKCiAgICBkZWYgX19p - bml0X18oc2VsZiwgYXJnX2xpc3Q9Tm9uZSk6CiAgICAgICAgc2VsZi5vdXRfbWFwID0ge30KICAg - ICAgICBzZWxmLl9leGNsdWRlZF9rZXlzID0gc2V0KCkKICAgICAgICBzZWxmLl9hcmdfcGFyc2Vy - ID0gc2VsZi5nZW5fYXJnX3BhcnNlcihhcmdzX3RvX3BhcnNlPWFyZ19saXN0KQogICAgICAgIGlm - IHNlbGYuX2FyZ19wYXJzZXIuY29uZmlnX2ZpbGU6CiAgICAgICAgICAgIHNlbGYuY29uZmlnID0g - c2VsZi5wYXJzZV9jb25maWdfZmlsZShzZWxmLl9hcmdfcGFyc2VyLmNvbmZpZ19maWxlKQogICAg - ICAgIHNlbGYuX2NoZWNrX2NvbmZsaWN0aW5nX29wdGlvbnMoKQogICAgICAgIHNlbGYucnVuX2Fz - X3VzZXIgPSBzZWxmLl9hcmdfcGFyc2VyLnJ1bl9hc191c2VyCiAgICAgICAgc2VsZi5vdXRwdXRf - ZmlsZSA9IHNlbGYuX2FyZ19wYXJzZXIub3V0cHV0CiAgICAgICAgc2VsZi5jZXBoX2NvbmYgPSBz - ZWxmLl9hcmdfcGFyc2VyLmNlcGhfY29uZgogICAgICAgIHNlbGYuY2VwaF9rZXlyaW5nID0gc2Vs - Zi5fYXJnX3BhcnNlci5rZXlyaW5nCiAgICAgICAgIyBpZiB1c2VyIG5vdCBwcm92aWRlZCwgZ2l2 - ZSBhIGRlZmF1bHQgdXNlcgogICAgICAgIGlmIG5vdCBzZWxmLnJ1bl9hc191c2VyIGFuZCBub3Qg - c2VsZi5fYXJnX3BhcnNlci51cGdyYWRlOgogICAgICAgICAgICBzZWxmLnJ1bl9hc191c2VyID0g - c2VsZi5FWFRFUk5BTF9VU0VSX05BTUUKICAgICAgICBpZiBub3Qgc2VsZi5fYXJnX3BhcnNlci5y - Z3dfcG9vbF9wcmVmaXggYW5kIG5vdCBzZWxmLl9hcmdfcGFyc2VyLnVwZ3JhZGU6CiAgICAgICAg - ICAgIHNlbGYuX2FyZ19wYXJzZXIucmd3X3Bvb2xfcHJlZml4ID0gc2VsZi5ERUZBVUxUX1JHV19Q - T09MX1BSRUZJWAogICAgICAgIGlmIHNlbGYuY2VwaF9jb25mOgogICAgICAgICAgICBrd2FyZ3Mg - PSB7fQogICAgICAgICAgICBpZiBzZWxmLmNlcGhfa2V5cmluZzoKICAgICAgICAgICAgICAgIGt3 - YXJnc1siY29uZiJdID0geyJrZXlyaW5nIjogc2VsZi5jZXBoX2tleXJpbmd9CiAgICAgICAgICAg - IHNlbGYuY2x1c3RlciA9IHJhZG9zLlJhZG9zKGNvbmZmaWxlPXNlbGYuY2VwaF9jb25mLCAqKmt3 - YXJncykKICAgICAgICBlbHNlOgogICAgICAgICAgICBzZWxmLmNsdXN0ZXIgPSByYWRvcy5SYWRv - cygpCiAgICAgICAgICAgIHNlbGYuY2x1c3Rlci5jb25mX3JlYWRfZmlsZSgpCiAgICAgICAgc2Vs - Zi5jbHVzdGVyLmNvbm5lY3QoKQoKICAgIGRlZiBzaHV0ZG93bihzZWxmKToKICAgICAgICBpZiBz - ZWxmLmNsdXN0ZXIuc3RhdGUgPT0gImNvbm5lY3RlZCI6CiAgICAgICAgICAgIHNlbGYuY2x1c3Rl - ci5zaHV0ZG93bigpCgogICAgZGVmIGdldF9mc2lkKHNlbGYpOgogICAgICAgIGlmIHNlbGYuX2Fy - Z19wYXJzZXIuZHJ5X3J1bjoKICAgICAgICAgICAgcmV0dXJuIHNlbGYuZHJ5X3J1bigiY2VwaCBm - c2lkIikKICAgICAgICByZXR1cm4gc3RyKHNlbGYuY2x1c3Rlci5nZXRfZnNpZCgpKQoKICAgIGRl - ZiBfY29tbW9uX2NtZF9qc29uX2dlbihzZWxmLCBjbWRfanNvbik6CiAgICAgICAgY21kID0ganNv - bi5kdW1wcyhjbWRfanNvbiwgc29ydF9rZXlzPVRydWUpCiAgICAgICAgcmV0X3ZhbCwgY21kX291 - dCwgZXJyX21zZyA9IHNlbGYuY2x1c3Rlci5tb25fY29tbWFuZChjbWQsIGIiIikKICAgICAgICBp - ZiBzZWxmLl9hcmdfcGFyc2VyLnZlcmJvc2U6CiAgICAgICAgICAgIHByaW50KGYiQ29tbWFuZCBJ - bnB1dDoge2NtZH0iKQogICAgICAgICAgICBwcmludCgKICAgICAgICAgICAgICAgIGYiUmV0dXJu - IFZhbDoge3JldF92YWx9XG5Db21tYW5kIE91dHB1dDoge2NtZF9vdXR9XG4iCiAgICAgICAgICAg - ICAgICBmIkVycm9yIE1lc3NhZ2U6IHtlcnJfbXNnfVxuLS0tLS0tLS0tLVxuIgogICAgICAgICAg - ICApCiAgICAgICAganNvbl9vdXQgPSB7fQogICAgICAgICMgaWYgdGhlcmUgaXMgbm8gZXJyb3Ig - KGkuZTsgcmV0X3ZhbCBpcyBaRVJPKSBhbmQgJ2NtZF9vdXQnIGlzIG5vdCBlbXB0eQogICAgICAg - ICMgdGhlbiBjb252ZXJ0ICdjbWRfb3V0JyB0byBhIGpzb24gb3V0cHV0CiAgICAgICAgaWYgcmV0 - X3ZhbCA9PSAwIGFuZCBjbWRfb3V0OgogICAgICAgICAgICBqc29uX291dCA9IGpzb24ubG9hZHMo - Y21kX291dCkKICAgICAgICByZXR1cm4gcmV0X3ZhbCwganNvbl9vdXQsIGVycl9tc2cKCiAgICBk - ZWYgZ2V0X2NlcGhfZXh0ZXJuYWxfbW9uX2RhdGEoc2VsZik6CiAgICAgICAgY21kX2pzb24gPSB7 - InByZWZpeCI6ICJxdW9ydW1fc3RhdHVzIiwgImZvcm1hdCI6ICJqc29uIn0KICAgICAgICBpZiBz - ZWxmLl9hcmdfcGFyc2VyLmRyeV9ydW46CiAgICAgICAgICAgIHJldHVybiBzZWxmLmRyeV9ydW4o - ImNlcGggIiArIGNtZF9qc29uWyJwcmVmaXgiXSkKICAgICAgICByZXRfdmFsLCBqc29uX291dCwg - ZXJyX21zZyA9IHNlbGYuX2NvbW1vbl9jbWRfanNvbl9nZW4oY21kX2pzb24pCiAgICAgICAgIyBp - ZiB0aGVyZSBpcyBhbiB1bnN1Y2Nlc3NmdWwgYXR0ZW1wdCwKICAgICAgICBpZiByZXRfdmFsICE9 - IDAgb3IgbGVuKGpzb25fb3V0KSA9PSAwOgogICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWls - dXJlRXhjZXB0aW9uKAogICAgICAgICAgICAgICAgIidxdW9ydW1fc3RhdHVzJyBjb21tYW5kIGZh - aWxlZC5cbiIKICAgICAgICAgICAgICAgIGYiRXJyb3I6IHtlcnJfbXNnIGlmIHJldF92YWwgIT0g - MCBlbHNlIHNlbGYuRU1QVFlfT1VUUFVUX0xJU1R9IgogICAgICAgICAgICApCiAgICAgICAgcV9s - ZWFkZXJfbmFtZSA9IGpzb25fb3V0WyJxdW9ydW1fbGVhZGVyX25hbWUiXQogICAgICAgIHFfbGVh - ZGVyX2RldGFpbHMgPSB7fQogICAgICAgIHFfbGVhZGVyX21hdGNoaW5nX2xpc3QgPSBbCiAgICAg - ICAgICAgIGwgZm9yIGwgaW4ganNvbl9vdXRbIm1vbm1hcCJdWyJtb25zIl0gaWYgbFsibmFtZSJd - ID09IHFfbGVhZGVyX25hbWUKICAgICAgICBdCiAgICAgICAgaWYgbGVuKHFfbGVhZGVyX21hdGNo - aW5nX2xpc3QpID09IDA6CiAgICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1cmVFeGNlcHRp - b24oIk5vIG1hdGNoaW5nICdtb24nIGRldGFpbHMgZm91bmQiKQogICAgICAgIHFfbGVhZGVyX2Rl - dGFpbHMgPSBxX2xlYWRlcl9tYXRjaGluZ19saXN0WzBdCiAgICAgICAgIyBnZXQgdGhlIGFkZHJl - c3MgdmVjdG9yIG9mIHRoZSBxdW9ydW0tbGVhZGVyCiAgICAgICAgcV9sZWFkZXJfYWRkcnZlYyA9 - IHFfbGVhZGVyX2RldGFpbHMuZ2V0KCJwdWJsaWNfYWRkcnMiLCB7fSkuZ2V0KCJhZGRydmVjIiwg - W10pCiAgICAgICAgaXBfYWRkciA9IHN0cihxX2xlYWRlcl9kZXRhaWxzWyJwdWJsaWNfYWRkciJd - LnNwbGl0KCIvIilbMF0pCgogICAgICAgIGlmIHNlbGYuX2FyZ19wYXJzZXIudjJfcG9ydF9lbmFi - bGU6CiAgICAgICAgICAgIGlmIHFfbGVhZGVyX2FkZHJ2ZWNbMF1bInR5cGUiXSA9PSAidjIiOgog - ICAgICAgICAgICAgICAgaXBfYWRkciA9IHFfbGVhZGVyX2FkZHJ2ZWNbMF1bImFkZHIiXQogICAg - ICAgICAgICBlbGlmIGxlbihxX2xlYWRlcl9hZGRydmVjKSA+IDEgYW5kIHFfbGVhZGVyX2FkZHJ2 - ZWNbMV1bInR5cGUiXSA9PSAidjIiOgogICAgICAgICAgICAgICAgaXBfYWRkciA9IHFfbGVhZGVy - X2FkZHJ2ZWNbMV1bImFkZHIiXQogICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgc3lz - LnN0ZGVyci53cml0ZSgKICAgICAgICAgICAgICAgICAgICAiJ3YyJyBhZGRyZXNzIHR5cGUgbm90 - IHByZXNlbnQsIGFuZCAndjItcG9ydC1lbmFibGUnIGZsYWcgaXMgcHJvdmlkZWQiCiAgICAgICAg - ICAgICAgICApCgogICAgICAgIHJldHVybiBmIntzdHIocV9sZWFkZXJfbmFtZSl9PXtpcF9hZGRy - fSIKCiAgICBkZWYgX2NvbnZlcnRfaG9zdG5hbWVfdG9faXAoc2VsZiwgaG9zdF9uYW1lLCBwb3J0 - LCBpcF90eXBlKToKICAgICAgICAjIGlmICdjbHVzdGVyJyBpbnN0YW5jZSBpcyBhIGR1bW15IHR5 - cGUsCiAgICAgICAgIyBjYWxsIHRoZSBkdW1teSBpbnN0YW5jZSdzICJjb252ZXJ0IiBtZXRob2QK - ICAgICAgICBpZiBub3QgaG9zdF9uYW1lOgogICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWls - dXJlRXhjZXB0aW9uKCJFbXB0eSBob3N0bmFtZSBwcm92aWRlZCIpCiAgICAgICAgaWYgaXNpbnN0 - YW5jZShzZWxmLmNsdXN0ZXIsIER1bW15UmFkb3MpOgogICAgICAgICAgICByZXR1cm4gc2VsZi5j - bHVzdGVyLl9jb252ZXJ0X2hvc3RuYW1lX3RvX2lwKGhvc3RfbmFtZSkKCiAgICAgICAgaWYgaXBf - dHlwZSA9PSAiRlFETiI6CiAgICAgICAgICAgICMgY2hlY2sgd2hpY2ggaXAgRlFETiBzaG91bGQg - YmUgY29udmVydGVkIHRvLCBJUHY0IG9yIElQdjYKICAgICAgICAgICAgIyBjaGVjayB0aGUgaG9z - dCBpcCwgdGhlIGVuZHBvaW50IGlwIHR5cGUgd291bGQgYmUgc2ltaWxhciB0byBob3N0IGlwCiAg - ICAgICAgICAgIGNtZF9qc29uID0geyJwcmVmaXgiOiAib3JjaCBob3N0IGxzIiwgImZvcm1hdCI6 - ICJqc29uIn0KICAgICAgICAgICAgcmV0X3ZhbCwganNvbl9vdXQsIGVycl9tc2cgPSBzZWxmLl9j - b21tb25fY21kX2pzb25fZ2VuKGNtZF9qc29uKQogICAgICAgICAgICAjIGlmIHRoZXJlIGlzIGFu - IHVuc3VjY2Vzc2Z1bCBhdHRlbXB0LAogICAgICAgICAgICBpZiByZXRfdmFsICE9IDAgb3IgbGVu - KGpzb25fb3V0KSA9PSAwOgogICAgICAgICAgICAgICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4 - Y2VwdGlvbigKICAgICAgICAgICAgICAgICAgICAiJ29yY2ggaG9zdCBscycgY29tbWFuZCBmYWls - ZWQuXG4iCiAgICAgICAgICAgICAgICAgICAgZiJFcnJvcjoge2Vycl9tc2cgaWYgcmV0X3ZhbCAh - PSAwIGVsc2Ugc2VsZi5FTVBUWV9PVVRQVVRfTElTVH0iCiAgICAgICAgICAgICAgICApCiAgICAg - ICAgICAgIGhvc3RfYWRkciA9IGpzb25fb3V0WzBdWyJhZGRyIl0KICAgICAgICAgICAgIyBhZGQg - OjgwIHNhbXBsZSBwb3J0IGluIGlwX3R5cGUsIGFzIF9pbnZhbGlkX2VuZHBvaW50IGFsc28gdmVy - aWZ5IHBvcnQKICAgICAgICAgICAgaG9zdF9pcF90eXBlID0gc2VsZi5faW52YWxpZF9lbmRwb2lu - dChob3N0X2FkZHIgKyAiOjgwIikKICAgICAgICAgICAgaW1wb3J0IHNvY2tldAoKICAgICAgICAg - ICAgaXAgPSBbXQogICAgICAgICAgICAjIGV4YW1wbGUgb3V0cHV0IFsoPEFkZHJlc3NGYW1pbHku - QUZfSU5FVDogMj4sIDxTb2NrZXRLaW5kLlNPQ0tfU1RSRUFNOiAxPiwgNiwgJycsICgnOTMuMTg0 - LjIxNi4zNCcsIDgwKSksIC4uLl0KICAgICAgICAgICAgIyB3ZSBuZWVkIHRvIGdldCA5My4xODQu - MjE2LjM0IHNvIGl0IHdvdWxkIGJlIGlwWzBdWzRdWzBdCiAgICAgICAgICAgIGlmIGhvc3RfaXBf - dHlwZSA9PSAiSVB2NiI6CiAgICAgICAgICAgICAgICBpcCA9IHNvY2tldC5nZXRhZGRyaW5mbygK - ICAgICAgICAgICAgICAgICAgICBob3N0X25hbWUsIHBvcnQsIGZhbWlseT1zb2NrZXQuQUZfSU5F - VDYsIHByb3RvPXNvY2tldC5JUFBST1RPX1RDUAogICAgICAgICAgICAgICAgKQogICAgICAgICAg - ICBlbGlmIGhvc3RfaXBfdHlwZSA9PSAiSVB2NCI6CiAgICAgICAgICAgICAgICBpcCA9IHNvY2tl - dC5nZXRhZGRyaW5mbygKICAgICAgICAgICAgICAgICAgICBob3N0X25hbWUsIHBvcnQsIGZhbWls - eT1zb2NrZXQuQUZfSU5FVCwgcHJvdG89c29ja2V0LklQUFJPVE9fVENQCiAgICAgICAgICAgICAg - ICApCiAgICAgICAgICAgIGRlbCBzb2NrZXQKICAgICAgICAgICAgcmV0dXJuIGlwWzBdWzRdWzBd - CiAgICAgICAgcmV0dXJuIGhvc3RfbmFtZQoKICAgIGRlZiBnZXRfYWN0aXZlX2FuZF9zdGFuZGJ5 - X21ncnMoc2VsZik6CiAgICAgICAgaWYgc2VsZi5fYXJnX3BhcnNlci5kcnlfcnVuOgogICAgICAg - ICAgICByZXR1cm4gIiIsIHNlbGYuZHJ5X3J1bigiY2VwaCBzdGF0dXMiKQogICAgICAgIG1vbml0 - b3JpbmdfZW5kcG9pbnRfcG9ydCA9IHNlbGYuX2FyZ19wYXJzZXIubW9uaXRvcmluZ19lbmRwb2lu - dF9wb3J0CiAgICAgICAgbW9uaXRvcmluZ19lbmRwb2ludF9pcF9saXN0ID0gc2VsZi5fYXJnX3Bh - cnNlci5tb25pdG9yaW5nX2VuZHBvaW50CiAgICAgICAgc3RhbmRieV9tZ3JzID0gW10KICAgICAg - ICBpZiBub3QgbW9uaXRvcmluZ19lbmRwb2ludF9pcF9saXN0OgogICAgICAgICAgICBjbWRfanNv - biA9IHsicHJlZml4IjogInN0YXR1cyIsICJmb3JtYXQiOiAianNvbiJ9CiAgICAgICAgICAgIHJl - dF92YWwsIGpzb25fb3V0LCBlcnJfbXNnID0gc2VsZi5fY29tbW9uX2NtZF9qc29uX2dlbihjbWRf - anNvbikKICAgICAgICAgICAgIyBpZiB0aGVyZSBpcyBhbiB1bnN1Y2Nlc3NmdWwgYXR0ZW1wdCwK - ICAgICAgICAgICAgaWYgcmV0X3ZhbCAhPSAwIG9yIGxlbihqc29uX291dCkgPT0gMDoKICAgICAg - ICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1cmVFeGNlcHRpb24oCiAgICAgICAgICAgICAg - ICAgICAgIidtZ3Igc2VydmljZXMnIGNvbW1hbmQgZmFpbGVkLlxuIgogICAgICAgICAgICAgICAg - ICAgIGYiRXJyb3I6IHtlcnJfbXNnIGlmIHJldF92YWwgIT0gMCBlbHNlIHNlbGYuRU1QVFlfT1VU - UFVUX0xJU1R9IgogICAgICAgICAgICAgICAgKQogICAgICAgICAgICBtb25pdG9yaW5nX2VuZHBv - aW50ID0gKAogICAgICAgICAgICAgICAganNvbl9vdXQuZ2V0KCJtZ3JtYXAiLCB7fSkuZ2V0KCJz - ZXJ2aWNlcyIsIHt9KS5nZXQoInByb21ldGhldXMiLCAiIikKICAgICAgICAgICAgKQogICAgICAg - ICAgICBpZiBub3QgbW9uaXRvcmluZ19lbmRwb2ludDoKICAgICAgICAgICAgICAgIHJhaXNlIEV4 - ZWN1dGlvbkZhaWx1cmVFeGNlcHRpb24oCiAgICAgICAgICAgICAgICAgICAgImNhbid0IGZpbmQg - bW9uaXRvcmluZ19lbmRwb2ludCwgcHJvbWV0aGV1cyBtb2R1bGUgbWlnaHQgbm90IGJlIGVuYWJs - ZWQsICIKICAgICAgICAgICAgICAgICAgICAiZW5hYmxlIHRoZSBtb2R1bGUgYnkgcnVubmluZyAn - Y2VwaCBtZ3IgbW9kdWxlIGVuYWJsZSBwcm9tZXRoZXVzJyIKICAgICAgICAgICAgICAgICkKICAg - ICAgICAgICAgIyBub3cgY2hlY2sgdGhlIHN0YW5kLWJ5IG1nci1zCiAgICAgICAgICAgIHN0YW5k - YnlfYXJyID0ganNvbl9vdXQuZ2V0KCJtZ3JtYXAiLCB7fSkuZ2V0KCJzdGFuZGJ5cyIsIFtdKQog - ICAgICAgICAgICBmb3IgZWFjaF9zdGFuZGJ5IGluIHN0YW5kYnlfYXJyOgogICAgICAgICAgICAg - ICAgaWYgIm5hbWUiIGluIGVhY2hfc3RhbmRieS5rZXlzKCk6CiAgICAgICAgICAgICAgICAgICAg - c3RhbmRieV9tZ3JzLmFwcGVuZChlYWNoX3N0YW5kYnlbIm5hbWUiXSkKICAgICAgICAgICAgdHJ5 - OgogICAgICAgICAgICAgICAgcGFyc2VkX2VuZHBvaW50ID0gdXJscGFyc2UobW9uaXRvcmluZ19l - bmRwb2ludCkKICAgICAgICAgICAgZXhjZXB0IFZhbHVlRXJyb3I6CiAgICAgICAgICAgICAgICBy - YWlzZSBFeGVjdXRpb25GYWlsdXJlRXhjZXB0aW9uKAogICAgICAgICAgICAgICAgICAgIGYiaW52 - YWxpZCBlbmRwb2ludDoge21vbml0b3JpbmdfZW5kcG9pbnR9IgogICAgICAgICAgICAgICAgKQog - ICAgICAgICAgICBtb25pdG9yaW5nX2VuZHBvaW50X2lwX2xpc3QgPSBwYXJzZWRfZW5kcG9pbnQu - aG9zdG5hbWUKICAgICAgICAgICAgaWYgbm90IG1vbml0b3JpbmdfZW5kcG9pbnRfcG9ydDoKICAg - ICAgICAgICAgICAgIG1vbml0b3JpbmdfZW5kcG9pbnRfcG9ydCA9IHN0cihwYXJzZWRfZW5kcG9p - bnQucG9ydCkKCiAgICAgICAgIyBpZiBtb25pdG9yaW5nIGVuZHBvaW50IHBvcnQgaXMgbm90IHNl - dCwgcHV0IGEgZGVmYXVsdCBtb24gcG9ydAogICAgICAgIGlmIG5vdCBtb25pdG9yaW5nX2VuZHBv - aW50X3BvcnQ6CiAgICAgICAgICAgIG1vbml0b3JpbmdfZW5kcG9pbnRfcG9ydCA9IHNlbGYuREVG - QVVMVF9NT05JVE9SSU5HX0VORFBPSU5UX1BPUlQKCiAgICAgICAgIyB1c2VyIGNvdWxkIGdpdmUg - Y29tbWEgYW5kIHNwYWNlIHNlcGFyYXRlZCBpbnB1dHMgKGxpa2UgLS1tb25pdG9yaW5nLWVuZHBv - aW50PSI8aXAxPiwgPGlwMj4iKQogICAgICAgIG1vbml0b3JpbmdfZW5kcG9pbnRfaXBfbGlzdCA9 - IG1vbml0b3JpbmdfZW5kcG9pbnRfaXBfbGlzdC5yZXBsYWNlKCIsIiwgIiAiKQogICAgICAgIG1v - bml0b3JpbmdfZW5kcG9pbnRfaXBfbGlzdF9zcGxpdCA9IG1vbml0b3JpbmdfZW5kcG9pbnRfaXBf - bGlzdC5zcGxpdCgpCiAgICAgICAgIyBpZiBtb25pdG9yaW5nLWVuZHBvaW50IGNvdWxkIG5vdCBi - ZSBmb3VuZCwgcmFpc2UgYW4gZXJyb3IKICAgICAgICBpZiBsZW4obW9uaXRvcmluZ19lbmRwb2lu - dF9pcF9saXN0X3NwbGl0KSA9PSAwOgogICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWlsdXJl - RXhjZXB0aW9uKCJObyAnbW9uaXRvcmluZy1lbmRwb2ludCcgZm91bmQiKQogICAgICAgICMgZmly - c3QgaXAgaXMgdHJlYXRlZCBhcyB0aGUgbWFpbiBtb25pdG9yaW5nLWVuZHBvaW50CiAgICAgICAg - bW9uaXRvcmluZ19lbmRwb2ludF9pcCA9IG1vbml0b3JpbmdfZW5kcG9pbnRfaXBfbGlzdF9zcGxp - dFswXQogICAgICAgICMgcmVzdCBvZiB0aGUgaXAtcyBhcmUgYWRkZWQgdG8gdGhlICdzdGFuZGJ5 - X21ncnMnIGxpc3QKICAgICAgICBzdGFuZGJ5X21ncnMuZXh0ZW5kKG1vbml0b3JpbmdfZW5kcG9p - bnRfaXBfbGlzdF9zcGxpdFsxOl0pCiAgICAgICAgZmFpbGVkX2lwID0gbW9uaXRvcmluZ19lbmRw - b2ludF9pcAoKICAgICAgICBtb25pdG9yaW5nX2VuZHBvaW50ID0gIjoiLmpvaW4oCiAgICAgICAg - ICAgIFttb25pdG9yaW5nX2VuZHBvaW50X2lwLCBtb25pdG9yaW5nX2VuZHBvaW50X3BvcnRdCiAg - ICAgICAgKQogICAgICAgIGlwX3R5cGUgPSBzZWxmLl9pbnZhbGlkX2VuZHBvaW50KG1vbml0b3Jp - bmdfZW5kcG9pbnQpCiAgICAgICAgdHJ5OgogICAgICAgICAgICBtb25pdG9yaW5nX2VuZHBvaW50 - X2lwID0gc2VsZi5fY29udmVydF9ob3N0bmFtZV90b19pcCgKICAgICAgICAgICAgICAgIG1vbml0 - b3JpbmdfZW5kcG9pbnRfaXAsIG1vbml0b3JpbmdfZW5kcG9pbnRfcG9ydCwgaXBfdHlwZQogICAg - ICAgICAgICApCiAgICAgICAgICAgICMgY29sbGVjdCBhbGwgdGhlICdzdGFuZC1ieScgbWdyIGlw - cwogICAgICAgICAgICBtZ3JfaXBzID0gW10KICAgICAgICAgICAgZm9yIGVhY2hfc3RhbmRieV9t - Z3IgaW4gc3RhbmRieV9tZ3JzOgogICAgICAgICAgICAgICAgZmFpbGVkX2lwID0gZWFjaF9zdGFu - ZGJ5X21ncgogICAgICAgICAgICAgICAgbWdyX2lwcy5hcHBlbmQoCiAgICAgICAgICAgICAgICAg - ICAgc2VsZi5fY29udmVydF9ob3N0bmFtZV90b19pcCgKICAgICAgICAgICAgICAgICAgICAgICAg - ZWFjaF9zdGFuZGJ5X21nciwgbW9uaXRvcmluZ19lbmRwb2ludF9wb3J0LCBpcF90eXBlCiAgICAg - ICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgKQogICAgICAgIGV4Y2VwdDoKICAgICAg - ICAgICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlvbigKICAgICAgICAgICAgICAgIGYi - Q29udmVyc2lvbiBvZiBob3N0OiB7ZmFpbGVkX2lwfSB0byBJUCBmYWlsZWQuICIKICAgICAgICAg - ICAgICAgICJQbGVhc2UgZW50ZXIgdGhlIElQIGFkZHJlc3NlcyBvZiBhbGwgdGhlIGNlcGgtbWdy - cyB3aXRoIHRoZSAnLS1tb25pdG9yaW5nLWVuZHBvaW50JyBmbGFnIgogICAgICAgICAgICApCgog - ICAgICAgIF8sIF8sIGVyciA9IHNlbGYuZW5kcG9pbnRfZGlhbChtb25pdG9yaW5nX2VuZHBvaW50 - LCBpcF90eXBlKQogICAgICAgIGlmIGVyciA9PSAiLTEiOgogICAgICAgICAgICByYWlzZSBFeGVj - dXRpb25GYWlsdXJlRXhjZXB0aW9uKGVycikKICAgICAgICAjIGFkZCB0aGUgdmFsaWRhdGVkIGFj - dGl2ZSBtZ3IgSVAgaW50byB0aGUgZmlyc3QgaW5kZXgKICAgICAgICBtZ3JfaXBzLmluc2VydCgw - LCBtb25pdG9yaW5nX2VuZHBvaW50X2lwKQogICAgICAgIGFsbF9tZ3JfaXBzX3N0ciA9ICIsIi5q - b2luKG1ncl9pcHMpCiAgICAgICAgcmV0dXJuIGFsbF9tZ3JfaXBzX3N0ciwgbW9uaXRvcmluZ19l - bmRwb2ludF9wb3J0CgogICAgZGVmIGNoZWNrX3VzZXJfZXhpc3Qoc2VsZiwgdXNlcik6CiAgICAg - ICAgY21kX2pzb24gPSB7InByZWZpeCI6ICJhdXRoIGdldCIsICJlbnRpdHkiOiBmInt1c2VyfSIs - ICJmb3JtYXQiOiAianNvbiJ9CiAgICAgICAgcmV0X3ZhbCwganNvbl9vdXQsIF8gPSBzZWxmLl9j - b21tb25fY21kX2pzb25fZ2VuKGNtZF9qc29uKQogICAgICAgIGlmIHJldF92YWwgIT0gMCBvciBs - ZW4oanNvbl9vdXQpID09IDA6CiAgICAgICAgICAgIHJldHVybiAiIgogICAgICAgIHJldHVybiBz - dHIoanNvbl9vdXRbMF1bImtleSJdKQoKICAgIGRlZiBnZXRfY2VwaGZzX3Byb3Zpc2lvbmVyX2Nh - cHNfYW5kX2VudGl0eShzZWxmKToKICAgICAgICBlbnRpdHkgPSAiY2xpZW50LmNzaS1jZXBoZnMt - cHJvdmlzaW9uZXIiCiAgICAgICAgY2FwcyA9IHsKICAgICAgICAgICAgIm1vbiI6ICJhbGxvdyBy - LCBhbGxvdyBjb21tYW5kICdvc2QgYmxvY2tsaXN0JyIsCiAgICAgICAgICAgICJtZ3IiOiAiYWxs - b3cgcnciLAogICAgICAgICAgICAib3NkIjogImFsbG93IHJ3IHRhZyBjZXBoZnMgbWV0YWRhdGE9 - KiIsCiAgICAgICAgICAgICJtZHMiOiAiYWxsb3cgKiIsCiAgICAgICAgfQogICAgICAgIGlmIHNl - bGYuX2FyZ19wYXJzZXIucmVzdHJpY3RlZF9hdXRoX3Blcm1pc3Npb246CiAgICAgICAgICAgIGs4 - c19jbHVzdGVyX25hbWUgPSBzZWxmLl9hcmdfcGFyc2VyLms4c19jbHVzdGVyX25hbWUKICAgICAg - ICAgICAgaWYgazhzX2NsdXN0ZXJfbmFtZSA9PSAiIjoKICAgICAgICAgICAgICAgIHJhaXNlIEV4 - ZWN1dGlvbkZhaWx1cmVFeGNlcHRpb24oCiAgICAgICAgICAgICAgICAgICAgIms4c19jbHVzdGVy - X25hbWUgbm90IGZvdW5kLCBwbGVhc2Ugc2V0IHRoZSAnLS1rOHMtY2x1c3Rlci1uYW1lJyBmbGFn - IgogICAgICAgICAgICAgICAgKQogICAgICAgICAgICBjZXBoZnNfZmlsZXN5c3RlbSA9IHNlbGYu - X2FyZ19wYXJzZXIuY2VwaGZzX2ZpbGVzeXN0ZW1fbmFtZQogICAgICAgICAgICBpZiBjZXBoZnNf - ZmlsZXN5c3RlbSA9PSAiIjoKICAgICAgICAgICAgICAgIGVudGl0eSA9IGYie2VudGl0eX0te2s4 - c19jbHVzdGVyX25hbWV9IgogICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgZW50aXR5 - ID0gZiJ7ZW50aXR5fS17azhzX2NsdXN0ZXJfbmFtZX0te2NlcGhmc19maWxlc3lzdGVtfSIKICAg - ICAgICAgICAgICAgIGNhcHNbIm9zZCJdID0gZiJhbGxvdyBydyB0YWcgY2VwaGZzIG1ldGFkYXRh - PXtjZXBoZnNfZmlsZXN5c3RlbX0iCgogICAgICAgIHJldHVybiBjYXBzLCBlbnRpdHkKCiAgICBk - ZWYgZ2V0X2NlcGhmc19ub2RlX2NhcHNfYW5kX2VudGl0eShzZWxmKToKICAgICAgICBlbnRpdHkg - PSAiY2xpZW50LmNzaS1jZXBoZnMtbm9kZSIKICAgICAgICBjYXBzID0gewogICAgICAgICAgICAi - bW9uIjogImFsbG93IHIsIGFsbG93IGNvbW1hbmQgJ29zZCBibG9ja2xpc3QnIiwKICAgICAgICAg - ICAgIm1nciI6ICJhbGxvdyBydyIsCiAgICAgICAgICAgICJvc2QiOiAiYWxsb3cgcncgdGFnIGNl - cGhmcyAqPSoiLAogICAgICAgICAgICAibWRzIjogImFsbG93IHJ3IiwKICAgICAgICB9CiAgICAg - ICAgaWYgc2VsZi5fYXJnX3BhcnNlci5yZXN0cmljdGVkX2F1dGhfcGVybWlzc2lvbjoKICAgICAg - ICAgICAgazhzX2NsdXN0ZXJfbmFtZSA9IHNlbGYuX2FyZ19wYXJzZXIuazhzX2NsdXN0ZXJfbmFt - ZQogICAgICAgICAgICBpZiBrOHNfY2x1c3Rlcl9uYW1lID09ICIiOgogICAgICAgICAgICAgICAg - cmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlvbigKICAgICAgICAgICAgICAgICAgICAiazhz - X2NsdXN0ZXJfbmFtZSBub3QgZm91bmQsIHBsZWFzZSBzZXQgdGhlICctLWs4cy1jbHVzdGVyLW5h - bWUnIGZsYWciCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgIGNlcGhmc19maWxlc3lzdGVt - ID0gc2VsZi5fYXJnX3BhcnNlci5jZXBoZnNfZmlsZXN5c3RlbV9uYW1lCiAgICAgICAgICAgIGlm - IGNlcGhmc19maWxlc3lzdGVtID09ICIiOgogICAgICAgICAgICAgICAgZW50aXR5ID0gZiJ7ZW50 - aXR5fS17azhzX2NsdXN0ZXJfbmFtZX0iCiAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAg - ICBlbnRpdHkgPSBmIntlbnRpdHl9LXtrOHNfY2x1c3Rlcl9uYW1lfS17Y2VwaGZzX2ZpbGVzeXN0 - ZW19IgogICAgICAgICAgICAgICAgY2Fwc1sib3NkIl0gPSBmImFsbG93IHJ3IHRhZyBjZXBoZnMg - Kj17Y2VwaGZzX2ZpbGVzeXN0ZW19IgoKICAgICAgICByZXR1cm4gY2FwcywgZW50aXR5CgogICAg - ZGVmIGdldF9lbnRpdHkoCiAgICAgICAgc2VsZiwKICAgICAgICBlbnRpdHksCiAgICAgICAgcmJk - X3Bvb2xfbmFtZSwKICAgICAgICBhbGlhc19yYmRfcG9vbF9uYW1lLAogICAgICAgIGs4c19jbHVz - dGVyX25hbWUsCiAgICAgICAgcmFkb3NfbmFtZXNwYWNlLAogICAgKToKICAgICAgICBpZiAoCiAg - ICAgICAgICAgIHJiZF9wb29sX25hbWUuY291bnQoIi4iKSAhPSAwCiAgICAgICAgICAgIG9yIHJi - ZF9wb29sX25hbWUuY291bnQoIl8iKSAhPSAwCiAgICAgICAgICAgIG9yIGFsaWFzX3JiZF9wb29s - X25hbWUgIT0gIiIKICAgICAgICAgICAgIyBjaGVja2luZyBhbGlhc19yYmRfcG9vbF9uYW1lIGlz - IG5vdCBlbXB0eSBhcyB0aGVyZSBtYXliZSBhIHNwZWNpYWwgY2hhcmFjdGVyIHVzZWQgb3RoZXIg - dGhhbiAuIG9yIF8KICAgICAgICApOgogICAgICAgICAgICBpZiBhbGlhc19yYmRfcG9vbF9uYW1l - ID09ICIiOgogICAgICAgICAgICAgICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlvbigK - ICAgICAgICAgICAgICAgICAgICAicGxlYXNlIHNldCB0aGUgJy0tYWxpYXMtcmJkLWRhdGEtcG9v - bC1uYW1lJyBmbGFnIGFzIHRoZSByYmQgZGF0YSBwb29sIG5hbWUgY29udGFpbnMgJy4nIG9yICdf - JyIKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgaWYgKAogICAgICAgICAgICAgICAgYWxp - YXNfcmJkX3Bvb2xfbmFtZS5jb3VudCgiLiIpICE9IDAKICAgICAgICAgICAgICAgIG9yIGFsaWFz - X3JiZF9wb29sX25hbWUuY291bnQoIl8iKSAhPSAwCiAgICAgICAgICAgICk6CiAgICAgICAgICAg - ICAgICByYWlzZSBFeGVjdXRpb25GYWlsdXJlRXhjZXB0aW9uKAogICAgICAgICAgICAgICAgICAg - ICInLS1hbGlhcy1yYmQtZGF0YS1wb29sLW5hbWUnIGZsYWcgdmFsdWUgc2hvdWxkIG5vdCBjb250 - YWluICcuJyBvciAnXyciCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgIGVudGl0eSA9IGYi - e2VudGl0eX0te2s4c19jbHVzdGVyX25hbWV9LXthbGlhc19yYmRfcG9vbF9uYW1lfSIKICAgICAg - ICBlbHNlOgogICAgICAgICAgICBlbnRpdHkgPSBmIntlbnRpdHl9LXtrOHNfY2x1c3Rlcl9uYW1l - fS17cmJkX3Bvb2xfbmFtZX0iCgogICAgICAgIGlmIHJhZG9zX25hbWVzcGFjZToKICAgICAgICAg - ICAgZW50aXR5ID0gZiJ7ZW50aXR5fS17cmFkb3NfbmFtZXNwYWNlfSIKICAgICAgICByZXR1cm4g - ZW50aXR5CgogICAgZGVmIGdldF9yYmRfcHJvdmlzaW9uZXJfY2Fwc19hbmRfZW50aXR5KHNlbGYp - OgogICAgICAgIGVudGl0eSA9ICJjbGllbnQuY3NpLXJiZC1wcm92aXNpb25lciIKICAgICAgICBj - YXBzID0gewogICAgICAgICAgICAibW9uIjogInByb2ZpbGUgcmJkLCBhbGxvdyBjb21tYW5kICdv - c2QgYmxvY2tsaXN0JyIsCiAgICAgICAgICAgICJtZ3IiOiAiYWxsb3cgcnciLAogICAgICAgICAg - ICAib3NkIjogInByb2ZpbGUgcmJkIiwKICAgICAgICB9CiAgICAgICAgaWYgc2VsZi5fYXJnX3Bh - cnNlci5yZXN0cmljdGVkX2F1dGhfcGVybWlzc2lvbjoKICAgICAgICAgICAgcmJkX3Bvb2xfbmFt - ZSA9IHNlbGYuX2FyZ19wYXJzZXIucmJkX2RhdGFfcG9vbF9uYW1lCiAgICAgICAgICAgIGFsaWFz - X3JiZF9wb29sX25hbWUgPSBzZWxmLl9hcmdfcGFyc2VyLmFsaWFzX3JiZF9kYXRhX3Bvb2xfbmFt - ZQogICAgICAgICAgICBrOHNfY2x1c3Rlcl9uYW1lID0gc2VsZi5fYXJnX3BhcnNlci5rOHNfY2x1 - c3Rlcl9uYW1lCiAgICAgICAgICAgIHJhZG9zX25hbWVzcGFjZSA9IHNlbGYuX2FyZ19wYXJzZXIu - cmFkb3NfbmFtZXNwYWNlCiAgICAgICAgICAgIGlmIHJiZF9wb29sX25hbWUgPT0gIiI6CiAgICAg - ICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWlsdXJlRXhjZXB0aW9uKAogICAgICAgICAgICAg - ICAgICAgICJtYW5kYXRvcnkgZmxhZyBub3QgZm91bmQsIHBsZWFzZSBzZXQgdGhlICctLXJiZC1k - YXRhLXBvb2wtbmFtZScgZmxhZyIKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgaWYgazhz - X2NsdXN0ZXJfbmFtZSA9PSAiIjoKICAgICAgICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1 - cmVFeGNlcHRpb24oCiAgICAgICAgICAgICAgICAgICAgIm1hbmRhdG9yeSBmbGFnIG5vdCBmb3Vu - ZCwgcGxlYXNlIHNldCB0aGUgJy0tazhzLWNsdXN0ZXItbmFtZScgZmxhZyIKICAgICAgICAgICAg - ICAgICkKICAgICAgICAgICAgZW50aXR5ID0gc2VsZi5nZXRfZW50aXR5KAogICAgICAgICAgICAg - ICAgZW50aXR5LAogICAgICAgICAgICAgICAgcmJkX3Bvb2xfbmFtZSwKICAgICAgICAgICAgICAg - IGFsaWFzX3JiZF9wb29sX25hbWUsCiAgICAgICAgICAgICAgICBrOHNfY2x1c3Rlcl9uYW1lLAog - ICAgICAgICAgICAgICAgcmFkb3NfbmFtZXNwYWNlLAogICAgICAgICAgICApCiAgICAgICAgICAg - IGlmIHJhZG9zX25hbWVzcGFjZSAhPSAiIjoKICAgICAgICAgICAgICAgIGNhcHNbIm9zZCJdID0g - KAogICAgICAgICAgICAgICAgICAgIGYicHJvZmlsZSByYmQgcG9vbD17cmJkX3Bvb2xfbmFtZX0g - bmFtZXNwYWNlPXtyYWRvc19uYW1lc3BhY2V9IgogICAgICAgICAgICAgICAgKQogICAgICAgICAg - ICBlbHNlOgogICAgICAgICAgICAgICAgY2Fwc1sib3NkIl0gPSBmInByb2ZpbGUgcmJkIHBvb2w9 - e3JiZF9wb29sX25hbWV9IgoKICAgICAgICByZXR1cm4gY2FwcywgZW50aXR5CgogICAgZGVmIGdl - dF9yYmRfbm9kZV9jYXBzX2FuZF9lbnRpdHkoc2VsZik6CiAgICAgICAgZW50aXR5ID0gImNsaWVu - dC5jc2ktcmJkLW5vZGUiCiAgICAgICAgY2FwcyA9IHsKICAgICAgICAgICAgIm1vbiI6ICJwcm9m - aWxlIHJiZCwgYWxsb3cgY29tbWFuZCAnb3NkIGJsb2NrbGlzdCciLAogICAgICAgICAgICAib3Nk - IjogInByb2ZpbGUgcmJkIiwKICAgICAgICB9CiAgICAgICAgaWYgc2VsZi5fYXJnX3BhcnNlci5y - ZXN0cmljdGVkX2F1dGhfcGVybWlzc2lvbjoKICAgICAgICAgICAgcmJkX3Bvb2xfbmFtZSA9IHNl - bGYuX2FyZ19wYXJzZXIucmJkX2RhdGFfcG9vbF9uYW1lCiAgICAgICAgICAgIGFsaWFzX3JiZF9w - b29sX25hbWUgPSBzZWxmLl9hcmdfcGFyc2VyLmFsaWFzX3JiZF9kYXRhX3Bvb2xfbmFtZQogICAg - ICAgICAgICBrOHNfY2x1c3Rlcl9uYW1lID0gc2VsZi5fYXJnX3BhcnNlci5rOHNfY2x1c3Rlcl9u - YW1lCiAgICAgICAgICAgIHJhZG9zX25hbWVzcGFjZSA9IHNlbGYuX2FyZ19wYXJzZXIucmFkb3Nf - bmFtZXNwYWNlCiAgICAgICAgICAgIGlmIHJiZF9wb29sX25hbWUgPT0gIiI6CiAgICAgICAgICAg + ICAgIi0tcmJkLW1ldGFkYXRhLWVjLXBvb2wtbmFtZSIsCiAgICAgICAgICAgIGRlZmF1bHQ9IiIs + CiAgICAgICAgICAgIHJlcXVpcmVkPUZhbHNlLAogICAgICAgICAgICBoZWxwPSJQcm92aWRlcyB0 + aGUgbmFtZSBvZiBlcmFzdXJlIGNvZGVkIFJCRCBtZXRhZGF0YSBwb29sIiwKICAgICAgICApCiAg + ICAgICAgb3V0cHV0X2dyb3VwLmFkZF9hcmd1bWVudCgKICAgICAgICAgICAgIi0tZHJ5LXJ1biIs + CiAgICAgICAgICAgIGRlZmF1bHQ9RmFsc2UsCiAgICAgICAgICAgIGFjdGlvbj0ic3RvcmVfdHJ1 + ZSIsCiAgICAgICAgICAgIGhlbHA9IkRyeSBydW4gcHJpbnRzIHRoZSBleGVjdXRlZCBjb21tYW5k + cyB3aXRob3V0IHJ1bm5pbmcgdGhlbSIsCiAgICAgICAgKQogICAgICAgIG91dHB1dF9ncm91cC5h + ZGRfYXJndW1lbnQoCiAgICAgICAgICAgICItLXJhZG9zLW5hbWVzcGFjZSIsCiAgICAgICAgICAg + IGRlZmF1bHQ9IiIsCiAgICAgICAgICAgIHJlcXVpcmVkPUZhbHNlLAogICAgICAgICAgICBoZWxw + PSJEaXZpZGVzIGEgcG9vbCBpbnRvIHNlcGFyYXRlIGxvZ2ljYWwgbmFtZXNwYWNlcywgdXNlZCBm + b3IgY3JlYXRpbmcgUkJEIFBWQyBpbiBhIENlcGhCbG9ja1Bvb2xSYWRvc05hbWVzcGFjZSAoc2hv + dWxkIGJlIGxvd2VyIGNhc2UpIiwKICAgICAgICApCiAgICAgICAgb3V0cHV0X2dyb3VwLmFkZF9h + cmd1bWVudCgKICAgICAgICAgICAgIi0tc3Vidm9sdW1lLWdyb3VwIiwKICAgICAgICAgICAgZGVm + YXVsdD0iIiwKICAgICAgICAgICAgcmVxdWlyZWQ9RmFsc2UsCiAgICAgICAgICAgIGhlbHA9InBy + b3ZpZGVzIHRoZSBuYW1lIG9mIHRoZSBzdWJ2b2x1bWUgZ3JvdXAiLAogICAgICAgICkKICAgICAg + ICBvdXRwdXRfZ3JvdXAuYWRkX2FyZ3VtZW50KAogICAgICAgICAgICAiLS1yZ3ctcmVhbG0tbmFt + ZSIsCiAgICAgICAgICAgIGRlZmF1bHQ9IiIsCiAgICAgICAgICAgIHJlcXVpcmVkPUZhbHNlLAog + ICAgICAgICAgICBoZWxwPSJwcm92aWRlcyB0aGUgbmFtZSBvZiB0aGUgcmd3LXJlYWxtIiwKICAg + ICAgICApCiAgICAgICAgb3V0cHV0X2dyb3VwLmFkZF9hcmd1bWVudCgKICAgICAgICAgICAgIi0t + cmd3LXpvbmUtbmFtZSIsCiAgICAgICAgICAgIGRlZmF1bHQ9IiIsCiAgICAgICAgICAgIHJlcXVp + cmVkPUZhbHNlLAogICAgICAgICAgICBoZWxwPSJwcm92aWRlcyB0aGUgbmFtZSBvZiB0aGUgcmd3 + LXpvbmUiLAogICAgICAgICkKICAgICAgICBvdXRwdXRfZ3JvdXAuYWRkX2FyZ3VtZW50KAogICAg + ICAgICAgICAiLS1yZ3ctem9uZWdyb3VwLW5hbWUiLAogICAgICAgICAgICBkZWZhdWx0PSIiLAog + ICAgICAgICAgICByZXF1aXJlZD1GYWxzZSwKICAgICAgICAgICAgaGVscD0icHJvdmlkZXMgdGhl + IG5hbWUgb2YgdGhlIHJndy16b25lZ3JvdXAiLAogICAgICAgICkKICAgICAgICBvdXRwdXRfZ3Jv + dXAuYWRkX2FyZ3VtZW50KAogICAgICAgICAgICAiLS10b3BvbG9neS1wb29scyIsCiAgICAgICAg + ICAgIGRlZmF1bHQ9IiIsCiAgICAgICAgICAgIHJlcXVpcmVkPUZhbHNlLAogICAgICAgICAgICBo + ZWxwPSJjb21tYS1zZXBhcmF0ZWQgbGlzdCBvZiB0b3BvbG9neS1jb25zdHJhaW5lZCByYmQgcG9v + bHMiLAogICAgICAgICkKICAgICAgICBvdXRwdXRfZ3JvdXAuYWRkX2FyZ3VtZW50KAogICAgICAg + ICAgICAiLS10b3BvbG9neS1mYWlsdXJlLWRvbWFpbi1sYWJlbCIsCiAgICAgICAgICAgIGRlZmF1 + bHQ9IiIsCiAgICAgICAgICAgIHJlcXVpcmVkPUZhbHNlLAogICAgICAgICAgICBoZWxwPSJrOHMg + Y2x1c3RlciBmYWlsdXJlIGRvbWFpbiBsYWJlbCAoZXhhbXBsZTogem9uZSwgcmFjaywgb3IgaG9z + dCkgZm9yIHRoZSB0b3BvbG9neS1wb29scyB0aGF0IG1hdGNoIHRoZSBjZXBoIGRvbWFpbiIsCiAg + ICAgICAgKQogICAgICAgIG91dHB1dF9ncm91cC5hZGRfYXJndW1lbnQoCiAgICAgICAgICAgICIt + LXRvcG9sb2d5LWZhaWx1cmUtZG9tYWluLXZhbHVlcyIsCiAgICAgICAgICAgIGRlZmF1bHQ9IiIs + CiAgICAgICAgICAgIHJlcXVpcmVkPUZhbHNlLAogICAgICAgICAgICBoZWxwPSJjb21tYS1zZXBh + cmF0ZWQgbGlzdCBvZiB0aGUgazhzIGNsdXN0ZXIgZmFpbHVyZSBkb21haW4gdmFsdWVzIGNvcnJl + c3BvbmRpbmcgdG8gZWFjaCBvZiB0aGUgcG9vbHMgaW4gdGhlIGB0b3BvbG9neS1wb29sc2AgbGlz + dCIsCiAgICAgICAgKQoKICAgICAgICB1cGdyYWRlX2dyb3VwID0gYXJnUC5hZGRfYXJndW1lbnRf + Z3JvdXAoInVwZ3JhZGUiKQogICAgICAgIHVwZ3JhZGVfZ3JvdXAuYWRkX2FyZ3VtZW50KAogICAg + ICAgICAgICAiLS11cGdyYWRlIiwKICAgICAgICAgICAgYWN0aW9uPSJzdG9yZV90cnVlIiwKICAg + ICAgICAgICAgZGVmYXVsdD1GYWxzZSwKICAgICAgICAgICAgaGVscD0iVXBncmFkZXMgdGhlIGNl + cGhDU0lLZXlyaW5ncyhGb3IgZXhhbXBsZTogY2xpZW50LmNzaS1jZXBoZnMtcHJvdmlzaW9uZXIp + IGFuZCBjbGllbnQuaGVhbHRoY2hlY2tlciBjZXBoIHVzZXJzIHdpdGggbmV3IHBlcm1pc3Npb25z + IG5lZWRlZCBmb3IgdGhlIG5ldyBjbHVzdGVyIHZlcnNpb24gYW5kIG9sZGVyIHBlcm1pc3Npb24g + d2lsbCBzdGlsbCBiZSBhcHBsaWVkLiIKICAgICAgICAgICAgKyAiU2FtcGxlIHJ1bjogYHB5dGhv + bjMgL2V0Yy9jZXBoL2NyZWF0ZS1leHRlcm5hbC1jbHVzdGVyLXJlc291cmNlcy5weSAtLXVwZ3Jh + ZGVgLCB0aGlzIHdpbGwgdXBncmFkZSBhbGwgdGhlIGRlZmF1bHQgY3NpIHVzZXJzKG5vbi1yZXN0 + cmljdGVkKSIKICAgICAgICAgICAgKyAiRm9yIHJlc3RyaWN0ZWQgdXNlcnMoRm9yIGV4YW1wbGU6 + IGNsaWVudC5jc2ktY2VwaGZzLXByb3Zpc2lvbmVyLW9wZW5zaGlmdC1zdG9yYWdlLW15ZnMpLCB1 + c2VycyBjcmVhdGVkIHVzaW5nIC0tcmVzdHJpY3RlZC1hdXRoLXBlcm1pc3Npb24gZmxhZyBuZWVk + IHRvIHBhc3MgbWFuZGF0b3J5IGZsYWdzIgogICAgICAgICAgICArICJtYW5kYXRvcnkgZmxhZ3M6 + ICctLXJiZC1kYXRhLXBvb2wtbmFtZSwgLS1rOHMtY2x1c3Rlci1uYW1lIGFuZCAtLXJ1bi1hcy11 + c2VyJyBmbGFncyB3aGlsZSB1cGdyYWRpbmciCiAgICAgICAgICAgICsgImluIGNhc2Ugb2YgY2Vw + aGZzIHVzZXJzIGlmIHlvdSBoYXZlIHBhc3NlZCAtLWNlcGhmcy1maWxlc3lzdGVtLW5hbWUgZmxh + ZyB3aGlsZSBjcmVhdGluZyB1c2VyIHRoZW4gd2hpbGUgdXBncmFkaW5nIGl0IHdpbGwgYmUgbWFu + ZGF0b3J5IHRvbyIKICAgICAgICAgICAgKyAiU2FtcGxlIHJ1bjogYHB5dGhvbjMgL2V0Yy9jZXBo + L2NyZWF0ZS1leHRlcm5hbC1jbHVzdGVyLXJlc291cmNlcy5weSAtLXVwZ3JhZGUgLS1yYmQtZGF0 + YS1wb29sLW5hbWUgcmVwbGljYXBvb2wgLS1rOHMtY2x1c3Rlci1uYW1lIHJvb2tzdG9yYWdlICAt + LXJ1bi1hcy11c2VyIGNsaWVudC5jc2ktcmJkLW5vZGUtcm9va3N0b3JhZ2UtcmVwbGljYXBvb2xg + IgogICAgICAgICAgICArICJQUzogQW4gZXhpc3Rpbmcgbm9uLXJlc3RyaWN0ZWQgdXNlciBjYW5u + b3QgYmUgY29udmVydGVkIHRvIGEgcmVzdHJpY3RlZCB1c2VyIGJ5IHVwZ3JhZGluZy4iCiAgICAg + ICAgICAgICsgIlVwZ3JhZGUgZmxhZyBzaG91bGQgb25seSBiZSB1c2VkIHRvIGFwcGVuZCBuZXcg + cGVybWlzc2lvbnMgdG8gdXNlcnMsIGl0IHNob3VsZG4ndCBiZSB1c2VkIGZvciBjaGFuZ2luZyB1 + c2VyIGFscmVhZHkgYXBwbGllZCBwZXJtaXNzaW9uLCBmb3IgZXhhbXBsZSB5b3Ugc2hvdWxkbid0 + IGNoYW5nZSBpbiB3aGljaCBwb29sIHVzZXIgaGFzIGFjY2VzcyIsCiAgICAgICAgKQoKICAgICAg + ICAjIEFkZCBjb21tYW5kLWxpbmUgYXJndW1lbnRzCiAgICAgICAgY29uZmlnX2dyb3VwID0gYXJn + UC5hZGRfYXJndW1lbnRfZ3JvdXAoImNvbmZpZyIpCiAgICAgICAgY29uZmlnX2dyb3VwLmFkZF9h + cmd1bWVudCgKICAgICAgICAgICAgIi0tY29uZmlnLWZpbGUiLAogICAgICAgICAgICB0eXBlPXN0 + ciwKICAgICAgICAgICAgaGVscD0iUGF0aCB0byB0aGUgY29uZmlndXJhdGlvbiBmaWxlLCBQcmlv + cml0eTogY29tbWFuZC1saW5lLWFyZ3MgPiBjb25maWcuaW5pIGZpbGUgdmFsdWVzID4gZGVmYXVs + dCB2YWx1ZXMiLAogICAgICAgICAgICByZXF1aXJlZD1GYWxzZSwKICAgICAgICAgICAgZGVmYXVs + dD0iIiwKICAgICAgICApCgogICAgICAgIGlmIGFyZ3NfdG9fcGFyc2U6CiAgICAgICAgICAgIGFz + c2VydCAoCiAgICAgICAgICAgICAgICB0eXBlKGFyZ3NfdG9fcGFyc2UpID09IGxpc3QKICAgICAg + ICAgICAgKSwgIkFyZ3VtZW50IHRvICdnZW5fYXJnX3BhcnNlcicgc2hvdWxkIGJlIGEgbGlzdCIK + ICAgICAgICBlbHNlOgogICAgICAgICAgICBhcmdzX3RvX3BhcnNlID0gc3lzLmFyZ3ZbMTpdCiAg + ICAgICAgcmV0dXJuIGFyZ1AucGFyc2VfYXJncyhhcmdzX3RvX3BhcnNlKQoKICAgIGRlZiB2YWxp + ZGF0ZV9yYmRfbWV0YWRhdGFfZWNfcG9vbF9uYW1lKHNlbGYpOgogICAgICAgIGlmIHNlbGYuX2Fy + Z19wYXJzZXIucmJkX21ldGFkYXRhX2VjX3Bvb2xfbmFtZToKICAgICAgICAgICAgcmJkX21ldGFk + YXRhX2VjX3Bvb2xfbmFtZSA9IHNlbGYuX2FyZ19wYXJzZXIucmJkX21ldGFkYXRhX2VjX3Bvb2xf + bmFtZQogICAgICAgICAgICByYmRfcG9vbF9uYW1lID0gc2VsZi5fYXJnX3BhcnNlci5yYmRfZGF0 + YV9wb29sX25hbWUKCiAgICAgICAgICAgIGlmIHJiZF9wb29sX25hbWUgPT0gIiI6CiAgICAgICAg + ICAgICAgICByYWlzZSBFeGVjdXRpb25GYWlsdXJlRXhjZXB0aW9uKAogICAgICAgICAgICAgICAg + ICAgICJGbGFnICctLXJiZC1kYXRhLXBvb2wtbmFtZScgc2hvdWxkIG5vdCBiZSBlbXB0eSIKICAg + ICAgICAgICAgICAgICkKCiAgICAgICAgICAgIGlmIHJiZF9tZXRhZGF0YV9lY19wb29sX25hbWUg + PT0gIiI6CiAgICAgICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWlsdXJlRXhjZXB0aW9uKAog + ICAgICAgICAgICAgICAgICAgICJGbGFnICctLXJiZC1tZXRhZGF0YS1lYy1wb29sLW5hbWUnIHNo + b3VsZCBub3QgYmUgZW1wdHkiCiAgICAgICAgICAgICAgICApCgogICAgICAgICAgICBjbWRfanNv + biA9IHsicHJlZml4IjogIm9zZCBkdW1wIiwgImZvcm1hdCI6ICJqc29uIn0KICAgICAgICAgICAg + cmV0X3ZhbCwganNvbl9vdXQsIGVycl9tc2cgPSBzZWxmLl9jb21tb25fY21kX2pzb25fZ2VuKGNt + ZF9qc29uKQogICAgICAgICAgICBpZiByZXRfdmFsICE9IDAgb3IgbGVuKGpzb25fb3V0KSA9PSAw + OgogICAgICAgICAgICAgICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlvbigKICAgICAg + ICAgICAgICAgICAgICBmIntjbWRfanNvblsncHJlZml4J119IGNvbW1hbmQgZmFpbGVkLlxuIgog + ICAgICAgICAgICAgICAgICAgIGYiRXJyb3I6IHtlcnJfbXNnIGlmIHJldF92YWwgIT0gMCBlbHNl + IHNlbGYuRU1QVFlfT1VUUFVUX0xJU1R9IgogICAgICAgICAgICAgICAgKQogICAgICAgICAgICBt + ZXRhZGF0YV9wb29sX2V4aXN0LCBwb29sX2V4aXN0ID0gRmFsc2UsIEZhbHNlCgogICAgICAgICAg + ICBmb3Iga2V5IGluIGpzb25fb3V0WyJwb29scyJdOgogICAgICAgICAgICAgICAgIyBpZiBlcmFz + dXJlX2NvZGVfcHJvZmlsZSBpcyBlbXB0eSBhbmQgcG9vbCBuYW1lIGV4aXN0cyB0aGVuIGl0IHJl + cGxpY2EgcG9vbAogICAgICAgICAgICAgICAgaWYgKAogICAgICAgICAgICAgICAgICAgIGtleVsi + ZXJhc3VyZV9jb2RlX3Byb2ZpbGUiXSA9PSAiIgogICAgICAgICAgICAgICAgICAgIGFuZCBrZXlb + InBvb2xfbmFtZSJdID09IHJiZF9tZXRhZGF0YV9lY19wb29sX25hbWUKICAgICAgICAgICAgICAg + ICk6CiAgICAgICAgICAgICAgICAgICAgbWV0YWRhdGFfcG9vbF9leGlzdCA9IFRydWUKICAgICAg + ICAgICAgICAgICMgaWYgZXJhc3VyZV9jb2RlX3Byb2ZpbGUgaXMgbm90IGVtcHR5IGFuZCBwb29s + IG5hbWUgZXhpc3RzIHRoZW4gaXQgaXMgZWMgcG9vbAogICAgICAgICAgICAgICAgaWYga2V5WyJl + cmFzdXJlX2NvZGVfcHJvZmlsZSJdIGFuZCBrZXlbInBvb2xfbmFtZSJdID09IHJiZF9wb29sX25h + bWU6CiAgICAgICAgICAgICAgICAgICAgcG9vbF9leGlzdCA9IFRydWUKCiAgICAgICAgICAgIGlm + IG5vdCBtZXRhZGF0YV9wb29sX2V4aXN0OgogICAgICAgICAgICAgICAgcmFpc2UgRXhlY3V0aW9u + RmFpbHVyZUV4Y2VwdGlvbigKICAgICAgICAgICAgICAgICAgICAiUHJvdmlkZWQgcmJkX2VjX21l + dGFkYXRhX3Bvb2wgbmFtZSwiCiAgICAgICAgICAgICAgICAgICAgZiIge3JiZF9tZXRhZGF0YV9l + Y19wb29sX25hbWV9LCBkb2VzIG5vdCBleGlzdCIKICAgICAgICAgICAgICAgICkKICAgICAgICAg + ICAgaWYgbm90IHBvb2xfZXhpc3Q6CiAgICAgICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWls + dXJlRXhjZXB0aW9uKAogICAgICAgICAgICAgICAgICAgIGYiUHJvdmlkZWQgcmJkX2RhdGFfcG9v + bCBuYW1lLCB7cmJkX3Bvb2xfbmFtZX0sIGRvZXMgbm90IGV4aXN0IgogICAgICAgICAgICAgICAg + KQogICAgICAgICAgICByZXR1cm4gcmJkX21ldGFkYXRhX2VjX3Bvb2xfbmFtZQoKICAgIGRlZiBk + cnlfcnVuKHNlbGYsIG1zZyk6CiAgICAgICAgaWYgc2VsZi5fYXJnX3BhcnNlci5kcnlfcnVuOgog + ICAgICAgICAgICBwcmludCgiRXhlY3V0ZTogIiArICInIiArIG1zZyArICInIikKCiAgICBkZWYg + dmFsaWRhdGVfcmd3X2VuZHBvaW50X3Rsc19jZXJ0KHNlbGYpOgogICAgICAgIGlmIHNlbGYuX2Fy + Z19wYXJzZXIucmd3X3Rsc19jZXJ0X3BhdGg6CiAgICAgICAgICAgIHdpdGggb3BlbihzZWxmLl9h + cmdfcGFyc2VyLnJnd190bHNfY2VydF9wYXRoLCBlbmNvZGluZz0idXRmOCIpIGFzIGY6CiAgICAg + ICAgICAgICAgICBjb250ZW50cyA9IGYucmVhZCgpCiAgICAgICAgICAgICAgICByZXR1cm4gY29u + dGVudHMucnN0cmlwKCkKCiAgICBkZWYgX2NoZWNrX2NvbmZsaWN0aW5nX29wdGlvbnMoc2VsZik6 + CiAgICAgICAgaWYgbm90IHNlbGYuX2FyZ19wYXJzZXIudXBncmFkZSBhbmQgbm90IHNlbGYuX2Fy + Z19wYXJzZXIucmJkX2RhdGFfcG9vbF9uYW1lOgogICAgICAgICAgICByYWlzZSBFeGVjdXRpb25G + YWlsdXJlRXhjZXB0aW9uKAogICAgICAgICAgICAgICAgIkVpdGhlciAnLS11cGdyYWRlJyBvciAn + LS1yYmQtZGF0YS1wb29sLW5hbWUgPHBvb2xfbmFtZT4nIHNob3VsZCBiZSBzcGVjaWZpZWQiCiAg + ICAgICAgICAgICkKCiAgICBkZWYgX2ludmFsaWRfZW5kcG9pbnQoc2VsZiwgZW5kcG9pbnRfc3Ry + KToKICAgICAgICAjIGV4dHJhY3QgdGhlIHBvcnQgYnkgZ2V0dGluZyB0aGUgbGFzdCBzcGxpdCBv + biBgOmAgZGVsaW1pdGVyCiAgICAgICAgdHJ5OgogICAgICAgICAgICBlbmRwb2ludF9zdHJfaXAs + IHBvcnQgPSBlbmRwb2ludF9zdHIucnNwbGl0KCI6IiwgMSkKICAgICAgICBleGNlcHQgVmFsdWVF + cnJvcjoKICAgICAgICAgICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlvbihmIk5vdCBh + IHByb3BlciBlbmRwb2ludDoge2VuZHBvaW50X3N0cn0iKQoKICAgICAgICB0cnk6CiAgICAgICAg + ICAgIGlmIGVuZHBvaW50X3N0cl9pcFswXSA9PSAiWyI6CiAgICAgICAgICAgICAgICBlbmRwb2lu + dF9zdHJfaXAgPSBlbmRwb2ludF9zdHJfaXBbMSA6IGxlbihlbmRwb2ludF9zdHJfaXApIC0gMV0K + ICAgICAgICAgICAgaXBfdHlwZSA9ICgKICAgICAgICAgICAgICAgICJJUHY0IiBpZiB0eXBlKGlw + X2FkZHJlc3MoZW5kcG9pbnRfc3RyX2lwKSkgaXMgSVB2NEFkZHJlc3MgZWxzZSAiSVB2NiIKICAg + ICAgICAgICAgKQogICAgICAgIGV4Y2VwdCBWYWx1ZUVycm9yOgogICAgICAgICAgICBpcF90eXBl + ID0gIkZRRE4iCiAgICAgICAgaWYgbm90IHBvcnQuaXNkaWdpdCgpOgogICAgICAgICAgICByYWlz + ZSBFeGVjdXRpb25GYWlsdXJlRXhjZXB0aW9uKGYiUG9ydCBub3QgdmFsaWQ6IHtwb3J0fSIpCiAg + ICAgICAgaW50UG9ydCA9IGludChwb3J0KQogICAgICAgIGlmIGludFBvcnQgPCAxIG9yIGludFBv + cnQgPiAyKioxNiAtIDE6CiAgICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1cmVFeGNlcHRp + b24oZiJPdXQgb2YgcmFuZ2UgcG9ydCBudW1iZXI6IHtwb3J0fSIpCgogICAgICAgIHJldHVybiBp + cF90eXBlCgogICAgZGVmIGVuZHBvaW50X2RpYWwoc2VsZiwgZW5kcG9pbnRfc3RyLCBpcF90eXBl + LCB0aW1lb3V0PTMsIGNlcnQ9Tm9uZSk6CiAgICAgICAgIyBpZiB0aGUgJ2NsdXN0ZXInIGluc3Rh + bmNlIGlzIGEgZHVtbXkgb25lLAogICAgICAgICMgZG9uJ3QgdHJ5IHRvIHJlYWNoIG91dCB0byB0 + aGUgZW5kcG9pbnQKICAgICAgICBpZiBpc2luc3RhbmNlKHNlbGYuY2x1c3RlciwgRHVtbXlSYWRv + cyk6CiAgICAgICAgICAgIHJldHVybiAiIiwgIiIsICIiCiAgICAgICAgaWYgaXBfdHlwZSA9PSAi + SVB2NiI6CiAgICAgICAgICAgIHRyeToKICAgICAgICAgICAgICAgIGVuZHBvaW50X3N0cl9pcCwg + ZW5kcG9pbnRfc3RyX3BvcnQgPSBlbmRwb2ludF9zdHIucnNwbGl0KCI6IiwgMSkKICAgICAgICAg + ICAgZXhjZXB0IFZhbHVlRXJyb3I6CiAgICAgICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWls + dXJlRXhjZXB0aW9uKAogICAgICAgICAgICAgICAgICAgIGYiTm90IGEgcHJvcGVyIGVuZHBvaW50 + OiB7ZW5kcG9pbnRfc3RyfSIKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgaWYgZW5kcG9p + bnRfc3RyX2lwWzBdICE9ICJbIjoKICAgICAgICAgICAgICAgIGVuZHBvaW50X3N0cl9pcCA9ICJb + IiArIGVuZHBvaW50X3N0cl9pcCArICJdIgogICAgICAgICAgICBlbmRwb2ludF9zdHIgPSAiOiIu + am9pbihbZW5kcG9pbnRfc3RyX2lwLCBlbmRwb2ludF9zdHJfcG9ydF0pCgogICAgICAgIHByb3Rv + Y29scyA9IFsiaHR0cCIsICJodHRwcyJdCiAgICAgICAgcmVzcG9uc2VfZXJyb3IgPSBOb25lCiAg + ICAgICAgZm9yIHByZWZpeCBpbiBwcm90b2NvbHM6CiAgICAgICAgICAgIHRyeToKICAgICAgICAg + ICAgICAgIGVwID0gZiJ7cHJlZml4fTovL3tlbmRwb2ludF9zdHJ9IgogICAgICAgICAgICAgICAg + dmVyaWZ5ID0gTm9uZQogICAgICAgICAgICAgICAgIyBJZiB2ZXJpZnkgaXMgc2V0IHRvIGEgcGF0 + aCB0byBhIGRpcmVjdG9yeSwKICAgICAgICAgICAgICAgICMgdGhlIGRpcmVjdG9yeSBtdXN0IGhh + dmUgYmVlbiBwcm9jZXNzZWQgdXNpbmcgdGhlIGNfcmVoYXNoIHV0aWxpdHkgc3VwcGxpZWQgd2l0 + aCBPcGVuU1NMLgogICAgICAgICAgICAgICAgaWYgcHJlZml4ID09ICJodHRwcyIgYW5kIHNlbGYu + X2FyZ19wYXJzZXIucmd3X3NraXBfdGxzOgogICAgICAgICAgICAgICAgICAgIHZlcmlmeSA9IEZh + bHNlCiAgICAgICAgICAgICAgICAgICAgciA9IHJlcXVlc3RzLmhlYWQoZXAsIHRpbWVvdXQ9dGlt + ZW91dCwgdmVyaWZ5PUZhbHNlKQogICAgICAgICAgICAgICAgZWxpZiBwcmVmaXggPT0gImh0dHBz + IiBhbmQgY2VydDoKICAgICAgICAgICAgICAgICAgICB2ZXJpZnkgPSBjZXJ0CiAgICAgICAgICAg + ICAgICAgICAgciA9IHJlcXVlc3RzLmhlYWQoZXAsIHRpbWVvdXQ9dGltZW91dCwgdmVyaWZ5PWNl + cnQpCiAgICAgICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgICAgIHIgPSByZXF1ZXN0 + cy5oZWFkKGVwLCB0aW1lb3V0PXRpbWVvdXQpCiAgICAgICAgICAgICAgICBpZiByLnN0YXR1c19j + b2RlID09IDIwMDoKICAgICAgICAgICAgICAgICAgICByZXR1cm4gcHJlZml4LCB2ZXJpZnksICIi + CiAgICAgICAgICAgIGV4Y2VwdCBFeGNlcHRpb24gYXMgZXJyOgogICAgICAgICAgICAgICAgcmVz + cG9uc2VfZXJyb3IgPSBlcnIKICAgICAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgc3lzLnN0 + ZGVyci53cml0ZSgKICAgICAgICAgICAgZiJ1bmFibGUgdG8gY29ubmVjdCB0byBlbmRwb2ludDog + e2VuZHBvaW50X3N0cn0sIGZhaWxlZCBlcnJvcjoge3Jlc3BvbnNlX2Vycm9yfSIKICAgICAgICAp + CiAgICAgICAgcmV0dXJuICgKICAgICAgICAgICAgIiIsCiAgICAgICAgICAgICIiLAogICAgICAg + ICAgICAoIi0xIiksCiAgICAgICAgKQoKICAgIGRlZiBwYXJzZV9jb25maWdfZmlsZShzZWxmLCBj + b25maWdfZmlsZSk6CiAgICAgICAgY29uZmlnID0gY29uZmlncGFyc2VyLkNvbmZpZ1BhcnNlcigp + CiAgICAgICAgY29uZmlnLnJlYWQoY29uZmlnX2ZpbGUpCiAgICAgICAgZm9yIGFyZyBpbiBsaXN0 + KHZhcnMoc2VsZi5fYXJnX3BhcnNlcikpOgogICAgICAgICAgICAjIHB5dGhvbiB0cmVhdHMgZmxh + Zy1uYW1lIGFzIGZsYWdfbmFtZSBpbnRlcm5hbGx5LCBzbyBjb252ZXJ0aW5nIGJhY2sgdG8gZmxh + Zy1uYW1lLAogICAgICAgICAgICAjIHNvIHdlIGNhbiBnZXQgdGhvc2UgdmFsdWVzIGZyb20gY29u + ZmlnIGZpbGUKICAgICAgICAgICAgYXJndW1lbnQgPSBhcmcucmVwbGFjZSgiXyIsICItIikKICAg + ICAgICAgICAgYXJndW1lbnRWYWx1ZSA9IHN0cihnZXRhdHRyKHNlbGYuX2FyZ19wYXJzZXIsIGFy + ZykpCiAgICAgICAgICAgIGNvbmZpZ192YWx1ZSA9IGNvbmZpZy5nZXQoIkNvbmZpZ3VyYXRpb25z + IiwgYXJndW1lbnQsIGZhbGxiYWNrPU5vbmUpCiAgICAgICAgICAgICMgZ2l2ZSBwcmlvcml0eSB0 + byBjb21tYW5kIGxpbmUgYXJndW1lbnQsIGlmIGNvbW1hbmQgbGluZSBhcmd1bWVudCBpcyBub3Qg + cHJlc2VudCB1c2UgY29uZmlnLmluaSB2YWx1ZSwKICAgICAgICAgICAgaWYgKHN0cihzeXMuYXJn + dikuZmluZChhcmd1bWVudCkgPT0gLTEpIGFuZCAoCiAgICAgICAgICAgICAgICAoY29uZmlnX3Zh + bHVlICE9IE5vbmUpIGFuZCAoY29uZmlnX3ZhbHVlICE9ICIiKQogICAgICAgICAgICApOgogICAg + ICAgICAgICAgICAgc2VsZi5fYXJnX3BhcnNlci5fX3NldGF0dHJfXyhhcmcsIGNvbmZpZ192YWx1 + ZSkKCiAgICAgICAgcmV0dXJuIGNvbmZpZwoKICAgIGRlZiBfX2luaXRfXyhzZWxmLCBhcmdfbGlz + dD1Ob25lKToKICAgICAgICBzZWxmLm91dF9tYXAgPSB7fQogICAgICAgIHNlbGYuX2V4Y2x1ZGVk + X2tleXMgPSBzZXQoKQogICAgICAgIHNlbGYuX2FyZ19wYXJzZXIgPSBzZWxmLmdlbl9hcmdfcGFy + c2VyKGFyZ3NfdG9fcGFyc2U9YXJnX2xpc3QpCiAgICAgICAgaWYgc2VsZi5fYXJnX3BhcnNlci5j + b25maWdfZmlsZToKICAgICAgICAgICAgc2VsZi5jb25maWcgPSBzZWxmLnBhcnNlX2NvbmZpZ19m + aWxlKHNlbGYuX2FyZ19wYXJzZXIuY29uZmlnX2ZpbGUpCiAgICAgICAgc2VsZi5fY2hlY2tfY29u + ZmxpY3Rpbmdfb3B0aW9ucygpCiAgICAgICAgc2VsZi5ydW5fYXNfdXNlciA9IHNlbGYuX2FyZ19w + YXJzZXIucnVuX2FzX3VzZXIKICAgICAgICBzZWxmLm91dHB1dF9maWxlID0gc2VsZi5fYXJnX3Bh + cnNlci5vdXRwdXQKICAgICAgICBzZWxmLmNlcGhfY29uZiA9IHNlbGYuX2FyZ19wYXJzZXIuY2Vw + aF9jb25mCiAgICAgICAgc2VsZi5jZXBoX2tleXJpbmcgPSBzZWxmLl9hcmdfcGFyc2VyLmtleXJp + bmcKICAgICAgICAjIGlmIHVzZXIgbm90IHByb3ZpZGVkLCBnaXZlIGEgZGVmYXVsdCB1c2VyCiAg + ICAgICAgaWYgbm90IHNlbGYucnVuX2FzX3VzZXIgYW5kIG5vdCBzZWxmLl9hcmdfcGFyc2VyLnVw + Z3JhZGU6CiAgICAgICAgICAgIHNlbGYucnVuX2FzX3VzZXIgPSBzZWxmLkVYVEVSTkFMX1VTRVJf + TkFNRQogICAgICAgIGlmIG5vdCBzZWxmLl9hcmdfcGFyc2VyLnJnd19wb29sX3ByZWZpeCBhbmQg + bm90IHNlbGYuX2FyZ19wYXJzZXIudXBncmFkZToKICAgICAgICAgICAgc2VsZi5fYXJnX3BhcnNl + ci5yZ3dfcG9vbF9wcmVmaXggPSBzZWxmLkRFRkFVTFRfUkdXX1BPT0xfUFJFRklYCiAgICAgICAg + aWYgc2VsZi5jZXBoX2NvbmY6CiAgICAgICAgICAgIGt3YXJncyA9IHt9CiAgICAgICAgICAgIGlm + IHNlbGYuY2VwaF9rZXlyaW5nOgogICAgICAgICAgICAgICAga3dhcmdzWyJjb25mIl0gPSB7Imtl + eXJpbmciOiBzZWxmLmNlcGhfa2V5cmluZ30KICAgICAgICAgICAgc2VsZi5jbHVzdGVyID0gcmFk + b3MuUmFkb3MoY29uZmZpbGU9c2VsZi5jZXBoX2NvbmYsICoqa3dhcmdzKQogICAgICAgIGVsc2U6 + CiAgICAgICAgICAgIHNlbGYuY2x1c3RlciA9IHJhZG9zLlJhZG9zKCkKICAgICAgICAgICAgc2Vs + Zi5jbHVzdGVyLmNvbmZfcmVhZF9maWxlKCkKICAgICAgICBzZWxmLmNsdXN0ZXIuY29ubmVjdCgp + CgogICAgZGVmIHNodXRkb3duKHNlbGYpOgogICAgICAgIGlmIHNlbGYuY2x1c3Rlci5zdGF0ZSA9 + PSAiY29ubmVjdGVkIjoKICAgICAgICAgICAgc2VsZi5jbHVzdGVyLnNodXRkb3duKCkKCiAgICBk + ZWYgZ2V0X2ZzaWQoc2VsZik6CiAgICAgICAgaWYgc2VsZi5fYXJnX3BhcnNlci5kcnlfcnVuOgog + ICAgICAgICAgICByZXR1cm4gc2VsZi5kcnlfcnVuKCJjZXBoIGZzaWQiKQogICAgICAgIHJldHVy + biBzdHIoc2VsZi5jbHVzdGVyLmdldF9mc2lkKCkpCgogICAgZGVmIF9jb21tb25fY21kX2pzb25f + Z2VuKHNlbGYsIGNtZF9qc29uKToKICAgICAgICBjbWQgPSBqc29uLmR1bXBzKGNtZF9qc29uLCBz + b3J0X2tleXM9VHJ1ZSkKICAgICAgICByZXRfdmFsLCBjbWRfb3V0LCBlcnJfbXNnID0gc2VsZi5j + bHVzdGVyLm1vbl9jb21tYW5kKGNtZCwgYiIiKQogICAgICAgIGlmIHNlbGYuX2FyZ19wYXJzZXIu + dmVyYm9zZToKICAgICAgICAgICAgcHJpbnQoZiJDb21tYW5kIElucHV0OiB7Y21kfSIpCiAgICAg + ICAgICAgIHByaW50KAogICAgICAgICAgICAgICAgZiJSZXR1cm4gVmFsOiB7cmV0X3ZhbH1cbkNv + bW1hbmQgT3V0cHV0OiB7Y21kX291dH1cbiIKICAgICAgICAgICAgICAgIGYiRXJyb3IgTWVzc2Fn + ZToge2Vycl9tc2d9XG4tLS0tLS0tLS0tXG4iCiAgICAgICAgICAgICkKICAgICAgICBqc29uX291 + dCA9IHt9CiAgICAgICAgIyBpZiB0aGVyZSBpcyBubyBlcnJvciAoaS5lOyByZXRfdmFsIGlzIFpF + Uk8pIGFuZCAnY21kX291dCcgaXMgbm90IGVtcHR5CiAgICAgICAgIyB0aGVuIGNvbnZlcnQgJ2Nt + ZF9vdXQnIHRvIGEganNvbiBvdXRwdXQKICAgICAgICBpZiByZXRfdmFsID09IDAgYW5kIGNtZF9v + dXQ6CiAgICAgICAgICAgIGpzb25fb3V0ID0ganNvbi5sb2FkcyhjbWRfb3V0KQogICAgICAgIHJl + dHVybiByZXRfdmFsLCBqc29uX291dCwgZXJyX21zZwoKICAgIGRlZiBnZXRfY2VwaF9leHRlcm5h + bF9tb25fZGF0YShzZWxmKToKICAgICAgICBjbWRfanNvbiA9IHsicHJlZml4IjogInF1b3J1bV9z + dGF0dXMiLCAiZm9ybWF0IjogImpzb24ifQogICAgICAgIGlmIHNlbGYuX2FyZ19wYXJzZXIuZHJ5 + X3J1bjoKICAgICAgICAgICAgcmV0dXJuIHNlbGYuZHJ5X3J1bigiY2VwaCAiICsgY21kX2pzb25b + InByZWZpeCJdKQogICAgICAgIHJldF92YWwsIGpzb25fb3V0LCBlcnJfbXNnID0gc2VsZi5fY29t + bW9uX2NtZF9qc29uX2dlbihjbWRfanNvbikKICAgICAgICAjIGlmIHRoZXJlIGlzIGFuIHVuc3Vj + Y2Vzc2Z1bCBhdHRlbXB0LAogICAgICAgIGlmIHJldF92YWwgIT0gMCBvciBsZW4oanNvbl9vdXQp + ID09IDA6CiAgICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1cmVFeGNlcHRpb24oCiAgICAg + ICAgICAgICAgICAiJ3F1b3J1bV9zdGF0dXMnIGNvbW1hbmQgZmFpbGVkLlxuIgogICAgICAgICAg + ICAgICAgZiJFcnJvcjoge2Vycl9tc2cgaWYgcmV0X3ZhbCAhPSAwIGVsc2Ugc2VsZi5FTVBUWV9P + VVRQVVRfTElTVH0iCiAgICAgICAgICAgICkKICAgICAgICBxX2xlYWRlcl9uYW1lID0ganNvbl9v + dXRbInF1b3J1bV9sZWFkZXJfbmFtZSJdCiAgICAgICAgcV9sZWFkZXJfZGV0YWlscyA9IHt9CiAg + ICAgICAgcV9sZWFkZXJfbWF0Y2hpbmdfbGlzdCA9IFsKICAgICAgICAgICAgbCBmb3IgbCBpbiBq + c29uX291dFsibW9ubWFwIl1bIm1vbnMiXSBpZiBsWyJuYW1lIl0gPT0gcV9sZWFkZXJfbmFtZQog + ICAgICAgIF0KICAgICAgICBpZiBsZW4ocV9sZWFkZXJfbWF0Y2hpbmdfbGlzdCkgPT0gMDoKICAg + ICAgICAgICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlvbigiTm8gbWF0Y2hpbmcgJ21v + bicgZGV0YWlscyBmb3VuZCIpCiAgICAgICAgcV9sZWFkZXJfZGV0YWlscyA9IHFfbGVhZGVyX21h + dGNoaW5nX2xpc3RbMF0KICAgICAgICAjIGdldCB0aGUgYWRkcmVzcyB2ZWN0b3Igb2YgdGhlIHF1 + b3J1bS1sZWFkZXIKICAgICAgICBxX2xlYWRlcl9hZGRydmVjID0gcV9sZWFkZXJfZGV0YWlscy5n + ZXQoInB1YmxpY19hZGRycyIsIHt9KS5nZXQoImFkZHJ2ZWMiLCBbXSkKICAgICAgICBpcF9hZGRy + ID0gc3RyKHFfbGVhZGVyX2RldGFpbHNbInB1YmxpY19hZGRyIl0uc3BsaXQoIi8iKVswXSkKCiAg + ICAgICAgaWYgc2VsZi5fYXJnX3BhcnNlci52Ml9wb3J0X2VuYWJsZToKICAgICAgICAgICAgaWYg + cV9sZWFkZXJfYWRkcnZlY1swXVsidHlwZSJdID09ICJ2MiI6CiAgICAgICAgICAgICAgICBpcF9h + ZGRyID0gcV9sZWFkZXJfYWRkcnZlY1swXVsiYWRkciJdCiAgICAgICAgICAgIGVsaWYgbGVuKHFf + bGVhZGVyX2FkZHJ2ZWMpID4gMSBhbmQgcV9sZWFkZXJfYWRkcnZlY1sxXVsidHlwZSJdID09ICJ2 + MiI6CiAgICAgICAgICAgICAgICBpcF9hZGRyID0gcV9sZWFkZXJfYWRkcnZlY1sxXVsiYWRkciJd + CiAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICBzeXMuc3RkZXJyLndyaXRlKAogICAg + ICAgICAgICAgICAgICAgICIndjInIGFkZHJlc3MgdHlwZSBub3QgcHJlc2VudCwgYW5kICd2Mi1w + b3J0LWVuYWJsZScgZmxhZyBpcyBwcm92aWRlZCIKICAgICAgICAgICAgICAgICkKCiAgICAgICAg + cmV0dXJuIGYie3N0cihxX2xlYWRlcl9uYW1lKX09e2lwX2FkZHJ9IgoKICAgIGRlZiBfY29udmVy + dF9ob3N0bmFtZV90b19pcChzZWxmLCBob3N0X25hbWUsIHBvcnQsIGlwX3R5cGUpOgogICAgICAg + ICMgaWYgJ2NsdXN0ZXInIGluc3RhbmNlIGlzIGEgZHVtbXkgdHlwZSwKICAgICAgICAjIGNhbGwg + dGhlIGR1bW15IGluc3RhbmNlJ3MgImNvbnZlcnQiIG1ldGhvZAogICAgICAgIGlmIG5vdCBob3N0 + X25hbWU6CiAgICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1cmVFeGNlcHRpb24oIkVtcHR5 + IGhvc3RuYW1lIHByb3ZpZGVkIikKICAgICAgICBpZiBpc2luc3RhbmNlKHNlbGYuY2x1c3Rlciwg + RHVtbXlSYWRvcyk6CiAgICAgICAgICAgIHJldHVybiBzZWxmLmNsdXN0ZXIuX2NvbnZlcnRfaG9z + dG5hbWVfdG9faXAoaG9zdF9uYW1lKQoKICAgICAgICBpZiBpcF90eXBlID09ICJGUUROIjoKICAg + ICAgICAgICAgIyBjaGVjayB3aGljaCBpcCBGUUROIHNob3VsZCBiZSBjb252ZXJ0ZWQgdG8sIElQ + djQgb3IgSVB2NgogICAgICAgICAgICAjIGNoZWNrIHRoZSBob3N0IGlwLCB0aGUgZW5kcG9pbnQg + aXAgdHlwZSB3b3VsZCBiZSBzaW1pbGFyIHRvIGhvc3QgaXAKICAgICAgICAgICAgY21kX2pzb24g + PSB7InByZWZpeCI6ICJvcmNoIGhvc3QgbHMiLCAiZm9ybWF0IjogImpzb24ifQogICAgICAgICAg + ICByZXRfdmFsLCBqc29uX291dCwgZXJyX21zZyA9IHNlbGYuX2NvbW1vbl9jbWRfanNvbl9nZW4o + Y21kX2pzb24pCiAgICAgICAgICAgICMgaWYgdGhlcmUgaXMgYW4gdW5zdWNjZXNzZnVsIGF0dGVt + cHQsCiAgICAgICAgICAgIGlmIHJldF92YWwgIT0gMCBvciBsZW4oanNvbl9vdXQpID09IDA6CiAg + ICAgICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWlsdXJlRXhjZXB0aW9uKAogICAgICAgICAg + ICAgICAgICAgICInb3JjaCBob3N0IGxzJyBjb21tYW5kIGZhaWxlZC5cbiIKICAgICAgICAgICAg + ICAgICAgICBmIkVycm9yOiB7ZXJyX21zZyBpZiByZXRfdmFsICE9IDAgZWxzZSBzZWxmLkVNUFRZ + X09VVFBVVF9MSVNUfSIKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgaG9zdF9hZGRyID0g + anNvbl9vdXRbMF1bImFkZHIiXQogICAgICAgICAgICAjIGFkZCA6ODAgc2FtcGxlIHBvcnQgaW4g + aXBfdHlwZSwgYXMgX2ludmFsaWRfZW5kcG9pbnQgYWxzbyB2ZXJpZnkgcG9ydAogICAgICAgICAg + ICBob3N0X2lwX3R5cGUgPSBzZWxmLl9pbnZhbGlkX2VuZHBvaW50KGhvc3RfYWRkciArICI6ODAi + KQogICAgICAgICAgICBpbXBvcnQgc29ja2V0CgogICAgICAgICAgICBpcCA9IFtdCiAgICAgICAg + ICAgICMgZXhhbXBsZSBvdXRwdXQgWyg8QWRkcmVzc0ZhbWlseS5BRl9JTkVUOiAyPiwgPFNvY2tl + dEtpbmQuU09DS19TVFJFQU06IDE+LCA2LCAnJywgKCc5My4xODQuMjE2LjM0JywgODApKSwgLi4u + XQogICAgICAgICAgICAjIHdlIG5lZWQgdG8gZ2V0IDkzLjE4NC4yMTYuMzQgc28gaXQgd291bGQg + YmUgaXBbMF1bNF1bMF0KICAgICAgICAgICAgaWYgaG9zdF9pcF90eXBlID09ICJJUHY2IjoKICAg + ICAgICAgICAgICAgIGlwID0gc29ja2V0LmdldGFkZHJpbmZvKAogICAgICAgICAgICAgICAgICAg + IGhvc3RfbmFtZSwgcG9ydCwgZmFtaWx5PXNvY2tldC5BRl9JTkVUNiwgcHJvdG89c29ja2V0LklQ + UFJPVE9fVENQCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgIGVsaWYgaG9zdF9pcF90eXBl + ID09ICJJUHY0IjoKICAgICAgICAgICAgICAgIGlwID0gc29ja2V0LmdldGFkZHJpbmZvKAogICAg + ICAgICAgICAgICAgICAgIGhvc3RfbmFtZSwgcG9ydCwgZmFtaWx5PXNvY2tldC5BRl9JTkVULCBw + cm90bz1zb2NrZXQuSVBQUk9UT19UQ1AKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgZGVs + IHNvY2tldAogICAgICAgICAgICByZXR1cm4gaXBbMF1bNF1bMF0KICAgICAgICByZXR1cm4gaG9z + dF9uYW1lCgogICAgZGVmIGdldF9hY3RpdmVfYW5kX3N0YW5kYnlfbWdycyhzZWxmKToKICAgICAg + ICBpZiBzZWxmLl9hcmdfcGFyc2VyLmRyeV9ydW46CiAgICAgICAgICAgIHJldHVybiAiIiwgc2Vs + Zi5kcnlfcnVuKCJjZXBoIHN0YXR1cyIpCiAgICAgICAgbW9uaXRvcmluZ19lbmRwb2ludF9wb3J0 + ID0gc2VsZi5fYXJnX3BhcnNlci5tb25pdG9yaW5nX2VuZHBvaW50X3BvcnQKICAgICAgICBtb25p + dG9yaW5nX2VuZHBvaW50X2lwX2xpc3QgPSBzZWxmLl9hcmdfcGFyc2VyLm1vbml0b3JpbmdfZW5k + cG9pbnQKICAgICAgICBzdGFuZGJ5X21ncnMgPSBbXQogICAgICAgIGlmIG5vdCBtb25pdG9yaW5n + X2VuZHBvaW50X2lwX2xpc3Q6CiAgICAgICAgICAgIGNtZF9qc29uID0geyJwcmVmaXgiOiAic3Rh + dHVzIiwgImZvcm1hdCI6ICJqc29uIn0KICAgICAgICAgICAgcmV0X3ZhbCwganNvbl9vdXQsIGVy + cl9tc2cgPSBzZWxmLl9jb21tb25fY21kX2pzb25fZ2VuKGNtZF9qc29uKQogICAgICAgICAgICAj + IGlmIHRoZXJlIGlzIGFuIHVuc3VjY2Vzc2Z1bCBhdHRlbXB0LAogICAgICAgICAgICBpZiByZXRf + dmFsICE9IDAgb3IgbGVuKGpzb25fb3V0KSA9PSAwOgogICAgICAgICAgICAgICAgcmFpc2UgRXhl + Y3V0aW9uRmFpbHVyZUV4Y2VwdGlvbigKICAgICAgICAgICAgICAgICAgICAiJ21nciBzZXJ2aWNl + cycgY29tbWFuZCBmYWlsZWQuXG4iCiAgICAgICAgICAgICAgICAgICAgZiJFcnJvcjoge2Vycl9t + c2cgaWYgcmV0X3ZhbCAhPSAwIGVsc2Ugc2VsZi5FTVBUWV9PVVRQVVRfTElTVH0iCiAgICAgICAg + ICAgICAgICApCiAgICAgICAgICAgIG1vbml0b3JpbmdfZW5kcG9pbnQgPSAoCiAgICAgICAgICAg + ICAgICBqc29uX291dC5nZXQoIm1ncm1hcCIsIHt9KS5nZXQoInNlcnZpY2VzIiwge30pLmdldCgi + cHJvbWV0aGV1cyIsICIiKQogICAgICAgICAgICApCiAgICAgICAgICAgIGlmIG5vdCBtb25pdG9y + aW5nX2VuZHBvaW50OgogICAgICAgICAgICAgICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2Vw + dGlvbigKICAgICAgICAgICAgICAgICAgICAiY2FuJ3QgZmluZCBtb25pdG9yaW5nX2VuZHBvaW50 + LCBwcm9tZXRoZXVzIG1vZHVsZSBtaWdodCBub3QgYmUgZW5hYmxlZCwgIgogICAgICAgICAgICAg + ICAgICAgICJlbmFibGUgdGhlIG1vZHVsZSBieSBydW5uaW5nICdjZXBoIG1nciBtb2R1bGUgZW5h + YmxlIHByb21ldGhldXMnIgogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAjIG5vdyBjaGVj + ayB0aGUgc3RhbmQtYnkgbWdyLXMKICAgICAgICAgICAgc3RhbmRieV9hcnIgPSBqc29uX291dC5n + ZXQoIm1ncm1hcCIsIHt9KS5nZXQoInN0YW5kYnlzIiwgW10pCiAgICAgICAgICAgIGZvciBlYWNo + X3N0YW5kYnkgaW4gc3RhbmRieV9hcnI6CiAgICAgICAgICAgICAgICBpZiAibmFtZSIgaW4gZWFj + aF9zdGFuZGJ5LmtleXMoKToKICAgICAgICAgICAgICAgICAgICBzdGFuZGJ5X21ncnMuYXBwZW5k + KGVhY2hfc3RhbmRieVsibmFtZSJdKQogICAgICAgICAgICB0cnk6CiAgICAgICAgICAgICAgICBw + YXJzZWRfZW5kcG9pbnQgPSB1cmxwYXJzZShtb25pdG9yaW5nX2VuZHBvaW50KQogICAgICAgICAg + ICBleGNlcHQgVmFsdWVFcnJvcjoKICAgICAgICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1 + cmVFeGNlcHRpb24oCiAgICAgICAgICAgICAgICAgICAgZiJpbnZhbGlkIGVuZHBvaW50OiB7bW9u + aXRvcmluZ19lbmRwb2ludH0iCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgIG1vbml0b3Jp + bmdfZW5kcG9pbnRfaXBfbGlzdCA9IHBhcnNlZF9lbmRwb2ludC5ob3N0bmFtZQogICAgICAgICAg + ICBpZiBub3QgbW9uaXRvcmluZ19lbmRwb2ludF9wb3J0OgogICAgICAgICAgICAgICAgbW9uaXRv + cmluZ19lbmRwb2ludF9wb3J0ID0gc3RyKHBhcnNlZF9lbmRwb2ludC5wb3J0KQoKICAgICAgICAj + IGlmIG1vbml0b3JpbmcgZW5kcG9pbnQgcG9ydCBpcyBub3Qgc2V0LCBwdXQgYSBkZWZhdWx0IG1v + biBwb3J0CiAgICAgICAgaWYgbm90IG1vbml0b3JpbmdfZW5kcG9pbnRfcG9ydDoKICAgICAgICAg + ICAgbW9uaXRvcmluZ19lbmRwb2ludF9wb3J0ID0gc2VsZi5ERUZBVUxUX01PTklUT1JJTkdfRU5E + UE9JTlRfUE9SVAoKICAgICAgICAjIHVzZXIgY291bGQgZ2l2ZSBjb21tYSBhbmQgc3BhY2Ugc2Vw + YXJhdGVkIGlucHV0cyAobGlrZSAtLW1vbml0b3JpbmctZW5kcG9pbnQ9IjxpcDE+LCA8aXAyPiIp + CiAgICAgICAgbW9uaXRvcmluZ19lbmRwb2ludF9pcF9saXN0ID0gbW9uaXRvcmluZ19lbmRwb2lu + dF9pcF9saXN0LnJlcGxhY2UoIiwiLCAiICIpCiAgICAgICAgbW9uaXRvcmluZ19lbmRwb2ludF9p + cF9saXN0X3NwbGl0ID0gbW9uaXRvcmluZ19lbmRwb2ludF9pcF9saXN0LnNwbGl0KCkKICAgICAg + ICAjIGlmIG1vbml0b3JpbmctZW5kcG9pbnQgY291bGQgbm90IGJlIGZvdW5kLCByYWlzZSBhbiBl + cnJvcgogICAgICAgIGlmIGxlbihtb25pdG9yaW5nX2VuZHBvaW50X2lwX2xpc3Rfc3BsaXQpID09 + IDA6CiAgICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1cmVFeGNlcHRpb24oIk5vICdtb25p + dG9yaW5nLWVuZHBvaW50JyBmb3VuZCIpCiAgICAgICAgIyBmaXJzdCBpcCBpcyB0cmVhdGVkIGFz + IHRoZSBtYWluIG1vbml0b3JpbmctZW5kcG9pbnQKICAgICAgICBtb25pdG9yaW5nX2VuZHBvaW50 + X2lwID0gbW9uaXRvcmluZ19lbmRwb2ludF9pcF9saXN0X3NwbGl0WzBdCiAgICAgICAgIyByZXN0 + IG9mIHRoZSBpcC1zIGFyZSBhZGRlZCB0byB0aGUgJ3N0YW5kYnlfbWdycycgbGlzdAogICAgICAg + IHN0YW5kYnlfbWdycy5leHRlbmQobW9uaXRvcmluZ19lbmRwb2ludF9pcF9saXN0X3NwbGl0WzE6 + XSkKICAgICAgICBmYWlsZWRfaXAgPSBtb25pdG9yaW5nX2VuZHBvaW50X2lwCgogICAgICAgIG1v + bml0b3JpbmdfZW5kcG9pbnQgPSAiOiIuam9pbigKICAgICAgICAgICAgW21vbml0b3JpbmdfZW5k + cG9pbnRfaXAsIG1vbml0b3JpbmdfZW5kcG9pbnRfcG9ydF0KICAgICAgICApCiAgICAgICAgaXBf + dHlwZSA9IHNlbGYuX2ludmFsaWRfZW5kcG9pbnQobW9uaXRvcmluZ19lbmRwb2ludCkKICAgICAg + ICB0cnk6CiAgICAgICAgICAgIG1vbml0b3JpbmdfZW5kcG9pbnRfaXAgPSBzZWxmLl9jb252ZXJ0 + X2hvc3RuYW1lX3RvX2lwKAogICAgICAgICAgICAgICAgbW9uaXRvcmluZ19lbmRwb2ludF9pcCwg + bW9uaXRvcmluZ19lbmRwb2ludF9wb3J0LCBpcF90eXBlCiAgICAgICAgICAgICkKICAgICAgICAg + ICAgIyBjb2xsZWN0IGFsbCB0aGUgJ3N0YW5kLWJ5JyBtZ3IgaXBzCiAgICAgICAgICAgIG1ncl9p + cHMgPSBbXQogICAgICAgICAgICBmb3IgZWFjaF9zdGFuZGJ5X21nciBpbiBzdGFuZGJ5X21ncnM6 + CiAgICAgICAgICAgICAgICBmYWlsZWRfaXAgPSBlYWNoX3N0YW5kYnlfbWdyCiAgICAgICAgICAg + ICAgICBtZ3JfaXBzLmFwcGVuZCgKICAgICAgICAgICAgICAgICAgICBzZWxmLl9jb252ZXJ0X2hv + c3RuYW1lX3RvX2lwKAogICAgICAgICAgICAgICAgICAgICAgICBlYWNoX3N0YW5kYnlfbWdyLCBt + b25pdG9yaW5nX2VuZHBvaW50X3BvcnQsIGlwX3R5cGUKICAgICAgICAgICAgICAgICAgICApCiAg + ICAgICAgICAgICAgICApCiAgICAgICAgZXhjZXB0OgogICAgICAgICAgICByYWlzZSBFeGVjdXRp + b25GYWlsdXJlRXhjZXB0aW9uKAogICAgICAgICAgICAgICAgZiJDb252ZXJzaW9uIG9mIGhvc3Q6 + IHtmYWlsZWRfaXB9IHRvIElQIGZhaWxlZC4gIgogICAgICAgICAgICAgICAgIlBsZWFzZSBlbnRl + ciB0aGUgSVAgYWRkcmVzc2VzIG9mIGFsbCB0aGUgY2VwaC1tZ3JzIHdpdGggdGhlICctLW1vbml0 + b3JpbmctZW5kcG9pbnQnIGZsYWciCiAgICAgICAgICAgICkKCiAgICAgICAgXywgXywgZXJyID0g + c2VsZi5lbmRwb2ludF9kaWFsKG1vbml0b3JpbmdfZW5kcG9pbnQsIGlwX3R5cGUpCiAgICAgICAg + aWYgZXJyID09ICItMSI6CiAgICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1cmVFeGNlcHRp + b24oZXJyKQogICAgICAgICMgYWRkIHRoZSB2YWxpZGF0ZWQgYWN0aXZlIG1nciBJUCBpbnRvIHRo + ZSBmaXJzdCBpbmRleAogICAgICAgIG1ncl9pcHMuaW5zZXJ0KDAsIG1vbml0b3JpbmdfZW5kcG9p + bnRfaXApCiAgICAgICAgYWxsX21ncl9pcHNfc3RyID0gIiwiLmpvaW4obWdyX2lwcykKICAgICAg + ICByZXR1cm4gYWxsX21ncl9pcHNfc3RyLCBtb25pdG9yaW5nX2VuZHBvaW50X3BvcnQKCiAgICBk + ZWYgY2hlY2tfdXNlcl9leGlzdChzZWxmLCB1c2VyKToKICAgICAgICBjbWRfanNvbiA9IHsicHJl + Zml4IjogImF1dGggZ2V0IiwgImVudGl0eSI6IGYie3VzZXJ9IiwgImZvcm1hdCI6ICJqc29uIn0K + ICAgICAgICByZXRfdmFsLCBqc29uX291dCwgXyA9IHNlbGYuX2NvbW1vbl9jbWRfanNvbl9nZW4o + Y21kX2pzb24pCiAgICAgICAgaWYgcmV0X3ZhbCAhPSAwIG9yIGxlbihqc29uX291dCkgPT0gMDoK + ICAgICAgICAgICAgcmV0dXJuICIiCiAgICAgICAgcmV0dXJuIHN0cihqc29uX291dFswXVsia2V5 + Il0pCgogICAgZGVmIGdldF9jZXBoZnNfcHJvdmlzaW9uZXJfY2Fwc19hbmRfZW50aXR5KHNlbGYp + OgogICAgICAgIGVudGl0eSA9ICJjbGllbnQuY3NpLWNlcGhmcy1wcm92aXNpb25lciIKICAgICAg + ICBjYXBzID0gewogICAgICAgICAgICAibW9uIjogImFsbG93IHIsIGFsbG93IGNvbW1hbmQgJ29z + ZCBibG9ja2xpc3QnIiwKICAgICAgICAgICAgIm1nciI6ICJhbGxvdyBydyIsCiAgICAgICAgICAg + ICJvc2QiOiAiYWxsb3cgcncgdGFnIGNlcGhmcyBtZXRhZGF0YT0qIiwKICAgICAgICAgICAgIm1k + cyI6ICJhbGxvdyAqIiwKICAgICAgICB9CiAgICAgICAgaWYgc2VsZi5fYXJnX3BhcnNlci5yZXN0 + cmljdGVkX2F1dGhfcGVybWlzc2lvbjoKICAgICAgICAgICAgazhzX2NsdXN0ZXJfbmFtZSA9IHNl + bGYuX2FyZ19wYXJzZXIuazhzX2NsdXN0ZXJfbmFtZQogICAgICAgICAgICBpZiBrOHNfY2x1c3Rl + cl9uYW1lID09ICIiOgogICAgICAgICAgICAgICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2Vw + dGlvbigKICAgICAgICAgICAgICAgICAgICAiazhzX2NsdXN0ZXJfbmFtZSBub3QgZm91bmQsIHBs + ZWFzZSBzZXQgdGhlICctLWs4cy1jbHVzdGVyLW5hbWUnIGZsYWciCiAgICAgICAgICAgICAgICAp + CiAgICAgICAgICAgIGNlcGhmc19maWxlc3lzdGVtID0gc2VsZi5fYXJnX3BhcnNlci5jZXBoZnNf + ZmlsZXN5c3RlbV9uYW1lCiAgICAgICAgICAgIGlmIGNlcGhmc19maWxlc3lzdGVtID09ICIiOgog + ICAgICAgICAgICAgICAgZW50aXR5ID0gZiJ7ZW50aXR5fS17azhzX2NsdXN0ZXJfbmFtZX0iCiAg + ICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICBlbnRpdHkgPSBmIntlbnRpdHl9LXtrOHNf + Y2x1c3Rlcl9uYW1lfS17Y2VwaGZzX2ZpbGVzeXN0ZW19IgogICAgICAgICAgICAgICAgY2Fwc1si + b3NkIl0gPSBmImFsbG93IHJ3IHRhZyBjZXBoZnMgbWV0YWRhdGE9e2NlcGhmc19maWxlc3lzdGVt + fSIKCiAgICAgICAgcmV0dXJuIGNhcHMsIGVudGl0eQoKICAgIGRlZiBnZXRfY2VwaGZzX25vZGVf + Y2Fwc19hbmRfZW50aXR5KHNlbGYpOgogICAgICAgIGVudGl0eSA9ICJjbGllbnQuY3NpLWNlcGhm + cy1ub2RlIgogICAgICAgIGNhcHMgPSB7CiAgICAgICAgICAgICJtb24iOiAiYWxsb3cgciwgYWxs + b3cgY29tbWFuZCAnb3NkIGJsb2NrbGlzdCciLAogICAgICAgICAgICAibWdyIjogImFsbG93IHJ3 + IiwKICAgICAgICAgICAgIm9zZCI6ICJhbGxvdyBydyB0YWcgY2VwaGZzICo9KiIsCiAgICAgICAg + ICAgICJtZHMiOiAiYWxsb3cgcnciLAogICAgICAgIH0KICAgICAgICBpZiBzZWxmLl9hcmdfcGFy + c2VyLnJlc3RyaWN0ZWRfYXV0aF9wZXJtaXNzaW9uOgogICAgICAgICAgICBrOHNfY2x1c3Rlcl9u + YW1lID0gc2VsZi5fYXJnX3BhcnNlci5rOHNfY2x1c3Rlcl9uYW1lCiAgICAgICAgICAgIGlmIGs4 + c19jbHVzdGVyX25hbWUgPT0gIiI6CiAgICAgICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWls + dXJlRXhjZXB0aW9uKAogICAgICAgICAgICAgICAgICAgICJrOHNfY2x1c3Rlcl9uYW1lIG5vdCBm + b3VuZCwgcGxlYXNlIHNldCB0aGUgJy0tazhzLWNsdXN0ZXItbmFtZScgZmxhZyIKICAgICAgICAg + ICAgICAgICkKICAgICAgICAgICAgY2VwaGZzX2ZpbGVzeXN0ZW0gPSBzZWxmLl9hcmdfcGFyc2Vy + LmNlcGhmc19maWxlc3lzdGVtX25hbWUKICAgICAgICAgICAgaWYgY2VwaGZzX2ZpbGVzeXN0ZW0g + PT0gIiI6CiAgICAgICAgICAgICAgICBlbnRpdHkgPSBmIntlbnRpdHl9LXtrOHNfY2x1c3Rlcl9u + YW1lfSIKICAgICAgICAgICAgZWxzZToKICAgICAgICAgICAgICAgIGVudGl0eSA9IGYie2VudGl0 + eX0te2s4c19jbHVzdGVyX25hbWV9LXtjZXBoZnNfZmlsZXN5c3RlbX0iCiAgICAgICAgICAgICAg + ICBjYXBzWyJvc2QiXSA9IGYiYWxsb3cgcncgdGFnIGNlcGhmcyAqPXtjZXBoZnNfZmlsZXN5c3Rl + bX0iCgogICAgICAgIHJldHVybiBjYXBzLCBlbnRpdHkKCiAgICBkZWYgZ2V0X2VudGl0eSgKICAg + ICAgICBzZWxmLAogICAgICAgIGVudGl0eSwKICAgICAgICByYmRfcG9vbF9uYW1lLAogICAgICAg + IGFsaWFzX3JiZF9wb29sX25hbWUsCiAgICAgICAgazhzX2NsdXN0ZXJfbmFtZSwKICAgICAgICBy + YWRvc19uYW1lc3BhY2UsCiAgICApOgogICAgICAgIGlmICgKICAgICAgICAgICAgcmJkX3Bvb2xf + bmFtZS5jb3VudCgiLiIpICE9IDAKICAgICAgICAgICAgb3IgcmJkX3Bvb2xfbmFtZS5jb3VudCgi + XyIpICE9IDAKICAgICAgICAgICAgb3IgYWxpYXNfcmJkX3Bvb2xfbmFtZSAhPSAiIgogICAgICAg + ICAgICAjIGNoZWNraW5nIGFsaWFzX3JiZF9wb29sX25hbWUgaXMgbm90IGVtcHR5IGFzIHRoZXJl + IG1heWJlIGEgc3BlY2lhbCBjaGFyYWN0ZXIgdXNlZCBvdGhlciB0aGFuIC4gb3IgXwogICAgICAg + ICk6CiAgICAgICAgICAgIGlmIGFsaWFzX3JiZF9wb29sX25hbWUgPT0gIiI6CiAgICAgICAgICAg ICAgICByYWlzZSBFeGVjdXRpb25GYWlsdXJlRXhjZXB0aW9uKAogICAgICAgICAgICAgICAgICAg - ICJtYW5kYXRvcnkgZmxhZyBub3QgZm91bmQsIHBsZWFzZSBzZXQgdGhlICctLXJiZC1kYXRhLXBv - b2wtbmFtZScgZmxhZyIKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgaWYgazhzX2NsdXN0 - ZXJfbmFtZSA9PSAiIjoKICAgICAgICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1cmVFeGNl - cHRpb24oCiAgICAgICAgICAgICAgICAgICAgIm1hbmRhdG9yeSBmbGFnIG5vdCBmb3VuZCwgcGxl - YXNlIHNldCB0aGUgJy0tazhzLWNsdXN0ZXItbmFtZScgZmxhZyIKICAgICAgICAgICAgICAgICkK - ICAgICAgICAgICAgZW50aXR5ID0gc2VsZi5nZXRfZW50aXR5KAogICAgICAgICAgICAgICAgZW50 - aXR5LAogICAgICAgICAgICAgICAgcmJkX3Bvb2xfbmFtZSwKICAgICAgICAgICAgICAgIGFsaWFz - X3JiZF9wb29sX25hbWUsCiAgICAgICAgICAgICAgICBrOHNfY2x1c3Rlcl9uYW1lLAogICAgICAg - ICAgICAgICAgcmFkb3NfbmFtZXNwYWNlLAogICAgICAgICAgICApCiAgICAgICAgICAgIGlmIHJh - ZG9zX25hbWVzcGFjZSAhPSAiIjoKICAgICAgICAgICAgICAgIGNhcHNbIm9zZCJdID0gKAogICAg - ICAgICAgICAgICAgICAgIGYicHJvZmlsZSByYmQgcG9vbD17cmJkX3Bvb2xfbmFtZX0gbmFtZXNw - YWNlPXtyYWRvc19uYW1lc3BhY2V9IgogICAgICAgICAgICAgICAgKQogICAgICAgICAgICBlbHNl - OgogICAgICAgICAgICAgICAgY2Fwc1sib3NkIl0gPSBmInByb2ZpbGUgcmJkIHBvb2w9e3JiZF9w - b29sX25hbWV9IgoKICAgICAgICByZXR1cm4gY2FwcywgZW50aXR5CgogICAgZGVmIGdldF9kZWZh - dWx0VXNlcl9jYXBzX2FuZF9lbnRpdHkoc2VsZik6CiAgICAgICAgZW50aXR5ID0gc2VsZi5ydW5f - YXNfdXNlcgogICAgICAgIGNhcHMgPSB7CiAgICAgICAgICAgICJtb24iOiAiYWxsb3cgciwgYWxs - b3cgY29tbWFuZCBxdW9ydW1fc3RhdHVzLCBhbGxvdyBjb21tYW5kIHZlcnNpb24iLAogICAgICAg - ICAgICAibWdyIjogImFsbG93IGNvbW1hbmQgY29uZmlnIiwKICAgICAgICAgICAgIm9zZCI6IGYi - cHJvZmlsZSByYmQtcmVhZC1vbmx5LCBhbGxvdyByd3ggcG9vbD17c2VsZi5fYXJnX3BhcnNlci5y - Z3dfcG9vbF9wcmVmaXh9LnJndy5tZXRhLCBhbGxvdyByIHBvb2w9LnJndy5yb290LCBhbGxvdyBy - dyBwb29sPXtzZWxmLl9hcmdfcGFyc2VyLnJnd19wb29sX3ByZWZpeH0ucmd3LmNvbnRyb2wsIGFs - bG93IHJ4IHBvb2w9e3NlbGYuX2FyZ19wYXJzZXIucmd3X3Bvb2xfcHJlZml4fS5yZ3cubG9nLCBh - bGxvdyB4IHBvb2w9e3NlbGYuX2FyZ19wYXJzZXIucmd3X3Bvb2xfcHJlZml4fS5yZ3cuYnVja2V0 - cy5pbmRleCIsCiAgICAgICAgICAgICJtZHMiOiAiYWxsb3cgKiIsCiAgICAgICAgfQoKICAgICAg - ICByZXR1cm4gY2FwcywgZW50aXR5CgogICAgZGVmIGdldF9jYXBzX2FuZF9lbnRpdHkoc2VsZiwg - dXNlcl9uYW1lKToKICAgICAgICBpZiAiY2xpZW50LmNzaS1jZXBoZnMtcHJvdmlzaW9uZXIiIGlu - IHVzZXJfbmFtZToKICAgICAgICAgICAgaWYgImNsaWVudC5jc2ktY2VwaGZzLXByb3Zpc2lvbmVy - IiAhPSB1c2VyX25hbWU6CiAgICAgICAgICAgICAgICBzZWxmLl9hcmdfcGFyc2VyLnJlc3RyaWN0 - ZWRfYXV0aF9wZXJtaXNzaW9uID0gVHJ1ZQogICAgICAgICAgICByZXR1cm4gc2VsZi5nZXRfY2Vw - aGZzX3Byb3Zpc2lvbmVyX2NhcHNfYW5kX2VudGl0eSgpCiAgICAgICAgaWYgImNsaWVudC5jc2kt - Y2VwaGZzLW5vZGUiIGluIHVzZXJfbmFtZToKICAgICAgICAgICAgaWYgImNsaWVudC5jc2ktY2Vw - aGZzLW5vZGUiICE9IHVzZXJfbmFtZToKICAgICAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIu - cmVzdHJpY3RlZF9hdXRoX3Blcm1pc3Npb24gPSBUcnVlCiAgICAgICAgICAgIHJldHVybiBzZWxm - LmdldF9jZXBoZnNfbm9kZV9jYXBzX2FuZF9lbnRpdHkoKQogICAgICAgIGlmICJjbGllbnQuY3Np - LXJiZC1wcm92aXNpb25lciIgaW4gdXNlcl9uYW1lOgogICAgICAgICAgICBpZiAiY2xpZW50LmNz - aS1yYmQtcHJvdmlzaW9uZXIiICE9IHVzZXJfbmFtZToKICAgICAgICAgICAgICAgIHNlbGYuX2Fy - Z19wYXJzZXIucmVzdHJpY3RlZF9hdXRoX3Blcm1pc3Npb24gPSBUcnVlCiAgICAgICAgICAgIHJl - dHVybiBzZWxmLmdldF9yYmRfcHJvdmlzaW9uZXJfY2Fwc19hbmRfZW50aXR5KCkKICAgICAgICBp - ZiAiY2xpZW50LmNzaS1yYmQtbm9kZSIgaW4gdXNlcl9uYW1lOgogICAgICAgICAgICBpZiAiY2xp - ZW50LmNzaS1yYmQtbm9kZSIgIT0gdXNlcl9uYW1lOgogICAgICAgICAgICAgICAgc2VsZi5fYXJn - X3BhcnNlci5yZXN0cmljdGVkX2F1dGhfcGVybWlzc2lvbiA9IFRydWUKICAgICAgICAgICAgcmV0 - dXJuIHNlbGYuZ2V0X3JiZF9ub2RlX2NhcHNfYW5kX2VudGl0eSgpCiAgICAgICAgaWYgImNsaWVu - dC5oZWFsdGhjaGVja2VyIiBpbiB1c2VyX25hbWU6CiAgICAgICAgICAgIGlmICJjbGllbnQuaGVh - bHRoY2hlY2tlciIgIT0gdXNlcl9uYW1lOgogICAgICAgICAgICAgICAgc2VsZi5fYXJnX3BhcnNl - ci5yZXN0cmljdGVkX2F1dGhfcGVybWlzc2lvbiA9IFRydWUKICAgICAgICAgICAgcmV0dXJuIHNl - bGYuZ2V0X2RlZmF1bHRVc2VyX2NhcHNfYW5kX2VudGl0eSgpCgogICAgICAgIHJhaXNlIEV4ZWN1 - dGlvbkZhaWx1cmVFeGNlcHRpb24oCiAgICAgICAgICAgIGYibm8gdXNlciBmb3VuZCB3aXRoIHVz - ZXJfbmFtZToge3VzZXJfbmFtZX0sICIKICAgICAgICAgICAgImdldF9jYXBzX2FuZF9lbnRpdHkg - Y29tbWFuZCBmYWlsZWQuXG4iCiAgICAgICAgKQoKICAgIGRlZiBjcmVhdGVfY2VwaENTSUtleXJp - bmdfdXNlcihzZWxmLCB1c2VyKToKICAgICAgICAiIiIKICAgICAgICBjb21tYW5kOiBjZXBoIGF1 - dGggZ2V0LW9yLWNyZWF0ZSBjbGllbnQuY3NpLWNlcGhmcy1wcm92aXNpb25lciBtb24gJ2FsbG93 - IHInIG1nciAnYWxsb3cgcncnIG9zZCAnYWxsb3cgcncgdGFnIGNlcGhmcyBtZXRhZGF0YT0qJwog - ICAgICAgICIiIgogICAgICAgIGNhcHMsIGVudGl0eSA9IHNlbGYuZ2V0X2NhcHNfYW5kX2VudGl0 - eSh1c2VyKQogICAgICAgIGNtZF9qc29uID0gewogICAgICAgICAgICAicHJlZml4IjogImF1dGgg - Z2V0LW9yLWNyZWF0ZSIsCiAgICAgICAgICAgICJlbnRpdHkiOiBlbnRpdHksCiAgICAgICAgICAg - ICJjYXBzIjogW2NhcCBmb3IgY2FwX2xpc3QgaW4gbGlzdChjYXBzLml0ZW1zKCkpIGZvciBjYXAg - aW4gY2FwX2xpc3RdLAogICAgICAgICAgICAiZm9ybWF0IjogImpzb24iLAogICAgICAgIH0KCiAg - ICAgICAgaWYgc2VsZi5fYXJnX3BhcnNlci5kcnlfcnVuOgogICAgICAgICAgICByZXR1cm4gKAog - ICAgICAgICAgICAgICAgc2VsZi5kcnlfcnVuKAogICAgICAgICAgICAgICAgICAgICJjZXBoICIK - ICAgICAgICAgICAgICAgICAgICArIGNtZF9qc29uWyJwcmVmaXgiXQogICAgICAgICAgICAgICAg - ICAgICsgIiAiCiAgICAgICAgICAgICAgICAgICAgKyBjbWRfanNvblsiZW50aXR5Il0KICAgICAg - ICAgICAgICAgICAgICArICIgIgogICAgICAgICAgICAgICAgICAgICsgIiAiLmpvaW4oY21kX2pz - b25bImNhcHMiXSkKICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAiIiwKICAgICAg - ICAgICAgKQogICAgICAgICMgY2hlY2sgaWYgdXNlciBhbHJlYWR5IGV4aXN0CiAgICAgICAgdXNl - cl9rZXkgPSBzZWxmLmNoZWNrX3VzZXJfZXhpc3QoZW50aXR5KQogICAgICAgIGlmIHVzZXJfa2V5 - ICE9ICIiOgogICAgICAgICAgICByZXR1cm4gdXNlcl9rZXksIGYie2VudGl0eS5zcGxpdCgnLics - IDEpWzFdfSIKICAgICAgICAgICAgIyBlbnRpdHkuc3BsaXQoJy4nLDEpWzFdIHRvIHJlbmFtZSBl - bnRpdHkoY2xpZW50LmNzaS1yYmQtbm9kZSkgYXMgY3NpLXJiZC1ub2RlCgogICAgICAgIHJldF92 - YWwsIGpzb25fb3V0LCBlcnJfbXNnID0gc2VsZi5fY29tbW9uX2NtZF9qc29uX2dlbihjbWRfanNv - bikKICAgICAgICAjIGlmIHRoZXJlIGlzIGFuIHVuc3VjY2Vzc2Z1bCBhdHRlbXB0LAogICAgICAg - IGlmIHJldF92YWwgIT0gMCBvciBsZW4oanNvbl9vdXQpID09IDA6CiAgICAgICAgICAgIHJhaXNl - IEV4ZWN1dGlvbkZhaWx1cmVFeGNlcHRpb24oCiAgICAgICAgICAgICAgICBmIidhdXRoIGdldC1v - ci1jcmVhdGUge3VzZXJ9JyBjb21tYW5kIGZhaWxlZC5cbiIKICAgICAgICAgICAgICAgIGYiRXJy - b3I6IHtlcnJfbXNnIGlmIHJldF92YWwgIT0gMCBlbHNlIHNlbGYuRU1QVFlfT1VUUFVUX0xJU1R9 - IgogICAgICAgICAgICApCiAgICAgICAgcmV0dXJuIHN0cihqc29uX291dFswXVsia2V5Il0pLCBm - IntlbnRpdHkuc3BsaXQoJy4nLCAxKVsxXX0iCiAgICAgICAgIyBlbnRpdHkuc3BsaXQoJy4nLDEp - WzFdIHRvIHJlbmFtZSBlbnRpdHkoY2xpZW50LmNzaS1yYmQtbm9kZSkgYXMgY3NpLXJiZC1ub2Rl - CgogICAgZGVmIGdldF9jZXBoZnNfZGF0YV9wb29sX2RldGFpbHMoc2VsZik6CiAgICAgICAgY21k - X2pzb24gPSB7InByZWZpeCI6ICJmcyBscyIsICJmb3JtYXQiOiAianNvbiJ9CiAgICAgICAgaWYg - c2VsZi5fYXJnX3BhcnNlci5kcnlfcnVuOgogICAgICAgICAgICByZXR1cm4gc2VsZi5kcnlfcnVu - KCJjZXBoICIgKyBjbWRfanNvblsicHJlZml4Il0pCiAgICAgICAgcmV0X3ZhbCwganNvbl9vdXQs - IGVycl9tc2cgPSBzZWxmLl9jb21tb25fY21kX2pzb25fZ2VuKGNtZF9qc29uKQogICAgICAgICMg - aWYgdGhlcmUgaXMgYW4gdW5zdWNjZXNzZnVsIGF0dGVtcHQsIHJlcG9ydCBhbiBlcnJvcgogICAg - ICAgIGlmIHJldF92YWwgIT0gMDoKICAgICAgICAgICAgIyBpZiBmcyBhbmQgZGF0YV9wb29sIGFy - Z3VtZW50cyBhcmUgbm90IHNldCwgc2lsZW50bHkgcmV0dXJuCiAgICAgICAgICAgIGlmICgKICAg - ICAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIuY2VwaGZzX2ZpbGVzeXN0ZW1fbmFtZSA9PSAi - IgogICAgICAgICAgICAgICAgYW5kIHNlbGYuX2FyZ19wYXJzZXIuY2VwaGZzX2RhdGFfcG9vbF9u - YW1lID09ICIiCiAgICAgICAgICAgICk6CiAgICAgICAgICAgICAgICByZXR1cm4KICAgICAgICAg - ICAgIyBpZiB1c2VyIGhhcyBwcm92aWRlZCBhbnkgb2YgdGhlCiAgICAgICAgICAgICMgJy0tY2Vw - aGZzLWZpbGVzeXN0ZW0tbmFtZScgb3IgJy0tY2VwaGZzLWRhdGEtcG9vbC1uYW1lJyBhcmd1bWVu - dHMsCiAgICAgICAgICAgICMgcmFpc2UgYW4gZXhjZXB0aW9uIGFzIHdlIGFyZSB1bmFibGUgdG8g - dmVyaWZ5IHRoZSBhcmdzCiAgICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1cmVFeGNlcHRp - b24oCiAgICAgICAgICAgICAgICBmIidmcyBscycgY2VwaCBjYWxsIGZhaWxlZCB3aXRoIGVycm9y - OiB7ZXJyX21zZ30iCiAgICAgICAgICAgICkKCiAgICAgICAgbWF0Y2hpbmdfanNvbl9vdXQgPSB7 - fQogICAgICAgICMgaWYgJy0tY2VwaGZzLWZpbGVzeXN0ZW0tbmFtZScgYXJndW1lbnQgaXMgcHJv - dmlkZWQsCiAgICAgICAgIyBjaGVjayB3aGV0aGVyIHRoZSBwcm92aWRlZCBmaWxlc3lzdGVtLW5h - bWUgZXhpc3RzIG9yIG5vdAogICAgICAgIGlmIHNlbGYuX2FyZ19wYXJzZXIuY2VwaGZzX2ZpbGVz - eXN0ZW1fbmFtZToKICAgICAgICAgICAgIyBnZXQgdGhlIG1hdGNoaW5nIGxpc3QKICAgICAgICAg - ICAgbWF0Y2hpbmdfanNvbl9vdXRfbGlzdCA9IFsKICAgICAgICAgICAgICAgIG1hdGNoZWQKICAg - ICAgICAgICAgICAgIGZvciBtYXRjaGVkIGluIGpzb25fb3V0CiAgICAgICAgICAgICAgICBpZiBz - dHIobWF0Y2hlZFsibmFtZSJdKSA9PSBzZWxmLl9hcmdfcGFyc2VyLmNlcGhmc19maWxlc3lzdGVt - X25hbWUKICAgICAgICAgICAgXQogICAgICAgICAgICAjIHVuYWJsZSB0byBmaW5kIGEgbWF0Y2hp - bmcgZnMtbmFtZSwgcmFpc2UgYW4gZXJyb3IKICAgICAgICAgICAgaWYgbGVuKG1hdGNoaW5nX2pz - b25fb3V0X2xpc3QpID09IDA6CiAgICAgICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWlsdXJl - RXhjZXB0aW9uKAogICAgICAgICAgICAgICAgICAgIGYiRmlsZXN5c3RlbSBwcm92aWRlZCwgJ3tz - ZWxmLl9hcmdfcGFyc2VyLmNlcGhmc19maWxlc3lzdGVtX25hbWV9JywgIgogICAgICAgICAgICAg - ICAgICAgIGYiaXMgbm90IGZvdW5kIGluIHRoZSBmcy1saXN0OiB7W3N0cih4WyduYW1lJ10pIGZv - ciB4IGluIGpzb25fb3V0XX0iCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgIG1hdGNoaW5n - X2pzb25fb3V0ID0gbWF0Y2hpbmdfanNvbl9vdXRfbGlzdFswXQogICAgICAgICMgaWYgY2VwaGZz - IGZpbGVzeXN0ZW0gbmFtZSBpcyBub3QgcHJvdmlkZWQsCiAgICAgICAgIyB0cnkgdG8gZ2V0IGEg - ZGVmYXVsdCBmcyBuYW1lIGJ5IGRvaW5nIHRoZSBmb2xsb3dpbmcKICAgICAgICBlbHNlOgogICAg - ICAgICAgICAjIGEuIGNoZWNrIGlmIHRoZXJlIGlzIG9ubHkgb25lIGZpbGVzeXN0ZW0gaXMgcHJl - c2VudAogICAgICAgICAgICBpZiBsZW4oanNvbl9vdXQpID09IDE6CiAgICAgICAgICAgICAgICBt - YXRjaGluZ19qc29uX291dCA9IGpzb25fb3V0WzBdCiAgICAgICAgICAgICMgYi4gb3IgZWxzZSwg - Y2hlY2sgaWYgZGF0YV9wb29sIG5hbWUgaXMgcHJvdmlkZWQKICAgICAgICAgICAgZWxpZiBzZWxm - Ll9hcmdfcGFyc2VyLmNlcGhmc19kYXRhX3Bvb2xfbmFtZToKICAgICAgICAgICAgICAgICMgYW5k - IGlmIHByZXNlbnQsIGNoZWNrIHdoZXRoZXIgdGhlcmUgZXhpc3RzIGEgZnMgd2hpY2ggaGFzIHRo - ZSBkYXRhX3Bvb2wKICAgICAgICAgICAgICAgIGZvciBlYWNoSiBpbiBqc29uX291dDoKICAgICAg - ICAgICAgICAgICAgICBpZiBzZWxmLl9hcmdfcGFyc2VyLmNlcGhmc19kYXRhX3Bvb2xfbmFtZSBp - biBlYWNoSlsiZGF0YV9wb29scyJdOgogICAgICAgICAgICAgICAgICAgICAgICBtYXRjaGluZ19q - c29uX291dCA9IGVhY2hKCiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrCiAgICAgICAgICAg - ICAgICAjIGlmIHRoZXJlIGlzIG5vIG1hdGNoaW5nIGZzIGV4aXN0cywgdGhhdCBtZWFucyBwcm92 - aWRlZCBkYXRhX3Bvb2wgbmFtZSBpcyBpbnZhbGlkCiAgICAgICAgICAgICAgICBpZiBub3QgbWF0 - Y2hpbmdfanNvbl9vdXQ6CiAgICAgICAgICAgICAgICAgICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVy - ZUV4Y2VwdGlvbigKICAgICAgICAgICAgICAgICAgICAgICAgZiJQcm92aWRlZCBkYXRhX3Bvb2wg - bmFtZSwge3NlbGYuX2FyZ19wYXJzZXIuY2VwaGZzX2RhdGFfcG9vbF9uYW1lfSwiCiAgICAgICAg - ICAgICAgICAgICAgICAgICIgZG9lcyBub3QgZXhpc3RzIgogICAgICAgICAgICAgICAgICAgICkK - ICAgICAgICAgICAgIyBjLiBpZiBub3RoaW5nIGlzIHNldCBhbmQgY291bGRuJ3QgZmluZCBhIGRl - ZmF1bHQsCiAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICAjIGp1c3QgcmV0dXJuIHNp - bGVudGx5CiAgICAgICAgICAgICAgICByZXR1cm4KCiAgICAgICAgaWYgbWF0Y2hpbmdfanNvbl9v - dXQ6CiAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIuY2VwaGZzX2ZpbGVzeXN0ZW1fbmFtZSA9 - IHN0cihtYXRjaGluZ19qc29uX291dFsibmFtZSJdKQogICAgICAgICAgICBzZWxmLl9hcmdfcGFy - c2VyLmNlcGhmc19tZXRhZGF0YV9wb29sX25hbWUgPSBzdHIoCiAgICAgICAgICAgICAgICBtYXRj - aGluZ19qc29uX291dFsibWV0YWRhdGFfcG9vbCJdCiAgICAgICAgICAgICkKCiAgICAgICAgaWYg - aXNpbnN0YW5jZShtYXRjaGluZ19qc29uX291dFsiZGF0YV9wb29scyJdLCBsaXN0KToKICAgICAg - ICAgICAgIyBpZiB0aGUgdXNlciBoYXMgYWxyZWFkeSBwcm92aWRlZCBkYXRhLXBvb2wtbmFtZSwK - ICAgICAgICAgICAgIyB0aHJvdWdoIC0tY2VwaGZzLWRhdGEtcG9vbC1uYW1lCiAgICAgICAgICAg - IGlmIHNlbGYuX2FyZ19wYXJzZXIuY2VwaGZzX2RhdGFfcG9vbF9uYW1lOgogICAgICAgICAgICAg - ICAgIyBpZiB0aGUgcHJvdmlkZWQgbmFtZSBpcyBub3QgbWF0Y2hpbmcgd2l0aCB0aGUgb25lIGlu - IHRoZSBsaXN0CiAgICAgICAgICAgICAgICBpZiAoCiAgICAgICAgICAgICAgICAgICAgc2VsZi5f - YXJnX3BhcnNlci5jZXBoZnNfZGF0YV9wb29sX25hbWUKICAgICAgICAgICAgICAgICAgICBub3Qg - aW4gbWF0Y2hpbmdfanNvbl9vdXRbImRhdGFfcG9vbHMiXQogICAgICAgICAgICAgICAgKToKICAg - ICAgICAgICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWlsdXJlRXhjZXB0aW9uKAogICAgICAg - ICAgICAgICAgICAgICAgICBmIlByb3ZpZGVkIGRhdGEtcG9vbC1uYW1lOiAne3NlbGYuX2FyZ19w - YXJzZXIuY2VwaGZzX2RhdGFfcG9vbF9uYW1lfScsICIKICAgICAgICAgICAgICAgICAgICAgICAg - ImRvZXNuJ3QgbWF0Y2ggZnJvbSB0aGUgZGF0YS1wb29scyBsaXN0OiAiCiAgICAgICAgICAgICAg - ICAgICAgICAgIGYie1tzdHIoeCkgZm9yIHggaW4gbWF0Y2hpbmdfanNvbl9vdXRbJ2RhdGFfcG9v - bHMnXV19IgogICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgIyBpZiBkYXRhX3Bvb2wg - bmFtZSBpcyBub3QgcHJvdmlkZWQsCiAgICAgICAgICAgICMgdGhlbiB0cnkgdG8gZmluZCBhIGRl - ZmF1bHQgZGF0YSBwb29sIG5hbWUKICAgICAgICAgICAgZWxzZToKICAgICAgICAgICAgICAgICMg - aWYgbm8gZGF0YV9wb29scyBleGlzdCwgc2lsZW50bHkgcmV0dXJuCiAgICAgICAgICAgICAgICBp - ZiBsZW4obWF0Y2hpbmdfanNvbl9vdXRbImRhdGFfcG9vbHMiXSkgPT0gMDoKICAgICAgICAgICAg - ICAgICAgICByZXR1cm4KICAgICAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIuY2VwaGZzX2Rh - dGFfcG9vbF9uYW1lID0gc3RyKAogICAgICAgICAgICAgICAgICAgIG1hdGNoaW5nX2pzb25fb3V0 - WyJkYXRhX3Bvb2xzIl1bMF0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgIyBpZiB0aGVy - ZSBhcmUgbW9yZSB0aGFuIG9uZSAnZGF0YV9wb29scycgZXhpc3QsCiAgICAgICAgICAgICMgdGhl - biB3YXJuIHRoZSB1c2VyIHRoYXQgd2UgYXJlIHVzaW5nIHRoZSBzZWxlY3RlZCBuYW1lCiAgICAg - ICAgICAgIGlmIGxlbihtYXRjaGluZ19qc29uX291dFsiZGF0YV9wb29scyJdKSA+IDE6CiAgICAg - ICAgICAgICAgICBwcmludCgKICAgICAgICAgICAgICAgICAgICAiV0FSTklORzogTXVsdGlwbGUg - ZGF0YSBwb29scyBkZXRlY3RlZDogIgogICAgICAgICAgICAgICAgICAgIGYie1tzdHIoeCkgZm9y - IHggaW4gbWF0Y2hpbmdfanNvbl9vdXRbJ2RhdGFfcG9vbHMnXV19XG4iCiAgICAgICAgICAgICAg - ICAgICAgZiJVc2luZyB0aGUgZGF0YS1wb29sOiAne3NlbGYuX2FyZ19wYXJzZXIuY2VwaGZzX2Rh - dGFfcG9vbF9uYW1lfSdcbiIKICAgICAgICAgICAgICAgICkKCiAgICBkZWYgY3JlYXRlX2NoZWNr - ZXJLZXkoc2VsZiwgdXNlcik6CiAgICAgICAgY2FwcywgZW50aXR5ID0gc2VsZi5nZXRfY2Fwc19h - bmRfZW50aXR5KHVzZXIpCiAgICAgICAgY21kX2pzb24gPSB7CiAgICAgICAgICAgICJwcmVmaXgi - OiAiYXV0aCBnZXQtb3ItY3JlYXRlIiwKICAgICAgICAgICAgImVudGl0eSI6IGVudGl0eSwKICAg - ICAgICAgICAgImNhcHMiOiBbY2FwIGZvciBjYXBfbGlzdCBpbiBsaXN0KGNhcHMuaXRlbXMoKSkg - Zm9yIGNhcCBpbiBjYXBfbGlzdF0sCiAgICAgICAgICAgICJmb3JtYXQiOiAianNvbiIsCiAgICAg - ICAgfQoKICAgICAgICBpZiBzZWxmLl9hcmdfcGFyc2VyLmRyeV9ydW46CiAgICAgICAgICAgIHJl - dHVybiBzZWxmLmRyeV9ydW4oCiAgICAgICAgICAgICAgICAiY2VwaCAiCiAgICAgICAgICAgICAg - ICArIGNtZF9qc29uWyJwcmVmaXgiXQogICAgICAgICAgICAgICAgKyAiICIKICAgICAgICAgICAg - ICAgICsgY21kX2pzb25bImVudGl0eSJdCiAgICAgICAgICAgICAgICArICIgIgogICAgICAgICAg - ICAgICAgKyAiICIuam9pbihjbWRfanNvblsiY2FwcyJdKQogICAgICAgICAgICApCiAgICAgICAg - IyBjaGVjayBpZiB1c2VyIGFscmVhZHkgZXhpc3QKICAgICAgICB1c2VyX2tleSA9IHNlbGYuY2hl - Y2tfdXNlcl9leGlzdChlbnRpdHkpCiAgICAgICAgaWYgdXNlcl9rZXkgIT0gIiI6CiAgICAgICAg - ICAgIHJldHVybiB1c2VyX2tleQoKICAgICAgICByZXRfdmFsLCBqc29uX291dCwgZXJyX21zZyA9 - IHNlbGYuX2NvbW1vbl9jbWRfanNvbl9nZW4oY21kX2pzb24pCiAgICAgICAgIyBpZiB0aGVyZSBp - cyBhbiB1bnN1Y2Nlc3NmdWwgYXR0ZW1wdCwKICAgICAgICBpZiByZXRfdmFsICE9IDAgb3IgbGVu - KGpzb25fb3V0KSA9PSAwOgogICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWlsdXJlRXhjZXB0 - aW9uKAogICAgICAgICAgICAgICAgZiInYXV0aCBnZXQtb3ItY3JlYXRlIHtzZWxmLnJ1bl9hc191 - c2VyfScgY29tbWFuZCBmYWlsZWRcbiIKICAgICAgICAgICAgICAgIGYiRXJyb3I6IHtlcnJfbXNn - IGlmIHJldF92YWwgIT0gMCBlbHNlIHNlbGYuRU1QVFlfT1VUUFVUX0xJU1R9IgogICAgICAgICAg - ICApCiAgICAgICAgcmV0dXJuIHN0cihqc29uX291dFswXVsia2V5Il0pCgogICAgZGVmIGdldF9j - ZXBoX2Rhc2hib2FyZF9saW5rKHNlbGYpOgogICAgICAgIGNtZF9qc29uID0geyJwcmVmaXgiOiAi - bWdyIHNlcnZpY2VzIiwgImZvcm1hdCI6ICJqc29uIn0KICAgICAgICBpZiBzZWxmLl9hcmdfcGFy - c2VyLmRyeV9ydW46CiAgICAgICAgICAgIHJldHVybiBzZWxmLmRyeV9ydW4oImNlcGggIiArIGNt - ZF9qc29uWyJwcmVmaXgiXSkKICAgICAgICByZXRfdmFsLCBqc29uX291dCwgXyA9IHNlbGYuX2Nv + ICJwbGVhc2Ugc2V0IHRoZSAnLS1hbGlhcy1yYmQtZGF0YS1wb29sLW5hbWUnIGZsYWcgYXMgdGhl + IHJiZCBkYXRhIHBvb2wgbmFtZSBjb250YWlucyAnLicgb3IgJ18nIgogICAgICAgICAgICAgICAg + KQogICAgICAgICAgICBpZiAoCiAgICAgICAgICAgICAgICBhbGlhc19yYmRfcG9vbF9uYW1lLmNv + dW50KCIuIikgIT0gMAogICAgICAgICAgICAgICAgb3IgYWxpYXNfcmJkX3Bvb2xfbmFtZS5jb3Vu + dCgiXyIpICE9IDAKICAgICAgICAgICAgKToKICAgICAgICAgICAgICAgIHJhaXNlIEV4ZWN1dGlv + bkZhaWx1cmVFeGNlcHRpb24oCiAgICAgICAgICAgICAgICAgICAgIictLWFsaWFzLXJiZC1kYXRh + LXBvb2wtbmFtZScgZmxhZyB2YWx1ZSBzaG91bGQgbm90IGNvbnRhaW4gJy4nIG9yICdfJyIKICAg + ICAgICAgICAgICAgICkKICAgICAgICAgICAgZW50aXR5ID0gZiJ7ZW50aXR5fS17azhzX2NsdXN0 + ZXJfbmFtZX0te2FsaWFzX3JiZF9wb29sX25hbWV9IgogICAgICAgIGVsc2U6CiAgICAgICAgICAg + IGVudGl0eSA9IGYie2VudGl0eX0te2s4c19jbHVzdGVyX25hbWV9LXtyYmRfcG9vbF9uYW1lfSIK + CiAgICAgICAgaWYgcmFkb3NfbmFtZXNwYWNlOgogICAgICAgICAgICBlbnRpdHkgPSBmIntlbnRp + dHl9LXtyYWRvc19uYW1lc3BhY2V9IgogICAgICAgIHJldHVybiBlbnRpdHkKCiAgICBkZWYgZ2V0 + X3JiZF9wcm92aXNpb25lcl9jYXBzX2FuZF9lbnRpdHkoc2VsZik6CiAgICAgICAgZW50aXR5ID0g + ImNsaWVudC5jc2ktcmJkLXByb3Zpc2lvbmVyIgogICAgICAgIGNhcHMgPSB7CiAgICAgICAgICAg + ICJtb24iOiAicHJvZmlsZSByYmQsIGFsbG93IGNvbW1hbmQgJ29zZCBibG9ja2xpc3QnIiwKICAg + ICAgICAgICAgIm1nciI6ICJhbGxvdyBydyIsCiAgICAgICAgICAgICJvc2QiOiAicHJvZmlsZSBy + YmQiLAogICAgICAgIH0KICAgICAgICBpZiBzZWxmLl9hcmdfcGFyc2VyLnJlc3RyaWN0ZWRfYXV0 + aF9wZXJtaXNzaW9uOgogICAgICAgICAgICByYmRfcG9vbF9uYW1lID0gc2VsZi5fYXJnX3BhcnNl + ci5yYmRfZGF0YV9wb29sX25hbWUKICAgICAgICAgICAgYWxpYXNfcmJkX3Bvb2xfbmFtZSA9IHNl + bGYuX2FyZ19wYXJzZXIuYWxpYXNfcmJkX2RhdGFfcG9vbF9uYW1lCiAgICAgICAgICAgIGs4c19j + bHVzdGVyX25hbWUgPSBzZWxmLl9hcmdfcGFyc2VyLms4c19jbHVzdGVyX25hbWUKICAgICAgICAg + ICAgcmFkb3NfbmFtZXNwYWNlID0gc2VsZi5fYXJnX3BhcnNlci5yYWRvc19uYW1lc3BhY2UKICAg + ICAgICAgICAgaWYgcmJkX3Bvb2xfbmFtZSA9PSAiIjoKICAgICAgICAgICAgICAgIHJhaXNlIEV4 + ZWN1dGlvbkZhaWx1cmVFeGNlcHRpb24oCiAgICAgICAgICAgICAgICAgICAgIm1hbmRhdG9yeSBm + bGFnIG5vdCBmb3VuZCwgcGxlYXNlIHNldCB0aGUgJy0tcmJkLWRhdGEtcG9vbC1uYW1lJyBmbGFn + IgogICAgICAgICAgICAgICAgKQogICAgICAgICAgICBpZiBrOHNfY2x1c3Rlcl9uYW1lID09ICIi + OgogICAgICAgICAgICAgICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlvbigKICAgICAg + ICAgICAgICAgICAgICAibWFuZGF0b3J5IGZsYWcgbm90IGZvdW5kLCBwbGVhc2Ugc2V0IHRoZSAn + LS1rOHMtY2x1c3Rlci1uYW1lJyBmbGFnIgogICAgICAgICAgICAgICAgKQogICAgICAgICAgICBl + bnRpdHkgPSBzZWxmLmdldF9lbnRpdHkoCiAgICAgICAgICAgICAgICBlbnRpdHksCiAgICAgICAg + ICAgICAgICByYmRfcG9vbF9uYW1lLAogICAgICAgICAgICAgICAgYWxpYXNfcmJkX3Bvb2xfbmFt + ZSwKICAgICAgICAgICAgICAgIGs4c19jbHVzdGVyX25hbWUsCiAgICAgICAgICAgICAgICByYWRv + c19uYW1lc3BhY2UsCiAgICAgICAgICAgICkKICAgICAgICAgICAgaWYgcmFkb3NfbmFtZXNwYWNl + ICE9ICIiOgogICAgICAgICAgICAgICAgY2Fwc1sib3NkIl0gPSAoCiAgICAgICAgICAgICAgICAg + ICAgZiJwcm9maWxlIHJiZCBwb29sPXtyYmRfcG9vbF9uYW1lfSBuYW1lc3BhY2U9e3JhZG9zX25h + bWVzcGFjZX0iCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAg + ICAgICBjYXBzWyJvc2QiXSA9IGYicHJvZmlsZSByYmQgcG9vbD17cmJkX3Bvb2xfbmFtZX0iCgog + ICAgICAgIHJldHVybiBjYXBzLCBlbnRpdHkKCiAgICBkZWYgZ2V0X3JiZF9ub2RlX2NhcHNfYW5k + X2VudGl0eShzZWxmKToKICAgICAgICBlbnRpdHkgPSAiY2xpZW50LmNzaS1yYmQtbm9kZSIKICAg + ICAgICBjYXBzID0gewogICAgICAgICAgICAibW9uIjogInByb2ZpbGUgcmJkLCBhbGxvdyBjb21t + YW5kICdvc2QgYmxvY2tsaXN0JyIsCiAgICAgICAgICAgICJvc2QiOiAicHJvZmlsZSByYmQiLAog + ICAgICAgIH0KICAgICAgICBpZiBzZWxmLl9hcmdfcGFyc2VyLnJlc3RyaWN0ZWRfYXV0aF9wZXJt + aXNzaW9uOgogICAgICAgICAgICByYmRfcG9vbF9uYW1lID0gc2VsZi5fYXJnX3BhcnNlci5yYmRf + ZGF0YV9wb29sX25hbWUKICAgICAgICAgICAgYWxpYXNfcmJkX3Bvb2xfbmFtZSA9IHNlbGYuX2Fy + Z19wYXJzZXIuYWxpYXNfcmJkX2RhdGFfcG9vbF9uYW1lCiAgICAgICAgICAgIGs4c19jbHVzdGVy + X25hbWUgPSBzZWxmLl9hcmdfcGFyc2VyLms4c19jbHVzdGVyX25hbWUKICAgICAgICAgICAgcmFk + b3NfbmFtZXNwYWNlID0gc2VsZi5fYXJnX3BhcnNlci5yYWRvc19uYW1lc3BhY2UKICAgICAgICAg + ICAgaWYgcmJkX3Bvb2xfbmFtZSA9PSAiIjoKICAgICAgICAgICAgICAgIHJhaXNlIEV4ZWN1dGlv + bkZhaWx1cmVFeGNlcHRpb24oCiAgICAgICAgICAgICAgICAgICAgIm1hbmRhdG9yeSBmbGFnIG5v + dCBmb3VuZCwgcGxlYXNlIHNldCB0aGUgJy0tcmJkLWRhdGEtcG9vbC1uYW1lJyBmbGFnIgogICAg + ICAgICAgICAgICAgKQogICAgICAgICAgICBpZiBrOHNfY2x1c3Rlcl9uYW1lID09ICIiOgogICAg + ICAgICAgICAgICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlvbigKICAgICAgICAgICAg + ICAgICAgICAibWFuZGF0b3J5IGZsYWcgbm90IGZvdW5kLCBwbGVhc2Ugc2V0IHRoZSAnLS1rOHMt + Y2x1c3Rlci1uYW1lJyBmbGFnIgogICAgICAgICAgICAgICAgKQogICAgICAgICAgICBlbnRpdHkg + PSBzZWxmLmdldF9lbnRpdHkoCiAgICAgICAgICAgICAgICBlbnRpdHksCiAgICAgICAgICAgICAg + ICByYmRfcG9vbF9uYW1lLAogICAgICAgICAgICAgICAgYWxpYXNfcmJkX3Bvb2xfbmFtZSwKICAg + ICAgICAgICAgICAgIGs4c19jbHVzdGVyX25hbWUsCiAgICAgICAgICAgICAgICByYWRvc19uYW1l + c3BhY2UsCiAgICAgICAgICAgICkKICAgICAgICAgICAgaWYgcmFkb3NfbmFtZXNwYWNlICE9ICIi + OgogICAgICAgICAgICAgICAgY2Fwc1sib3NkIl0gPSAoCiAgICAgICAgICAgICAgICAgICAgZiJw + cm9maWxlIHJiZCBwb29sPXtyYmRfcG9vbF9uYW1lfSBuYW1lc3BhY2U9e3JhZG9zX25hbWVzcGFj + ZX0iCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICBj + YXBzWyJvc2QiXSA9IGYicHJvZmlsZSByYmQgcG9vbD17cmJkX3Bvb2xfbmFtZX0iCgogICAgICAg + IHJldHVybiBjYXBzLCBlbnRpdHkKCiAgICBkZWYgZ2V0X2RlZmF1bHRVc2VyX2NhcHNfYW5kX2Vu + dGl0eShzZWxmKToKICAgICAgICBlbnRpdHkgPSBzZWxmLnJ1bl9hc191c2VyCiAgICAgICAgY2Fw + cyA9IHsKICAgICAgICAgICAgIm1vbiI6ICJhbGxvdyByLCBhbGxvdyBjb21tYW5kIHF1b3J1bV9z + dGF0dXMsIGFsbG93IGNvbW1hbmQgdmVyc2lvbiIsCiAgICAgICAgICAgICJtZ3IiOiAiYWxsb3cg + Y29tbWFuZCBjb25maWciLAogICAgICAgICAgICAib3NkIjogZiJwcm9maWxlIHJiZC1yZWFkLW9u + bHksIGFsbG93IHJ3eCBwb29sPXtzZWxmLl9hcmdfcGFyc2VyLnJnd19wb29sX3ByZWZpeH0ucmd3 + Lm1ldGEsIGFsbG93IHIgcG9vbD0ucmd3LnJvb3QsIGFsbG93IHJ3IHBvb2w9e3NlbGYuX2FyZ19w + YXJzZXIucmd3X3Bvb2xfcHJlZml4fS5yZ3cuY29udHJvbCwgYWxsb3cgcnggcG9vbD17c2VsZi5f + YXJnX3BhcnNlci5yZ3dfcG9vbF9wcmVmaXh9LnJndy5sb2csIGFsbG93IHggcG9vbD17c2VsZi5f + YXJnX3BhcnNlci5yZ3dfcG9vbF9wcmVmaXh9LnJndy5idWNrZXRzLmluZGV4IiwKICAgICAgICAg + ICAgIm1kcyI6ICJhbGxvdyAqIiwKICAgICAgICB9CgogICAgICAgIHJldHVybiBjYXBzLCBlbnRp + dHkKCiAgICBkZWYgZ2V0X2NhcHNfYW5kX2VudGl0eShzZWxmLCB1c2VyX25hbWUpOgogICAgICAg + IGlmICJjbGllbnQuY3NpLWNlcGhmcy1wcm92aXNpb25lciIgaW4gdXNlcl9uYW1lOgogICAgICAg + ICAgICBpZiAiY2xpZW50LmNzaS1jZXBoZnMtcHJvdmlzaW9uZXIiICE9IHVzZXJfbmFtZToKICAg + ICAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIucmVzdHJpY3RlZF9hdXRoX3Blcm1pc3Npb24g + PSBUcnVlCiAgICAgICAgICAgIHJldHVybiBzZWxmLmdldF9jZXBoZnNfcHJvdmlzaW9uZXJfY2Fw + c19hbmRfZW50aXR5KCkKICAgICAgICBpZiAiY2xpZW50LmNzaS1jZXBoZnMtbm9kZSIgaW4gdXNl + cl9uYW1lOgogICAgICAgICAgICBpZiAiY2xpZW50LmNzaS1jZXBoZnMtbm9kZSIgIT0gdXNlcl9u + YW1lOgogICAgICAgICAgICAgICAgc2VsZi5fYXJnX3BhcnNlci5yZXN0cmljdGVkX2F1dGhfcGVy + bWlzc2lvbiA9IFRydWUKICAgICAgICAgICAgcmV0dXJuIHNlbGYuZ2V0X2NlcGhmc19ub2RlX2Nh + cHNfYW5kX2VudGl0eSgpCiAgICAgICAgaWYgImNsaWVudC5jc2ktcmJkLXByb3Zpc2lvbmVyIiBp + biB1c2VyX25hbWU6CiAgICAgICAgICAgIGlmICJjbGllbnQuY3NpLXJiZC1wcm92aXNpb25lciIg + IT0gdXNlcl9uYW1lOgogICAgICAgICAgICAgICAgc2VsZi5fYXJnX3BhcnNlci5yZXN0cmljdGVk + X2F1dGhfcGVybWlzc2lvbiA9IFRydWUKICAgICAgICAgICAgcmV0dXJuIHNlbGYuZ2V0X3JiZF9w + cm92aXNpb25lcl9jYXBzX2FuZF9lbnRpdHkoKQogICAgICAgIGlmICJjbGllbnQuY3NpLXJiZC1u + b2RlIiBpbiB1c2VyX25hbWU6CiAgICAgICAgICAgIGlmICJjbGllbnQuY3NpLXJiZC1ub2RlIiAh + PSB1c2VyX25hbWU6CiAgICAgICAgICAgICAgICBzZWxmLl9hcmdfcGFyc2VyLnJlc3RyaWN0ZWRf + YXV0aF9wZXJtaXNzaW9uID0gVHJ1ZQogICAgICAgICAgICByZXR1cm4gc2VsZi5nZXRfcmJkX25v + ZGVfY2Fwc19hbmRfZW50aXR5KCkKICAgICAgICBpZiAiY2xpZW50LmhlYWx0aGNoZWNrZXIiIGlu + IHVzZXJfbmFtZToKICAgICAgICAgICAgaWYgImNsaWVudC5oZWFsdGhjaGVja2VyIiAhPSB1c2Vy + X25hbWU6CiAgICAgICAgICAgICAgICBzZWxmLl9hcmdfcGFyc2VyLnJlc3RyaWN0ZWRfYXV0aF9w + ZXJtaXNzaW9uID0gVHJ1ZQogICAgICAgICAgICByZXR1cm4gc2VsZi5nZXRfZGVmYXVsdFVzZXJf + Y2Fwc19hbmRfZW50aXR5KCkKCiAgICAgICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlv + bigKICAgICAgICAgICAgZiJubyB1c2VyIGZvdW5kIHdpdGggdXNlcl9uYW1lOiB7dXNlcl9uYW1l + fSwgIgogICAgICAgICAgICAiZ2V0X2NhcHNfYW5kX2VudGl0eSBjb21tYW5kIGZhaWxlZC5cbiIK + ICAgICAgICApCgogICAgZGVmIGNyZWF0ZV9jZXBoQ1NJS2V5cmluZ191c2VyKHNlbGYsIHVzZXIp + OgogICAgICAgICIiIgogICAgICAgIGNvbW1hbmQ6IGNlcGggYXV0aCBnZXQtb3ItY3JlYXRlIGNs + aWVudC5jc2ktY2VwaGZzLXByb3Zpc2lvbmVyIG1vbiAnYWxsb3cgcicgbWdyICdhbGxvdyBydycg + b3NkICdhbGxvdyBydyB0YWcgY2VwaGZzIG1ldGFkYXRhPSonCiAgICAgICAgIiIiCiAgICAgICAg + Y2FwcywgZW50aXR5ID0gc2VsZi5nZXRfY2Fwc19hbmRfZW50aXR5KHVzZXIpCiAgICAgICAgY21k + X2pzb24gPSB7CiAgICAgICAgICAgICJwcmVmaXgiOiAiYXV0aCBnZXQtb3ItY3JlYXRlIiwKICAg + ICAgICAgICAgImVudGl0eSI6IGVudGl0eSwKICAgICAgICAgICAgImNhcHMiOiBbY2FwIGZvciBj + YXBfbGlzdCBpbiBsaXN0KGNhcHMuaXRlbXMoKSkgZm9yIGNhcCBpbiBjYXBfbGlzdF0sCiAgICAg + ICAgICAgICJmb3JtYXQiOiAianNvbiIsCiAgICAgICAgfQoKICAgICAgICBpZiBzZWxmLl9hcmdf + cGFyc2VyLmRyeV9ydW46CiAgICAgICAgICAgIHJldHVybiAoCiAgICAgICAgICAgICAgICBzZWxm + LmRyeV9ydW4oCiAgICAgICAgICAgICAgICAgICAgImNlcGggIgogICAgICAgICAgICAgICAgICAg + ICsgY21kX2pzb25bInByZWZpeCJdCiAgICAgICAgICAgICAgICAgICAgKyAiICIKICAgICAgICAg + ICAgICAgICAgICArIGNtZF9qc29uWyJlbnRpdHkiXQogICAgICAgICAgICAgICAgICAgICsgIiAi + CiAgICAgICAgICAgICAgICAgICAgKyAiICIuam9pbihjbWRfanNvblsiY2FwcyJdKQogICAgICAg + ICAgICAgICAgKSwKICAgICAgICAgICAgICAgICIiLAogICAgICAgICAgICApCiAgICAgICAgIyBj + aGVjayBpZiB1c2VyIGFscmVhZHkgZXhpc3QKICAgICAgICB1c2VyX2tleSA9IHNlbGYuY2hlY2tf + dXNlcl9leGlzdChlbnRpdHkpCiAgICAgICAgaWYgdXNlcl9rZXkgIT0gIiI6CiAgICAgICAgICAg + IHJldHVybiB1c2VyX2tleSwgZiJ7ZW50aXR5LnNwbGl0KCcuJywgMSlbMV19IgogICAgICAgICAg + ICAjIGVudGl0eS5zcGxpdCgnLicsMSlbMV0gdG8gcmVuYW1lIGVudGl0eShjbGllbnQuY3NpLXJi + ZC1ub2RlKSBhcyBjc2ktcmJkLW5vZGUKCiAgICAgICAgcmV0X3ZhbCwganNvbl9vdXQsIGVycl9t + c2cgPSBzZWxmLl9jb21tb25fY21kX2pzb25fZ2VuKGNtZF9qc29uKQogICAgICAgICMgaWYgdGhl + cmUgaXMgYW4gdW5zdWNjZXNzZnVsIGF0dGVtcHQsCiAgICAgICAgaWYgcmV0X3ZhbCAhPSAwIG9y + IGxlbihqc29uX291dCkgPT0gMDoKICAgICAgICAgICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4 + Y2VwdGlvbigKICAgICAgICAgICAgICAgIGYiJ2F1dGggZ2V0LW9yLWNyZWF0ZSB7dXNlcn0nIGNv + bW1hbmQgZmFpbGVkLlxuIgogICAgICAgICAgICAgICAgZiJFcnJvcjoge2Vycl9tc2cgaWYgcmV0 + X3ZhbCAhPSAwIGVsc2Ugc2VsZi5FTVBUWV9PVVRQVVRfTElTVH0iCiAgICAgICAgICAgICkKICAg + ICAgICByZXR1cm4gc3RyKGpzb25fb3V0WzBdWyJrZXkiXSksIGYie2VudGl0eS5zcGxpdCgnLics + IDEpWzFdfSIKICAgICAgICAjIGVudGl0eS5zcGxpdCgnLicsMSlbMV0gdG8gcmVuYW1lIGVudGl0 + eShjbGllbnQuY3NpLXJiZC1ub2RlKSBhcyBjc2ktcmJkLW5vZGUKCiAgICBkZWYgZ2V0X2NlcGhm + c19kYXRhX3Bvb2xfZGV0YWlscyhzZWxmKToKICAgICAgICBjbWRfanNvbiA9IHsicHJlZml4Ijog + ImZzIGxzIiwgImZvcm1hdCI6ICJqc29uIn0KICAgICAgICBpZiBzZWxmLl9hcmdfcGFyc2VyLmRy + eV9ydW46CiAgICAgICAgICAgIHJldHVybiBzZWxmLmRyeV9ydW4oImNlcGggIiArIGNtZF9qc29u + WyJwcmVmaXgiXSkKICAgICAgICByZXRfdmFsLCBqc29uX291dCwgZXJyX21zZyA9IHNlbGYuX2Nv bW1vbl9jbWRfanNvbl9nZW4oY21kX2pzb24pCiAgICAgICAgIyBpZiB0aGVyZSBpcyBhbiB1bnN1 - Y2Nlc3NmdWwgYXR0ZW1wdCwKICAgICAgICBpZiByZXRfdmFsICE9IDAgb3IgbGVuKGpzb25fb3V0 - KSA9PSAwOgogICAgICAgICAgICByZXR1cm4gTm9uZQogICAgICAgIGlmICJkYXNoYm9hcmQiIG5v - dCBpbiBqc29uX291dDoKICAgICAgICAgICAgcmV0dXJuIE5vbmUKICAgICAgICByZXR1cm4ganNv - bl9vdXRbImRhc2hib2FyZCJdCgogICAgZGVmIGNyZWF0ZV9yZ3dfYWRtaW5fb3BzX3VzZXIoc2Vs - Zik6CiAgICAgICAgY21kID0gWwogICAgICAgICAgICAicmFkb3Nndy1hZG1pbiIsCiAgICAgICAg - ICAgICJ1c2VyIiwKICAgICAgICAgICAgImNyZWF0ZSIsCiAgICAgICAgICAgICItLXVpZCIsCiAg - ICAgICAgICAgIHNlbGYuRVhURVJOQUxfUkdXX0FETUlOX09QU19VU0VSX05BTUUsCiAgICAgICAg - ICAgICItLWRpc3BsYXktbmFtZSIsCiAgICAgICAgICAgICJSb29rIFJHVyBBZG1pbiBPcHMgdXNl - ciIsCiAgICAgICAgICAgICItLWNhcHMiLAogICAgICAgICAgICAiYnVja2V0cz0qO3VzZXJzPSo7 - dXNhZ2U9cmVhZDttZXRhZGF0YT1yZWFkO3pvbmU9cmVhZCIsCiAgICAgICAgICAgICItLXJndy1y - ZWFsbSIsCiAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIucmd3X3JlYWxtX25hbWUsCiAgICAg - ICAgICAgICItLXJndy16b25lZ3JvdXAiLAogICAgICAgICAgICBzZWxmLl9hcmdfcGFyc2VyLnJn - d196b25lZ3JvdXBfbmFtZSwKICAgICAgICAgICAgIi0tcmd3LXpvbmUiLAogICAgICAgICAgICBz - ZWxmLl9hcmdfcGFyc2VyLnJnd196b25lX25hbWUsCiAgICAgICAgXQogICAgICAgIGlmIHNlbGYu - X2FyZ19wYXJzZXIuZHJ5X3J1bjoKICAgICAgICAgICAgcmV0dXJuIHNlbGYuZHJ5X3J1bigiY2Vw - aCAiICsgIiAiLmpvaW4oY21kKSkKICAgICAgICB0cnk6CiAgICAgICAgICAgIG91dHB1dCA9IHN1 - YnByb2Nlc3MuY2hlY2tfb3V0cHV0KGNtZCwgc3RkZXJyPXN1YnByb2Nlc3MuUElQRSkKICAgICAg - ICBleGNlcHQgc3VicHJvY2Vzcy5DYWxsZWRQcm9jZXNzRXJyb3IgYXMgZXhlY0VycjoKICAgICAg - ICAgICAgIyBpZiB0aGUgdXNlciBhbHJlYWR5IGV4aXN0cywgd2UganVzdCBxdWVyeSBpdAogICAg - ICAgICAgICBpZiBleGVjRXJyLnJldHVybmNvZGUgPT0gZXJybm8uRUVYSVNUOgogICAgICAgICAg - ICAgICAgY21kID0gWwogICAgICAgICAgICAgICAgICAgICJyYWRvc2d3LWFkbWluIiwKICAgICAg - ICAgICAgICAgICAgICAidXNlciIsCiAgICAgICAgICAgICAgICAgICAgImluZm8iLAogICAgICAg - ICAgICAgICAgICAgICItLXVpZCIsCiAgICAgICAgICAgICAgICAgICAgc2VsZi5FWFRFUk5BTF9S - R1dfQURNSU5fT1BTX1VTRVJfTkFNRSwKICAgICAgICAgICAgICAgICAgICAiLS1yZ3ctcmVhbG0i - LAogICAgICAgICAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIucmd3X3JlYWxtX25hbWUsCiAg - ICAgICAgICAgICAgICAgICAgIi0tcmd3LXpvbmVncm91cCIsCiAgICAgICAgICAgICAgICAgICAg - c2VsZi5fYXJnX3BhcnNlci5yZ3dfem9uZWdyb3VwX25hbWUsCiAgICAgICAgICAgICAgICAgICAg - Ii0tcmd3LXpvbmUiLAogICAgICAgICAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIucmd3X3pv - bmVfbmFtZSwKICAgICAgICAgICAgICAgIF0KICAgICAgICAgICAgICAgIHRyeToKICAgICAgICAg - ICAgICAgICAgICBvdXRwdXQgPSBzdWJwcm9jZXNzLmNoZWNrX291dHB1dChjbWQsIHN0ZGVycj1z - dWJwcm9jZXNzLlBJUEUpCiAgICAgICAgICAgICAgICBleGNlcHQgc3VicHJvY2Vzcy5DYWxsZWRQ - cm9jZXNzRXJyb3IgYXMgZXhlY0VycjoKICAgICAgICAgICAgICAgICAgICBlcnJfbXNnID0gKAog - ICAgICAgICAgICAgICAgICAgICAgICBmImZhaWxlZCB0byBleGVjdXRlIGNvbW1hbmQge2NtZH0u - IE91dHB1dDoge2V4ZWNFcnIub3V0cHV0fS4gIgogICAgICAgICAgICAgICAgICAgICAgICBmIkNv - ZGU6IHtleGVjRXJyLnJldHVybmNvZGV9LiBFcnJvcjoge2V4ZWNFcnIuc3RkZXJyfSIKICAgICAg - ICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgc3lzLnN0ZGVyci53cml0ZShlcnJf - bXNnKQogICAgICAgICAgICAgICAgICAgIHJldHVybiBOb25lLCBOb25lLCBGYWxzZSwgIi0xIgog - ICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgZXJyX21zZyA9ICgKICAgICAgICAgICAg - ICAgICAgICBmImZhaWxlZCB0byBleGVjdXRlIGNvbW1hbmQge2NtZH0uIE91dHB1dDoge2V4ZWNF - cnIub3V0cHV0fS4gIgogICAgICAgICAgICAgICAgICAgIGYiQ29kZToge2V4ZWNFcnIucmV0dXJu - Y29kZX0uIEVycm9yOiB7ZXhlY0Vyci5zdGRlcnJ9IgogICAgICAgICAgICAgICAgKQogICAgICAg - ICAgICAgICAgc3lzLnN0ZGVyci53cml0ZShlcnJfbXNnKQogICAgICAgICAgICAgICAgcmV0dXJu - IE5vbmUsIE5vbmUsIEZhbHNlLCAiLTEiCgogICAgICAgICMgc2VwYXJhdGVseSBhZGQgaW5mbz1y - ZWFkIGNhcHMgZm9yIHJndy1lbmRwb2ludCBpcCB2YWxpZGF0aW9uCiAgICAgICAgaW5mb19jYXBf - c3VwcG9ydGVkID0gVHJ1ZQogICAgICAgIGNtZCA9IFsKICAgICAgICAgICAgInJhZG9zZ3ctYWRt - aW4iLAogICAgICAgICAgICAiY2FwcyIsCiAgICAgICAgICAgICJhZGQiLAogICAgICAgICAgICAi - LS11aWQiLAogICAgICAgICAgICBzZWxmLkVYVEVSTkFMX1JHV19BRE1JTl9PUFNfVVNFUl9OQU1F - LAogICAgICAgICAgICAiLS1jYXBzIiwKICAgICAgICAgICAgImluZm89cmVhZCIsCiAgICAgICAg - ICAgICItLXJndy1yZWFsbSIsCiAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIucmd3X3JlYWxt - X25hbWUsCiAgICAgICAgICAgICItLXJndy16b25lZ3JvdXAiLAogICAgICAgICAgICBzZWxmLl9h - cmdfcGFyc2VyLnJnd196b25lZ3JvdXBfbmFtZSwKICAgICAgICAgICAgIi0tcmd3LXpvbmUiLAog - ICAgICAgICAgICBzZWxmLl9hcmdfcGFyc2VyLnJnd196b25lX25hbWUsCiAgICAgICAgXQogICAg - ICAgIHRyeToKICAgICAgICAgICAgb3V0cHV0ID0gc3VicHJvY2Vzcy5jaGVja19vdXRwdXQoY21k - LCBzdGRlcnI9c3VicHJvY2Vzcy5QSVBFKQogICAgICAgIGV4Y2VwdCBzdWJwcm9jZXNzLkNhbGxl - ZFByb2Nlc3NFcnJvciBhcyBleGVjRXJyOgogICAgICAgICAgICAjIGlmIHRoZSBjZXBoIHZlcnNp - b24gbm90IHN1cHBvcnRlZCBmb3IgYWRkaW5nIGBpbmZvPXJlYWRgIGNhcChyZ3dfdmFsaWRhdGlv - bikKICAgICAgICAgICAgaWYgKAogICAgICAgICAgICAgICAgImNvdWxkIG5vdCBhZGQgY2Fwczog - dW5hYmxlIHRvIGFkZCBjYXBzOiBpbmZvPXJlYWRcbiIKICAgICAgICAgICAgICAgIGluIGV4ZWNF - cnIuc3RkZXJyLmRlY29kZSgidXRmLTgiKQogICAgICAgICAgICAgICAgYW5kIGV4ZWNFcnIucmV0 - dXJuY29kZSA9PSAyNDQKICAgICAgICAgICAgKToKICAgICAgICAgICAgICAgIGluZm9fY2FwX3N1 - cHBvcnRlZCA9IEZhbHNlCiAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICBlcnJfbXNn - ID0gKAogICAgICAgICAgICAgICAgICAgIGYiZmFpbGVkIHRvIGV4ZWN1dGUgY29tbWFuZCB7Y21k - fS4gT3V0cHV0OiB7ZXhlY0Vyci5vdXRwdXR9LiAiCiAgICAgICAgICAgICAgICAgICAgZiJDb2Rl - OiB7ZXhlY0Vyci5yZXR1cm5jb2RlfS4gRXJyb3I6IHtleGVjRXJyLnN0ZGVycn0iCiAgICAgICAg - ICAgICAgICApCiAgICAgICAgICAgICAgICBzeXMuc3RkZXJyLndyaXRlKGVycl9tc2cpCiAgICAg - ICAgICAgICAgICByZXR1cm4gTm9uZSwgTm9uZSwgRmFsc2UsICItMSIKCiAgICAgICAganNvbm91 - dHB1dCA9IGpzb24ubG9hZHMob3V0cHV0KQogICAgICAgIHJldHVybiAoCiAgICAgICAgICAgIGpz - b25vdXRwdXRbImtleXMiXVswXVsiYWNjZXNzX2tleSJdLAogICAgICAgICAgICBqc29ub3V0cHV0 - WyJrZXlzIl1bMF1bInNlY3JldF9rZXkiXSwKICAgICAgICAgICAgaW5mb19jYXBfc3VwcG9ydGVk - LAogICAgICAgICAgICAiIiwKICAgICAgICApCgogICAgZGVmIHZhbGlkYXRlX3JiZF9wb29sKHNl - bGYsIHBvb2xfbmFtZSk6CiAgICAgICAgaWYgbm90IHNlbGYuY2x1c3Rlci5wb29sX2V4aXN0cyhw - b29sX25hbWUpOgogICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWlsdXJlRXhjZXB0aW9uKAog - ICAgICAgICAgICAgICAgZiJUaGUgcHJvdmlkZWQgcG9vbCwgJ3twb29sX25hbWV9JywgZG9lcyBu - b3QgZXhpc3QiCiAgICAgICAgICAgICkKCiAgICBkZWYgaW5pdF9yYmRfcG9vbChzZWxmLCByYmRf - cG9vbF9uYW1lKToKICAgICAgICBpZiBpc2luc3RhbmNlKHNlbGYuY2x1c3RlciwgRHVtbXlSYWRv - cyk6CiAgICAgICAgICAgIHJldHVybgogICAgICAgIGlvY3R4ID0gc2VsZi5jbHVzdGVyLm9wZW5f - aW9jdHgocmJkX3Bvb2xfbmFtZSkKICAgICAgICByYmRfaW5zdCA9IHJiZC5SQkQoKQogICAgICAg - IHJiZF9pbnN0LnBvb2xfaW5pdChpb2N0eCwgVHJ1ZSkKCiAgICBkZWYgdmFsaWRhdGVfcmFkb3Nf - bmFtZXNwYWNlKHNlbGYpOgogICAgICAgIHJiZF9wb29sX25hbWUgPSBzZWxmLl9hcmdfcGFyc2Vy - LnJiZF9kYXRhX3Bvb2xfbmFtZQogICAgICAgIGlmIHNlbGYuX2FyZ19wYXJzZXIucmJkX21ldGFk - YXRhX2VjX3Bvb2xfbmFtZToKICAgICAgICAgICAgcmJkX3Bvb2xfbmFtZSA9IHNlbGYuX2FyZ19w - YXJzZXIucmJkX21ldGFkYXRhX2VjX3Bvb2xfbmFtZQogICAgICAgIHJhZG9zX25hbWVzcGFjZSA9 - IHNlbGYuX2FyZ19wYXJzZXIucmFkb3NfbmFtZXNwYWNlCiAgICAgICAgaWYgcmFkb3NfbmFtZXNw - YWNlID09ICIiOgogICAgICAgICAgICByZXR1cm4KICAgICAgICBpZiByYWRvc19uYW1lc3BhY2Uu - aXNsb3dlcigpID09IEZhbHNlOgogICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWlsdXJlRXhj - ZXB0aW9uKAogICAgICAgICAgICAgICAgZiJUaGUgcHJvdmlkZWQgcmFkb3MgTmFtZXNwYWNlLCAn - e3JhZG9zX25hbWVzcGFjZX0nLCAiCiAgICAgICAgICAgICAgICBmImNvbnRhaW5zIHVwcGVyIGNh - c2UiCiAgICAgICAgICAgICkKICAgICAgICByYmRfaW5zdCA9IHJiZC5SQkQoKQogICAgICAgIGlv - Y3R4ID0gc2VsZi5jbHVzdGVyLm9wZW5faW9jdHgocmJkX3Bvb2xfbmFtZSkKICAgICAgICBpZiBy - YmRfaW5zdC5uYW1lc3BhY2VfZXhpc3RzKGlvY3R4LCByYWRvc19uYW1lc3BhY2UpIGlzIEZhbHNl - OgogICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWlsdXJlRXhjZXB0aW9uKAogICAgICAgICAg - ICAgICAgZiJUaGUgcHJvdmlkZWQgcmFkb3MgTmFtZXNwYWNlLCAne3JhZG9zX25hbWVzcGFjZX0n - LCAiCiAgICAgICAgICAgICAgICBmImlzIG5vdCBmb3VuZCBpbiB0aGUgcG9vbCAne3JiZF9wb29s - X25hbWV9JyIKICAgICAgICAgICAgKQoKICAgIGRlZiBnZXRfb3JfY3JlYXRlX3N1YnZvbHVtZV9n - cm91cChzZWxmLCBzdWJ2b2x1bWVfZ3JvdXAsIGNlcGhmc19maWxlc3lzdGVtX25hbWUpOgogICAg - ICAgIGNtZCA9IFsKICAgICAgICAgICAgImNlcGgiLAogICAgICAgICAgICAiZnMiLAogICAgICAg - ICAgICAic3Vidm9sdW1lZ3JvdXAiLAogICAgICAgICAgICAiZ2V0cGF0aCIsCiAgICAgICAgICAg - IGNlcGhmc19maWxlc3lzdGVtX25hbWUsCiAgICAgICAgICAgIHN1YnZvbHVtZV9ncm91cCwKICAg - ICAgICBdCiAgICAgICAgdHJ5OgogICAgICAgICAgICBfID0gc3VicHJvY2Vzcy5jaGVja19vdXRw + Y2Nlc3NmdWwgYXR0ZW1wdCwgcmVwb3J0IGFuIGVycm9yCiAgICAgICAgaWYgcmV0X3ZhbCAhPSAw + OgogICAgICAgICAgICAjIGlmIGZzIGFuZCBkYXRhX3Bvb2wgYXJndW1lbnRzIGFyZSBub3Qgc2V0 + LCBzaWxlbnRseSByZXR1cm4KICAgICAgICAgICAgaWYgKAogICAgICAgICAgICAgICAgc2VsZi5f + YXJnX3BhcnNlci5jZXBoZnNfZmlsZXN5c3RlbV9uYW1lID09ICIiCiAgICAgICAgICAgICAgICBh + bmQgc2VsZi5fYXJnX3BhcnNlci5jZXBoZnNfZGF0YV9wb29sX25hbWUgPT0gIiIKICAgICAgICAg + ICAgKToKICAgICAgICAgICAgICAgIHJldHVybgogICAgICAgICAgICAjIGlmIHVzZXIgaGFzIHBy + b3ZpZGVkIGFueSBvZiB0aGUKICAgICAgICAgICAgIyAnLS1jZXBoZnMtZmlsZXN5c3RlbS1uYW1l + JyBvciAnLS1jZXBoZnMtZGF0YS1wb29sLW5hbWUnIGFyZ3VtZW50cywKICAgICAgICAgICAgIyBy + YWlzZSBhbiBleGNlcHRpb24gYXMgd2UgYXJlIHVuYWJsZSB0byB2ZXJpZnkgdGhlIGFyZ3MKICAg + ICAgICAgICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlvbigKICAgICAgICAgICAgICAg + IGYiJ2ZzIGxzJyBjZXBoIGNhbGwgZmFpbGVkIHdpdGggZXJyb3I6IHtlcnJfbXNnfSIKICAgICAg + ICAgICAgKQoKICAgICAgICBtYXRjaGluZ19qc29uX291dCA9IHt9CiAgICAgICAgIyBpZiAnLS1j + ZXBoZnMtZmlsZXN5c3RlbS1uYW1lJyBhcmd1bWVudCBpcyBwcm92aWRlZCwKICAgICAgICAjIGNo + ZWNrIHdoZXRoZXIgdGhlIHByb3ZpZGVkIGZpbGVzeXN0ZW0tbmFtZSBleGlzdHMgb3Igbm90CiAg + ICAgICAgaWYgc2VsZi5fYXJnX3BhcnNlci5jZXBoZnNfZmlsZXN5c3RlbV9uYW1lOgogICAgICAg + ICAgICAjIGdldCB0aGUgbWF0Y2hpbmcgbGlzdAogICAgICAgICAgICBtYXRjaGluZ19qc29uX291 + dF9saXN0ID0gWwogICAgICAgICAgICAgICAgbWF0Y2hlZAogICAgICAgICAgICAgICAgZm9yIG1h + dGNoZWQgaW4ganNvbl9vdXQKICAgICAgICAgICAgICAgIGlmIHN0cihtYXRjaGVkWyJuYW1lIl0p + ID09IHNlbGYuX2FyZ19wYXJzZXIuY2VwaGZzX2ZpbGVzeXN0ZW1fbmFtZQogICAgICAgICAgICBd + CiAgICAgICAgICAgICMgdW5hYmxlIHRvIGZpbmQgYSBtYXRjaGluZyBmcy1uYW1lLCByYWlzZSBh + biBlcnJvcgogICAgICAgICAgICBpZiBsZW4obWF0Y2hpbmdfanNvbl9vdXRfbGlzdCkgPT0gMDoK + ICAgICAgICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1cmVFeGNlcHRpb24oCiAgICAgICAg + ICAgICAgICAgICAgZiJGaWxlc3lzdGVtIHByb3ZpZGVkLCAne3NlbGYuX2FyZ19wYXJzZXIuY2Vw + aGZzX2ZpbGVzeXN0ZW1fbmFtZX0nLCAiCiAgICAgICAgICAgICAgICAgICAgZiJpcyBub3QgZm91 + bmQgaW4gdGhlIGZzLWxpc3Q6IHtbc3RyKHhbJ25hbWUnXSkgZm9yIHggaW4ganNvbl9vdXRdfSIK + ICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgbWF0Y2hpbmdfanNvbl9vdXQgPSBtYXRjaGlu + Z19qc29uX291dF9saXN0WzBdCiAgICAgICAgIyBpZiBjZXBoZnMgZmlsZXN5c3RlbSBuYW1lIGlz + IG5vdCBwcm92aWRlZCwKICAgICAgICAjIHRyeSB0byBnZXQgYSBkZWZhdWx0IGZzIG5hbWUgYnkg + ZG9pbmcgdGhlIGZvbGxvd2luZwogICAgICAgIGVsc2U6CiAgICAgICAgICAgICMgYS4gY2hlY2sg + aWYgdGhlcmUgaXMgb25seSBvbmUgZmlsZXN5c3RlbSBpcyBwcmVzZW50CiAgICAgICAgICAgIGlm + IGxlbihqc29uX291dCkgPT0gMToKICAgICAgICAgICAgICAgIG1hdGNoaW5nX2pzb25fb3V0ID0g + anNvbl9vdXRbMF0KICAgICAgICAgICAgIyBiLiBvciBlbHNlLCBjaGVjayBpZiBkYXRhX3Bvb2wg + bmFtZSBpcyBwcm92aWRlZAogICAgICAgICAgICBlbGlmIHNlbGYuX2FyZ19wYXJzZXIuY2VwaGZz + X2RhdGFfcG9vbF9uYW1lOgogICAgICAgICAgICAgICAgIyBhbmQgaWYgcHJlc2VudCwgY2hlY2sg + d2hldGhlciB0aGVyZSBleGlzdHMgYSBmcyB3aGljaCBoYXMgdGhlIGRhdGFfcG9vbAogICAgICAg + ICAgICAgICAgZm9yIGVhY2hKIGluIGpzb25fb3V0OgogICAgICAgICAgICAgICAgICAgIGlmIHNl + bGYuX2FyZ19wYXJzZXIuY2VwaGZzX2RhdGFfcG9vbF9uYW1lIGluIGVhY2hKWyJkYXRhX3Bvb2xz + Il06CiAgICAgICAgICAgICAgICAgICAgICAgIG1hdGNoaW5nX2pzb25fb3V0ID0gZWFjaEoKICAg + ICAgICAgICAgICAgICAgICAgICAgYnJlYWsKICAgICAgICAgICAgICAgICMgaWYgdGhlcmUgaXMg + bm8gbWF0Y2hpbmcgZnMgZXhpc3RzLCB0aGF0IG1lYW5zIHByb3ZpZGVkIGRhdGFfcG9vbCBuYW1l + IGlzIGludmFsaWQKICAgICAgICAgICAgICAgIGlmIG5vdCBtYXRjaGluZ19qc29uX291dDoKICAg + ICAgICAgICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWlsdXJlRXhjZXB0aW9uKAogICAgICAg + ICAgICAgICAgICAgICAgICBmIlByb3ZpZGVkIGRhdGFfcG9vbCBuYW1lLCB7c2VsZi5fYXJnX3Bh + cnNlci5jZXBoZnNfZGF0YV9wb29sX25hbWV9LCIKICAgICAgICAgICAgICAgICAgICAgICAgIiBk + b2VzIG5vdCBleGlzdHMiCiAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAjIGMuIGlm + IG5vdGhpbmcgaXMgc2V0IGFuZCBjb3VsZG4ndCBmaW5kIGEgZGVmYXVsdCwKICAgICAgICAgICAg + ZWxzZToKICAgICAgICAgICAgICAgICMganVzdCByZXR1cm4gc2lsZW50bHkKICAgICAgICAgICAg + ICAgIHJldHVybgoKICAgICAgICBpZiBtYXRjaGluZ19qc29uX291dDoKICAgICAgICAgICAgc2Vs + Zi5fYXJnX3BhcnNlci5jZXBoZnNfZmlsZXN5c3RlbV9uYW1lID0gc3RyKG1hdGNoaW5nX2pzb25f + b3V0WyJuYW1lIl0pCiAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIuY2VwaGZzX21ldGFkYXRh + X3Bvb2xfbmFtZSA9IHN0cigKICAgICAgICAgICAgICAgIG1hdGNoaW5nX2pzb25fb3V0WyJtZXRh + ZGF0YV9wb29sIl0KICAgICAgICAgICAgKQoKICAgICAgICBpZiBpc2luc3RhbmNlKG1hdGNoaW5n + X2pzb25fb3V0WyJkYXRhX3Bvb2xzIl0sIGxpc3QpOgogICAgICAgICAgICAjIGlmIHRoZSB1c2Vy + IGhhcyBhbHJlYWR5IHByb3ZpZGVkIGRhdGEtcG9vbC1uYW1lLAogICAgICAgICAgICAjIHRocm91 + Z2ggLS1jZXBoZnMtZGF0YS1wb29sLW5hbWUKICAgICAgICAgICAgaWYgc2VsZi5fYXJnX3BhcnNl + ci5jZXBoZnNfZGF0YV9wb29sX25hbWU6CiAgICAgICAgICAgICAgICAjIGlmIHRoZSBwcm92aWRl + ZCBuYW1lIGlzIG5vdCBtYXRjaGluZyB3aXRoIHRoZSBvbmUgaW4gdGhlIGxpc3QKICAgICAgICAg + ICAgICAgIGlmICgKICAgICAgICAgICAgICAgICAgICBzZWxmLl9hcmdfcGFyc2VyLmNlcGhmc19k + YXRhX3Bvb2xfbmFtZQogICAgICAgICAgICAgICAgICAgIG5vdCBpbiBtYXRjaGluZ19qc29uX291 + dFsiZGF0YV9wb29scyJdCiAgICAgICAgICAgICAgICApOgogICAgICAgICAgICAgICAgICAgIHJh + aXNlIEV4ZWN1dGlvbkZhaWx1cmVFeGNlcHRpb24oCiAgICAgICAgICAgICAgICAgICAgICAgIGYi + UHJvdmlkZWQgZGF0YS1wb29sLW5hbWU6ICd7c2VsZi5fYXJnX3BhcnNlci5jZXBoZnNfZGF0YV9w + b29sX25hbWV9JywgIgogICAgICAgICAgICAgICAgICAgICAgICAiZG9lc24ndCBtYXRjaCBmcm9t + IHRoZSBkYXRhLXBvb2xzIGxpc3Q6ICIKICAgICAgICAgICAgICAgICAgICAgICAgZiJ7W3N0cih4 + KSBmb3IgeCBpbiBtYXRjaGluZ19qc29uX291dFsnZGF0YV9wb29scyddXX0iCiAgICAgICAgICAg + ICAgICAgICAgKQogICAgICAgICAgICAjIGlmIGRhdGFfcG9vbCBuYW1lIGlzIG5vdCBwcm92aWRl + ZCwKICAgICAgICAgICAgIyB0aGVuIHRyeSB0byBmaW5kIGEgZGVmYXVsdCBkYXRhIHBvb2wgbmFt + ZQogICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgIyBpZiBubyBkYXRhX3Bvb2xzIGV4 + aXN0LCBzaWxlbnRseSByZXR1cm4KICAgICAgICAgICAgICAgIGlmIGxlbihtYXRjaGluZ19qc29u + X291dFsiZGF0YV9wb29scyJdKSA9PSAwOgogICAgICAgICAgICAgICAgICAgIHJldHVybgogICAg + ICAgICAgICAgICAgc2VsZi5fYXJnX3BhcnNlci5jZXBoZnNfZGF0YV9wb29sX25hbWUgPSBzdHIo + CiAgICAgICAgICAgICAgICAgICAgbWF0Y2hpbmdfanNvbl9vdXRbImRhdGFfcG9vbHMiXVswXQog + ICAgICAgICAgICAgICAgKQogICAgICAgICAgICAjIGlmIHRoZXJlIGFyZSBtb3JlIHRoYW4gb25l + ICdkYXRhX3Bvb2xzJyBleGlzdCwKICAgICAgICAgICAgIyB0aGVuIHdhcm4gdGhlIHVzZXIgdGhh + dCB3ZSBhcmUgdXNpbmcgdGhlIHNlbGVjdGVkIG5hbWUKICAgICAgICAgICAgaWYgbGVuKG1hdGNo + aW5nX2pzb25fb3V0WyJkYXRhX3Bvb2xzIl0pID4gMToKICAgICAgICAgICAgICAgIHByaW50KAog + ICAgICAgICAgICAgICAgICAgICJXQVJOSU5HOiBNdWx0aXBsZSBkYXRhIHBvb2xzIGRldGVjdGVk + OiAiCiAgICAgICAgICAgICAgICAgICAgZiJ7W3N0cih4KSBmb3IgeCBpbiBtYXRjaGluZ19qc29u + X291dFsnZGF0YV9wb29scyddXX1cbiIKICAgICAgICAgICAgICAgICAgICBmIlVzaW5nIHRoZSBk + YXRhLXBvb2w6ICd7c2VsZi5fYXJnX3BhcnNlci5jZXBoZnNfZGF0YV9wb29sX25hbWV9J1xuIgog + ICAgICAgICAgICAgICAgKQoKICAgIGRlZiBjcmVhdGVfY2hlY2tlcktleShzZWxmLCB1c2VyKToK + ICAgICAgICBjYXBzLCBlbnRpdHkgPSBzZWxmLmdldF9jYXBzX2FuZF9lbnRpdHkodXNlcikKICAg + ICAgICBjbWRfanNvbiA9IHsKICAgICAgICAgICAgInByZWZpeCI6ICJhdXRoIGdldC1vci1jcmVh + dGUiLAogICAgICAgICAgICAiZW50aXR5IjogZW50aXR5LAogICAgICAgICAgICAiY2FwcyI6IFtj + YXAgZm9yIGNhcF9saXN0IGluIGxpc3QoY2Fwcy5pdGVtcygpKSBmb3IgY2FwIGluIGNhcF9saXN0 + XSwKICAgICAgICAgICAgImZvcm1hdCI6ICJqc29uIiwKICAgICAgICB9CgogICAgICAgIGlmIHNl + bGYuX2FyZ19wYXJzZXIuZHJ5X3J1bjoKICAgICAgICAgICAgcmV0dXJuIHNlbGYuZHJ5X3J1bigK + ICAgICAgICAgICAgICAgICJjZXBoICIKICAgICAgICAgICAgICAgICsgY21kX2pzb25bInByZWZp + eCJdCiAgICAgICAgICAgICAgICArICIgIgogICAgICAgICAgICAgICAgKyBjbWRfanNvblsiZW50 + aXR5Il0KICAgICAgICAgICAgICAgICsgIiAiCiAgICAgICAgICAgICAgICArICIgIi5qb2luKGNt + ZF9qc29uWyJjYXBzIl0pCiAgICAgICAgICAgICkKICAgICAgICAjIGNoZWNrIGlmIHVzZXIgYWxy + ZWFkeSBleGlzdAogICAgICAgIHVzZXJfa2V5ID0gc2VsZi5jaGVja191c2VyX2V4aXN0KGVudGl0 + eSkKICAgICAgICBpZiB1c2VyX2tleSAhPSAiIjoKICAgICAgICAgICAgcmV0dXJuIHVzZXJfa2V5 + CgogICAgICAgIHJldF92YWwsIGpzb25fb3V0LCBlcnJfbXNnID0gc2VsZi5fY29tbW9uX2NtZF9q + c29uX2dlbihjbWRfanNvbikKICAgICAgICAjIGlmIHRoZXJlIGlzIGFuIHVuc3VjY2Vzc2Z1bCBh + dHRlbXB0LAogICAgICAgIGlmIHJldF92YWwgIT0gMCBvciBsZW4oanNvbl9vdXQpID09IDA6CiAg + ICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1cmVFeGNlcHRpb24oCiAgICAgICAgICAgICAg + ICBmIidhdXRoIGdldC1vci1jcmVhdGUge3NlbGYucnVuX2FzX3VzZXJ9JyBjb21tYW5kIGZhaWxl + ZFxuIgogICAgICAgICAgICAgICAgZiJFcnJvcjoge2Vycl9tc2cgaWYgcmV0X3ZhbCAhPSAwIGVs + c2Ugc2VsZi5FTVBUWV9PVVRQVVRfTElTVH0iCiAgICAgICAgICAgICkKICAgICAgICByZXR1cm4g + c3RyKGpzb25fb3V0WzBdWyJrZXkiXSkKCiAgICBkZWYgZ2V0X2NlcGhfZGFzaGJvYXJkX2xpbmso + c2VsZik6CiAgICAgICAgY21kX2pzb24gPSB7InByZWZpeCI6ICJtZ3Igc2VydmljZXMiLCAiZm9y + bWF0IjogImpzb24ifQogICAgICAgIGlmIHNlbGYuX2FyZ19wYXJzZXIuZHJ5X3J1bjoKICAgICAg + ICAgICAgcmV0dXJuIHNlbGYuZHJ5X3J1bigiY2VwaCAiICsgY21kX2pzb25bInByZWZpeCJdKQog + ICAgICAgIHJldF92YWwsIGpzb25fb3V0LCBfID0gc2VsZi5fY29tbW9uX2NtZF9qc29uX2dlbihj + bWRfanNvbikKICAgICAgICAjIGlmIHRoZXJlIGlzIGFuIHVuc3VjY2Vzc2Z1bCBhdHRlbXB0LAog + ICAgICAgIGlmIHJldF92YWwgIT0gMCBvciBsZW4oanNvbl9vdXQpID09IDA6CiAgICAgICAgICAg + IHJldHVybiBOb25lCiAgICAgICAgaWYgImRhc2hib2FyZCIgbm90IGluIGpzb25fb3V0OgogICAg + ICAgICAgICByZXR1cm4gTm9uZQogICAgICAgIHJldHVybiBqc29uX291dFsiZGFzaGJvYXJkIl0K + CiAgICBkZWYgY3JlYXRlX3Jnd19hZG1pbl9vcHNfdXNlcihzZWxmKToKICAgICAgICBjbWQgPSBb + CiAgICAgICAgICAgICJyYWRvc2d3LWFkbWluIiwKICAgICAgICAgICAgInVzZXIiLAogICAgICAg + ICAgICAiY3JlYXRlIiwKICAgICAgICAgICAgIi0tdWlkIiwKICAgICAgICAgICAgc2VsZi5FWFRF + Uk5BTF9SR1dfQURNSU5fT1BTX1VTRVJfTkFNRSwKICAgICAgICAgICAgIi0tZGlzcGxheS1uYW1l + IiwKICAgICAgICAgICAgIlJvb2sgUkdXIEFkbWluIE9wcyB1c2VyIiwKICAgICAgICAgICAgIi0t + Y2FwcyIsCiAgICAgICAgICAgICJidWNrZXRzPSo7dXNlcnM9Kjt1c2FnZT1yZWFkO21ldGFkYXRh + PXJlYWQ7em9uZT1yZWFkIiwKICAgICAgICAgICAgIi0tcmd3LXJlYWxtIiwKICAgICAgICAgICAg + c2VsZi5fYXJnX3BhcnNlci5yZ3dfcmVhbG1fbmFtZSwKICAgICAgICAgICAgIi0tcmd3LXpvbmVn + cm91cCIsCiAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIucmd3X3pvbmVncm91cF9uYW1lLAog + ICAgICAgICAgICAiLS1yZ3ctem9uZSIsCiAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIucmd3 + X3pvbmVfbmFtZSwKICAgICAgICBdCiAgICAgICAgaWYgc2VsZi5fYXJnX3BhcnNlci5kcnlfcnVu + OgogICAgICAgICAgICByZXR1cm4gc2VsZi5kcnlfcnVuKCJjZXBoICIgKyAiICIuam9pbihjbWQp + KQogICAgICAgIHRyeToKICAgICAgICAgICAgb3V0cHV0ID0gc3VicHJvY2Vzcy5jaGVja19vdXRw dXQoY21kLCBzdGRlcnI9c3VicHJvY2Vzcy5QSVBFKQogICAgICAgIGV4Y2VwdCBzdWJwcm9jZXNz - LkNhbGxlZFByb2Nlc3NFcnJvcjoKICAgICAgICAgICAgY21kID0gWwogICAgICAgICAgICAgICAg - ImNlcGgiLAogICAgICAgICAgICAgICAgImZzIiwKICAgICAgICAgICAgICAgICJzdWJ2b2x1bWVn - cm91cCIsCiAgICAgICAgICAgICAgICAiY3JlYXRlIiwKICAgICAgICAgICAgICAgIGNlcGhmc19m - aWxlc3lzdGVtX25hbWUsCiAgICAgICAgICAgICAgICBzdWJ2b2x1bWVfZ3JvdXAsCiAgICAgICAg - ICAgIF0KICAgICAgICAgICAgdHJ5OgogICAgICAgICAgICAgICAgXyA9IHN1YnByb2Nlc3MuY2hl - Y2tfb3V0cHV0KGNtZCwgc3RkZXJyPXN1YnByb2Nlc3MuUElQRSkKICAgICAgICAgICAgZXhjZXB0 - IHN1YnByb2Nlc3MuQ2FsbGVkUHJvY2Vzc0Vycm9yOgogICAgICAgICAgICAgICAgcmFpc2UgRXhl - Y3V0aW9uRmFpbHVyZUV4Y2VwdGlvbigKICAgICAgICAgICAgICAgICAgICBmInN1YnZvbHVtZSBn - cm91cCB7c3Vidm9sdW1lX2dyb3VwfSBpcyBub3QgYWJsZSB0byBnZXQgY3JlYXRlZCIKICAgICAg - ICAgICAgICAgICkKCiAgICBkZWYgcGluX3N1YnZvbHVtZSgKICAgICAgICBzZWxmLCBzdWJ2b2x1 - bWVfZ3JvdXAsIGNlcGhmc19maWxlc3lzdGVtX25hbWUsIHBpbl90eXBlLCBwaW5fc2V0dGluZwog - ICAgKToKICAgICAgICBjbWQgPSBbCiAgICAgICAgICAgICJjZXBoIiwKICAgICAgICAgICAgImZz - IiwKICAgICAgICAgICAgInN1YnZvbHVtZWdyb3VwIiwKICAgICAgICAgICAgInBpbiIsCiAgICAg - ICAgICAgIGNlcGhmc19maWxlc3lzdGVtX25hbWUsCiAgICAgICAgICAgIHN1YnZvbHVtZV9ncm91 - cCwKICAgICAgICAgICAgcGluX3R5cGUsCiAgICAgICAgICAgIHBpbl9zZXR0aW5nLAogICAgICAg - IF0KICAgICAgICB0cnk6CiAgICAgICAgICAgIF8gPSBzdWJwcm9jZXNzLmNoZWNrX291dHB1dChj - bWQsIHN0ZGVycj1zdWJwcm9jZXNzLlBJUEUpCiAgICAgICAgZXhjZXB0IHN1YnByb2Nlc3MuQ2Fs - bGVkUHJvY2Vzc0Vycm9yOgogICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWlsdXJlRXhjZXB0 - aW9uKAogICAgICAgICAgICAgICAgZiJzdWJ2b2x1bWUgZ3JvdXAge3N1YnZvbHVtZV9ncm91cH0g - aXMgbm90IGFibGUgdG8gZ2V0IHBpbm5lZCIKICAgICAgICAgICAgKQoKICAgIGRlZiBnZXRfcmd3 - X2ZzaWQoc2VsZiwgYmFzZV91cmwsIHZlcmlmeSk6CiAgICAgICAgYWNjZXNzX2tleSA9IHNlbGYu - b3V0X21hcFsiUkdXX0FETUlOX09QU19VU0VSX0FDQ0VTU19LRVkiXQogICAgICAgIHNlY3JldF9r - ZXkgPSBzZWxmLm91dF9tYXBbIlJHV19BRE1JTl9PUFNfVVNFUl9TRUNSRVRfS0VZIl0KICAgICAg - ICByZ3dfZW5kcG9pbnQgPSBzZWxmLl9hcmdfcGFyc2VyLnJnd19lbmRwb2ludAogICAgICAgIGJh - c2VfdXJsID0gYmFzZV91cmwgKyAiOi8vIiArIHJnd19lbmRwb2ludCArICIvYWRtaW4vaW5mbz8i - CiAgICAgICAgcGFyYW1zID0geyJmb3JtYXQiOiAianNvbiJ9CiAgICAgICAgcmVxdWVzdF91cmwg - PSBiYXNlX3VybCArIHVybGVuY29kZShwYXJhbXMpCgogICAgICAgIHRyeToKICAgICAgICAgICAg - ciA9IHJlcXVlc3RzLmdldCgKICAgICAgICAgICAgICAgIHJlcXVlc3RfdXJsLAogICAgICAgICAg - ICAgICAgYXV0aD1TM0F1dGgoYWNjZXNzX2tleSwgc2VjcmV0X2tleSwgcmd3X2VuZHBvaW50KSwK - ICAgICAgICAgICAgICAgIHZlcmlmeT12ZXJpZnksCiAgICAgICAgICAgICkKICAgICAgICBleGNl - cHQgcmVxdWVzdHMuZXhjZXB0aW9ucy5UaW1lb3V0OgogICAgICAgICAgICBzeXMuc3RkZXJyLndy - aXRlKAogICAgICAgICAgICAgICAgZiJpbnZhbGlkIGVuZHBvaW50Oiwgbm90IGFibGUgdG8gY2Fs - bCBhZG1pbi1vcHMgYXBpe3Jnd19lbmRwb2ludH0iCiAgICAgICAgICAgICkKICAgICAgICAgICAg - cmV0dXJuICIiLCAiLTEiCiAgICAgICAgcjEgPSByLmpzb24oKQogICAgICAgIGlmIHIxIGlzIE5v - bmUgb3IgcjEuZ2V0KCJpbmZvIikgaXMgTm9uZToKICAgICAgICAgICAgc3lzLnN0ZGVyci53cml0 - ZSgKICAgICAgICAgICAgICAgIGYiVGhlIHByb3ZpZGVkIHJndyBFbmRwb2ludCwgJ3tzZWxmLl9h - cmdfcGFyc2VyLnJnd19lbmRwb2ludH0nLCBpcyBpbnZhbGlkLiIKICAgICAgICAgICAgKQogICAg - ICAgICAgICByZXR1cm4gKAogICAgICAgICAgICAgICAgIiIsCiAgICAgICAgICAgICAgICAiLTEi - LAogICAgICAgICAgICApCgogICAgICAgIHJldHVybiByMVsiaW5mbyJdWyJzdG9yYWdlX2JhY2tl - bmRzIl1bMF1bImNsdXN0ZXJfaWQiXSwgIiIKCiAgICBkZWYgdmFsaWRhdGVfcmd3X2VuZHBvaW50 - KHNlbGYsIGluZm9fY2FwX3N1cHBvcnRlZCk6CiAgICAgICAgIyBpZiB0aGUgJ2NsdXN0ZXInIGlu - c3RhbmNlIGlzIGEgZHVtbXkgb25lLAogICAgICAgICMgZG9uJ3QgdHJ5IHRvIHJlYWNoIG91dCB0 - byB0aGUgZW5kcG9pbnQKICAgICAgICBpZiBpc2luc3RhbmNlKHNlbGYuY2x1c3RlciwgRHVtbXlS - YWRvcyk6CiAgICAgICAgICAgIHJldHVybgoKICAgICAgICByZ3dfZW5kcG9pbnQgPSBzZWxmLl9h - cmdfcGFyc2VyLnJnd19lbmRwb2ludAoKICAgICAgICAjIHZhbGlkYXRlIHJndyBlbmRwb2ludCBv - bmx5IGlmIGlwIGFkZHJlc3MgaXMgcGFzc2VkCiAgICAgICAgaXBfdHlwZSA9IHNlbGYuX2ludmFs - aWRfZW5kcG9pbnQocmd3X2VuZHBvaW50KQoKICAgICAgICAjIGNoZWNrIGlmIHRoZSByZ3cgZW5k - cG9pbnQgaXMgcmVhY2hhYmxlCiAgICAgICAgY2VydCA9IE5vbmUKICAgICAgICBpZiBub3Qgc2Vs - Zi5fYXJnX3BhcnNlci5yZ3dfc2tpcF90bHMgYW5kIHNlbGYudmFsaWRhdGVfcmd3X2VuZHBvaW50 - X3Rsc19jZXJ0KCk6CiAgICAgICAgICAgIGNlcnQgPSBzZWxmLl9hcmdfcGFyc2VyLnJnd190bHNf - Y2VydF9wYXRoCiAgICAgICAgYmFzZV91cmwsIHZlcmlmeSwgZXJyID0gc2VsZi5lbmRwb2ludF9k - aWFsKHJnd19lbmRwb2ludCwgaXBfdHlwZSwgY2VydD1jZXJ0KQogICAgICAgIGlmIGVyciAhPSAi - IjoKICAgICAgICAgICAgcmV0dXJuICItMSIKCiAgICAgICAgIyBjaGVjayBpZiB0aGUgcmd3IGVu - ZHBvaW50IGJlbG9uZ3MgdG8gdGhlIHNhbWUgY2x1c3RlcgogICAgICAgICMgb25seSBjaGVjayBp - ZiBgaW5mb2AgY2FwIGlzIHN1cHBvcnRlZAogICAgICAgIGlmIGluZm9fY2FwX3N1cHBvcnRlZDoK - ICAgICAgICAgICAgZnNpZCA9IHNlbGYuZ2V0X2ZzaWQoKQogICAgICAgICAgICByZ3dfZnNpZCwg - ZXJyID0gc2VsZi5nZXRfcmd3X2ZzaWQoYmFzZV91cmwsIHZlcmlmeSkKICAgICAgICAgICAgaWYg - ZXJyID09ICItMSI6CiAgICAgICAgICAgICAgICByZXR1cm4gIi0xIgogICAgICAgICAgICBpZiBm - c2lkICE9IHJnd19mc2lkOgogICAgICAgICAgICAgICAgc3lzLnN0ZGVyci53cml0ZSgKICAgICAg - ICAgICAgICAgICAgICBmIlRoZSBwcm92aWRlZCByZ3cgRW5kcG9pbnQsICd7c2VsZi5fYXJnX3Bh - cnNlci5yZ3dfZW5kcG9pbnR9JywgaXMgaW52YWxpZC4gV2UgYXJlIHZhbGlkYXRpbmcgYnkgY2Fs - bGluZyB0aGUgYWRtaW5vcHMgYXBpIHRocm91Z2ggcmd3LWVuZHBvaW50IGFuZCB2YWxpZGF0aW5n - IHRoZSBjbHVzdGVyX2lkICd7cmd3X2ZzaWR9JyBpcyBlcXVhbCB0byB0aGUgY2VwaCBjbHVzdGVy - IGZzaWQgJ3tmc2lkfSciCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICByZXR1cm4g - Ii0xIgoKICAgICAgICAjIGNoZWNrIGlmIHRoZSByZ3cgZW5kcG9pbnQgcG9vbCBleGlzdAogICAg - ICAgICMgb25seSB2YWxpZGF0ZSBpZiByZ3dfcG9vbF9wcmVmaXggaXMgcGFzc2VkIGVsc2UgaXQg - d2lsbCB0YWtlIGRlZmF1bHQgdmFsdWUgYW5kIHdlIGRvbid0IGNyZWF0ZSB0aGVzZSBkZWZhdWx0 - IHBvb2xzCiAgICAgICAgaWYgc2VsZi5fYXJnX3BhcnNlci5yZ3dfcG9vbF9wcmVmaXggIT0gImRl - ZmF1bHQiOgogICAgICAgICAgICByZ3dfcG9vbHNfdG9fdmFsaWRhdGUgPSBbCiAgICAgICAgICAg - ICAgICBmIntzZWxmLl9hcmdfcGFyc2VyLnJnd19wb29sX3ByZWZpeH0ucmd3Lm1ldGEiLAogICAg - ICAgICAgICAgICAgIi5yZ3cucm9vdCIsCiAgICAgICAgICAgICAgICBmIntzZWxmLl9hcmdfcGFy - c2VyLnJnd19wb29sX3ByZWZpeH0ucmd3LmNvbnRyb2wiLAogICAgICAgICAgICAgICAgZiJ7c2Vs - Zi5fYXJnX3BhcnNlci5yZ3dfcG9vbF9wcmVmaXh9LnJndy5sb2ciLAogICAgICAgICAgICBdCiAg - ICAgICAgICAgIGZvciBfcmd3X3Bvb2xfdG9fdmFsaWRhdGUgaW4gcmd3X3Bvb2xzX3RvX3ZhbGlk - YXRlOgogICAgICAgICAgICAgICAgaWYgbm90IHNlbGYuY2x1c3Rlci5wb29sX2V4aXN0cyhfcmd3 - X3Bvb2xfdG9fdmFsaWRhdGUpOgogICAgICAgICAgICAgICAgICAgIHN5cy5zdGRlcnIud3JpdGUo - CiAgICAgICAgICAgICAgICAgICAgICAgIGYiVGhlIHByb3ZpZGVkIHBvb2wsICd7X3Jnd19wb29s - X3RvX3ZhbGlkYXRlfScsIGRvZXMgbm90IGV4aXN0IgogICAgICAgICAgICAgICAgICAgICkKICAg - ICAgICAgICAgICAgICAgICByZXR1cm4gIi0xIgoKICAgICAgICByZXR1cm4gIiIKCiAgICBkZWYg - dmFsaWRhdGVfcmd3X211bHRpc2l0ZShzZWxmLCByZ3dfbXVsdGlzaXRlX2NvbmZpZ19uYW1lLCBy - Z3dfbXVsdGlzaXRlX2NvbmZpZyk6CiAgICAgICAgaWYgcmd3X211bHRpc2l0ZV9jb25maWcgIT0g - IiI6CiAgICAgICAgICAgIGNtZCA9IFsKICAgICAgICAgICAgICAgICJyYWRvc2d3LWFkbWluIiwK - ICAgICAgICAgICAgICAgIHJnd19tdWx0aXNpdGVfY29uZmlnLAogICAgICAgICAgICAgICAgImdl - dCIsCiAgICAgICAgICAgICAgICAiLS1yZ3ctIiArIHJnd19tdWx0aXNpdGVfY29uZmlnLAogICAg - ICAgICAgICAgICAgcmd3X211bHRpc2l0ZV9jb25maWdfbmFtZSwKICAgICAgICAgICAgXQogICAg - ICAgICAgICB0cnk6CiAgICAgICAgICAgICAgICBfID0gc3VicHJvY2Vzcy5jaGVja19vdXRwdXQo - Y21kLCBzdGRlcnI9c3VicHJvY2Vzcy5QSVBFKQogICAgICAgICAgICBleGNlcHQgc3VicHJvY2Vz - cy5DYWxsZWRQcm9jZXNzRXJyb3IgYXMgZXhlY0VycjoKICAgICAgICAgICAgICAgIGVycl9tc2cg - PSAoCiAgICAgICAgICAgICAgICAgICAgZiJmYWlsZWQgdG8gZXhlY3V0ZSBjb21tYW5kIHtjbWR9 - LiBPdXRwdXQ6IHtleGVjRXJyLm91dHB1dH0uICIKICAgICAgICAgICAgICAgICAgICBmIkNvZGU6 - IHtleGVjRXJyLnJldHVybmNvZGV9LiBFcnJvcjoge2V4ZWNFcnIuc3RkZXJyfSIKICAgICAgICAg - ICAgICAgICkKICAgICAgICAgICAgICAgIHN5cy5zdGRlcnIud3JpdGUoZXJyX21zZykKICAgICAg - ICAgICAgICAgIHJldHVybiAiLTEiCiAgICAgICAgcmV0dXJuICIiCgogICAgZGVmIGNvbnZlcnRf - Y29tbWFfc2VwYXJhdGVkX3RvX2FycmF5KHNlbGYsIHZhbHVlKToKICAgICAgICByZXR1cm4gdmFs - dWUuc3BsaXQoIiwiKQoKICAgIGRlZiByYWlzZV9leGNlcHRpb25faWZfYW55X3RvcG9sb2d5X2Zs - YWdfaXNfbWlzc2luZyhzZWxmKToKICAgICAgICBpZiAoCiAgICAgICAgICAgICgKICAgICAgICAg - ICAgICAgIHNlbGYuX2FyZ19wYXJzZXIudG9wb2xvZ3lfcG9vbHMgIT0gIiIKICAgICAgICAgICAg - ICAgIGFuZCAoCiAgICAgICAgICAgICAgICAgICAgc2VsZi5fYXJnX3BhcnNlci50b3BvbG9neV9m - YWlsdXJlX2RvbWFpbl9sYWJlbCA9PSAiIgogICAgICAgICAgICAgICAgICAgIG9yIHNlbGYuX2Fy - Z19wYXJzZXIudG9wb2xvZ3lfZmFpbHVyZV9kb21haW5fdmFsdWVzID09ICIiCiAgICAgICAgICAg - ICAgICApCiAgICAgICAgICAgICkKICAgICAgICAgICAgb3IgKAogICAgICAgICAgICAgICAgc2Vs - Zi5fYXJnX3BhcnNlci50b3BvbG9neV9mYWlsdXJlX2RvbWFpbl9sYWJlbCAhPSAiIgogICAgICAg - ICAgICAgICAgYW5kICgKICAgICAgICAgICAgICAgICAgICBzZWxmLl9hcmdfcGFyc2VyLnRvcG9s - b2d5X3Bvb2xzID09ICIiCiAgICAgICAgICAgICAgICAgICAgb3Igc2VsZi5fYXJnX3BhcnNlci50 - b3BvbG9neV9mYWlsdXJlX2RvbWFpbl92YWx1ZXMgPT0gIiIKICAgICAgICAgICAgICAgICkKICAg - ICAgICAgICAgKQogICAgICAgICAgICBvciAoCiAgICAgICAgICAgICAgICBzZWxmLl9hcmdfcGFy - c2VyLnRvcG9sb2d5X2ZhaWx1cmVfZG9tYWluX3ZhbHVlcyAhPSAiIgogICAgICAgICAgICAgICAg - YW5kICgKICAgICAgICAgICAgICAgICAgICBzZWxmLl9hcmdfcGFyc2VyLnRvcG9sb2d5X3Bvb2xz + LkNhbGxlZFByb2Nlc3NFcnJvciBhcyBleGVjRXJyOgogICAgICAgICAgICAjIGlmIHRoZSB1c2Vy + IGFscmVhZHkgZXhpc3RzLCB3ZSBqdXN0IHF1ZXJ5IGl0CiAgICAgICAgICAgIGlmIGV4ZWNFcnIu + cmV0dXJuY29kZSA9PSBlcnJuby5FRVhJU1Q6CiAgICAgICAgICAgICAgICBjbWQgPSBbCiAgICAg + ICAgICAgICAgICAgICAgInJhZG9zZ3ctYWRtaW4iLAogICAgICAgICAgICAgICAgICAgICJ1c2Vy + IiwKICAgICAgICAgICAgICAgICAgICAiaW5mbyIsCiAgICAgICAgICAgICAgICAgICAgIi0tdWlk + IiwKICAgICAgICAgICAgICAgICAgICBzZWxmLkVYVEVSTkFMX1JHV19BRE1JTl9PUFNfVVNFUl9O + QU1FLAogICAgICAgICAgICAgICAgICAgICItLXJndy1yZWFsbSIsCiAgICAgICAgICAgICAgICAg + ICAgc2VsZi5fYXJnX3BhcnNlci5yZ3dfcmVhbG1fbmFtZSwKICAgICAgICAgICAgICAgICAgICAi + LS1yZ3ctem9uZWdyb3VwIiwKICAgICAgICAgICAgICAgICAgICBzZWxmLl9hcmdfcGFyc2VyLnJn + d196b25lZ3JvdXBfbmFtZSwKICAgICAgICAgICAgICAgICAgICAiLS1yZ3ctem9uZSIsCiAgICAg + ICAgICAgICAgICAgICAgc2VsZi5fYXJnX3BhcnNlci5yZ3dfem9uZV9uYW1lLAogICAgICAgICAg + ICAgICAgXQogICAgICAgICAgICAgICAgdHJ5OgogICAgICAgICAgICAgICAgICAgIG91dHB1dCA9 + IHN1YnByb2Nlc3MuY2hlY2tfb3V0cHV0KGNtZCwgc3RkZXJyPXN1YnByb2Nlc3MuUElQRSkKICAg + ICAgICAgICAgICAgIGV4Y2VwdCBzdWJwcm9jZXNzLkNhbGxlZFByb2Nlc3NFcnJvciBhcyBleGVj + RXJyOgogICAgICAgICAgICAgICAgICAgIGVycl9tc2cgPSAoCiAgICAgICAgICAgICAgICAgICAg + ICAgIGYiZmFpbGVkIHRvIGV4ZWN1dGUgY29tbWFuZCB7Y21kfS4gT3V0cHV0OiB7ZXhlY0Vyci5v + dXRwdXR9LiAiCiAgICAgICAgICAgICAgICAgICAgICAgIGYiQ29kZToge2V4ZWNFcnIucmV0dXJu + Y29kZX0uIEVycm9yOiB7ZXhlY0Vyci5zdGRlcnJ9IgogICAgICAgICAgICAgICAgICAgICkKICAg + ICAgICAgICAgICAgICAgICBzeXMuc3RkZXJyLndyaXRlKGVycl9tc2cpCiAgICAgICAgICAgICAg + ICAgICAgcmV0dXJuIE5vbmUsIE5vbmUsIEZhbHNlLCAiLTEiCiAgICAgICAgICAgIGVsc2U6CiAg + ICAgICAgICAgICAgICBlcnJfbXNnID0gKAogICAgICAgICAgICAgICAgICAgIGYiZmFpbGVkIHRv + IGV4ZWN1dGUgY29tbWFuZCB7Y21kfS4gT3V0cHV0OiB7ZXhlY0Vyci5vdXRwdXR9LiAiCiAgICAg + ICAgICAgICAgICAgICAgZiJDb2RlOiB7ZXhlY0Vyci5yZXR1cm5jb2RlfS4gRXJyb3I6IHtleGVj + RXJyLnN0ZGVycn0iCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICBzeXMuc3RkZXJy + LndyaXRlKGVycl9tc2cpCiAgICAgICAgICAgICAgICByZXR1cm4gTm9uZSwgTm9uZSwgRmFsc2Us + ICItMSIKCiAgICAgICAgIyBzZXBhcmF0ZWx5IGFkZCBpbmZvPXJlYWQgY2FwcyBmb3Igcmd3LWVu + ZHBvaW50IGlwIHZhbGlkYXRpb24KICAgICAgICBpbmZvX2NhcF9zdXBwb3J0ZWQgPSBUcnVlCiAg + ICAgICAgY21kID0gWwogICAgICAgICAgICAicmFkb3Nndy1hZG1pbiIsCiAgICAgICAgICAgICJj + YXBzIiwKICAgICAgICAgICAgImFkZCIsCiAgICAgICAgICAgICItLXVpZCIsCiAgICAgICAgICAg + IHNlbGYuRVhURVJOQUxfUkdXX0FETUlOX09QU19VU0VSX05BTUUsCiAgICAgICAgICAgICItLWNh + cHMiLAogICAgICAgICAgICAiaW5mbz1yZWFkIiwKICAgICAgICAgICAgIi0tcmd3LXJlYWxtIiwK + ICAgICAgICAgICAgc2VsZi5fYXJnX3BhcnNlci5yZ3dfcmVhbG1fbmFtZSwKICAgICAgICAgICAg + Ii0tcmd3LXpvbmVncm91cCIsCiAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIucmd3X3pvbmVn + cm91cF9uYW1lLAogICAgICAgICAgICAiLS1yZ3ctem9uZSIsCiAgICAgICAgICAgIHNlbGYuX2Fy + Z19wYXJzZXIucmd3X3pvbmVfbmFtZSwKICAgICAgICBdCiAgICAgICAgdHJ5OgogICAgICAgICAg + ICBvdXRwdXQgPSBzdWJwcm9jZXNzLmNoZWNrX291dHB1dChjbWQsIHN0ZGVycj1zdWJwcm9jZXNz + LlBJUEUpCiAgICAgICAgZXhjZXB0IHN1YnByb2Nlc3MuQ2FsbGVkUHJvY2Vzc0Vycm9yIGFzIGV4 + ZWNFcnI6CiAgICAgICAgICAgICMgaWYgdGhlIGNlcGggdmVyc2lvbiBub3Qgc3VwcG9ydGVkIGZv + ciBhZGRpbmcgYGluZm89cmVhZGAgY2FwKHJnd192YWxpZGF0aW9uKQogICAgICAgICAgICBpZiAo + CiAgICAgICAgICAgICAgICAiY291bGQgbm90IGFkZCBjYXBzOiB1bmFibGUgdG8gYWRkIGNhcHM6 + IGluZm89cmVhZFxuIgogICAgICAgICAgICAgICAgaW4gZXhlY0Vyci5zdGRlcnIuZGVjb2RlKCJ1 + dGYtOCIpCiAgICAgICAgICAgICAgICBhbmQgZXhlY0Vyci5yZXR1cm5jb2RlID09IDI0NAogICAg + ICAgICAgICApOgogICAgICAgICAgICAgICAgaW5mb19jYXBfc3VwcG9ydGVkID0gRmFsc2UKICAg + ICAgICAgICAgZWxzZToKICAgICAgICAgICAgICAgIGVycl9tc2cgPSAoCiAgICAgICAgICAgICAg + ICAgICAgZiJmYWlsZWQgdG8gZXhlY3V0ZSBjb21tYW5kIHtjbWR9LiBPdXRwdXQ6IHtleGVjRXJy + Lm91dHB1dH0uICIKICAgICAgICAgICAgICAgICAgICBmIkNvZGU6IHtleGVjRXJyLnJldHVybmNv + ZGV9LiBFcnJvcjoge2V4ZWNFcnIuc3RkZXJyfSIKICAgICAgICAgICAgICAgICkKICAgICAgICAg + ICAgICAgIHN5cy5zdGRlcnIud3JpdGUoZXJyX21zZykKICAgICAgICAgICAgICAgIHJldHVybiBO + b25lLCBOb25lLCBGYWxzZSwgIi0xIgoKICAgICAgICBqc29ub3V0cHV0ID0ganNvbi5sb2Fkcyhv + dXRwdXQpCiAgICAgICAgcmV0dXJuICgKICAgICAgICAgICAganNvbm91dHB1dFsia2V5cyJdWzBd + WyJhY2Nlc3Nfa2V5Il0sCiAgICAgICAgICAgIGpzb25vdXRwdXRbImtleXMiXVswXVsic2VjcmV0 + X2tleSJdLAogICAgICAgICAgICBpbmZvX2NhcF9zdXBwb3J0ZWQsCiAgICAgICAgICAgICIiLAog + ICAgICAgICkKCiAgICBkZWYgdmFsaWRhdGVfcmJkX3Bvb2woc2VsZiwgcG9vbF9uYW1lKToKICAg + ICAgICBpZiBub3Qgc2VsZi5jbHVzdGVyLnBvb2xfZXhpc3RzKHBvb2xfbmFtZSk6CiAgICAgICAg + ICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1cmVFeGNlcHRpb24oCiAgICAgICAgICAgICAgICBmIlRo + ZSBwcm92aWRlZCBwb29sLCAne3Bvb2xfbmFtZX0nLCBkb2VzIG5vdCBleGlzdCIKICAgICAgICAg + ICAgKQoKICAgIGRlZiBpbml0X3JiZF9wb29sKHNlbGYsIHJiZF9wb29sX25hbWUpOgogICAgICAg + IGlmIGlzaW5zdGFuY2Uoc2VsZi5jbHVzdGVyLCBEdW1teVJhZG9zKToKICAgICAgICAgICAgcmV0 + dXJuCiAgICAgICAgaW9jdHggPSBzZWxmLmNsdXN0ZXIub3Blbl9pb2N0eChyYmRfcG9vbF9uYW1l + KQogICAgICAgIHJiZF9pbnN0ID0gcmJkLlJCRCgpCiAgICAgICAgcmJkX2luc3QucG9vbF9pbml0 + KGlvY3R4LCBUcnVlKQoKICAgIGRlZiB2YWxpZGF0ZV9yYWRvc19uYW1lc3BhY2Uoc2VsZik6CiAg + ICAgICAgcmJkX3Bvb2xfbmFtZSA9IHNlbGYuX2FyZ19wYXJzZXIucmJkX2RhdGFfcG9vbF9uYW1l + CiAgICAgICAgaWYgc2VsZi5fYXJnX3BhcnNlci5yYmRfbWV0YWRhdGFfZWNfcG9vbF9uYW1lOgog + ICAgICAgICAgICByYmRfcG9vbF9uYW1lID0gc2VsZi5fYXJnX3BhcnNlci5yYmRfbWV0YWRhdGFf + ZWNfcG9vbF9uYW1lCiAgICAgICAgcmFkb3NfbmFtZXNwYWNlID0gc2VsZi5fYXJnX3BhcnNlci5y + YWRvc19uYW1lc3BhY2UKICAgICAgICBpZiByYWRvc19uYW1lc3BhY2UgPT0gIiI6CiAgICAgICAg + ICAgIHJldHVybgogICAgICAgIGlmIHJhZG9zX25hbWVzcGFjZS5pc2xvd2VyKCkgPT0gRmFsc2U6 + CiAgICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1cmVFeGNlcHRpb24oCiAgICAgICAgICAg + ICAgICBmIlRoZSBwcm92aWRlZCByYWRvcyBOYW1lc3BhY2UsICd7cmFkb3NfbmFtZXNwYWNlfScs + ICIKICAgICAgICAgICAgICAgIGYiY29udGFpbnMgdXBwZXIgY2FzZSIKICAgICAgICAgICAgKQog + ICAgICAgIHJiZF9pbnN0ID0gcmJkLlJCRCgpCiAgICAgICAgaW9jdHggPSBzZWxmLmNsdXN0ZXIu + b3Blbl9pb2N0eChyYmRfcG9vbF9uYW1lKQogICAgICAgIGlmIHJiZF9pbnN0Lm5hbWVzcGFjZV9l + eGlzdHMoaW9jdHgsIHJhZG9zX25hbWVzcGFjZSkgaXMgRmFsc2U6CiAgICAgICAgICAgIHJhaXNl + IEV4ZWN1dGlvbkZhaWx1cmVFeGNlcHRpb24oCiAgICAgICAgICAgICAgICBmIlRoZSBwcm92aWRl + ZCByYWRvcyBOYW1lc3BhY2UsICd7cmFkb3NfbmFtZXNwYWNlfScsICIKICAgICAgICAgICAgICAg + IGYiaXMgbm90IGZvdW5kIGluIHRoZSBwb29sICd7cmJkX3Bvb2xfbmFtZX0nIgogICAgICAgICAg + ICApCgogICAgZGVmIGdldF9vcl9jcmVhdGVfc3Vidm9sdW1lX2dyb3VwKHNlbGYsIHN1YnZvbHVt + ZV9ncm91cCwgY2VwaGZzX2ZpbGVzeXN0ZW1fbmFtZSk6CiAgICAgICAgY21kID0gWwogICAgICAg + ICAgICAiY2VwaCIsCiAgICAgICAgICAgICJmcyIsCiAgICAgICAgICAgICJzdWJ2b2x1bWVncm91 + cCIsCiAgICAgICAgICAgICJnZXRwYXRoIiwKICAgICAgICAgICAgY2VwaGZzX2ZpbGVzeXN0ZW1f + bmFtZSwKICAgICAgICAgICAgc3Vidm9sdW1lX2dyb3VwLAogICAgICAgIF0KICAgICAgICB0cnk6 + CiAgICAgICAgICAgIF8gPSBzdWJwcm9jZXNzLmNoZWNrX291dHB1dChjbWQsIHN0ZGVycj1zdWJw + cm9jZXNzLlBJUEUpCiAgICAgICAgZXhjZXB0IHN1YnByb2Nlc3MuQ2FsbGVkUHJvY2Vzc0Vycm9y + OgogICAgICAgICAgICBjbWQgPSBbCiAgICAgICAgICAgICAgICAiY2VwaCIsCiAgICAgICAgICAg + ICAgICAiZnMiLAogICAgICAgICAgICAgICAgInN1YnZvbHVtZWdyb3VwIiwKICAgICAgICAgICAg + ICAgICJjcmVhdGUiLAogICAgICAgICAgICAgICAgY2VwaGZzX2ZpbGVzeXN0ZW1fbmFtZSwKICAg + ICAgICAgICAgICAgIHN1YnZvbHVtZV9ncm91cCwKICAgICAgICAgICAgXQogICAgICAgICAgICB0 + cnk6CiAgICAgICAgICAgICAgICBfID0gc3VicHJvY2Vzcy5jaGVja19vdXRwdXQoY21kLCBzdGRl + cnI9c3VicHJvY2Vzcy5QSVBFKQogICAgICAgICAgICBleGNlcHQgc3VicHJvY2Vzcy5DYWxsZWRQ + cm9jZXNzRXJyb3I6CiAgICAgICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWlsdXJlRXhjZXB0 + aW9uKAogICAgICAgICAgICAgICAgICAgIGYic3Vidm9sdW1lIGdyb3VwIHtzdWJ2b2x1bWVfZ3Jv + dXB9IGlzIG5vdCBhYmxlIHRvIGdldCBjcmVhdGVkIgogICAgICAgICAgICAgICAgKQoKICAgIGRl + ZiBwaW5fc3Vidm9sdW1lKAogICAgICAgIHNlbGYsIHN1YnZvbHVtZV9ncm91cCwgY2VwaGZzX2Zp + bGVzeXN0ZW1fbmFtZSwgcGluX3R5cGUsIHBpbl9zZXR0aW5nCiAgICApOgogICAgICAgIGNtZCA9 + IFsKICAgICAgICAgICAgImNlcGgiLAogICAgICAgICAgICAiZnMiLAogICAgICAgICAgICAic3Vi + dm9sdW1lZ3JvdXAiLAogICAgICAgICAgICAicGluIiwKICAgICAgICAgICAgY2VwaGZzX2ZpbGVz + eXN0ZW1fbmFtZSwKICAgICAgICAgICAgc3Vidm9sdW1lX2dyb3VwLAogICAgICAgICAgICBwaW5f + dHlwZSwKICAgICAgICAgICAgcGluX3NldHRpbmcsCiAgICAgICAgXQogICAgICAgIHRyeToKICAg + ICAgICAgICAgXyA9IHN1YnByb2Nlc3MuY2hlY2tfb3V0cHV0KGNtZCwgc3RkZXJyPXN1YnByb2Nl + c3MuUElQRSkKICAgICAgICBleGNlcHQgc3VicHJvY2Vzcy5DYWxsZWRQcm9jZXNzRXJyb3I6CiAg + ICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1cmVFeGNlcHRpb24oCiAgICAgICAgICAgICAg + ICBmInN1YnZvbHVtZSBncm91cCB7c3Vidm9sdW1lX2dyb3VwfSBpcyBub3QgYWJsZSB0byBnZXQg + cGlubmVkIgogICAgICAgICAgICApCgogICAgZGVmIGdldF9yZ3dfZnNpZChzZWxmLCBiYXNlX3Vy + bCwgdmVyaWZ5KToKICAgICAgICBhY2Nlc3Nfa2V5ID0gc2VsZi5vdXRfbWFwWyJSR1dfQURNSU5f + T1BTX1VTRVJfQUNDRVNTX0tFWSJdCiAgICAgICAgc2VjcmV0X2tleSA9IHNlbGYub3V0X21hcFsi + UkdXX0FETUlOX09QU19VU0VSX1NFQ1JFVF9LRVkiXQogICAgICAgIHJnd19lbmRwb2ludCA9IHNl + bGYuX2FyZ19wYXJzZXIucmd3X2VuZHBvaW50CiAgICAgICAgYmFzZV91cmwgPSBiYXNlX3VybCAr + ICI6Ly8iICsgcmd3X2VuZHBvaW50ICsgIi9hZG1pbi9pbmZvPyIKICAgICAgICBwYXJhbXMgPSB7 + ImZvcm1hdCI6ICJqc29uIn0KICAgICAgICByZXF1ZXN0X3VybCA9IGJhc2VfdXJsICsgdXJsZW5j + b2RlKHBhcmFtcykKCiAgICAgICAgdHJ5OgogICAgICAgICAgICByID0gcmVxdWVzdHMuZ2V0KAog + ICAgICAgICAgICAgICAgcmVxdWVzdF91cmwsCiAgICAgICAgICAgICAgICBhdXRoPVMzQXV0aChh + Y2Nlc3Nfa2V5LCBzZWNyZXRfa2V5LCByZ3dfZW5kcG9pbnQpLAogICAgICAgICAgICAgICAgdmVy + aWZ5PXZlcmlmeSwKICAgICAgICAgICAgKQogICAgICAgIGV4Y2VwdCByZXF1ZXN0cy5leGNlcHRp + b25zLlRpbWVvdXQ6CiAgICAgICAgICAgIHN5cy5zdGRlcnIud3JpdGUoCiAgICAgICAgICAgICAg + ICBmImludmFsaWQgZW5kcG9pbnQ6LCBub3QgYWJsZSB0byBjYWxsIGFkbWluLW9wcyBhcGl7cmd3 + X2VuZHBvaW50fSIKICAgICAgICAgICAgKQogICAgICAgICAgICByZXR1cm4gIiIsICItMSIKICAg + ICAgICByMSA9IHIuanNvbigpCiAgICAgICAgaWYgcjEgaXMgTm9uZSBvciByMS5nZXQoImluZm8i + KSBpcyBOb25lOgogICAgICAgICAgICBzeXMuc3RkZXJyLndyaXRlKAogICAgICAgICAgICAgICAg + ZiJUaGUgcHJvdmlkZWQgcmd3IEVuZHBvaW50LCAne3NlbGYuX2FyZ19wYXJzZXIucmd3X2VuZHBv + aW50fScsIGlzIGludmFsaWQuIgogICAgICAgICAgICApCiAgICAgICAgICAgIHJldHVybiAoCiAg + ICAgICAgICAgICAgICAiIiwKICAgICAgICAgICAgICAgICItMSIsCiAgICAgICAgICAgICkKCiAg + ICAgICAgcmV0dXJuIHIxWyJpbmZvIl1bInN0b3JhZ2VfYmFja2VuZHMiXVswXVsiY2x1c3Rlcl9p + ZCJdLCAiIgoKICAgIGRlZiB2YWxpZGF0ZV9yZ3dfZW5kcG9pbnQoc2VsZiwgaW5mb19jYXBfc3Vw + cG9ydGVkKToKICAgICAgICAjIGlmIHRoZSAnY2x1c3RlcicgaW5zdGFuY2UgaXMgYSBkdW1teSBv + bmUsCiAgICAgICAgIyBkb24ndCB0cnkgdG8gcmVhY2ggb3V0IHRvIHRoZSBlbmRwb2ludAogICAg + ICAgIGlmIGlzaW5zdGFuY2Uoc2VsZi5jbHVzdGVyLCBEdW1teVJhZG9zKToKICAgICAgICAgICAg + cmV0dXJuCgogICAgICAgIHJnd19lbmRwb2ludCA9IHNlbGYuX2FyZ19wYXJzZXIucmd3X2VuZHBv + aW50CgogICAgICAgICMgdmFsaWRhdGUgcmd3IGVuZHBvaW50IG9ubHkgaWYgaXAgYWRkcmVzcyBp + cyBwYXNzZWQKICAgICAgICBpcF90eXBlID0gc2VsZi5faW52YWxpZF9lbmRwb2ludChyZ3dfZW5k + cG9pbnQpCgogICAgICAgICMgY2hlY2sgaWYgdGhlIHJndyBlbmRwb2ludCBpcyByZWFjaGFibGUK + ICAgICAgICBjZXJ0ID0gTm9uZQogICAgICAgIGlmIG5vdCBzZWxmLl9hcmdfcGFyc2VyLnJnd19z + a2lwX3RscyBhbmQgc2VsZi52YWxpZGF0ZV9yZ3dfZW5kcG9pbnRfdGxzX2NlcnQoKToKICAgICAg + ICAgICAgY2VydCA9IHNlbGYuX2FyZ19wYXJzZXIucmd3X3Rsc19jZXJ0X3BhdGgKICAgICAgICBi + YXNlX3VybCwgdmVyaWZ5LCBlcnIgPSBzZWxmLmVuZHBvaW50X2RpYWwocmd3X2VuZHBvaW50LCBp + cF90eXBlLCBjZXJ0PWNlcnQpCiAgICAgICAgaWYgZXJyICE9ICIiOgogICAgICAgICAgICByZXR1 + cm4gIi0xIgoKICAgICAgICAjIGNoZWNrIGlmIHRoZSByZ3cgZW5kcG9pbnQgYmVsb25ncyB0byB0 + aGUgc2FtZSBjbHVzdGVyCiAgICAgICAgIyBvbmx5IGNoZWNrIGlmIGBpbmZvYCBjYXAgaXMgc3Vw + cG9ydGVkCiAgICAgICAgaWYgaW5mb19jYXBfc3VwcG9ydGVkOgogICAgICAgICAgICBmc2lkID0g + c2VsZi5nZXRfZnNpZCgpCiAgICAgICAgICAgIHJnd19mc2lkLCBlcnIgPSBzZWxmLmdldF9yZ3df + ZnNpZChiYXNlX3VybCwgdmVyaWZ5KQogICAgICAgICAgICBpZiBlcnIgPT0gIi0xIjoKICAgICAg + ICAgICAgICAgIHJldHVybiAiLTEiCiAgICAgICAgICAgIGlmIGZzaWQgIT0gcmd3X2ZzaWQ6CiAg + ICAgICAgICAgICAgICBzeXMuc3RkZXJyLndyaXRlKAogICAgICAgICAgICAgICAgICAgIGYiVGhl + IHByb3ZpZGVkIHJndyBFbmRwb2ludCwgJ3tzZWxmLl9hcmdfcGFyc2VyLnJnd19lbmRwb2ludH0n + LCBpcyBpbnZhbGlkLiBXZSBhcmUgdmFsaWRhdGluZyBieSBjYWxsaW5nIHRoZSBhZG1pbm9wcyBh + cGkgdGhyb3VnaCByZ3ctZW5kcG9pbnQgYW5kIHZhbGlkYXRpbmcgdGhlIGNsdXN0ZXJfaWQgJ3ty + Z3dfZnNpZH0nIGlzIGVxdWFsIHRvIHRoZSBjZXBoIGNsdXN0ZXIgZnNpZCAne2ZzaWR9JyIKICAg + ICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIHJldHVybiAiLTEiCgogICAgICAgICMgY2hl + Y2sgaWYgdGhlIHJndyBlbmRwb2ludCBwb29sIGV4aXN0CiAgICAgICAgIyBvbmx5IHZhbGlkYXRl + IGlmIHJnd19wb29sX3ByZWZpeCBpcyBwYXNzZWQgZWxzZSBpdCB3aWxsIHRha2UgZGVmYXVsdCB2 + YWx1ZSBhbmQgd2UgZG9uJ3QgY3JlYXRlIHRoZXNlIGRlZmF1bHQgcG9vbHMKICAgICAgICBpZiBz + ZWxmLl9hcmdfcGFyc2VyLnJnd19wb29sX3ByZWZpeCAhPSAiZGVmYXVsdCI6CiAgICAgICAgICAg + IHJnd19wb29sc190b192YWxpZGF0ZSA9IFsKICAgICAgICAgICAgICAgIGYie3NlbGYuX2FyZ19w + YXJzZXIucmd3X3Bvb2xfcHJlZml4fS5yZ3cubWV0YSIsCiAgICAgICAgICAgICAgICAiLnJndy5y + b290IiwKICAgICAgICAgICAgICAgIGYie3NlbGYuX2FyZ19wYXJzZXIucmd3X3Bvb2xfcHJlZml4 + fS5yZ3cuY29udHJvbCIsCiAgICAgICAgICAgICAgICBmIntzZWxmLl9hcmdfcGFyc2VyLnJnd19w + b29sX3ByZWZpeH0ucmd3LmxvZyIsCiAgICAgICAgICAgIF0KICAgICAgICAgICAgZm9yIF9yZ3df + cG9vbF90b192YWxpZGF0ZSBpbiByZ3dfcG9vbHNfdG9fdmFsaWRhdGU6CiAgICAgICAgICAgICAg + ICBpZiBub3Qgc2VsZi5jbHVzdGVyLnBvb2xfZXhpc3RzKF9yZ3dfcG9vbF90b192YWxpZGF0ZSk6 + CiAgICAgICAgICAgICAgICAgICAgc3lzLnN0ZGVyci53cml0ZSgKICAgICAgICAgICAgICAgICAg + ICAgICAgZiJUaGUgcHJvdmlkZWQgcG9vbCwgJ3tfcmd3X3Bvb2xfdG9fdmFsaWRhdGV9JywgZG9l + cyBub3QgZXhpc3QiCiAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgIHJl + dHVybiAiLTEiCgogICAgICAgIHJldHVybiAiIgoKICAgIGRlZiB2YWxpZGF0ZV9yZ3dfbXVsdGlz + aXRlKHNlbGYsIHJnd19tdWx0aXNpdGVfY29uZmlnX25hbWUsIHJnd19tdWx0aXNpdGVfY29uZmln + KToKICAgICAgICBpZiByZ3dfbXVsdGlzaXRlX2NvbmZpZyAhPSAiIjoKICAgICAgICAgICAgY21k + ID0gWwogICAgICAgICAgICAgICAgInJhZG9zZ3ctYWRtaW4iLAogICAgICAgICAgICAgICAgcmd3 + X211bHRpc2l0ZV9jb25maWcsCiAgICAgICAgICAgICAgICAiZ2V0IiwKICAgICAgICAgICAgICAg + ICItLXJndy0iICsgcmd3X211bHRpc2l0ZV9jb25maWcsCiAgICAgICAgICAgICAgICByZ3dfbXVs + dGlzaXRlX2NvbmZpZ19uYW1lLAogICAgICAgICAgICBdCiAgICAgICAgICAgIHRyeToKICAgICAg + ICAgICAgICAgIF8gPSBzdWJwcm9jZXNzLmNoZWNrX291dHB1dChjbWQsIHN0ZGVycj1zdWJwcm9j + ZXNzLlBJUEUpCiAgICAgICAgICAgIGV4Y2VwdCBzdWJwcm9jZXNzLkNhbGxlZFByb2Nlc3NFcnJv + ciBhcyBleGVjRXJyOgogICAgICAgICAgICAgICAgZXJyX21zZyA9ICgKICAgICAgICAgICAgICAg + ICAgICBmImZhaWxlZCB0byBleGVjdXRlIGNvbW1hbmQge2NtZH0uIE91dHB1dDoge2V4ZWNFcnIu + b3V0cHV0fS4gIgogICAgICAgICAgICAgICAgICAgIGYiQ29kZToge2V4ZWNFcnIucmV0dXJuY29k + ZX0uIEVycm9yOiB7ZXhlY0Vyci5zdGRlcnJ9IgogICAgICAgICAgICAgICAgKQogICAgICAgICAg + ICAgICAgc3lzLnN0ZGVyci53cml0ZShlcnJfbXNnKQogICAgICAgICAgICAgICAgcmV0dXJuICIt + MSIKICAgICAgICByZXR1cm4gIiIKCiAgICBkZWYgY29udmVydF9jb21tYV9zZXBhcmF0ZWRfdG9f + YXJyYXkoc2VsZiwgdmFsdWUpOgogICAgICAgIHJldHVybiB2YWx1ZS5zcGxpdCgiLCIpCgogICAg + ZGVmIHJhaXNlX2V4Y2VwdGlvbl9pZl9hbnlfdG9wb2xvZ3lfZmxhZ19pc19taXNzaW5nKHNlbGYp + OgogICAgICAgIGlmICgKICAgICAgICAgICAgKAogICAgICAgICAgICAgICAgc2VsZi5fYXJnX3Bh + cnNlci50b3BvbG9neV9wb29scyAhPSAiIgogICAgICAgICAgICAgICAgYW5kICgKICAgICAgICAg + ICAgICAgICAgICBzZWxmLl9hcmdfcGFyc2VyLnRvcG9sb2d5X2ZhaWx1cmVfZG9tYWluX2xhYmVs ID09ICIiCiAgICAgICAgICAgICAgICAgICAgb3Igc2VsZi5fYXJnX3BhcnNlci50b3BvbG9neV9m - YWlsdXJlX2RvbWFpbl9sYWJlbCA9PSAiIgogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAp - CiAgICAgICAgKToKICAgICAgICAgICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlvbigK - ICAgICAgICAgICAgICAgICJwcm92aWRlIGFsbCB0aGUgdG9wb2xvZ3kgZmxhZ3MgLS10b3BvbG9n - eS1wb29scywgLS10b3BvbG9neS1mYWlsdXJlLWRvbWFpbi1sYWJlbCwgLS10b3BvbG9neS1mYWls - dXJlLWRvbWFpbi12YWx1ZXMiCiAgICAgICAgICAgICkKCiAgICBkZWYgdmFsaWRhdGVfdG9wb2xv - Z3lfdmFsdWVzKHNlbGYsIHRvcG9sb2d5X3Bvb2xzLCB0b3BvbG9neV9mZCk6CiAgICAgICAgaWYg - bGVuKHRvcG9sb2d5X3Bvb2xzKSAhPSBsZW4odG9wb2xvZ3lfZmQpOgogICAgICAgICAgICByYWlz - ZSBFeGVjdXRpb25GYWlsdXJlRXhjZXB0aW9uKAogICAgICAgICAgICAgICAgZiJUaGUgcHJvdmlk - ZWQgdG9wb2xvZ3kgcG9vbHMsICd7dG9wb2xvZ3lfcG9vbHN9JywgYW5kICIKICAgICAgICAgICAg - ICAgIGYidG9wb2xvZ3kgZmFpbHVyZSBkb21haW4sICd7dG9wb2xvZ3lfZmR9JywiCiAgICAgICAg - ICAgICAgICBmImFyZSBvZiBkaWZmZXJlbnQgbGVuZ3RoLCAne2xlbih0b3BvbG9neV9wb29scyl9 - JyBhbmQgJ3tsZW4odG9wb2xvZ3lfZmQpfScgcmVzcGN0aXZlbHkiCiAgICAgICAgICAgICkKICAg - ICAgICByZXR1cm4KCiAgICBkZWYgdmFsaWRhdGVfdG9wb2xvZ3lfcmJkX3Bvb2xzKHNlbGYsIHRv - cG9sb2d5X3JiZF9wb29scyk6CiAgICAgICAgZm9yIHBvb2wgaW4gdG9wb2xvZ3lfcmJkX3Bvb2xz - OgogICAgICAgICAgICBzZWxmLnZhbGlkYXRlX3JiZF9wb29sKHBvb2wpCgogICAgZGVmIGluaXRf - dG9wb2xvZ3lfcmJkX3Bvb2xzKHNlbGYsIHRvcG9sb2d5X3JiZF9wb29scyk6CiAgICAgICAgZm9y - IHBvb2wgaW4gdG9wb2xvZ3lfcmJkX3Bvb2xzOgogICAgICAgICAgICBzZWxmLmluaXRfcmJkX3Bv - b2wocG9vbCkKCiAgICAjIHRoaXMgd2lsbCByZXR1cm4gdGhlIGZpbmFsIGFyZ3MgdGhhdCBzY3Jp - cHQgdXNlcyB0byBwcm9jZXNzCiAgICAjIHRoZSBwcmlvcml0eSB0byBzZXQgYSBwYXJ0aWN1bGFy - IHZhbHVlIGlzLAogICAgIyBjb21tYW5kLWxpbmUtYXJncyA+IGNvbmZpZy5pbmkgZmlsZSB2YWx1 - ZXMgPiBkZWZhdWx0IHZhbHVlcwogICAgZGVmIGdldEZpbmFsVXNlZEFyZ3Moc2VsZik6CiAgICAg - ICAgYXJndW1lbnQgPSBmIltDb25maWd1cmF0aW9uc11cbiIKICAgICAgICBmb3IgYXJnIGluIHZh - cnMoc2VsZi5fYXJnX3BhcnNlcik6CiAgICAgICAgICAgIGlmIHN0cihnZXRhdHRyKHNlbGYuX2Fy - Z19wYXJzZXIsIGFyZykpOgogICAgICAgICAgICAgICAgIyBweXRob24gdHJlYXRzIGZsYWctbmFt - ZSBhcyBmbGFnX25hbWUgaW50ZXJuYWxseSwgc28gY29udmVydGluZyBiYWNrIHRvIGZsYWctbmFt - ZSwKICAgICAgICAgICAgICAgICMgc28gd2UgY2FuIGdldCB0aG9zZSB2YWx1ZXMgZnJvbSBjb25m - aWcgZmlsZQogICAgICAgICAgICAgICAgYXJnVmFsdWUgPSBhcmcucmVwbGFjZSgiXyIsICItIikK - ICAgICAgICAgICAgICAgICMgZG8gbm90IGFkZCB0aGUgY29uZmlnLWZpbGUgZmxhZyBhbmQgYWxz - byBub3QgYWRkIHRoZSBib29sZWFuIGZsYWdzIHdoaWNoIGFyZSBzZXQgdG8gRmFsc2UKICAgICAg - ICAgICAgICAgICMgYmVjYXVzZSBjb25maWcuaW5pIGZpbGUgdHJlYXRzIGJvb2xlYW4gZmxhZ3Mg - YXMgVHJ1ZSBhbHdheXMKICAgICAgICAgICAgICAgIGlmICgKICAgICAgICAgICAgICAgICAgICBh - cmdWYWx1ZSAhPSAiY29uZmlnLWZpbGUiCiAgICAgICAgICAgICAgICAgICAgYW5kIGdldGF0dHIo - c2VsZi5fYXJnX3BhcnNlciwgYXJnKSAhPSBGYWxzZQogICAgICAgICAgICAgICAgKToKICAgICAg - ICAgICAgICAgICAgICBhcmd1bWVudCArPSBmInthcmdWYWx1ZX0gPSB7c3RyKGdldGF0dHIoc2Vs - Zi5fYXJnX3BhcnNlciwgYXJnKSl9XG4iCiAgICAgICAgcmV0dXJuIGFyZ3VtZW50CgogICAgZGVm - IF9nZW5fb3V0cHV0X21hcChzZWxmKToKICAgICAgICBpZiBzZWxmLm91dF9tYXA6CiAgICAgICAg - ICAgIHJldHVybgogICAgICAgICMgc3VwcG9ydCBsZWdhY3kgZmxhZyB3aXRoIHVwZ3JhZGVzCiAg - ICAgICAgaWYgc2VsZi5fYXJnX3BhcnNlci5jbHVzdGVyX25hbWU6CiAgICAgICAgICAgIHNlbGYu - X2FyZ19wYXJzZXIuazhzX2NsdXN0ZXJfbmFtZSA9IHNlbGYuX2FyZ19wYXJzZXIuY2x1c3Rlcl9u - YW1lCiAgICAgICAgc2VsZi5fYXJnX3BhcnNlci5rOHNfY2x1c3Rlcl9uYW1lID0gKAogICAgICAg - ICAgICBzZWxmLl9hcmdfcGFyc2VyLms4c19jbHVzdGVyX25hbWUubG93ZXIoKQogICAgICAgICkg - ICMgYWx3YXlzIGNvbnZlcnQgY2x1c3RlciBuYW1lIHRvIGxvd2VyY2FzZSBjaGFyYWN0ZXJzCiAg - ICAgICAgc2VsZi52YWxpZGF0ZV9yYmRfcG9vbChzZWxmLl9hcmdfcGFyc2VyLnJiZF9kYXRhX3Bv - b2xfbmFtZSkKICAgICAgICBzZWxmLmluaXRfcmJkX3Bvb2woc2VsZi5fYXJnX3BhcnNlci5yYmRf - ZGF0YV9wb29sX25hbWUpCiAgICAgICAgc2VsZi52YWxpZGF0ZV9yYWRvc19uYW1lc3BhY2UoKQog - ICAgICAgIHNlbGYuX2V4Y2x1ZGVkX2tleXMuYWRkKCJLOFNfQ0xVU1RFUl9OQU1FIikKICAgICAg - ICBzZWxmLmdldF9jZXBoZnNfZGF0YV9wb29sX2RldGFpbHMoKQogICAgICAgICMgZG91YmxlIHN0 - cmluZyBuZWVkZWQgZm9yIHVwc3RyZWFtIGV4cG9ydHMgb2YgZmxhZ3MKICAgICAgICBzZWxmLm91 - dF9tYXBbIkFSR1MiXSA9IGYnIntzZWxmLmdldEZpbmFsVXNlZEFyZ3MoKX0iJwogICAgICAgIHNl - bGYub3V0X21hcFsiTkFNRVNQQUNFIl0gPSBzZWxmLl9hcmdfcGFyc2VyLm5hbWVzcGFjZQogICAg - ICAgIHNlbGYub3V0X21hcFsiSzhTX0NMVVNURVJfTkFNRSJdID0gc2VsZi5fYXJnX3BhcnNlci5r - OHNfY2x1c3Rlcl9uYW1lCiAgICAgICAgc2VsZi5vdXRfbWFwWyJST09LX0VYVEVSTkFMX0ZTSUQi - XSA9IHNlbGYuZ2V0X2ZzaWQoKQogICAgICAgIHNlbGYub3V0X21hcFsiUk9PS19FWFRFUk5BTF9V - U0VSTkFNRSJdID0gc2VsZi5ydW5fYXNfdXNlcgogICAgICAgIHNlbGYub3V0X21hcFsiUk9PS19F - WFRFUk5BTF9DRVBIX01PTl9EQVRBIl0gPSBzZWxmLmdldF9jZXBoX2V4dGVybmFsX21vbl9kYXRh - KCkKICAgICAgICBzZWxmLm91dF9tYXBbIlJPT0tfRVhURVJOQUxfVVNFUl9TRUNSRVQiXSA9IHNl - bGYuY3JlYXRlX2NoZWNrZXJLZXkoCiAgICAgICAgICAgICJjbGllbnQuaGVhbHRoY2hlY2tlciIK - ICAgICAgICApCiAgICAgICAgc2VsZi5vdXRfbWFwWyJST09LX0VYVEVSTkFMX0RBU0hCT0FSRF9M - SU5LIl0gPSBzZWxmLmdldF9jZXBoX2Rhc2hib2FyZF9saW5rKCkKICAgICAgICAoCiAgICAgICAg - ICAgIHNlbGYub3V0X21hcFsiQ1NJX1JCRF9OT0RFX1NFQ1JFVCJdLAogICAgICAgICAgICBzZWxm - Lm91dF9tYXBbIkNTSV9SQkRfTk9ERV9TRUNSRVRfTkFNRSJdLAogICAgICAgICkgPSBzZWxmLmNy - ZWF0ZV9jZXBoQ1NJS2V5cmluZ191c2VyKCJjbGllbnQuY3NpLXJiZC1ub2RlIikKICAgICAgICAo - CiAgICAgICAgICAgIHNlbGYub3V0X21hcFsiQ1NJX1JCRF9QUk9WSVNJT05FUl9TRUNSRVQiXSwK - ICAgICAgICAgICAgc2VsZi5vdXRfbWFwWyJDU0lfUkJEX1BST1ZJU0lPTkVSX1NFQ1JFVF9OQU1F - Il0sCiAgICAgICAgKSA9IHNlbGYuY3JlYXRlX2NlcGhDU0lLZXlyaW5nX3VzZXIoImNsaWVudC5j - c2ktcmJkLXByb3Zpc2lvbmVyIikKICAgICAgICBzZWxmLm91dF9tYXBbIkNFUEhGU19QT09MX05B - TUUiXSA9IHNlbGYuX2FyZ19wYXJzZXIuY2VwaGZzX2RhdGFfcG9vbF9uYW1lCiAgICAgICAgc2Vs - Zi5vdXRfbWFwWyJDRVBIRlNfTUVUQURBVEFfUE9PTF9OQU1FIl0gPSAoCiAgICAgICAgICAgIHNl - bGYuX2FyZ19wYXJzZXIuY2VwaGZzX21ldGFkYXRhX3Bvb2xfbmFtZQogICAgICAgICkKICAgICAg - ICBzZWxmLm91dF9tYXBbIkNFUEhGU19GU19OQU1FIl0gPSBzZWxmLl9hcmdfcGFyc2VyLmNlcGhm - c19maWxlc3lzdGVtX25hbWUKICAgICAgICBzZWxmLm91dF9tYXBbIlJFU1RSSUNURURfQVVUSF9Q - RVJNSVNTSU9OIl0gPSAoCiAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIucmVzdHJpY3RlZF9h - dXRoX3Blcm1pc3Npb24KICAgICAgICApCiAgICAgICAgc2VsZi5vdXRfbWFwWyJSQURPU19OQU1F - U1BBQ0UiXSA9IHNlbGYuX2FyZ19wYXJzZXIucmFkb3NfbmFtZXNwYWNlCiAgICAgICAgc2VsZi5v - dXRfbWFwWyJTVUJWT0xVTUVfR1JPVVAiXSA9IHNlbGYuX2FyZ19wYXJzZXIuc3Vidm9sdW1lX2dy - b3VwCiAgICAgICAgc2VsZi5vdXRfbWFwWyJDU0lfQ0VQSEZTX05PREVfU0VDUkVUIl0gPSAiIgog - ICAgICAgIHNlbGYub3V0X21hcFsiQ1NJX0NFUEhGU19QUk9WSVNJT05FUl9TRUNSRVQiXSA9ICIi - CiAgICAgICAgIyBjcmVhdGUgQ2VwaEZTIG5vZGUgYW5kIHByb3Zpc2lvbmVyIGtleXJpbmcgb25s - eSB3aGVuIE1EUyBleGlzdHMKICAgICAgICBpZiBzZWxmLm91dF9tYXBbIkNFUEhGU19GU19OQU1F - Il0gYW5kIHNlbGYub3V0X21hcFsiQ0VQSEZTX1BPT0xfTkFNRSJdOgogICAgICAgICAgICAoCiAg - ICAgICAgICAgICAgICBzZWxmLm91dF9tYXBbIkNTSV9DRVBIRlNfTk9ERV9TRUNSRVQiXSwKICAg - ICAgICAgICAgICAgIHNlbGYub3V0X21hcFsiQ1NJX0NFUEhGU19OT0RFX1NFQ1JFVF9OQU1FIl0s - CiAgICAgICAgICAgICkgPSBzZWxmLmNyZWF0ZV9jZXBoQ1NJS2V5cmluZ191c2VyKCJjbGllbnQu - Y3NpLWNlcGhmcy1ub2RlIikKICAgICAgICAgICAgKAogICAgICAgICAgICAgICAgc2VsZi5vdXRf - bWFwWyJDU0lfQ0VQSEZTX1BST1ZJU0lPTkVSX1NFQ1JFVCJdLAogICAgICAgICAgICAgICAgc2Vs - Zi5vdXRfbWFwWyJDU0lfQ0VQSEZTX1BST1ZJU0lPTkVSX1NFQ1JFVF9OQU1FIl0sCiAgICAgICAg - ICAgICkgPSBzZWxmLmNyZWF0ZV9jZXBoQ1NJS2V5cmluZ191c2VyKCJjbGllbnQuY3NpLWNlcGhm - cy1wcm92aXNpb25lciIpCiAgICAgICAgICAgICMgY3JlYXRlIHRoZSBkZWZhdWx0ICJjc2kiIHN1 - YnZvbHVtZWdyb3VwCiAgICAgICAgICAgIHNlbGYuZ2V0X29yX2NyZWF0ZV9zdWJ2b2x1bWVfZ3Jv - dXAoCiAgICAgICAgICAgICAgICAiY3NpIiwgc2VsZi5fYXJnX3BhcnNlci5jZXBoZnNfZmlsZXN5 - c3RlbV9uYW1lCiAgICAgICAgICAgICkKICAgICAgICAgICAgIyBwaW4gdGhlIGRlZmF1bHQgImNz - aSIgc3Vidm9sdW1lZ3JvdXAKICAgICAgICAgICAgc2VsZi5waW5fc3Vidm9sdW1lKAogICAgICAg - ICAgICAgICAgImNzaSIsIHNlbGYuX2FyZ19wYXJzZXIuY2VwaGZzX2ZpbGVzeXN0ZW1fbmFtZSwg - ImRpc3RyaWJ1dGVkIiwgIjEiCiAgICAgICAgICAgICkKICAgICAgICAgICAgaWYgc2VsZi5vdXRf - bWFwWyJTVUJWT0xVTUVfR1JPVVAiXToKICAgICAgICAgICAgICAgIHNlbGYuZ2V0X29yX2NyZWF0 - ZV9zdWJ2b2x1bWVfZ3JvdXAoCiAgICAgICAgICAgICAgICAgICAgc2VsZi5fYXJnX3BhcnNlci5z - dWJ2b2x1bWVfZ3JvdXAsCiAgICAgICAgICAgICAgICAgICAgc2VsZi5fYXJnX3BhcnNlci5jZXBo - ZnNfZmlsZXN5c3RlbV9uYW1lLAogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgc2Vs - Zi5waW5fc3Vidm9sdW1lKAogICAgICAgICAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIuc3Vi - dm9sdW1lX2dyb3VwLAogICAgICAgICAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIuY2VwaGZz - X2ZpbGVzeXN0ZW1fbmFtZSwKICAgICAgICAgICAgICAgICAgICAiZGlzdHJpYnV0ZWQiLAogICAg - ICAgICAgICAgICAgICAgICIxIiwKICAgICAgICAgICAgICAgICkKICAgICAgICBzZWxmLm91dF9t - YXBbIlJHV19UTFNfQ0VSVCJdID0gIiIKICAgICAgICBzZWxmLm91dF9tYXBbIk1PTklUT1JJTkdf - RU5EUE9JTlQiXSA9ICIiCiAgICAgICAgc2VsZi5vdXRfbWFwWyJNT05JVE9SSU5HX0VORFBPSU5U - X1BPUlQiXSA9ICIiCiAgICAgICAgaWYgbm90IHNlbGYuX2FyZ19wYXJzZXIuc2tpcF9tb25pdG9y - aW5nX2VuZHBvaW50OgogICAgICAgICAgICAoCiAgICAgICAgICAgICAgICBzZWxmLm91dF9tYXBb - Ik1PTklUT1JJTkdfRU5EUE9JTlQiXSwKICAgICAgICAgICAgICAgIHNlbGYub3V0X21hcFsiTU9O - SVRPUklOR19FTkRQT0lOVF9QT1JUIl0sCiAgICAgICAgICAgICkgPSBzZWxmLmdldF9hY3RpdmVf - YW5kX3N0YW5kYnlfbWdycygpCiAgICAgICAgc2VsZi5vdXRfbWFwWyJSQkRfUE9PTF9OQU1FIl0g - PSBzZWxmLl9hcmdfcGFyc2VyLnJiZF9kYXRhX3Bvb2xfbmFtZQogICAgICAgIHNlbGYub3V0X21h - cFsiUkJEX01FVEFEQVRBX0VDX1BPT0xfTkFNRSJdID0gKAogICAgICAgICAgICBzZWxmLnZhbGlk - YXRlX3JiZF9tZXRhZGF0YV9lY19wb29sX25hbWUoKQogICAgICAgICkKICAgICAgICBzZWxmLm91 - dF9tYXBbIlRPUE9MT0dZX1BPT0xTIl0gPSBzZWxmLl9hcmdfcGFyc2VyLnRvcG9sb2d5X3Bvb2xz - CiAgICAgICAgc2VsZi5vdXRfbWFwWyJUT1BPTE9HWV9GQUlMVVJFX0RPTUFJTl9MQUJFTCJdID0g - KAogICAgICAgICAgICBzZWxmLl9hcmdfcGFyc2VyLnRvcG9sb2d5X2ZhaWx1cmVfZG9tYWluX2xh - YmVsCiAgICAgICAgKQogICAgICAgIHNlbGYub3V0X21hcFsiVE9QT0xPR1lfRkFJTFVSRV9ET01B - SU5fVkFMVUVTIl0gPSAoCiAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIudG9wb2xvZ3lfZmFp - bHVyZV9kb21haW5fdmFsdWVzCiAgICAgICAgKQogICAgICAgIGlmICgKICAgICAgICAgICAgc2Vs - Zi5fYXJnX3BhcnNlci50b3BvbG9neV9wb29scyAhPSAiIgogICAgICAgICAgICBhbmQgc2VsZi5f - YXJnX3BhcnNlci50b3BvbG9neV9mYWlsdXJlX2RvbWFpbl9sYWJlbCAhPSAiIgogICAgICAgICAg - ICBhbmQgc2VsZi5fYXJnX3BhcnNlci50b3BvbG9neV9mYWlsdXJlX2RvbWFpbl92YWx1ZXMgIT0g - IiIKICAgICAgICApOgogICAgICAgICAgICBzZWxmLnZhbGlkYXRlX3RvcG9sb2d5X3ZhbHVlcygK - ICAgICAgICAgICAgICAgIHNlbGYuY29udmVydF9jb21tYV9zZXBhcmF0ZWRfdG9fYXJyYXkoc2Vs - Zi5vdXRfbWFwWyJUT1BPTE9HWV9QT09MUyJdKSwKICAgICAgICAgICAgICAgIHNlbGYuY29udmVy - dF9jb21tYV9zZXBhcmF0ZWRfdG9fYXJyYXkoCiAgICAgICAgICAgICAgICAgICAgc2VsZi5vdXRf - bWFwWyJUT1BPTE9HWV9GQUlMVVJFX0RPTUFJTl9WQUxVRVMiXQogICAgICAgICAgICAgICAgKSwK - ICAgICAgICAgICAgKQogICAgICAgICAgICBzZWxmLnZhbGlkYXRlX3RvcG9sb2d5X3JiZF9wb29s - cygKICAgICAgICAgICAgICAgIHNlbGYuY29udmVydF9jb21tYV9zZXBhcmF0ZWRfdG9fYXJyYXko - c2VsZi5vdXRfbWFwWyJUT1BPTE9HWV9QT09MUyJdKQogICAgICAgICAgICApCiAgICAgICAgICAg - IHNlbGYuaW5pdF90b3BvbG9neV9yYmRfcG9vbHMoCiAgICAgICAgICAgICAgICBzZWxmLmNvbnZl - cnRfY29tbWFfc2VwYXJhdGVkX3RvX2FycmF5KHNlbGYub3V0X21hcFsiVE9QT0xPR1lfUE9PTFMi - XSkKICAgICAgICAgICAgKQogICAgICAgIGVsc2U6CiAgICAgICAgICAgIHNlbGYucmFpc2VfZXhj - ZXB0aW9uX2lmX2FueV90b3BvbG9neV9mbGFnX2lzX21pc3NpbmcoKQoKICAgICAgICBzZWxmLm91 - dF9tYXBbIlJHV19QT09MX1BSRUZJWCJdID0gc2VsZi5fYXJnX3BhcnNlci5yZ3dfcG9vbF9wcmVm - aXgKICAgICAgICBzZWxmLm91dF9tYXBbIlJHV19FTkRQT0lOVCJdID0gIiIKICAgICAgICBpZiBz - ZWxmLl9hcmdfcGFyc2VyLnJnd19lbmRwb2ludDoKICAgICAgICAgICAgaWYgc2VsZi5fYXJnX3Bh - cnNlci5kcnlfcnVuOgogICAgICAgICAgICAgICAgc2VsZi5jcmVhdGVfcmd3X2FkbWluX29wc191 - c2VyKCkKICAgICAgICAgICAgZWxzZToKICAgICAgICAgICAgICAgIGlmICgKICAgICAgICAgICAg - ICAgICAgICBzZWxmLl9hcmdfcGFyc2VyLnJnd19yZWFsbV9uYW1lICE9ICIiCiAgICAgICAgICAg - ICAgICAgICAgYW5kIHNlbGYuX2FyZ19wYXJzZXIucmd3X3pvbmVncm91cF9uYW1lICE9ICIiCiAg - ICAgICAgICAgICAgICAgICAgYW5kIHNlbGYuX2FyZ19wYXJzZXIucmd3X3pvbmVfbmFtZSAhPSAi - IgogICAgICAgICAgICAgICAgKToKICAgICAgICAgICAgICAgICAgICBlcnIgPSBzZWxmLnZhbGlk - YXRlX3Jnd19tdWx0aXNpdGUoCiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJz - ZXIucmd3X3JlYWxtX25hbWUsICJyZWFsbSIKICAgICAgICAgICAgICAgICAgICApCiAgICAgICAg - ICAgICAgICAgICAgZXJyID0gc2VsZi52YWxpZGF0ZV9yZ3dfbXVsdGlzaXRlKAogICAgICAgICAg - ICAgICAgICAgICAgICBzZWxmLl9hcmdfcGFyc2VyLnJnd196b25lZ3JvdXBfbmFtZSwgInpvbmVn - cm91cCIKICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgZXJyID0gc2Vs - Zi52YWxpZGF0ZV9yZ3dfbXVsdGlzaXRlKAogICAgICAgICAgICAgICAgICAgICAgICBzZWxmLl9h - cmdfcGFyc2VyLnJnd196b25lX25hbWUsICJ6b25lIgogICAgICAgICAgICAgICAgICAgICkKCiAg - ICAgICAgICAgICAgICBpZiAoCiAgICAgICAgICAgICAgICAgICAgc2VsZi5fYXJnX3BhcnNlci5y - Z3dfcmVhbG1fbmFtZSA9PSAiIgogICAgICAgICAgICAgICAgICAgIGFuZCBzZWxmLl9hcmdfcGFy - c2VyLnJnd196b25lZ3JvdXBfbmFtZSA9PSAiIgogICAgICAgICAgICAgICAgICAgIGFuZCBzZWxm - Ll9hcmdfcGFyc2VyLnJnd196b25lX25hbWUgPT0gIiIKICAgICAgICAgICAgICAgICkgb3IgKAog - ICAgICAgICAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIucmd3X3JlYWxtX25hbWUgIT0gIiIK - ICAgICAgICAgICAgICAgICAgICBhbmQgc2VsZi5fYXJnX3BhcnNlci5yZ3dfem9uZWdyb3VwX25h - bWUgIT0gIiIKICAgICAgICAgICAgICAgICAgICBhbmQgc2VsZi5fYXJnX3BhcnNlci5yZ3dfem9u - ZV9uYW1lICE9ICIiCiAgICAgICAgICAgICAgICApOgogICAgICAgICAgICAgICAgICAgICgKICAg - ICAgICAgICAgICAgICAgICAgICAgc2VsZi5vdXRfbWFwWyJSR1dfQURNSU5fT1BTX1VTRVJfQUND - RVNTX0tFWSJdLAogICAgICAgICAgICAgICAgICAgICAgICBzZWxmLm91dF9tYXBbIlJHV19BRE1J - Tl9PUFNfVVNFUl9TRUNSRVRfS0VZIl0sCiAgICAgICAgICAgICAgICAgICAgICAgIGluZm9fY2Fw - X3N1cHBvcnRlZCwKICAgICAgICAgICAgICAgICAgICAgICAgZXJyLAogICAgICAgICAgICAgICAg - ICAgICkgPSBzZWxmLmNyZWF0ZV9yZ3dfYWRtaW5fb3BzX3VzZXIoKQogICAgICAgICAgICAgICAg - ICAgIGVyciA9IHNlbGYudmFsaWRhdGVfcmd3X2VuZHBvaW50KGluZm9fY2FwX3N1cHBvcnRlZCkK - ICAgICAgICAgICAgICAgICAgICBpZiBzZWxmLl9hcmdfcGFyc2VyLnJnd190bHNfY2VydF9wYXRo - OgogICAgICAgICAgICAgICAgICAgICAgICBzZWxmLm91dF9tYXBbIlJHV19UTFNfQ0VSVCJdID0g - KAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi52YWxpZGF0ZV9yZ3dfZW5kcG9pbnRf - dGxzX2NlcnQoKQogICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAg - IyBpZiB0aGVyZSBpcyBubyBlcnJvciwgc2V0IHRoZSBSR1dfRU5EUE9JTlQKICAgICAgICAgICAg - ICAgICAgICBpZiBlcnIgIT0gIi0xIjoKICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5vdXRf - bWFwWyJSR1dfRU5EUE9JTlQiXSA9IHNlbGYuX2FyZ19wYXJzZXIucmd3X2VuZHBvaW50CiAgICAg - ICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgICAgIGVyciA9ICJQbGVhc2UgcHJvdmlk - ZSBhbGwgdGhlIFJHVyBtdWx0aXNpdGUgcGFyYW1ldGVycyBvciBub25lIG9mIHRoZW0iCiAgICAg - ICAgICAgICAgICAgICAgc3lzLnN0ZGVyci53cml0ZShlcnIpCgogICAgZGVmIGdlbl9zaGVsbF9v - dXQoc2VsZik6CiAgICAgICAgc2VsZi5fZ2VuX291dHB1dF9tYXAoKQogICAgICAgIHNoT3V0SU8g - PSBTdHJpbmdJTygpCiAgICAgICAgZm9yIGssIHYgaW4gc2VsZi5vdXRfbWFwLml0ZW1zKCk6CiAg - ICAgICAgICAgIGlmIHYgYW5kIGsgbm90IGluIHNlbGYuX2V4Y2x1ZGVkX2tleXM6CiAgICAgICAg - ICAgICAgICBzaE91dElPLndyaXRlKGYiZXhwb3J0IHtrfT17dn17TElORVNFUH0iKQogICAgICAg - IHNoT3V0ID0gc2hPdXRJTy5nZXR2YWx1ZSgpCiAgICAgICAgc2hPdXRJTy5jbG9zZSgpCiAgICAg - ICAgcmV0dXJuIHNoT3V0CgogICAgZGVmIGdlbl9qc29uX291dChzZWxmKToKICAgICAgICBzZWxm - Ll9nZW5fb3V0cHV0X21hcCgpCiAgICAgICAgaWYgc2VsZi5fYXJnX3BhcnNlci5kcnlfcnVuOgog - ICAgICAgICAgICByZXR1cm4gIiIKICAgICAgICBqc29uX291dCA9IFsKICAgICAgICAgICAgewog - ICAgICAgICAgICAgICAgIm5hbWUiOiAiZXh0ZXJuYWwtY2x1c3Rlci11c2VyLWNvbW1hbmQiLAog - ICAgICAgICAgICAgICAgImtpbmQiOiAiQ29uZmlnTWFwIiwKICAgICAgICAgICAgICAgICJkYXRh - IjogewogICAgICAgICAgICAgICAgICAgICJhcmdzIjogc2VsZi5vdXRfbWFwWyJBUkdTIl0sCiAg - ICAgICAgICAgICAgICB9LAogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAg - ICAgICAibmFtZSI6ICJyb29rLWNlcGgtbW9uLWVuZHBvaW50cyIsCiAgICAgICAgICAgICAgICAi - a2luZCI6ICJDb25maWdNYXAiLAogICAgICAgICAgICAgICAgImRhdGEiOiB7CiAgICAgICAgICAg - ICAgICAgICAgImRhdGEiOiBzZWxmLm91dF9tYXBbIlJPT0tfRVhURVJOQUxfQ0VQSF9NT05fREFU - QSJdLAogICAgICAgICAgICAgICAgICAgICJtYXhNb25JZCI6ICIwIiwKICAgICAgICAgICAgICAg - ICAgICAibWFwcGluZyI6ICJ7fSIsCiAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICB9LAog - ICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAibmFtZSI6ICJyb29rLWNlcGgtbW9uIiwKICAg - ICAgICAgICAgICAgICJraW5kIjogIlNlY3JldCIsCiAgICAgICAgICAgICAgICAiZGF0YSI6IHsK - ICAgICAgICAgICAgICAgICAgICAiYWRtaW4tc2VjcmV0IjogImFkbWluLXNlY3JldCIsCiAgICAg - ICAgICAgICAgICAgICAgImZzaWQiOiBzZWxmLm91dF9tYXBbIlJPT0tfRVhURVJOQUxfRlNJRCJd - LAogICAgICAgICAgICAgICAgICAgICJtb24tc2VjcmV0IjogIm1vbi1zZWNyZXQiLAogICAgICAg - ICAgICAgICAgfSwKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAg - Im5hbWUiOiAicm9vay1jZXBoLW9wZXJhdG9yLWNyZWRzIiwKICAgICAgICAgICAgICAgICJraW5k - IjogIlNlY3JldCIsCiAgICAgICAgICAgICAgICAiZGF0YSI6IHsKICAgICAgICAgICAgICAgICAg - ICAidXNlcklEIjogc2VsZi5vdXRfbWFwWyJST09LX0VYVEVSTkFMX1VTRVJOQU1FIl0sCiAgICAg - ICAgICAgICAgICAgICAgInVzZXJLZXkiOiBzZWxmLm91dF9tYXBbIlJPT0tfRVhURVJOQUxfVVNF - Ul9TRUNSRVQiXSwKICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgIH0sCiAgICAgICAgXQoK - ICAgICAgICAjIGlmICdNT05JVE9SSU5HX0VORFBPSU5UJyBleGlzdHMsIHRoZW4gb25seSBhZGQg - J21vbml0b3JpbmctZW5kcG9pbnQnIHRvIENsdXN0ZXIKICAgICAgICBpZiAoCiAgICAgICAgICAg - IHNlbGYub3V0X21hcFsiTU9OSVRPUklOR19FTkRQT0lOVCJdCiAgICAgICAgICAgIGFuZCBzZWxm - Lm91dF9tYXBbIk1PTklUT1JJTkdfRU5EUE9JTlRfUE9SVCJdCiAgICAgICAgKToKICAgICAgICAg - ICAganNvbl9vdXQuYXBwZW5kKAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAg - ICJuYW1lIjogIm1vbml0b3JpbmctZW5kcG9pbnQiLAogICAgICAgICAgICAgICAgICAgICJraW5k - IjogIkNlcGhDbHVzdGVyIiwKICAgICAgICAgICAgICAgICAgICAiZGF0YSI6IHsKICAgICAgICAg - ICAgICAgICAgICAgICAgIk1vbml0b3JpbmdFbmRwb2ludCI6IHNlbGYub3V0X21hcFsiTU9OSVRP - UklOR19FTkRQT0lOVCJdLAogICAgICAgICAgICAgICAgICAgICAgICAiTW9uaXRvcmluZ1BvcnQi - OiBzZWxmLm91dF9tYXBbIk1PTklUT1JJTkdfRU5EUE9JTlRfUE9SVCJdLAogICAgICAgICAgICAg - ICAgICAgIH0sCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICkKCiAgICAgICAgIyBpZiAn - Q1NJX1JCRF9OT0RFX1NFQ1JFVCcgZXhpc3RzLCB0aGVuIG9ubHkgYWRkICdyb29rLWNzaS1yYmQt - cHJvdmlzaW9uZXInIFNlY3JldAogICAgICAgIGlmICgKICAgICAgICAgICAgc2VsZi5vdXRfbWFw - WyJDU0lfUkJEX05PREVfU0VDUkVUIl0KICAgICAgICAgICAgYW5kIHNlbGYub3V0X21hcFsiQ1NJ - X1JCRF9OT0RFX1NFQ1JFVF9OQU1FIl0KICAgICAgICApOgogICAgICAgICAgICBqc29uX291dC5h - cHBlbmQoCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgIm5hbWUiOiBmInJv - b2ste3NlbGYub3V0X21hcFsnQ1NJX1JCRF9OT0RFX1NFQ1JFVF9OQU1FJ119IiwKICAgICAgICAg + YWlsdXJlX2RvbWFpbl92YWx1ZXMgPT0gIiIKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAg + KQogICAgICAgICAgICBvciAoCiAgICAgICAgICAgICAgICBzZWxmLl9hcmdfcGFyc2VyLnRvcG9s + b2d5X2ZhaWx1cmVfZG9tYWluX2xhYmVsICE9ICIiCiAgICAgICAgICAgICAgICBhbmQgKAogICAg + ICAgICAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIudG9wb2xvZ3lfcG9vbHMgPT0gIiIKICAg + ICAgICAgICAgICAgICAgICBvciBzZWxmLl9hcmdfcGFyc2VyLnRvcG9sb2d5X2ZhaWx1cmVfZG9t + YWluX3ZhbHVlcyA9PSAiIgogICAgICAgICAgICAgICAgKQogICAgICAgICAgICApCiAgICAgICAg + ICAgIG9yICgKICAgICAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIudG9wb2xvZ3lfZmFpbHVy + ZV9kb21haW5fdmFsdWVzICE9ICIiCiAgICAgICAgICAgICAgICBhbmQgKAogICAgICAgICAgICAg + ICAgICAgIHNlbGYuX2FyZ19wYXJzZXIudG9wb2xvZ3lfcG9vbHMgPT0gIiIKICAgICAgICAgICAg + ICAgICAgICBvciBzZWxmLl9hcmdfcGFyc2VyLnRvcG9sb2d5X2ZhaWx1cmVfZG9tYWluX2xhYmVs + ID09ICIiCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICkKICAgICAgICApOgogICAgICAg + ICAgICByYWlzZSBFeGVjdXRpb25GYWlsdXJlRXhjZXB0aW9uKAogICAgICAgICAgICAgICAgInBy + b3ZpZGUgYWxsIHRoZSB0b3BvbG9neSBmbGFncyAtLXRvcG9sb2d5LXBvb2xzLCAtLXRvcG9sb2d5 + LWZhaWx1cmUtZG9tYWluLWxhYmVsLCAtLXRvcG9sb2d5LWZhaWx1cmUtZG9tYWluLXZhbHVlcyIK + ICAgICAgICAgICAgKQoKICAgIGRlZiB2YWxpZGF0ZV90b3BvbG9neV92YWx1ZXMoc2VsZiwgdG9w + b2xvZ3lfcG9vbHMsIHRvcG9sb2d5X2ZkKToKICAgICAgICBpZiBsZW4odG9wb2xvZ3lfcG9vbHMp + ICE9IGxlbih0b3BvbG9neV9mZCk6CiAgICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1cmVF + eGNlcHRpb24oCiAgICAgICAgICAgICAgICBmIlRoZSBwcm92aWRlZCB0b3BvbG9neSBwb29scywg + J3t0b3BvbG9neV9wb29sc30nLCBhbmQgIgogICAgICAgICAgICAgICAgZiJ0b3BvbG9neSBmYWls + dXJlIGRvbWFpbiwgJ3t0b3BvbG9neV9mZH0nLCIKICAgICAgICAgICAgICAgIGYiYXJlIG9mIGRp + ZmZlcmVudCBsZW5ndGgsICd7bGVuKHRvcG9sb2d5X3Bvb2xzKX0nIGFuZCAne2xlbih0b3BvbG9n + eV9mZCl9JyByZXNwY3RpdmVseSIKICAgICAgICAgICAgKQogICAgICAgIHJldHVybgoKICAgIGRl + ZiB2YWxpZGF0ZV90b3BvbG9neV9yYmRfcG9vbHMoc2VsZiwgdG9wb2xvZ3lfcmJkX3Bvb2xzKToK + ICAgICAgICBmb3IgcG9vbCBpbiB0b3BvbG9neV9yYmRfcG9vbHM6CiAgICAgICAgICAgIHNlbGYu + dmFsaWRhdGVfcmJkX3Bvb2wocG9vbCkKCiAgICBkZWYgaW5pdF90b3BvbG9neV9yYmRfcG9vbHMo + c2VsZiwgdG9wb2xvZ3lfcmJkX3Bvb2xzKToKICAgICAgICBmb3IgcG9vbCBpbiB0b3BvbG9neV9y + YmRfcG9vbHM6CiAgICAgICAgICAgIHNlbGYuaW5pdF9yYmRfcG9vbChwb29sKQoKICAgICMgdGhp + cyB3aWxsIHJldHVybiB0aGUgZmluYWwgYXJncyB0aGF0IHNjcmlwdCB1c2VzIHRvIHByb2Nlc3MK + ICAgICMgdGhlIHByaW9yaXR5IHRvIHNldCBhIHBhcnRpY3VsYXIgdmFsdWUgaXMsCiAgICAjIGNv + bW1hbmQtbGluZS1hcmdzID4gY29uZmlnLmluaSBmaWxlIHZhbHVlcyA+IGRlZmF1bHQgdmFsdWVz + CiAgICBkZWYgZ2V0RmluYWxVc2VkQXJncyhzZWxmKToKICAgICAgICBhcmd1bWVudCA9IGYiW0Nv + bmZpZ3VyYXRpb25zXVxuIgogICAgICAgIGZvciBhcmcgaW4gdmFycyhzZWxmLl9hcmdfcGFyc2Vy + KToKICAgICAgICAgICAgaWYgc3RyKGdldGF0dHIoc2VsZi5fYXJnX3BhcnNlciwgYXJnKSk6CiAg + ICAgICAgICAgICAgICAjIHB5dGhvbiB0cmVhdHMgZmxhZy1uYW1lIGFzIGZsYWdfbmFtZSBpbnRl + cm5hbGx5LCBzbyBjb252ZXJ0aW5nIGJhY2sgdG8gZmxhZy1uYW1lLAogICAgICAgICAgICAgICAg + IyBzbyB3ZSBjYW4gZ2V0IHRob3NlIHZhbHVlcyBmcm9tIGNvbmZpZyBmaWxlCiAgICAgICAgICAg + ICAgICBhcmdWYWx1ZSA9IGFyZy5yZXBsYWNlKCJfIiwgIi0iKQogICAgICAgICAgICAgICAgIyBk + byBub3QgYWRkIHRoZSBjb25maWctZmlsZSBmbGFnIGFuZCBhbHNvIG5vdCBhZGQgdGhlIGJvb2xl + YW4gZmxhZ3Mgd2hpY2ggYXJlIHNldCB0byBGYWxzZQogICAgICAgICAgICAgICAgIyBiZWNhdXNl + IGNvbmZpZy5pbmkgZmlsZSB0cmVhdHMgYm9vbGVhbiBmbGFncyBhcyBUcnVlIGFsd2F5cwogICAg + ICAgICAgICAgICAgaWYgKAogICAgICAgICAgICAgICAgICAgIGFyZ1ZhbHVlICE9ICJjb25maWct + ZmlsZSIKICAgICAgICAgICAgICAgICAgICBhbmQgZ2V0YXR0cihzZWxmLl9hcmdfcGFyc2VyLCBh + cmcpICE9IEZhbHNlCiAgICAgICAgICAgICAgICApOgogICAgICAgICAgICAgICAgICAgIGFyZ3Vt + ZW50ICs9IGYie2FyZ1ZhbHVlfSA9IHtzdHIoZ2V0YXR0cihzZWxmLl9hcmdfcGFyc2VyLCBhcmcp + KX1cbiIKICAgICAgICByZXR1cm4gYXJndW1lbnQKCiAgICBkZWYgX2dlbl9vdXRwdXRfbWFwKHNl + bGYpOgogICAgICAgIGlmIHNlbGYub3V0X21hcDoKICAgICAgICAgICAgcmV0dXJuCiAgICAgICAg + IyBzdXBwb3J0IGxlZ2FjeSBmbGFnIHdpdGggdXBncmFkZXMKICAgICAgICBpZiBzZWxmLl9hcmdf + cGFyc2VyLmNsdXN0ZXJfbmFtZToKICAgICAgICAgICAgc2VsZi5fYXJnX3BhcnNlci5rOHNfY2x1 + c3Rlcl9uYW1lID0gc2VsZi5fYXJnX3BhcnNlci5jbHVzdGVyX25hbWUKICAgICAgICBzZWxmLl9h + cmdfcGFyc2VyLms4c19jbHVzdGVyX25hbWUgPSAoCiAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJz + ZXIuazhzX2NsdXN0ZXJfbmFtZS5sb3dlcigpCiAgICAgICAgKSAgIyBhbHdheXMgY29udmVydCBj + bHVzdGVyIG5hbWUgdG8gbG93ZXJjYXNlIGNoYXJhY3RlcnMKICAgICAgICBzZWxmLnZhbGlkYXRl + X3JiZF9wb29sKHNlbGYuX2FyZ19wYXJzZXIucmJkX2RhdGFfcG9vbF9uYW1lKQogICAgICAgIHNl + bGYuaW5pdF9yYmRfcG9vbChzZWxmLl9hcmdfcGFyc2VyLnJiZF9kYXRhX3Bvb2xfbmFtZSkKICAg + ICAgICBzZWxmLnZhbGlkYXRlX3JhZG9zX25hbWVzcGFjZSgpCiAgICAgICAgc2VsZi5fZXhjbHVk + ZWRfa2V5cy5hZGQoIks4U19DTFVTVEVSX05BTUUiKQogICAgICAgIHNlbGYuZ2V0X2NlcGhmc19k + YXRhX3Bvb2xfZGV0YWlscygpCiAgICAgICAgIyBkb3VibGUgc3RyaW5nIG5lZWRlZCBmb3IgdXBz + dHJlYW0gZXhwb3J0cyBvZiBmbGFncwogICAgICAgIHNlbGYub3V0X21hcFsiQVJHUyJdID0gZici + e3NlbGYuZ2V0RmluYWxVc2VkQXJncygpfSInCiAgICAgICAgc2VsZi5vdXRfbWFwWyJOQU1FU1BB + Q0UiXSA9IHNlbGYuX2FyZ19wYXJzZXIubmFtZXNwYWNlCiAgICAgICAgc2VsZi5vdXRfbWFwWyJL + OFNfQ0xVU1RFUl9OQU1FIl0gPSBzZWxmLl9hcmdfcGFyc2VyLms4c19jbHVzdGVyX25hbWUKICAg + ICAgICBzZWxmLm91dF9tYXBbIlJPT0tfRVhURVJOQUxfRlNJRCJdID0gc2VsZi5nZXRfZnNpZCgp + CiAgICAgICAgc2VsZi5vdXRfbWFwWyJST09LX0VYVEVSTkFMX1VTRVJOQU1FIl0gPSBzZWxmLnJ1 + bl9hc191c2VyCiAgICAgICAgc2VsZi5vdXRfbWFwWyJST09LX0VYVEVSTkFMX0NFUEhfTU9OX0RB + VEEiXSA9IHNlbGYuZ2V0X2NlcGhfZXh0ZXJuYWxfbW9uX2RhdGEoKQogICAgICAgIHNlbGYub3V0 + X21hcFsiUk9PS19FWFRFUk5BTF9VU0VSX1NFQ1JFVCJdID0gc2VsZi5jcmVhdGVfY2hlY2tlcktl + eSgKICAgICAgICAgICAgImNsaWVudC5oZWFsdGhjaGVja2VyIgogICAgICAgICkKICAgICAgICBz + ZWxmLm91dF9tYXBbIlJPT0tfRVhURVJOQUxfREFTSEJPQVJEX0xJTksiXSA9IHNlbGYuZ2V0X2Nl + cGhfZGFzaGJvYXJkX2xpbmsoKQogICAgICAgICgKICAgICAgICAgICAgc2VsZi5vdXRfbWFwWyJD + U0lfUkJEX05PREVfU0VDUkVUIl0sCiAgICAgICAgICAgIHNlbGYub3V0X21hcFsiQ1NJX1JCRF9O + T0RFX1NFQ1JFVF9OQU1FIl0sCiAgICAgICAgKSA9IHNlbGYuY3JlYXRlX2NlcGhDU0lLZXlyaW5n + X3VzZXIoImNsaWVudC5jc2ktcmJkLW5vZGUiKQogICAgICAgICgKICAgICAgICAgICAgc2VsZi5v + dXRfbWFwWyJDU0lfUkJEX1BST1ZJU0lPTkVSX1NFQ1JFVCJdLAogICAgICAgICAgICBzZWxmLm91 + dF9tYXBbIkNTSV9SQkRfUFJPVklTSU9ORVJfU0VDUkVUX05BTUUiXSwKICAgICAgICApID0gc2Vs + Zi5jcmVhdGVfY2VwaENTSUtleXJpbmdfdXNlcigiY2xpZW50LmNzaS1yYmQtcHJvdmlzaW9uZXIi + KQogICAgICAgIHNlbGYub3V0X21hcFsiQ0VQSEZTX1BPT0xfTkFNRSJdID0gc2VsZi5fYXJnX3Bh + cnNlci5jZXBoZnNfZGF0YV9wb29sX25hbWUKICAgICAgICBzZWxmLm91dF9tYXBbIkNFUEhGU19N + RVRBREFUQV9QT09MX05BTUUiXSA9ICgKICAgICAgICAgICAgc2VsZi5fYXJnX3BhcnNlci5jZXBo + ZnNfbWV0YWRhdGFfcG9vbF9uYW1lCiAgICAgICAgKQogICAgICAgIHNlbGYub3V0X21hcFsiQ0VQ + SEZTX0ZTX05BTUUiXSA9IHNlbGYuX2FyZ19wYXJzZXIuY2VwaGZzX2ZpbGVzeXN0ZW1fbmFtZQog + ICAgICAgIHNlbGYub3V0X21hcFsiUkVTVFJJQ1RFRF9BVVRIX1BFUk1JU1NJT04iXSA9ICgKICAg + ICAgICAgICAgc2VsZi5fYXJnX3BhcnNlci5yZXN0cmljdGVkX2F1dGhfcGVybWlzc2lvbgogICAg + ICAgICkKICAgICAgICBzZWxmLm91dF9tYXBbIlJBRE9TX05BTUVTUEFDRSJdID0gc2VsZi5fYXJn + X3BhcnNlci5yYWRvc19uYW1lc3BhY2UKICAgICAgICBzZWxmLm91dF9tYXBbIlNVQlZPTFVNRV9H + Uk9VUCJdID0gc2VsZi5fYXJnX3BhcnNlci5zdWJ2b2x1bWVfZ3JvdXAKICAgICAgICBzZWxmLm91 + dF9tYXBbIkNTSV9DRVBIRlNfTk9ERV9TRUNSRVQiXSA9ICIiCiAgICAgICAgc2VsZi5vdXRfbWFw + WyJDU0lfQ0VQSEZTX1BST1ZJU0lPTkVSX1NFQ1JFVCJdID0gIiIKICAgICAgICAjIGNyZWF0ZSBD + ZXBoRlMgbm9kZSBhbmQgcHJvdmlzaW9uZXIga2V5cmluZyBvbmx5IHdoZW4gTURTIGV4aXN0cwog + ICAgICAgIGlmIHNlbGYub3V0X21hcFsiQ0VQSEZTX0ZTX05BTUUiXSBhbmQgc2VsZi5vdXRfbWFw + WyJDRVBIRlNfUE9PTF9OQU1FIl06CiAgICAgICAgICAgICgKICAgICAgICAgICAgICAgIHNlbGYu + b3V0X21hcFsiQ1NJX0NFUEhGU19OT0RFX1NFQ1JFVCJdLAogICAgICAgICAgICAgICAgc2VsZi5v + dXRfbWFwWyJDU0lfQ0VQSEZTX05PREVfU0VDUkVUX05BTUUiXSwKICAgICAgICAgICAgKSA9IHNl + bGYuY3JlYXRlX2NlcGhDU0lLZXlyaW5nX3VzZXIoImNsaWVudC5jc2ktY2VwaGZzLW5vZGUiKQog + ICAgICAgICAgICAoCiAgICAgICAgICAgICAgICBzZWxmLm91dF9tYXBbIkNTSV9DRVBIRlNfUFJP + VklTSU9ORVJfU0VDUkVUIl0sCiAgICAgICAgICAgICAgICBzZWxmLm91dF9tYXBbIkNTSV9DRVBI + RlNfUFJPVklTSU9ORVJfU0VDUkVUX05BTUUiXSwKICAgICAgICAgICAgKSA9IHNlbGYuY3JlYXRl + X2NlcGhDU0lLZXlyaW5nX3VzZXIoImNsaWVudC5jc2ktY2VwaGZzLXByb3Zpc2lvbmVyIikKICAg + ICAgICAgICAgIyBjcmVhdGUgdGhlIGRlZmF1bHQgImNzaSIgc3Vidm9sdW1lZ3JvdXAKICAgICAg + ICAgICAgc2VsZi5nZXRfb3JfY3JlYXRlX3N1YnZvbHVtZV9ncm91cCgKICAgICAgICAgICAgICAg + ICJjc2kiLCBzZWxmLl9hcmdfcGFyc2VyLmNlcGhmc19maWxlc3lzdGVtX25hbWUKICAgICAgICAg + ICAgKQogICAgICAgICAgICAjIHBpbiB0aGUgZGVmYXVsdCAiY3NpIiBzdWJ2b2x1bWVncm91cAog + ICAgICAgICAgICBzZWxmLnBpbl9zdWJ2b2x1bWUoCiAgICAgICAgICAgICAgICAiY3NpIiwgc2Vs + Zi5fYXJnX3BhcnNlci5jZXBoZnNfZmlsZXN5c3RlbV9uYW1lLCAiZGlzdHJpYnV0ZWQiLCAiMSIK + ICAgICAgICAgICAgKQogICAgICAgICAgICBpZiBzZWxmLm91dF9tYXBbIlNVQlZPTFVNRV9HUk9V + UCJdOgogICAgICAgICAgICAgICAgc2VsZi5nZXRfb3JfY3JlYXRlX3N1YnZvbHVtZV9ncm91cCgK + ICAgICAgICAgICAgICAgICAgICBzZWxmLl9hcmdfcGFyc2VyLnN1YnZvbHVtZV9ncm91cCwKICAg + ICAgICAgICAgICAgICAgICBzZWxmLl9hcmdfcGFyc2VyLmNlcGhmc19maWxlc3lzdGVtX25hbWUs + CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICBzZWxmLnBpbl9zdWJ2b2x1bWUoCiAg + ICAgICAgICAgICAgICAgICAgc2VsZi5fYXJnX3BhcnNlci5zdWJ2b2x1bWVfZ3JvdXAsCiAgICAg + ICAgICAgICAgICAgICAgc2VsZi5fYXJnX3BhcnNlci5jZXBoZnNfZmlsZXN5c3RlbV9uYW1lLAog + ICAgICAgICAgICAgICAgICAgICJkaXN0cmlidXRlZCIsCiAgICAgICAgICAgICAgICAgICAgIjEi + LAogICAgICAgICAgICAgICAgKQogICAgICAgIHNlbGYub3V0X21hcFsiUkdXX1RMU19DRVJUIl0g + PSAiIgogICAgICAgIHNlbGYub3V0X21hcFsiTU9OSVRPUklOR19FTkRQT0lOVCJdID0gIiIKICAg + ICAgICBzZWxmLm91dF9tYXBbIk1PTklUT1JJTkdfRU5EUE9JTlRfUE9SVCJdID0gIiIKICAgICAg + ICBpZiBub3Qgc2VsZi5fYXJnX3BhcnNlci5za2lwX21vbml0b3JpbmdfZW5kcG9pbnQ6CiAgICAg + ICAgICAgICgKICAgICAgICAgICAgICAgIHNlbGYub3V0X21hcFsiTU9OSVRPUklOR19FTkRQT0lO + VCJdLAogICAgICAgICAgICAgICAgc2VsZi5vdXRfbWFwWyJNT05JVE9SSU5HX0VORFBPSU5UX1BP + UlQiXSwKICAgICAgICAgICAgKSA9IHNlbGYuZ2V0X2FjdGl2ZV9hbmRfc3RhbmRieV9tZ3JzKCkK + ICAgICAgICBzZWxmLm91dF9tYXBbIlJCRF9QT09MX05BTUUiXSA9IHNlbGYuX2FyZ19wYXJzZXIu + cmJkX2RhdGFfcG9vbF9uYW1lCiAgICAgICAgc2VsZi5vdXRfbWFwWyJSQkRfTUVUQURBVEFfRUNf + UE9PTF9OQU1FIl0gPSAoCiAgICAgICAgICAgIHNlbGYudmFsaWRhdGVfcmJkX21ldGFkYXRhX2Vj + X3Bvb2xfbmFtZSgpCiAgICAgICAgKQogICAgICAgIHNlbGYub3V0X21hcFsiVE9QT0xPR1lfUE9P + TFMiXSA9IHNlbGYuX2FyZ19wYXJzZXIudG9wb2xvZ3lfcG9vbHMKICAgICAgICBzZWxmLm91dF9t + YXBbIlRPUE9MT0dZX0ZBSUxVUkVfRE9NQUlOX0xBQkVMIl0gPSAoCiAgICAgICAgICAgIHNlbGYu + X2FyZ19wYXJzZXIudG9wb2xvZ3lfZmFpbHVyZV9kb21haW5fbGFiZWwKICAgICAgICApCiAgICAg + ICAgc2VsZi5vdXRfbWFwWyJUT1BPTE9HWV9GQUlMVVJFX0RPTUFJTl9WQUxVRVMiXSA9ICgKICAg + ICAgICAgICAgc2VsZi5fYXJnX3BhcnNlci50b3BvbG9neV9mYWlsdXJlX2RvbWFpbl92YWx1ZXMK + ICAgICAgICApCiAgICAgICAgaWYgKAogICAgICAgICAgICBzZWxmLl9hcmdfcGFyc2VyLnRvcG9s + b2d5X3Bvb2xzICE9ICIiCiAgICAgICAgICAgIGFuZCBzZWxmLl9hcmdfcGFyc2VyLnRvcG9sb2d5 + X2ZhaWx1cmVfZG9tYWluX2xhYmVsICE9ICIiCiAgICAgICAgICAgIGFuZCBzZWxmLl9hcmdfcGFy + c2VyLnRvcG9sb2d5X2ZhaWx1cmVfZG9tYWluX3ZhbHVlcyAhPSAiIgogICAgICAgICk6CiAgICAg + ICAgICAgIHNlbGYudmFsaWRhdGVfdG9wb2xvZ3lfdmFsdWVzKAogICAgICAgICAgICAgICAgc2Vs + Zi5jb252ZXJ0X2NvbW1hX3NlcGFyYXRlZF90b19hcnJheShzZWxmLm91dF9tYXBbIlRPUE9MT0dZ + X1BPT0xTIl0pLAogICAgICAgICAgICAgICAgc2VsZi5jb252ZXJ0X2NvbW1hX3NlcGFyYXRlZF90 + b19hcnJheSgKICAgICAgICAgICAgICAgICAgICBzZWxmLm91dF9tYXBbIlRPUE9MT0dZX0ZBSUxV + UkVfRE9NQUlOX1ZBTFVFUyJdCiAgICAgICAgICAgICAgICApLAogICAgICAgICAgICApCiAgICAg + ICAgICAgIHNlbGYudmFsaWRhdGVfdG9wb2xvZ3lfcmJkX3Bvb2xzKAogICAgICAgICAgICAgICAg + c2VsZi5jb252ZXJ0X2NvbW1hX3NlcGFyYXRlZF90b19hcnJheShzZWxmLm91dF9tYXBbIlRPUE9M + T0dZX1BPT0xTIl0pCiAgICAgICAgICAgICkKICAgICAgICAgICAgc2VsZi5pbml0X3RvcG9sb2d5 + X3JiZF9wb29scygKICAgICAgICAgICAgICAgIHNlbGYuY29udmVydF9jb21tYV9zZXBhcmF0ZWRf + dG9fYXJyYXkoc2VsZi5vdXRfbWFwWyJUT1BPTE9HWV9QT09MUyJdKQogICAgICAgICAgICApCiAg + ICAgICAgZWxzZToKICAgICAgICAgICAgc2VsZi5yYWlzZV9leGNlcHRpb25faWZfYW55X3RvcG9s + b2d5X2ZsYWdfaXNfbWlzc2luZygpCgogICAgICAgIHNlbGYub3V0X21hcFsiUkdXX1BPT0xfUFJF + RklYIl0gPSBzZWxmLl9hcmdfcGFyc2VyLnJnd19wb29sX3ByZWZpeAogICAgICAgIHNlbGYub3V0 + X21hcFsiUkdXX0VORFBPSU5UIl0gPSAiIgogICAgICAgIGlmIHNlbGYuX2FyZ19wYXJzZXIucmd3 + X2VuZHBvaW50OgogICAgICAgICAgICBpZiBzZWxmLl9hcmdfcGFyc2VyLmRyeV9ydW46CiAgICAg + ICAgICAgICAgICBzZWxmLmNyZWF0ZV9yZ3dfYWRtaW5fb3BzX3VzZXIoKQogICAgICAgICAgICBl + bHNlOgogICAgICAgICAgICAgICAgaWYgKAogICAgICAgICAgICAgICAgICAgIHNlbGYuX2FyZ19w + YXJzZXIucmd3X3JlYWxtX25hbWUgIT0gIiIKICAgICAgICAgICAgICAgICAgICBhbmQgc2VsZi5f + YXJnX3BhcnNlci5yZ3dfem9uZWdyb3VwX25hbWUgIT0gIiIKICAgICAgICAgICAgICAgICAgICBh + bmQgc2VsZi5fYXJnX3BhcnNlci5yZ3dfem9uZV9uYW1lICE9ICIiCiAgICAgICAgICAgICAgICAp + OgogICAgICAgICAgICAgICAgICAgIGVyciA9IHNlbGYudmFsaWRhdGVfcmd3X211bHRpc2l0ZSgK + ICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5fYXJnX3BhcnNlci5yZ3dfcmVhbG1fbmFtZSwg + InJlYWxtIgogICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICBlcnIgPSBz + ZWxmLnZhbGlkYXRlX3Jnd19tdWx0aXNpdGUoCiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYu + X2FyZ19wYXJzZXIucmd3X3pvbmVncm91cF9uYW1lLCAiem9uZWdyb3VwIgogICAgICAgICAgICAg + ICAgICAgICkKICAgICAgICAgICAgICAgICAgICBlcnIgPSBzZWxmLnZhbGlkYXRlX3Jnd19tdWx0 + aXNpdGUoCiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIucmd3X3pvbmVf + bmFtZSwgInpvbmUiCiAgICAgICAgICAgICAgICAgICAgKQoKICAgICAgICAgICAgICAgIGlmICgK + ICAgICAgICAgICAgICAgICAgICBzZWxmLl9hcmdfcGFyc2VyLnJnd19yZWFsbV9uYW1lID09ICIi + CiAgICAgICAgICAgICAgICAgICAgYW5kIHNlbGYuX2FyZ19wYXJzZXIucmd3X3pvbmVncm91cF9u + YW1lID09ICIiCiAgICAgICAgICAgICAgICAgICAgYW5kIHNlbGYuX2FyZ19wYXJzZXIucmd3X3pv + bmVfbmFtZSA9PSAiIgogICAgICAgICAgICAgICAgKSBvciAoCiAgICAgICAgICAgICAgICAgICAg + c2VsZi5fYXJnX3BhcnNlci5yZ3dfcmVhbG1fbmFtZSAhPSAiIgogICAgICAgICAgICAgICAgICAg + IGFuZCBzZWxmLl9hcmdfcGFyc2VyLnJnd196b25lZ3JvdXBfbmFtZSAhPSAiIgogICAgICAgICAg + ICAgICAgICAgIGFuZCBzZWxmLl9hcmdfcGFyc2VyLnJnd196b25lX25hbWUgIT0gIiIKICAgICAg + ICAgICAgICAgICk6CiAgICAgICAgICAgICAgICAgICAgKAogICAgICAgICAgICAgICAgICAgICAg + ICBzZWxmLm91dF9tYXBbIlJHV19BRE1JTl9PUFNfVVNFUl9BQ0NFU1NfS0VZIl0sCiAgICAgICAg + ICAgICAgICAgICAgICAgIHNlbGYub3V0X21hcFsiUkdXX0FETUlOX09QU19VU0VSX1NFQ1JFVF9L + RVkiXSwKICAgICAgICAgICAgICAgICAgICAgICAgaW5mb19jYXBfc3VwcG9ydGVkLAogICAgICAg + ICAgICAgICAgICAgICAgICBlcnIsCiAgICAgICAgICAgICAgICAgICAgKSA9IHNlbGYuY3JlYXRl + X3Jnd19hZG1pbl9vcHNfdXNlcigpCiAgICAgICAgICAgICAgICAgICAgZXJyID0gc2VsZi52YWxp + ZGF0ZV9yZ3dfZW5kcG9pbnQoaW5mb19jYXBfc3VwcG9ydGVkKQogICAgICAgICAgICAgICAgICAg + IGlmIHNlbGYuX2FyZ19wYXJzZXIucmd3X3Rsc19jZXJ0X3BhdGg6CiAgICAgICAgICAgICAgICAg + ICAgICAgIHNlbGYub3V0X21hcFsiUkdXX1RMU19DRVJUIl0gPSAoCiAgICAgICAgICAgICAgICAg + ICAgICAgICAgICBzZWxmLnZhbGlkYXRlX3Jnd19lbmRwb2ludF90bHNfY2VydCgpCiAgICAgICAg + ICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAjIGlmIHRoZXJlIGlzIG5vIGVy + cm9yLCBzZXQgdGhlIFJHV19FTkRQT0lOVAogICAgICAgICAgICAgICAgICAgIGlmIGVyciAhPSAi + LTEiOgogICAgICAgICAgICAgICAgICAgICAgICBzZWxmLm91dF9tYXBbIlJHV19FTkRQT0lOVCJd + ID0gc2VsZi5fYXJnX3BhcnNlci5yZ3dfZW5kcG9pbnQKICAgICAgICAgICAgICAgIGVsc2U6CiAg + ICAgICAgICAgICAgICAgICAgZXJyID0gIlBsZWFzZSBwcm92aWRlIGFsbCB0aGUgUkdXIG11bHRp + c2l0ZSBwYXJhbWV0ZXJzIG9yIG5vbmUgb2YgdGhlbSIKICAgICAgICAgICAgICAgICAgICBzeXMu + c3RkZXJyLndyaXRlKGVycikKCiAgICBkZWYgZ2VuX3NoZWxsX291dChzZWxmKToKICAgICAgICBz + ZWxmLl9nZW5fb3V0cHV0X21hcCgpCiAgICAgICAgc2hPdXRJTyA9IFN0cmluZ0lPKCkKICAgICAg + ICBmb3IgaywgdiBpbiBzZWxmLm91dF9tYXAuaXRlbXMoKToKICAgICAgICAgICAgaWYgdiBhbmQg + ayBub3QgaW4gc2VsZi5fZXhjbHVkZWRfa2V5czoKICAgICAgICAgICAgICAgIHNoT3V0SU8ud3Jp + dGUoZiJleHBvcnQge2t9PXt2fXtMSU5FU0VQfSIpCiAgICAgICAgc2hPdXQgPSBzaE91dElPLmdl + dHZhbHVlKCkKICAgICAgICBzaE91dElPLmNsb3NlKCkKICAgICAgICByZXR1cm4gc2hPdXQKCiAg + ICBkZWYgZ2VuX2pzb25fb3V0KHNlbGYpOgogICAgICAgIHNlbGYuX2dlbl9vdXRwdXRfbWFwKCkK + ICAgICAgICBpZiBzZWxmLl9hcmdfcGFyc2VyLmRyeV9ydW46CiAgICAgICAgICAgIHJldHVybiAi + IgogICAgICAgIGpzb25fb3V0ID0gWwogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAibmFt + ZSI6ICJleHRlcm5hbC1jbHVzdGVyLXVzZXItY29tbWFuZCIsCiAgICAgICAgICAgICAgICAia2lu + ZCI6ICJDb25maWdNYXAiLAogICAgICAgICAgICAgICAgImRhdGEiOiB7CiAgICAgICAgICAgICAg + ICAgICAgImFyZ3MiOiBzZWxmLm91dF9tYXBbIkFSR1MiXSwKICAgICAgICAgICAgICAgIH0sCiAg + ICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJuYW1lIjogInJvb2st + Y2VwaC1tb24tZW5kcG9pbnRzIiwKICAgICAgICAgICAgICAgICJraW5kIjogIkNvbmZpZ01hcCIs + CiAgICAgICAgICAgICAgICAiZGF0YSI6IHsKICAgICAgICAgICAgICAgICAgICAiZGF0YSI6IHNl + bGYub3V0X21hcFsiUk9PS19FWFRFUk5BTF9DRVBIX01PTl9EQVRBIl0sCiAgICAgICAgICAgICAg + ICAgICAgIm1heE1vbklkIjogIjAiLAogICAgICAgICAgICAgICAgICAgICJtYXBwaW5nIjogInt9 + IiwKICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAg + ICAgICAgICAgICJuYW1lIjogInJvb2stY2VwaC1tb24iLAogICAgICAgICAgICAgICAgImtpbmQi + OiAiU2VjcmV0IiwKICAgICAgICAgICAgICAgICJkYXRhIjogewogICAgICAgICAgICAgICAgICAg + ICJhZG1pbi1zZWNyZXQiOiAiYWRtaW4tc2VjcmV0IiwKICAgICAgICAgICAgICAgICAgICAiZnNp + ZCI6IHNlbGYub3V0X21hcFsiUk9PS19FWFRFUk5BTF9GU0lEIl0sCiAgICAgICAgICAgICAgICAg + ICAgIm1vbi1zZWNyZXQiOiAibW9uLXNlY3JldCIsCiAgICAgICAgICAgICAgICB9LAogICAgICAg + ICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAibmFtZSI6ICJyb29rLWNlcGgt + b3BlcmF0b3ItY3JlZHMiLAogICAgICAgICAgICAgICAgImtpbmQiOiAiU2VjcmV0IiwKICAgICAg + ICAgICAgICAgICJkYXRhIjogewogICAgICAgICAgICAgICAgICAgICJ1c2VySUQiOiBzZWxmLm91 + dF9tYXBbIlJPT0tfRVhURVJOQUxfVVNFUk5BTUUiXSwKICAgICAgICAgICAgICAgICAgICAidXNl + cktleSI6IHNlbGYub3V0X21hcFsiUk9PS19FWFRFUk5BTF9VU0VSX1NFQ1JFVCJdLAogICAgICAg + ICAgICAgICAgfSwKICAgICAgICAgICAgfSwKICAgICAgICBdCgogICAgICAgICMgaWYgJ01PTklU + T1JJTkdfRU5EUE9JTlQnIGV4aXN0cywgdGhlbiBvbmx5IGFkZCAnbW9uaXRvcmluZy1lbmRwb2lu + dCcgdG8gQ2x1c3RlcgogICAgICAgIGlmICgKICAgICAgICAgICAgc2VsZi5vdXRfbWFwWyJNT05J + VE9SSU5HX0VORFBPSU5UIl0KICAgICAgICAgICAgYW5kIHNlbGYub3V0X21hcFsiTU9OSVRPUklO + R19FTkRQT0lOVF9QT1JUIl0KICAgICAgICApOgogICAgICAgICAgICBqc29uX291dC5hcHBlbmQo + CiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgIm5hbWUiOiAibW9uaXRvcmlu + Zy1lbmRwb2ludCIsCiAgICAgICAgICAgICAgICAgICAgImtpbmQiOiAiQ2VwaENsdXN0ZXIiLAog + ICAgICAgICAgICAgICAgICAgICJkYXRhIjogewogICAgICAgICAgICAgICAgICAgICAgICAiTW9u + aXRvcmluZ0VuZHBvaW50Ijogc2VsZi5vdXRfbWFwWyJNT05JVE9SSU5HX0VORFBPSU5UIl0sCiAg + ICAgICAgICAgICAgICAgICAgICAgICJNb25pdG9yaW5nUG9ydCI6IHNlbGYub3V0X21hcFsiTU9O + SVRPUklOR19FTkRQT0lOVF9QT1JUIl0sCiAgICAgICAgICAgICAgICAgICAgfSwKICAgICAgICAg + ICAgICAgIH0KICAgICAgICAgICAgKQoKICAgICAgICAjIGlmICdDU0lfUkJEX05PREVfU0VDUkVU + JyBleGlzdHMsIHRoZW4gb25seSBhZGQgJ3Jvb2stY3NpLXJiZC1wcm92aXNpb25lcicgU2VjcmV0 + CiAgICAgICAgaWYgKAogICAgICAgICAgICBzZWxmLm91dF9tYXBbIkNTSV9SQkRfTk9ERV9TRUNS + RVQiXQogICAgICAgICAgICBhbmQgc2VsZi5vdXRfbWFwWyJDU0lfUkJEX05PREVfU0VDUkVUX05B + TUUiXQogICAgICAgICk6CiAgICAgICAgICAgIGpzb25fb3V0LmFwcGVuZCgKICAgICAgICAgICAg + ICAgIHsKICAgICAgICAgICAgICAgICAgICAibmFtZSI6IGYicm9vay17c2VsZi5vdXRfbWFwWydD + U0lfUkJEX05PREVfU0VDUkVUX05BTUUnXX0iLAogICAgICAgICAgICAgICAgICAgICJraW5kIjog + IlNlY3JldCIsCiAgICAgICAgICAgICAgICAgICAgImRhdGEiOiB7CiAgICAgICAgICAgICAgICAg + ICAgICAgICJ1c2VySUQiOiBzZWxmLm91dF9tYXBbIkNTSV9SQkRfTk9ERV9TRUNSRVRfTkFNRSJd + LAogICAgICAgICAgICAgICAgICAgICAgICAidXNlcktleSI6IHNlbGYub3V0X21hcFsiQ1NJX1JC + RF9OT0RFX1NFQ1JFVCJdLAogICAgICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICB9 + CiAgICAgICAgICAgICkKICAgICAgICAjIGlmICdDU0lfUkJEX1BST1ZJU0lPTkVSX1NFQ1JFVCcg + ZXhpc3RzLCB0aGVuIG9ubHkgYWRkICdyb29rLWNzaS1yYmQtcHJvdmlzaW9uZXInIFNlY3JldAog + ICAgICAgIGlmICgKICAgICAgICAgICAgc2VsZi5vdXRfbWFwWyJDU0lfUkJEX1BST1ZJU0lPTkVS + X1NFQ1JFVCJdCiAgICAgICAgICAgIGFuZCBzZWxmLm91dF9tYXBbIkNTSV9SQkRfUFJPVklTSU9O + RVJfU0VDUkVUX05BTUUiXQogICAgICAgICk6CiAgICAgICAgICAgIGpzb25fb3V0LmFwcGVuZCgK + ICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAibmFtZSI6IGYicm9vay17c2Vs + Zi5vdXRfbWFwWydDU0lfUkJEX1BST1ZJU0lPTkVSX1NFQ1JFVF9OQU1FJ119IiwKICAgICAgICAg ICAgICAgICAgICAia2luZCI6ICJTZWNyZXQiLAogICAgICAgICAgICAgICAgICAgICJkYXRhIjog ewogICAgICAgICAgICAgICAgICAgICAgICAidXNlcklEIjogc2VsZi5vdXRfbWFwWyJDU0lfUkJE - X05PREVfU0VDUkVUX05BTUUiXSwKICAgICAgICAgICAgICAgICAgICAgICAgInVzZXJLZXkiOiBz - ZWxmLm91dF9tYXBbIkNTSV9SQkRfTk9ERV9TRUNSRVQiXSwKICAgICAgICAgICAgICAgICAgICB9 - LAogICAgICAgICAgICAgICAgfQogICAgICAgICAgICApCiAgICAgICAgIyBpZiAnQ1NJX1JCRF9Q - Uk9WSVNJT05FUl9TRUNSRVQnIGV4aXN0cywgdGhlbiBvbmx5IGFkZCAncm9vay1jc2ktcmJkLXBy - b3Zpc2lvbmVyJyBTZWNyZXQKICAgICAgICBpZiAoCiAgICAgICAgICAgIHNlbGYub3V0X21hcFsi - Q1NJX1JCRF9QUk9WSVNJT05FUl9TRUNSRVQiXQogICAgICAgICAgICBhbmQgc2VsZi5vdXRfbWFw - WyJDU0lfUkJEX1BST1ZJU0lPTkVSX1NFQ1JFVF9OQU1FIl0KICAgICAgICApOgogICAgICAgICAg - ICBqc29uX291dC5hcHBlbmQoCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAg - Im5hbWUiOiBmInJvb2ste3NlbGYub3V0X21hcFsnQ1NJX1JCRF9QUk9WSVNJT05FUl9TRUNSRVRf - TkFNRSddfSIsCiAgICAgICAgICAgICAgICAgICAgImtpbmQiOiAiU2VjcmV0IiwKICAgICAgICAg - ICAgICAgICAgICAiZGF0YSI6IHsKICAgICAgICAgICAgICAgICAgICAgICAgInVzZXJJRCI6IHNl - bGYub3V0X21hcFsiQ1NJX1JCRF9QUk9WSVNJT05FUl9TRUNSRVRfTkFNRSJdLAogICAgICAgICAg - ICAgICAgICAgICAgICAidXNlcktleSI6IHNlbGYub3V0X21hcFsiQ1NJX1JCRF9QUk9WSVNJT05F - Ul9TRUNSRVQiXSwKICAgICAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAgfQogICAg - ICAgICAgICApCiAgICAgICAgIyBpZiAnQ1NJX0NFUEhGU19QUk9WSVNJT05FUl9TRUNSRVQnIGV4 - aXN0cywgdGhlbiBvbmx5IGFkZCAncm9vay1jc2ktY2VwaGZzLXByb3Zpc2lvbmVyJyBTZWNyZXQK - ICAgICAgICBpZiAoCiAgICAgICAgICAgIHNlbGYub3V0X21hcFsiQ1NJX0NFUEhGU19QUk9WSVNJ - T05FUl9TRUNSRVQiXQogICAgICAgICAgICBhbmQgc2VsZi5vdXRfbWFwWyJDU0lfQ0VQSEZTX1BS - T1ZJU0lPTkVSX1NFQ1JFVF9OQU1FIl0KICAgICAgICApOgogICAgICAgICAgICBqc29uX291dC5h - cHBlbmQoCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgIm5hbWUiOiBmInJv - b2ste3NlbGYub3V0X21hcFsnQ1NJX0NFUEhGU19QUk9WSVNJT05FUl9TRUNSRVRfTkFNRSddfSIs - CiAgICAgICAgICAgICAgICAgICAgImtpbmQiOiAiU2VjcmV0IiwKICAgICAgICAgICAgICAgICAg - ICAiZGF0YSI6IHsKICAgICAgICAgICAgICAgICAgICAgICAgImFkbWluSUQiOiBzZWxmLm91dF9t - YXBbIkNTSV9DRVBIRlNfUFJPVklTSU9ORVJfU0VDUkVUX05BTUUiXSwKICAgICAgICAgICAgICAg - ICAgICAgICAgImFkbWluS2V5Ijogc2VsZi5vdXRfbWFwWyJDU0lfQ0VQSEZTX1BST1ZJU0lPTkVS - X1NFQ1JFVCJdLAogICAgICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICB9CiAgICAg - ICAgICAgICkKICAgICAgICAjIGlmICdDU0lfQ0VQSEZTX05PREVfU0VDUkVUJyBleGlzdHMsIHRo - ZW4gb25seSBhZGQgJ3Jvb2stY3NpLWNlcGhmcy1ub2RlJyBTZWNyZXQKICAgICAgICBpZiAoCiAg - ICAgICAgICAgIHNlbGYub3V0X21hcFsiQ1NJX0NFUEhGU19OT0RFX1NFQ1JFVCJdCiAgICAgICAg - ICAgIGFuZCBzZWxmLm91dF9tYXBbIkNTSV9DRVBIRlNfTk9ERV9TRUNSRVRfTkFNRSJdCiAgICAg - ICAgKToKICAgICAgICAgICAganNvbl9vdXQuYXBwZW5kKAogICAgICAgICAgICAgICAgewogICAg - ICAgICAgICAgICAgICAgICJuYW1lIjogZiJyb29rLXtzZWxmLm91dF9tYXBbJ0NTSV9DRVBIRlNf - Tk9ERV9TRUNSRVRfTkFNRSddfSIsCiAgICAgICAgICAgICAgICAgICAgImtpbmQiOiAiU2VjcmV0 - IiwKICAgICAgICAgICAgICAgICAgICAiZGF0YSI6IHsKICAgICAgICAgICAgICAgICAgICAgICAg - ImFkbWluSUQiOiBzZWxmLm91dF9tYXBbIkNTSV9DRVBIRlNfTk9ERV9TRUNSRVRfTkFNRSJdLAog - ICAgICAgICAgICAgICAgICAgICAgICAiYWRtaW5LZXkiOiBzZWxmLm91dF9tYXBbIkNTSV9DRVBI - RlNfTk9ERV9TRUNSRVQiXSwKICAgICAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAg - fQogICAgICAgICAgICApCiAgICAgICAgIyBpZiAnUk9PS19FWFRFUk5BTF9EQVNIQk9BUkRfTElO - SycgZXhpc3RzLCB0aGVuIG9ubHkgYWRkICdyb29rLWNlcGgtZGFzaGJvYXJkLWxpbmsnIFNlY3Jl - dAogICAgICAgIGlmIHNlbGYub3V0X21hcFsiUk9PS19FWFRFUk5BTF9EQVNIQk9BUkRfTElOSyJd - OgogICAgICAgICAgICBqc29uX291dC5hcHBlbmQoCiAgICAgICAgICAgICAgICB7CiAgICAgICAg - ICAgICAgICAgICAgIm5hbWUiOiAicm9vay1jZXBoLWRhc2hib2FyZC1saW5rIiwKICAgICAgICAg - ICAgICAgICAgICAia2luZCI6ICJTZWNyZXQiLAogICAgICAgICAgICAgICAgICAgICJkYXRhIjog - ewogICAgICAgICAgICAgICAgICAgICAgICAidXNlcklEIjogImNlcGgtZGFzaGJvYXJkLWxpbmsi - LAogICAgICAgICAgICAgICAgICAgICAgICAidXNlcktleSI6IHNlbGYub3V0X21hcFsiUk9PS19F - WFRFUk5BTF9EQVNIQk9BUkRfTElOSyJdLAogICAgICAgICAgICAgICAgICAgIH0sCiAgICAgICAg - ICAgICAgICB9CiAgICAgICAgICAgICkKICAgICAgICAjIGlmICdSQURPU19OQU1FU1BBQ0UnIGV4 - aXN0cywgdGhlbiBvbmx5IGFkZCB0aGUgIlJBRE9TX05BTUVTUEFDRSIgbmFtZXNwYWNlCiAgICAg - ICAgaWYgKAogICAgICAgICAgICBzZWxmLm91dF9tYXBbIlJBRE9TX05BTUVTUEFDRSJdCiAgICAg - ICAgICAgIGFuZCBzZWxmLm91dF9tYXBbIlJFU1RSSUNURURfQVVUSF9QRVJNSVNTSU9OIl0KICAg - ICAgICAgICAgYW5kIG5vdCBzZWxmLm91dF9tYXBbIlJCRF9NRVRBREFUQV9FQ19QT09MX05BTUUi - XQogICAgICAgICk6CiAgICAgICAgICAgIGpzb25fb3V0LmFwcGVuZCgKICAgICAgICAgICAgICAg - IHsKICAgICAgICAgICAgICAgICAgICAibmFtZSI6ICJyYWRvcy1uYW1lc3BhY2UiLAogICAgICAg - ICAgICAgICAgICAgICJraW5kIjogIkNlcGhCbG9ja1Bvb2xSYWRvc05hbWVzcGFjZSIsCiAgICAg - ICAgICAgICAgICAgICAgImRhdGEiOiB7CiAgICAgICAgICAgICAgICAgICAgICAgICJyYWRvc05h - bWVzcGFjZU5hbWUiOiBzZWxmLm91dF9tYXBbIlJBRE9TX05BTUVTUEFDRSJdLAogICAgICAgICAg - ICAgICAgICAgICAgICAicG9vbCI6IHNlbGYub3V0X21hcFsiUkJEX1BPT0xfTkFNRSJdLAogICAg - ICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICkKICAgICAg + X1BST1ZJU0lPTkVSX1NFQ1JFVF9OQU1FIl0sCiAgICAgICAgICAgICAgICAgICAgICAgICJ1c2Vy + S2V5Ijogc2VsZi5vdXRfbWFwWyJDU0lfUkJEX1BST1ZJU0lPTkVSX1NFQ1JFVCJdLAogICAgICAg + ICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICkKICAgICAgICAj + IGlmICdDU0lfQ0VQSEZTX1BST1ZJU0lPTkVSX1NFQ1JFVCcgZXhpc3RzLCB0aGVuIG9ubHkgYWRk + ICdyb29rLWNzaS1jZXBoZnMtcHJvdmlzaW9uZXInIFNlY3JldAogICAgICAgIGlmICgKICAgICAg + ICAgICAgc2VsZi5vdXRfbWFwWyJDU0lfQ0VQSEZTX1BST1ZJU0lPTkVSX1NFQ1JFVCJdCiAgICAg + ICAgICAgIGFuZCBzZWxmLm91dF9tYXBbIkNTSV9DRVBIRlNfUFJPVklTSU9ORVJfU0VDUkVUX05B + TUUiXQogICAgICAgICk6CiAgICAgICAgICAgIGpzb25fb3V0LmFwcGVuZCgKICAgICAgICAgICAg + ICAgIHsKICAgICAgICAgICAgICAgICAgICAibmFtZSI6IGYicm9vay17c2VsZi5vdXRfbWFwWydD + U0lfQ0VQSEZTX1BST1ZJU0lPTkVSX1NFQ1JFVF9OQU1FJ119IiwKICAgICAgICAgICAgICAgICAg + ICAia2luZCI6ICJTZWNyZXQiLAogICAgICAgICAgICAgICAgICAgICJkYXRhIjogewogICAgICAg + ICAgICAgICAgICAgICAgICAiYWRtaW5JRCI6IHNlbGYub3V0X21hcFsiQ1NJX0NFUEhGU19QUk9W + SVNJT05FUl9TRUNSRVRfTkFNRSJdLAogICAgICAgICAgICAgICAgICAgICAgICAiYWRtaW5LZXki + OiBzZWxmLm91dF9tYXBbIkNTSV9DRVBIRlNfUFJPVklTSU9ORVJfU0VDUkVUIl0sCiAgICAgICAg + ICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgKQogICAgICAgICMg + aWYgJ0NTSV9DRVBIRlNfTk9ERV9TRUNSRVQnIGV4aXN0cywgdGhlbiBvbmx5IGFkZCAncm9vay1j + c2ktY2VwaGZzLW5vZGUnIFNlY3JldAogICAgICAgIGlmICgKICAgICAgICAgICAgc2VsZi5vdXRf + bWFwWyJDU0lfQ0VQSEZTX05PREVfU0VDUkVUIl0KICAgICAgICAgICAgYW5kIHNlbGYub3V0X21h + cFsiQ1NJX0NFUEhGU19OT0RFX1NFQ1JFVF9OQU1FIl0KICAgICAgICApOgogICAgICAgICAgICBq + c29uX291dC5hcHBlbmQoCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgIm5h + bWUiOiBmInJvb2ste3NlbGYub3V0X21hcFsnQ1NJX0NFUEhGU19OT0RFX1NFQ1JFVF9OQU1FJ119 + IiwKICAgICAgICAgICAgICAgICAgICAia2luZCI6ICJTZWNyZXQiLAogICAgICAgICAgICAgICAg + ICAgICJkYXRhIjogewogICAgICAgICAgICAgICAgICAgICAgICAiYWRtaW5JRCI6IHNlbGYub3V0 + X21hcFsiQ1NJX0NFUEhGU19OT0RFX1NFQ1JFVF9OQU1FIl0sCiAgICAgICAgICAgICAgICAgICAg + ICAgICJhZG1pbktleSI6IHNlbGYub3V0X21hcFsiQ1NJX0NFUEhGU19OT0RFX1NFQ1JFVCJdLAog + ICAgICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICkKICAg + ICAgICAjIGlmICdST09LX0VYVEVSTkFMX0RBU0hCT0FSRF9MSU5LJyBleGlzdHMsIHRoZW4gb25s + eSBhZGQgJ3Jvb2stY2VwaC1kYXNoYm9hcmQtbGluaycgU2VjcmV0CiAgICAgICAgaWYgc2VsZi5v + dXRfbWFwWyJST09LX0VYVEVSTkFMX0RBU0hCT0FSRF9MSU5LIl06CiAgICAgICAgICAgIGpzb25f + b3V0LmFwcGVuZCgKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAibmFtZSI6 + ICJyb29rLWNlcGgtZGFzaGJvYXJkLWxpbmsiLAogICAgICAgICAgICAgICAgICAgICJraW5kIjog + IlNlY3JldCIsCiAgICAgICAgICAgICAgICAgICAgImRhdGEiOiB7CiAgICAgICAgICAgICAgICAg + ICAgICAgICJ1c2VySUQiOiAiY2VwaC1kYXNoYm9hcmQtbGluayIsCiAgICAgICAgICAgICAgICAg + ICAgICAgICJ1c2VyS2V5Ijogc2VsZi5vdXRfbWFwWyJST09LX0VYVEVSTkFMX0RBU0hCT0FSRF9M + SU5LIl0sCiAgICAgICAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAgIH0KICAgICAgICAg + ICAgKQogICAgICAgICMgaWYgJ1JBRE9TX05BTUVTUEFDRScgZXhpc3RzLCB0aGVuIG9ubHkgYWRk + IHRoZSAiUkFET1NfTkFNRVNQQUNFIiBuYW1lc3BhY2UKICAgICAgICBpZiAoCiAgICAgICAgICAg + IHNlbGYub3V0X21hcFsiUkFET1NfTkFNRVNQQUNFIl0KICAgICAgICAgICAgYW5kIHNlbGYub3V0 + X21hcFsiUkVTVFJJQ1RFRF9BVVRIX1BFUk1JU1NJT04iXQogICAgICAgICAgICBhbmQgbm90IHNl + bGYub3V0X21hcFsiUkJEX01FVEFEQVRBX0VDX1BPT0xfTkFNRSJdCiAgICAgICAgKToKICAgICAg ICAgICAganNvbl9vdXQuYXBwZW5kKAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAg - ICAgICJuYW1lIjogImNlcGgtcmJkLXJhZG9zLW5hbWVzcGFjZSIsCiAgICAgICAgICAgICAgICAg - ICAgImtpbmQiOiAiU3RvcmFnZUNsYXNzIiwKICAgICAgICAgICAgICAgICAgICAiZGF0YSI6IHsK - ICAgICAgICAgICAgICAgICAgICAgICAgInBvb2wiOiBzZWxmLm91dF9tYXBbIlJCRF9QT09MX05B - TUUiXSwKICAgICAgICAgICAgICAgICAgICAgICAgImNzaS5zdG9yYWdlLms4cy5pby9wcm92aXNp - b25lci1zZWNyZXQtbmFtZSI6IGYicm9vay17c2VsZi5vdXRfbWFwWydDU0lfUkJEX1BST1ZJU0lP - TkVSX1NFQ1JFVF9OQU1FJ119IiwKICAgICAgICAgICAgICAgICAgICAgICAgImNzaS5zdG9yYWdl - Lms4cy5pby9jb250cm9sbGVyLWV4cGFuZC1zZWNyZXQtbmFtZSI6IGYicm9vay17c2VsZi5vdXRf - bWFwWydDU0lfUkJEX1BST1ZJU0lPTkVSX1NFQ1JFVF9OQU1FJ119IiwKICAgICAgICAgICAgICAg - ICAgICAgICAgImNzaS5zdG9yYWdlLms4cy5pby9ub2RlLXN0YWdlLXNlY3JldC1uYW1lIjogZiJy - b29rLXtzZWxmLm91dF9tYXBbJ0NTSV9SQkRfTk9ERV9TRUNSRVRfTkFNRSddfSIsCiAgICAgICAg - ICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgKQogICAgICAgIGVs - c2U6CiAgICAgICAgICAgIGlmIHNlbGYub3V0X21hcFsiUkJEX01FVEFEQVRBX0VDX1BPT0xfTkFN - RSJdOgogICAgICAgICAgICAgICAganNvbl9vdXQuYXBwZW5kKAogICAgICAgICAgICAgICAgICAg - IHsKICAgICAgICAgICAgICAgICAgICAgICAgIm5hbWUiOiAiY2VwaC1yYmQiLAogICAgICAgICAg - ICAgICAgICAgICAgICAia2luZCI6ICJTdG9yYWdlQ2xhc3MiLAogICAgICAgICAgICAgICAgICAg - ICAgICAiZGF0YSI6IHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJkYXRhUG9vbCI6IHNl - bGYub3V0X21hcFsiUkJEX1BPT0xfTkFNRSJdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAg - InBvb2wiOiBzZWxmLm91dF9tYXBbIlJCRF9NRVRBREFUQV9FQ19QT09MX05BTUUiXSwKICAgICAg - ICAgICAgICAgICAgICAgICAgICAgICJjc2kuc3RvcmFnZS5rOHMuaW8vcHJvdmlzaW9uZXItc2Vj - cmV0LW5hbWUiOiBmInJvb2ste3NlbGYub3V0X21hcFsnQ1NJX1JCRF9QUk9WSVNJT05FUl9TRUNS - RVRfTkFNRSddfSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY3NpLnN0b3JhZ2Uuazhz - LmlvL2NvbnRyb2xsZXItZXhwYW5kLXNlY3JldC1uYW1lIjogZiJyb29rLXtzZWxmLm91dF9tYXBb - J0NTSV9SQkRfUFJPVklTSU9ORVJfU0VDUkVUX05BTUUnXX0iLAogICAgICAgICAgICAgICAgICAg - ICAgICAgICAgImNzaS5zdG9yYWdlLms4cy5pby9ub2RlLXN0YWdlLXNlY3JldC1uYW1lIjogZiJy - b29rLXtzZWxmLm91dF9tYXBbJ0NTSV9SQkRfTk9ERV9TRUNSRVRfTkFNRSddfSIsCiAgICAgICAg - ICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAg - KQogICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAganNvbl9vdXQuYXBwZW5kKAogICAg - ICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAgICAgIm5hbWUiOiAiY2VwaC1y - YmQiLAogICAgICAgICAgICAgICAgICAgICAgICAia2luZCI6ICJTdG9yYWdlQ2xhc3MiLAogICAg - ICAgICAgICAgICAgICAgICAgICAiZGF0YSI6IHsKICAgICAgICAgICAgICAgICAgICAgICAgICAg - ICJwb29sIjogc2VsZi5vdXRfbWFwWyJSQkRfUE9PTF9OQU1FIl0sCiAgICAgICAgICAgICAgICAg + ICAgICJuYW1lIjogInJhZG9zLW5hbWVzcGFjZSIsCiAgICAgICAgICAgICAgICAgICAgImtpbmQi + OiAiQ2VwaEJsb2NrUG9vbFJhZG9zTmFtZXNwYWNlIiwKICAgICAgICAgICAgICAgICAgICAiZGF0 + YSI6IHsKICAgICAgICAgICAgICAgICAgICAgICAgInJhZG9zTmFtZXNwYWNlTmFtZSI6IHNlbGYu + b3V0X21hcFsiUkFET1NfTkFNRVNQQUNFIl0sCiAgICAgICAgICAgICAgICAgICAgICAgICJwb29s + Ijogc2VsZi5vdXRfbWFwWyJSQkRfUE9PTF9OQU1FIl0sCiAgICAgICAgICAgICAgICAgICAgfSwK + ICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgKQogICAgICAgICAgICBqc29uX291dC5hcHBl + bmQoCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgIm5hbWUiOiAiY2VwaC1y + YmQtcmFkb3MtbmFtZXNwYWNlIiwKICAgICAgICAgICAgICAgICAgICAia2luZCI6ICJTdG9yYWdl + Q2xhc3MiLAogICAgICAgICAgICAgICAgICAgICJkYXRhIjogewogICAgICAgICAgICAgICAgICAg + ICAgICAicG9vbCI6IHNlbGYub3V0X21hcFsiUkJEX1BPT0xfTkFNRSJdLAogICAgICAgICAgICAg ICAgICAgICAgICAiY3NpLnN0b3JhZ2UuazhzLmlvL3Byb3Zpc2lvbmVyLXNlY3JldC1uYW1lIjog ZiJyb29rLXtzZWxmLm91dF9tYXBbJ0NTSV9SQkRfUFJPVklTSU9ORVJfU0VDUkVUX05BTUUnXX0i - LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgImNzaS5zdG9yYWdlLms4cy5pby9jb250cm9s - bGVyLWV4cGFuZC1zZWNyZXQtbmFtZSI6IGYicm9vay17c2VsZi5vdXRfbWFwWydDU0lfUkJEX1BS - T1ZJU0lPTkVSX1NFQ1JFVF9OQU1FJ119IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJj - c2kuc3RvcmFnZS5rOHMuaW8vbm9kZS1zdGFnZS1zZWNyZXQtbmFtZSI6IGYicm9vay17c2VsZi5v - dXRfbWFwWydDU0lfUkJEX05PREVfU0VDUkVUX05BTUUnXX0iLAogICAgICAgICAgICAgICAgICAg - ICAgICB9LAogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKCiAgICAgICAg - IyBpZiAnVE9QT0xPR1lfUE9PTFMnLCAnVE9QT0xPR1lfRkFJTFVSRV9ET01BSU5fTEFCRUwnLCAn - VE9QT0xPR1lfRkFJTFVSRV9ET01BSU5fVkFMVUVTJyAgZXhpc3RzLAogICAgICAgICMgdGhlbiBv - bmx5IGFkZCAndG9wb2xvZ3knIFN0b3JhZ2VDbGFzcwogICAgICAgIGlmICgKICAgICAgICAgICAg - c2VsZi5vdXRfbWFwWyJUT1BPTE9HWV9QT09MUyJdCiAgICAgICAgICAgIGFuZCBzZWxmLm91dF9t - YXBbIlRPUE9MT0dZX0ZBSUxVUkVfRE9NQUlOX0xBQkVMIl0KICAgICAgICAgICAgYW5kIHNlbGYu - b3V0X21hcFsiVE9QT0xPR1lfRkFJTFVSRV9ET01BSU5fVkFMVUVTIl0KICAgICAgICApOgogICAg - ICAgICAgICBqc29uX291dC5hcHBlbmQoCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAg - ICAgICAgIm5hbWUiOiAiY2VwaC1yYmQtdG9wb2xvZ3kiLAogICAgICAgICAgICAgICAgICAgICJr - aW5kIjogIlN0b3JhZ2VDbGFzcyIsCiAgICAgICAgICAgICAgICAgICAgImRhdGEiOiB7CiAgICAg - ICAgICAgICAgICAgICAgICAgICJ0b3BvbG9neUZhaWx1cmVEb21haW5MYWJlbCI6IHNlbGYub3V0 - X21hcFsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUT1BPTE9HWV9GQUlMVVJFX0RPTUFJ - Tl9MQUJFTCIKICAgICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAg - ICAgInRvcG9sb2d5RmFpbHVyZURvbWFpblZhbHVlcyI6IHNlbGYub3V0X21hcFsKICAgICAgICAg - ICAgICAgICAgICAgICAgICAgICJUT1BPTE9HWV9GQUlMVVJFX0RPTUFJTl9WQUxVRVMiCiAgICAg - ICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgICAgICJ0b3BvbG9neVBv - b2xzIjogc2VsZi5vdXRfbWFwWyJUT1BPTE9HWV9QT09MUyJdLAogICAgICAgICAgICAgICAgICAg - ICAgICAiY3NpLnN0b3JhZ2UuazhzLmlvL3Byb3Zpc2lvbmVyLXNlY3JldC1uYW1lIjogZiJyb29r - LXtzZWxmLm91dF9tYXBbJ0NTSV9SQkRfUFJPVklTSU9ORVJfU0VDUkVUX05BTUUnXX0iLAogICAg - ICAgICAgICAgICAgICAgICAgICAiY3NpLnN0b3JhZ2UuazhzLmlvL2NvbnRyb2xsZXItZXhwYW5k - LXNlY3JldC1uYW1lIjogZiJyb29rLXtzZWxmLm91dF9tYXBbJ0NTSV9SQkRfUFJPVklTSU9ORVJf - U0VDUkVUX05BTUUnXX0iLAogICAgICAgICAgICAgICAgICAgICAgICAiY3NpLnN0b3JhZ2Uuazhz - LmlvL25vZGUtc3RhZ2Utc2VjcmV0LW5hbWUiOiBmInJvb2ste3NlbGYub3V0X21hcFsnQ1NJX1JC - RF9OT0RFX1NFQ1JFVF9OQU1FJ119IiwKICAgICAgICAgICAgICAgICAgICB9LAogICAgICAgICAg - ICAgICAgfQogICAgICAgICAgICApCgogICAgICAgICMgaWYgJ0NFUEhGU19GU19OQU1FJyBleGlz - dHMsIHRoZW4gb25seSBhZGQgJ2NlcGhmcycgU3RvcmFnZUNsYXNzCiAgICAgICAgaWYgc2VsZi5v - dXRfbWFwWyJDRVBIRlNfRlNfTkFNRSJdOgogICAgICAgICAgICBqc29uX291dC5hcHBlbmQoCiAg - ICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgIm5hbWUiOiAiY2VwaGZzIiwKICAg - ICAgICAgICAgICAgICAgICAia2luZCI6ICJTdG9yYWdlQ2xhc3MiLAogICAgICAgICAgICAgICAg - ICAgICJkYXRhIjogewogICAgICAgICAgICAgICAgICAgICAgICAiZnNOYW1lIjogc2VsZi5vdXRf - bWFwWyJDRVBIRlNfRlNfTkFNRSJdLAogICAgICAgICAgICAgICAgICAgICAgICAicG9vbCI6IHNl - bGYub3V0X21hcFsiQ0VQSEZTX1BPT0xfTkFNRSJdLAogICAgICAgICAgICAgICAgICAgICAgICAi - Y3NpLnN0b3JhZ2UuazhzLmlvL3Byb3Zpc2lvbmVyLXNlY3JldC1uYW1lIjogZiJyb29rLXtzZWxm - Lm91dF9tYXBbJ0NTSV9DRVBIRlNfUFJPVklTSU9ORVJfU0VDUkVUX05BTUUnXX0iLAogICAgICAg - ICAgICAgICAgICAgICAgICAiY3NpLnN0b3JhZ2UuazhzLmlvL2NvbnRyb2xsZXItZXhwYW5kLXNl - Y3JldC1uYW1lIjogZiJyb29rLXtzZWxmLm91dF9tYXBbJ0NTSV9DRVBIRlNfUFJPVklTSU9ORVJf - U0VDUkVUX05BTUUnXX0iLAogICAgICAgICAgICAgICAgICAgICAgICAiY3NpLnN0b3JhZ2Uuazhz - LmlvL25vZGUtc3RhZ2Utc2VjcmV0LW5hbWUiOiBmInJvb2ste3NlbGYub3V0X21hcFsnQ1NJX0NF - UEhGU19OT0RFX1NFQ1JFVF9OQU1FJ119IiwKICAgICAgICAgICAgICAgICAgICB9LAogICAgICAg - ICAgICAgICAgfQogICAgICAgICAgICApCiAgICAgICAgIyBpZiAnUkdXX0VORFBPSU5UJyBleGlz - dHMsIHRoZW4gb25seSBhZGQgJ2NlcGgtcmd3JyBTdG9yYWdlQ2xhc3MKICAgICAgICBpZiBzZWxm - Lm91dF9tYXBbIlJHV19FTkRQT0lOVCJdOgogICAgICAgICAgICBqc29uX291dC5hcHBlbmQoCiAg - ICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgIm5hbWUiOiAiY2VwaC1yZ3ciLAog - ICAgICAgICAgICAgICAgICAgICJraW5kIjogIlN0b3JhZ2VDbGFzcyIsCiAgICAgICAgICAgICAg - ICAgICAgImRhdGEiOiB7CiAgICAgICAgICAgICAgICAgICAgICAgICJlbmRwb2ludCI6IHNlbGYu - b3V0X21hcFsiUkdXX0VORFBPSU5UIl0sCiAgICAgICAgICAgICAgICAgICAgICAgICJwb29sUHJl - Zml4Ijogc2VsZi5vdXRfbWFwWyJSR1dfUE9PTF9QUkVGSVgiXSwKICAgICAgICAgICAgICAgICAg - ICB9LAogICAgICAgICAgICAgICAgfQogICAgICAgICAgICApCiAgICAgICAgICAgIGpzb25fb3V0 - LmFwcGVuZCgKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAibmFtZSI6ICJy - Z3ctYWRtaW4tb3BzLXVzZXIiLAogICAgICAgICAgICAgICAgICAgICJraW5kIjogIlNlY3JldCIs - CiAgICAgICAgICAgICAgICAgICAgImRhdGEiOiB7CiAgICAgICAgICAgICAgICAgICAgICAgICJh - Y2Nlc3NLZXkiOiBzZWxmLm91dF9tYXBbIlJHV19BRE1JTl9PUFNfVVNFUl9BQ0NFU1NfS0VZIl0s - CiAgICAgICAgICAgICAgICAgICAgICAgICJzZWNyZXRLZXkiOiBzZWxmLm91dF9tYXBbIlJHV19B - RE1JTl9PUFNfVVNFUl9TRUNSRVRfS0VZIl0sCiAgICAgICAgICAgICAgICAgICAgfSwKICAgICAg - ICAgICAgICAgIH0KICAgICAgICAgICAgKQogICAgICAgICMgaWYgJ1JHV19UTFNfQ0VSVCcgZXhp - c3RzLCB0aGVuIG9ubHkgYWRkIHRoZSAiY2VwaC1yZ3ctdGxzLWNlcnQiIHNlY3JldAogICAgICAg - IGlmIHNlbGYub3V0X21hcFsiUkdXX1RMU19DRVJUIl06CiAgICAgICAgICAgIGpzb25fb3V0LmFw + LAogICAgICAgICAgICAgICAgICAgICAgICAiY3NpLnN0b3JhZ2UuazhzLmlvL2NvbnRyb2xsZXIt + ZXhwYW5kLXNlY3JldC1uYW1lIjogZiJyb29rLXtzZWxmLm91dF9tYXBbJ0NTSV9SQkRfUFJPVklT + SU9ORVJfU0VDUkVUX05BTUUnXX0iLAogICAgICAgICAgICAgICAgICAgICAgICAiY3NpLnN0b3Jh + Z2UuazhzLmlvL25vZGUtc3RhZ2Utc2VjcmV0LW5hbWUiOiBmInJvb2ste3NlbGYub3V0X21hcFsn + Q1NJX1JCRF9OT0RFX1NFQ1JFVF9OQU1FJ119IiwKICAgICAgICAgICAgICAgICAgICB9LAogICAg + ICAgICAgICAgICAgfQogICAgICAgICAgICApCiAgICAgICAgZWxzZToKICAgICAgICAgICAgaWYg + c2VsZi5vdXRfbWFwWyJSQkRfTUVUQURBVEFfRUNfUE9PTF9OQU1FIl06CiAgICAgICAgICAgICAg + ICBqc29uX291dC5hcHBlbmQoCiAgICAgICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAg + ICAgICAgICAibmFtZSI6ICJjZXBoLXJiZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICJraW5k + IjogIlN0b3JhZ2VDbGFzcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICJkYXRhIjogewogICAg + ICAgICAgICAgICAgICAgICAgICAgICAgImRhdGFQb29sIjogc2VsZi5vdXRfbWFwWyJSQkRfUE9P + TF9OQU1FIl0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAicG9vbCI6IHNlbGYub3V0X21h + cFsiUkJEX01FVEFEQVRBX0VDX1BPT0xfTkFNRSJdLAogICAgICAgICAgICAgICAgICAgICAgICAg + ICAgImNzaS5zdG9yYWdlLms4cy5pby9wcm92aXNpb25lci1zZWNyZXQtbmFtZSI6IGYicm9vay17 + c2VsZi5vdXRfbWFwWydDU0lfUkJEX1BST1ZJU0lPTkVSX1NFQ1JFVF9OQU1FJ119IiwKICAgICAg + ICAgICAgICAgICAgICAgICAgICAgICJjc2kuc3RvcmFnZS5rOHMuaW8vY29udHJvbGxlci1leHBh + bmQtc2VjcmV0LW5hbWUiOiBmInJvb2ste3NlbGYub3V0X21hcFsnQ1NJX1JCRF9QUk9WSVNJT05F + Ul9TRUNSRVRfTkFNRSddfSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY3NpLnN0b3Jh + Z2UuazhzLmlvL25vZGUtc3RhZ2Utc2VjcmV0LW5hbWUiOiBmInJvb2ste3NlbGYub3V0X21hcFsn + Q1NJX1JCRF9OT0RFX1NFQ1JFVF9OQU1FJ119IiwKICAgICAgICAgICAgICAgICAgICAgICAgfSwK + ICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgIGVsc2U6 + CiAgICAgICAgICAgICAgICBqc29uX291dC5hcHBlbmQoCiAgICAgICAgICAgICAgICAgICAgewog + ICAgICAgICAgICAgICAgICAgICAgICAibmFtZSI6ICJjZXBoLXJiZCIsCiAgICAgICAgICAgICAg + ICAgICAgICAgICJraW5kIjogIlN0b3JhZ2VDbGFzcyIsCiAgICAgICAgICAgICAgICAgICAgICAg + ICJkYXRhIjogewogICAgICAgICAgICAgICAgICAgICAgICAgICAgInBvb2wiOiBzZWxmLm91dF9t + YXBbIlJCRF9QT09MX05BTUUiXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjc2kuc3Rv + cmFnZS5rOHMuaW8vcHJvdmlzaW9uZXItc2VjcmV0LW5hbWUiOiBmInJvb2ste3NlbGYub3V0X21h + cFsnQ1NJX1JCRF9QUk9WSVNJT05FUl9TRUNSRVRfTkFNRSddfSIsCiAgICAgICAgICAgICAgICAg + ICAgICAgICAgICAiY3NpLnN0b3JhZ2UuazhzLmlvL2NvbnRyb2xsZXItZXhwYW5kLXNlY3JldC1u + YW1lIjogZiJyb29rLXtzZWxmLm91dF9tYXBbJ0NTSV9SQkRfUFJPVklTSU9ORVJfU0VDUkVUX05B + TUUnXX0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgImNzaS5zdG9yYWdlLms4cy5pby9u + b2RlLXN0YWdlLXNlY3JldC1uYW1lIjogZiJyb29rLXtzZWxmLm91dF9tYXBbJ0NTSV9SQkRfTk9E + RV9TRUNSRVRfTkFNRSddfSIsCiAgICAgICAgICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAg + ICAgICAgICAgfQogICAgICAgICAgICAgICAgKQoKICAgICAgICAjIGlmICdUT1BPTE9HWV9QT09M + UycsICdUT1BPTE9HWV9GQUlMVVJFX0RPTUFJTl9MQUJFTCcsICdUT1BPTE9HWV9GQUlMVVJFX0RP + TUFJTl9WQUxVRVMnICBleGlzdHMsCiAgICAgICAgIyB0aGVuIG9ubHkgYWRkICd0b3BvbG9neScg + U3RvcmFnZUNsYXNzCiAgICAgICAgaWYgKAogICAgICAgICAgICBzZWxmLm91dF9tYXBbIlRPUE9M + T0dZX1BPT0xTIl0KICAgICAgICAgICAgYW5kIHNlbGYub3V0X21hcFsiVE9QT0xPR1lfRkFJTFVS + RV9ET01BSU5fTEFCRUwiXQogICAgICAgICAgICBhbmQgc2VsZi5vdXRfbWFwWyJUT1BPTE9HWV9G + QUlMVVJFX0RPTUFJTl9WQUxVRVMiXQogICAgICAgICk6CiAgICAgICAgICAgIGpzb25fb3V0LmFw cGVuZCgKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAibmFtZSI6ICJjZXBo - LXJndy10bHMtY2VydCIsCiAgICAgICAgICAgICAgICAgICAgImtpbmQiOiAiU2VjcmV0IiwKICAg - ICAgICAgICAgICAgICAgICAiZGF0YSI6IHsKICAgICAgICAgICAgICAgICAgICAgICAgImNlcnQi - OiBzZWxmLm91dF9tYXBbIlJHV19UTFNfQ0VSVCJdLAogICAgICAgICAgICAgICAgICAgIH0sCiAg - ICAgICAgICAgICAgICB9CiAgICAgICAgICAgICkKCiAgICAgICAgcmV0dXJuIGpzb24uZHVtcHMo - anNvbl9vdXQpICsgTElORVNFUAoKICAgIGRlZiB1cGdyYWRlX3VzZXJzX3Blcm1pc3Npb25zKHNl - bGYpOgogICAgICAgIHVzZXJzID0gWwogICAgICAgICAgICAiY2xpZW50LmNzaS1jZXBoZnMtbm9k - ZSIsCiAgICAgICAgICAgICJjbGllbnQuY3NpLWNlcGhmcy1wcm92aXNpb25lciIsCiAgICAgICAg - ICAgICJjbGllbnQuY3NpLXJiZC1ub2RlIiwKICAgICAgICAgICAgImNsaWVudC5jc2ktcmJkLXBy - b3Zpc2lvbmVyIiwKICAgICAgICAgICAgImNsaWVudC5oZWFsdGhjaGVja2VyIiwKICAgICAgICBd - CiAgICAgICAgaWYgc2VsZi5ydW5fYXNfdXNlciAhPSAiIiBhbmQgc2VsZi5ydW5fYXNfdXNlciBu - b3QgaW4gdXNlcnM6CiAgICAgICAgICAgIHVzZXJzLmFwcGVuZChzZWxmLnJ1bl9hc191c2VyKQog - ICAgICAgIGZvciB1c2VyIGluIHVzZXJzOgogICAgICAgICAgICBzZWxmLnVwZ3JhZGVfdXNlcl9w - ZXJtaXNzaW9ucyh1c2VyKQoKICAgIGRlZiBnZXRfcmd3X3Bvb2xfbmFtZV9kdXJpbmdfdXBncmFk - ZShzZWxmLCB1c2VyLCBjYXBzKToKICAgICAgICBpZiB1c2VyID09ICJjbGllbnQuaGVhbHRoY2hl - Y2tlciI6CiAgICAgICAgICAgICMgd2hlbiBhZG1pbiBoYXMgbm90IHByb3ZpZGVkIHJndyBwb29s - IG5hbWUgZHVyaW5nIHVwZ3JhZGUsCiAgICAgICAgICAgICMgZ2V0IHRoZSByZ3cgcG9vbCBuYW1l - IGZyb20gY2xpZW50LmhlYWx0aGNoZWNrZXIgdXNlciB3aGljaCB3YXMgdXNlZCBkdXJpbmcgY29u - bmVjdGlvbgogICAgICAgICAgICBpZiBub3Qgc2VsZi5fYXJnX3BhcnNlci5yZ3dfcG9vbF9wcmVm - aXg6CiAgICAgICAgICAgICAgICAjIFRvIGdldCB2YWx1ZSAnZGVmYXVsdCcgd2hpY2ggaXMgcmd3 - IHBvb2wgbmFtZSBmcm9tICdhbGxvdyByd3ggcG9vbD1kZWZhdWx0LnJndy5tZXRhJwogICAgICAg - ICAgICAgICAgcGF0dGVybiA9IHIicG9vbD0oLio/KVwucmd3XC5tZXRhIgogICAgICAgICAgICAg - ICAgbWF0Y2ggPSByZS5zZWFyY2gocGF0dGVybiwgY2FwcykKICAgICAgICAgICAgICAgIGlmIG1h - dGNoOgogICAgICAgICAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIucmd3X3Bvb2xfcHJlZml4 - ID0gbWF0Y2guZ3JvdXAoMSkKICAgICAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICAg - ICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlvbigKICAgICAgICAgICAgICAgICAgICAg - ICAgImZhaWxlZCB0byBnZXQgcmd3IHBvb2wgbmFtZSBmb3IgdXBncmFkZSIKICAgICAgICAgICAg - ICAgICAgICApCgogICAgZGVmIHVwZ3JhZGVfdXNlcl9wZXJtaXNzaW9ucyhzZWxmLCB1c2VyKToK - ICAgICAgICAjIGNoZWNrIHdoZXRoZXIgdGhlIGdpdmVuIHVzZXIgZXhpc3RzIG9yIG5vdAogICAg - ICAgIGNtZF9qc29uID0geyJwcmVmaXgiOiAiYXV0aCBnZXQiLCAiZW50aXR5IjogZiJ7dXNlcn0i - LCAiZm9ybWF0IjogImpzb24ifQogICAgICAgIHJldF92YWwsIGpzb25fb3V0LCBlcnJfbXNnID0g - c2VsZi5fY29tbW9uX2NtZF9qc29uX2dlbihjbWRfanNvbikKICAgICAgICBpZiByZXRfdmFsICE9 - IDAgb3IgbGVuKGpzb25fb3V0KSA9PSAwOgogICAgICAgICAgICBwcmludChmInVzZXIge3VzZXJ9 - IG5vdCBmb3VuZCBmb3IgdXBncmFkaW5nLiIpCiAgICAgICAgICAgIHJldHVybgogICAgICAgIGV4 - aXN0aW5nX2NhcHMgPSBqc29uX291dFswXVsiY2FwcyJdCiAgICAgICAgc2VsZi5nZXRfcmd3X3Bv - b2xfbmFtZV9kdXJpbmdfdXBncmFkZSh1c2VyLCBzdHIoZXhpc3RpbmdfY2FwcykpCiAgICAgICAg - bmV3X2NhcCwgXyA9IHNlbGYuZ2V0X2NhcHNfYW5kX2VudGl0eSh1c2VyKQogICAgICAgIGNhcF9r - ZXlzID0gWyJtb24iLCAibWdyIiwgIm9zZCIsICJtZHMiXQogICAgICAgIGNhcHMgPSBbXQogICAg - ICAgIGZvciBlYWNoQ2FwIGluIGNhcF9rZXlzOgogICAgICAgICAgICBjdXJfY2FwX3ZhbHVlcyA9 - IGV4aXN0aW5nX2NhcHMuZ2V0KGVhY2hDYXAsICIiKQogICAgICAgICAgICBuZXdfY2FwX3ZhbHVl - cyA9IG5ld19jYXAuZ2V0KGVhY2hDYXAsICIiKQogICAgICAgICAgICBjdXJfY2FwX3Blcm1fbGlz - dCA9IFsKICAgICAgICAgICAgICAgIHguc3RyaXAoKSBmb3IgeCBpbiBjdXJfY2FwX3ZhbHVlcy5z - cGxpdCgiLCIpIGlmIHguc3RyaXAoKQogICAgICAgICAgICBdCiAgICAgICAgICAgIG5ld19jYXBf - cGVybV9saXN0ID0gWwogICAgICAgICAgICAgICAgeC5zdHJpcCgpIGZvciB4IGluIG5ld19jYXBf - dmFsdWVzLnNwbGl0KCIsIikgaWYgeC5zdHJpcCgpCiAgICAgICAgICAgIF0KICAgICAgICAgICAg - IyBhcHBlbmQgbmV3X2NhcF9saXN0IHRvIGN1cl9jYXBfbGlzdCB0byBtYWludGFpbiB0aGUgb3Jk - ZXIgb2YgY2FwcwogICAgICAgICAgICBjdXJfY2FwX3Blcm1fbGlzdC5leHRlbmQobmV3X2NhcF9w - ZXJtX2xpc3QpCiAgICAgICAgICAgICMgZWxpbWluYXRlIGR1cGxpY2F0ZXMgd2l0aG91dCB1c2lu - ZyAnc2V0JwogICAgICAgICAgICAjIHNldCByZS1vcmRlcnMgaXRlbXMgaW4gdGhlIGxpc3QgYW5k - IHdlIGhhdmUgdG8ga2VlcCB0aGUgb3JkZXIKICAgICAgICAgICAgbmV3X2NhcF9saXN0ID0gW10K - ICAgICAgICAgICAgW25ld19jYXBfbGlzdC5hcHBlbmQoeCkgZm9yIHggaW4gY3VyX2NhcF9wZXJt - X2xpc3QgaWYgeCBub3QgaW4gbmV3X2NhcF9saXN0XQogICAgICAgICAgICBleGlzdGluZ19jYXBz - W2VhY2hDYXBdID0gIiwgIi5qb2luKG5ld19jYXBfbGlzdCkKICAgICAgICAgICAgaWYgZXhpc3Rp - bmdfY2Fwc1tlYWNoQ2FwXToKICAgICAgICAgICAgICAgIGNhcHMuYXBwZW5kKGVhY2hDYXApCiAg - ICAgICAgICAgICAgICBjYXBzLmFwcGVuZChleGlzdGluZ19jYXBzW2VhY2hDYXBdKQogICAgICAg - IGNtZF9qc29uID0gewogICAgICAgICAgICAicHJlZml4IjogImF1dGggY2FwcyIsCiAgICAgICAg - ICAgICJlbnRpdHkiOiB1c2VyLAogICAgICAgICAgICAiY2FwcyI6IGNhcHMsCiAgICAgICAgICAg - ICJmb3JtYXQiOiAianNvbiIsCiAgICAgICAgfQogICAgICAgIHJldF92YWwsIGpzb25fb3V0LCBl - cnJfbXNnID0gc2VsZi5fY29tbW9uX2NtZF9qc29uX2dlbihjbWRfanNvbikKICAgICAgICBpZiBy - ZXRfdmFsICE9IDA6CiAgICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1cmVFeGNlcHRpb24o - CiAgICAgICAgICAgICAgICBmIidhdXRoIGNhcHMge3VzZXJ9JyBjb21tYW5kIGZhaWxlZC5cbiBF - cnJvcjoge2Vycl9tc2d9IgogICAgICAgICAgICApCiAgICAgICAgcHJpbnQoZiJVcGRhdGVkIHVz - ZXIge3VzZXJ9IHN1Y2Nlc3NmdWxseS4iKQoKICAgIGRlZiBtYWluKHNlbGYpOgogICAgICAgIGdl - bmVyYXRlZF9vdXRwdXQgPSAiIgogICAgICAgIGlmIHNlbGYuX2FyZ19wYXJzZXIudXBncmFkZToK - ICAgICAgICAgICAgc2VsZi51cGdyYWRlX3VzZXJzX3Blcm1pc3Npb25zKCkKICAgICAgICBlbGlm - IHNlbGYuX2FyZ19wYXJzZXIuZm9ybWF0ID09ICJqc29uIjoKICAgICAgICAgICAgZ2VuZXJhdGVk - X291dHB1dCA9IHNlbGYuZ2VuX2pzb25fb3V0KCkKICAgICAgICBlbGlmIHNlbGYuX2FyZ19wYXJz - ZXIuZm9ybWF0ID09ICJiYXNoIjoKICAgICAgICAgICAgZ2VuZXJhdGVkX291dHB1dCA9IHNlbGYu - Z2VuX3NoZWxsX291dCgpCiAgICAgICAgZWxzZToKICAgICAgICAgICAgcmFpc2UgRXhlY3V0aW9u - RmFpbHVyZUV4Y2VwdGlvbigKICAgICAgICAgICAgICAgIGYiVW5zdXBwb3J0ZWQgZm9ybWF0OiB7 - c2VsZi5fYXJnX3BhcnNlci5mb3JtYXR9IgogICAgICAgICAgICApCiAgICAgICAgcHJpbnQoZ2Vu - ZXJhdGVkX291dHB1dCkKICAgICAgICBpZiBzZWxmLm91dHB1dF9maWxlIGFuZCBnZW5lcmF0ZWRf - b3V0cHV0OgogICAgICAgICAgICBmT3V0ID0gb3BlbihzZWxmLm91dHB1dF9maWxlLCBtb2RlPSJ3 - IiwgZW5jb2Rpbmc9IlVURi04IikKICAgICAgICAgICAgZk91dC53cml0ZShnZW5lcmF0ZWRfb3V0 - cHV0KQogICAgICAgICAgICBmT3V0LmNsb3NlKCkKCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMj - IyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIE1BSU4gIyMjIyMj - IyMjIyMjIyMjIyMjIyMjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMj - IyMjIyMjIwppZiBfX25hbWVfXyA9PSAiX19tYWluX18iOgogICAgcmpPYmogPSBSYWRvc0pTT04o - KQogICAgdHJ5OgogICAgICAgIHJqT2JqLm1haW4oKQogICAgZXhjZXB0IEV4ZWN1dGlvbkZhaWx1 - cmVFeGNlcHRpb24gYXMgZXJyOgogICAgICAgIHByaW50KGYiRXhlY3V0aW9uIEZhaWxlZDoge2Vy - cn0iKQogICAgICAgIHJhaXNlIGVycgogICAgZXhjZXB0IEtleUVycm9yIGFzIGtFcnI6CiAgICAg - ICAgcHJpbnQoZiJLZXlFcnJvcjoge2tFcnJ9IikKICAgIGV4Y2VwdCBPU0Vycm9yIGFzIG9zRXJy - OgogICAgICAgIHByaW50KGYiRXJyb3Igd2hpbGUgdHJ5aW5nIHRvIG91dHB1dCB0aGUgZGF0YTog - e29zRXJyfSIpCiAgICBmaW5hbGx5OgogICAgICAgIHJqT2JqLnNodXRkb3duKCkK + LXJiZC10b3BvbG9neSIsCiAgICAgICAgICAgICAgICAgICAgImtpbmQiOiAiU3RvcmFnZUNsYXNz + IiwKICAgICAgICAgICAgICAgICAgICAiZGF0YSI6IHsKICAgICAgICAgICAgICAgICAgICAgICAg + InRvcG9sb2d5RmFpbHVyZURvbWFpbkxhYmVsIjogc2VsZi5vdXRfbWFwWwogICAgICAgICAgICAg + ICAgICAgICAgICAgICAgIlRPUE9MT0dZX0ZBSUxVUkVfRE9NQUlOX0xBQkVMIgogICAgICAgICAg + ICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICAgICAidG9wb2xvZ3lGYWlsdXJl + RG9tYWluVmFsdWVzIjogc2VsZi5vdXRfbWFwWwogICAgICAgICAgICAgICAgICAgICAgICAgICAg + IlRPUE9MT0dZX0ZBSUxVUkVfRE9NQUlOX1ZBTFVFUyIKICAgICAgICAgICAgICAgICAgICAgICAg + XSwKICAgICAgICAgICAgICAgICAgICAgICAgInRvcG9sb2d5UG9vbHMiOiBzZWxmLm91dF9tYXBb + IlRPUE9MT0dZX1BPT0xTIl0sCiAgICAgICAgICAgICAgICAgICAgICAgICJjc2kuc3RvcmFnZS5r + OHMuaW8vcHJvdmlzaW9uZXItc2VjcmV0LW5hbWUiOiBmInJvb2ste3NlbGYub3V0X21hcFsnQ1NJ + X1JCRF9QUk9WSVNJT05FUl9TRUNSRVRfTkFNRSddfSIsCiAgICAgICAgICAgICAgICAgICAgICAg + ICJjc2kuc3RvcmFnZS5rOHMuaW8vY29udHJvbGxlci1leHBhbmQtc2VjcmV0LW5hbWUiOiBmInJv + b2ste3NlbGYub3V0X21hcFsnQ1NJX1JCRF9QUk9WSVNJT05FUl9TRUNSRVRfTkFNRSddfSIsCiAg + ICAgICAgICAgICAgICAgICAgICAgICJjc2kuc3RvcmFnZS5rOHMuaW8vbm9kZS1zdGFnZS1zZWNy + ZXQtbmFtZSI6IGYicm9vay17c2VsZi5vdXRfbWFwWydDU0lfUkJEX05PREVfU0VDUkVUX05BTUUn + XX0iLAogICAgICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAg + ICkKCiAgICAgICAgIyBpZiAnQ0VQSEZTX0ZTX05BTUUnIGV4aXN0cywgdGhlbiBvbmx5IGFkZCAn + Y2VwaGZzJyBTdG9yYWdlQ2xhc3MKICAgICAgICBpZiBzZWxmLm91dF9tYXBbIkNFUEhGU19GU19O + QU1FIl06CiAgICAgICAgICAgIGpzb25fb3V0LmFwcGVuZCgKICAgICAgICAgICAgICAgIHsKICAg + ICAgICAgICAgICAgICAgICAibmFtZSI6ICJjZXBoZnMiLAogICAgICAgICAgICAgICAgICAgICJr + aW5kIjogIlN0b3JhZ2VDbGFzcyIsCiAgICAgICAgICAgICAgICAgICAgImRhdGEiOiB7CiAgICAg + ICAgICAgICAgICAgICAgICAgICJmc05hbWUiOiBzZWxmLm91dF9tYXBbIkNFUEhGU19GU19OQU1F + Il0sCiAgICAgICAgICAgICAgICAgICAgICAgICJwb29sIjogc2VsZi5vdXRfbWFwWyJDRVBIRlNf + UE9PTF9OQU1FIl0sCiAgICAgICAgICAgICAgICAgICAgICAgICJjc2kuc3RvcmFnZS5rOHMuaW8v + cHJvdmlzaW9uZXItc2VjcmV0LW5hbWUiOiBmInJvb2ste3NlbGYub3V0X21hcFsnQ1NJX0NFUEhG + U19QUk9WSVNJT05FUl9TRUNSRVRfTkFNRSddfSIsCiAgICAgICAgICAgICAgICAgICAgICAgICJj + c2kuc3RvcmFnZS5rOHMuaW8vY29udHJvbGxlci1leHBhbmQtc2VjcmV0LW5hbWUiOiBmInJvb2st + e3NlbGYub3V0X21hcFsnQ1NJX0NFUEhGU19QUk9WSVNJT05FUl9TRUNSRVRfTkFNRSddfSIsCiAg + ICAgICAgICAgICAgICAgICAgICAgICJjc2kuc3RvcmFnZS5rOHMuaW8vbm9kZS1zdGFnZS1zZWNy + ZXQtbmFtZSI6IGYicm9vay17c2VsZi5vdXRfbWFwWydDU0lfQ0VQSEZTX05PREVfU0VDUkVUX05B + TUUnXX0iLAogICAgICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICB9CiAgICAgICAg + ICAgICkKICAgICAgICAjIGlmICdSR1dfRU5EUE9JTlQnIGV4aXN0cywgdGhlbiBvbmx5IGFkZCAn + Y2VwaC1yZ3cnIFN0b3JhZ2VDbGFzcwogICAgICAgIGlmIHNlbGYub3V0X21hcFsiUkdXX0VORFBP + SU5UIl06CiAgICAgICAgICAgIGpzb25fb3V0LmFwcGVuZCgKICAgICAgICAgICAgICAgIHsKICAg + ICAgICAgICAgICAgICAgICAibmFtZSI6ICJjZXBoLXJndyIsCiAgICAgICAgICAgICAgICAgICAg + ImtpbmQiOiAiU3RvcmFnZUNsYXNzIiwKICAgICAgICAgICAgICAgICAgICAiZGF0YSI6IHsKICAg + ICAgICAgICAgICAgICAgICAgICAgImVuZHBvaW50Ijogc2VsZi5vdXRfbWFwWyJSR1dfRU5EUE9J + TlQiXSwKICAgICAgICAgICAgICAgICAgICAgICAgInBvb2xQcmVmaXgiOiBzZWxmLm91dF9tYXBb + IlJHV19QT09MX1BSRUZJWCJdLAogICAgICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAg + ICB9CiAgICAgICAgICAgICkKICAgICAgICAgICAganNvbl9vdXQuYXBwZW5kKAogICAgICAgICAg + ICAgICAgewogICAgICAgICAgICAgICAgICAgICJuYW1lIjogInJndy1hZG1pbi1vcHMtdXNlciIs + CiAgICAgICAgICAgICAgICAgICAgImtpbmQiOiAiU2VjcmV0IiwKICAgICAgICAgICAgICAgICAg + ICAiZGF0YSI6IHsKICAgICAgICAgICAgICAgICAgICAgICAgImFjY2Vzc0tleSI6IHNlbGYub3V0 + X21hcFsiUkdXX0FETUlOX09QU19VU0VSX0FDQ0VTU19LRVkiXSwKICAgICAgICAgICAgICAgICAg + ICAgICAgInNlY3JldEtleSI6IHNlbGYub3V0X21hcFsiUkdXX0FETUlOX09QU19VU0VSX1NFQ1JF + VF9LRVkiXSwKICAgICAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAgfQogICAgICAg + ICAgICApCiAgICAgICAgIyBpZiAnUkdXX1RMU19DRVJUJyBleGlzdHMsIHRoZW4gb25seSBhZGQg + dGhlICJjZXBoLXJndy10bHMtY2VydCIgc2VjcmV0CiAgICAgICAgaWYgc2VsZi5vdXRfbWFwWyJS + R1dfVExTX0NFUlQiXToKICAgICAgICAgICAganNvbl9vdXQuYXBwZW5kKAogICAgICAgICAgICAg + ICAgewogICAgICAgICAgICAgICAgICAgICJuYW1lIjogImNlcGgtcmd3LXRscy1jZXJ0IiwKICAg + ICAgICAgICAgICAgICAgICAia2luZCI6ICJTZWNyZXQiLAogICAgICAgICAgICAgICAgICAgICJk + YXRhIjogewogICAgICAgICAgICAgICAgICAgICAgICAiY2VydCI6IHNlbGYub3V0X21hcFsiUkdX + X1RMU19DRVJUIl0sCiAgICAgICAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAgIH0KICAg + ICAgICAgICAgKQoKICAgICAgICByZXR1cm4ganNvbi5kdW1wcyhqc29uX291dCkgKyBMSU5FU0VQ + CgogICAgZGVmIHVwZ3JhZGVfdXNlcnNfcGVybWlzc2lvbnMoc2VsZik6CiAgICAgICAgdXNlcnMg + PSBbCiAgICAgICAgICAgICJjbGllbnQuY3NpLWNlcGhmcy1ub2RlIiwKICAgICAgICAgICAgImNs + aWVudC5jc2ktY2VwaGZzLXByb3Zpc2lvbmVyIiwKICAgICAgICAgICAgImNsaWVudC5jc2ktcmJk + LW5vZGUiLAogICAgICAgICAgICAiY2xpZW50LmNzaS1yYmQtcHJvdmlzaW9uZXIiLAogICAgICAg + ICAgICAiY2xpZW50LmhlYWx0aGNoZWNrZXIiLAogICAgICAgIF0KICAgICAgICBpZiBzZWxmLnJ1 + bl9hc191c2VyICE9ICIiIGFuZCBzZWxmLnJ1bl9hc191c2VyIG5vdCBpbiB1c2VyczoKICAgICAg + ICAgICAgdXNlcnMuYXBwZW5kKHNlbGYucnVuX2FzX3VzZXIpCiAgICAgICAgZm9yIHVzZXIgaW4g + dXNlcnM6CiAgICAgICAgICAgIHNlbGYudXBncmFkZV91c2VyX3Blcm1pc3Npb25zKHVzZXIpCgog + ICAgZGVmIGdldF9yZ3dfcG9vbF9uYW1lX2R1cmluZ191cGdyYWRlKHNlbGYsIHVzZXIsIGNhcHMp + OgogICAgICAgIGlmIHVzZXIgPT0gImNsaWVudC5oZWFsdGhjaGVja2VyIjoKICAgICAgICAgICAg + IyB3aGVuIGFkbWluIGhhcyBub3QgcHJvdmlkZWQgcmd3IHBvb2wgbmFtZSBkdXJpbmcgdXBncmFk + ZSwKICAgICAgICAgICAgIyBnZXQgdGhlIHJndyBwb29sIG5hbWUgZnJvbSBjbGllbnQuaGVhbHRo + Y2hlY2tlciB1c2VyIHdoaWNoIHdhcyB1c2VkIGR1cmluZyBjb25uZWN0aW9uCiAgICAgICAgICAg + IGlmIG5vdCBzZWxmLl9hcmdfcGFyc2VyLnJnd19wb29sX3ByZWZpeDoKICAgICAgICAgICAgICAg + ICMgVG8gZ2V0IHZhbHVlICdkZWZhdWx0JyB3aGljaCBpcyByZ3cgcG9vbCBuYW1lIGZyb20gJ2Fs + bG93IHJ3eCBwb29sPWRlZmF1bHQucmd3Lm1ldGEnCiAgICAgICAgICAgICAgICBwYXR0ZXJuID0g + ciJwb29sPSguKj8pXC5yZ3dcLm1ldGEiCiAgICAgICAgICAgICAgICBtYXRjaCA9IHJlLnNlYXJj + aChwYXR0ZXJuLCBjYXBzKQogICAgICAgICAgICAgICAgaWYgbWF0Y2g6CiAgICAgICAgICAgICAg + ICAgICAgc2VsZi5fYXJnX3BhcnNlci5yZ3dfcG9vbF9wcmVmaXggPSBtYXRjaC5ncm91cCgxKQog + ICAgICAgICAgICAgICAgZWxzZToKICAgICAgICAgICAgICAgICAgICByYWlzZSBFeGVjdXRpb25G + YWlsdXJlRXhjZXB0aW9uKAogICAgICAgICAgICAgICAgICAgICAgICAiZmFpbGVkIHRvIGdldCBy + Z3cgcG9vbCBuYW1lIGZvciB1cGdyYWRlIgogICAgICAgICAgICAgICAgICAgICkKCiAgICBkZWYg + dXBncmFkZV91c2VyX3Blcm1pc3Npb25zKHNlbGYsIHVzZXIpOgogICAgICAgICMgY2hlY2sgd2hl + dGhlciB0aGUgZ2l2ZW4gdXNlciBleGlzdHMgb3Igbm90CiAgICAgICAgY21kX2pzb24gPSB7InBy + ZWZpeCI6ICJhdXRoIGdldCIsICJlbnRpdHkiOiBmInt1c2VyfSIsICJmb3JtYXQiOiAianNvbiJ9 + CiAgICAgICAgcmV0X3ZhbCwganNvbl9vdXQsIGVycl9tc2cgPSBzZWxmLl9jb21tb25fY21kX2pz + b25fZ2VuKGNtZF9qc29uKQogICAgICAgIGlmIHJldF92YWwgIT0gMCBvciBsZW4oanNvbl9vdXQp + ID09IDA6CiAgICAgICAgICAgIHByaW50KGYidXNlciB7dXNlcn0gbm90IGZvdW5kIGZvciB1cGdy + YWRpbmcuIikKICAgICAgICAgICAgcmV0dXJuCiAgICAgICAgZXhpc3RpbmdfY2FwcyA9IGpzb25f + b3V0WzBdWyJjYXBzIl0KICAgICAgICBzZWxmLmdldF9yZ3dfcG9vbF9uYW1lX2R1cmluZ191cGdy + YWRlKHVzZXIsIHN0cihleGlzdGluZ19jYXBzKSkKICAgICAgICBuZXdfY2FwLCBfID0gc2VsZi5n + ZXRfY2Fwc19hbmRfZW50aXR5KHVzZXIpCiAgICAgICAgY2FwX2tleXMgPSBbIm1vbiIsICJtZ3Ii + LCAib3NkIiwgIm1kcyJdCiAgICAgICAgY2FwcyA9IFtdCiAgICAgICAgZm9yIGVhY2hDYXAgaW4g + Y2FwX2tleXM6CiAgICAgICAgICAgIGN1cl9jYXBfdmFsdWVzID0gZXhpc3RpbmdfY2Fwcy5nZXQo + ZWFjaENhcCwgIiIpCiAgICAgICAgICAgIG5ld19jYXBfdmFsdWVzID0gbmV3X2NhcC5nZXQoZWFj + aENhcCwgIiIpCiAgICAgICAgICAgIGN1cl9jYXBfcGVybV9saXN0ID0gWwogICAgICAgICAgICAg + ICAgeC5zdHJpcCgpIGZvciB4IGluIGN1cl9jYXBfdmFsdWVzLnNwbGl0KCIsIikgaWYgeC5zdHJp + cCgpCiAgICAgICAgICAgIF0KICAgICAgICAgICAgbmV3X2NhcF9wZXJtX2xpc3QgPSBbCiAgICAg + ICAgICAgICAgICB4LnN0cmlwKCkgZm9yIHggaW4gbmV3X2NhcF92YWx1ZXMuc3BsaXQoIiwiKSBp + ZiB4LnN0cmlwKCkKICAgICAgICAgICAgXQogICAgICAgICAgICAjIGFwcGVuZCBuZXdfY2FwX2xp + c3QgdG8gY3VyX2NhcF9saXN0IHRvIG1haW50YWluIHRoZSBvcmRlciBvZiBjYXBzCiAgICAgICAg + ICAgIGN1cl9jYXBfcGVybV9saXN0LmV4dGVuZChuZXdfY2FwX3Blcm1fbGlzdCkKICAgICAgICAg + ICAgIyBlbGltaW5hdGUgZHVwbGljYXRlcyB3aXRob3V0IHVzaW5nICdzZXQnCiAgICAgICAgICAg + ICMgc2V0IHJlLW9yZGVycyBpdGVtcyBpbiB0aGUgbGlzdCBhbmQgd2UgaGF2ZSB0byBrZWVwIHRo + ZSBvcmRlcgogICAgICAgICAgICBuZXdfY2FwX2xpc3QgPSBbXQogICAgICAgICAgICBbbmV3X2Nh + cF9saXN0LmFwcGVuZCh4KSBmb3IgeCBpbiBjdXJfY2FwX3Blcm1fbGlzdCBpZiB4IG5vdCBpbiBu + ZXdfY2FwX2xpc3RdCiAgICAgICAgICAgIGV4aXN0aW5nX2NhcHNbZWFjaENhcF0gPSAiLCAiLmpv + aW4obmV3X2NhcF9saXN0KQogICAgICAgICAgICBpZiBleGlzdGluZ19jYXBzW2VhY2hDYXBdOgog + ICAgICAgICAgICAgICAgY2Fwcy5hcHBlbmQoZWFjaENhcCkKICAgICAgICAgICAgICAgIGNhcHMu + YXBwZW5kKGV4aXN0aW5nX2NhcHNbZWFjaENhcF0pCiAgICAgICAgY21kX2pzb24gPSB7CiAgICAg + ICAgICAgICJwcmVmaXgiOiAiYXV0aCBjYXBzIiwKICAgICAgICAgICAgImVudGl0eSI6IHVzZXIs + CiAgICAgICAgICAgICJjYXBzIjogY2FwcywKICAgICAgICAgICAgImZvcm1hdCI6ICJqc29uIiwK + ICAgICAgICB9CiAgICAgICAgcmV0X3ZhbCwganNvbl9vdXQsIGVycl9tc2cgPSBzZWxmLl9jb21t + b25fY21kX2pzb25fZ2VuKGNtZF9qc29uKQogICAgICAgIGlmIHJldF92YWwgIT0gMDoKICAgICAg + ICAgICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlvbigKICAgICAgICAgICAgICAgIGYi + J2F1dGggY2FwcyB7dXNlcn0nIGNvbW1hbmQgZmFpbGVkLlxuIEVycm9yOiB7ZXJyX21zZ30iCiAg + ICAgICAgICAgICkKICAgICAgICBwcmludChmIlVwZGF0ZWQgdXNlciB7dXNlcn0gc3VjY2Vzc2Z1 + bGx5LiIpCgogICAgZGVmIG1haW4oc2VsZik6CiAgICAgICAgZ2VuZXJhdGVkX291dHB1dCA9ICIi + CiAgICAgICAgaWYgc2VsZi5fYXJnX3BhcnNlci51cGdyYWRlOgogICAgICAgICAgICBzZWxmLnVw + Z3JhZGVfdXNlcnNfcGVybWlzc2lvbnMoKQogICAgICAgIGVsaWYgc2VsZi5fYXJnX3BhcnNlci5m + b3JtYXQgPT0gImpzb24iOgogICAgICAgICAgICBnZW5lcmF0ZWRfb3V0cHV0ID0gc2VsZi5nZW5f + anNvbl9vdXQoKQogICAgICAgIGVsaWYgc2VsZi5fYXJnX3BhcnNlci5mb3JtYXQgPT0gImJhc2gi + OgogICAgICAgICAgICBnZW5lcmF0ZWRfb3V0cHV0ID0gc2VsZi5nZW5fc2hlbGxfb3V0KCkKICAg + ICAgICBlbHNlOgogICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWlsdXJlRXhjZXB0aW9uKAog + ICAgICAgICAgICAgICAgZiJVbnN1cHBvcnRlZCBmb3JtYXQ6IHtzZWxmLl9hcmdfcGFyc2VyLmZv + cm1hdH0iCiAgICAgICAgICAgICkKICAgICAgICBwcmludChnZW5lcmF0ZWRfb3V0cHV0KQogICAg + ICAgIGlmIHNlbGYub3V0cHV0X2ZpbGUgYW5kIGdlbmVyYXRlZF9vdXRwdXQ6CiAgICAgICAgICAg + IGZPdXQgPSBvcGVuKHNlbGYub3V0cHV0X2ZpbGUsIG1vZGU9InciLCBlbmNvZGluZz0iVVRGLTgi + KQogICAgICAgICAgICBmT3V0LndyaXRlKGdlbmVyYXRlZF9vdXRwdXQpCiAgICAgICAgICAgIGZP + dXQuY2xvc2UoKQoKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMj + IyMjIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMgTUFJTiAjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyMj + IyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCmlmIF9fbmFtZV9f + ID09ICJfX21haW5fXyI6CiAgICByak9iaiA9IFJhZG9zSlNPTigpCiAgICB0cnk6CiAgICAgICAg + cmpPYmoubWFpbigpCiAgICBleGNlcHQgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlvbiBhcyBlcnI6 + CiAgICAgICAgcHJpbnQoZiJFeGVjdXRpb24gRmFpbGVkOiB7ZXJyfSIpCiAgICAgICAgcmFpc2Ug + ZXJyCiAgICBleGNlcHQgS2V5RXJyb3IgYXMga0VycjoKICAgICAgICBwcmludChmIktleUVycm9y + OiB7a0Vycn0iKQogICAgZXhjZXB0IE9TRXJyb3IgYXMgb3NFcnI6CiAgICAgICAgcHJpbnQoZiJF + cnJvciB3aGlsZSB0cnlpbmcgdG8gb3V0cHV0IHRoZSBkYXRhOiB7b3NFcnJ9IikKICAgIGZpbmFs + bHk6CiAgICAgICAgcmpPYmouc2h1dGRvd24oKQo= kind: ConfigMap metadata: name: rook-ceph-external-cluster-script-config diff --git a/build/csv/ceph/rook-ceph-operator.clusterserviceversion.yaml b/build/csv/ceph/rook-ceph-operator.clusterserviceversion.yaml index 2ceace130c69..e4f97d1b1b5c 100644 --- a/build/csv/ceph/rook-ceph-operator.clusterserviceversion.yaml +++ b/build/csv/ceph/rook-ceph-operator.clusterserviceversion.yaml @@ -564,1341 +564,1342 @@ metadata: ICAgICAgICkKICAgICAgICBvdXRwdXRfZ3JvdXAuYWRkX2FyZ3VtZW50KAogICAgICAgICAgICAi LS1yZ3ctdGxzLWNlcnQtcGF0aCIsCiAgICAgICAgICAgIGRlZmF1bHQ9IiIsCiAgICAgICAgICAg IHJlcXVpcmVkPUZhbHNlLAogICAgICAgICAgICBoZWxwPSJSQURPUyBHYXRld2F5IGVuZHBvaW50 - IFRMUyBjZXJ0aWZpY2F0ZSIsCiAgICAgICAgKQogICAgICAgIG91dHB1dF9ncm91cC5hZGRfYXJn - dW1lbnQoCiAgICAgICAgICAgICItLXJndy1za2lwLXRscyIsCiAgICAgICAgICAgIHJlcXVpcmVk - PUZhbHNlLAogICAgICAgICAgICBkZWZhdWx0PUZhbHNlLAogICAgICAgICAgICBoZWxwPSJJZ25v - cmUgVExTIGNlcnRpZmljYXRpb24gdmFsaWRhdGlvbiB3aGVuIGEgc2VsZi1zaWduZWQgY2VydGlm - aWNhdGUgaXMgcHJvdmlkZWQgKE5PVCBSRUNPTU1FTkRFRCIsCiAgICAgICAgKQogICAgICAgIG91 - dHB1dF9ncm91cC5hZGRfYXJndW1lbnQoCiAgICAgICAgICAgICItLW1vbml0b3JpbmctZW5kcG9p - bnQiLAogICAgICAgICAgICBkZWZhdWx0PSIiLAogICAgICAgICAgICByZXF1aXJlZD1GYWxzZSwK - ICAgICAgICAgICAgaGVscD0iQ2VwaCBNYW5hZ2VyIHByb21ldGhldXMgZXhwb3J0ZXIgZW5kcG9p - bnRzIChjb21tYSBzZXBhcmF0ZWQgbGlzdCBvZiAoZm9ybWF0IGA8SVB2ND5gIG9yIGA8W0lQdjZd - PmAgb3IgYDxGUUROPmApIGVudHJpZXMgb2YgYWN0aXZlIGFuZCBzdGFuZGJ5IG1ncnMpIiwKICAg - ICAgICApCiAgICAgICAgb3V0cHV0X2dyb3VwLmFkZF9hcmd1bWVudCgKICAgICAgICAgICAgIi0t - bW9uaXRvcmluZy1lbmRwb2ludC1wb3J0IiwKICAgICAgICAgICAgZGVmYXVsdD0iIiwKICAgICAg - ICAgICAgcmVxdWlyZWQ9RmFsc2UsCiAgICAgICAgICAgIGhlbHA9IkNlcGggTWFuYWdlciBwcm9t - ZXRoZXVzIGV4cG9ydGVyIHBvcnQiLAogICAgICAgICkKICAgICAgICBvdXRwdXRfZ3JvdXAuYWRk - X2FyZ3VtZW50KAogICAgICAgICAgICAiLS1za2lwLW1vbml0b3JpbmctZW5kcG9pbnQiLAogICAg - ICAgICAgICBkZWZhdWx0PUZhbHNlLAogICAgICAgICAgICBhY3Rpb249InN0b3JlX3RydWUiLAog - ICAgICAgICAgICBoZWxwPSJEbyBub3QgY2hlY2sgZm9yIGEgbW9uaXRvcmluZyBlbmRwb2ludCBm - b3IgdGhlIENlcGggY2x1c3RlciIsCiAgICAgICAgKQogICAgICAgIG91dHB1dF9ncm91cC5hZGRf - YXJndW1lbnQoCiAgICAgICAgICAgICItLXJiZC1tZXRhZGF0YS1lYy1wb29sLW5hbWUiLAogICAg - ICAgICAgICBkZWZhdWx0PSIiLAogICAgICAgICAgICByZXF1aXJlZD1GYWxzZSwKICAgICAgICAg - ICAgaGVscD0iUHJvdmlkZXMgdGhlIG5hbWUgb2YgZXJhc3VyZSBjb2RlZCBSQkQgbWV0YWRhdGEg - cG9vbCIsCiAgICAgICAgKQogICAgICAgIG91dHB1dF9ncm91cC5hZGRfYXJndW1lbnQoCiAgICAg - ICAgICAgICItLWRyeS1ydW4iLAogICAgICAgICAgICBkZWZhdWx0PUZhbHNlLAogICAgICAgICAg - ICBhY3Rpb249InN0b3JlX3RydWUiLAogICAgICAgICAgICBoZWxwPSJEcnkgcnVuIHByaW50cyB0 - aGUgZXhlY3V0ZWQgY29tbWFuZHMgd2l0aG91dCBydW5uaW5nIHRoZW0iLAogICAgICAgICkKICAg - ICAgICBvdXRwdXRfZ3JvdXAuYWRkX2FyZ3VtZW50KAogICAgICAgICAgICAiLS1yYWRvcy1uYW1l - c3BhY2UiLAogICAgICAgICAgICBkZWZhdWx0PSIiLAogICAgICAgICAgICByZXF1aXJlZD1GYWxz - ZSwKICAgICAgICAgICAgaGVscD0iRGl2aWRlcyBhIHBvb2wgaW50byBzZXBhcmF0ZSBsb2dpY2Fs - IG5hbWVzcGFjZXMsIHVzZWQgZm9yIGNyZWF0aW5nIFJCRCBQVkMgaW4gYSBDZXBoQmxvY2tQb29s - UmFkb3NOYW1lc3BhY2UgKHNob3VsZCBiZSBsb3dlciBjYXNlKSIsCiAgICAgICAgKQogICAgICAg - IG91dHB1dF9ncm91cC5hZGRfYXJndW1lbnQoCiAgICAgICAgICAgICItLXN1YnZvbHVtZS1ncm91 - cCIsCiAgICAgICAgICAgIGRlZmF1bHQ9IiIsCiAgICAgICAgICAgIHJlcXVpcmVkPUZhbHNlLAog - ICAgICAgICAgICBoZWxwPSJwcm92aWRlcyB0aGUgbmFtZSBvZiB0aGUgc3Vidm9sdW1lIGdyb3Vw + IFRMUyBjZXJ0aWZpY2F0ZSAob3IgaW50ZXJtZWRpYXRlIHNpZ25pbmcgY2VydGlmaWNhdGUpIiwK + ICAgICAgICApCiAgICAgICAgb3V0cHV0X2dyb3VwLmFkZF9hcmd1bWVudCgKICAgICAgICAgICAg + Ii0tcmd3LXNraXAtdGxzIiwKICAgICAgICAgICAgcmVxdWlyZWQ9RmFsc2UsCiAgICAgICAgICAg + IGRlZmF1bHQ9RmFsc2UsCiAgICAgICAgICAgIGhlbHA9Iklnbm9yZSBUTFMgY2VydGlmaWNhdGlv + biB2YWxpZGF0aW9uIHdoZW4gYSBzZWxmLXNpZ25lZCBjZXJ0aWZpY2F0ZSBpcyBwcm92aWRlZCAo + Tk9UIFJFQ09NTUVOREVEIiwKICAgICAgICApCiAgICAgICAgb3V0cHV0X2dyb3VwLmFkZF9hcmd1 + bWVudCgKICAgICAgICAgICAgIi0tbW9uaXRvcmluZy1lbmRwb2ludCIsCiAgICAgICAgICAgIGRl + ZmF1bHQ9IiIsCiAgICAgICAgICAgIHJlcXVpcmVkPUZhbHNlLAogICAgICAgICAgICBoZWxwPSJD + ZXBoIE1hbmFnZXIgcHJvbWV0aGV1cyBleHBvcnRlciBlbmRwb2ludHMgKGNvbW1hIHNlcGFyYXRl + ZCBsaXN0IG9mIChmb3JtYXQgYDxJUHY0PmAgb3IgYDxbSVB2Nl0+YCBvciBgPEZRRE4+YCkgZW50 + cmllcyBvZiBhY3RpdmUgYW5kIHN0YW5kYnkgbWdycykiLAogICAgICAgICkKICAgICAgICBvdXRw + dXRfZ3JvdXAuYWRkX2FyZ3VtZW50KAogICAgICAgICAgICAiLS1tb25pdG9yaW5nLWVuZHBvaW50 + LXBvcnQiLAogICAgICAgICAgICBkZWZhdWx0PSIiLAogICAgICAgICAgICByZXF1aXJlZD1GYWxz + ZSwKICAgICAgICAgICAgaGVscD0iQ2VwaCBNYW5hZ2VyIHByb21ldGhldXMgZXhwb3J0ZXIgcG9y + dCIsCiAgICAgICAgKQogICAgICAgIG91dHB1dF9ncm91cC5hZGRfYXJndW1lbnQoCiAgICAgICAg + ICAgICItLXNraXAtbW9uaXRvcmluZy1lbmRwb2ludCIsCiAgICAgICAgICAgIGRlZmF1bHQ9RmFs + c2UsCiAgICAgICAgICAgIGFjdGlvbj0ic3RvcmVfdHJ1ZSIsCiAgICAgICAgICAgIGhlbHA9IkRv + IG5vdCBjaGVjayBmb3IgYSBtb25pdG9yaW5nIGVuZHBvaW50IGZvciB0aGUgQ2VwaCBjbHVzdGVy IiwKICAgICAgICApCiAgICAgICAgb3V0cHV0X2dyb3VwLmFkZF9hcmd1bWVudCgKICAgICAgICAg - ICAgIi0tcmd3LXJlYWxtLW5hbWUiLAogICAgICAgICAgICBkZWZhdWx0PSIiLAogICAgICAgICAg - ICByZXF1aXJlZD1GYWxzZSwKICAgICAgICAgICAgaGVscD0icHJvdmlkZXMgdGhlIG5hbWUgb2Yg - dGhlIHJndy1yZWFsbSIsCiAgICAgICAgKQogICAgICAgIG91dHB1dF9ncm91cC5hZGRfYXJndW1l - bnQoCiAgICAgICAgICAgICItLXJndy16b25lLW5hbWUiLAogICAgICAgICAgICBkZWZhdWx0PSIi - LAogICAgICAgICAgICByZXF1aXJlZD1GYWxzZSwKICAgICAgICAgICAgaGVscD0icHJvdmlkZXMg - dGhlIG5hbWUgb2YgdGhlIHJndy16b25lIiwKICAgICAgICApCiAgICAgICAgb3V0cHV0X2dyb3Vw - LmFkZF9hcmd1bWVudCgKICAgICAgICAgICAgIi0tcmd3LXpvbmVncm91cC1uYW1lIiwKICAgICAg - ICAgICAgZGVmYXVsdD0iIiwKICAgICAgICAgICAgcmVxdWlyZWQ9RmFsc2UsCiAgICAgICAgICAg - IGhlbHA9InByb3ZpZGVzIHRoZSBuYW1lIG9mIHRoZSByZ3ctem9uZWdyb3VwIiwKICAgICAgICAp - CiAgICAgICAgb3V0cHV0X2dyb3VwLmFkZF9hcmd1bWVudCgKICAgICAgICAgICAgIi0tdG9wb2xv - Z3ktcG9vbHMiLAogICAgICAgICAgICBkZWZhdWx0PSIiLAogICAgICAgICAgICByZXF1aXJlZD1G - YWxzZSwKICAgICAgICAgICAgaGVscD0iY29tbWEtc2VwYXJhdGVkIGxpc3Qgb2YgdG9wb2xvZ3kt - Y29uc3RyYWluZWQgcmJkIHBvb2xzIiwKICAgICAgICApCiAgICAgICAgb3V0cHV0X2dyb3VwLmFk - ZF9hcmd1bWVudCgKICAgICAgICAgICAgIi0tdG9wb2xvZ3ktZmFpbHVyZS1kb21haW4tbGFiZWwi - LAogICAgICAgICAgICBkZWZhdWx0PSIiLAogICAgICAgICAgICByZXF1aXJlZD1GYWxzZSwKICAg - ICAgICAgICAgaGVscD0iazhzIGNsdXN0ZXIgZmFpbHVyZSBkb21haW4gbGFiZWwgKGV4YW1wbGU6 - IHpvbmUsIHJhY2ssIG9yIGhvc3QpIGZvciB0aGUgdG9wb2xvZ3ktcG9vbHMgdGhhdCBtYXRjaCB0 - aGUgY2VwaCBkb21haW4iLAogICAgICAgICkKICAgICAgICBvdXRwdXRfZ3JvdXAuYWRkX2FyZ3Vt - ZW50KAogICAgICAgICAgICAiLS10b3BvbG9neS1mYWlsdXJlLWRvbWFpbi12YWx1ZXMiLAogICAg - ICAgICAgICBkZWZhdWx0PSIiLAogICAgICAgICAgICByZXF1aXJlZD1GYWxzZSwKICAgICAgICAg - ICAgaGVscD0iY29tbWEtc2VwYXJhdGVkIGxpc3Qgb2YgdGhlIGs4cyBjbHVzdGVyIGZhaWx1cmUg - ZG9tYWluIHZhbHVlcyBjb3JyZXNwb25kaW5nIHRvIGVhY2ggb2YgdGhlIHBvb2xzIGluIHRoZSBg - dG9wb2xvZ3ktcG9vbHNgIGxpc3QiLAogICAgICAgICkKCiAgICAgICAgdXBncmFkZV9ncm91cCA9 - IGFyZ1AuYWRkX2FyZ3VtZW50X2dyb3VwKCJ1cGdyYWRlIikKICAgICAgICB1cGdyYWRlX2dyb3Vw - LmFkZF9hcmd1bWVudCgKICAgICAgICAgICAgIi0tdXBncmFkZSIsCiAgICAgICAgICAgIGFjdGlv - bj0ic3RvcmVfdHJ1ZSIsCiAgICAgICAgICAgIGRlZmF1bHQ9RmFsc2UsCiAgICAgICAgICAgIGhl - bHA9IlVwZ3JhZGVzIHRoZSBjZXBoQ1NJS2V5cmluZ3MoRm9yIGV4YW1wbGU6IGNsaWVudC5jc2kt - Y2VwaGZzLXByb3Zpc2lvbmVyKSBhbmQgY2xpZW50LmhlYWx0aGNoZWNrZXIgY2VwaCB1c2VycyB3 - aXRoIG5ldyBwZXJtaXNzaW9ucyBuZWVkZWQgZm9yIHRoZSBuZXcgY2x1c3RlciB2ZXJzaW9uIGFu - ZCBvbGRlciBwZXJtaXNzaW9uIHdpbGwgc3RpbGwgYmUgYXBwbGllZC4iCiAgICAgICAgICAgICsg - IlNhbXBsZSBydW46IGBweXRob24zIC9ldGMvY2VwaC9jcmVhdGUtZXh0ZXJuYWwtY2x1c3Rlci1y - ZXNvdXJjZXMucHkgLS11cGdyYWRlYCwgdGhpcyB3aWxsIHVwZ3JhZGUgYWxsIHRoZSBkZWZhdWx0 - IGNzaSB1c2Vycyhub24tcmVzdHJpY3RlZCkiCiAgICAgICAgICAgICsgIkZvciByZXN0cmljdGVk - IHVzZXJzKEZvciBleGFtcGxlOiBjbGllbnQuY3NpLWNlcGhmcy1wcm92aXNpb25lci1vcGVuc2hp - ZnQtc3RvcmFnZS1teWZzKSwgdXNlcnMgY3JlYXRlZCB1c2luZyAtLXJlc3RyaWN0ZWQtYXV0aC1w - ZXJtaXNzaW9uIGZsYWcgbmVlZCB0byBwYXNzIG1hbmRhdG9yeSBmbGFncyIKICAgICAgICAgICAg - KyAibWFuZGF0b3J5IGZsYWdzOiAnLS1yYmQtZGF0YS1wb29sLW5hbWUsIC0tazhzLWNsdXN0ZXIt - bmFtZSBhbmQgLS1ydW4tYXMtdXNlcicgZmxhZ3Mgd2hpbGUgdXBncmFkaW5nIgogICAgICAgICAg - ICArICJpbiBjYXNlIG9mIGNlcGhmcyB1c2VycyBpZiB5b3UgaGF2ZSBwYXNzZWQgLS1jZXBoZnMt - ZmlsZXN5c3RlbS1uYW1lIGZsYWcgd2hpbGUgY3JlYXRpbmcgdXNlciB0aGVuIHdoaWxlIHVwZ3Jh - ZGluZyBpdCB3aWxsIGJlIG1hbmRhdG9yeSB0b28iCiAgICAgICAgICAgICsgIlNhbXBsZSBydW46 - IGBweXRob24zIC9ldGMvY2VwaC9jcmVhdGUtZXh0ZXJuYWwtY2x1c3Rlci1yZXNvdXJjZXMucHkg - LS11cGdyYWRlIC0tcmJkLWRhdGEtcG9vbC1uYW1lIHJlcGxpY2Fwb29sIC0tazhzLWNsdXN0ZXIt - bmFtZSByb29rc3RvcmFnZSAgLS1ydW4tYXMtdXNlciBjbGllbnQuY3NpLXJiZC1ub2RlLXJvb2tz - dG9yYWdlLXJlcGxpY2Fwb29sYCIKICAgICAgICAgICAgKyAiUFM6IEFuIGV4aXN0aW5nIG5vbi1y - ZXN0cmljdGVkIHVzZXIgY2Fubm90IGJlIGNvbnZlcnRlZCB0byBhIHJlc3RyaWN0ZWQgdXNlciBi - eSB1cGdyYWRpbmcuIgogICAgICAgICAgICArICJVcGdyYWRlIGZsYWcgc2hvdWxkIG9ubHkgYmUg - dXNlZCB0byBhcHBlbmQgbmV3IHBlcm1pc3Npb25zIHRvIHVzZXJzLCBpdCBzaG91bGRuJ3QgYmUg - dXNlZCBmb3IgY2hhbmdpbmcgdXNlciBhbHJlYWR5IGFwcGxpZWQgcGVybWlzc2lvbiwgZm9yIGV4 - YW1wbGUgeW91IHNob3VsZG4ndCBjaGFuZ2UgaW4gd2hpY2ggcG9vbCB1c2VyIGhhcyBhY2Nlc3Mi - LAogICAgICAgICkKCiAgICAgICAgIyBBZGQgY29tbWFuZC1saW5lIGFyZ3VtZW50cwogICAgICAg - IGNvbmZpZ19ncm91cCA9IGFyZ1AuYWRkX2FyZ3VtZW50X2dyb3VwKCJjb25maWciKQogICAgICAg - IGNvbmZpZ19ncm91cC5hZGRfYXJndW1lbnQoCiAgICAgICAgICAgICItLWNvbmZpZy1maWxlIiwK - ICAgICAgICAgICAgdHlwZT1zdHIsCiAgICAgICAgICAgIGhlbHA9IlBhdGggdG8gdGhlIGNvbmZp - Z3VyYXRpb24gZmlsZSwgUHJpb3JpdHk6IGNvbW1hbmQtbGluZS1hcmdzID4gY29uZmlnLmluaSBm - aWxlIHZhbHVlcyA+IGRlZmF1bHQgdmFsdWVzIiwKICAgICAgICAgICAgcmVxdWlyZWQ9RmFsc2Us - CiAgICAgICAgICAgIGRlZmF1bHQ9IiIsCiAgICAgICAgKQoKICAgICAgICBpZiBhcmdzX3RvX3Bh - cnNlOgogICAgICAgICAgICBhc3NlcnQgKAogICAgICAgICAgICAgICAgdHlwZShhcmdzX3RvX3Bh - cnNlKSA9PSBsaXN0CiAgICAgICAgICAgICksICJBcmd1bWVudCB0byAnZ2VuX2FyZ19wYXJzZXIn - IHNob3VsZCBiZSBhIGxpc3QiCiAgICAgICAgZWxzZToKICAgICAgICAgICAgYXJnc190b19wYXJz - ZSA9IHN5cy5hcmd2WzE6XQogICAgICAgIHJldHVybiBhcmdQLnBhcnNlX2FyZ3MoYXJnc190b19w - YXJzZSkKCiAgICBkZWYgdmFsaWRhdGVfcmJkX21ldGFkYXRhX2VjX3Bvb2xfbmFtZShzZWxmKToK - ICAgICAgICBpZiBzZWxmLl9hcmdfcGFyc2VyLnJiZF9tZXRhZGF0YV9lY19wb29sX25hbWU6CiAg - ICAgICAgICAgIHJiZF9tZXRhZGF0YV9lY19wb29sX25hbWUgPSBzZWxmLl9hcmdfcGFyc2VyLnJi - ZF9tZXRhZGF0YV9lY19wb29sX25hbWUKICAgICAgICAgICAgcmJkX3Bvb2xfbmFtZSA9IHNlbGYu - X2FyZ19wYXJzZXIucmJkX2RhdGFfcG9vbF9uYW1lCgogICAgICAgICAgICBpZiByYmRfcG9vbF9u - YW1lID09ICIiOgogICAgICAgICAgICAgICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlv - bigKICAgICAgICAgICAgICAgICAgICAiRmxhZyAnLS1yYmQtZGF0YS1wb29sLW5hbWUnIHNob3Vs - ZCBub3QgYmUgZW1wdHkiCiAgICAgICAgICAgICAgICApCgogICAgICAgICAgICBpZiByYmRfbWV0 - YWRhdGFfZWNfcG9vbF9uYW1lID09ICIiOgogICAgICAgICAgICAgICAgcmFpc2UgRXhlY3V0aW9u - RmFpbHVyZUV4Y2VwdGlvbigKICAgICAgICAgICAgICAgICAgICAiRmxhZyAnLS1yYmQtbWV0YWRh - dGEtZWMtcG9vbC1uYW1lJyBzaG91bGQgbm90IGJlIGVtcHR5IgogICAgICAgICAgICAgICAgKQoK - ICAgICAgICAgICAgY21kX2pzb24gPSB7InByZWZpeCI6ICJvc2QgZHVtcCIsICJmb3JtYXQiOiAi - anNvbiJ9CiAgICAgICAgICAgIHJldF92YWwsIGpzb25fb3V0LCBlcnJfbXNnID0gc2VsZi5fY29t - bW9uX2NtZF9qc29uX2dlbihjbWRfanNvbikKICAgICAgICAgICAgaWYgcmV0X3ZhbCAhPSAwIG9y - IGxlbihqc29uX291dCkgPT0gMDoKICAgICAgICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1 - cmVFeGNlcHRpb24oCiAgICAgICAgICAgICAgICAgICAgZiJ7Y21kX2pzb25bJ3ByZWZpeCddfSBj - b21tYW5kIGZhaWxlZC5cbiIKICAgICAgICAgICAgICAgICAgICBmIkVycm9yOiB7ZXJyX21zZyBp - ZiByZXRfdmFsICE9IDAgZWxzZSBzZWxmLkVNUFRZX09VVFBVVF9MSVNUfSIKICAgICAgICAgICAg - ICAgICkKICAgICAgICAgICAgbWV0YWRhdGFfcG9vbF9leGlzdCwgcG9vbF9leGlzdCA9IEZhbHNl - LCBGYWxzZQoKICAgICAgICAgICAgZm9yIGtleSBpbiBqc29uX291dFsicG9vbHMiXToKICAgICAg - ICAgICAgICAgICMgaWYgZXJhc3VyZV9jb2RlX3Byb2ZpbGUgaXMgZW1wdHkgYW5kIHBvb2wgbmFt - ZSBleGlzdHMgdGhlbiBpdCByZXBsaWNhIHBvb2wKICAgICAgICAgICAgICAgIGlmICgKICAgICAg - ICAgICAgICAgICAgICBrZXlbImVyYXN1cmVfY29kZV9wcm9maWxlIl0gPT0gIiIKICAgICAgICAg - ICAgICAgICAgICBhbmQga2V5WyJwb29sX25hbWUiXSA9PSByYmRfbWV0YWRhdGFfZWNfcG9vbF9u - YW1lCiAgICAgICAgICAgICAgICApOgogICAgICAgICAgICAgICAgICAgIG1ldGFkYXRhX3Bvb2xf - ZXhpc3QgPSBUcnVlCiAgICAgICAgICAgICAgICAjIGlmIGVyYXN1cmVfY29kZV9wcm9maWxlIGlz - IG5vdCBlbXB0eSBhbmQgcG9vbCBuYW1lIGV4aXN0cyB0aGVuIGl0IGlzIGVjIHBvb2wKICAgICAg - ICAgICAgICAgIGlmIGtleVsiZXJhc3VyZV9jb2RlX3Byb2ZpbGUiXSBhbmQga2V5WyJwb29sX25h - bWUiXSA9PSByYmRfcG9vbF9uYW1lOgogICAgICAgICAgICAgICAgICAgIHBvb2xfZXhpc3QgPSBU - cnVlCgogICAgICAgICAgICBpZiBub3QgbWV0YWRhdGFfcG9vbF9leGlzdDoKICAgICAgICAgICAg - ICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1cmVFeGNlcHRpb24oCiAgICAgICAgICAgICAgICAgICAg - IlByb3ZpZGVkIHJiZF9lY19tZXRhZGF0YV9wb29sIG5hbWUsIgogICAgICAgICAgICAgICAgICAg - IGYiIHtyYmRfbWV0YWRhdGFfZWNfcG9vbF9uYW1lfSwgZG9lcyBub3QgZXhpc3QiCiAgICAgICAg - ICAgICAgICApCiAgICAgICAgICAgIGlmIG5vdCBwb29sX2V4aXN0OgogICAgICAgICAgICAgICAg - cmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlvbigKICAgICAgICAgICAgICAgICAgICBmIlBy - b3ZpZGVkIHJiZF9kYXRhX3Bvb2wgbmFtZSwge3JiZF9wb29sX25hbWV9LCBkb2VzIG5vdCBleGlz - dCIKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgcmV0dXJuIHJiZF9tZXRhZGF0YV9lY19w - b29sX25hbWUKCiAgICBkZWYgZHJ5X3J1bihzZWxmLCBtc2cpOgogICAgICAgIGlmIHNlbGYuX2Fy - Z19wYXJzZXIuZHJ5X3J1bjoKICAgICAgICAgICAgcHJpbnQoIkV4ZWN1dGU6ICIgKyAiJyIgKyBt - c2cgKyAiJyIpCgogICAgZGVmIHZhbGlkYXRlX3Jnd19lbmRwb2ludF90bHNfY2VydChzZWxmKToK - ICAgICAgICBpZiBzZWxmLl9hcmdfcGFyc2VyLnJnd190bHNfY2VydF9wYXRoOgogICAgICAgICAg - ICB3aXRoIG9wZW4oc2VsZi5fYXJnX3BhcnNlci5yZ3dfdGxzX2NlcnRfcGF0aCwgZW5jb2Rpbmc9 - InV0ZjgiKSBhcyBmOgogICAgICAgICAgICAgICAgY29udGVudHMgPSBmLnJlYWQoKQogICAgICAg - ICAgICAgICAgcmV0dXJuIGNvbnRlbnRzLnJzdHJpcCgpCgogICAgZGVmIF9jaGVja19jb25mbGlj - dGluZ19vcHRpb25zKHNlbGYpOgogICAgICAgIGlmIG5vdCBzZWxmLl9hcmdfcGFyc2VyLnVwZ3Jh - ZGUgYW5kIG5vdCBzZWxmLl9hcmdfcGFyc2VyLnJiZF9kYXRhX3Bvb2xfbmFtZToKICAgICAgICAg - ICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlvbigKICAgICAgICAgICAgICAgICJFaXRo - ZXIgJy0tdXBncmFkZScgb3IgJy0tcmJkLWRhdGEtcG9vbC1uYW1lIDxwb29sX25hbWU+JyBzaG91 - bGQgYmUgc3BlY2lmaWVkIgogICAgICAgICAgICApCgogICAgZGVmIF9pbnZhbGlkX2VuZHBvaW50 - KHNlbGYsIGVuZHBvaW50X3N0cik6CiAgICAgICAgIyBleHRyYWN0IHRoZSBwb3J0IGJ5IGdldHRp - bmcgdGhlIGxhc3Qgc3BsaXQgb24gYDpgIGRlbGltaXRlcgogICAgICAgIHRyeToKICAgICAgICAg - ICAgZW5kcG9pbnRfc3RyX2lwLCBwb3J0ID0gZW5kcG9pbnRfc3RyLnJzcGxpdCgiOiIsIDEpCiAg - ICAgICAgZXhjZXB0IFZhbHVlRXJyb3I6CiAgICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1 - cmVFeGNlcHRpb24oZiJOb3QgYSBwcm9wZXIgZW5kcG9pbnQ6IHtlbmRwb2ludF9zdHJ9IikKCiAg - ICAgICAgdHJ5OgogICAgICAgICAgICBpZiBlbmRwb2ludF9zdHJfaXBbMF0gPT0gIlsiOgogICAg - ICAgICAgICAgICAgZW5kcG9pbnRfc3RyX2lwID0gZW5kcG9pbnRfc3RyX2lwWzEgOiBsZW4oZW5k - cG9pbnRfc3RyX2lwKSAtIDFdCiAgICAgICAgICAgIGlwX3R5cGUgPSAoCiAgICAgICAgICAgICAg - ICAiSVB2NCIgaWYgdHlwZShpcF9hZGRyZXNzKGVuZHBvaW50X3N0cl9pcCkpIGlzIElQdjRBZGRy - ZXNzIGVsc2UgIklQdjYiCiAgICAgICAgICAgICkKICAgICAgICBleGNlcHQgVmFsdWVFcnJvcjoK - ICAgICAgICAgICAgaXBfdHlwZSA9ICJGUUROIgogICAgICAgIGlmIG5vdCBwb3J0LmlzZGlnaXQo - KToKICAgICAgICAgICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlvbihmIlBvcnQgbm90 - IHZhbGlkOiB7cG9ydH0iKQogICAgICAgIGludFBvcnQgPSBpbnQocG9ydCkKICAgICAgICBpZiBp - bnRQb3J0IDwgMSBvciBpbnRQb3J0ID4gMioqMTYgLSAxOgogICAgICAgICAgICByYWlzZSBFeGVj - dXRpb25GYWlsdXJlRXhjZXB0aW9uKGYiT3V0IG9mIHJhbmdlIHBvcnQgbnVtYmVyOiB7cG9ydH0i - KQoKICAgICAgICByZXR1cm4gaXBfdHlwZQoKICAgIGRlZiBlbmRwb2ludF9kaWFsKHNlbGYsIGVu - ZHBvaW50X3N0ciwgaXBfdHlwZSwgdGltZW91dD0zLCBjZXJ0PU5vbmUpOgogICAgICAgICMgaWYg - dGhlICdjbHVzdGVyJyBpbnN0YW5jZSBpcyBhIGR1bW15IG9uZSwKICAgICAgICAjIGRvbid0IHRy - eSB0byByZWFjaCBvdXQgdG8gdGhlIGVuZHBvaW50CiAgICAgICAgaWYgaXNpbnN0YW5jZShzZWxm - LmNsdXN0ZXIsIER1bW15UmFkb3MpOgogICAgICAgICAgICByZXR1cm4gIiIsICIiLCAiIgogICAg - ICAgIGlmIGlwX3R5cGUgPT0gIklQdjYiOgogICAgICAgICAgICB0cnk6CiAgICAgICAgICAgICAg - ICBlbmRwb2ludF9zdHJfaXAsIGVuZHBvaW50X3N0cl9wb3J0ID0gZW5kcG9pbnRfc3RyLnJzcGxp - dCgiOiIsIDEpCiAgICAgICAgICAgIGV4Y2VwdCBWYWx1ZUVycm9yOgogICAgICAgICAgICAgICAg - cmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlvbigKICAgICAgICAgICAgICAgICAgICBmIk5v - dCBhIHByb3BlciBlbmRwb2ludDoge2VuZHBvaW50X3N0cn0iCiAgICAgICAgICAgICAgICApCiAg - ICAgICAgICAgIGlmIGVuZHBvaW50X3N0cl9pcFswXSAhPSAiWyI6CiAgICAgICAgICAgICAgICBl - bmRwb2ludF9zdHJfaXAgPSAiWyIgKyBlbmRwb2ludF9zdHJfaXAgKyAiXSIKICAgICAgICAgICAg - ZW5kcG9pbnRfc3RyID0gIjoiLmpvaW4oW2VuZHBvaW50X3N0cl9pcCwgZW5kcG9pbnRfc3RyX3Bv - cnRdKQoKICAgICAgICBwcm90b2NvbHMgPSBbImh0dHAiLCAiaHR0cHMiXQogICAgICAgIHJlc3Bv - bnNlX2Vycm9yID0gTm9uZQogICAgICAgIGZvciBwcmVmaXggaW4gcHJvdG9jb2xzOgogICAgICAg - ICAgICB0cnk6CiAgICAgICAgICAgICAgICBlcCA9IGYie3ByZWZpeH06Ly97ZW5kcG9pbnRfc3Ry - fSIKICAgICAgICAgICAgICAgIHZlcmlmeSA9IE5vbmUKICAgICAgICAgICAgICAgICMgSWYgdmVy - aWZ5IGlzIHNldCB0byBhIHBhdGggdG8gYSBkaXJlY3RvcnksCiAgICAgICAgICAgICAgICAjIHRo - ZSBkaXJlY3RvcnkgbXVzdCBoYXZlIGJlZW4gcHJvY2Vzc2VkIHVzaW5nIHRoZSBjX3JlaGFzaCB1 - dGlsaXR5IHN1cHBsaWVkIHdpdGggT3BlblNTTC4KICAgICAgICAgICAgICAgIGlmIHByZWZpeCA9 - PSAiaHR0cHMiIGFuZCBzZWxmLl9hcmdfcGFyc2VyLnJnd19za2lwX3RsczoKICAgICAgICAgICAg - ICAgICAgICB2ZXJpZnkgPSBGYWxzZQogICAgICAgICAgICAgICAgICAgIHIgPSByZXF1ZXN0cy5o - ZWFkKGVwLCB0aW1lb3V0PXRpbWVvdXQsIHZlcmlmeT1GYWxzZSkKICAgICAgICAgICAgICAgIGVs - aWYgcHJlZml4ID09ICJodHRwcyIgYW5kIGNlcnQ6CiAgICAgICAgICAgICAgICAgICAgdmVyaWZ5 - ID0gY2VydAogICAgICAgICAgICAgICAgICAgIHIgPSByZXF1ZXN0cy5oZWFkKGVwLCB0aW1lb3V0 - PXRpbWVvdXQsIHZlcmlmeT1jZXJ0KQogICAgICAgICAgICAgICAgZWxzZToKICAgICAgICAgICAg - ICAgICAgICByID0gcmVxdWVzdHMuaGVhZChlcCwgdGltZW91dD10aW1lb3V0KQogICAgICAgICAg - ICAgICAgaWYgci5zdGF0dXNfY29kZSA9PSAyMDA6CiAgICAgICAgICAgICAgICAgICAgcmV0dXJu - IHByZWZpeCwgdmVyaWZ5LCAiIgogICAgICAgICAgICBleGNlcHQgRXhjZXB0aW9uIGFzIGVycjoK - ICAgICAgICAgICAgICAgIHJlc3BvbnNlX2Vycm9yID0gZXJyCiAgICAgICAgICAgICAgICBjb250 - aW51ZQogICAgICAgIHN5cy5zdGRlcnIud3JpdGUoCiAgICAgICAgICAgIGYidW5hYmxlIHRvIGNv - bm5lY3QgdG8gZW5kcG9pbnQ6IHtlbmRwb2ludF9zdHJ9LCBmYWlsZWQgZXJyb3I6IHtyZXNwb25z - ZV9lcnJvcn0iCiAgICAgICAgKQogICAgICAgIHJldHVybiAoCiAgICAgICAgICAgICIiLAogICAg - ICAgICAgICAiIiwKICAgICAgICAgICAgKCItMSIpLAogICAgICAgICkKCiAgICBkZWYgcGFyc2Vf - Y29uZmlnX2ZpbGUoc2VsZiwgY29uZmlnX2ZpbGUpOgogICAgICAgIGNvbmZpZyA9IGNvbmZpZ3Bh - cnNlci5Db25maWdQYXJzZXIoKQogICAgICAgIGNvbmZpZy5yZWFkKGNvbmZpZ19maWxlKQogICAg - ICAgIGZvciBhcmcgaW4gbGlzdCh2YXJzKHNlbGYuX2FyZ19wYXJzZXIpKToKICAgICAgICAgICAg - IyBweXRob24gdHJlYXRzIGZsYWctbmFtZSBhcyBmbGFnX25hbWUgaW50ZXJuYWxseSwgc28gY29u - dmVydGluZyBiYWNrIHRvIGZsYWctbmFtZSwKICAgICAgICAgICAgIyBzbyB3ZSBjYW4gZ2V0IHRo - b3NlIHZhbHVlcyBmcm9tIGNvbmZpZyBmaWxlCiAgICAgICAgICAgIGFyZ3VtZW50ID0gYXJnLnJl - cGxhY2UoIl8iLCAiLSIpCiAgICAgICAgICAgIGFyZ3VtZW50VmFsdWUgPSBzdHIoZ2V0YXR0cihz - ZWxmLl9hcmdfcGFyc2VyLCBhcmcpKQogICAgICAgICAgICBjb25maWdfdmFsdWUgPSBjb25maWcu - Z2V0KCJDb25maWd1cmF0aW9ucyIsIGFyZ3VtZW50LCBmYWxsYmFjaz1Ob25lKQogICAgICAgICAg - ICAjIGdpdmUgcHJpb3JpdHkgdG8gY29tbWFuZCBsaW5lIGFyZ3VtZW50LCBpZiBjb21tYW5kIGxp - bmUgYXJndW1lbnQgaXMgbm90IHByZXNlbnQgdXNlIGNvbmZpZy5pbmkgdmFsdWUsCiAgICAgICAg - ICAgIGlmIChzdHIoc3lzLmFyZ3YpLmZpbmQoYXJndW1lbnQpID09IC0xKSBhbmQgKAogICAgICAg - ICAgICAgICAgKGNvbmZpZ192YWx1ZSAhPSBOb25lKSBhbmQgKGNvbmZpZ192YWx1ZSAhPSAiIikK - ICAgICAgICAgICAgKToKICAgICAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIuX19zZXRhdHRy - X18oYXJnLCBjb25maWdfdmFsdWUpCgogICAgICAgIHJldHVybiBjb25maWcKCiAgICBkZWYgX19p - bml0X18oc2VsZiwgYXJnX2xpc3Q9Tm9uZSk6CiAgICAgICAgc2VsZi5vdXRfbWFwID0ge30KICAg - ICAgICBzZWxmLl9leGNsdWRlZF9rZXlzID0gc2V0KCkKICAgICAgICBzZWxmLl9hcmdfcGFyc2Vy - ID0gc2VsZi5nZW5fYXJnX3BhcnNlcihhcmdzX3RvX3BhcnNlPWFyZ19saXN0KQogICAgICAgIGlm - IHNlbGYuX2FyZ19wYXJzZXIuY29uZmlnX2ZpbGU6CiAgICAgICAgICAgIHNlbGYuY29uZmlnID0g - c2VsZi5wYXJzZV9jb25maWdfZmlsZShzZWxmLl9hcmdfcGFyc2VyLmNvbmZpZ19maWxlKQogICAg - ICAgIHNlbGYuX2NoZWNrX2NvbmZsaWN0aW5nX29wdGlvbnMoKQogICAgICAgIHNlbGYucnVuX2Fz - X3VzZXIgPSBzZWxmLl9hcmdfcGFyc2VyLnJ1bl9hc191c2VyCiAgICAgICAgc2VsZi5vdXRwdXRf - ZmlsZSA9IHNlbGYuX2FyZ19wYXJzZXIub3V0cHV0CiAgICAgICAgc2VsZi5jZXBoX2NvbmYgPSBz - ZWxmLl9hcmdfcGFyc2VyLmNlcGhfY29uZgogICAgICAgIHNlbGYuY2VwaF9rZXlyaW5nID0gc2Vs - Zi5fYXJnX3BhcnNlci5rZXlyaW5nCiAgICAgICAgIyBpZiB1c2VyIG5vdCBwcm92aWRlZCwgZ2l2 - ZSBhIGRlZmF1bHQgdXNlcgogICAgICAgIGlmIG5vdCBzZWxmLnJ1bl9hc191c2VyIGFuZCBub3Qg - c2VsZi5fYXJnX3BhcnNlci51cGdyYWRlOgogICAgICAgICAgICBzZWxmLnJ1bl9hc191c2VyID0g - c2VsZi5FWFRFUk5BTF9VU0VSX05BTUUKICAgICAgICBpZiBub3Qgc2VsZi5fYXJnX3BhcnNlci5y - Z3dfcG9vbF9wcmVmaXggYW5kIG5vdCBzZWxmLl9hcmdfcGFyc2VyLnVwZ3JhZGU6CiAgICAgICAg - ICAgIHNlbGYuX2FyZ19wYXJzZXIucmd3X3Bvb2xfcHJlZml4ID0gc2VsZi5ERUZBVUxUX1JHV19Q - T09MX1BSRUZJWAogICAgICAgIGlmIHNlbGYuY2VwaF9jb25mOgogICAgICAgICAgICBrd2FyZ3Mg - PSB7fQogICAgICAgICAgICBpZiBzZWxmLmNlcGhfa2V5cmluZzoKICAgICAgICAgICAgICAgIGt3 - YXJnc1siY29uZiJdID0geyJrZXlyaW5nIjogc2VsZi5jZXBoX2tleXJpbmd9CiAgICAgICAgICAg - IHNlbGYuY2x1c3RlciA9IHJhZG9zLlJhZG9zKGNvbmZmaWxlPXNlbGYuY2VwaF9jb25mLCAqKmt3 - YXJncykKICAgICAgICBlbHNlOgogICAgICAgICAgICBzZWxmLmNsdXN0ZXIgPSByYWRvcy5SYWRv - cygpCiAgICAgICAgICAgIHNlbGYuY2x1c3Rlci5jb25mX3JlYWRfZmlsZSgpCiAgICAgICAgc2Vs - Zi5jbHVzdGVyLmNvbm5lY3QoKQoKICAgIGRlZiBzaHV0ZG93bihzZWxmKToKICAgICAgICBpZiBz - ZWxmLmNsdXN0ZXIuc3RhdGUgPT0gImNvbm5lY3RlZCI6CiAgICAgICAgICAgIHNlbGYuY2x1c3Rl - ci5zaHV0ZG93bigpCgogICAgZGVmIGdldF9mc2lkKHNlbGYpOgogICAgICAgIGlmIHNlbGYuX2Fy - Z19wYXJzZXIuZHJ5X3J1bjoKICAgICAgICAgICAgcmV0dXJuIHNlbGYuZHJ5X3J1bigiY2VwaCBm - c2lkIikKICAgICAgICByZXR1cm4gc3RyKHNlbGYuY2x1c3Rlci5nZXRfZnNpZCgpKQoKICAgIGRl - ZiBfY29tbW9uX2NtZF9qc29uX2dlbihzZWxmLCBjbWRfanNvbik6CiAgICAgICAgY21kID0ganNv - bi5kdW1wcyhjbWRfanNvbiwgc29ydF9rZXlzPVRydWUpCiAgICAgICAgcmV0X3ZhbCwgY21kX291 - dCwgZXJyX21zZyA9IHNlbGYuY2x1c3Rlci5tb25fY29tbWFuZChjbWQsIGIiIikKICAgICAgICBp - ZiBzZWxmLl9hcmdfcGFyc2VyLnZlcmJvc2U6CiAgICAgICAgICAgIHByaW50KGYiQ29tbWFuZCBJ - bnB1dDoge2NtZH0iKQogICAgICAgICAgICBwcmludCgKICAgICAgICAgICAgICAgIGYiUmV0dXJu - IFZhbDoge3JldF92YWx9XG5Db21tYW5kIE91dHB1dDoge2NtZF9vdXR9XG4iCiAgICAgICAgICAg - ICAgICBmIkVycm9yIE1lc3NhZ2U6IHtlcnJfbXNnfVxuLS0tLS0tLS0tLVxuIgogICAgICAgICAg - ICApCiAgICAgICAganNvbl9vdXQgPSB7fQogICAgICAgICMgaWYgdGhlcmUgaXMgbm8gZXJyb3Ig - KGkuZTsgcmV0X3ZhbCBpcyBaRVJPKSBhbmQgJ2NtZF9vdXQnIGlzIG5vdCBlbXB0eQogICAgICAg - ICMgdGhlbiBjb252ZXJ0ICdjbWRfb3V0JyB0byBhIGpzb24gb3V0cHV0CiAgICAgICAgaWYgcmV0 - X3ZhbCA9PSAwIGFuZCBjbWRfb3V0OgogICAgICAgICAgICBqc29uX291dCA9IGpzb24ubG9hZHMo - Y21kX291dCkKICAgICAgICByZXR1cm4gcmV0X3ZhbCwganNvbl9vdXQsIGVycl9tc2cKCiAgICBk - ZWYgZ2V0X2NlcGhfZXh0ZXJuYWxfbW9uX2RhdGEoc2VsZik6CiAgICAgICAgY21kX2pzb24gPSB7 - InByZWZpeCI6ICJxdW9ydW1fc3RhdHVzIiwgImZvcm1hdCI6ICJqc29uIn0KICAgICAgICBpZiBz - ZWxmLl9hcmdfcGFyc2VyLmRyeV9ydW46CiAgICAgICAgICAgIHJldHVybiBzZWxmLmRyeV9ydW4o - ImNlcGggIiArIGNtZF9qc29uWyJwcmVmaXgiXSkKICAgICAgICByZXRfdmFsLCBqc29uX291dCwg - ZXJyX21zZyA9IHNlbGYuX2NvbW1vbl9jbWRfanNvbl9nZW4oY21kX2pzb24pCiAgICAgICAgIyBp - ZiB0aGVyZSBpcyBhbiB1bnN1Y2Nlc3NmdWwgYXR0ZW1wdCwKICAgICAgICBpZiByZXRfdmFsICE9 - IDAgb3IgbGVuKGpzb25fb3V0KSA9PSAwOgogICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWls - dXJlRXhjZXB0aW9uKAogICAgICAgICAgICAgICAgIidxdW9ydW1fc3RhdHVzJyBjb21tYW5kIGZh - aWxlZC5cbiIKICAgICAgICAgICAgICAgIGYiRXJyb3I6IHtlcnJfbXNnIGlmIHJldF92YWwgIT0g - MCBlbHNlIHNlbGYuRU1QVFlfT1VUUFVUX0xJU1R9IgogICAgICAgICAgICApCiAgICAgICAgcV9s - ZWFkZXJfbmFtZSA9IGpzb25fb3V0WyJxdW9ydW1fbGVhZGVyX25hbWUiXQogICAgICAgIHFfbGVh - ZGVyX2RldGFpbHMgPSB7fQogICAgICAgIHFfbGVhZGVyX21hdGNoaW5nX2xpc3QgPSBbCiAgICAg - ICAgICAgIGwgZm9yIGwgaW4ganNvbl9vdXRbIm1vbm1hcCJdWyJtb25zIl0gaWYgbFsibmFtZSJd - ID09IHFfbGVhZGVyX25hbWUKICAgICAgICBdCiAgICAgICAgaWYgbGVuKHFfbGVhZGVyX21hdGNo - aW5nX2xpc3QpID09IDA6CiAgICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1cmVFeGNlcHRp - b24oIk5vIG1hdGNoaW5nICdtb24nIGRldGFpbHMgZm91bmQiKQogICAgICAgIHFfbGVhZGVyX2Rl - dGFpbHMgPSBxX2xlYWRlcl9tYXRjaGluZ19saXN0WzBdCiAgICAgICAgIyBnZXQgdGhlIGFkZHJl - c3MgdmVjdG9yIG9mIHRoZSBxdW9ydW0tbGVhZGVyCiAgICAgICAgcV9sZWFkZXJfYWRkcnZlYyA9 - IHFfbGVhZGVyX2RldGFpbHMuZ2V0KCJwdWJsaWNfYWRkcnMiLCB7fSkuZ2V0KCJhZGRydmVjIiwg - W10pCiAgICAgICAgaXBfYWRkciA9IHN0cihxX2xlYWRlcl9kZXRhaWxzWyJwdWJsaWNfYWRkciJd - LnNwbGl0KCIvIilbMF0pCgogICAgICAgIGlmIHNlbGYuX2FyZ19wYXJzZXIudjJfcG9ydF9lbmFi - bGU6CiAgICAgICAgICAgIGlmIHFfbGVhZGVyX2FkZHJ2ZWNbMF1bInR5cGUiXSA9PSAidjIiOgog - ICAgICAgICAgICAgICAgaXBfYWRkciA9IHFfbGVhZGVyX2FkZHJ2ZWNbMF1bImFkZHIiXQogICAg - ICAgICAgICBlbGlmIGxlbihxX2xlYWRlcl9hZGRydmVjKSA+IDEgYW5kIHFfbGVhZGVyX2FkZHJ2 - ZWNbMV1bInR5cGUiXSA9PSAidjIiOgogICAgICAgICAgICAgICAgaXBfYWRkciA9IHFfbGVhZGVy - X2FkZHJ2ZWNbMV1bImFkZHIiXQogICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgc3lz - LnN0ZGVyci53cml0ZSgKICAgICAgICAgICAgICAgICAgICAiJ3YyJyBhZGRyZXNzIHR5cGUgbm90 - IHByZXNlbnQsIGFuZCAndjItcG9ydC1lbmFibGUnIGZsYWcgaXMgcHJvdmlkZWQiCiAgICAgICAg - ICAgICAgICApCgogICAgICAgIHJldHVybiBmIntzdHIocV9sZWFkZXJfbmFtZSl9PXtpcF9hZGRy - fSIKCiAgICBkZWYgX2NvbnZlcnRfaG9zdG5hbWVfdG9faXAoc2VsZiwgaG9zdF9uYW1lLCBwb3J0 - LCBpcF90eXBlKToKICAgICAgICAjIGlmICdjbHVzdGVyJyBpbnN0YW5jZSBpcyBhIGR1bW15IHR5 - cGUsCiAgICAgICAgIyBjYWxsIHRoZSBkdW1teSBpbnN0YW5jZSdzICJjb252ZXJ0IiBtZXRob2QK - ICAgICAgICBpZiBub3QgaG9zdF9uYW1lOgogICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWls - dXJlRXhjZXB0aW9uKCJFbXB0eSBob3N0bmFtZSBwcm92aWRlZCIpCiAgICAgICAgaWYgaXNpbnN0 - YW5jZShzZWxmLmNsdXN0ZXIsIER1bW15UmFkb3MpOgogICAgICAgICAgICByZXR1cm4gc2VsZi5j - bHVzdGVyLl9jb252ZXJ0X2hvc3RuYW1lX3RvX2lwKGhvc3RfbmFtZSkKCiAgICAgICAgaWYgaXBf - dHlwZSA9PSAiRlFETiI6CiAgICAgICAgICAgICMgY2hlY2sgd2hpY2ggaXAgRlFETiBzaG91bGQg - YmUgY29udmVydGVkIHRvLCBJUHY0IG9yIElQdjYKICAgICAgICAgICAgIyBjaGVjayB0aGUgaG9z - dCBpcCwgdGhlIGVuZHBvaW50IGlwIHR5cGUgd291bGQgYmUgc2ltaWxhciB0byBob3N0IGlwCiAg - ICAgICAgICAgIGNtZF9qc29uID0geyJwcmVmaXgiOiAib3JjaCBob3N0IGxzIiwgImZvcm1hdCI6 - ICJqc29uIn0KICAgICAgICAgICAgcmV0X3ZhbCwganNvbl9vdXQsIGVycl9tc2cgPSBzZWxmLl9j - b21tb25fY21kX2pzb25fZ2VuKGNtZF9qc29uKQogICAgICAgICAgICAjIGlmIHRoZXJlIGlzIGFu - IHVuc3VjY2Vzc2Z1bCBhdHRlbXB0LAogICAgICAgICAgICBpZiByZXRfdmFsICE9IDAgb3IgbGVu - KGpzb25fb3V0KSA9PSAwOgogICAgICAgICAgICAgICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4 - Y2VwdGlvbigKICAgICAgICAgICAgICAgICAgICAiJ29yY2ggaG9zdCBscycgY29tbWFuZCBmYWls - ZWQuXG4iCiAgICAgICAgICAgICAgICAgICAgZiJFcnJvcjoge2Vycl9tc2cgaWYgcmV0X3ZhbCAh - PSAwIGVsc2Ugc2VsZi5FTVBUWV9PVVRQVVRfTElTVH0iCiAgICAgICAgICAgICAgICApCiAgICAg - ICAgICAgIGhvc3RfYWRkciA9IGpzb25fb3V0WzBdWyJhZGRyIl0KICAgICAgICAgICAgIyBhZGQg - OjgwIHNhbXBsZSBwb3J0IGluIGlwX3R5cGUsIGFzIF9pbnZhbGlkX2VuZHBvaW50IGFsc28gdmVy - aWZ5IHBvcnQKICAgICAgICAgICAgaG9zdF9pcF90eXBlID0gc2VsZi5faW52YWxpZF9lbmRwb2lu - dChob3N0X2FkZHIgKyAiOjgwIikKICAgICAgICAgICAgaW1wb3J0IHNvY2tldAoKICAgICAgICAg - ICAgaXAgPSBbXQogICAgICAgICAgICAjIGV4YW1wbGUgb3V0cHV0IFsoPEFkZHJlc3NGYW1pbHku - QUZfSU5FVDogMj4sIDxTb2NrZXRLaW5kLlNPQ0tfU1RSRUFNOiAxPiwgNiwgJycsICgnOTMuMTg0 - LjIxNi4zNCcsIDgwKSksIC4uLl0KICAgICAgICAgICAgIyB3ZSBuZWVkIHRvIGdldCA5My4xODQu - MjE2LjM0IHNvIGl0IHdvdWxkIGJlIGlwWzBdWzRdWzBdCiAgICAgICAgICAgIGlmIGhvc3RfaXBf - dHlwZSA9PSAiSVB2NiI6CiAgICAgICAgICAgICAgICBpcCA9IHNvY2tldC5nZXRhZGRyaW5mbygK - ICAgICAgICAgICAgICAgICAgICBob3N0X25hbWUsIHBvcnQsIGZhbWlseT1zb2NrZXQuQUZfSU5F - VDYsIHByb3RvPXNvY2tldC5JUFBST1RPX1RDUAogICAgICAgICAgICAgICAgKQogICAgICAgICAg - ICBlbGlmIGhvc3RfaXBfdHlwZSA9PSAiSVB2NCI6CiAgICAgICAgICAgICAgICBpcCA9IHNvY2tl - dC5nZXRhZGRyaW5mbygKICAgICAgICAgICAgICAgICAgICBob3N0X25hbWUsIHBvcnQsIGZhbWls - eT1zb2NrZXQuQUZfSU5FVCwgcHJvdG89c29ja2V0LklQUFJPVE9fVENQCiAgICAgICAgICAgICAg - ICApCiAgICAgICAgICAgIGRlbCBzb2NrZXQKICAgICAgICAgICAgcmV0dXJuIGlwWzBdWzRdWzBd - CiAgICAgICAgcmV0dXJuIGhvc3RfbmFtZQoKICAgIGRlZiBnZXRfYWN0aXZlX2FuZF9zdGFuZGJ5 - X21ncnMoc2VsZik6CiAgICAgICAgaWYgc2VsZi5fYXJnX3BhcnNlci5kcnlfcnVuOgogICAgICAg - ICAgICByZXR1cm4gIiIsIHNlbGYuZHJ5X3J1bigiY2VwaCBzdGF0dXMiKQogICAgICAgIG1vbml0 - b3JpbmdfZW5kcG9pbnRfcG9ydCA9IHNlbGYuX2FyZ19wYXJzZXIubW9uaXRvcmluZ19lbmRwb2lu - dF9wb3J0CiAgICAgICAgbW9uaXRvcmluZ19lbmRwb2ludF9pcF9saXN0ID0gc2VsZi5fYXJnX3Bh - cnNlci5tb25pdG9yaW5nX2VuZHBvaW50CiAgICAgICAgc3RhbmRieV9tZ3JzID0gW10KICAgICAg - ICBpZiBub3QgbW9uaXRvcmluZ19lbmRwb2ludF9pcF9saXN0OgogICAgICAgICAgICBjbWRfanNv - biA9IHsicHJlZml4IjogInN0YXR1cyIsICJmb3JtYXQiOiAianNvbiJ9CiAgICAgICAgICAgIHJl - dF92YWwsIGpzb25fb3V0LCBlcnJfbXNnID0gc2VsZi5fY29tbW9uX2NtZF9qc29uX2dlbihjbWRf - anNvbikKICAgICAgICAgICAgIyBpZiB0aGVyZSBpcyBhbiB1bnN1Y2Nlc3NmdWwgYXR0ZW1wdCwK - ICAgICAgICAgICAgaWYgcmV0X3ZhbCAhPSAwIG9yIGxlbihqc29uX291dCkgPT0gMDoKICAgICAg - ICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1cmVFeGNlcHRpb24oCiAgICAgICAgICAgICAg - ICAgICAgIidtZ3Igc2VydmljZXMnIGNvbW1hbmQgZmFpbGVkLlxuIgogICAgICAgICAgICAgICAg - ICAgIGYiRXJyb3I6IHtlcnJfbXNnIGlmIHJldF92YWwgIT0gMCBlbHNlIHNlbGYuRU1QVFlfT1VU - UFVUX0xJU1R9IgogICAgICAgICAgICAgICAgKQogICAgICAgICAgICBtb25pdG9yaW5nX2VuZHBv - aW50ID0gKAogICAgICAgICAgICAgICAganNvbl9vdXQuZ2V0KCJtZ3JtYXAiLCB7fSkuZ2V0KCJz - ZXJ2aWNlcyIsIHt9KS5nZXQoInByb21ldGhldXMiLCAiIikKICAgICAgICAgICAgKQogICAgICAg - ICAgICBpZiBub3QgbW9uaXRvcmluZ19lbmRwb2ludDoKICAgICAgICAgICAgICAgIHJhaXNlIEV4 - ZWN1dGlvbkZhaWx1cmVFeGNlcHRpb24oCiAgICAgICAgICAgICAgICAgICAgImNhbid0IGZpbmQg - bW9uaXRvcmluZ19lbmRwb2ludCwgcHJvbWV0aGV1cyBtb2R1bGUgbWlnaHQgbm90IGJlIGVuYWJs - ZWQsICIKICAgICAgICAgICAgICAgICAgICAiZW5hYmxlIHRoZSBtb2R1bGUgYnkgcnVubmluZyAn - Y2VwaCBtZ3IgbW9kdWxlIGVuYWJsZSBwcm9tZXRoZXVzJyIKICAgICAgICAgICAgICAgICkKICAg - ICAgICAgICAgIyBub3cgY2hlY2sgdGhlIHN0YW5kLWJ5IG1nci1zCiAgICAgICAgICAgIHN0YW5k - YnlfYXJyID0ganNvbl9vdXQuZ2V0KCJtZ3JtYXAiLCB7fSkuZ2V0KCJzdGFuZGJ5cyIsIFtdKQog - ICAgICAgICAgICBmb3IgZWFjaF9zdGFuZGJ5IGluIHN0YW5kYnlfYXJyOgogICAgICAgICAgICAg - ICAgaWYgIm5hbWUiIGluIGVhY2hfc3RhbmRieS5rZXlzKCk6CiAgICAgICAgICAgICAgICAgICAg - c3RhbmRieV9tZ3JzLmFwcGVuZChlYWNoX3N0YW5kYnlbIm5hbWUiXSkKICAgICAgICAgICAgdHJ5 - OgogICAgICAgICAgICAgICAgcGFyc2VkX2VuZHBvaW50ID0gdXJscGFyc2UobW9uaXRvcmluZ19l - bmRwb2ludCkKICAgICAgICAgICAgZXhjZXB0IFZhbHVlRXJyb3I6CiAgICAgICAgICAgICAgICBy - YWlzZSBFeGVjdXRpb25GYWlsdXJlRXhjZXB0aW9uKAogICAgICAgICAgICAgICAgICAgIGYiaW52 - YWxpZCBlbmRwb2ludDoge21vbml0b3JpbmdfZW5kcG9pbnR9IgogICAgICAgICAgICAgICAgKQog - ICAgICAgICAgICBtb25pdG9yaW5nX2VuZHBvaW50X2lwX2xpc3QgPSBwYXJzZWRfZW5kcG9pbnQu - aG9zdG5hbWUKICAgICAgICAgICAgaWYgbm90IG1vbml0b3JpbmdfZW5kcG9pbnRfcG9ydDoKICAg - ICAgICAgICAgICAgIG1vbml0b3JpbmdfZW5kcG9pbnRfcG9ydCA9IHN0cihwYXJzZWRfZW5kcG9p - bnQucG9ydCkKCiAgICAgICAgIyBpZiBtb25pdG9yaW5nIGVuZHBvaW50IHBvcnQgaXMgbm90IHNl - dCwgcHV0IGEgZGVmYXVsdCBtb24gcG9ydAogICAgICAgIGlmIG5vdCBtb25pdG9yaW5nX2VuZHBv - aW50X3BvcnQ6CiAgICAgICAgICAgIG1vbml0b3JpbmdfZW5kcG9pbnRfcG9ydCA9IHNlbGYuREVG - QVVMVF9NT05JVE9SSU5HX0VORFBPSU5UX1BPUlQKCiAgICAgICAgIyB1c2VyIGNvdWxkIGdpdmUg - Y29tbWEgYW5kIHNwYWNlIHNlcGFyYXRlZCBpbnB1dHMgKGxpa2UgLS1tb25pdG9yaW5nLWVuZHBv - aW50PSI8aXAxPiwgPGlwMj4iKQogICAgICAgIG1vbml0b3JpbmdfZW5kcG9pbnRfaXBfbGlzdCA9 - IG1vbml0b3JpbmdfZW5kcG9pbnRfaXBfbGlzdC5yZXBsYWNlKCIsIiwgIiAiKQogICAgICAgIG1v - bml0b3JpbmdfZW5kcG9pbnRfaXBfbGlzdF9zcGxpdCA9IG1vbml0b3JpbmdfZW5kcG9pbnRfaXBf - bGlzdC5zcGxpdCgpCiAgICAgICAgIyBpZiBtb25pdG9yaW5nLWVuZHBvaW50IGNvdWxkIG5vdCBi - ZSBmb3VuZCwgcmFpc2UgYW4gZXJyb3IKICAgICAgICBpZiBsZW4obW9uaXRvcmluZ19lbmRwb2lu - dF9pcF9saXN0X3NwbGl0KSA9PSAwOgogICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWlsdXJl - RXhjZXB0aW9uKCJObyAnbW9uaXRvcmluZy1lbmRwb2ludCcgZm91bmQiKQogICAgICAgICMgZmly - c3QgaXAgaXMgdHJlYXRlZCBhcyB0aGUgbWFpbiBtb25pdG9yaW5nLWVuZHBvaW50CiAgICAgICAg - bW9uaXRvcmluZ19lbmRwb2ludF9pcCA9IG1vbml0b3JpbmdfZW5kcG9pbnRfaXBfbGlzdF9zcGxp - dFswXQogICAgICAgICMgcmVzdCBvZiB0aGUgaXAtcyBhcmUgYWRkZWQgdG8gdGhlICdzdGFuZGJ5 - X21ncnMnIGxpc3QKICAgICAgICBzdGFuZGJ5X21ncnMuZXh0ZW5kKG1vbml0b3JpbmdfZW5kcG9p - bnRfaXBfbGlzdF9zcGxpdFsxOl0pCiAgICAgICAgZmFpbGVkX2lwID0gbW9uaXRvcmluZ19lbmRw - b2ludF9pcAoKICAgICAgICBtb25pdG9yaW5nX2VuZHBvaW50ID0gIjoiLmpvaW4oCiAgICAgICAg - ICAgIFttb25pdG9yaW5nX2VuZHBvaW50X2lwLCBtb25pdG9yaW5nX2VuZHBvaW50X3BvcnRdCiAg - ICAgICAgKQogICAgICAgIGlwX3R5cGUgPSBzZWxmLl9pbnZhbGlkX2VuZHBvaW50KG1vbml0b3Jp - bmdfZW5kcG9pbnQpCiAgICAgICAgdHJ5OgogICAgICAgICAgICBtb25pdG9yaW5nX2VuZHBvaW50 - X2lwID0gc2VsZi5fY29udmVydF9ob3N0bmFtZV90b19pcCgKICAgICAgICAgICAgICAgIG1vbml0 - b3JpbmdfZW5kcG9pbnRfaXAsIG1vbml0b3JpbmdfZW5kcG9pbnRfcG9ydCwgaXBfdHlwZQogICAg - ICAgICAgICApCiAgICAgICAgICAgICMgY29sbGVjdCBhbGwgdGhlICdzdGFuZC1ieScgbWdyIGlw - cwogICAgICAgICAgICBtZ3JfaXBzID0gW10KICAgICAgICAgICAgZm9yIGVhY2hfc3RhbmRieV9t - Z3IgaW4gc3RhbmRieV9tZ3JzOgogICAgICAgICAgICAgICAgZmFpbGVkX2lwID0gZWFjaF9zdGFu - ZGJ5X21ncgogICAgICAgICAgICAgICAgbWdyX2lwcy5hcHBlbmQoCiAgICAgICAgICAgICAgICAg - ICAgc2VsZi5fY29udmVydF9ob3N0bmFtZV90b19pcCgKICAgICAgICAgICAgICAgICAgICAgICAg - ZWFjaF9zdGFuZGJ5X21nciwgbW9uaXRvcmluZ19lbmRwb2ludF9wb3J0LCBpcF90eXBlCiAgICAg - ICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgKQogICAgICAgIGV4Y2VwdDoKICAgICAg - ICAgICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlvbigKICAgICAgICAgICAgICAgIGYi - Q29udmVyc2lvbiBvZiBob3N0OiB7ZmFpbGVkX2lwfSB0byBJUCBmYWlsZWQuICIKICAgICAgICAg - ICAgICAgICJQbGVhc2UgZW50ZXIgdGhlIElQIGFkZHJlc3NlcyBvZiBhbGwgdGhlIGNlcGgtbWdy - cyB3aXRoIHRoZSAnLS1tb25pdG9yaW5nLWVuZHBvaW50JyBmbGFnIgogICAgICAgICAgICApCgog - ICAgICAgIF8sIF8sIGVyciA9IHNlbGYuZW5kcG9pbnRfZGlhbChtb25pdG9yaW5nX2VuZHBvaW50 - LCBpcF90eXBlKQogICAgICAgIGlmIGVyciA9PSAiLTEiOgogICAgICAgICAgICByYWlzZSBFeGVj - dXRpb25GYWlsdXJlRXhjZXB0aW9uKGVycikKICAgICAgICAjIGFkZCB0aGUgdmFsaWRhdGVkIGFj - dGl2ZSBtZ3IgSVAgaW50byB0aGUgZmlyc3QgaW5kZXgKICAgICAgICBtZ3JfaXBzLmluc2VydCgw - LCBtb25pdG9yaW5nX2VuZHBvaW50X2lwKQogICAgICAgIGFsbF9tZ3JfaXBzX3N0ciA9ICIsIi5q - b2luKG1ncl9pcHMpCiAgICAgICAgcmV0dXJuIGFsbF9tZ3JfaXBzX3N0ciwgbW9uaXRvcmluZ19l - bmRwb2ludF9wb3J0CgogICAgZGVmIGNoZWNrX3VzZXJfZXhpc3Qoc2VsZiwgdXNlcik6CiAgICAg - ICAgY21kX2pzb24gPSB7InByZWZpeCI6ICJhdXRoIGdldCIsICJlbnRpdHkiOiBmInt1c2VyfSIs - ICJmb3JtYXQiOiAianNvbiJ9CiAgICAgICAgcmV0X3ZhbCwganNvbl9vdXQsIF8gPSBzZWxmLl9j - b21tb25fY21kX2pzb25fZ2VuKGNtZF9qc29uKQogICAgICAgIGlmIHJldF92YWwgIT0gMCBvciBs - ZW4oanNvbl9vdXQpID09IDA6CiAgICAgICAgICAgIHJldHVybiAiIgogICAgICAgIHJldHVybiBz - dHIoanNvbl9vdXRbMF1bImtleSJdKQoKICAgIGRlZiBnZXRfY2VwaGZzX3Byb3Zpc2lvbmVyX2Nh - cHNfYW5kX2VudGl0eShzZWxmKToKICAgICAgICBlbnRpdHkgPSAiY2xpZW50LmNzaS1jZXBoZnMt - cHJvdmlzaW9uZXIiCiAgICAgICAgY2FwcyA9IHsKICAgICAgICAgICAgIm1vbiI6ICJhbGxvdyBy - LCBhbGxvdyBjb21tYW5kICdvc2QgYmxvY2tsaXN0JyIsCiAgICAgICAgICAgICJtZ3IiOiAiYWxs - b3cgcnciLAogICAgICAgICAgICAib3NkIjogImFsbG93IHJ3IHRhZyBjZXBoZnMgbWV0YWRhdGE9 - KiIsCiAgICAgICAgICAgICJtZHMiOiAiYWxsb3cgKiIsCiAgICAgICAgfQogICAgICAgIGlmIHNl - bGYuX2FyZ19wYXJzZXIucmVzdHJpY3RlZF9hdXRoX3Blcm1pc3Npb246CiAgICAgICAgICAgIGs4 - c19jbHVzdGVyX25hbWUgPSBzZWxmLl9hcmdfcGFyc2VyLms4c19jbHVzdGVyX25hbWUKICAgICAg - ICAgICAgaWYgazhzX2NsdXN0ZXJfbmFtZSA9PSAiIjoKICAgICAgICAgICAgICAgIHJhaXNlIEV4 - ZWN1dGlvbkZhaWx1cmVFeGNlcHRpb24oCiAgICAgICAgICAgICAgICAgICAgIms4c19jbHVzdGVy - X25hbWUgbm90IGZvdW5kLCBwbGVhc2Ugc2V0IHRoZSAnLS1rOHMtY2x1c3Rlci1uYW1lJyBmbGFn - IgogICAgICAgICAgICAgICAgKQogICAgICAgICAgICBjZXBoZnNfZmlsZXN5c3RlbSA9IHNlbGYu - X2FyZ19wYXJzZXIuY2VwaGZzX2ZpbGVzeXN0ZW1fbmFtZQogICAgICAgICAgICBpZiBjZXBoZnNf - ZmlsZXN5c3RlbSA9PSAiIjoKICAgICAgICAgICAgICAgIGVudGl0eSA9IGYie2VudGl0eX0te2s4 - c19jbHVzdGVyX25hbWV9IgogICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgZW50aXR5 - ID0gZiJ7ZW50aXR5fS17azhzX2NsdXN0ZXJfbmFtZX0te2NlcGhmc19maWxlc3lzdGVtfSIKICAg - ICAgICAgICAgICAgIGNhcHNbIm9zZCJdID0gZiJhbGxvdyBydyB0YWcgY2VwaGZzIG1ldGFkYXRh - PXtjZXBoZnNfZmlsZXN5c3RlbX0iCgogICAgICAgIHJldHVybiBjYXBzLCBlbnRpdHkKCiAgICBk - ZWYgZ2V0X2NlcGhmc19ub2RlX2NhcHNfYW5kX2VudGl0eShzZWxmKToKICAgICAgICBlbnRpdHkg - PSAiY2xpZW50LmNzaS1jZXBoZnMtbm9kZSIKICAgICAgICBjYXBzID0gewogICAgICAgICAgICAi - bW9uIjogImFsbG93IHIsIGFsbG93IGNvbW1hbmQgJ29zZCBibG9ja2xpc3QnIiwKICAgICAgICAg - ICAgIm1nciI6ICJhbGxvdyBydyIsCiAgICAgICAgICAgICJvc2QiOiAiYWxsb3cgcncgdGFnIGNl - cGhmcyAqPSoiLAogICAgICAgICAgICAibWRzIjogImFsbG93IHJ3IiwKICAgICAgICB9CiAgICAg - ICAgaWYgc2VsZi5fYXJnX3BhcnNlci5yZXN0cmljdGVkX2F1dGhfcGVybWlzc2lvbjoKICAgICAg - ICAgICAgazhzX2NsdXN0ZXJfbmFtZSA9IHNlbGYuX2FyZ19wYXJzZXIuazhzX2NsdXN0ZXJfbmFt - ZQogICAgICAgICAgICBpZiBrOHNfY2x1c3Rlcl9uYW1lID09ICIiOgogICAgICAgICAgICAgICAg - cmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlvbigKICAgICAgICAgICAgICAgICAgICAiazhz - X2NsdXN0ZXJfbmFtZSBub3QgZm91bmQsIHBsZWFzZSBzZXQgdGhlICctLWs4cy1jbHVzdGVyLW5h - bWUnIGZsYWciCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgIGNlcGhmc19maWxlc3lzdGVt - ID0gc2VsZi5fYXJnX3BhcnNlci5jZXBoZnNfZmlsZXN5c3RlbV9uYW1lCiAgICAgICAgICAgIGlm - IGNlcGhmc19maWxlc3lzdGVtID09ICIiOgogICAgICAgICAgICAgICAgZW50aXR5ID0gZiJ7ZW50 - aXR5fS17azhzX2NsdXN0ZXJfbmFtZX0iCiAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAg - ICBlbnRpdHkgPSBmIntlbnRpdHl9LXtrOHNfY2x1c3Rlcl9uYW1lfS17Y2VwaGZzX2ZpbGVzeXN0 - ZW19IgogICAgICAgICAgICAgICAgY2Fwc1sib3NkIl0gPSBmImFsbG93IHJ3IHRhZyBjZXBoZnMg - Kj17Y2VwaGZzX2ZpbGVzeXN0ZW19IgoKICAgICAgICByZXR1cm4gY2FwcywgZW50aXR5CgogICAg - ZGVmIGdldF9lbnRpdHkoCiAgICAgICAgc2VsZiwKICAgICAgICBlbnRpdHksCiAgICAgICAgcmJk - X3Bvb2xfbmFtZSwKICAgICAgICBhbGlhc19yYmRfcG9vbF9uYW1lLAogICAgICAgIGs4c19jbHVz - dGVyX25hbWUsCiAgICAgICAgcmFkb3NfbmFtZXNwYWNlLAogICAgKToKICAgICAgICBpZiAoCiAg - ICAgICAgICAgIHJiZF9wb29sX25hbWUuY291bnQoIi4iKSAhPSAwCiAgICAgICAgICAgIG9yIHJi - ZF9wb29sX25hbWUuY291bnQoIl8iKSAhPSAwCiAgICAgICAgICAgIG9yIGFsaWFzX3JiZF9wb29s - X25hbWUgIT0gIiIKICAgICAgICAgICAgIyBjaGVja2luZyBhbGlhc19yYmRfcG9vbF9uYW1lIGlz - IG5vdCBlbXB0eSBhcyB0aGVyZSBtYXliZSBhIHNwZWNpYWwgY2hhcmFjdGVyIHVzZWQgb3RoZXIg - dGhhbiAuIG9yIF8KICAgICAgICApOgogICAgICAgICAgICBpZiBhbGlhc19yYmRfcG9vbF9uYW1l - ID09ICIiOgogICAgICAgICAgICAgICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlvbigK - ICAgICAgICAgICAgICAgICAgICAicGxlYXNlIHNldCB0aGUgJy0tYWxpYXMtcmJkLWRhdGEtcG9v - bC1uYW1lJyBmbGFnIGFzIHRoZSByYmQgZGF0YSBwb29sIG5hbWUgY29udGFpbnMgJy4nIG9yICdf - JyIKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgaWYgKAogICAgICAgICAgICAgICAgYWxp - YXNfcmJkX3Bvb2xfbmFtZS5jb3VudCgiLiIpICE9IDAKICAgICAgICAgICAgICAgIG9yIGFsaWFz - X3JiZF9wb29sX25hbWUuY291bnQoIl8iKSAhPSAwCiAgICAgICAgICAgICk6CiAgICAgICAgICAg - ICAgICByYWlzZSBFeGVjdXRpb25GYWlsdXJlRXhjZXB0aW9uKAogICAgICAgICAgICAgICAgICAg - ICInLS1hbGlhcy1yYmQtZGF0YS1wb29sLW5hbWUnIGZsYWcgdmFsdWUgc2hvdWxkIG5vdCBjb250 - YWluICcuJyBvciAnXyciCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgIGVudGl0eSA9IGYi - e2VudGl0eX0te2s4c19jbHVzdGVyX25hbWV9LXthbGlhc19yYmRfcG9vbF9uYW1lfSIKICAgICAg - ICBlbHNlOgogICAgICAgICAgICBlbnRpdHkgPSBmIntlbnRpdHl9LXtrOHNfY2x1c3Rlcl9uYW1l - fS17cmJkX3Bvb2xfbmFtZX0iCgogICAgICAgIGlmIHJhZG9zX25hbWVzcGFjZToKICAgICAgICAg - ICAgZW50aXR5ID0gZiJ7ZW50aXR5fS17cmFkb3NfbmFtZXNwYWNlfSIKICAgICAgICByZXR1cm4g - ZW50aXR5CgogICAgZGVmIGdldF9yYmRfcHJvdmlzaW9uZXJfY2Fwc19hbmRfZW50aXR5KHNlbGYp - OgogICAgICAgIGVudGl0eSA9ICJjbGllbnQuY3NpLXJiZC1wcm92aXNpb25lciIKICAgICAgICBj - YXBzID0gewogICAgICAgICAgICAibW9uIjogInByb2ZpbGUgcmJkLCBhbGxvdyBjb21tYW5kICdv - c2QgYmxvY2tsaXN0JyIsCiAgICAgICAgICAgICJtZ3IiOiAiYWxsb3cgcnciLAogICAgICAgICAg - ICAib3NkIjogInByb2ZpbGUgcmJkIiwKICAgICAgICB9CiAgICAgICAgaWYgc2VsZi5fYXJnX3Bh - cnNlci5yZXN0cmljdGVkX2F1dGhfcGVybWlzc2lvbjoKICAgICAgICAgICAgcmJkX3Bvb2xfbmFt - ZSA9IHNlbGYuX2FyZ19wYXJzZXIucmJkX2RhdGFfcG9vbF9uYW1lCiAgICAgICAgICAgIGFsaWFz - X3JiZF9wb29sX25hbWUgPSBzZWxmLl9hcmdfcGFyc2VyLmFsaWFzX3JiZF9kYXRhX3Bvb2xfbmFt - ZQogICAgICAgICAgICBrOHNfY2x1c3Rlcl9uYW1lID0gc2VsZi5fYXJnX3BhcnNlci5rOHNfY2x1 - c3Rlcl9uYW1lCiAgICAgICAgICAgIHJhZG9zX25hbWVzcGFjZSA9IHNlbGYuX2FyZ19wYXJzZXIu - cmFkb3NfbmFtZXNwYWNlCiAgICAgICAgICAgIGlmIHJiZF9wb29sX25hbWUgPT0gIiI6CiAgICAg - ICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWlsdXJlRXhjZXB0aW9uKAogICAgICAgICAgICAg - ICAgICAgICJtYW5kYXRvcnkgZmxhZyBub3QgZm91bmQsIHBsZWFzZSBzZXQgdGhlICctLXJiZC1k - YXRhLXBvb2wtbmFtZScgZmxhZyIKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgaWYgazhz - X2NsdXN0ZXJfbmFtZSA9PSAiIjoKICAgICAgICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1 - cmVFeGNlcHRpb24oCiAgICAgICAgICAgICAgICAgICAgIm1hbmRhdG9yeSBmbGFnIG5vdCBmb3Vu - ZCwgcGxlYXNlIHNldCB0aGUgJy0tazhzLWNsdXN0ZXItbmFtZScgZmxhZyIKICAgICAgICAgICAg - ICAgICkKICAgICAgICAgICAgZW50aXR5ID0gc2VsZi5nZXRfZW50aXR5KAogICAgICAgICAgICAg - ICAgZW50aXR5LAogICAgICAgICAgICAgICAgcmJkX3Bvb2xfbmFtZSwKICAgICAgICAgICAgICAg - IGFsaWFzX3JiZF9wb29sX25hbWUsCiAgICAgICAgICAgICAgICBrOHNfY2x1c3Rlcl9uYW1lLAog - ICAgICAgICAgICAgICAgcmFkb3NfbmFtZXNwYWNlLAogICAgICAgICAgICApCiAgICAgICAgICAg - IGlmIHJhZG9zX25hbWVzcGFjZSAhPSAiIjoKICAgICAgICAgICAgICAgIGNhcHNbIm9zZCJdID0g - KAogICAgICAgICAgICAgICAgICAgIGYicHJvZmlsZSByYmQgcG9vbD17cmJkX3Bvb2xfbmFtZX0g - bmFtZXNwYWNlPXtyYWRvc19uYW1lc3BhY2V9IgogICAgICAgICAgICAgICAgKQogICAgICAgICAg - ICBlbHNlOgogICAgICAgICAgICAgICAgY2Fwc1sib3NkIl0gPSBmInByb2ZpbGUgcmJkIHBvb2w9 - e3JiZF9wb29sX25hbWV9IgoKICAgICAgICByZXR1cm4gY2FwcywgZW50aXR5CgogICAgZGVmIGdl - dF9yYmRfbm9kZV9jYXBzX2FuZF9lbnRpdHkoc2VsZik6CiAgICAgICAgZW50aXR5ID0gImNsaWVu - dC5jc2ktcmJkLW5vZGUiCiAgICAgICAgY2FwcyA9IHsKICAgICAgICAgICAgIm1vbiI6ICJwcm9m - aWxlIHJiZCwgYWxsb3cgY29tbWFuZCAnb3NkIGJsb2NrbGlzdCciLAogICAgICAgICAgICAib3Nk - IjogInByb2ZpbGUgcmJkIiwKICAgICAgICB9CiAgICAgICAgaWYgc2VsZi5fYXJnX3BhcnNlci5y - ZXN0cmljdGVkX2F1dGhfcGVybWlzc2lvbjoKICAgICAgICAgICAgcmJkX3Bvb2xfbmFtZSA9IHNl - bGYuX2FyZ19wYXJzZXIucmJkX2RhdGFfcG9vbF9uYW1lCiAgICAgICAgICAgIGFsaWFzX3JiZF9w - b29sX25hbWUgPSBzZWxmLl9hcmdfcGFyc2VyLmFsaWFzX3JiZF9kYXRhX3Bvb2xfbmFtZQogICAg - ICAgICAgICBrOHNfY2x1c3Rlcl9uYW1lID0gc2VsZi5fYXJnX3BhcnNlci5rOHNfY2x1c3Rlcl9u - YW1lCiAgICAgICAgICAgIHJhZG9zX25hbWVzcGFjZSA9IHNlbGYuX2FyZ19wYXJzZXIucmFkb3Nf - bmFtZXNwYWNlCiAgICAgICAgICAgIGlmIHJiZF9wb29sX25hbWUgPT0gIiI6CiAgICAgICAgICAg + ICAgIi0tcmJkLW1ldGFkYXRhLWVjLXBvb2wtbmFtZSIsCiAgICAgICAgICAgIGRlZmF1bHQ9IiIs + CiAgICAgICAgICAgIHJlcXVpcmVkPUZhbHNlLAogICAgICAgICAgICBoZWxwPSJQcm92aWRlcyB0 + aGUgbmFtZSBvZiBlcmFzdXJlIGNvZGVkIFJCRCBtZXRhZGF0YSBwb29sIiwKICAgICAgICApCiAg + ICAgICAgb3V0cHV0X2dyb3VwLmFkZF9hcmd1bWVudCgKICAgICAgICAgICAgIi0tZHJ5LXJ1biIs + CiAgICAgICAgICAgIGRlZmF1bHQ9RmFsc2UsCiAgICAgICAgICAgIGFjdGlvbj0ic3RvcmVfdHJ1 + ZSIsCiAgICAgICAgICAgIGhlbHA9IkRyeSBydW4gcHJpbnRzIHRoZSBleGVjdXRlZCBjb21tYW5k + cyB3aXRob3V0IHJ1bm5pbmcgdGhlbSIsCiAgICAgICAgKQogICAgICAgIG91dHB1dF9ncm91cC5h + ZGRfYXJndW1lbnQoCiAgICAgICAgICAgICItLXJhZG9zLW5hbWVzcGFjZSIsCiAgICAgICAgICAg + IGRlZmF1bHQ9IiIsCiAgICAgICAgICAgIHJlcXVpcmVkPUZhbHNlLAogICAgICAgICAgICBoZWxw + PSJEaXZpZGVzIGEgcG9vbCBpbnRvIHNlcGFyYXRlIGxvZ2ljYWwgbmFtZXNwYWNlcywgdXNlZCBm + b3IgY3JlYXRpbmcgUkJEIFBWQyBpbiBhIENlcGhCbG9ja1Bvb2xSYWRvc05hbWVzcGFjZSAoc2hv + dWxkIGJlIGxvd2VyIGNhc2UpIiwKICAgICAgICApCiAgICAgICAgb3V0cHV0X2dyb3VwLmFkZF9h + cmd1bWVudCgKICAgICAgICAgICAgIi0tc3Vidm9sdW1lLWdyb3VwIiwKICAgICAgICAgICAgZGVm + YXVsdD0iIiwKICAgICAgICAgICAgcmVxdWlyZWQ9RmFsc2UsCiAgICAgICAgICAgIGhlbHA9InBy + b3ZpZGVzIHRoZSBuYW1lIG9mIHRoZSBzdWJ2b2x1bWUgZ3JvdXAiLAogICAgICAgICkKICAgICAg + ICBvdXRwdXRfZ3JvdXAuYWRkX2FyZ3VtZW50KAogICAgICAgICAgICAiLS1yZ3ctcmVhbG0tbmFt + ZSIsCiAgICAgICAgICAgIGRlZmF1bHQ9IiIsCiAgICAgICAgICAgIHJlcXVpcmVkPUZhbHNlLAog + ICAgICAgICAgICBoZWxwPSJwcm92aWRlcyB0aGUgbmFtZSBvZiB0aGUgcmd3LXJlYWxtIiwKICAg + ICAgICApCiAgICAgICAgb3V0cHV0X2dyb3VwLmFkZF9hcmd1bWVudCgKICAgICAgICAgICAgIi0t + cmd3LXpvbmUtbmFtZSIsCiAgICAgICAgICAgIGRlZmF1bHQ9IiIsCiAgICAgICAgICAgIHJlcXVp + cmVkPUZhbHNlLAogICAgICAgICAgICBoZWxwPSJwcm92aWRlcyB0aGUgbmFtZSBvZiB0aGUgcmd3 + LXpvbmUiLAogICAgICAgICkKICAgICAgICBvdXRwdXRfZ3JvdXAuYWRkX2FyZ3VtZW50KAogICAg + ICAgICAgICAiLS1yZ3ctem9uZWdyb3VwLW5hbWUiLAogICAgICAgICAgICBkZWZhdWx0PSIiLAog + ICAgICAgICAgICByZXF1aXJlZD1GYWxzZSwKICAgICAgICAgICAgaGVscD0icHJvdmlkZXMgdGhl + IG5hbWUgb2YgdGhlIHJndy16b25lZ3JvdXAiLAogICAgICAgICkKICAgICAgICBvdXRwdXRfZ3Jv + dXAuYWRkX2FyZ3VtZW50KAogICAgICAgICAgICAiLS10b3BvbG9neS1wb29scyIsCiAgICAgICAg + ICAgIGRlZmF1bHQ9IiIsCiAgICAgICAgICAgIHJlcXVpcmVkPUZhbHNlLAogICAgICAgICAgICBo + ZWxwPSJjb21tYS1zZXBhcmF0ZWQgbGlzdCBvZiB0b3BvbG9neS1jb25zdHJhaW5lZCByYmQgcG9v + bHMiLAogICAgICAgICkKICAgICAgICBvdXRwdXRfZ3JvdXAuYWRkX2FyZ3VtZW50KAogICAgICAg + ICAgICAiLS10b3BvbG9neS1mYWlsdXJlLWRvbWFpbi1sYWJlbCIsCiAgICAgICAgICAgIGRlZmF1 + bHQ9IiIsCiAgICAgICAgICAgIHJlcXVpcmVkPUZhbHNlLAogICAgICAgICAgICBoZWxwPSJrOHMg + Y2x1c3RlciBmYWlsdXJlIGRvbWFpbiBsYWJlbCAoZXhhbXBsZTogem9uZSwgcmFjaywgb3IgaG9z + dCkgZm9yIHRoZSB0b3BvbG9neS1wb29scyB0aGF0IG1hdGNoIHRoZSBjZXBoIGRvbWFpbiIsCiAg + ICAgICAgKQogICAgICAgIG91dHB1dF9ncm91cC5hZGRfYXJndW1lbnQoCiAgICAgICAgICAgICIt + LXRvcG9sb2d5LWZhaWx1cmUtZG9tYWluLXZhbHVlcyIsCiAgICAgICAgICAgIGRlZmF1bHQ9IiIs + CiAgICAgICAgICAgIHJlcXVpcmVkPUZhbHNlLAogICAgICAgICAgICBoZWxwPSJjb21tYS1zZXBh + cmF0ZWQgbGlzdCBvZiB0aGUgazhzIGNsdXN0ZXIgZmFpbHVyZSBkb21haW4gdmFsdWVzIGNvcnJl + c3BvbmRpbmcgdG8gZWFjaCBvZiB0aGUgcG9vbHMgaW4gdGhlIGB0b3BvbG9neS1wb29sc2AgbGlz + dCIsCiAgICAgICAgKQoKICAgICAgICB1cGdyYWRlX2dyb3VwID0gYXJnUC5hZGRfYXJndW1lbnRf + Z3JvdXAoInVwZ3JhZGUiKQogICAgICAgIHVwZ3JhZGVfZ3JvdXAuYWRkX2FyZ3VtZW50KAogICAg + ICAgICAgICAiLS11cGdyYWRlIiwKICAgICAgICAgICAgYWN0aW9uPSJzdG9yZV90cnVlIiwKICAg + ICAgICAgICAgZGVmYXVsdD1GYWxzZSwKICAgICAgICAgICAgaGVscD0iVXBncmFkZXMgdGhlIGNl + cGhDU0lLZXlyaW5ncyhGb3IgZXhhbXBsZTogY2xpZW50LmNzaS1jZXBoZnMtcHJvdmlzaW9uZXIp + IGFuZCBjbGllbnQuaGVhbHRoY2hlY2tlciBjZXBoIHVzZXJzIHdpdGggbmV3IHBlcm1pc3Npb25z + IG5lZWRlZCBmb3IgdGhlIG5ldyBjbHVzdGVyIHZlcnNpb24gYW5kIG9sZGVyIHBlcm1pc3Npb24g + d2lsbCBzdGlsbCBiZSBhcHBsaWVkLiIKICAgICAgICAgICAgKyAiU2FtcGxlIHJ1bjogYHB5dGhv + bjMgL2V0Yy9jZXBoL2NyZWF0ZS1leHRlcm5hbC1jbHVzdGVyLXJlc291cmNlcy5weSAtLXVwZ3Jh + ZGVgLCB0aGlzIHdpbGwgdXBncmFkZSBhbGwgdGhlIGRlZmF1bHQgY3NpIHVzZXJzKG5vbi1yZXN0 + cmljdGVkKSIKICAgICAgICAgICAgKyAiRm9yIHJlc3RyaWN0ZWQgdXNlcnMoRm9yIGV4YW1wbGU6 + IGNsaWVudC5jc2ktY2VwaGZzLXByb3Zpc2lvbmVyLW9wZW5zaGlmdC1zdG9yYWdlLW15ZnMpLCB1 + c2VycyBjcmVhdGVkIHVzaW5nIC0tcmVzdHJpY3RlZC1hdXRoLXBlcm1pc3Npb24gZmxhZyBuZWVk + IHRvIHBhc3MgbWFuZGF0b3J5IGZsYWdzIgogICAgICAgICAgICArICJtYW5kYXRvcnkgZmxhZ3M6 + ICctLXJiZC1kYXRhLXBvb2wtbmFtZSwgLS1rOHMtY2x1c3Rlci1uYW1lIGFuZCAtLXJ1bi1hcy11 + c2VyJyBmbGFncyB3aGlsZSB1cGdyYWRpbmciCiAgICAgICAgICAgICsgImluIGNhc2Ugb2YgY2Vw + aGZzIHVzZXJzIGlmIHlvdSBoYXZlIHBhc3NlZCAtLWNlcGhmcy1maWxlc3lzdGVtLW5hbWUgZmxh + ZyB3aGlsZSBjcmVhdGluZyB1c2VyIHRoZW4gd2hpbGUgdXBncmFkaW5nIGl0IHdpbGwgYmUgbWFu + ZGF0b3J5IHRvbyIKICAgICAgICAgICAgKyAiU2FtcGxlIHJ1bjogYHB5dGhvbjMgL2V0Yy9jZXBo + L2NyZWF0ZS1leHRlcm5hbC1jbHVzdGVyLXJlc291cmNlcy5weSAtLXVwZ3JhZGUgLS1yYmQtZGF0 + YS1wb29sLW5hbWUgcmVwbGljYXBvb2wgLS1rOHMtY2x1c3Rlci1uYW1lIHJvb2tzdG9yYWdlICAt + LXJ1bi1hcy11c2VyIGNsaWVudC5jc2ktcmJkLW5vZGUtcm9va3N0b3JhZ2UtcmVwbGljYXBvb2xg + IgogICAgICAgICAgICArICJQUzogQW4gZXhpc3Rpbmcgbm9uLXJlc3RyaWN0ZWQgdXNlciBjYW5u + b3QgYmUgY29udmVydGVkIHRvIGEgcmVzdHJpY3RlZCB1c2VyIGJ5IHVwZ3JhZGluZy4iCiAgICAg + ICAgICAgICsgIlVwZ3JhZGUgZmxhZyBzaG91bGQgb25seSBiZSB1c2VkIHRvIGFwcGVuZCBuZXcg + cGVybWlzc2lvbnMgdG8gdXNlcnMsIGl0IHNob3VsZG4ndCBiZSB1c2VkIGZvciBjaGFuZ2luZyB1 + c2VyIGFscmVhZHkgYXBwbGllZCBwZXJtaXNzaW9uLCBmb3IgZXhhbXBsZSB5b3Ugc2hvdWxkbid0 + IGNoYW5nZSBpbiB3aGljaCBwb29sIHVzZXIgaGFzIGFjY2VzcyIsCiAgICAgICAgKQoKICAgICAg + ICAjIEFkZCBjb21tYW5kLWxpbmUgYXJndW1lbnRzCiAgICAgICAgY29uZmlnX2dyb3VwID0gYXJn + UC5hZGRfYXJndW1lbnRfZ3JvdXAoImNvbmZpZyIpCiAgICAgICAgY29uZmlnX2dyb3VwLmFkZF9h + cmd1bWVudCgKICAgICAgICAgICAgIi0tY29uZmlnLWZpbGUiLAogICAgICAgICAgICB0eXBlPXN0 + ciwKICAgICAgICAgICAgaGVscD0iUGF0aCB0byB0aGUgY29uZmlndXJhdGlvbiBmaWxlLCBQcmlv + cml0eTogY29tbWFuZC1saW5lLWFyZ3MgPiBjb25maWcuaW5pIGZpbGUgdmFsdWVzID4gZGVmYXVs + dCB2YWx1ZXMiLAogICAgICAgICAgICByZXF1aXJlZD1GYWxzZSwKICAgICAgICAgICAgZGVmYXVs + dD0iIiwKICAgICAgICApCgogICAgICAgIGlmIGFyZ3NfdG9fcGFyc2U6CiAgICAgICAgICAgIGFz + c2VydCAoCiAgICAgICAgICAgICAgICB0eXBlKGFyZ3NfdG9fcGFyc2UpID09IGxpc3QKICAgICAg + ICAgICAgKSwgIkFyZ3VtZW50IHRvICdnZW5fYXJnX3BhcnNlcicgc2hvdWxkIGJlIGEgbGlzdCIK + ICAgICAgICBlbHNlOgogICAgICAgICAgICBhcmdzX3RvX3BhcnNlID0gc3lzLmFyZ3ZbMTpdCiAg + ICAgICAgcmV0dXJuIGFyZ1AucGFyc2VfYXJncyhhcmdzX3RvX3BhcnNlKQoKICAgIGRlZiB2YWxp + ZGF0ZV9yYmRfbWV0YWRhdGFfZWNfcG9vbF9uYW1lKHNlbGYpOgogICAgICAgIGlmIHNlbGYuX2Fy + Z19wYXJzZXIucmJkX21ldGFkYXRhX2VjX3Bvb2xfbmFtZToKICAgICAgICAgICAgcmJkX21ldGFk + YXRhX2VjX3Bvb2xfbmFtZSA9IHNlbGYuX2FyZ19wYXJzZXIucmJkX21ldGFkYXRhX2VjX3Bvb2xf + bmFtZQogICAgICAgICAgICByYmRfcG9vbF9uYW1lID0gc2VsZi5fYXJnX3BhcnNlci5yYmRfZGF0 + YV9wb29sX25hbWUKCiAgICAgICAgICAgIGlmIHJiZF9wb29sX25hbWUgPT0gIiI6CiAgICAgICAg + ICAgICAgICByYWlzZSBFeGVjdXRpb25GYWlsdXJlRXhjZXB0aW9uKAogICAgICAgICAgICAgICAg + ICAgICJGbGFnICctLXJiZC1kYXRhLXBvb2wtbmFtZScgc2hvdWxkIG5vdCBiZSBlbXB0eSIKICAg + ICAgICAgICAgICAgICkKCiAgICAgICAgICAgIGlmIHJiZF9tZXRhZGF0YV9lY19wb29sX25hbWUg + PT0gIiI6CiAgICAgICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWlsdXJlRXhjZXB0aW9uKAog + ICAgICAgICAgICAgICAgICAgICJGbGFnICctLXJiZC1tZXRhZGF0YS1lYy1wb29sLW5hbWUnIHNo + b3VsZCBub3QgYmUgZW1wdHkiCiAgICAgICAgICAgICAgICApCgogICAgICAgICAgICBjbWRfanNv + biA9IHsicHJlZml4IjogIm9zZCBkdW1wIiwgImZvcm1hdCI6ICJqc29uIn0KICAgICAgICAgICAg + cmV0X3ZhbCwganNvbl9vdXQsIGVycl9tc2cgPSBzZWxmLl9jb21tb25fY21kX2pzb25fZ2VuKGNt + ZF9qc29uKQogICAgICAgICAgICBpZiByZXRfdmFsICE9IDAgb3IgbGVuKGpzb25fb3V0KSA9PSAw + OgogICAgICAgICAgICAgICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlvbigKICAgICAg + ICAgICAgICAgICAgICBmIntjbWRfanNvblsncHJlZml4J119IGNvbW1hbmQgZmFpbGVkLlxuIgog + ICAgICAgICAgICAgICAgICAgIGYiRXJyb3I6IHtlcnJfbXNnIGlmIHJldF92YWwgIT0gMCBlbHNl + IHNlbGYuRU1QVFlfT1VUUFVUX0xJU1R9IgogICAgICAgICAgICAgICAgKQogICAgICAgICAgICBt + ZXRhZGF0YV9wb29sX2V4aXN0LCBwb29sX2V4aXN0ID0gRmFsc2UsIEZhbHNlCgogICAgICAgICAg + ICBmb3Iga2V5IGluIGpzb25fb3V0WyJwb29scyJdOgogICAgICAgICAgICAgICAgIyBpZiBlcmFz + dXJlX2NvZGVfcHJvZmlsZSBpcyBlbXB0eSBhbmQgcG9vbCBuYW1lIGV4aXN0cyB0aGVuIGl0IHJl + cGxpY2EgcG9vbAogICAgICAgICAgICAgICAgaWYgKAogICAgICAgICAgICAgICAgICAgIGtleVsi + ZXJhc3VyZV9jb2RlX3Byb2ZpbGUiXSA9PSAiIgogICAgICAgICAgICAgICAgICAgIGFuZCBrZXlb + InBvb2xfbmFtZSJdID09IHJiZF9tZXRhZGF0YV9lY19wb29sX25hbWUKICAgICAgICAgICAgICAg + ICk6CiAgICAgICAgICAgICAgICAgICAgbWV0YWRhdGFfcG9vbF9leGlzdCA9IFRydWUKICAgICAg + ICAgICAgICAgICMgaWYgZXJhc3VyZV9jb2RlX3Byb2ZpbGUgaXMgbm90IGVtcHR5IGFuZCBwb29s + IG5hbWUgZXhpc3RzIHRoZW4gaXQgaXMgZWMgcG9vbAogICAgICAgICAgICAgICAgaWYga2V5WyJl + cmFzdXJlX2NvZGVfcHJvZmlsZSJdIGFuZCBrZXlbInBvb2xfbmFtZSJdID09IHJiZF9wb29sX25h + bWU6CiAgICAgICAgICAgICAgICAgICAgcG9vbF9leGlzdCA9IFRydWUKCiAgICAgICAgICAgIGlm + IG5vdCBtZXRhZGF0YV9wb29sX2V4aXN0OgogICAgICAgICAgICAgICAgcmFpc2UgRXhlY3V0aW9u + RmFpbHVyZUV4Y2VwdGlvbigKICAgICAgICAgICAgICAgICAgICAiUHJvdmlkZWQgcmJkX2VjX21l + dGFkYXRhX3Bvb2wgbmFtZSwiCiAgICAgICAgICAgICAgICAgICAgZiIge3JiZF9tZXRhZGF0YV9l + Y19wb29sX25hbWV9LCBkb2VzIG5vdCBleGlzdCIKICAgICAgICAgICAgICAgICkKICAgICAgICAg + ICAgaWYgbm90IHBvb2xfZXhpc3Q6CiAgICAgICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWls + dXJlRXhjZXB0aW9uKAogICAgICAgICAgICAgICAgICAgIGYiUHJvdmlkZWQgcmJkX2RhdGFfcG9v + bCBuYW1lLCB7cmJkX3Bvb2xfbmFtZX0sIGRvZXMgbm90IGV4aXN0IgogICAgICAgICAgICAgICAg + KQogICAgICAgICAgICByZXR1cm4gcmJkX21ldGFkYXRhX2VjX3Bvb2xfbmFtZQoKICAgIGRlZiBk + cnlfcnVuKHNlbGYsIG1zZyk6CiAgICAgICAgaWYgc2VsZi5fYXJnX3BhcnNlci5kcnlfcnVuOgog + ICAgICAgICAgICBwcmludCgiRXhlY3V0ZTogIiArICInIiArIG1zZyArICInIikKCiAgICBkZWYg + dmFsaWRhdGVfcmd3X2VuZHBvaW50X3Rsc19jZXJ0KHNlbGYpOgogICAgICAgIGlmIHNlbGYuX2Fy + Z19wYXJzZXIucmd3X3Rsc19jZXJ0X3BhdGg6CiAgICAgICAgICAgIHdpdGggb3BlbihzZWxmLl9h + cmdfcGFyc2VyLnJnd190bHNfY2VydF9wYXRoLCBlbmNvZGluZz0idXRmOCIpIGFzIGY6CiAgICAg + ICAgICAgICAgICBjb250ZW50cyA9IGYucmVhZCgpCiAgICAgICAgICAgICAgICByZXR1cm4gY29u + dGVudHMucnN0cmlwKCkKCiAgICBkZWYgX2NoZWNrX2NvbmZsaWN0aW5nX29wdGlvbnMoc2VsZik6 + CiAgICAgICAgaWYgbm90IHNlbGYuX2FyZ19wYXJzZXIudXBncmFkZSBhbmQgbm90IHNlbGYuX2Fy + Z19wYXJzZXIucmJkX2RhdGFfcG9vbF9uYW1lOgogICAgICAgICAgICByYWlzZSBFeGVjdXRpb25G + YWlsdXJlRXhjZXB0aW9uKAogICAgICAgICAgICAgICAgIkVpdGhlciAnLS11cGdyYWRlJyBvciAn + LS1yYmQtZGF0YS1wb29sLW5hbWUgPHBvb2xfbmFtZT4nIHNob3VsZCBiZSBzcGVjaWZpZWQiCiAg + ICAgICAgICAgICkKCiAgICBkZWYgX2ludmFsaWRfZW5kcG9pbnQoc2VsZiwgZW5kcG9pbnRfc3Ry + KToKICAgICAgICAjIGV4dHJhY3QgdGhlIHBvcnQgYnkgZ2V0dGluZyB0aGUgbGFzdCBzcGxpdCBv + biBgOmAgZGVsaW1pdGVyCiAgICAgICAgdHJ5OgogICAgICAgICAgICBlbmRwb2ludF9zdHJfaXAs + IHBvcnQgPSBlbmRwb2ludF9zdHIucnNwbGl0KCI6IiwgMSkKICAgICAgICBleGNlcHQgVmFsdWVF + cnJvcjoKICAgICAgICAgICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlvbihmIk5vdCBh + IHByb3BlciBlbmRwb2ludDoge2VuZHBvaW50X3N0cn0iKQoKICAgICAgICB0cnk6CiAgICAgICAg + ICAgIGlmIGVuZHBvaW50X3N0cl9pcFswXSA9PSAiWyI6CiAgICAgICAgICAgICAgICBlbmRwb2lu + dF9zdHJfaXAgPSBlbmRwb2ludF9zdHJfaXBbMSA6IGxlbihlbmRwb2ludF9zdHJfaXApIC0gMV0K + ICAgICAgICAgICAgaXBfdHlwZSA9ICgKICAgICAgICAgICAgICAgICJJUHY0IiBpZiB0eXBlKGlw + X2FkZHJlc3MoZW5kcG9pbnRfc3RyX2lwKSkgaXMgSVB2NEFkZHJlc3MgZWxzZSAiSVB2NiIKICAg + ICAgICAgICAgKQogICAgICAgIGV4Y2VwdCBWYWx1ZUVycm9yOgogICAgICAgICAgICBpcF90eXBl + ID0gIkZRRE4iCiAgICAgICAgaWYgbm90IHBvcnQuaXNkaWdpdCgpOgogICAgICAgICAgICByYWlz + ZSBFeGVjdXRpb25GYWlsdXJlRXhjZXB0aW9uKGYiUG9ydCBub3QgdmFsaWQ6IHtwb3J0fSIpCiAg + ICAgICAgaW50UG9ydCA9IGludChwb3J0KQogICAgICAgIGlmIGludFBvcnQgPCAxIG9yIGludFBv + cnQgPiAyKioxNiAtIDE6CiAgICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1cmVFeGNlcHRp + b24oZiJPdXQgb2YgcmFuZ2UgcG9ydCBudW1iZXI6IHtwb3J0fSIpCgogICAgICAgIHJldHVybiBp + cF90eXBlCgogICAgZGVmIGVuZHBvaW50X2RpYWwoc2VsZiwgZW5kcG9pbnRfc3RyLCBpcF90eXBl + LCB0aW1lb3V0PTMsIGNlcnQ9Tm9uZSk6CiAgICAgICAgIyBpZiB0aGUgJ2NsdXN0ZXInIGluc3Rh + bmNlIGlzIGEgZHVtbXkgb25lLAogICAgICAgICMgZG9uJ3QgdHJ5IHRvIHJlYWNoIG91dCB0byB0 + aGUgZW5kcG9pbnQKICAgICAgICBpZiBpc2luc3RhbmNlKHNlbGYuY2x1c3RlciwgRHVtbXlSYWRv + cyk6CiAgICAgICAgICAgIHJldHVybiAiIiwgIiIsICIiCiAgICAgICAgaWYgaXBfdHlwZSA9PSAi + SVB2NiI6CiAgICAgICAgICAgIHRyeToKICAgICAgICAgICAgICAgIGVuZHBvaW50X3N0cl9pcCwg + ZW5kcG9pbnRfc3RyX3BvcnQgPSBlbmRwb2ludF9zdHIucnNwbGl0KCI6IiwgMSkKICAgICAgICAg + ICAgZXhjZXB0IFZhbHVlRXJyb3I6CiAgICAgICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWls + dXJlRXhjZXB0aW9uKAogICAgICAgICAgICAgICAgICAgIGYiTm90IGEgcHJvcGVyIGVuZHBvaW50 + OiB7ZW5kcG9pbnRfc3RyfSIKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgaWYgZW5kcG9p + bnRfc3RyX2lwWzBdICE9ICJbIjoKICAgICAgICAgICAgICAgIGVuZHBvaW50X3N0cl9pcCA9ICJb + IiArIGVuZHBvaW50X3N0cl9pcCArICJdIgogICAgICAgICAgICBlbmRwb2ludF9zdHIgPSAiOiIu + am9pbihbZW5kcG9pbnRfc3RyX2lwLCBlbmRwb2ludF9zdHJfcG9ydF0pCgogICAgICAgIHByb3Rv + Y29scyA9IFsiaHR0cCIsICJodHRwcyJdCiAgICAgICAgcmVzcG9uc2VfZXJyb3IgPSBOb25lCiAg + ICAgICAgZm9yIHByZWZpeCBpbiBwcm90b2NvbHM6CiAgICAgICAgICAgIHRyeToKICAgICAgICAg + ICAgICAgIGVwID0gZiJ7cHJlZml4fTovL3tlbmRwb2ludF9zdHJ9IgogICAgICAgICAgICAgICAg + dmVyaWZ5ID0gTm9uZQogICAgICAgICAgICAgICAgIyBJZiB2ZXJpZnkgaXMgc2V0IHRvIGEgcGF0 + aCB0byBhIGRpcmVjdG9yeSwKICAgICAgICAgICAgICAgICMgdGhlIGRpcmVjdG9yeSBtdXN0IGhh + dmUgYmVlbiBwcm9jZXNzZWQgdXNpbmcgdGhlIGNfcmVoYXNoIHV0aWxpdHkgc3VwcGxpZWQgd2l0 + aCBPcGVuU1NMLgogICAgICAgICAgICAgICAgaWYgcHJlZml4ID09ICJodHRwcyIgYW5kIHNlbGYu + X2FyZ19wYXJzZXIucmd3X3NraXBfdGxzOgogICAgICAgICAgICAgICAgICAgIHZlcmlmeSA9IEZh + bHNlCiAgICAgICAgICAgICAgICAgICAgciA9IHJlcXVlc3RzLmhlYWQoZXAsIHRpbWVvdXQ9dGlt + ZW91dCwgdmVyaWZ5PUZhbHNlKQogICAgICAgICAgICAgICAgZWxpZiBwcmVmaXggPT0gImh0dHBz + IiBhbmQgY2VydDoKICAgICAgICAgICAgICAgICAgICB2ZXJpZnkgPSBjZXJ0CiAgICAgICAgICAg + ICAgICAgICAgciA9IHJlcXVlc3RzLmhlYWQoZXAsIHRpbWVvdXQ9dGltZW91dCwgdmVyaWZ5PWNl + cnQpCiAgICAgICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgICAgIHIgPSByZXF1ZXN0 + cy5oZWFkKGVwLCB0aW1lb3V0PXRpbWVvdXQpCiAgICAgICAgICAgICAgICBpZiByLnN0YXR1c19j + b2RlID09IDIwMDoKICAgICAgICAgICAgICAgICAgICByZXR1cm4gcHJlZml4LCB2ZXJpZnksICIi + CiAgICAgICAgICAgIGV4Y2VwdCBFeGNlcHRpb24gYXMgZXJyOgogICAgICAgICAgICAgICAgcmVz + cG9uc2VfZXJyb3IgPSBlcnIKICAgICAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgc3lzLnN0 + ZGVyci53cml0ZSgKICAgICAgICAgICAgZiJ1bmFibGUgdG8gY29ubmVjdCB0byBlbmRwb2ludDog + e2VuZHBvaW50X3N0cn0sIGZhaWxlZCBlcnJvcjoge3Jlc3BvbnNlX2Vycm9yfSIKICAgICAgICAp + CiAgICAgICAgcmV0dXJuICgKICAgICAgICAgICAgIiIsCiAgICAgICAgICAgICIiLAogICAgICAg + ICAgICAoIi0xIiksCiAgICAgICAgKQoKICAgIGRlZiBwYXJzZV9jb25maWdfZmlsZShzZWxmLCBj + b25maWdfZmlsZSk6CiAgICAgICAgY29uZmlnID0gY29uZmlncGFyc2VyLkNvbmZpZ1BhcnNlcigp + CiAgICAgICAgY29uZmlnLnJlYWQoY29uZmlnX2ZpbGUpCiAgICAgICAgZm9yIGFyZyBpbiBsaXN0 + KHZhcnMoc2VsZi5fYXJnX3BhcnNlcikpOgogICAgICAgICAgICAjIHB5dGhvbiB0cmVhdHMgZmxh + Zy1uYW1lIGFzIGZsYWdfbmFtZSBpbnRlcm5hbGx5LCBzbyBjb252ZXJ0aW5nIGJhY2sgdG8gZmxh + Zy1uYW1lLAogICAgICAgICAgICAjIHNvIHdlIGNhbiBnZXQgdGhvc2UgdmFsdWVzIGZyb20gY29u + ZmlnIGZpbGUKICAgICAgICAgICAgYXJndW1lbnQgPSBhcmcucmVwbGFjZSgiXyIsICItIikKICAg + ICAgICAgICAgYXJndW1lbnRWYWx1ZSA9IHN0cihnZXRhdHRyKHNlbGYuX2FyZ19wYXJzZXIsIGFy + ZykpCiAgICAgICAgICAgIGNvbmZpZ192YWx1ZSA9IGNvbmZpZy5nZXQoIkNvbmZpZ3VyYXRpb25z + IiwgYXJndW1lbnQsIGZhbGxiYWNrPU5vbmUpCiAgICAgICAgICAgICMgZ2l2ZSBwcmlvcml0eSB0 + byBjb21tYW5kIGxpbmUgYXJndW1lbnQsIGlmIGNvbW1hbmQgbGluZSBhcmd1bWVudCBpcyBub3Qg + cHJlc2VudCB1c2UgY29uZmlnLmluaSB2YWx1ZSwKICAgICAgICAgICAgaWYgKHN0cihzeXMuYXJn + dikuZmluZChhcmd1bWVudCkgPT0gLTEpIGFuZCAoCiAgICAgICAgICAgICAgICAoY29uZmlnX3Zh + bHVlICE9IE5vbmUpIGFuZCAoY29uZmlnX3ZhbHVlICE9ICIiKQogICAgICAgICAgICApOgogICAg + ICAgICAgICAgICAgc2VsZi5fYXJnX3BhcnNlci5fX3NldGF0dHJfXyhhcmcsIGNvbmZpZ192YWx1 + ZSkKCiAgICAgICAgcmV0dXJuIGNvbmZpZwoKICAgIGRlZiBfX2luaXRfXyhzZWxmLCBhcmdfbGlz + dD1Ob25lKToKICAgICAgICBzZWxmLm91dF9tYXAgPSB7fQogICAgICAgIHNlbGYuX2V4Y2x1ZGVk + X2tleXMgPSBzZXQoKQogICAgICAgIHNlbGYuX2FyZ19wYXJzZXIgPSBzZWxmLmdlbl9hcmdfcGFy + c2VyKGFyZ3NfdG9fcGFyc2U9YXJnX2xpc3QpCiAgICAgICAgaWYgc2VsZi5fYXJnX3BhcnNlci5j + b25maWdfZmlsZToKICAgICAgICAgICAgc2VsZi5jb25maWcgPSBzZWxmLnBhcnNlX2NvbmZpZ19m + aWxlKHNlbGYuX2FyZ19wYXJzZXIuY29uZmlnX2ZpbGUpCiAgICAgICAgc2VsZi5fY2hlY2tfY29u + ZmxpY3Rpbmdfb3B0aW9ucygpCiAgICAgICAgc2VsZi5ydW5fYXNfdXNlciA9IHNlbGYuX2FyZ19w + YXJzZXIucnVuX2FzX3VzZXIKICAgICAgICBzZWxmLm91dHB1dF9maWxlID0gc2VsZi5fYXJnX3Bh + cnNlci5vdXRwdXQKICAgICAgICBzZWxmLmNlcGhfY29uZiA9IHNlbGYuX2FyZ19wYXJzZXIuY2Vw + aF9jb25mCiAgICAgICAgc2VsZi5jZXBoX2tleXJpbmcgPSBzZWxmLl9hcmdfcGFyc2VyLmtleXJp + bmcKICAgICAgICAjIGlmIHVzZXIgbm90IHByb3ZpZGVkLCBnaXZlIGEgZGVmYXVsdCB1c2VyCiAg + ICAgICAgaWYgbm90IHNlbGYucnVuX2FzX3VzZXIgYW5kIG5vdCBzZWxmLl9hcmdfcGFyc2VyLnVw + Z3JhZGU6CiAgICAgICAgICAgIHNlbGYucnVuX2FzX3VzZXIgPSBzZWxmLkVYVEVSTkFMX1VTRVJf + TkFNRQogICAgICAgIGlmIG5vdCBzZWxmLl9hcmdfcGFyc2VyLnJnd19wb29sX3ByZWZpeCBhbmQg + bm90IHNlbGYuX2FyZ19wYXJzZXIudXBncmFkZToKICAgICAgICAgICAgc2VsZi5fYXJnX3BhcnNl + ci5yZ3dfcG9vbF9wcmVmaXggPSBzZWxmLkRFRkFVTFRfUkdXX1BPT0xfUFJFRklYCiAgICAgICAg + aWYgc2VsZi5jZXBoX2NvbmY6CiAgICAgICAgICAgIGt3YXJncyA9IHt9CiAgICAgICAgICAgIGlm + IHNlbGYuY2VwaF9rZXlyaW5nOgogICAgICAgICAgICAgICAga3dhcmdzWyJjb25mIl0gPSB7Imtl + eXJpbmciOiBzZWxmLmNlcGhfa2V5cmluZ30KICAgICAgICAgICAgc2VsZi5jbHVzdGVyID0gcmFk + b3MuUmFkb3MoY29uZmZpbGU9c2VsZi5jZXBoX2NvbmYsICoqa3dhcmdzKQogICAgICAgIGVsc2U6 + CiAgICAgICAgICAgIHNlbGYuY2x1c3RlciA9IHJhZG9zLlJhZG9zKCkKICAgICAgICAgICAgc2Vs + Zi5jbHVzdGVyLmNvbmZfcmVhZF9maWxlKCkKICAgICAgICBzZWxmLmNsdXN0ZXIuY29ubmVjdCgp + CgogICAgZGVmIHNodXRkb3duKHNlbGYpOgogICAgICAgIGlmIHNlbGYuY2x1c3Rlci5zdGF0ZSA9 + PSAiY29ubmVjdGVkIjoKICAgICAgICAgICAgc2VsZi5jbHVzdGVyLnNodXRkb3duKCkKCiAgICBk + ZWYgZ2V0X2ZzaWQoc2VsZik6CiAgICAgICAgaWYgc2VsZi5fYXJnX3BhcnNlci5kcnlfcnVuOgog + ICAgICAgICAgICByZXR1cm4gc2VsZi5kcnlfcnVuKCJjZXBoIGZzaWQiKQogICAgICAgIHJldHVy + biBzdHIoc2VsZi5jbHVzdGVyLmdldF9mc2lkKCkpCgogICAgZGVmIF9jb21tb25fY21kX2pzb25f + Z2VuKHNlbGYsIGNtZF9qc29uKToKICAgICAgICBjbWQgPSBqc29uLmR1bXBzKGNtZF9qc29uLCBz + b3J0X2tleXM9VHJ1ZSkKICAgICAgICByZXRfdmFsLCBjbWRfb3V0LCBlcnJfbXNnID0gc2VsZi5j + bHVzdGVyLm1vbl9jb21tYW5kKGNtZCwgYiIiKQogICAgICAgIGlmIHNlbGYuX2FyZ19wYXJzZXIu + dmVyYm9zZToKICAgICAgICAgICAgcHJpbnQoZiJDb21tYW5kIElucHV0OiB7Y21kfSIpCiAgICAg + ICAgICAgIHByaW50KAogICAgICAgICAgICAgICAgZiJSZXR1cm4gVmFsOiB7cmV0X3ZhbH1cbkNv + bW1hbmQgT3V0cHV0OiB7Y21kX291dH1cbiIKICAgICAgICAgICAgICAgIGYiRXJyb3IgTWVzc2Fn + ZToge2Vycl9tc2d9XG4tLS0tLS0tLS0tXG4iCiAgICAgICAgICAgICkKICAgICAgICBqc29uX291 + dCA9IHt9CiAgICAgICAgIyBpZiB0aGVyZSBpcyBubyBlcnJvciAoaS5lOyByZXRfdmFsIGlzIFpF + Uk8pIGFuZCAnY21kX291dCcgaXMgbm90IGVtcHR5CiAgICAgICAgIyB0aGVuIGNvbnZlcnQgJ2Nt + ZF9vdXQnIHRvIGEganNvbiBvdXRwdXQKICAgICAgICBpZiByZXRfdmFsID09IDAgYW5kIGNtZF9v + dXQ6CiAgICAgICAgICAgIGpzb25fb3V0ID0ganNvbi5sb2FkcyhjbWRfb3V0KQogICAgICAgIHJl + dHVybiByZXRfdmFsLCBqc29uX291dCwgZXJyX21zZwoKICAgIGRlZiBnZXRfY2VwaF9leHRlcm5h + bF9tb25fZGF0YShzZWxmKToKICAgICAgICBjbWRfanNvbiA9IHsicHJlZml4IjogInF1b3J1bV9z + dGF0dXMiLCAiZm9ybWF0IjogImpzb24ifQogICAgICAgIGlmIHNlbGYuX2FyZ19wYXJzZXIuZHJ5 + X3J1bjoKICAgICAgICAgICAgcmV0dXJuIHNlbGYuZHJ5X3J1bigiY2VwaCAiICsgY21kX2pzb25b + InByZWZpeCJdKQogICAgICAgIHJldF92YWwsIGpzb25fb3V0LCBlcnJfbXNnID0gc2VsZi5fY29t + bW9uX2NtZF9qc29uX2dlbihjbWRfanNvbikKICAgICAgICAjIGlmIHRoZXJlIGlzIGFuIHVuc3Vj + Y2Vzc2Z1bCBhdHRlbXB0LAogICAgICAgIGlmIHJldF92YWwgIT0gMCBvciBsZW4oanNvbl9vdXQp + ID09IDA6CiAgICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1cmVFeGNlcHRpb24oCiAgICAg + ICAgICAgICAgICAiJ3F1b3J1bV9zdGF0dXMnIGNvbW1hbmQgZmFpbGVkLlxuIgogICAgICAgICAg + ICAgICAgZiJFcnJvcjoge2Vycl9tc2cgaWYgcmV0X3ZhbCAhPSAwIGVsc2Ugc2VsZi5FTVBUWV9P + VVRQVVRfTElTVH0iCiAgICAgICAgICAgICkKICAgICAgICBxX2xlYWRlcl9uYW1lID0ganNvbl9v + dXRbInF1b3J1bV9sZWFkZXJfbmFtZSJdCiAgICAgICAgcV9sZWFkZXJfZGV0YWlscyA9IHt9CiAg + ICAgICAgcV9sZWFkZXJfbWF0Y2hpbmdfbGlzdCA9IFsKICAgICAgICAgICAgbCBmb3IgbCBpbiBq + c29uX291dFsibW9ubWFwIl1bIm1vbnMiXSBpZiBsWyJuYW1lIl0gPT0gcV9sZWFkZXJfbmFtZQog + ICAgICAgIF0KICAgICAgICBpZiBsZW4ocV9sZWFkZXJfbWF0Y2hpbmdfbGlzdCkgPT0gMDoKICAg + ICAgICAgICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlvbigiTm8gbWF0Y2hpbmcgJ21v + bicgZGV0YWlscyBmb3VuZCIpCiAgICAgICAgcV9sZWFkZXJfZGV0YWlscyA9IHFfbGVhZGVyX21h + dGNoaW5nX2xpc3RbMF0KICAgICAgICAjIGdldCB0aGUgYWRkcmVzcyB2ZWN0b3Igb2YgdGhlIHF1 + b3J1bS1sZWFkZXIKICAgICAgICBxX2xlYWRlcl9hZGRydmVjID0gcV9sZWFkZXJfZGV0YWlscy5n + ZXQoInB1YmxpY19hZGRycyIsIHt9KS5nZXQoImFkZHJ2ZWMiLCBbXSkKICAgICAgICBpcF9hZGRy + ID0gc3RyKHFfbGVhZGVyX2RldGFpbHNbInB1YmxpY19hZGRyIl0uc3BsaXQoIi8iKVswXSkKCiAg + ICAgICAgaWYgc2VsZi5fYXJnX3BhcnNlci52Ml9wb3J0X2VuYWJsZToKICAgICAgICAgICAgaWYg + cV9sZWFkZXJfYWRkcnZlY1swXVsidHlwZSJdID09ICJ2MiI6CiAgICAgICAgICAgICAgICBpcF9h + ZGRyID0gcV9sZWFkZXJfYWRkcnZlY1swXVsiYWRkciJdCiAgICAgICAgICAgIGVsaWYgbGVuKHFf + bGVhZGVyX2FkZHJ2ZWMpID4gMSBhbmQgcV9sZWFkZXJfYWRkcnZlY1sxXVsidHlwZSJdID09ICJ2 + MiI6CiAgICAgICAgICAgICAgICBpcF9hZGRyID0gcV9sZWFkZXJfYWRkcnZlY1sxXVsiYWRkciJd + CiAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICBzeXMuc3RkZXJyLndyaXRlKAogICAg + ICAgICAgICAgICAgICAgICIndjInIGFkZHJlc3MgdHlwZSBub3QgcHJlc2VudCwgYW5kICd2Mi1w + b3J0LWVuYWJsZScgZmxhZyBpcyBwcm92aWRlZCIKICAgICAgICAgICAgICAgICkKCiAgICAgICAg + cmV0dXJuIGYie3N0cihxX2xlYWRlcl9uYW1lKX09e2lwX2FkZHJ9IgoKICAgIGRlZiBfY29udmVy + dF9ob3N0bmFtZV90b19pcChzZWxmLCBob3N0X25hbWUsIHBvcnQsIGlwX3R5cGUpOgogICAgICAg + ICMgaWYgJ2NsdXN0ZXInIGluc3RhbmNlIGlzIGEgZHVtbXkgdHlwZSwKICAgICAgICAjIGNhbGwg + dGhlIGR1bW15IGluc3RhbmNlJ3MgImNvbnZlcnQiIG1ldGhvZAogICAgICAgIGlmIG5vdCBob3N0 + X25hbWU6CiAgICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1cmVFeGNlcHRpb24oIkVtcHR5 + IGhvc3RuYW1lIHByb3ZpZGVkIikKICAgICAgICBpZiBpc2luc3RhbmNlKHNlbGYuY2x1c3Rlciwg + RHVtbXlSYWRvcyk6CiAgICAgICAgICAgIHJldHVybiBzZWxmLmNsdXN0ZXIuX2NvbnZlcnRfaG9z + dG5hbWVfdG9faXAoaG9zdF9uYW1lKQoKICAgICAgICBpZiBpcF90eXBlID09ICJGUUROIjoKICAg + ICAgICAgICAgIyBjaGVjayB3aGljaCBpcCBGUUROIHNob3VsZCBiZSBjb252ZXJ0ZWQgdG8sIElQ + djQgb3IgSVB2NgogICAgICAgICAgICAjIGNoZWNrIHRoZSBob3N0IGlwLCB0aGUgZW5kcG9pbnQg + aXAgdHlwZSB3b3VsZCBiZSBzaW1pbGFyIHRvIGhvc3QgaXAKICAgICAgICAgICAgY21kX2pzb24g + PSB7InByZWZpeCI6ICJvcmNoIGhvc3QgbHMiLCAiZm9ybWF0IjogImpzb24ifQogICAgICAgICAg + ICByZXRfdmFsLCBqc29uX291dCwgZXJyX21zZyA9IHNlbGYuX2NvbW1vbl9jbWRfanNvbl9nZW4o + Y21kX2pzb24pCiAgICAgICAgICAgICMgaWYgdGhlcmUgaXMgYW4gdW5zdWNjZXNzZnVsIGF0dGVt + cHQsCiAgICAgICAgICAgIGlmIHJldF92YWwgIT0gMCBvciBsZW4oanNvbl9vdXQpID09IDA6CiAg + ICAgICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWlsdXJlRXhjZXB0aW9uKAogICAgICAgICAg + ICAgICAgICAgICInb3JjaCBob3N0IGxzJyBjb21tYW5kIGZhaWxlZC5cbiIKICAgICAgICAgICAg + ICAgICAgICBmIkVycm9yOiB7ZXJyX21zZyBpZiByZXRfdmFsICE9IDAgZWxzZSBzZWxmLkVNUFRZ + X09VVFBVVF9MSVNUfSIKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgaG9zdF9hZGRyID0g + anNvbl9vdXRbMF1bImFkZHIiXQogICAgICAgICAgICAjIGFkZCA6ODAgc2FtcGxlIHBvcnQgaW4g + aXBfdHlwZSwgYXMgX2ludmFsaWRfZW5kcG9pbnQgYWxzbyB2ZXJpZnkgcG9ydAogICAgICAgICAg + ICBob3N0X2lwX3R5cGUgPSBzZWxmLl9pbnZhbGlkX2VuZHBvaW50KGhvc3RfYWRkciArICI6ODAi + KQogICAgICAgICAgICBpbXBvcnQgc29ja2V0CgogICAgICAgICAgICBpcCA9IFtdCiAgICAgICAg + ICAgICMgZXhhbXBsZSBvdXRwdXQgWyg8QWRkcmVzc0ZhbWlseS5BRl9JTkVUOiAyPiwgPFNvY2tl + dEtpbmQuU09DS19TVFJFQU06IDE+LCA2LCAnJywgKCc5My4xODQuMjE2LjM0JywgODApKSwgLi4u + XQogICAgICAgICAgICAjIHdlIG5lZWQgdG8gZ2V0IDkzLjE4NC4yMTYuMzQgc28gaXQgd291bGQg + YmUgaXBbMF1bNF1bMF0KICAgICAgICAgICAgaWYgaG9zdF9pcF90eXBlID09ICJJUHY2IjoKICAg + ICAgICAgICAgICAgIGlwID0gc29ja2V0LmdldGFkZHJpbmZvKAogICAgICAgICAgICAgICAgICAg + IGhvc3RfbmFtZSwgcG9ydCwgZmFtaWx5PXNvY2tldC5BRl9JTkVUNiwgcHJvdG89c29ja2V0LklQ + UFJPVE9fVENQCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgIGVsaWYgaG9zdF9pcF90eXBl + ID09ICJJUHY0IjoKICAgICAgICAgICAgICAgIGlwID0gc29ja2V0LmdldGFkZHJpbmZvKAogICAg + ICAgICAgICAgICAgICAgIGhvc3RfbmFtZSwgcG9ydCwgZmFtaWx5PXNvY2tldC5BRl9JTkVULCBw + cm90bz1zb2NrZXQuSVBQUk9UT19UQ1AKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgZGVs + IHNvY2tldAogICAgICAgICAgICByZXR1cm4gaXBbMF1bNF1bMF0KICAgICAgICByZXR1cm4gaG9z + dF9uYW1lCgogICAgZGVmIGdldF9hY3RpdmVfYW5kX3N0YW5kYnlfbWdycyhzZWxmKToKICAgICAg + ICBpZiBzZWxmLl9hcmdfcGFyc2VyLmRyeV9ydW46CiAgICAgICAgICAgIHJldHVybiAiIiwgc2Vs + Zi5kcnlfcnVuKCJjZXBoIHN0YXR1cyIpCiAgICAgICAgbW9uaXRvcmluZ19lbmRwb2ludF9wb3J0 + ID0gc2VsZi5fYXJnX3BhcnNlci5tb25pdG9yaW5nX2VuZHBvaW50X3BvcnQKICAgICAgICBtb25p + dG9yaW5nX2VuZHBvaW50X2lwX2xpc3QgPSBzZWxmLl9hcmdfcGFyc2VyLm1vbml0b3JpbmdfZW5k + cG9pbnQKICAgICAgICBzdGFuZGJ5X21ncnMgPSBbXQogICAgICAgIGlmIG5vdCBtb25pdG9yaW5n + X2VuZHBvaW50X2lwX2xpc3Q6CiAgICAgICAgICAgIGNtZF9qc29uID0geyJwcmVmaXgiOiAic3Rh + dHVzIiwgImZvcm1hdCI6ICJqc29uIn0KICAgICAgICAgICAgcmV0X3ZhbCwganNvbl9vdXQsIGVy + cl9tc2cgPSBzZWxmLl9jb21tb25fY21kX2pzb25fZ2VuKGNtZF9qc29uKQogICAgICAgICAgICAj + IGlmIHRoZXJlIGlzIGFuIHVuc3VjY2Vzc2Z1bCBhdHRlbXB0LAogICAgICAgICAgICBpZiByZXRf + dmFsICE9IDAgb3IgbGVuKGpzb25fb3V0KSA9PSAwOgogICAgICAgICAgICAgICAgcmFpc2UgRXhl + Y3V0aW9uRmFpbHVyZUV4Y2VwdGlvbigKICAgICAgICAgICAgICAgICAgICAiJ21nciBzZXJ2aWNl + cycgY29tbWFuZCBmYWlsZWQuXG4iCiAgICAgICAgICAgICAgICAgICAgZiJFcnJvcjoge2Vycl9t + c2cgaWYgcmV0X3ZhbCAhPSAwIGVsc2Ugc2VsZi5FTVBUWV9PVVRQVVRfTElTVH0iCiAgICAgICAg + ICAgICAgICApCiAgICAgICAgICAgIG1vbml0b3JpbmdfZW5kcG9pbnQgPSAoCiAgICAgICAgICAg + ICAgICBqc29uX291dC5nZXQoIm1ncm1hcCIsIHt9KS5nZXQoInNlcnZpY2VzIiwge30pLmdldCgi + cHJvbWV0aGV1cyIsICIiKQogICAgICAgICAgICApCiAgICAgICAgICAgIGlmIG5vdCBtb25pdG9y + aW5nX2VuZHBvaW50OgogICAgICAgICAgICAgICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2Vw + dGlvbigKICAgICAgICAgICAgICAgICAgICAiY2FuJ3QgZmluZCBtb25pdG9yaW5nX2VuZHBvaW50 + LCBwcm9tZXRoZXVzIG1vZHVsZSBtaWdodCBub3QgYmUgZW5hYmxlZCwgIgogICAgICAgICAgICAg + ICAgICAgICJlbmFibGUgdGhlIG1vZHVsZSBieSBydW5uaW5nICdjZXBoIG1nciBtb2R1bGUgZW5h + YmxlIHByb21ldGhldXMnIgogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAjIG5vdyBjaGVj + ayB0aGUgc3RhbmQtYnkgbWdyLXMKICAgICAgICAgICAgc3RhbmRieV9hcnIgPSBqc29uX291dC5n + ZXQoIm1ncm1hcCIsIHt9KS5nZXQoInN0YW5kYnlzIiwgW10pCiAgICAgICAgICAgIGZvciBlYWNo + X3N0YW5kYnkgaW4gc3RhbmRieV9hcnI6CiAgICAgICAgICAgICAgICBpZiAibmFtZSIgaW4gZWFj + aF9zdGFuZGJ5LmtleXMoKToKICAgICAgICAgICAgICAgICAgICBzdGFuZGJ5X21ncnMuYXBwZW5k + KGVhY2hfc3RhbmRieVsibmFtZSJdKQogICAgICAgICAgICB0cnk6CiAgICAgICAgICAgICAgICBw + YXJzZWRfZW5kcG9pbnQgPSB1cmxwYXJzZShtb25pdG9yaW5nX2VuZHBvaW50KQogICAgICAgICAg + ICBleGNlcHQgVmFsdWVFcnJvcjoKICAgICAgICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1 + cmVFeGNlcHRpb24oCiAgICAgICAgICAgICAgICAgICAgZiJpbnZhbGlkIGVuZHBvaW50OiB7bW9u + aXRvcmluZ19lbmRwb2ludH0iCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgIG1vbml0b3Jp + bmdfZW5kcG9pbnRfaXBfbGlzdCA9IHBhcnNlZF9lbmRwb2ludC5ob3N0bmFtZQogICAgICAgICAg + ICBpZiBub3QgbW9uaXRvcmluZ19lbmRwb2ludF9wb3J0OgogICAgICAgICAgICAgICAgbW9uaXRv + cmluZ19lbmRwb2ludF9wb3J0ID0gc3RyKHBhcnNlZF9lbmRwb2ludC5wb3J0KQoKICAgICAgICAj + IGlmIG1vbml0b3JpbmcgZW5kcG9pbnQgcG9ydCBpcyBub3Qgc2V0LCBwdXQgYSBkZWZhdWx0IG1v + biBwb3J0CiAgICAgICAgaWYgbm90IG1vbml0b3JpbmdfZW5kcG9pbnRfcG9ydDoKICAgICAgICAg + ICAgbW9uaXRvcmluZ19lbmRwb2ludF9wb3J0ID0gc2VsZi5ERUZBVUxUX01PTklUT1JJTkdfRU5E + UE9JTlRfUE9SVAoKICAgICAgICAjIHVzZXIgY291bGQgZ2l2ZSBjb21tYSBhbmQgc3BhY2Ugc2Vw + YXJhdGVkIGlucHV0cyAobGlrZSAtLW1vbml0b3JpbmctZW5kcG9pbnQ9IjxpcDE+LCA8aXAyPiIp + CiAgICAgICAgbW9uaXRvcmluZ19lbmRwb2ludF9pcF9saXN0ID0gbW9uaXRvcmluZ19lbmRwb2lu + dF9pcF9saXN0LnJlcGxhY2UoIiwiLCAiICIpCiAgICAgICAgbW9uaXRvcmluZ19lbmRwb2ludF9p + cF9saXN0X3NwbGl0ID0gbW9uaXRvcmluZ19lbmRwb2ludF9pcF9saXN0LnNwbGl0KCkKICAgICAg + ICAjIGlmIG1vbml0b3JpbmctZW5kcG9pbnQgY291bGQgbm90IGJlIGZvdW5kLCByYWlzZSBhbiBl + cnJvcgogICAgICAgIGlmIGxlbihtb25pdG9yaW5nX2VuZHBvaW50X2lwX2xpc3Rfc3BsaXQpID09 + IDA6CiAgICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1cmVFeGNlcHRpb24oIk5vICdtb25p + dG9yaW5nLWVuZHBvaW50JyBmb3VuZCIpCiAgICAgICAgIyBmaXJzdCBpcCBpcyB0cmVhdGVkIGFz + IHRoZSBtYWluIG1vbml0b3JpbmctZW5kcG9pbnQKICAgICAgICBtb25pdG9yaW5nX2VuZHBvaW50 + X2lwID0gbW9uaXRvcmluZ19lbmRwb2ludF9pcF9saXN0X3NwbGl0WzBdCiAgICAgICAgIyByZXN0 + IG9mIHRoZSBpcC1zIGFyZSBhZGRlZCB0byB0aGUgJ3N0YW5kYnlfbWdycycgbGlzdAogICAgICAg + IHN0YW5kYnlfbWdycy5leHRlbmQobW9uaXRvcmluZ19lbmRwb2ludF9pcF9saXN0X3NwbGl0WzE6 + XSkKICAgICAgICBmYWlsZWRfaXAgPSBtb25pdG9yaW5nX2VuZHBvaW50X2lwCgogICAgICAgIG1v + bml0b3JpbmdfZW5kcG9pbnQgPSAiOiIuam9pbigKICAgICAgICAgICAgW21vbml0b3JpbmdfZW5k + cG9pbnRfaXAsIG1vbml0b3JpbmdfZW5kcG9pbnRfcG9ydF0KICAgICAgICApCiAgICAgICAgaXBf + dHlwZSA9IHNlbGYuX2ludmFsaWRfZW5kcG9pbnQobW9uaXRvcmluZ19lbmRwb2ludCkKICAgICAg + ICB0cnk6CiAgICAgICAgICAgIG1vbml0b3JpbmdfZW5kcG9pbnRfaXAgPSBzZWxmLl9jb252ZXJ0 + X2hvc3RuYW1lX3RvX2lwKAogICAgICAgICAgICAgICAgbW9uaXRvcmluZ19lbmRwb2ludF9pcCwg + bW9uaXRvcmluZ19lbmRwb2ludF9wb3J0LCBpcF90eXBlCiAgICAgICAgICAgICkKICAgICAgICAg + ICAgIyBjb2xsZWN0IGFsbCB0aGUgJ3N0YW5kLWJ5JyBtZ3IgaXBzCiAgICAgICAgICAgIG1ncl9p + cHMgPSBbXQogICAgICAgICAgICBmb3IgZWFjaF9zdGFuZGJ5X21nciBpbiBzdGFuZGJ5X21ncnM6 + CiAgICAgICAgICAgICAgICBmYWlsZWRfaXAgPSBlYWNoX3N0YW5kYnlfbWdyCiAgICAgICAgICAg + ICAgICBtZ3JfaXBzLmFwcGVuZCgKICAgICAgICAgICAgICAgICAgICBzZWxmLl9jb252ZXJ0X2hv + c3RuYW1lX3RvX2lwKAogICAgICAgICAgICAgICAgICAgICAgICBlYWNoX3N0YW5kYnlfbWdyLCBt + b25pdG9yaW5nX2VuZHBvaW50X3BvcnQsIGlwX3R5cGUKICAgICAgICAgICAgICAgICAgICApCiAg + ICAgICAgICAgICAgICApCiAgICAgICAgZXhjZXB0OgogICAgICAgICAgICByYWlzZSBFeGVjdXRp + b25GYWlsdXJlRXhjZXB0aW9uKAogICAgICAgICAgICAgICAgZiJDb252ZXJzaW9uIG9mIGhvc3Q6 + IHtmYWlsZWRfaXB9IHRvIElQIGZhaWxlZC4gIgogICAgICAgICAgICAgICAgIlBsZWFzZSBlbnRl + ciB0aGUgSVAgYWRkcmVzc2VzIG9mIGFsbCB0aGUgY2VwaC1tZ3JzIHdpdGggdGhlICctLW1vbml0 + b3JpbmctZW5kcG9pbnQnIGZsYWciCiAgICAgICAgICAgICkKCiAgICAgICAgXywgXywgZXJyID0g + c2VsZi5lbmRwb2ludF9kaWFsKG1vbml0b3JpbmdfZW5kcG9pbnQsIGlwX3R5cGUpCiAgICAgICAg + aWYgZXJyID09ICItMSI6CiAgICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1cmVFeGNlcHRp + b24oZXJyKQogICAgICAgICMgYWRkIHRoZSB2YWxpZGF0ZWQgYWN0aXZlIG1nciBJUCBpbnRvIHRo + ZSBmaXJzdCBpbmRleAogICAgICAgIG1ncl9pcHMuaW5zZXJ0KDAsIG1vbml0b3JpbmdfZW5kcG9p + bnRfaXApCiAgICAgICAgYWxsX21ncl9pcHNfc3RyID0gIiwiLmpvaW4obWdyX2lwcykKICAgICAg + ICByZXR1cm4gYWxsX21ncl9pcHNfc3RyLCBtb25pdG9yaW5nX2VuZHBvaW50X3BvcnQKCiAgICBk + ZWYgY2hlY2tfdXNlcl9leGlzdChzZWxmLCB1c2VyKToKICAgICAgICBjbWRfanNvbiA9IHsicHJl + Zml4IjogImF1dGggZ2V0IiwgImVudGl0eSI6IGYie3VzZXJ9IiwgImZvcm1hdCI6ICJqc29uIn0K + ICAgICAgICByZXRfdmFsLCBqc29uX291dCwgXyA9IHNlbGYuX2NvbW1vbl9jbWRfanNvbl9nZW4o + Y21kX2pzb24pCiAgICAgICAgaWYgcmV0X3ZhbCAhPSAwIG9yIGxlbihqc29uX291dCkgPT0gMDoK + ICAgICAgICAgICAgcmV0dXJuICIiCiAgICAgICAgcmV0dXJuIHN0cihqc29uX291dFswXVsia2V5 + Il0pCgogICAgZGVmIGdldF9jZXBoZnNfcHJvdmlzaW9uZXJfY2Fwc19hbmRfZW50aXR5KHNlbGYp + OgogICAgICAgIGVudGl0eSA9ICJjbGllbnQuY3NpLWNlcGhmcy1wcm92aXNpb25lciIKICAgICAg + ICBjYXBzID0gewogICAgICAgICAgICAibW9uIjogImFsbG93IHIsIGFsbG93IGNvbW1hbmQgJ29z + ZCBibG9ja2xpc3QnIiwKICAgICAgICAgICAgIm1nciI6ICJhbGxvdyBydyIsCiAgICAgICAgICAg + ICJvc2QiOiAiYWxsb3cgcncgdGFnIGNlcGhmcyBtZXRhZGF0YT0qIiwKICAgICAgICAgICAgIm1k + cyI6ICJhbGxvdyAqIiwKICAgICAgICB9CiAgICAgICAgaWYgc2VsZi5fYXJnX3BhcnNlci5yZXN0 + cmljdGVkX2F1dGhfcGVybWlzc2lvbjoKICAgICAgICAgICAgazhzX2NsdXN0ZXJfbmFtZSA9IHNl + bGYuX2FyZ19wYXJzZXIuazhzX2NsdXN0ZXJfbmFtZQogICAgICAgICAgICBpZiBrOHNfY2x1c3Rl + cl9uYW1lID09ICIiOgogICAgICAgICAgICAgICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2Vw + dGlvbigKICAgICAgICAgICAgICAgICAgICAiazhzX2NsdXN0ZXJfbmFtZSBub3QgZm91bmQsIHBs + ZWFzZSBzZXQgdGhlICctLWs4cy1jbHVzdGVyLW5hbWUnIGZsYWciCiAgICAgICAgICAgICAgICAp + CiAgICAgICAgICAgIGNlcGhmc19maWxlc3lzdGVtID0gc2VsZi5fYXJnX3BhcnNlci5jZXBoZnNf + ZmlsZXN5c3RlbV9uYW1lCiAgICAgICAgICAgIGlmIGNlcGhmc19maWxlc3lzdGVtID09ICIiOgog + ICAgICAgICAgICAgICAgZW50aXR5ID0gZiJ7ZW50aXR5fS17azhzX2NsdXN0ZXJfbmFtZX0iCiAg + ICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICBlbnRpdHkgPSBmIntlbnRpdHl9LXtrOHNf + Y2x1c3Rlcl9uYW1lfS17Y2VwaGZzX2ZpbGVzeXN0ZW19IgogICAgICAgICAgICAgICAgY2Fwc1si + b3NkIl0gPSBmImFsbG93IHJ3IHRhZyBjZXBoZnMgbWV0YWRhdGE9e2NlcGhmc19maWxlc3lzdGVt + fSIKCiAgICAgICAgcmV0dXJuIGNhcHMsIGVudGl0eQoKICAgIGRlZiBnZXRfY2VwaGZzX25vZGVf + Y2Fwc19hbmRfZW50aXR5KHNlbGYpOgogICAgICAgIGVudGl0eSA9ICJjbGllbnQuY3NpLWNlcGhm + cy1ub2RlIgogICAgICAgIGNhcHMgPSB7CiAgICAgICAgICAgICJtb24iOiAiYWxsb3cgciwgYWxs + b3cgY29tbWFuZCAnb3NkIGJsb2NrbGlzdCciLAogICAgICAgICAgICAibWdyIjogImFsbG93IHJ3 + IiwKICAgICAgICAgICAgIm9zZCI6ICJhbGxvdyBydyB0YWcgY2VwaGZzICo9KiIsCiAgICAgICAg + ICAgICJtZHMiOiAiYWxsb3cgcnciLAogICAgICAgIH0KICAgICAgICBpZiBzZWxmLl9hcmdfcGFy + c2VyLnJlc3RyaWN0ZWRfYXV0aF9wZXJtaXNzaW9uOgogICAgICAgICAgICBrOHNfY2x1c3Rlcl9u + YW1lID0gc2VsZi5fYXJnX3BhcnNlci5rOHNfY2x1c3Rlcl9uYW1lCiAgICAgICAgICAgIGlmIGs4 + c19jbHVzdGVyX25hbWUgPT0gIiI6CiAgICAgICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWls + dXJlRXhjZXB0aW9uKAogICAgICAgICAgICAgICAgICAgICJrOHNfY2x1c3Rlcl9uYW1lIG5vdCBm + b3VuZCwgcGxlYXNlIHNldCB0aGUgJy0tazhzLWNsdXN0ZXItbmFtZScgZmxhZyIKICAgICAgICAg + ICAgICAgICkKICAgICAgICAgICAgY2VwaGZzX2ZpbGVzeXN0ZW0gPSBzZWxmLl9hcmdfcGFyc2Vy + LmNlcGhmc19maWxlc3lzdGVtX25hbWUKICAgICAgICAgICAgaWYgY2VwaGZzX2ZpbGVzeXN0ZW0g + PT0gIiI6CiAgICAgICAgICAgICAgICBlbnRpdHkgPSBmIntlbnRpdHl9LXtrOHNfY2x1c3Rlcl9u + YW1lfSIKICAgICAgICAgICAgZWxzZToKICAgICAgICAgICAgICAgIGVudGl0eSA9IGYie2VudGl0 + eX0te2s4c19jbHVzdGVyX25hbWV9LXtjZXBoZnNfZmlsZXN5c3RlbX0iCiAgICAgICAgICAgICAg + ICBjYXBzWyJvc2QiXSA9IGYiYWxsb3cgcncgdGFnIGNlcGhmcyAqPXtjZXBoZnNfZmlsZXN5c3Rl + bX0iCgogICAgICAgIHJldHVybiBjYXBzLCBlbnRpdHkKCiAgICBkZWYgZ2V0X2VudGl0eSgKICAg + ICAgICBzZWxmLAogICAgICAgIGVudGl0eSwKICAgICAgICByYmRfcG9vbF9uYW1lLAogICAgICAg + IGFsaWFzX3JiZF9wb29sX25hbWUsCiAgICAgICAgazhzX2NsdXN0ZXJfbmFtZSwKICAgICAgICBy + YWRvc19uYW1lc3BhY2UsCiAgICApOgogICAgICAgIGlmICgKICAgICAgICAgICAgcmJkX3Bvb2xf + bmFtZS5jb3VudCgiLiIpICE9IDAKICAgICAgICAgICAgb3IgcmJkX3Bvb2xfbmFtZS5jb3VudCgi + XyIpICE9IDAKICAgICAgICAgICAgb3IgYWxpYXNfcmJkX3Bvb2xfbmFtZSAhPSAiIgogICAgICAg + ICAgICAjIGNoZWNraW5nIGFsaWFzX3JiZF9wb29sX25hbWUgaXMgbm90IGVtcHR5IGFzIHRoZXJl + IG1heWJlIGEgc3BlY2lhbCBjaGFyYWN0ZXIgdXNlZCBvdGhlciB0aGFuIC4gb3IgXwogICAgICAg + ICk6CiAgICAgICAgICAgIGlmIGFsaWFzX3JiZF9wb29sX25hbWUgPT0gIiI6CiAgICAgICAgICAg ICAgICByYWlzZSBFeGVjdXRpb25GYWlsdXJlRXhjZXB0aW9uKAogICAgICAgICAgICAgICAgICAg - ICJtYW5kYXRvcnkgZmxhZyBub3QgZm91bmQsIHBsZWFzZSBzZXQgdGhlICctLXJiZC1kYXRhLXBv - b2wtbmFtZScgZmxhZyIKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgaWYgazhzX2NsdXN0 - ZXJfbmFtZSA9PSAiIjoKICAgICAgICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1cmVFeGNl - cHRpb24oCiAgICAgICAgICAgICAgICAgICAgIm1hbmRhdG9yeSBmbGFnIG5vdCBmb3VuZCwgcGxl - YXNlIHNldCB0aGUgJy0tazhzLWNsdXN0ZXItbmFtZScgZmxhZyIKICAgICAgICAgICAgICAgICkK - ICAgICAgICAgICAgZW50aXR5ID0gc2VsZi5nZXRfZW50aXR5KAogICAgICAgICAgICAgICAgZW50 - aXR5LAogICAgICAgICAgICAgICAgcmJkX3Bvb2xfbmFtZSwKICAgICAgICAgICAgICAgIGFsaWFz - X3JiZF9wb29sX25hbWUsCiAgICAgICAgICAgICAgICBrOHNfY2x1c3Rlcl9uYW1lLAogICAgICAg - ICAgICAgICAgcmFkb3NfbmFtZXNwYWNlLAogICAgICAgICAgICApCiAgICAgICAgICAgIGlmIHJh - ZG9zX25hbWVzcGFjZSAhPSAiIjoKICAgICAgICAgICAgICAgIGNhcHNbIm9zZCJdID0gKAogICAg - ICAgICAgICAgICAgICAgIGYicHJvZmlsZSByYmQgcG9vbD17cmJkX3Bvb2xfbmFtZX0gbmFtZXNw - YWNlPXtyYWRvc19uYW1lc3BhY2V9IgogICAgICAgICAgICAgICAgKQogICAgICAgICAgICBlbHNl - OgogICAgICAgICAgICAgICAgY2Fwc1sib3NkIl0gPSBmInByb2ZpbGUgcmJkIHBvb2w9e3JiZF9w - b29sX25hbWV9IgoKICAgICAgICByZXR1cm4gY2FwcywgZW50aXR5CgogICAgZGVmIGdldF9kZWZh - dWx0VXNlcl9jYXBzX2FuZF9lbnRpdHkoc2VsZik6CiAgICAgICAgZW50aXR5ID0gc2VsZi5ydW5f - YXNfdXNlcgogICAgICAgIGNhcHMgPSB7CiAgICAgICAgICAgICJtb24iOiAiYWxsb3cgciwgYWxs - b3cgY29tbWFuZCBxdW9ydW1fc3RhdHVzLCBhbGxvdyBjb21tYW5kIHZlcnNpb24iLAogICAgICAg - ICAgICAibWdyIjogImFsbG93IGNvbW1hbmQgY29uZmlnIiwKICAgICAgICAgICAgIm9zZCI6IGYi - cHJvZmlsZSByYmQtcmVhZC1vbmx5LCBhbGxvdyByd3ggcG9vbD17c2VsZi5fYXJnX3BhcnNlci5y - Z3dfcG9vbF9wcmVmaXh9LnJndy5tZXRhLCBhbGxvdyByIHBvb2w9LnJndy5yb290LCBhbGxvdyBy - dyBwb29sPXtzZWxmLl9hcmdfcGFyc2VyLnJnd19wb29sX3ByZWZpeH0ucmd3LmNvbnRyb2wsIGFs - bG93IHJ4IHBvb2w9e3NlbGYuX2FyZ19wYXJzZXIucmd3X3Bvb2xfcHJlZml4fS5yZ3cubG9nLCBh - bGxvdyB4IHBvb2w9e3NlbGYuX2FyZ19wYXJzZXIucmd3X3Bvb2xfcHJlZml4fS5yZ3cuYnVja2V0 - cy5pbmRleCIsCiAgICAgICAgICAgICJtZHMiOiAiYWxsb3cgKiIsCiAgICAgICAgfQoKICAgICAg - ICByZXR1cm4gY2FwcywgZW50aXR5CgogICAgZGVmIGdldF9jYXBzX2FuZF9lbnRpdHkoc2VsZiwg - dXNlcl9uYW1lKToKICAgICAgICBpZiAiY2xpZW50LmNzaS1jZXBoZnMtcHJvdmlzaW9uZXIiIGlu - IHVzZXJfbmFtZToKICAgICAgICAgICAgaWYgImNsaWVudC5jc2ktY2VwaGZzLXByb3Zpc2lvbmVy - IiAhPSB1c2VyX25hbWU6CiAgICAgICAgICAgICAgICBzZWxmLl9hcmdfcGFyc2VyLnJlc3RyaWN0 - ZWRfYXV0aF9wZXJtaXNzaW9uID0gVHJ1ZQogICAgICAgICAgICByZXR1cm4gc2VsZi5nZXRfY2Vw - aGZzX3Byb3Zpc2lvbmVyX2NhcHNfYW5kX2VudGl0eSgpCiAgICAgICAgaWYgImNsaWVudC5jc2kt - Y2VwaGZzLW5vZGUiIGluIHVzZXJfbmFtZToKICAgICAgICAgICAgaWYgImNsaWVudC5jc2ktY2Vw - aGZzLW5vZGUiICE9IHVzZXJfbmFtZToKICAgICAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIu - cmVzdHJpY3RlZF9hdXRoX3Blcm1pc3Npb24gPSBUcnVlCiAgICAgICAgICAgIHJldHVybiBzZWxm - LmdldF9jZXBoZnNfbm9kZV9jYXBzX2FuZF9lbnRpdHkoKQogICAgICAgIGlmICJjbGllbnQuY3Np - LXJiZC1wcm92aXNpb25lciIgaW4gdXNlcl9uYW1lOgogICAgICAgICAgICBpZiAiY2xpZW50LmNz - aS1yYmQtcHJvdmlzaW9uZXIiICE9IHVzZXJfbmFtZToKICAgICAgICAgICAgICAgIHNlbGYuX2Fy - Z19wYXJzZXIucmVzdHJpY3RlZF9hdXRoX3Blcm1pc3Npb24gPSBUcnVlCiAgICAgICAgICAgIHJl - dHVybiBzZWxmLmdldF9yYmRfcHJvdmlzaW9uZXJfY2Fwc19hbmRfZW50aXR5KCkKICAgICAgICBp - ZiAiY2xpZW50LmNzaS1yYmQtbm9kZSIgaW4gdXNlcl9uYW1lOgogICAgICAgICAgICBpZiAiY2xp - ZW50LmNzaS1yYmQtbm9kZSIgIT0gdXNlcl9uYW1lOgogICAgICAgICAgICAgICAgc2VsZi5fYXJn - X3BhcnNlci5yZXN0cmljdGVkX2F1dGhfcGVybWlzc2lvbiA9IFRydWUKICAgICAgICAgICAgcmV0 - dXJuIHNlbGYuZ2V0X3JiZF9ub2RlX2NhcHNfYW5kX2VudGl0eSgpCiAgICAgICAgaWYgImNsaWVu - dC5oZWFsdGhjaGVja2VyIiBpbiB1c2VyX25hbWU6CiAgICAgICAgICAgIGlmICJjbGllbnQuaGVh - bHRoY2hlY2tlciIgIT0gdXNlcl9uYW1lOgogICAgICAgICAgICAgICAgc2VsZi5fYXJnX3BhcnNl - ci5yZXN0cmljdGVkX2F1dGhfcGVybWlzc2lvbiA9IFRydWUKICAgICAgICAgICAgcmV0dXJuIHNl - bGYuZ2V0X2RlZmF1bHRVc2VyX2NhcHNfYW5kX2VudGl0eSgpCgogICAgICAgIHJhaXNlIEV4ZWN1 - dGlvbkZhaWx1cmVFeGNlcHRpb24oCiAgICAgICAgICAgIGYibm8gdXNlciBmb3VuZCB3aXRoIHVz - ZXJfbmFtZToge3VzZXJfbmFtZX0sICIKICAgICAgICAgICAgImdldF9jYXBzX2FuZF9lbnRpdHkg - Y29tbWFuZCBmYWlsZWQuXG4iCiAgICAgICAgKQoKICAgIGRlZiBjcmVhdGVfY2VwaENTSUtleXJp - bmdfdXNlcihzZWxmLCB1c2VyKToKICAgICAgICAiIiIKICAgICAgICBjb21tYW5kOiBjZXBoIGF1 - dGggZ2V0LW9yLWNyZWF0ZSBjbGllbnQuY3NpLWNlcGhmcy1wcm92aXNpb25lciBtb24gJ2FsbG93 - IHInIG1nciAnYWxsb3cgcncnIG9zZCAnYWxsb3cgcncgdGFnIGNlcGhmcyBtZXRhZGF0YT0qJwog - ICAgICAgICIiIgogICAgICAgIGNhcHMsIGVudGl0eSA9IHNlbGYuZ2V0X2NhcHNfYW5kX2VudGl0 - eSh1c2VyKQogICAgICAgIGNtZF9qc29uID0gewogICAgICAgICAgICAicHJlZml4IjogImF1dGgg - Z2V0LW9yLWNyZWF0ZSIsCiAgICAgICAgICAgICJlbnRpdHkiOiBlbnRpdHksCiAgICAgICAgICAg - ICJjYXBzIjogW2NhcCBmb3IgY2FwX2xpc3QgaW4gbGlzdChjYXBzLml0ZW1zKCkpIGZvciBjYXAg - aW4gY2FwX2xpc3RdLAogICAgICAgICAgICAiZm9ybWF0IjogImpzb24iLAogICAgICAgIH0KCiAg - ICAgICAgaWYgc2VsZi5fYXJnX3BhcnNlci5kcnlfcnVuOgogICAgICAgICAgICByZXR1cm4gKAog - ICAgICAgICAgICAgICAgc2VsZi5kcnlfcnVuKAogICAgICAgICAgICAgICAgICAgICJjZXBoICIK - ICAgICAgICAgICAgICAgICAgICArIGNtZF9qc29uWyJwcmVmaXgiXQogICAgICAgICAgICAgICAg - ICAgICsgIiAiCiAgICAgICAgICAgICAgICAgICAgKyBjbWRfanNvblsiZW50aXR5Il0KICAgICAg - ICAgICAgICAgICAgICArICIgIgogICAgICAgICAgICAgICAgICAgICsgIiAiLmpvaW4oY21kX2pz - b25bImNhcHMiXSkKICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAiIiwKICAgICAg - ICAgICAgKQogICAgICAgICMgY2hlY2sgaWYgdXNlciBhbHJlYWR5IGV4aXN0CiAgICAgICAgdXNl - cl9rZXkgPSBzZWxmLmNoZWNrX3VzZXJfZXhpc3QoZW50aXR5KQogICAgICAgIGlmIHVzZXJfa2V5 - ICE9ICIiOgogICAgICAgICAgICByZXR1cm4gdXNlcl9rZXksIGYie2VudGl0eS5zcGxpdCgnLics - IDEpWzFdfSIKICAgICAgICAgICAgIyBlbnRpdHkuc3BsaXQoJy4nLDEpWzFdIHRvIHJlbmFtZSBl - bnRpdHkoY2xpZW50LmNzaS1yYmQtbm9kZSkgYXMgY3NpLXJiZC1ub2RlCgogICAgICAgIHJldF92 - YWwsIGpzb25fb3V0LCBlcnJfbXNnID0gc2VsZi5fY29tbW9uX2NtZF9qc29uX2dlbihjbWRfanNv - bikKICAgICAgICAjIGlmIHRoZXJlIGlzIGFuIHVuc3VjY2Vzc2Z1bCBhdHRlbXB0LAogICAgICAg - IGlmIHJldF92YWwgIT0gMCBvciBsZW4oanNvbl9vdXQpID09IDA6CiAgICAgICAgICAgIHJhaXNl - IEV4ZWN1dGlvbkZhaWx1cmVFeGNlcHRpb24oCiAgICAgICAgICAgICAgICBmIidhdXRoIGdldC1v - ci1jcmVhdGUge3VzZXJ9JyBjb21tYW5kIGZhaWxlZC5cbiIKICAgICAgICAgICAgICAgIGYiRXJy - b3I6IHtlcnJfbXNnIGlmIHJldF92YWwgIT0gMCBlbHNlIHNlbGYuRU1QVFlfT1VUUFVUX0xJU1R9 - IgogICAgICAgICAgICApCiAgICAgICAgcmV0dXJuIHN0cihqc29uX291dFswXVsia2V5Il0pLCBm - IntlbnRpdHkuc3BsaXQoJy4nLCAxKVsxXX0iCiAgICAgICAgIyBlbnRpdHkuc3BsaXQoJy4nLDEp - WzFdIHRvIHJlbmFtZSBlbnRpdHkoY2xpZW50LmNzaS1yYmQtbm9kZSkgYXMgY3NpLXJiZC1ub2Rl - CgogICAgZGVmIGdldF9jZXBoZnNfZGF0YV9wb29sX2RldGFpbHMoc2VsZik6CiAgICAgICAgY21k - X2pzb24gPSB7InByZWZpeCI6ICJmcyBscyIsICJmb3JtYXQiOiAianNvbiJ9CiAgICAgICAgaWYg - c2VsZi5fYXJnX3BhcnNlci5kcnlfcnVuOgogICAgICAgICAgICByZXR1cm4gc2VsZi5kcnlfcnVu - KCJjZXBoICIgKyBjbWRfanNvblsicHJlZml4Il0pCiAgICAgICAgcmV0X3ZhbCwganNvbl9vdXQs - IGVycl9tc2cgPSBzZWxmLl9jb21tb25fY21kX2pzb25fZ2VuKGNtZF9qc29uKQogICAgICAgICMg - aWYgdGhlcmUgaXMgYW4gdW5zdWNjZXNzZnVsIGF0dGVtcHQsIHJlcG9ydCBhbiBlcnJvcgogICAg - ICAgIGlmIHJldF92YWwgIT0gMDoKICAgICAgICAgICAgIyBpZiBmcyBhbmQgZGF0YV9wb29sIGFy - Z3VtZW50cyBhcmUgbm90IHNldCwgc2lsZW50bHkgcmV0dXJuCiAgICAgICAgICAgIGlmICgKICAg - ICAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIuY2VwaGZzX2ZpbGVzeXN0ZW1fbmFtZSA9PSAi - IgogICAgICAgICAgICAgICAgYW5kIHNlbGYuX2FyZ19wYXJzZXIuY2VwaGZzX2RhdGFfcG9vbF9u - YW1lID09ICIiCiAgICAgICAgICAgICk6CiAgICAgICAgICAgICAgICByZXR1cm4KICAgICAgICAg - ICAgIyBpZiB1c2VyIGhhcyBwcm92aWRlZCBhbnkgb2YgdGhlCiAgICAgICAgICAgICMgJy0tY2Vw - aGZzLWZpbGVzeXN0ZW0tbmFtZScgb3IgJy0tY2VwaGZzLWRhdGEtcG9vbC1uYW1lJyBhcmd1bWVu - dHMsCiAgICAgICAgICAgICMgcmFpc2UgYW4gZXhjZXB0aW9uIGFzIHdlIGFyZSB1bmFibGUgdG8g - dmVyaWZ5IHRoZSBhcmdzCiAgICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1cmVFeGNlcHRp - b24oCiAgICAgICAgICAgICAgICBmIidmcyBscycgY2VwaCBjYWxsIGZhaWxlZCB3aXRoIGVycm9y - OiB7ZXJyX21zZ30iCiAgICAgICAgICAgICkKCiAgICAgICAgbWF0Y2hpbmdfanNvbl9vdXQgPSB7 - fQogICAgICAgICMgaWYgJy0tY2VwaGZzLWZpbGVzeXN0ZW0tbmFtZScgYXJndW1lbnQgaXMgcHJv - dmlkZWQsCiAgICAgICAgIyBjaGVjayB3aGV0aGVyIHRoZSBwcm92aWRlZCBmaWxlc3lzdGVtLW5h - bWUgZXhpc3RzIG9yIG5vdAogICAgICAgIGlmIHNlbGYuX2FyZ19wYXJzZXIuY2VwaGZzX2ZpbGVz - eXN0ZW1fbmFtZToKICAgICAgICAgICAgIyBnZXQgdGhlIG1hdGNoaW5nIGxpc3QKICAgICAgICAg - ICAgbWF0Y2hpbmdfanNvbl9vdXRfbGlzdCA9IFsKICAgICAgICAgICAgICAgIG1hdGNoZWQKICAg - ICAgICAgICAgICAgIGZvciBtYXRjaGVkIGluIGpzb25fb3V0CiAgICAgICAgICAgICAgICBpZiBz - dHIobWF0Y2hlZFsibmFtZSJdKSA9PSBzZWxmLl9hcmdfcGFyc2VyLmNlcGhmc19maWxlc3lzdGVt - X25hbWUKICAgICAgICAgICAgXQogICAgICAgICAgICAjIHVuYWJsZSB0byBmaW5kIGEgbWF0Y2hp - bmcgZnMtbmFtZSwgcmFpc2UgYW4gZXJyb3IKICAgICAgICAgICAgaWYgbGVuKG1hdGNoaW5nX2pz - b25fb3V0X2xpc3QpID09IDA6CiAgICAgICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWlsdXJl - RXhjZXB0aW9uKAogICAgICAgICAgICAgICAgICAgIGYiRmlsZXN5c3RlbSBwcm92aWRlZCwgJ3tz - ZWxmLl9hcmdfcGFyc2VyLmNlcGhmc19maWxlc3lzdGVtX25hbWV9JywgIgogICAgICAgICAgICAg - ICAgICAgIGYiaXMgbm90IGZvdW5kIGluIHRoZSBmcy1saXN0OiB7W3N0cih4WyduYW1lJ10pIGZv - ciB4IGluIGpzb25fb3V0XX0iCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgIG1hdGNoaW5n - X2pzb25fb3V0ID0gbWF0Y2hpbmdfanNvbl9vdXRfbGlzdFswXQogICAgICAgICMgaWYgY2VwaGZz - IGZpbGVzeXN0ZW0gbmFtZSBpcyBub3QgcHJvdmlkZWQsCiAgICAgICAgIyB0cnkgdG8gZ2V0IGEg - ZGVmYXVsdCBmcyBuYW1lIGJ5IGRvaW5nIHRoZSBmb2xsb3dpbmcKICAgICAgICBlbHNlOgogICAg - ICAgICAgICAjIGEuIGNoZWNrIGlmIHRoZXJlIGlzIG9ubHkgb25lIGZpbGVzeXN0ZW0gaXMgcHJl - c2VudAogICAgICAgICAgICBpZiBsZW4oanNvbl9vdXQpID09IDE6CiAgICAgICAgICAgICAgICBt - YXRjaGluZ19qc29uX291dCA9IGpzb25fb3V0WzBdCiAgICAgICAgICAgICMgYi4gb3IgZWxzZSwg - Y2hlY2sgaWYgZGF0YV9wb29sIG5hbWUgaXMgcHJvdmlkZWQKICAgICAgICAgICAgZWxpZiBzZWxm - Ll9hcmdfcGFyc2VyLmNlcGhmc19kYXRhX3Bvb2xfbmFtZToKICAgICAgICAgICAgICAgICMgYW5k - IGlmIHByZXNlbnQsIGNoZWNrIHdoZXRoZXIgdGhlcmUgZXhpc3RzIGEgZnMgd2hpY2ggaGFzIHRo - ZSBkYXRhX3Bvb2wKICAgICAgICAgICAgICAgIGZvciBlYWNoSiBpbiBqc29uX291dDoKICAgICAg - ICAgICAgICAgICAgICBpZiBzZWxmLl9hcmdfcGFyc2VyLmNlcGhmc19kYXRhX3Bvb2xfbmFtZSBp - biBlYWNoSlsiZGF0YV9wb29scyJdOgogICAgICAgICAgICAgICAgICAgICAgICBtYXRjaGluZ19q - c29uX291dCA9IGVhY2hKCiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrCiAgICAgICAgICAg - ICAgICAjIGlmIHRoZXJlIGlzIG5vIG1hdGNoaW5nIGZzIGV4aXN0cywgdGhhdCBtZWFucyBwcm92 - aWRlZCBkYXRhX3Bvb2wgbmFtZSBpcyBpbnZhbGlkCiAgICAgICAgICAgICAgICBpZiBub3QgbWF0 - Y2hpbmdfanNvbl9vdXQ6CiAgICAgICAgICAgICAgICAgICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVy - ZUV4Y2VwdGlvbigKICAgICAgICAgICAgICAgICAgICAgICAgZiJQcm92aWRlZCBkYXRhX3Bvb2wg - bmFtZSwge3NlbGYuX2FyZ19wYXJzZXIuY2VwaGZzX2RhdGFfcG9vbF9uYW1lfSwiCiAgICAgICAg - ICAgICAgICAgICAgICAgICIgZG9lcyBub3QgZXhpc3RzIgogICAgICAgICAgICAgICAgICAgICkK - ICAgICAgICAgICAgIyBjLiBpZiBub3RoaW5nIGlzIHNldCBhbmQgY291bGRuJ3QgZmluZCBhIGRl - ZmF1bHQsCiAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICAjIGp1c3QgcmV0dXJuIHNp - bGVudGx5CiAgICAgICAgICAgICAgICByZXR1cm4KCiAgICAgICAgaWYgbWF0Y2hpbmdfanNvbl9v - dXQ6CiAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIuY2VwaGZzX2ZpbGVzeXN0ZW1fbmFtZSA9 - IHN0cihtYXRjaGluZ19qc29uX291dFsibmFtZSJdKQogICAgICAgICAgICBzZWxmLl9hcmdfcGFy - c2VyLmNlcGhmc19tZXRhZGF0YV9wb29sX25hbWUgPSBzdHIoCiAgICAgICAgICAgICAgICBtYXRj - aGluZ19qc29uX291dFsibWV0YWRhdGFfcG9vbCJdCiAgICAgICAgICAgICkKCiAgICAgICAgaWYg - aXNpbnN0YW5jZShtYXRjaGluZ19qc29uX291dFsiZGF0YV9wb29scyJdLCBsaXN0KToKICAgICAg - ICAgICAgIyBpZiB0aGUgdXNlciBoYXMgYWxyZWFkeSBwcm92aWRlZCBkYXRhLXBvb2wtbmFtZSwK - ICAgICAgICAgICAgIyB0aHJvdWdoIC0tY2VwaGZzLWRhdGEtcG9vbC1uYW1lCiAgICAgICAgICAg - IGlmIHNlbGYuX2FyZ19wYXJzZXIuY2VwaGZzX2RhdGFfcG9vbF9uYW1lOgogICAgICAgICAgICAg - ICAgIyBpZiB0aGUgcHJvdmlkZWQgbmFtZSBpcyBub3QgbWF0Y2hpbmcgd2l0aCB0aGUgb25lIGlu - IHRoZSBsaXN0CiAgICAgICAgICAgICAgICBpZiAoCiAgICAgICAgICAgICAgICAgICAgc2VsZi5f - YXJnX3BhcnNlci5jZXBoZnNfZGF0YV9wb29sX25hbWUKICAgICAgICAgICAgICAgICAgICBub3Qg - aW4gbWF0Y2hpbmdfanNvbl9vdXRbImRhdGFfcG9vbHMiXQogICAgICAgICAgICAgICAgKToKICAg - ICAgICAgICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWlsdXJlRXhjZXB0aW9uKAogICAgICAg - ICAgICAgICAgICAgICAgICBmIlByb3ZpZGVkIGRhdGEtcG9vbC1uYW1lOiAne3NlbGYuX2FyZ19w - YXJzZXIuY2VwaGZzX2RhdGFfcG9vbF9uYW1lfScsICIKICAgICAgICAgICAgICAgICAgICAgICAg - ImRvZXNuJ3QgbWF0Y2ggZnJvbSB0aGUgZGF0YS1wb29scyBsaXN0OiAiCiAgICAgICAgICAgICAg - ICAgICAgICAgIGYie1tzdHIoeCkgZm9yIHggaW4gbWF0Y2hpbmdfanNvbl9vdXRbJ2RhdGFfcG9v - bHMnXV19IgogICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgIyBpZiBkYXRhX3Bvb2wg - bmFtZSBpcyBub3QgcHJvdmlkZWQsCiAgICAgICAgICAgICMgdGhlbiB0cnkgdG8gZmluZCBhIGRl - ZmF1bHQgZGF0YSBwb29sIG5hbWUKICAgICAgICAgICAgZWxzZToKICAgICAgICAgICAgICAgICMg - aWYgbm8gZGF0YV9wb29scyBleGlzdCwgc2lsZW50bHkgcmV0dXJuCiAgICAgICAgICAgICAgICBp - ZiBsZW4obWF0Y2hpbmdfanNvbl9vdXRbImRhdGFfcG9vbHMiXSkgPT0gMDoKICAgICAgICAgICAg - ICAgICAgICByZXR1cm4KICAgICAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIuY2VwaGZzX2Rh - dGFfcG9vbF9uYW1lID0gc3RyKAogICAgICAgICAgICAgICAgICAgIG1hdGNoaW5nX2pzb25fb3V0 - WyJkYXRhX3Bvb2xzIl1bMF0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgIyBpZiB0aGVy - ZSBhcmUgbW9yZSB0aGFuIG9uZSAnZGF0YV9wb29scycgZXhpc3QsCiAgICAgICAgICAgICMgdGhl - biB3YXJuIHRoZSB1c2VyIHRoYXQgd2UgYXJlIHVzaW5nIHRoZSBzZWxlY3RlZCBuYW1lCiAgICAg - ICAgICAgIGlmIGxlbihtYXRjaGluZ19qc29uX291dFsiZGF0YV9wb29scyJdKSA+IDE6CiAgICAg - ICAgICAgICAgICBwcmludCgKICAgICAgICAgICAgICAgICAgICAiV0FSTklORzogTXVsdGlwbGUg - ZGF0YSBwb29scyBkZXRlY3RlZDogIgogICAgICAgICAgICAgICAgICAgIGYie1tzdHIoeCkgZm9y - IHggaW4gbWF0Y2hpbmdfanNvbl9vdXRbJ2RhdGFfcG9vbHMnXV19XG4iCiAgICAgICAgICAgICAg - ICAgICAgZiJVc2luZyB0aGUgZGF0YS1wb29sOiAne3NlbGYuX2FyZ19wYXJzZXIuY2VwaGZzX2Rh - dGFfcG9vbF9uYW1lfSdcbiIKICAgICAgICAgICAgICAgICkKCiAgICBkZWYgY3JlYXRlX2NoZWNr - ZXJLZXkoc2VsZiwgdXNlcik6CiAgICAgICAgY2FwcywgZW50aXR5ID0gc2VsZi5nZXRfY2Fwc19h - bmRfZW50aXR5KHVzZXIpCiAgICAgICAgY21kX2pzb24gPSB7CiAgICAgICAgICAgICJwcmVmaXgi - OiAiYXV0aCBnZXQtb3ItY3JlYXRlIiwKICAgICAgICAgICAgImVudGl0eSI6IGVudGl0eSwKICAg - ICAgICAgICAgImNhcHMiOiBbY2FwIGZvciBjYXBfbGlzdCBpbiBsaXN0KGNhcHMuaXRlbXMoKSkg - Zm9yIGNhcCBpbiBjYXBfbGlzdF0sCiAgICAgICAgICAgICJmb3JtYXQiOiAianNvbiIsCiAgICAg - ICAgfQoKICAgICAgICBpZiBzZWxmLl9hcmdfcGFyc2VyLmRyeV9ydW46CiAgICAgICAgICAgIHJl - dHVybiBzZWxmLmRyeV9ydW4oCiAgICAgICAgICAgICAgICAiY2VwaCAiCiAgICAgICAgICAgICAg - ICArIGNtZF9qc29uWyJwcmVmaXgiXQogICAgICAgICAgICAgICAgKyAiICIKICAgICAgICAgICAg - ICAgICsgY21kX2pzb25bImVudGl0eSJdCiAgICAgICAgICAgICAgICArICIgIgogICAgICAgICAg - ICAgICAgKyAiICIuam9pbihjbWRfanNvblsiY2FwcyJdKQogICAgICAgICAgICApCiAgICAgICAg - IyBjaGVjayBpZiB1c2VyIGFscmVhZHkgZXhpc3QKICAgICAgICB1c2VyX2tleSA9IHNlbGYuY2hl - Y2tfdXNlcl9leGlzdChlbnRpdHkpCiAgICAgICAgaWYgdXNlcl9rZXkgIT0gIiI6CiAgICAgICAg - ICAgIHJldHVybiB1c2VyX2tleQoKICAgICAgICByZXRfdmFsLCBqc29uX291dCwgZXJyX21zZyA9 - IHNlbGYuX2NvbW1vbl9jbWRfanNvbl9nZW4oY21kX2pzb24pCiAgICAgICAgIyBpZiB0aGVyZSBp - cyBhbiB1bnN1Y2Nlc3NmdWwgYXR0ZW1wdCwKICAgICAgICBpZiByZXRfdmFsICE9IDAgb3IgbGVu - KGpzb25fb3V0KSA9PSAwOgogICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWlsdXJlRXhjZXB0 - aW9uKAogICAgICAgICAgICAgICAgZiInYXV0aCBnZXQtb3ItY3JlYXRlIHtzZWxmLnJ1bl9hc191 - c2VyfScgY29tbWFuZCBmYWlsZWRcbiIKICAgICAgICAgICAgICAgIGYiRXJyb3I6IHtlcnJfbXNn - IGlmIHJldF92YWwgIT0gMCBlbHNlIHNlbGYuRU1QVFlfT1VUUFVUX0xJU1R9IgogICAgICAgICAg - ICApCiAgICAgICAgcmV0dXJuIHN0cihqc29uX291dFswXVsia2V5Il0pCgogICAgZGVmIGdldF9j - ZXBoX2Rhc2hib2FyZF9saW5rKHNlbGYpOgogICAgICAgIGNtZF9qc29uID0geyJwcmVmaXgiOiAi - bWdyIHNlcnZpY2VzIiwgImZvcm1hdCI6ICJqc29uIn0KICAgICAgICBpZiBzZWxmLl9hcmdfcGFy - c2VyLmRyeV9ydW46CiAgICAgICAgICAgIHJldHVybiBzZWxmLmRyeV9ydW4oImNlcGggIiArIGNt - ZF9qc29uWyJwcmVmaXgiXSkKICAgICAgICByZXRfdmFsLCBqc29uX291dCwgXyA9IHNlbGYuX2Nv + ICJwbGVhc2Ugc2V0IHRoZSAnLS1hbGlhcy1yYmQtZGF0YS1wb29sLW5hbWUnIGZsYWcgYXMgdGhl + IHJiZCBkYXRhIHBvb2wgbmFtZSBjb250YWlucyAnLicgb3IgJ18nIgogICAgICAgICAgICAgICAg + KQogICAgICAgICAgICBpZiAoCiAgICAgICAgICAgICAgICBhbGlhc19yYmRfcG9vbF9uYW1lLmNv + dW50KCIuIikgIT0gMAogICAgICAgICAgICAgICAgb3IgYWxpYXNfcmJkX3Bvb2xfbmFtZS5jb3Vu + dCgiXyIpICE9IDAKICAgICAgICAgICAgKToKICAgICAgICAgICAgICAgIHJhaXNlIEV4ZWN1dGlv + bkZhaWx1cmVFeGNlcHRpb24oCiAgICAgICAgICAgICAgICAgICAgIictLWFsaWFzLXJiZC1kYXRh + LXBvb2wtbmFtZScgZmxhZyB2YWx1ZSBzaG91bGQgbm90IGNvbnRhaW4gJy4nIG9yICdfJyIKICAg + ICAgICAgICAgICAgICkKICAgICAgICAgICAgZW50aXR5ID0gZiJ7ZW50aXR5fS17azhzX2NsdXN0 + ZXJfbmFtZX0te2FsaWFzX3JiZF9wb29sX25hbWV9IgogICAgICAgIGVsc2U6CiAgICAgICAgICAg + IGVudGl0eSA9IGYie2VudGl0eX0te2s4c19jbHVzdGVyX25hbWV9LXtyYmRfcG9vbF9uYW1lfSIK + CiAgICAgICAgaWYgcmFkb3NfbmFtZXNwYWNlOgogICAgICAgICAgICBlbnRpdHkgPSBmIntlbnRp + dHl9LXtyYWRvc19uYW1lc3BhY2V9IgogICAgICAgIHJldHVybiBlbnRpdHkKCiAgICBkZWYgZ2V0 + X3JiZF9wcm92aXNpb25lcl9jYXBzX2FuZF9lbnRpdHkoc2VsZik6CiAgICAgICAgZW50aXR5ID0g + ImNsaWVudC5jc2ktcmJkLXByb3Zpc2lvbmVyIgogICAgICAgIGNhcHMgPSB7CiAgICAgICAgICAg + ICJtb24iOiAicHJvZmlsZSByYmQsIGFsbG93IGNvbW1hbmQgJ29zZCBibG9ja2xpc3QnIiwKICAg + ICAgICAgICAgIm1nciI6ICJhbGxvdyBydyIsCiAgICAgICAgICAgICJvc2QiOiAicHJvZmlsZSBy + YmQiLAogICAgICAgIH0KICAgICAgICBpZiBzZWxmLl9hcmdfcGFyc2VyLnJlc3RyaWN0ZWRfYXV0 + aF9wZXJtaXNzaW9uOgogICAgICAgICAgICByYmRfcG9vbF9uYW1lID0gc2VsZi5fYXJnX3BhcnNl + ci5yYmRfZGF0YV9wb29sX25hbWUKICAgICAgICAgICAgYWxpYXNfcmJkX3Bvb2xfbmFtZSA9IHNl + bGYuX2FyZ19wYXJzZXIuYWxpYXNfcmJkX2RhdGFfcG9vbF9uYW1lCiAgICAgICAgICAgIGs4c19j + bHVzdGVyX25hbWUgPSBzZWxmLl9hcmdfcGFyc2VyLms4c19jbHVzdGVyX25hbWUKICAgICAgICAg + ICAgcmFkb3NfbmFtZXNwYWNlID0gc2VsZi5fYXJnX3BhcnNlci5yYWRvc19uYW1lc3BhY2UKICAg + ICAgICAgICAgaWYgcmJkX3Bvb2xfbmFtZSA9PSAiIjoKICAgICAgICAgICAgICAgIHJhaXNlIEV4 + ZWN1dGlvbkZhaWx1cmVFeGNlcHRpb24oCiAgICAgICAgICAgICAgICAgICAgIm1hbmRhdG9yeSBm + bGFnIG5vdCBmb3VuZCwgcGxlYXNlIHNldCB0aGUgJy0tcmJkLWRhdGEtcG9vbC1uYW1lJyBmbGFn + IgogICAgICAgICAgICAgICAgKQogICAgICAgICAgICBpZiBrOHNfY2x1c3Rlcl9uYW1lID09ICIi + OgogICAgICAgICAgICAgICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlvbigKICAgICAg + ICAgICAgICAgICAgICAibWFuZGF0b3J5IGZsYWcgbm90IGZvdW5kLCBwbGVhc2Ugc2V0IHRoZSAn + LS1rOHMtY2x1c3Rlci1uYW1lJyBmbGFnIgogICAgICAgICAgICAgICAgKQogICAgICAgICAgICBl + bnRpdHkgPSBzZWxmLmdldF9lbnRpdHkoCiAgICAgICAgICAgICAgICBlbnRpdHksCiAgICAgICAg + ICAgICAgICByYmRfcG9vbF9uYW1lLAogICAgICAgICAgICAgICAgYWxpYXNfcmJkX3Bvb2xfbmFt + ZSwKICAgICAgICAgICAgICAgIGs4c19jbHVzdGVyX25hbWUsCiAgICAgICAgICAgICAgICByYWRv + c19uYW1lc3BhY2UsCiAgICAgICAgICAgICkKICAgICAgICAgICAgaWYgcmFkb3NfbmFtZXNwYWNl + ICE9ICIiOgogICAgICAgICAgICAgICAgY2Fwc1sib3NkIl0gPSAoCiAgICAgICAgICAgICAgICAg + ICAgZiJwcm9maWxlIHJiZCBwb29sPXtyYmRfcG9vbF9uYW1lfSBuYW1lc3BhY2U9e3JhZG9zX25h + bWVzcGFjZX0iCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAg + ICAgICBjYXBzWyJvc2QiXSA9IGYicHJvZmlsZSByYmQgcG9vbD17cmJkX3Bvb2xfbmFtZX0iCgog + ICAgICAgIHJldHVybiBjYXBzLCBlbnRpdHkKCiAgICBkZWYgZ2V0X3JiZF9ub2RlX2NhcHNfYW5k + X2VudGl0eShzZWxmKToKICAgICAgICBlbnRpdHkgPSAiY2xpZW50LmNzaS1yYmQtbm9kZSIKICAg + ICAgICBjYXBzID0gewogICAgICAgICAgICAibW9uIjogInByb2ZpbGUgcmJkLCBhbGxvdyBjb21t + YW5kICdvc2QgYmxvY2tsaXN0JyIsCiAgICAgICAgICAgICJvc2QiOiAicHJvZmlsZSByYmQiLAog + ICAgICAgIH0KICAgICAgICBpZiBzZWxmLl9hcmdfcGFyc2VyLnJlc3RyaWN0ZWRfYXV0aF9wZXJt + aXNzaW9uOgogICAgICAgICAgICByYmRfcG9vbF9uYW1lID0gc2VsZi5fYXJnX3BhcnNlci5yYmRf + ZGF0YV9wb29sX25hbWUKICAgICAgICAgICAgYWxpYXNfcmJkX3Bvb2xfbmFtZSA9IHNlbGYuX2Fy + Z19wYXJzZXIuYWxpYXNfcmJkX2RhdGFfcG9vbF9uYW1lCiAgICAgICAgICAgIGs4c19jbHVzdGVy + X25hbWUgPSBzZWxmLl9hcmdfcGFyc2VyLms4c19jbHVzdGVyX25hbWUKICAgICAgICAgICAgcmFk + b3NfbmFtZXNwYWNlID0gc2VsZi5fYXJnX3BhcnNlci5yYWRvc19uYW1lc3BhY2UKICAgICAgICAg + ICAgaWYgcmJkX3Bvb2xfbmFtZSA9PSAiIjoKICAgICAgICAgICAgICAgIHJhaXNlIEV4ZWN1dGlv + bkZhaWx1cmVFeGNlcHRpb24oCiAgICAgICAgICAgICAgICAgICAgIm1hbmRhdG9yeSBmbGFnIG5v + dCBmb3VuZCwgcGxlYXNlIHNldCB0aGUgJy0tcmJkLWRhdGEtcG9vbC1uYW1lJyBmbGFnIgogICAg + ICAgICAgICAgICAgKQogICAgICAgICAgICBpZiBrOHNfY2x1c3Rlcl9uYW1lID09ICIiOgogICAg + ICAgICAgICAgICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlvbigKICAgICAgICAgICAg + ICAgICAgICAibWFuZGF0b3J5IGZsYWcgbm90IGZvdW5kLCBwbGVhc2Ugc2V0IHRoZSAnLS1rOHMt + Y2x1c3Rlci1uYW1lJyBmbGFnIgogICAgICAgICAgICAgICAgKQogICAgICAgICAgICBlbnRpdHkg + PSBzZWxmLmdldF9lbnRpdHkoCiAgICAgICAgICAgICAgICBlbnRpdHksCiAgICAgICAgICAgICAg + ICByYmRfcG9vbF9uYW1lLAogICAgICAgICAgICAgICAgYWxpYXNfcmJkX3Bvb2xfbmFtZSwKICAg + ICAgICAgICAgICAgIGs4c19jbHVzdGVyX25hbWUsCiAgICAgICAgICAgICAgICByYWRvc19uYW1l + c3BhY2UsCiAgICAgICAgICAgICkKICAgICAgICAgICAgaWYgcmFkb3NfbmFtZXNwYWNlICE9ICIi + OgogICAgICAgICAgICAgICAgY2Fwc1sib3NkIl0gPSAoCiAgICAgICAgICAgICAgICAgICAgZiJw + cm9maWxlIHJiZCBwb29sPXtyYmRfcG9vbF9uYW1lfSBuYW1lc3BhY2U9e3JhZG9zX25hbWVzcGFj + ZX0iCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICBj + YXBzWyJvc2QiXSA9IGYicHJvZmlsZSByYmQgcG9vbD17cmJkX3Bvb2xfbmFtZX0iCgogICAgICAg + IHJldHVybiBjYXBzLCBlbnRpdHkKCiAgICBkZWYgZ2V0X2RlZmF1bHRVc2VyX2NhcHNfYW5kX2Vu + dGl0eShzZWxmKToKICAgICAgICBlbnRpdHkgPSBzZWxmLnJ1bl9hc191c2VyCiAgICAgICAgY2Fw + cyA9IHsKICAgICAgICAgICAgIm1vbiI6ICJhbGxvdyByLCBhbGxvdyBjb21tYW5kIHF1b3J1bV9z + dGF0dXMsIGFsbG93IGNvbW1hbmQgdmVyc2lvbiIsCiAgICAgICAgICAgICJtZ3IiOiAiYWxsb3cg + Y29tbWFuZCBjb25maWciLAogICAgICAgICAgICAib3NkIjogZiJwcm9maWxlIHJiZC1yZWFkLW9u + bHksIGFsbG93IHJ3eCBwb29sPXtzZWxmLl9hcmdfcGFyc2VyLnJnd19wb29sX3ByZWZpeH0ucmd3 + Lm1ldGEsIGFsbG93IHIgcG9vbD0ucmd3LnJvb3QsIGFsbG93IHJ3IHBvb2w9e3NlbGYuX2FyZ19w + YXJzZXIucmd3X3Bvb2xfcHJlZml4fS5yZ3cuY29udHJvbCwgYWxsb3cgcnggcG9vbD17c2VsZi5f + YXJnX3BhcnNlci5yZ3dfcG9vbF9wcmVmaXh9LnJndy5sb2csIGFsbG93IHggcG9vbD17c2VsZi5f + YXJnX3BhcnNlci5yZ3dfcG9vbF9wcmVmaXh9LnJndy5idWNrZXRzLmluZGV4IiwKICAgICAgICAg + ICAgIm1kcyI6ICJhbGxvdyAqIiwKICAgICAgICB9CgogICAgICAgIHJldHVybiBjYXBzLCBlbnRp + dHkKCiAgICBkZWYgZ2V0X2NhcHNfYW5kX2VudGl0eShzZWxmLCB1c2VyX25hbWUpOgogICAgICAg + IGlmICJjbGllbnQuY3NpLWNlcGhmcy1wcm92aXNpb25lciIgaW4gdXNlcl9uYW1lOgogICAgICAg + ICAgICBpZiAiY2xpZW50LmNzaS1jZXBoZnMtcHJvdmlzaW9uZXIiICE9IHVzZXJfbmFtZToKICAg + ICAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIucmVzdHJpY3RlZF9hdXRoX3Blcm1pc3Npb24g + PSBUcnVlCiAgICAgICAgICAgIHJldHVybiBzZWxmLmdldF9jZXBoZnNfcHJvdmlzaW9uZXJfY2Fw + c19hbmRfZW50aXR5KCkKICAgICAgICBpZiAiY2xpZW50LmNzaS1jZXBoZnMtbm9kZSIgaW4gdXNl + cl9uYW1lOgogICAgICAgICAgICBpZiAiY2xpZW50LmNzaS1jZXBoZnMtbm9kZSIgIT0gdXNlcl9u + YW1lOgogICAgICAgICAgICAgICAgc2VsZi5fYXJnX3BhcnNlci5yZXN0cmljdGVkX2F1dGhfcGVy + bWlzc2lvbiA9IFRydWUKICAgICAgICAgICAgcmV0dXJuIHNlbGYuZ2V0X2NlcGhmc19ub2RlX2Nh + cHNfYW5kX2VudGl0eSgpCiAgICAgICAgaWYgImNsaWVudC5jc2ktcmJkLXByb3Zpc2lvbmVyIiBp + biB1c2VyX25hbWU6CiAgICAgICAgICAgIGlmICJjbGllbnQuY3NpLXJiZC1wcm92aXNpb25lciIg + IT0gdXNlcl9uYW1lOgogICAgICAgICAgICAgICAgc2VsZi5fYXJnX3BhcnNlci5yZXN0cmljdGVk + X2F1dGhfcGVybWlzc2lvbiA9IFRydWUKICAgICAgICAgICAgcmV0dXJuIHNlbGYuZ2V0X3JiZF9w + cm92aXNpb25lcl9jYXBzX2FuZF9lbnRpdHkoKQogICAgICAgIGlmICJjbGllbnQuY3NpLXJiZC1u + b2RlIiBpbiB1c2VyX25hbWU6CiAgICAgICAgICAgIGlmICJjbGllbnQuY3NpLXJiZC1ub2RlIiAh + PSB1c2VyX25hbWU6CiAgICAgICAgICAgICAgICBzZWxmLl9hcmdfcGFyc2VyLnJlc3RyaWN0ZWRf + YXV0aF9wZXJtaXNzaW9uID0gVHJ1ZQogICAgICAgICAgICByZXR1cm4gc2VsZi5nZXRfcmJkX25v + ZGVfY2Fwc19hbmRfZW50aXR5KCkKICAgICAgICBpZiAiY2xpZW50LmhlYWx0aGNoZWNrZXIiIGlu + IHVzZXJfbmFtZToKICAgICAgICAgICAgaWYgImNsaWVudC5oZWFsdGhjaGVja2VyIiAhPSB1c2Vy + X25hbWU6CiAgICAgICAgICAgICAgICBzZWxmLl9hcmdfcGFyc2VyLnJlc3RyaWN0ZWRfYXV0aF9w + ZXJtaXNzaW9uID0gVHJ1ZQogICAgICAgICAgICByZXR1cm4gc2VsZi5nZXRfZGVmYXVsdFVzZXJf + Y2Fwc19hbmRfZW50aXR5KCkKCiAgICAgICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlv + bigKICAgICAgICAgICAgZiJubyB1c2VyIGZvdW5kIHdpdGggdXNlcl9uYW1lOiB7dXNlcl9uYW1l + fSwgIgogICAgICAgICAgICAiZ2V0X2NhcHNfYW5kX2VudGl0eSBjb21tYW5kIGZhaWxlZC5cbiIK + ICAgICAgICApCgogICAgZGVmIGNyZWF0ZV9jZXBoQ1NJS2V5cmluZ191c2VyKHNlbGYsIHVzZXIp + OgogICAgICAgICIiIgogICAgICAgIGNvbW1hbmQ6IGNlcGggYXV0aCBnZXQtb3ItY3JlYXRlIGNs + aWVudC5jc2ktY2VwaGZzLXByb3Zpc2lvbmVyIG1vbiAnYWxsb3cgcicgbWdyICdhbGxvdyBydycg + b3NkICdhbGxvdyBydyB0YWcgY2VwaGZzIG1ldGFkYXRhPSonCiAgICAgICAgIiIiCiAgICAgICAg + Y2FwcywgZW50aXR5ID0gc2VsZi5nZXRfY2Fwc19hbmRfZW50aXR5KHVzZXIpCiAgICAgICAgY21k + X2pzb24gPSB7CiAgICAgICAgICAgICJwcmVmaXgiOiAiYXV0aCBnZXQtb3ItY3JlYXRlIiwKICAg + ICAgICAgICAgImVudGl0eSI6IGVudGl0eSwKICAgICAgICAgICAgImNhcHMiOiBbY2FwIGZvciBj + YXBfbGlzdCBpbiBsaXN0KGNhcHMuaXRlbXMoKSkgZm9yIGNhcCBpbiBjYXBfbGlzdF0sCiAgICAg + ICAgICAgICJmb3JtYXQiOiAianNvbiIsCiAgICAgICAgfQoKICAgICAgICBpZiBzZWxmLl9hcmdf + cGFyc2VyLmRyeV9ydW46CiAgICAgICAgICAgIHJldHVybiAoCiAgICAgICAgICAgICAgICBzZWxm + LmRyeV9ydW4oCiAgICAgICAgICAgICAgICAgICAgImNlcGggIgogICAgICAgICAgICAgICAgICAg + ICsgY21kX2pzb25bInByZWZpeCJdCiAgICAgICAgICAgICAgICAgICAgKyAiICIKICAgICAgICAg + ICAgICAgICAgICArIGNtZF9qc29uWyJlbnRpdHkiXQogICAgICAgICAgICAgICAgICAgICsgIiAi + CiAgICAgICAgICAgICAgICAgICAgKyAiICIuam9pbihjbWRfanNvblsiY2FwcyJdKQogICAgICAg + ICAgICAgICAgKSwKICAgICAgICAgICAgICAgICIiLAogICAgICAgICAgICApCiAgICAgICAgIyBj + aGVjayBpZiB1c2VyIGFscmVhZHkgZXhpc3QKICAgICAgICB1c2VyX2tleSA9IHNlbGYuY2hlY2tf + dXNlcl9leGlzdChlbnRpdHkpCiAgICAgICAgaWYgdXNlcl9rZXkgIT0gIiI6CiAgICAgICAgICAg + IHJldHVybiB1c2VyX2tleSwgZiJ7ZW50aXR5LnNwbGl0KCcuJywgMSlbMV19IgogICAgICAgICAg + ICAjIGVudGl0eS5zcGxpdCgnLicsMSlbMV0gdG8gcmVuYW1lIGVudGl0eShjbGllbnQuY3NpLXJi + ZC1ub2RlKSBhcyBjc2ktcmJkLW5vZGUKCiAgICAgICAgcmV0X3ZhbCwganNvbl9vdXQsIGVycl9t + c2cgPSBzZWxmLl9jb21tb25fY21kX2pzb25fZ2VuKGNtZF9qc29uKQogICAgICAgICMgaWYgdGhl + cmUgaXMgYW4gdW5zdWNjZXNzZnVsIGF0dGVtcHQsCiAgICAgICAgaWYgcmV0X3ZhbCAhPSAwIG9y + IGxlbihqc29uX291dCkgPT0gMDoKICAgICAgICAgICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4 + Y2VwdGlvbigKICAgICAgICAgICAgICAgIGYiJ2F1dGggZ2V0LW9yLWNyZWF0ZSB7dXNlcn0nIGNv + bW1hbmQgZmFpbGVkLlxuIgogICAgICAgICAgICAgICAgZiJFcnJvcjoge2Vycl9tc2cgaWYgcmV0 + X3ZhbCAhPSAwIGVsc2Ugc2VsZi5FTVBUWV9PVVRQVVRfTElTVH0iCiAgICAgICAgICAgICkKICAg + ICAgICByZXR1cm4gc3RyKGpzb25fb3V0WzBdWyJrZXkiXSksIGYie2VudGl0eS5zcGxpdCgnLics + IDEpWzFdfSIKICAgICAgICAjIGVudGl0eS5zcGxpdCgnLicsMSlbMV0gdG8gcmVuYW1lIGVudGl0 + eShjbGllbnQuY3NpLXJiZC1ub2RlKSBhcyBjc2ktcmJkLW5vZGUKCiAgICBkZWYgZ2V0X2NlcGhm + c19kYXRhX3Bvb2xfZGV0YWlscyhzZWxmKToKICAgICAgICBjbWRfanNvbiA9IHsicHJlZml4Ijog + ImZzIGxzIiwgImZvcm1hdCI6ICJqc29uIn0KICAgICAgICBpZiBzZWxmLl9hcmdfcGFyc2VyLmRy + eV9ydW46CiAgICAgICAgICAgIHJldHVybiBzZWxmLmRyeV9ydW4oImNlcGggIiArIGNtZF9qc29u + WyJwcmVmaXgiXSkKICAgICAgICByZXRfdmFsLCBqc29uX291dCwgZXJyX21zZyA9IHNlbGYuX2Nv bW1vbl9jbWRfanNvbl9nZW4oY21kX2pzb24pCiAgICAgICAgIyBpZiB0aGVyZSBpcyBhbiB1bnN1 - Y2Nlc3NmdWwgYXR0ZW1wdCwKICAgICAgICBpZiByZXRfdmFsICE9IDAgb3IgbGVuKGpzb25fb3V0 - KSA9PSAwOgogICAgICAgICAgICByZXR1cm4gTm9uZQogICAgICAgIGlmICJkYXNoYm9hcmQiIG5v - dCBpbiBqc29uX291dDoKICAgICAgICAgICAgcmV0dXJuIE5vbmUKICAgICAgICByZXR1cm4ganNv - bl9vdXRbImRhc2hib2FyZCJdCgogICAgZGVmIGNyZWF0ZV9yZ3dfYWRtaW5fb3BzX3VzZXIoc2Vs - Zik6CiAgICAgICAgY21kID0gWwogICAgICAgICAgICAicmFkb3Nndy1hZG1pbiIsCiAgICAgICAg - ICAgICJ1c2VyIiwKICAgICAgICAgICAgImNyZWF0ZSIsCiAgICAgICAgICAgICItLXVpZCIsCiAg - ICAgICAgICAgIHNlbGYuRVhURVJOQUxfUkdXX0FETUlOX09QU19VU0VSX05BTUUsCiAgICAgICAg - ICAgICItLWRpc3BsYXktbmFtZSIsCiAgICAgICAgICAgICJSb29rIFJHVyBBZG1pbiBPcHMgdXNl - ciIsCiAgICAgICAgICAgICItLWNhcHMiLAogICAgICAgICAgICAiYnVja2V0cz0qO3VzZXJzPSo7 - dXNhZ2U9cmVhZDttZXRhZGF0YT1yZWFkO3pvbmU9cmVhZCIsCiAgICAgICAgICAgICItLXJndy1y - ZWFsbSIsCiAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIucmd3X3JlYWxtX25hbWUsCiAgICAg - ICAgICAgICItLXJndy16b25lZ3JvdXAiLAogICAgICAgICAgICBzZWxmLl9hcmdfcGFyc2VyLnJn - d196b25lZ3JvdXBfbmFtZSwKICAgICAgICAgICAgIi0tcmd3LXpvbmUiLAogICAgICAgICAgICBz - ZWxmLl9hcmdfcGFyc2VyLnJnd196b25lX25hbWUsCiAgICAgICAgXQogICAgICAgIGlmIHNlbGYu - X2FyZ19wYXJzZXIuZHJ5X3J1bjoKICAgICAgICAgICAgcmV0dXJuIHNlbGYuZHJ5X3J1bigiY2Vw - aCAiICsgIiAiLmpvaW4oY21kKSkKICAgICAgICB0cnk6CiAgICAgICAgICAgIG91dHB1dCA9IHN1 - YnByb2Nlc3MuY2hlY2tfb3V0cHV0KGNtZCwgc3RkZXJyPXN1YnByb2Nlc3MuUElQRSkKICAgICAg - ICBleGNlcHQgc3VicHJvY2Vzcy5DYWxsZWRQcm9jZXNzRXJyb3IgYXMgZXhlY0VycjoKICAgICAg - ICAgICAgIyBpZiB0aGUgdXNlciBhbHJlYWR5IGV4aXN0cywgd2UganVzdCBxdWVyeSBpdAogICAg - ICAgICAgICBpZiBleGVjRXJyLnJldHVybmNvZGUgPT0gZXJybm8uRUVYSVNUOgogICAgICAgICAg - ICAgICAgY21kID0gWwogICAgICAgICAgICAgICAgICAgICJyYWRvc2d3LWFkbWluIiwKICAgICAg - ICAgICAgICAgICAgICAidXNlciIsCiAgICAgICAgICAgICAgICAgICAgImluZm8iLAogICAgICAg - ICAgICAgICAgICAgICItLXVpZCIsCiAgICAgICAgICAgICAgICAgICAgc2VsZi5FWFRFUk5BTF9S - R1dfQURNSU5fT1BTX1VTRVJfTkFNRSwKICAgICAgICAgICAgICAgICAgICAiLS1yZ3ctcmVhbG0i - LAogICAgICAgICAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIucmd3X3JlYWxtX25hbWUsCiAg - ICAgICAgICAgICAgICAgICAgIi0tcmd3LXpvbmVncm91cCIsCiAgICAgICAgICAgICAgICAgICAg - c2VsZi5fYXJnX3BhcnNlci5yZ3dfem9uZWdyb3VwX25hbWUsCiAgICAgICAgICAgICAgICAgICAg - Ii0tcmd3LXpvbmUiLAogICAgICAgICAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIucmd3X3pv - bmVfbmFtZSwKICAgICAgICAgICAgICAgIF0KICAgICAgICAgICAgICAgIHRyeToKICAgICAgICAg - ICAgICAgICAgICBvdXRwdXQgPSBzdWJwcm9jZXNzLmNoZWNrX291dHB1dChjbWQsIHN0ZGVycj1z - dWJwcm9jZXNzLlBJUEUpCiAgICAgICAgICAgICAgICBleGNlcHQgc3VicHJvY2Vzcy5DYWxsZWRQ - cm9jZXNzRXJyb3IgYXMgZXhlY0VycjoKICAgICAgICAgICAgICAgICAgICBlcnJfbXNnID0gKAog - ICAgICAgICAgICAgICAgICAgICAgICBmImZhaWxlZCB0byBleGVjdXRlIGNvbW1hbmQge2NtZH0u - IE91dHB1dDoge2V4ZWNFcnIub3V0cHV0fS4gIgogICAgICAgICAgICAgICAgICAgICAgICBmIkNv - ZGU6IHtleGVjRXJyLnJldHVybmNvZGV9LiBFcnJvcjoge2V4ZWNFcnIuc3RkZXJyfSIKICAgICAg - ICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgc3lzLnN0ZGVyci53cml0ZShlcnJf - bXNnKQogICAgICAgICAgICAgICAgICAgIHJldHVybiBOb25lLCBOb25lLCBGYWxzZSwgIi0xIgog - ICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgZXJyX21zZyA9ICgKICAgICAgICAgICAg - ICAgICAgICBmImZhaWxlZCB0byBleGVjdXRlIGNvbW1hbmQge2NtZH0uIE91dHB1dDoge2V4ZWNF - cnIub3V0cHV0fS4gIgogICAgICAgICAgICAgICAgICAgIGYiQ29kZToge2V4ZWNFcnIucmV0dXJu - Y29kZX0uIEVycm9yOiB7ZXhlY0Vyci5zdGRlcnJ9IgogICAgICAgICAgICAgICAgKQogICAgICAg - ICAgICAgICAgc3lzLnN0ZGVyci53cml0ZShlcnJfbXNnKQogICAgICAgICAgICAgICAgcmV0dXJu - IE5vbmUsIE5vbmUsIEZhbHNlLCAiLTEiCgogICAgICAgICMgc2VwYXJhdGVseSBhZGQgaW5mbz1y - ZWFkIGNhcHMgZm9yIHJndy1lbmRwb2ludCBpcCB2YWxpZGF0aW9uCiAgICAgICAgaW5mb19jYXBf - c3VwcG9ydGVkID0gVHJ1ZQogICAgICAgIGNtZCA9IFsKICAgICAgICAgICAgInJhZG9zZ3ctYWRt - aW4iLAogICAgICAgICAgICAiY2FwcyIsCiAgICAgICAgICAgICJhZGQiLAogICAgICAgICAgICAi - LS11aWQiLAogICAgICAgICAgICBzZWxmLkVYVEVSTkFMX1JHV19BRE1JTl9PUFNfVVNFUl9OQU1F - LAogICAgICAgICAgICAiLS1jYXBzIiwKICAgICAgICAgICAgImluZm89cmVhZCIsCiAgICAgICAg - ICAgICItLXJndy1yZWFsbSIsCiAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIucmd3X3JlYWxt - X25hbWUsCiAgICAgICAgICAgICItLXJndy16b25lZ3JvdXAiLAogICAgICAgICAgICBzZWxmLl9h - cmdfcGFyc2VyLnJnd196b25lZ3JvdXBfbmFtZSwKICAgICAgICAgICAgIi0tcmd3LXpvbmUiLAog - ICAgICAgICAgICBzZWxmLl9hcmdfcGFyc2VyLnJnd196b25lX25hbWUsCiAgICAgICAgXQogICAg - ICAgIHRyeToKICAgICAgICAgICAgb3V0cHV0ID0gc3VicHJvY2Vzcy5jaGVja19vdXRwdXQoY21k - LCBzdGRlcnI9c3VicHJvY2Vzcy5QSVBFKQogICAgICAgIGV4Y2VwdCBzdWJwcm9jZXNzLkNhbGxl - ZFByb2Nlc3NFcnJvciBhcyBleGVjRXJyOgogICAgICAgICAgICAjIGlmIHRoZSBjZXBoIHZlcnNp - b24gbm90IHN1cHBvcnRlZCBmb3IgYWRkaW5nIGBpbmZvPXJlYWRgIGNhcChyZ3dfdmFsaWRhdGlv - bikKICAgICAgICAgICAgaWYgKAogICAgICAgICAgICAgICAgImNvdWxkIG5vdCBhZGQgY2Fwczog - dW5hYmxlIHRvIGFkZCBjYXBzOiBpbmZvPXJlYWRcbiIKICAgICAgICAgICAgICAgIGluIGV4ZWNF - cnIuc3RkZXJyLmRlY29kZSgidXRmLTgiKQogICAgICAgICAgICAgICAgYW5kIGV4ZWNFcnIucmV0 - dXJuY29kZSA9PSAyNDQKICAgICAgICAgICAgKToKICAgICAgICAgICAgICAgIGluZm9fY2FwX3N1 - cHBvcnRlZCA9IEZhbHNlCiAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICBlcnJfbXNn - ID0gKAogICAgICAgICAgICAgICAgICAgIGYiZmFpbGVkIHRvIGV4ZWN1dGUgY29tbWFuZCB7Y21k - fS4gT3V0cHV0OiB7ZXhlY0Vyci5vdXRwdXR9LiAiCiAgICAgICAgICAgICAgICAgICAgZiJDb2Rl - OiB7ZXhlY0Vyci5yZXR1cm5jb2RlfS4gRXJyb3I6IHtleGVjRXJyLnN0ZGVycn0iCiAgICAgICAg - ICAgICAgICApCiAgICAgICAgICAgICAgICBzeXMuc3RkZXJyLndyaXRlKGVycl9tc2cpCiAgICAg - ICAgICAgICAgICByZXR1cm4gTm9uZSwgTm9uZSwgRmFsc2UsICItMSIKCiAgICAgICAganNvbm91 - dHB1dCA9IGpzb24ubG9hZHMob3V0cHV0KQogICAgICAgIHJldHVybiAoCiAgICAgICAgICAgIGpz - b25vdXRwdXRbImtleXMiXVswXVsiYWNjZXNzX2tleSJdLAogICAgICAgICAgICBqc29ub3V0cHV0 - WyJrZXlzIl1bMF1bInNlY3JldF9rZXkiXSwKICAgICAgICAgICAgaW5mb19jYXBfc3VwcG9ydGVk - LAogICAgICAgICAgICAiIiwKICAgICAgICApCgogICAgZGVmIHZhbGlkYXRlX3JiZF9wb29sKHNl - bGYsIHBvb2xfbmFtZSk6CiAgICAgICAgaWYgbm90IHNlbGYuY2x1c3Rlci5wb29sX2V4aXN0cyhw - b29sX25hbWUpOgogICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWlsdXJlRXhjZXB0aW9uKAog - ICAgICAgICAgICAgICAgZiJUaGUgcHJvdmlkZWQgcG9vbCwgJ3twb29sX25hbWV9JywgZG9lcyBu - b3QgZXhpc3QiCiAgICAgICAgICAgICkKCiAgICBkZWYgaW5pdF9yYmRfcG9vbChzZWxmLCByYmRf - cG9vbF9uYW1lKToKICAgICAgICBpZiBpc2luc3RhbmNlKHNlbGYuY2x1c3RlciwgRHVtbXlSYWRv - cyk6CiAgICAgICAgICAgIHJldHVybgogICAgICAgIGlvY3R4ID0gc2VsZi5jbHVzdGVyLm9wZW5f - aW9jdHgocmJkX3Bvb2xfbmFtZSkKICAgICAgICByYmRfaW5zdCA9IHJiZC5SQkQoKQogICAgICAg - IHJiZF9pbnN0LnBvb2xfaW5pdChpb2N0eCwgVHJ1ZSkKCiAgICBkZWYgdmFsaWRhdGVfcmFkb3Nf - bmFtZXNwYWNlKHNlbGYpOgogICAgICAgIHJiZF9wb29sX25hbWUgPSBzZWxmLl9hcmdfcGFyc2Vy - LnJiZF9kYXRhX3Bvb2xfbmFtZQogICAgICAgIGlmIHNlbGYuX2FyZ19wYXJzZXIucmJkX21ldGFk - YXRhX2VjX3Bvb2xfbmFtZToKICAgICAgICAgICAgcmJkX3Bvb2xfbmFtZSA9IHNlbGYuX2FyZ19w - YXJzZXIucmJkX21ldGFkYXRhX2VjX3Bvb2xfbmFtZQogICAgICAgIHJhZG9zX25hbWVzcGFjZSA9 - IHNlbGYuX2FyZ19wYXJzZXIucmFkb3NfbmFtZXNwYWNlCiAgICAgICAgaWYgcmFkb3NfbmFtZXNw - YWNlID09ICIiOgogICAgICAgICAgICByZXR1cm4KICAgICAgICBpZiByYWRvc19uYW1lc3BhY2Uu - aXNsb3dlcigpID09IEZhbHNlOgogICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWlsdXJlRXhj - ZXB0aW9uKAogICAgICAgICAgICAgICAgZiJUaGUgcHJvdmlkZWQgcmFkb3MgTmFtZXNwYWNlLCAn - e3JhZG9zX25hbWVzcGFjZX0nLCAiCiAgICAgICAgICAgICAgICBmImNvbnRhaW5zIHVwcGVyIGNh - c2UiCiAgICAgICAgICAgICkKICAgICAgICByYmRfaW5zdCA9IHJiZC5SQkQoKQogICAgICAgIGlv - Y3R4ID0gc2VsZi5jbHVzdGVyLm9wZW5faW9jdHgocmJkX3Bvb2xfbmFtZSkKICAgICAgICBpZiBy - YmRfaW5zdC5uYW1lc3BhY2VfZXhpc3RzKGlvY3R4LCByYWRvc19uYW1lc3BhY2UpIGlzIEZhbHNl - OgogICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWlsdXJlRXhjZXB0aW9uKAogICAgICAgICAg - ICAgICAgZiJUaGUgcHJvdmlkZWQgcmFkb3MgTmFtZXNwYWNlLCAne3JhZG9zX25hbWVzcGFjZX0n - LCAiCiAgICAgICAgICAgICAgICBmImlzIG5vdCBmb3VuZCBpbiB0aGUgcG9vbCAne3JiZF9wb29s - X25hbWV9JyIKICAgICAgICAgICAgKQoKICAgIGRlZiBnZXRfb3JfY3JlYXRlX3N1YnZvbHVtZV9n - cm91cChzZWxmLCBzdWJ2b2x1bWVfZ3JvdXAsIGNlcGhmc19maWxlc3lzdGVtX25hbWUpOgogICAg - ICAgIGNtZCA9IFsKICAgICAgICAgICAgImNlcGgiLAogICAgICAgICAgICAiZnMiLAogICAgICAg - ICAgICAic3Vidm9sdW1lZ3JvdXAiLAogICAgICAgICAgICAiZ2V0cGF0aCIsCiAgICAgICAgICAg - IGNlcGhmc19maWxlc3lzdGVtX25hbWUsCiAgICAgICAgICAgIHN1YnZvbHVtZV9ncm91cCwKICAg - ICAgICBdCiAgICAgICAgdHJ5OgogICAgICAgICAgICBfID0gc3VicHJvY2Vzcy5jaGVja19vdXRw + Y2Nlc3NmdWwgYXR0ZW1wdCwgcmVwb3J0IGFuIGVycm9yCiAgICAgICAgaWYgcmV0X3ZhbCAhPSAw + OgogICAgICAgICAgICAjIGlmIGZzIGFuZCBkYXRhX3Bvb2wgYXJndW1lbnRzIGFyZSBub3Qgc2V0 + LCBzaWxlbnRseSByZXR1cm4KICAgICAgICAgICAgaWYgKAogICAgICAgICAgICAgICAgc2VsZi5f + YXJnX3BhcnNlci5jZXBoZnNfZmlsZXN5c3RlbV9uYW1lID09ICIiCiAgICAgICAgICAgICAgICBh + bmQgc2VsZi5fYXJnX3BhcnNlci5jZXBoZnNfZGF0YV9wb29sX25hbWUgPT0gIiIKICAgICAgICAg + ICAgKToKICAgICAgICAgICAgICAgIHJldHVybgogICAgICAgICAgICAjIGlmIHVzZXIgaGFzIHBy + b3ZpZGVkIGFueSBvZiB0aGUKICAgICAgICAgICAgIyAnLS1jZXBoZnMtZmlsZXN5c3RlbS1uYW1l + JyBvciAnLS1jZXBoZnMtZGF0YS1wb29sLW5hbWUnIGFyZ3VtZW50cywKICAgICAgICAgICAgIyBy + YWlzZSBhbiBleGNlcHRpb24gYXMgd2UgYXJlIHVuYWJsZSB0byB2ZXJpZnkgdGhlIGFyZ3MKICAg + ICAgICAgICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlvbigKICAgICAgICAgICAgICAg + IGYiJ2ZzIGxzJyBjZXBoIGNhbGwgZmFpbGVkIHdpdGggZXJyb3I6IHtlcnJfbXNnfSIKICAgICAg + ICAgICAgKQoKICAgICAgICBtYXRjaGluZ19qc29uX291dCA9IHt9CiAgICAgICAgIyBpZiAnLS1j + ZXBoZnMtZmlsZXN5c3RlbS1uYW1lJyBhcmd1bWVudCBpcyBwcm92aWRlZCwKICAgICAgICAjIGNo + ZWNrIHdoZXRoZXIgdGhlIHByb3ZpZGVkIGZpbGVzeXN0ZW0tbmFtZSBleGlzdHMgb3Igbm90CiAg + ICAgICAgaWYgc2VsZi5fYXJnX3BhcnNlci5jZXBoZnNfZmlsZXN5c3RlbV9uYW1lOgogICAgICAg + ICAgICAjIGdldCB0aGUgbWF0Y2hpbmcgbGlzdAogICAgICAgICAgICBtYXRjaGluZ19qc29uX291 + dF9saXN0ID0gWwogICAgICAgICAgICAgICAgbWF0Y2hlZAogICAgICAgICAgICAgICAgZm9yIG1h + dGNoZWQgaW4ganNvbl9vdXQKICAgICAgICAgICAgICAgIGlmIHN0cihtYXRjaGVkWyJuYW1lIl0p + ID09IHNlbGYuX2FyZ19wYXJzZXIuY2VwaGZzX2ZpbGVzeXN0ZW1fbmFtZQogICAgICAgICAgICBd + CiAgICAgICAgICAgICMgdW5hYmxlIHRvIGZpbmQgYSBtYXRjaGluZyBmcy1uYW1lLCByYWlzZSBh + biBlcnJvcgogICAgICAgICAgICBpZiBsZW4obWF0Y2hpbmdfanNvbl9vdXRfbGlzdCkgPT0gMDoK + ICAgICAgICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1cmVFeGNlcHRpb24oCiAgICAgICAg + ICAgICAgICAgICAgZiJGaWxlc3lzdGVtIHByb3ZpZGVkLCAne3NlbGYuX2FyZ19wYXJzZXIuY2Vw + aGZzX2ZpbGVzeXN0ZW1fbmFtZX0nLCAiCiAgICAgICAgICAgICAgICAgICAgZiJpcyBub3QgZm91 + bmQgaW4gdGhlIGZzLWxpc3Q6IHtbc3RyKHhbJ25hbWUnXSkgZm9yIHggaW4ganNvbl9vdXRdfSIK + ICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgbWF0Y2hpbmdfanNvbl9vdXQgPSBtYXRjaGlu + Z19qc29uX291dF9saXN0WzBdCiAgICAgICAgIyBpZiBjZXBoZnMgZmlsZXN5c3RlbSBuYW1lIGlz + IG5vdCBwcm92aWRlZCwKICAgICAgICAjIHRyeSB0byBnZXQgYSBkZWZhdWx0IGZzIG5hbWUgYnkg + ZG9pbmcgdGhlIGZvbGxvd2luZwogICAgICAgIGVsc2U6CiAgICAgICAgICAgICMgYS4gY2hlY2sg + aWYgdGhlcmUgaXMgb25seSBvbmUgZmlsZXN5c3RlbSBpcyBwcmVzZW50CiAgICAgICAgICAgIGlm + IGxlbihqc29uX291dCkgPT0gMToKICAgICAgICAgICAgICAgIG1hdGNoaW5nX2pzb25fb3V0ID0g + anNvbl9vdXRbMF0KICAgICAgICAgICAgIyBiLiBvciBlbHNlLCBjaGVjayBpZiBkYXRhX3Bvb2wg + bmFtZSBpcyBwcm92aWRlZAogICAgICAgICAgICBlbGlmIHNlbGYuX2FyZ19wYXJzZXIuY2VwaGZz + X2RhdGFfcG9vbF9uYW1lOgogICAgICAgICAgICAgICAgIyBhbmQgaWYgcHJlc2VudCwgY2hlY2sg + d2hldGhlciB0aGVyZSBleGlzdHMgYSBmcyB3aGljaCBoYXMgdGhlIGRhdGFfcG9vbAogICAgICAg + ICAgICAgICAgZm9yIGVhY2hKIGluIGpzb25fb3V0OgogICAgICAgICAgICAgICAgICAgIGlmIHNl + bGYuX2FyZ19wYXJzZXIuY2VwaGZzX2RhdGFfcG9vbF9uYW1lIGluIGVhY2hKWyJkYXRhX3Bvb2xz + Il06CiAgICAgICAgICAgICAgICAgICAgICAgIG1hdGNoaW5nX2pzb25fb3V0ID0gZWFjaEoKICAg + ICAgICAgICAgICAgICAgICAgICAgYnJlYWsKICAgICAgICAgICAgICAgICMgaWYgdGhlcmUgaXMg + bm8gbWF0Y2hpbmcgZnMgZXhpc3RzLCB0aGF0IG1lYW5zIHByb3ZpZGVkIGRhdGFfcG9vbCBuYW1l + IGlzIGludmFsaWQKICAgICAgICAgICAgICAgIGlmIG5vdCBtYXRjaGluZ19qc29uX291dDoKICAg + ICAgICAgICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWlsdXJlRXhjZXB0aW9uKAogICAgICAg + ICAgICAgICAgICAgICAgICBmIlByb3ZpZGVkIGRhdGFfcG9vbCBuYW1lLCB7c2VsZi5fYXJnX3Bh + cnNlci5jZXBoZnNfZGF0YV9wb29sX25hbWV9LCIKICAgICAgICAgICAgICAgICAgICAgICAgIiBk + b2VzIG5vdCBleGlzdHMiCiAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAjIGMuIGlm + IG5vdGhpbmcgaXMgc2V0IGFuZCBjb3VsZG4ndCBmaW5kIGEgZGVmYXVsdCwKICAgICAgICAgICAg + ZWxzZToKICAgICAgICAgICAgICAgICMganVzdCByZXR1cm4gc2lsZW50bHkKICAgICAgICAgICAg + ICAgIHJldHVybgoKICAgICAgICBpZiBtYXRjaGluZ19qc29uX291dDoKICAgICAgICAgICAgc2Vs + Zi5fYXJnX3BhcnNlci5jZXBoZnNfZmlsZXN5c3RlbV9uYW1lID0gc3RyKG1hdGNoaW5nX2pzb25f + b3V0WyJuYW1lIl0pCiAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIuY2VwaGZzX21ldGFkYXRh + X3Bvb2xfbmFtZSA9IHN0cigKICAgICAgICAgICAgICAgIG1hdGNoaW5nX2pzb25fb3V0WyJtZXRh + ZGF0YV9wb29sIl0KICAgICAgICAgICAgKQoKICAgICAgICBpZiBpc2luc3RhbmNlKG1hdGNoaW5n + X2pzb25fb3V0WyJkYXRhX3Bvb2xzIl0sIGxpc3QpOgogICAgICAgICAgICAjIGlmIHRoZSB1c2Vy + IGhhcyBhbHJlYWR5IHByb3ZpZGVkIGRhdGEtcG9vbC1uYW1lLAogICAgICAgICAgICAjIHRocm91 + Z2ggLS1jZXBoZnMtZGF0YS1wb29sLW5hbWUKICAgICAgICAgICAgaWYgc2VsZi5fYXJnX3BhcnNl + ci5jZXBoZnNfZGF0YV9wb29sX25hbWU6CiAgICAgICAgICAgICAgICAjIGlmIHRoZSBwcm92aWRl + ZCBuYW1lIGlzIG5vdCBtYXRjaGluZyB3aXRoIHRoZSBvbmUgaW4gdGhlIGxpc3QKICAgICAgICAg + ICAgICAgIGlmICgKICAgICAgICAgICAgICAgICAgICBzZWxmLl9hcmdfcGFyc2VyLmNlcGhmc19k + YXRhX3Bvb2xfbmFtZQogICAgICAgICAgICAgICAgICAgIG5vdCBpbiBtYXRjaGluZ19qc29uX291 + dFsiZGF0YV9wb29scyJdCiAgICAgICAgICAgICAgICApOgogICAgICAgICAgICAgICAgICAgIHJh + aXNlIEV4ZWN1dGlvbkZhaWx1cmVFeGNlcHRpb24oCiAgICAgICAgICAgICAgICAgICAgICAgIGYi + UHJvdmlkZWQgZGF0YS1wb29sLW5hbWU6ICd7c2VsZi5fYXJnX3BhcnNlci5jZXBoZnNfZGF0YV9w + b29sX25hbWV9JywgIgogICAgICAgICAgICAgICAgICAgICAgICAiZG9lc24ndCBtYXRjaCBmcm9t + IHRoZSBkYXRhLXBvb2xzIGxpc3Q6ICIKICAgICAgICAgICAgICAgICAgICAgICAgZiJ7W3N0cih4 + KSBmb3IgeCBpbiBtYXRjaGluZ19qc29uX291dFsnZGF0YV9wb29scyddXX0iCiAgICAgICAgICAg + ICAgICAgICAgKQogICAgICAgICAgICAjIGlmIGRhdGFfcG9vbCBuYW1lIGlzIG5vdCBwcm92aWRl + ZCwKICAgICAgICAgICAgIyB0aGVuIHRyeSB0byBmaW5kIGEgZGVmYXVsdCBkYXRhIHBvb2wgbmFt + ZQogICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgIyBpZiBubyBkYXRhX3Bvb2xzIGV4 + aXN0LCBzaWxlbnRseSByZXR1cm4KICAgICAgICAgICAgICAgIGlmIGxlbihtYXRjaGluZ19qc29u + X291dFsiZGF0YV9wb29scyJdKSA9PSAwOgogICAgICAgICAgICAgICAgICAgIHJldHVybgogICAg + ICAgICAgICAgICAgc2VsZi5fYXJnX3BhcnNlci5jZXBoZnNfZGF0YV9wb29sX25hbWUgPSBzdHIo + CiAgICAgICAgICAgICAgICAgICAgbWF0Y2hpbmdfanNvbl9vdXRbImRhdGFfcG9vbHMiXVswXQog + ICAgICAgICAgICAgICAgKQogICAgICAgICAgICAjIGlmIHRoZXJlIGFyZSBtb3JlIHRoYW4gb25l + ICdkYXRhX3Bvb2xzJyBleGlzdCwKICAgICAgICAgICAgIyB0aGVuIHdhcm4gdGhlIHVzZXIgdGhh + dCB3ZSBhcmUgdXNpbmcgdGhlIHNlbGVjdGVkIG5hbWUKICAgICAgICAgICAgaWYgbGVuKG1hdGNo + aW5nX2pzb25fb3V0WyJkYXRhX3Bvb2xzIl0pID4gMToKICAgICAgICAgICAgICAgIHByaW50KAog + ICAgICAgICAgICAgICAgICAgICJXQVJOSU5HOiBNdWx0aXBsZSBkYXRhIHBvb2xzIGRldGVjdGVk + OiAiCiAgICAgICAgICAgICAgICAgICAgZiJ7W3N0cih4KSBmb3IgeCBpbiBtYXRjaGluZ19qc29u + X291dFsnZGF0YV9wb29scyddXX1cbiIKICAgICAgICAgICAgICAgICAgICBmIlVzaW5nIHRoZSBk + YXRhLXBvb2w6ICd7c2VsZi5fYXJnX3BhcnNlci5jZXBoZnNfZGF0YV9wb29sX25hbWV9J1xuIgog + ICAgICAgICAgICAgICAgKQoKICAgIGRlZiBjcmVhdGVfY2hlY2tlcktleShzZWxmLCB1c2VyKToK + ICAgICAgICBjYXBzLCBlbnRpdHkgPSBzZWxmLmdldF9jYXBzX2FuZF9lbnRpdHkodXNlcikKICAg + ICAgICBjbWRfanNvbiA9IHsKICAgICAgICAgICAgInByZWZpeCI6ICJhdXRoIGdldC1vci1jcmVh + dGUiLAogICAgICAgICAgICAiZW50aXR5IjogZW50aXR5LAogICAgICAgICAgICAiY2FwcyI6IFtj + YXAgZm9yIGNhcF9saXN0IGluIGxpc3QoY2Fwcy5pdGVtcygpKSBmb3IgY2FwIGluIGNhcF9saXN0 + XSwKICAgICAgICAgICAgImZvcm1hdCI6ICJqc29uIiwKICAgICAgICB9CgogICAgICAgIGlmIHNl + bGYuX2FyZ19wYXJzZXIuZHJ5X3J1bjoKICAgICAgICAgICAgcmV0dXJuIHNlbGYuZHJ5X3J1bigK + ICAgICAgICAgICAgICAgICJjZXBoICIKICAgICAgICAgICAgICAgICsgY21kX2pzb25bInByZWZp + eCJdCiAgICAgICAgICAgICAgICArICIgIgogICAgICAgICAgICAgICAgKyBjbWRfanNvblsiZW50 + aXR5Il0KICAgICAgICAgICAgICAgICsgIiAiCiAgICAgICAgICAgICAgICArICIgIi5qb2luKGNt + ZF9qc29uWyJjYXBzIl0pCiAgICAgICAgICAgICkKICAgICAgICAjIGNoZWNrIGlmIHVzZXIgYWxy + ZWFkeSBleGlzdAogICAgICAgIHVzZXJfa2V5ID0gc2VsZi5jaGVja191c2VyX2V4aXN0KGVudGl0 + eSkKICAgICAgICBpZiB1c2VyX2tleSAhPSAiIjoKICAgICAgICAgICAgcmV0dXJuIHVzZXJfa2V5 + CgogICAgICAgIHJldF92YWwsIGpzb25fb3V0LCBlcnJfbXNnID0gc2VsZi5fY29tbW9uX2NtZF9q + c29uX2dlbihjbWRfanNvbikKICAgICAgICAjIGlmIHRoZXJlIGlzIGFuIHVuc3VjY2Vzc2Z1bCBh + dHRlbXB0LAogICAgICAgIGlmIHJldF92YWwgIT0gMCBvciBsZW4oanNvbl9vdXQpID09IDA6CiAg + ICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1cmVFeGNlcHRpb24oCiAgICAgICAgICAgICAg + ICBmIidhdXRoIGdldC1vci1jcmVhdGUge3NlbGYucnVuX2FzX3VzZXJ9JyBjb21tYW5kIGZhaWxl + ZFxuIgogICAgICAgICAgICAgICAgZiJFcnJvcjoge2Vycl9tc2cgaWYgcmV0X3ZhbCAhPSAwIGVs + c2Ugc2VsZi5FTVBUWV9PVVRQVVRfTElTVH0iCiAgICAgICAgICAgICkKICAgICAgICByZXR1cm4g + c3RyKGpzb25fb3V0WzBdWyJrZXkiXSkKCiAgICBkZWYgZ2V0X2NlcGhfZGFzaGJvYXJkX2xpbmso + c2VsZik6CiAgICAgICAgY21kX2pzb24gPSB7InByZWZpeCI6ICJtZ3Igc2VydmljZXMiLCAiZm9y + bWF0IjogImpzb24ifQogICAgICAgIGlmIHNlbGYuX2FyZ19wYXJzZXIuZHJ5X3J1bjoKICAgICAg + ICAgICAgcmV0dXJuIHNlbGYuZHJ5X3J1bigiY2VwaCAiICsgY21kX2pzb25bInByZWZpeCJdKQog + ICAgICAgIHJldF92YWwsIGpzb25fb3V0LCBfID0gc2VsZi5fY29tbW9uX2NtZF9qc29uX2dlbihj + bWRfanNvbikKICAgICAgICAjIGlmIHRoZXJlIGlzIGFuIHVuc3VjY2Vzc2Z1bCBhdHRlbXB0LAog + ICAgICAgIGlmIHJldF92YWwgIT0gMCBvciBsZW4oanNvbl9vdXQpID09IDA6CiAgICAgICAgICAg + IHJldHVybiBOb25lCiAgICAgICAgaWYgImRhc2hib2FyZCIgbm90IGluIGpzb25fb3V0OgogICAg + ICAgICAgICByZXR1cm4gTm9uZQogICAgICAgIHJldHVybiBqc29uX291dFsiZGFzaGJvYXJkIl0K + CiAgICBkZWYgY3JlYXRlX3Jnd19hZG1pbl9vcHNfdXNlcihzZWxmKToKICAgICAgICBjbWQgPSBb + CiAgICAgICAgICAgICJyYWRvc2d3LWFkbWluIiwKICAgICAgICAgICAgInVzZXIiLAogICAgICAg + ICAgICAiY3JlYXRlIiwKICAgICAgICAgICAgIi0tdWlkIiwKICAgICAgICAgICAgc2VsZi5FWFRF + Uk5BTF9SR1dfQURNSU5fT1BTX1VTRVJfTkFNRSwKICAgICAgICAgICAgIi0tZGlzcGxheS1uYW1l + IiwKICAgICAgICAgICAgIlJvb2sgUkdXIEFkbWluIE9wcyB1c2VyIiwKICAgICAgICAgICAgIi0t + Y2FwcyIsCiAgICAgICAgICAgICJidWNrZXRzPSo7dXNlcnM9Kjt1c2FnZT1yZWFkO21ldGFkYXRh + PXJlYWQ7em9uZT1yZWFkIiwKICAgICAgICAgICAgIi0tcmd3LXJlYWxtIiwKICAgICAgICAgICAg + c2VsZi5fYXJnX3BhcnNlci5yZ3dfcmVhbG1fbmFtZSwKICAgICAgICAgICAgIi0tcmd3LXpvbmVn + cm91cCIsCiAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIucmd3X3pvbmVncm91cF9uYW1lLAog + ICAgICAgICAgICAiLS1yZ3ctem9uZSIsCiAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIucmd3 + X3pvbmVfbmFtZSwKICAgICAgICBdCiAgICAgICAgaWYgc2VsZi5fYXJnX3BhcnNlci5kcnlfcnVu + OgogICAgICAgICAgICByZXR1cm4gc2VsZi5kcnlfcnVuKCJjZXBoICIgKyAiICIuam9pbihjbWQp + KQogICAgICAgIHRyeToKICAgICAgICAgICAgb3V0cHV0ID0gc3VicHJvY2Vzcy5jaGVja19vdXRw dXQoY21kLCBzdGRlcnI9c3VicHJvY2Vzcy5QSVBFKQogICAgICAgIGV4Y2VwdCBzdWJwcm9jZXNz - LkNhbGxlZFByb2Nlc3NFcnJvcjoKICAgICAgICAgICAgY21kID0gWwogICAgICAgICAgICAgICAg - ImNlcGgiLAogICAgICAgICAgICAgICAgImZzIiwKICAgICAgICAgICAgICAgICJzdWJ2b2x1bWVn - cm91cCIsCiAgICAgICAgICAgICAgICAiY3JlYXRlIiwKICAgICAgICAgICAgICAgIGNlcGhmc19m - aWxlc3lzdGVtX25hbWUsCiAgICAgICAgICAgICAgICBzdWJ2b2x1bWVfZ3JvdXAsCiAgICAgICAg - ICAgIF0KICAgICAgICAgICAgdHJ5OgogICAgICAgICAgICAgICAgXyA9IHN1YnByb2Nlc3MuY2hl - Y2tfb3V0cHV0KGNtZCwgc3RkZXJyPXN1YnByb2Nlc3MuUElQRSkKICAgICAgICAgICAgZXhjZXB0 - IHN1YnByb2Nlc3MuQ2FsbGVkUHJvY2Vzc0Vycm9yOgogICAgICAgICAgICAgICAgcmFpc2UgRXhl - Y3V0aW9uRmFpbHVyZUV4Y2VwdGlvbigKICAgICAgICAgICAgICAgICAgICBmInN1YnZvbHVtZSBn - cm91cCB7c3Vidm9sdW1lX2dyb3VwfSBpcyBub3QgYWJsZSB0byBnZXQgY3JlYXRlZCIKICAgICAg - ICAgICAgICAgICkKCiAgICBkZWYgcGluX3N1YnZvbHVtZSgKICAgICAgICBzZWxmLCBzdWJ2b2x1 - bWVfZ3JvdXAsIGNlcGhmc19maWxlc3lzdGVtX25hbWUsIHBpbl90eXBlLCBwaW5fc2V0dGluZwog - ICAgKToKICAgICAgICBjbWQgPSBbCiAgICAgICAgICAgICJjZXBoIiwKICAgICAgICAgICAgImZz - IiwKICAgICAgICAgICAgInN1YnZvbHVtZWdyb3VwIiwKICAgICAgICAgICAgInBpbiIsCiAgICAg - ICAgICAgIGNlcGhmc19maWxlc3lzdGVtX25hbWUsCiAgICAgICAgICAgIHN1YnZvbHVtZV9ncm91 - cCwKICAgICAgICAgICAgcGluX3R5cGUsCiAgICAgICAgICAgIHBpbl9zZXR0aW5nLAogICAgICAg - IF0KICAgICAgICB0cnk6CiAgICAgICAgICAgIF8gPSBzdWJwcm9jZXNzLmNoZWNrX291dHB1dChj - bWQsIHN0ZGVycj1zdWJwcm9jZXNzLlBJUEUpCiAgICAgICAgZXhjZXB0IHN1YnByb2Nlc3MuQ2Fs - bGVkUHJvY2Vzc0Vycm9yOgogICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWlsdXJlRXhjZXB0 - aW9uKAogICAgICAgICAgICAgICAgZiJzdWJ2b2x1bWUgZ3JvdXAge3N1YnZvbHVtZV9ncm91cH0g - aXMgbm90IGFibGUgdG8gZ2V0IHBpbm5lZCIKICAgICAgICAgICAgKQoKICAgIGRlZiBnZXRfcmd3 - X2ZzaWQoc2VsZiwgYmFzZV91cmwsIHZlcmlmeSk6CiAgICAgICAgYWNjZXNzX2tleSA9IHNlbGYu - b3V0X21hcFsiUkdXX0FETUlOX09QU19VU0VSX0FDQ0VTU19LRVkiXQogICAgICAgIHNlY3JldF9r - ZXkgPSBzZWxmLm91dF9tYXBbIlJHV19BRE1JTl9PUFNfVVNFUl9TRUNSRVRfS0VZIl0KICAgICAg - ICByZ3dfZW5kcG9pbnQgPSBzZWxmLl9hcmdfcGFyc2VyLnJnd19lbmRwb2ludAogICAgICAgIGJh - c2VfdXJsID0gYmFzZV91cmwgKyAiOi8vIiArIHJnd19lbmRwb2ludCArICIvYWRtaW4vaW5mbz8i - CiAgICAgICAgcGFyYW1zID0geyJmb3JtYXQiOiAianNvbiJ9CiAgICAgICAgcmVxdWVzdF91cmwg - PSBiYXNlX3VybCArIHVybGVuY29kZShwYXJhbXMpCgogICAgICAgIHRyeToKICAgICAgICAgICAg - ciA9IHJlcXVlc3RzLmdldCgKICAgICAgICAgICAgICAgIHJlcXVlc3RfdXJsLAogICAgICAgICAg - ICAgICAgYXV0aD1TM0F1dGgoYWNjZXNzX2tleSwgc2VjcmV0X2tleSwgcmd3X2VuZHBvaW50KSwK - ICAgICAgICAgICAgICAgIHZlcmlmeT12ZXJpZnksCiAgICAgICAgICAgICkKICAgICAgICBleGNl - cHQgcmVxdWVzdHMuZXhjZXB0aW9ucy5UaW1lb3V0OgogICAgICAgICAgICBzeXMuc3RkZXJyLndy - aXRlKAogICAgICAgICAgICAgICAgZiJpbnZhbGlkIGVuZHBvaW50Oiwgbm90IGFibGUgdG8gY2Fs - bCBhZG1pbi1vcHMgYXBpe3Jnd19lbmRwb2ludH0iCiAgICAgICAgICAgICkKICAgICAgICAgICAg - cmV0dXJuICIiLCAiLTEiCiAgICAgICAgcjEgPSByLmpzb24oKQogICAgICAgIGlmIHIxIGlzIE5v - bmUgb3IgcjEuZ2V0KCJpbmZvIikgaXMgTm9uZToKICAgICAgICAgICAgc3lzLnN0ZGVyci53cml0 - ZSgKICAgICAgICAgICAgICAgIGYiVGhlIHByb3ZpZGVkIHJndyBFbmRwb2ludCwgJ3tzZWxmLl9h - cmdfcGFyc2VyLnJnd19lbmRwb2ludH0nLCBpcyBpbnZhbGlkLiIKICAgICAgICAgICAgKQogICAg - ICAgICAgICByZXR1cm4gKAogICAgICAgICAgICAgICAgIiIsCiAgICAgICAgICAgICAgICAiLTEi - LAogICAgICAgICAgICApCgogICAgICAgIHJldHVybiByMVsiaW5mbyJdWyJzdG9yYWdlX2JhY2tl - bmRzIl1bMF1bImNsdXN0ZXJfaWQiXSwgIiIKCiAgICBkZWYgdmFsaWRhdGVfcmd3X2VuZHBvaW50 - KHNlbGYsIGluZm9fY2FwX3N1cHBvcnRlZCk6CiAgICAgICAgIyBpZiB0aGUgJ2NsdXN0ZXInIGlu - c3RhbmNlIGlzIGEgZHVtbXkgb25lLAogICAgICAgICMgZG9uJ3QgdHJ5IHRvIHJlYWNoIG91dCB0 - byB0aGUgZW5kcG9pbnQKICAgICAgICBpZiBpc2luc3RhbmNlKHNlbGYuY2x1c3RlciwgRHVtbXlS - YWRvcyk6CiAgICAgICAgICAgIHJldHVybgoKICAgICAgICByZ3dfZW5kcG9pbnQgPSBzZWxmLl9h - cmdfcGFyc2VyLnJnd19lbmRwb2ludAoKICAgICAgICAjIHZhbGlkYXRlIHJndyBlbmRwb2ludCBv - bmx5IGlmIGlwIGFkZHJlc3MgaXMgcGFzc2VkCiAgICAgICAgaXBfdHlwZSA9IHNlbGYuX2ludmFs - aWRfZW5kcG9pbnQocmd3X2VuZHBvaW50KQoKICAgICAgICAjIGNoZWNrIGlmIHRoZSByZ3cgZW5k - cG9pbnQgaXMgcmVhY2hhYmxlCiAgICAgICAgY2VydCA9IE5vbmUKICAgICAgICBpZiBub3Qgc2Vs - Zi5fYXJnX3BhcnNlci5yZ3dfc2tpcF90bHMgYW5kIHNlbGYudmFsaWRhdGVfcmd3X2VuZHBvaW50 - X3Rsc19jZXJ0KCk6CiAgICAgICAgICAgIGNlcnQgPSBzZWxmLl9hcmdfcGFyc2VyLnJnd190bHNf - Y2VydF9wYXRoCiAgICAgICAgYmFzZV91cmwsIHZlcmlmeSwgZXJyID0gc2VsZi5lbmRwb2ludF9k - aWFsKHJnd19lbmRwb2ludCwgaXBfdHlwZSwgY2VydD1jZXJ0KQogICAgICAgIGlmIGVyciAhPSAi - IjoKICAgICAgICAgICAgcmV0dXJuICItMSIKCiAgICAgICAgIyBjaGVjayBpZiB0aGUgcmd3IGVu - ZHBvaW50IGJlbG9uZ3MgdG8gdGhlIHNhbWUgY2x1c3RlcgogICAgICAgICMgb25seSBjaGVjayBp - ZiBgaW5mb2AgY2FwIGlzIHN1cHBvcnRlZAogICAgICAgIGlmIGluZm9fY2FwX3N1cHBvcnRlZDoK - ICAgICAgICAgICAgZnNpZCA9IHNlbGYuZ2V0X2ZzaWQoKQogICAgICAgICAgICByZ3dfZnNpZCwg - ZXJyID0gc2VsZi5nZXRfcmd3X2ZzaWQoYmFzZV91cmwsIHZlcmlmeSkKICAgICAgICAgICAgaWYg - ZXJyID09ICItMSI6CiAgICAgICAgICAgICAgICByZXR1cm4gIi0xIgogICAgICAgICAgICBpZiBm - c2lkICE9IHJnd19mc2lkOgogICAgICAgICAgICAgICAgc3lzLnN0ZGVyci53cml0ZSgKICAgICAg - ICAgICAgICAgICAgICBmIlRoZSBwcm92aWRlZCByZ3cgRW5kcG9pbnQsICd7c2VsZi5fYXJnX3Bh - cnNlci5yZ3dfZW5kcG9pbnR9JywgaXMgaW52YWxpZC4gV2UgYXJlIHZhbGlkYXRpbmcgYnkgY2Fs - bGluZyB0aGUgYWRtaW5vcHMgYXBpIHRocm91Z2ggcmd3LWVuZHBvaW50IGFuZCB2YWxpZGF0aW5n - IHRoZSBjbHVzdGVyX2lkICd7cmd3X2ZzaWR9JyBpcyBlcXVhbCB0byB0aGUgY2VwaCBjbHVzdGVy - IGZzaWQgJ3tmc2lkfSciCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICByZXR1cm4g - Ii0xIgoKICAgICAgICAjIGNoZWNrIGlmIHRoZSByZ3cgZW5kcG9pbnQgcG9vbCBleGlzdAogICAg - ICAgICMgb25seSB2YWxpZGF0ZSBpZiByZ3dfcG9vbF9wcmVmaXggaXMgcGFzc2VkIGVsc2UgaXQg - d2lsbCB0YWtlIGRlZmF1bHQgdmFsdWUgYW5kIHdlIGRvbid0IGNyZWF0ZSB0aGVzZSBkZWZhdWx0 - IHBvb2xzCiAgICAgICAgaWYgc2VsZi5fYXJnX3BhcnNlci5yZ3dfcG9vbF9wcmVmaXggIT0gImRl - ZmF1bHQiOgogICAgICAgICAgICByZ3dfcG9vbHNfdG9fdmFsaWRhdGUgPSBbCiAgICAgICAgICAg - ICAgICBmIntzZWxmLl9hcmdfcGFyc2VyLnJnd19wb29sX3ByZWZpeH0ucmd3Lm1ldGEiLAogICAg - ICAgICAgICAgICAgIi5yZ3cucm9vdCIsCiAgICAgICAgICAgICAgICBmIntzZWxmLl9hcmdfcGFy - c2VyLnJnd19wb29sX3ByZWZpeH0ucmd3LmNvbnRyb2wiLAogICAgICAgICAgICAgICAgZiJ7c2Vs - Zi5fYXJnX3BhcnNlci5yZ3dfcG9vbF9wcmVmaXh9LnJndy5sb2ciLAogICAgICAgICAgICBdCiAg - ICAgICAgICAgIGZvciBfcmd3X3Bvb2xfdG9fdmFsaWRhdGUgaW4gcmd3X3Bvb2xzX3RvX3ZhbGlk - YXRlOgogICAgICAgICAgICAgICAgaWYgbm90IHNlbGYuY2x1c3Rlci5wb29sX2V4aXN0cyhfcmd3 - X3Bvb2xfdG9fdmFsaWRhdGUpOgogICAgICAgICAgICAgICAgICAgIHN5cy5zdGRlcnIud3JpdGUo - CiAgICAgICAgICAgICAgICAgICAgICAgIGYiVGhlIHByb3ZpZGVkIHBvb2wsICd7X3Jnd19wb29s - X3RvX3ZhbGlkYXRlfScsIGRvZXMgbm90IGV4aXN0IgogICAgICAgICAgICAgICAgICAgICkKICAg - ICAgICAgICAgICAgICAgICByZXR1cm4gIi0xIgoKICAgICAgICByZXR1cm4gIiIKCiAgICBkZWYg - dmFsaWRhdGVfcmd3X211bHRpc2l0ZShzZWxmLCByZ3dfbXVsdGlzaXRlX2NvbmZpZ19uYW1lLCBy - Z3dfbXVsdGlzaXRlX2NvbmZpZyk6CiAgICAgICAgaWYgcmd3X211bHRpc2l0ZV9jb25maWcgIT0g - IiI6CiAgICAgICAgICAgIGNtZCA9IFsKICAgICAgICAgICAgICAgICJyYWRvc2d3LWFkbWluIiwK - ICAgICAgICAgICAgICAgIHJnd19tdWx0aXNpdGVfY29uZmlnLAogICAgICAgICAgICAgICAgImdl - dCIsCiAgICAgICAgICAgICAgICAiLS1yZ3ctIiArIHJnd19tdWx0aXNpdGVfY29uZmlnLAogICAg - ICAgICAgICAgICAgcmd3X211bHRpc2l0ZV9jb25maWdfbmFtZSwKICAgICAgICAgICAgXQogICAg - ICAgICAgICB0cnk6CiAgICAgICAgICAgICAgICBfID0gc3VicHJvY2Vzcy5jaGVja19vdXRwdXQo - Y21kLCBzdGRlcnI9c3VicHJvY2Vzcy5QSVBFKQogICAgICAgICAgICBleGNlcHQgc3VicHJvY2Vz - cy5DYWxsZWRQcm9jZXNzRXJyb3IgYXMgZXhlY0VycjoKICAgICAgICAgICAgICAgIGVycl9tc2cg - PSAoCiAgICAgICAgICAgICAgICAgICAgZiJmYWlsZWQgdG8gZXhlY3V0ZSBjb21tYW5kIHtjbWR9 - LiBPdXRwdXQ6IHtleGVjRXJyLm91dHB1dH0uICIKICAgICAgICAgICAgICAgICAgICBmIkNvZGU6 - IHtleGVjRXJyLnJldHVybmNvZGV9LiBFcnJvcjoge2V4ZWNFcnIuc3RkZXJyfSIKICAgICAgICAg - ICAgICAgICkKICAgICAgICAgICAgICAgIHN5cy5zdGRlcnIud3JpdGUoZXJyX21zZykKICAgICAg - ICAgICAgICAgIHJldHVybiAiLTEiCiAgICAgICAgcmV0dXJuICIiCgogICAgZGVmIGNvbnZlcnRf - Y29tbWFfc2VwYXJhdGVkX3RvX2FycmF5KHNlbGYsIHZhbHVlKToKICAgICAgICByZXR1cm4gdmFs - dWUuc3BsaXQoIiwiKQoKICAgIGRlZiByYWlzZV9leGNlcHRpb25faWZfYW55X3RvcG9sb2d5X2Zs - YWdfaXNfbWlzc2luZyhzZWxmKToKICAgICAgICBpZiAoCiAgICAgICAgICAgICgKICAgICAgICAg - ICAgICAgIHNlbGYuX2FyZ19wYXJzZXIudG9wb2xvZ3lfcG9vbHMgIT0gIiIKICAgICAgICAgICAg - ICAgIGFuZCAoCiAgICAgICAgICAgICAgICAgICAgc2VsZi5fYXJnX3BhcnNlci50b3BvbG9neV9m - YWlsdXJlX2RvbWFpbl9sYWJlbCA9PSAiIgogICAgICAgICAgICAgICAgICAgIG9yIHNlbGYuX2Fy - Z19wYXJzZXIudG9wb2xvZ3lfZmFpbHVyZV9kb21haW5fdmFsdWVzID09ICIiCiAgICAgICAgICAg - ICAgICApCiAgICAgICAgICAgICkKICAgICAgICAgICAgb3IgKAogICAgICAgICAgICAgICAgc2Vs - Zi5fYXJnX3BhcnNlci50b3BvbG9neV9mYWlsdXJlX2RvbWFpbl9sYWJlbCAhPSAiIgogICAgICAg - ICAgICAgICAgYW5kICgKICAgICAgICAgICAgICAgICAgICBzZWxmLl9hcmdfcGFyc2VyLnRvcG9s - b2d5X3Bvb2xzID09ICIiCiAgICAgICAgICAgICAgICAgICAgb3Igc2VsZi5fYXJnX3BhcnNlci50 - b3BvbG9neV9mYWlsdXJlX2RvbWFpbl92YWx1ZXMgPT0gIiIKICAgICAgICAgICAgICAgICkKICAg - ICAgICAgICAgKQogICAgICAgICAgICBvciAoCiAgICAgICAgICAgICAgICBzZWxmLl9hcmdfcGFy - c2VyLnRvcG9sb2d5X2ZhaWx1cmVfZG9tYWluX3ZhbHVlcyAhPSAiIgogICAgICAgICAgICAgICAg - YW5kICgKICAgICAgICAgICAgICAgICAgICBzZWxmLl9hcmdfcGFyc2VyLnRvcG9sb2d5X3Bvb2xz + LkNhbGxlZFByb2Nlc3NFcnJvciBhcyBleGVjRXJyOgogICAgICAgICAgICAjIGlmIHRoZSB1c2Vy + IGFscmVhZHkgZXhpc3RzLCB3ZSBqdXN0IHF1ZXJ5IGl0CiAgICAgICAgICAgIGlmIGV4ZWNFcnIu + cmV0dXJuY29kZSA9PSBlcnJuby5FRVhJU1Q6CiAgICAgICAgICAgICAgICBjbWQgPSBbCiAgICAg + ICAgICAgICAgICAgICAgInJhZG9zZ3ctYWRtaW4iLAogICAgICAgICAgICAgICAgICAgICJ1c2Vy + IiwKICAgICAgICAgICAgICAgICAgICAiaW5mbyIsCiAgICAgICAgICAgICAgICAgICAgIi0tdWlk + IiwKICAgICAgICAgICAgICAgICAgICBzZWxmLkVYVEVSTkFMX1JHV19BRE1JTl9PUFNfVVNFUl9O + QU1FLAogICAgICAgICAgICAgICAgICAgICItLXJndy1yZWFsbSIsCiAgICAgICAgICAgICAgICAg + ICAgc2VsZi5fYXJnX3BhcnNlci5yZ3dfcmVhbG1fbmFtZSwKICAgICAgICAgICAgICAgICAgICAi + LS1yZ3ctem9uZWdyb3VwIiwKICAgICAgICAgICAgICAgICAgICBzZWxmLl9hcmdfcGFyc2VyLnJn + d196b25lZ3JvdXBfbmFtZSwKICAgICAgICAgICAgICAgICAgICAiLS1yZ3ctem9uZSIsCiAgICAg + ICAgICAgICAgICAgICAgc2VsZi5fYXJnX3BhcnNlci5yZ3dfem9uZV9uYW1lLAogICAgICAgICAg + ICAgICAgXQogICAgICAgICAgICAgICAgdHJ5OgogICAgICAgICAgICAgICAgICAgIG91dHB1dCA9 + IHN1YnByb2Nlc3MuY2hlY2tfb3V0cHV0KGNtZCwgc3RkZXJyPXN1YnByb2Nlc3MuUElQRSkKICAg + ICAgICAgICAgICAgIGV4Y2VwdCBzdWJwcm9jZXNzLkNhbGxlZFByb2Nlc3NFcnJvciBhcyBleGVj + RXJyOgogICAgICAgICAgICAgICAgICAgIGVycl9tc2cgPSAoCiAgICAgICAgICAgICAgICAgICAg + ICAgIGYiZmFpbGVkIHRvIGV4ZWN1dGUgY29tbWFuZCB7Y21kfS4gT3V0cHV0OiB7ZXhlY0Vyci5v + dXRwdXR9LiAiCiAgICAgICAgICAgICAgICAgICAgICAgIGYiQ29kZToge2V4ZWNFcnIucmV0dXJu + Y29kZX0uIEVycm9yOiB7ZXhlY0Vyci5zdGRlcnJ9IgogICAgICAgICAgICAgICAgICAgICkKICAg + ICAgICAgICAgICAgICAgICBzeXMuc3RkZXJyLndyaXRlKGVycl9tc2cpCiAgICAgICAgICAgICAg + ICAgICAgcmV0dXJuIE5vbmUsIE5vbmUsIEZhbHNlLCAiLTEiCiAgICAgICAgICAgIGVsc2U6CiAg + ICAgICAgICAgICAgICBlcnJfbXNnID0gKAogICAgICAgICAgICAgICAgICAgIGYiZmFpbGVkIHRv + IGV4ZWN1dGUgY29tbWFuZCB7Y21kfS4gT3V0cHV0OiB7ZXhlY0Vyci5vdXRwdXR9LiAiCiAgICAg + ICAgICAgICAgICAgICAgZiJDb2RlOiB7ZXhlY0Vyci5yZXR1cm5jb2RlfS4gRXJyb3I6IHtleGVj + RXJyLnN0ZGVycn0iCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICBzeXMuc3RkZXJy + LndyaXRlKGVycl9tc2cpCiAgICAgICAgICAgICAgICByZXR1cm4gTm9uZSwgTm9uZSwgRmFsc2Us + ICItMSIKCiAgICAgICAgIyBzZXBhcmF0ZWx5IGFkZCBpbmZvPXJlYWQgY2FwcyBmb3Igcmd3LWVu + ZHBvaW50IGlwIHZhbGlkYXRpb24KICAgICAgICBpbmZvX2NhcF9zdXBwb3J0ZWQgPSBUcnVlCiAg + ICAgICAgY21kID0gWwogICAgICAgICAgICAicmFkb3Nndy1hZG1pbiIsCiAgICAgICAgICAgICJj + YXBzIiwKICAgICAgICAgICAgImFkZCIsCiAgICAgICAgICAgICItLXVpZCIsCiAgICAgICAgICAg + IHNlbGYuRVhURVJOQUxfUkdXX0FETUlOX09QU19VU0VSX05BTUUsCiAgICAgICAgICAgICItLWNh + cHMiLAogICAgICAgICAgICAiaW5mbz1yZWFkIiwKICAgICAgICAgICAgIi0tcmd3LXJlYWxtIiwK + ICAgICAgICAgICAgc2VsZi5fYXJnX3BhcnNlci5yZ3dfcmVhbG1fbmFtZSwKICAgICAgICAgICAg + Ii0tcmd3LXpvbmVncm91cCIsCiAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIucmd3X3pvbmVn + cm91cF9uYW1lLAogICAgICAgICAgICAiLS1yZ3ctem9uZSIsCiAgICAgICAgICAgIHNlbGYuX2Fy + Z19wYXJzZXIucmd3X3pvbmVfbmFtZSwKICAgICAgICBdCiAgICAgICAgdHJ5OgogICAgICAgICAg + ICBvdXRwdXQgPSBzdWJwcm9jZXNzLmNoZWNrX291dHB1dChjbWQsIHN0ZGVycj1zdWJwcm9jZXNz + LlBJUEUpCiAgICAgICAgZXhjZXB0IHN1YnByb2Nlc3MuQ2FsbGVkUHJvY2Vzc0Vycm9yIGFzIGV4 + ZWNFcnI6CiAgICAgICAgICAgICMgaWYgdGhlIGNlcGggdmVyc2lvbiBub3Qgc3VwcG9ydGVkIGZv + ciBhZGRpbmcgYGluZm89cmVhZGAgY2FwKHJnd192YWxpZGF0aW9uKQogICAgICAgICAgICBpZiAo + CiAgICAgICAgICAgICAgICAiY291bGQgbm90IGFkZCBjYXBzOiB1bmFibGUgdG8gYWRkIGNhcHM6 + IGluZm89cmVhZFxuIgogICAgICAgICAgICAgICAgaW4gZXhlY0Vyci5zdGRlcnIuZGVjb2RlKCJ1 + dGYtOCIpCiAgICAgICAgICAgICAgICBhbmQgZXhlY0Vyci5yZXR1cm5jb2RlID09IDI0NAogICAg + ICAgICAgICApOgogICAgICAgICAgICAgICAgaW5mb19jYXBfc3VwcG9ydGVkID0gRmFsc2UKICAg + ICAgICAgICAgZWxzZToKICAgICAgICAgICAgICAgIGVycl9tc2cgPSAoCiAgICAgICAgICAgICAg + ICAgICAgZiJmYWlsZWQgdG8gZXhlY3V0ZSBjb21tYW5kIHtjbWR9LiBPdXRwdXQ6IHtleGVjRXJy + Lm91dHB1dH0uICIKICAgICAgICAgICAgICAgICAgICBmIkNvZGU6IHtleGVjRXJyLnJldHVybmNv + ZGV9LiBFcnJvcjoge2V4ZWNFcnIuc3RkZXJyfSIKICAgICAgICAgICAgICAgICkKICAgICAgICAg + ICAgICAgIHN5cy5zdGRlcnIud3JpdGUoZXJyX21zZykKICAgICAgICAgICAgICAgIHJldHVybiBO + b25lLCBOb25lLCBGYWxzZSwgIi0xIgoKICAgICAgICBqc29ub3V0cHV0ID0ganNvbi5sb2Fkcyhv + dXRwdXQpCiAgICAgICAgcmV0dXJuICgKICAgICAgICAgICAganNvbm91dHB1dFsia2V5cyJdWzBd + WyJhY2Nlc3Nfa2V5Il0sCiAgICAgICAgICAgIGpzb25vdXRwdXRbImtleXMiXVswXVsic2VjcmV0 + X2tleSJdLAogICAgICAgICAgICBpbmZvX2NhcF9zdXBwb3J0ZWQsCiAgICAgICAgICAgICIiLAog + ICAgICAgICkKCiAgICBkZWYgdmFsaWRhdGVfcmJkX3Bvb2woc2VsZiwgcG9vbF9uYW1lKToKICAg + ICAgICBpZiBub3Qgc2VsZi5jbHVzdGVyLnBvb2xfZXhpc3RzKHBvb2xfbmFtZSk6CiAgICAgICAg + ICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1cmVFeGNlcHRpb24oCiAgICAgICAgICAgICAgICBmIlRo + ZSBwcm92aWRlZCBwb29sLCAne3Bvb2xfbmFtZX0nLCBkb2VzIG5vdCBleGlzdCIKICAgICAgICAg + ICAgKQoKICAgIGRlZiBpbml0X3JiZF9wb29sKHNlbGYsIHJiZF9wb29sX25hbWUpOgogICAgICAg + IGlmIGlzaW5zdGFuY2Uoc2VsZi5jbHVzdGVyLCBEdW1teVJhZG9zKToKICAgICAgICAgICAgcmV0 + dXJuCiAgICAgICAgaW9jdHggPSBzZWxmLmNsdXN0ZXIub3Blbl9pb2N0eChyYmRfcG9vbF9uYW1l + KQogICAgICAgIHJiZF9pbnN0ID0gcmJkLlJCRCgpCiAgICAgICAgcmJkX2luc3QucG9vbF9pbml0 + KGlvY3R4LCBUcnVlKQoKICAgIGRlZiB2YWxpZGF0ZV9yYWRvc19uYW1lc3BhY2Uoc2VsZik6CiAg + ICAgICAgcmJkX3Bvb2xfbmFtZSA9IHNlbGYuX2FyZ19wYXJzZXIucmJkX2RhdGFfcG9vbF9uYW1l + CiAgICAgICAgaWYgc2VsZi5fYXJnX3BhcnNlci5yYmRfbWV0YWRhdGFfZWNfcG9vbF9uYW1lOgog + ICAgICAgICAgICByYmRfcG9vbF9uYW1lID0gc2VsZi5fYXJnX3BhcnNlci5yYmRfbWV0YWRhdGFf + ZWNfcG9vbF9uYW1lCiAgICAgICAgcmFkb3NfbmFtZXNwYWNlID0gc2VsZi5fYXJnX3BhcnNlci5y + YWRvc19uYW1lc3BhY2UKICAgICAgICBpZiByYWRvc19uYW1lc3BhY2UgPT0gIiI6CiAgICAgICAg + ICAgIHJldHVybgogICAgICAgIGlmIHJhZG9zX25hbWVzcGFjZS5pc2xvd2VyKCkgPT0gRmFsc2U6 + CiAgICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1cmVFeGNlcHRpb24oCiAgICAgICAgICAg + ICAgICBmIlRoZSBwcm92aWRlZCByYWRvcyBOYW1lc3BhY2UsICd7cmFkb3NfbmFtZXNwYWNlfScs + ICIKICAgICAgICAgICAgICAgIGYiY29udGFpbnMgdXBwZXIgY2FzZSIKICAgICAgICAgICAgKQog + ICAgICAgIHJiZF9pbnN0ID0gcmJkLlJCRCgpCiAgICAgICAgaW9jdHggPSBzZWxmLmNsdXN0ZXIu + b3Blbl9pb2N0eChyYmRfcG9vbF9uYW1lKQogICAgICAgIGlmIHJiZF9pbnN0Lm5hbWVzcGFjZV9l + eGlzdHMoaW9jdHgsIHJhZG9zX25hbWVzcGFjZSkgaXMgRmFsc2U6CiAgICAgICAgICAgIHJhaXNl + IEV4ZWN1dGlvbkZhaWx1cmVFeGNlcHRpb24oCiAgICAgICAgICAgICAgICBmIlRoZSBwcm92aWRl + ZCByYWRvcyBOYW1lc3BhY2UsICd7cmFkb3NfbmFtZXNwYWNlfScsICIKICAgICAgICAgICAgICAg + IGYiaXMgbm90IGZvdW5kIGluIHRoZSBwb29sICd7cmJkX3Bvb2xfbmFtZX0nIgogICAgICAgICAg + ICApCgogICAgZGVmIGdldF9vcl9jcmVhdGVfc3Vidm9sdW1lX2dyb3VwKHNlbGYsIHN1YnZvbHVt + ZV9ncm91cCwgY2VwaGZzX2ZpbGVzeXN0ZW1fbmFtZSk6CiAgICAgICAgY21kID0gWwogICAgICAg + ICAgICAiY2VwaCIsCiAgICAgICAgICAgICJmcyIsCiAgICAgICAgICAgICJzdWJ2b2x1bWVncm91 + cCIsCiAgICAgICAgICAgICJnZXRwYXRoIiwKICAgICAgICAgICAgY2VwaGZzX2ZpbGVzeXN0ZW1f + bmFtZSwKICAgICAgICAgICAgc3Vidm9sdW1lX2dyb3VwLAogICAgICAgIF0KICAgICAgICB0cnk6 + CiAgICAgICAgICAgIF8gPSBzdWJwcm9jZXNzLmNoZWNrX291dHB1dChjbWQsIHN0ZGVycj1zdWJw + cm9jZXNzLlBJUEUpCiAgICAgICAgZXhjZXB0IHN1YnByb2Nlc3MuQ2FsbGVkUHJvY2Vzc0Vycm9y + OgogICAgICAgICAgICBjbWQgPSBbCiAgICAgICAgICAgICAgICAiY2VwaCIsCiAgICAgICAgICAg + ICAgICAiZnMiLAogICAgICAgICAgICAgICAgInN1YnZvbHVtZWdyb3VwIiwKICAgICAgICAgICAg + ICAgICJjcmVhdGUiLAogICAgICAgICAgICAgICAgY2VwaGZzX2ZpbGVzeXN0ZW1fbmFtZSwKICAg + ICAgICAgICAgICAgIHN1YnZvbHVtZV9ncm91cCwKICAgICAgICAgICAgXQogICAgICAgICAgICB0 + cnk6CiAgICAgICAgICAgICAgICBfID0gc3VicHJvY2Vzcy5jaGVja19vdXRwdXQoY21kLCBzdGRl + cnI9c3VicHJvY2Vzcy5QSVBFKQogICAgICAgICAgICBleGNlcHQgc3VicHJvY2Vzcy5DYWxsZWRQ + cm9jZXNzRXJyb3I6CiAgICAgICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWlsdXJlRXhjZXB0 + aW9uKAogICAgICAgICAgICAgICAgICAgIGYic3Vidm9sdW1lIGdyb3VwIHtzdWJ2b2x1bWVfZ3Jv + dXB9IGlzIG5vdCBhYmxlIHRvIGdldCBjcmVhdGVkIgogICAgICAgICAgICAgICAgKQoKICAgIGRl + ZiBwaW5fc3Vidm9sdW1lKAogICAgICAgIHNlbGYsIHN1YnZvbHVtZV9ncm91cCwgY2VwaGZzX2Zp + bGVzeXN0ZW1fbmFtZSwgcGluX3R5cGUsIHBpbl9zZXR0aW5nCiAgICApOgogICAgICAgIGNtZCA9 + IFsKICAgICAgICAgICAgImNlcGgiLAogICAgICAgICAgICAiZnMiLAogICAgICAgICAgICAic3Vi + dm9sdW1lZ3JvdXAiLAogICAgICAgICAgICAicGluIiwKICAgICAgICAgICAgY2VwaGZzX2ZpbGVz + eXN0ZW1fbmFtZSwKICAgICAgICAgICAgc3Vidm9sdW1lX2dyb3VwLAogICAgICAgICAgICBwaW5f + dHlwZSwKICAgICAgICAgICAgcGluX3NldHRpbmcsCiAgICAgICAgXQogICAgICAgIHRyeToKICAg + ICAgICAgICAgXyA9IHN1YnByb2Nlc3MuY2hlY2tfb3V0cHV0KGNtZCwgc3RkZXJyPXN1YnByb2Nl + c3MuUElQRSkKICAgICAgICBleGNlcHQgc3VicHJvY2Vzcy5DYWxsZWRQcm9jZXNzRXJyb3I6CiAg + ICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1cmVFeGNlcHRpb24oCiAgICAgICAgICAgICAg + ICBmInN1YnZvbHVtZSBncm91cCB7c3Vidm9sdW1lX2dyb3VwfSBpcyBub3QgYWJsZSB0byBnZXQg + cGlubmVkIgogICAgICAgICAgICApCgogICAgZGVmIGdldF9yZ3dfZnNpZChzZWxmLCBiYXNlX3Vy + bCwgdmVyaWZ5KToKICAgICAgICBhY2Nlc3Nfa2V5ID0gc2VsZi5vdXRfbWFwWyJSR1dfQURNSU5f + T1BTX1VTRVJfQUNDRVNTX0tFWSJdCiAgICAgICAgc2VjcmV0X2tleSA9IHNlbGYub3V0X21hcFsi + UkdXX0FETUlOX09QU19VU0VSX1NFQ1JFVF9LRVkiXQogICAgICAgIHJnd19lbmRwb2ludCA9IHNl + bGYuX2FyZ19wYXJzZXIucmd3X2VuZHBvaW50CiAgICAgICAgYmFzZV91cmwgPSBiYXNlX3VybCAr + ICI6Ly8iICsgcmd3X2VuZHBvaW50ICsgIi9hZG1pbi9pbmZvPyIKICAgICAgICBwYXJhbXMgPSB7 + ImZvcm1hdCI6ICJqc29uIn0KICAgICAgICByZXF1ZXN0X3VybCA9IGJhc2VfdXJsICsgdXJsZW5j + b2RlKHBhcmFtcykKCiAgICAgICAgdHJ5OgogICAgICAgICAgICByID0gcmVxdWVzdHMuZ2V0KAog + ICAgICAgICAgICAgICAgcmVxdWVzdF91cmwsCiAgICAgICAgICAgICAgICBhdXRoPVMzQXV0aChh + Y2Nlc3Nfa2V5LCBzZWNyZXRfa2V5LCByZ3dfZW5kcG9pbnQpLAogICAgICAgICAgICAgICAgdmVy + aWZ5PXZlcmlmeSwKICAgICAgICAgICAgKQogICAgICAgIGV4Y2VwdCByZXF1ZXN0cy5leGNlcHRp + b25zLlRpbWVvdXQ6CiAgICAgICAgICAgIHN5cy5zdGRlcnIud3JpdGUoCiAgICAgICAgICAgICAg + ICBmImludmFsaWQgZW5kcG9pbnQ6LCBub3QgYWJsZSB0byBjYWxsIGFkbWluLW9wcyBhcGl7cmd3 + X2VuZHBvaW50fSIKICAgICAgICAgICAgKQogICAgICAgICAgICByZXR1cm4gIiIsICItMSIKICAg + ICAgICByMSA9IHIuanNvbigpCiAgICAgICAgaWYgcjEgaXMgTm9uZSBvciByMS5nZXQoImluZm8i + KSBpcyBOb25lOgogICAgICAgICAgICBzeXMuc3RkZXJyLndyaXRlKAogICAgICAgICAgICAgICAg + ZiJUaGUgcHJvdmlkZWQgcmd3IEVuZHBvaW50LCAne3NlbGYuX2FyZ19wYXJzZXIucmd3X2VuZHBv + aW50fScsIGlzIGludmFsaWQuIgogICAgICAgICAgICApCiAgICAgICAgICAgIHJldHVybiAoCiAg + ICAgICAgICAgICAgICAiIiwKICAgICAgICAgICAgICAgICItMSIsCiAgICAgICAgICAgICkKCiAg + ICAgICAgcmV0dXJuIHIxWyJpbmZvIl1bInN0b3JhZ2VfYmFja2VuZHMiXVswXVsiY2x1c3Rlcl9p + ZCJdLCAiIgoKICAgIGRlZiB2YWxpZGF0ZV9yZ3dfZW5kcG9pbnQoc2VsZiwgaW5mb19jYXBfc3Vw + cG9ydGVkKToKICAgICAgICAjIGlmIHRoZSAnY2x1c3RlcicgaW5zdGFuY2UgaXMgYSBkdW1teSBv + bmUsCiAgICAgICAgIyBkb24ndCB0cnkgdG8gcmVhY2ggb3V0IHRvIHRoZSBlbmRwb2ludAogICAg + ICAgIGlmIGlzaW5zdGFuY2Uoc2VsZi5jbHVzdGVyLCBEdW1teVJhZG9zKToKICAgICAgICAgICAg + cmV0dXJuCgogICAgICAgIHJnd19lbmRwb2ludCA9IHNlbGYuX2FyZ19wYXJzZXIucmd3X2VuZHBv + aW50CgogICAgICAgICMgdmFsaWRhdGUgcmd3IGVuZHBvaW50IG9ubHkgaWYgaXAgYWRkcmVzcyBp + cyBwYXNzZWQKICAgICAgICBpcF90eXBlID0gc2VsZi5faW52YWxpZF9lbmRwb2ludChyZ3dfZW5k + cG9pbnQpCgogICAgICAgICMgY2hlY2sgaWYgdGhlIHJndyBlbmRwb2ludCBpcyByZWFjaGFibGUK + ICAgICAgICBjZXJ0ID0gTm9uZQogICAgICAgIGlmIG5vdCBzZWxmLl9hcmdfcGFyc2VyLnJnd19z + a2lwX3RscyBhbmQgc2VsZi52YWxpZGF0ZV9yZ3dfZW5kcG9pbnRfdGxzX2NlcnQoKToKICAgICAg + ICAgICAgY2VydCA9IHNlbGYuX2FyZ19wYXJzZXIucmd3X3Rsc19jZXJ0X3BhdGgKICAgICAgICBi + YXNlX3VybCwgdmVyaWZ5LCBlcnIgPSBzZWxmLmVuZHBvaW50X2RpYWwocmd3X2VuZHBvaW50LCBp + cF90eXBlLCBjZXJ0PWNlcnQpCiAgICAgICAgaWYgZXJyICE9ICIiOgogICAgICAgICAgICByZXR1 + cm4gIi0xIgoKICAgICAgICAjIGNoZWNrIGlmIHRoZSByZ3cgZW5kcG9pbnQgYmVsb25ncyB0byB0 + aGUgc2FtZSBjbHVzdGVyCiAgICAgICAgIyBvbmx5IGNoZWNrIGlmIGBpbmZvYCBjYXAgaXMgc3Vw + cG9ydGVkCiAgICAgICAgaWYgaW5mb19jYXBfc3VwcG9ydGVkOgogICAgICAgICAgICBmc2lkID0g + c2VsZi5nZXRfZnNpZCgpCiAgICAgICAgICAgIHJnd19mc2lkLCBlcnIgPSBzZWxmLmdldF9yZ3df + ZnNpZChiYXNlX3VybCwgdmVyaWZ5KQogICAgICAgICAgICBpZiBlcnIgPT0gIi0xIjoKICAgICAg + ICAgICAgICAgIHJldHVybiAiLTEiCiAgICAgICAgICAgIGlmIGZzaWQgIT0gcmd3X2ZzaWQ6CiAg + ICAgICAgICAgICAgICBzeXMuc3RkZXJyLndyaXRlKAogICAgICAgICAgICAgICAgICAgIGYiVGhl + IHByb3ZpZGVkIHJndyBFbmRwb2ludCwgJ3tzZWxmLl9hcmdfcGFyc2VyLnJnd19lbmRwb2ludH0n + LCBpcyBpbnZhbGlkLiBXZSBhcmUgdmFsaWRhdGluZyBieSBjYWxsaW5nIHRoZSBhZG1pbm9wcyBh + cGkgdGhyb3VnaCByZ3ctZW5kcG9pbnQgYW5kIHZhbGlkYXRpbmcgdGhlIGNsdXN0ZXJfaWQgJ3ty + Z3dfZnNpZH0nIGlzIGVxdWFsIHRvIHRoZSBjZXBoIGNsdXN0ZXIgZnNpZCAne2ZzaWR9JyIKICAg + ICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIHJldHVybiAiLTEiCgogICAgICAgICMgY2hl + Y2sgaWYgdGhlIHJndyBlbmRwb2ludCBwb29sIGV4aXN0CiAgICAgICAgIyBvbmx5IHZhbGlkYXRl + IGlmIHJnd19wb29sX3ByZWZpeCBpcyBwYXNzZWQgZWxzZSBpdCB3aWxsIHRha2UgZGVmYXVsdCB2 + YWx1ZSBhbmQgd2UgZG9uJ3QgY3JlYXRlIHRoZXNlIGRlZmF1bHQgcG9vbHMKICAgICAgICBpZiBz + ZWxmLl9hcmdfcGFyc2VyLnJnd19wb29sX3ByZWZpeCAhPSAiZGVmYXVsdCI6CiAgICAgICAgICAg + IHJnd19wb29sc190b192YWxpZGF0ZSA9IFsKICAgICAgICAgICAgICAgIGYie3NlbGYuX2FyZ19w + YXJzZXIucmd3X3Bvb2xfcHJlZml4fS5yZ3cubWV0YSIsCiAgICAgICAgICAgICAgICAiLnJndy5y + b290IiwKICAgICAgICAgICAgICAgIGYie3NlbGYuX2FyZ19wYXJzZXIucmd3X3Bvb2xfcHJlZml4 + fS5yZ3cuY29udHJvbCIsCiAgICAgICAgICAgICAgICBmIntzZWxmLl9hcmdfcGFyc2VyLnJnd19w + b29sX3ByZWZpeH0ucmd3LmxvZyIsCiAgICAgICAgICAgIF0KICAgICAgICAgICAgZm9yIF9yZ3df + cG9vbF90b192YWxpZGF0ZSBpbiByZ3dfcG9vbHNfdG9fdmFsaWRhdGU6CiAgICAgICAgICAgICAg + ICBpZiBub3Qgc2VsZi5jbHVzdGVyLnBvb2xfZXhpc3RzKF9yZ3dfcG9vbF90b192YWxpZGF0ZSk6 + CiAgICAgICAgICAgICAgICAgICAgc3lzLnN0ZGVyci53cml0ZSgKICAgICAgICAgICAgICAgICAg + ICAgICAgZiJUaGUgcHJvdmlkZWQgcG9vbCwgJ3tfcmd3X3Bvb2xfdG9fdmFsaWRhdGV9JywgZG9l + cyBub3QgZXhpc3QiCiAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgIHJl + dHVybiAiLTEiCgogICAgICAgIHJldHVybiAiIgoKICAgIGRlZiB2YWxpZGF0ZV9yZ3dfbXVsdGlz + aXRlKHNlbGYsIHJnd19tdWx0aXNpdGVfY29uZmlnX25hbWUsIHJnd19tdWx0aXNpdGVfY29uZmln + KToKICAgICAgICBpZiByZ3dfbXVsdGlzaXRlX2NvbmZpZyAhPSAiIjoKICAgICAgICAgICAgY21k + ID0gWwogICAgICAgICAgICAgICAgInJhZG9zZ3ctYWRtaW4iLAogICAgICAgICAgICAgICAgcmd3 + X211bHRpc2l0ZV9jb25maWcsCiAgICAgICAgICAgICAgICAiZ2V0IiwKICAgICAgICAgICAgICAg + ICItLXJndy0iICsgcmd3X211bHRpc2l0ZV9jb25maWcsCiAgICAgICAgICAgICAgICByZ3dfbXVs + dGlzaXRlX2NvbmZpZ19uYW1lLAogICAgICAgICAgICBdCiAgICAgICAgICAgIHRyeToKICAgICAg + ICAgICAgICAgIF8gPSBzdWJwcm9jZXNzLmNoZWNrX291dHB1dChjbWQsIHN0ZGVycj1zdWJwcm9j + ZXNzLlBJUEUpCiAgICAgICAgICAgIGV4Y2VwdCBzdWJwcm9jZXNzLkNhbGxlZFByb2Nlc3NFcnJv + ciBhcyBleGVjRXJyOgogICAgICAgICAgICAgICAgZXJyX21zZyA9ICgKICAgICAgICAgICAgICAg + ICAgICBmImZhaWxlZCB0byBleGVjdXRlIGNvbW1hbmQge2NtZH0uIE91dHB1dDoge2V4ZWNFcnIu + b3V0cHV0fS4gIgogICAgICAgICAgICAgICAgICAgIGYiQ29kZToge2V4ZWNFcnIucmV0dXJuY29k + ZX0uIEVycm9yOiB7ZXhlY0Vyci5zdGRlcnJ9IgogICAgICAgICAgICAgICAgKQogICAgICAgICAg + ICAgICAgc3lzLnN0ZGVyci53cml0ZShlcnJfbXNnKQogICAgICAgICAgICAgICAgcmV0dXJuICIt + MSIKICAgICAgICByZXR1cm4gIiIKCiAgICBkZWYgY29udmVydF9jb21tYV9zZXBhcmF0ZWRfdG9f + YXJyYXkoc2VsZiwgdmFsdWUpOgogICAgICAgIHJldHVybiB2YWx1ZS5zcGxpdCgiLCIpCgogICAg + ZGVmIHJhaXNlX2V4Y2VwdGlvbl9pZl9hbnlfdG9wb2xvZ3lfZmxhZ19pc19taXNzaW5nKHNlbGYp + OgogICAgICAgIGlmICgKICAgICAgICAgICAgKAogICAgICAgICAgICAgICAgc2VsZi5fYXJnX3Bh + cnNlci50b3BvbG9neV9wb29scyAhPSAiIgogICAgICAgICAgICAgICAgYW5kICgKICAgICAgICAg + ICAgICAgICAgICBzZWxmLl9hcmdfcGFyc2VyLnRvcG9sb2d5X2ZhaWx1cmVfZG9tYWluX2xhYmVs ID09ICIiCiAgICAgICAgICAgICAgICAgICAgb3Igc2VsZi5fYXJnX3BhcnNlci50b3BvbG9neV9m - YWlsdXJlX2RvbWFpbl9sYWJlbCA9PSAiIgogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAp - CiAgICAgICAgKToKICAgICAgICAgICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlvbigK - ICAgICAgICAgICAgICAgICJwcm92aWRlIGFsbCB0aGUgdG9wb2xvZ3kgZmxhZ3MgLS10b3BvbG9n - eS1wb29scywgLS10b3BvbG9neS1mYWlsdXJlLWRvbWFpbi1sYWJlbCwgLS10b3BvbG9neS1mYWls - dXJlLWRvbWFpbi12YWx1ZXMiCiAgICAgICAgICAgICkKCiAgICBkZWYgdmFsaWRhdGVfdG9wb2xv - Z3lfdmFsdWVzKHNlbGYsIHRvcG9sb2d5X3Bvb2xzLCB0b3BvbG9neV9mZCk6CiAgICAgICAgaWYg - bGVuKHRvcG9sb2d5X3Bvb2xzKSAhPSBsZW4odG9wb2xvZ3lfZmQpOgogICAgICAgICAgICByYWlz - ZSBFeGVjdXRpb25GYWlsdXJlRXhjZXB0aW9uKAogICAgICAgICAgICAgICAgZiJUaGUgcHJvdmlk - ZWQgdG9wb2xvZ3kgcG9vbHMsICd7dG9wb2xvZ3lfcG9vbHN9JywgYW5kICIKICAgICAgICAgICAg - ICAgIGYidG9wb2xvZ3kgZmFpbHVyZSBkb21haW4sICd7dG9wb2xvZ3lfZmR9JywiCiAgICAgICAg - ICAgICAgICBmImFyZSBvZiBkaWZmZXJlbnQgbGVuZ3RoLCAne2xlbih0b3BvbG9neV9wb29scyl9 - JyBhbmQgJ3tsZW4odG9wb2xvZ3lfZmQpfScgcmVzcGN0aXZlbHkiCiAgICAgICAgICAgICkKICAg - ICAgICByZXR1cm4KCiAgICBkZWYgdmFsaWRhdGVfdG9wb2xvZ3lfcmJkX3Bvb2xzKHNlbGYsIHRv - cG9sb2d5X3JiZF9wb29scyk6CiAgICAgICAgZm9yIHBvb2wgaW4gdG9wb2xvZ3lfcmJkX3Bvb2xz - OgogICAgICAgICAgICBzZWxmLnZhbGlkYXRlX3JiZF9wb29sKHBvb2wpCgogICAgZGVmIGluaXRf - dG9wb2xvZ3lfcmJkX3Bvb2xzKHNlbGYsIHRvcG9sb2d5X3JiZF9wb29scyk6CiAgICAgICAgZm9y - IHBvb2wgaW4gdG9wb2xvZ3lfcmJkX3Bvb2xzOgogICAgICAgICAgICBzZWxmLmluaXRfcmJkX3Bv - b2wocG9vbCkKCiAgICAjIHRoaXMgd2lsbCByZXR1cm4gdGhlIGZpbmFsIGFyZ3MgdGhhdCBzY3Jp - cHQgdXNlcyB0byBwcm9jZXNzCiAgICAjIHRoZSBwcmlvcml0eSB0byBzZXQgYSBwYXJ0aWN1bGFy - IHZhbHVlIGlzLAogICAgIyBjb21tYW5kLWxpbmUtYXJncyA+IGNvbmZpZy5pbmkgZmlsZSB2YWx1 - ZXMgPiBkZWZhdWx0IHZhbHVlcwogICAgZGVmIGdldEZpbmFsVXNlZEFyZ3Moc2VsZik6CiAgICAg - ICAgYXJndW1lbnQgPSBmIltDb25maWd1cmF0aW9uc11cbiIKICAgICAgICBmb3IgYXJnIGluIHZh - cnMoc2VsZi5fYXJnX3BhcnNlcik6CiAgICAgICAgICAgIGlmIHN0cihnZXRhdHRyKHNlbGYuX2Fy - Z19wYXJzZXIsIGFyZykpOgogICAgICAgICAgICAgICAgIyBweXRob24gdHJlYXRzIGZsYWctbmFt - ZSBhcyBmbGFnX25hbWUgaW50ZXJuYWxseSwgc28gY29udmVydGluZyBiYWNrIHRvIGZsYWctbmFt - ZSwKICAgICAgICAgICAgICAgICMgc28gd2UgY2FuIGdldCB0aG9zZSB2YWx1ZXMgZnJvbSBjb25m - aWcgZmlsZQogICAgICAgICAgICAgICAgYXJnVmFsdWUgPSBhcmcucmVwbGFjZSgiXyIsICItIikK - ICAgICAgICAgICAgICAgICMgZG8gbm90IGFkZCB0aGUgY29uZmlnLWZpbGUgZmxhZyBhbmQgYWxz - byBub3QgYWRkIHRoZSBib29sZWFuIGZsYWdzIHdoaWNoIGFyZSBzZXQgdG8gRmFsc2UKICAgICAg - ICAgICAgICAgICMgYmVjYXVzZSBjb25maWcuaW5pIGZpbGUgdHJlYXRzIGJvb2xlYW4gZmxhZ3Mg - YXMgVHJ1ZSBhbHdheXMKICAgICAgICAgICAgICAgIGlmICgKICAgICAgICAgICAgICAgICAgICBh - cmdWYWx1ZSAhPSAiY29uZmlnLWZpbGUiCiAgICAgICAgICAgICAgICAgICAgYW5kIGdldGF0dHIo - c2VsZi5fYXJnX3BhcnNlciwgYXJnKSAhPSBGYWxzZQogICAgICAgICAgICAgICAgKToKICAgICAg - ICAgICAgICAgICAgICBhcmd1bWVudCArPSBmInthcmdWYWx1ZX0gPSB7c3RyKGdldGF0dHIoc2Vs - Zi5fYXJnX3BhcnNlciwgYXJnKSl9XG4iCiAgICAgICAgcmV0dXJuIGFyZ3VtZW50CgogICAgZGVm - IF9nZW5fb3V0cHV0X21hcChzZWxmKToKICAgICAgICBpZiBzZWxmLm91dF9tYXA6CiAgICAgICAg - ICAgIHJldHVybgogICAgICAgICMgc3VwcG9ydCBsZWdhY3kgZmxhZyB3aXRoIHVwZ3JhZGVzCiAg - ICAgICAgaWYgc2VsZi5fYXJnX3BhcnNlci5jbHVzdGVyX25hbWU6CiAgICAgICAgICAgIHNlbGYu - X2FyZ19wYXJzZXIuazhzX2NsdXN0ZXJfbmFtZSA9IHNlbGYuX2FyZ19wYXJzZXIuY2x1c3Rlcl9u - YW1lCiAgICAgICAgc2VsZi5fYXJnX3BhcnNlci5rOHNfY2x1c3Rlcl9uYW1lID0gKAogICAgICAg - ICAgICBzZWxmLl9hcmdfcGFyc2VyLms4c19jbHVzdGVyX25hbWUubG93ZXIoKQogICAgICAgICkg - ICMgYWx3YXlzIGNvbnZlcnQgY2x1c3RlciBuYW1lIHRvIGxvd2VyY2FzZSBjaGFyYWN0ZXJzCiAg - ICAgICAgc2VsZi52YWxpZGF0ZV9yYmRfcG9vbChzZWxmLl9hcmdfcGFyc2VyLnJiZF9kYXRhX3Bv - b2xfbmFtZSkKICAgICAgICBzZWxmLmluaXRfcmJkX3Bvb2woc2VsZi5fYXJnX3BhcnNlci5yYmRf - ZGF0YV9wb29sX25hbWUpCiAgICAgICAgc2VsZi52YWxpZGF0ZV9yYWRvc19uYW1lc3BhY2UoKQog - ICAgICAgIHNlbGYuX2V4Y2x1ZGVkX2tleXMuYWRkKCJLOFNfQ0xVU1RFUl9OQU1FIikKICAgICAg - ICBzZWxmLmdldF9jZXBoZnNfZGF0YV9wb29sX2RldGFpbHMoKQogICAgICAgICMgZG91YmxlIHN0 - cmluZyBuZWVkZWQgZm9yIHVwc3RyZWFtIGV4cG9ydHMgb2YgZmxhZ3MKICAgICAgICBzZWxmLm91 - dF9tYXBbIkFSR1MiXSA9IGYnIntzZWxmLmdldEZpbmFsVXNlZEFyZ3MoKX0iJwogICAgICAgIHNl - bGYub3V0X21hcFsiTkFNRVNQQUNFIl0gPSBzZWxmLl9hcmdfcGFyc2VyLm5hbWVzcGFjZQogICAg - ICAgIHNlbGYub3V0X21hcFsiSzhTX0NMVVNURVJfTkFNRSJdID0gc2VsZi5fYXJnX3BhcnNlci5r - OHNfY2x1c3Rlcl9uYW1lCiAgICAgICAgc2VsZi5vdXRfbWFwWyJST09LX0VYVEVSTkFMX0ZTSUQi - XSA9IHNlbGYuZ2V0X2ZzaWQoKQogICAgICAgIHNlbGYub3V0X21hcFsiUk9PS19FWFRFUk5BTF9V - U0VSTkFNRSJdID0gc2VsZi5ydW5fYXNfdXNlcgogICAgICAgIHNlbGYub3V0X21hcFsiUk9PS19F - WFRFUk5BTF9DRVBIX01PTl9EQVRBIl0gPSBzZWxmLmdldF9jZXBoX2V4dGVybmFsX21vbl9kYXRh - KCkKICAgICAgICBzZWxmLm91dF9tYXBbIlJPT0tfRVhURVJOQUxfVVNFUl9TRUNSRVQiXSA9IHNl - bGYuY3JlYXRlX2NoZWNrZXJLZXkoCiAgICAgICAgICAgICJjbGllbnQuaGVhbHRoY2hlY2tlciIK - ICAgICAgICApCiAgICAgICAgc2VsZi5vdXRfbWFwWyJST09LX0VYVEVSTkFMX0RBU0hCT0FSRF9M - SU5LIl0gPSBzZWxmLmdldF9jZXBoX2Rhc2hib2FyZF9saW5rKCkKICAgICAgICAoCiAgICAgICAg - ICAgIHNlbGYub3V0X21hcFsiQ1NJX1JCRF9OT0RFX1NFQ1JFVCJdLAogICAgICAgICAgICBzZWxm - Lm91dF9tYXBbIkNTSV9SQkRfTk9ERV9TRUNSRVRfTkFNRSJdLAogICAgICAgICkgPSBzZWxmLmNy - ZWF0ZV9jZXBoQ1NJS2V5cmluZ191c2VyKCJjbGllbnQuY3NpLXJiZC1ub2RlIikKICAgICAgICAo - CiAgICAgICAgICAgIHNlbGYub3V0X21hcFsiQ1NJX1JCRF9QUk9WSVNJT05FUl9TRUNSRVQiXSwK - ICAgICAgICAgICAgc2VsZi5vdXRfbWFwWyJDU0lfUkJEX1BST1ZJU0lPTkVSX1NFQ1JFVF9OQU1F - Il0sCiAgICAgICAgKSA9IHNlbGYuY3JlYXRlX2NlcGhDU0lLZXlyaW5nX3VzZXIoImNsaWVudC5j - c2ktcmJkLXByb3Zpc2lvbmVyIikKICAgICAgICBzZWxmLm91dF9tYXBbIkNFUEhGU19QT09MX05B - TUUiXSA9IHNlbGYuX2FyZ19wYXJzZXIuY2VwaGZzX2RhdGFfcG9vbF9uYW1lCiAgICAgICAgc2Vs - Zi5vdXRfbWFwWyJDRVBIRlNfTUVUQURBVEFfUE9PTF9OQU1FIl0gPSAoCiAgICAgICAgICAgIHNl - bGYuX2FyZ19wYXJzZXIuY2VwaGZzX21ldGFkYXRhX3Bvb2xfbmFtZQogICAgICAgICkKICAgICAg - ICBzZWxmLm91dF9tYXBbIkNFUEhGU19GU19OQU1FIl0gPSBzZWxmLl9hcmdfcGFyc2VyLmNlcGhm - c19maWxlc3lzdGVtX25hbWUKICAgICAgICBzZWxmLm91dF9tYXBbIlJFU1RSSUNURURfQVVUSF9Q - RVJNSVNTSU9OIl0gPSAoCiAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIucmVzdHJpY3RlZF9h - dXRoX3Blcm1pc3Npb24KICAgICAgICApCiAgICAgICAgc2VsZi5vdXRfbWFwWyJSQURPU19OQU1F - U1BBQ0UiXSA9IHNlbGYuX2FyZ19wYXJzZXIucmFkb3NfbmFtZXNwYWNlCiAgICAgICAgc2VsZi5v - dXRfbWFwWyJTVUJWT0xVTUVfR1JPVVAiXSA9IHNlbGYuX2FyZ19wYXJzZXIuc3Vidm9sdW1lX2dy - b3VwCiAgICAgICAgc2VsZi5vdXRfbWFwWyJDU0lfQ0VQSEZTX05PREVfU0VDUkVUIl0gPSAiIgog - ICAgICAgIHNlbGYub3V0X21hcFsiQ1NJX0NFUEhGU19QUk9WSVNJT05FUl9TRUNSRVQiXSA9ICIi - CiAgICAgICAgIyBjcmVhdGUgQ2VwaEZTIG5vZGUgYW5kIHByb3Zpc2lvbmVyIGtleXJpbmcgb25s - eSB3aGVuIE1EUyBleGlzdHMKICAgICAgICBpZiBzZWxmLm91dF9tYXBbIkNFUEhGU19GU19OQU1F - Il0gYW5kIHNlbGYub3V0X21hcFsiQ0VQSEZTX1BPT0xfTkFNRSJdOgogICAgICAgICAgICAoCiAg - ICAgICAgICAgICAgICBzZWxmLm91dF9tYXBbIkNTSV9DRVBIRlNfTk9ERV9TRUNSRVQiXSwKICAg - ICAgICAgICAgICAgIHNlbGYub3V0X21hcFsiQ1NJX0NFUEhGU19OT0RFX1NFQ1JFVF9OQU1FIl0s - CiAgICAgICAgICAgICkgPSBzZWxmLmNyZWF0ZV9jZXBoQ1NJS2V5cmluZ191c2VyKCJjbGllbnQu - Y3NpLWNlcGhmcy1ub2RlIikKICAgICAgICAgICAgKAogICAgICAgICAgICAgICAgc2VsZi5vdXRf - bWFwWyJDU0lfQ0VQSEZTX1BST1ZJU0lPTkVSX1NFQ1JFVCJdLAogICAgICAgICAgICAgICAgc2Vs - Zi5vdXRfbWFwWyJDU0lfQ0VQSEZTX1BST1ZJU0lPTkVSX1NFQ1JFVF9OQU1FIl0sCiAgICAgICAg - ICAgICkgPSBzZWxmLmNyZWF0ZV9jZXBoQ1NJS2V5cmluZ191c2VyKCJjbGllbnQuY3NpLWNlcGhm - cy1wcm92aXNpb25lciIpCiAgICAgICAgICAgICMgY3JlYXRlIHRoZSBkZWZhdWx0ICJjc2kiIHN1 - YnZvbHVtZWdyb3VwCiAgICAgICAgICAgIHNlbGYuZ2V0X29yX2NyZWF0ZV9zdWJ2b2x1bWVfZ3Jv - dXAoCiAgICAgICAgICAgICAgICAiY3NpIiwgc2VsZi5fYXJnX3BhcnNlci5jZXBoZnNfZmlsZXN5 - c3RlbV9uYW1lCiAgICAgICAgICAgICkKICAgICAgICAgICAgIyBwaW4gdGhlIGRlZmF1bHQgImNz - aSIgc3Vidm9sdW1lZ3JvdXAKICAgICAgICAgICAgc2VsZi5waW5fc3Vidm9sdW1lKAogICAgICAg - ICAgICAgICAgImNzaSIsIHNlbGYuX2FyZ19wYXJzZXIuY2VwaGZzX2ZpbGVzeXN0ZW1fbmFtZSwg - ImRpc3RyaWJ1dGVkIiwgIjEiCiAgICAgICAgICAgICkKICAgICAgICAgICAgaWYgc2VsZi5vdXRf - bWFwWyJTVUJWT0xVTUVfR1JPVVAiXToKICAgICAgICAgICAgICAgIHNlbGYuZ2V0X29yX2NyZWF0 - ZV9zdWJ2b2x1bWVfZ3JvdXAoCiAgICAgICAgICAgICAgICAgICAgc2VsZi5fYXJnX3BhcnNlci5z - dWJ2b2x1bWVfZ3JvdXAsCiAgICAgICAgICAgICAgICAgICAgc2VsZi5fYXJnX3BhcnNlci5jZXBo - ZnNfZmlsZXN5c3RlbV9uYW1lLAogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgc2Vs - Zi5waW5fc3Vidm9sdW1lKAogICAgICAgICAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIuc3Vi - dm9sdW1lX2dyb3VwLAogICAgICAgICAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIuY2VwaGZz - X2ZpbGVzeXN0ZW1fbmFtZSwKICAgICAgICAgICAgICAgICAgICAiZGlzdHJpYnV0ZWQiLAogICAg - ICAgICAgICAgICAgICAgICIxIiwKICAgICAgICAgICAgICAgICkKICAgICAgICBzZWxmLm91dF9t - YXBbIlJHV19UTFNfQ0VSVCJdID0gIiIKICAgICAgICBzZWxmLm91dF9tYXBbIk1PTklUT1JJTkdf - RU5EUE9JTlQiXSA9ICIiCiAgICAgICAgc2VsZi5vdXRfbWFwWyJNT05JVE9SSU5HX0VORFBPSU5U - X1BPUlQiXSA9ICIiCiAgICAgICAgaWYgbm90IHNlbGYuX2FyZ19wYXJzZXIuc2tpcF9tb25pdG9y - aW5nX2VuZHBvaW50OgogICAgICAgICAgICAoCiAgICAgICAgICAgICAgICBzZWxmLm91dF9tYXBb - Ik1PTklUT1JJTkdfRU5EUE9JTlQiXSwKICAgICAgICAgICAgICAgIHNlbGYub3V0X21hcFsiTU9O - SVRPUklOR19FTkRQT0lOVF9QT1JUIl0sCiAgICAgICAgICAgICkgPSBzZWxmLmdldF9hY3RpdmVf - YW5kX3N0YW5kYnlfbWdycygpCiAgICAgICAgc2VsZi5vdXRfbWFwWyJSQkRfUE9PTF9OQU1FIl0g - PSBzZWxmLl9hcmdfcGFyc2VyLnJiZF9kYXRhX3Bvb2xfbmFtZQogICAgICAgIHNlbGYub3V0X21h - cFsiUkJEX01FVEFEQVRBX0VDX1BPT0xfTkFNRSJdID0gKAogICAgICAgICAgICBzZWxmLnZhbGlk - YXRlX3JiZF9tZXRhZGF0YV9lY19wb29sX25hbWUoKQogICAgICAgICkKICAgICAgICBzZWxmLm91 - dF9tYXBbIlRPUE9MT0dZX1BPT0xTIl0gPSBzZWxmLl9hcmdfcGFyc2VyLnRvcG9sb2d5X3Bvb2xz - CiAgICAgICAgc2VsZi5vdXRfbWFwWyJUT1BPTE9HWV9GQUlMVVJFX0RPTUFJTl9MQUJFTCJdID0g - KAogICAgICAgICAgICBzZWxmLl9hcmdfcGFyc2VyLnRvcG9sb2d5X2ZhaWx1cmVfZG9tYWluX2xh - YmVsCiAgICAgICAgKQogICAgICAgIHNlbGYub3V0X21hcFsiVE9QT0xPR1lfRkFJTFVSRV9ET01B - SU5fVkFMVUVTIl0gPSAoCiAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIudG9wb2xvZ3lfZmFp - bHVyZV9kb21haW5fdmFsdWVzCiAgICAgICAgKQogICAgICAgIGlmICgKICAgICAgICAgICAgc2Vs - Zi5fYXJnX3BhcnNlci50b3BvbG9neV9wb29scyAhPSAiIgogICAgICAgICAgICBhbmQgc2VsZi5f - YXJnX3BhcnNlci50b3BvbG9neV9mYWlsdXJlX2RvbWFpbl9sYWJlbCAhPSAiIgogICAgICAgICAg - ICBhbmQgc2VsZi5fYXJnX3BhcnNlci50b3BvbG9neV9mYWlsdXJlX2RvbWFpbl92YWx1ZXMgIT0g - IiIKICAgICAgICApOgogICAgICAgICAgICBzZWxmLnZhbGlkYXRlX3RvcG9sb2d5X3ZhbHVlcygK - ICAgICAgICAgICAgICAgIHNlbGYuY29udmVydF9jb21tYV9zZXBhcmF0ZWRfdG9fYXJyYXkoc2Vs - Zi5vdXRfbWFwWyJUT1BPTE9HWV9QT09MUyJdKSwKICAgICAgICAgICAgICAgIHNlbGYuY29udmVy - dF9jb21tYV9zZXBhcmF0ZWRfdG9fYXJyYXkoCiAgICAgICAgICAgICAgICAgICAgc2VsZi5vdXRf - bWFwWyJUT1BPTE9HWV9GQUlMVVJFX0RPTUFJTl9WQUxVRVMiXQogICAgICAgICAgICAgICAgKSwK - ICAgICAgICAgICAgKQogICAgICAgICAgICBzZWxmLnZhbGlkYXRlX3RvcG9sb2d5X3JiZF9wb29s - cygKICAgICAgICAgICAgICAgIHNlbGYuY29udmVydF9jb21tYV9zZXBhcmF0ZWRfdG9fYXJyYXko - c2VsZi5vdXRfbWFwWyJUT1BPTE9HWV9QT09MUyJdKQogICAgICAgICAgICApCiAgICAgICAgICAg - IHNlbGYuaW5pdF90b3BvbG9neV9yYmRfcG9vbHMoCiAgICAgICAgICAgICAgICBzZWxmLmNvbnZl - cnRfY29tbWFfc2VwYXJhdGVkX3RvX2FycmF5KHNlbGYub3V0X21hcFsiVE9QT0xPR1lfUE9PTFMi - XSkKICAgICAgICAgICAgKQogICAgICAgIGVsc2U6CiAgICAgICAgICAgIHNlbGYucmFpc2VfZXhj - ZXB0aW9uX2lmX2FueV90b3BvbG9neV9mbGFnX2lzX21pc3NpbmcoKQoKICAgICAgICBzZWxmLm91 - dF9tYXBbIlJHV19QT09MX1BSRUZJWCJdID0gc2VsZi5fYXJnX3BhcnNlci5yZ3dfcG9vbF9wcmVm - aXgKICAgICAgICBzZWxmLm91dF9tYXBbIlJHV19FTkRQT0lOVCJdID0gIiIKICAgICAgICBpZiBz - ZWxmLl9hcmdfcGFyc2VyLnJnd19lbmRwb2ludDoKICAgICAgICAgICAgaWYgc2VsZi5fYXJnX3Bh - cnNlci5kcnlfcnVuOgogICAgICAgICAgICAgICAgc2VsZi5jcmVhdGVfcmd3X2FkbWluX29wc191 - c2VyKCkKICAgICAgICAgICAgZWxzZToKICAgICAgICAgICAgICAgIGlmICgKICAgICAgICAgICAg - ICAgICAgICBzZWxmLl9hcmdfcGFyc2VyLnJnd19yZWFsbV9uYW1lICE9ICIiCiAgICAgICAgICAg - ICAgICAgICAgYW5kIHNlbGYuX2FyZ19wYXJzZXIucmd3X3pvbmVncm91cF9uYW1lICE9ICIiCiAg - ICAgICAgICAgICAgICAgICAgYW5kIHNlbGYuX2FyZ19wYXJzZXIucmd3X3pvbmVfbmFtZSAhPSAi - IgogICAgICAgICAgICAgICAgKToKICAgICAgICAgICAgICAgICAgICBlcnIgPSBzZWxmLnZhbGlk - YXRlX3Jnd19tdWx0aXNpdGUoCiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJz - ZXIucmd3X3JlYWxtX25hbWUsICJyZWFsbSIKICAgICAgICAgICAgICAgICAgICApCiAgICAgICAg - ICAgICAgICAgICAgZXJyID0gc2VsZi52YWxpZGF0ZV9yZ3dfbXVsdGlzaXRlKAogICAgICAgICAg - ICAgICAgICAgICAgICBzZWxmLl9hcmdfcGFyc2VyLnJnd196b25lZ3JvdXBfbmFtZSwgInpvbmVn - cm91cCIKICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgZXJyID0gc2Vs - Zi52YWxpZGF0ZV9yZ3dfbXVsdGlzaXRlKAogICAgICAgICAgICAgICAgICAgICAgICBzZWxmLl9h - cmdfcGFyc2VyLnJnd196b25lX25hbWUsICJ6b25lIgogICAgICAgICAgICAgICAgICAgICkKCiAg - ICAgICAgICAgICAgICBpZiAoCiAgICAgICAgICAgICAgICAgICAgc2VsZi5fYXJnX3BhcnNlci5y - Z3dfcmVhbG1fbmFtZSA9PSAiIgogICAgICAgICAgICAgICAgICAgIGFuZCBzZWxmLl9hcmdfcGFy - c2VyLnJnd196b25lZ3JvdXBfbmFtZSA9PSAiIgogICAgICAgICAgICAgICAgICAgIGFuZCBzZWxm - Ll9hcmdfcGFyc2VyLnJnd196b25lX25hbWUgPT0gIiIKICAgICAgICAgICAgICAgICkgb3IgKAog - ICAgICAgICAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIucmd3X3JlYWxtX25hbWUgIT0gIiIK - ICAgICAgICAgICAgICAgICAgICBhbmQgc2VsZi5fYXJnX3BhcnNlci5yZ3dfem9uZWdyb3VwX25h - bWUgIT0gIiIKICAgICAgICAgICAgICAgICAgICBhbmQgc2VsZi5fYXJnX3BhcnNlci5yZ3dfem9u - ZV9uYW1lICE9ICIiCiAgICAgICAgICAgICAgICApOgogICAgICAgICAgICAgICAgICAgICgKICAg - ICAgICAgICAgICAgICAgICAgICAgc2VsZi5vdXRfbWFwWyJSR1dfQURNSU5fT1BTX1VTRVJfQUND - RVNTX0tFWSJdLAogICAgICAgICAgICAgICAgICAgICAgICBzZWxmLm91dF9tYXBbIlJHV19BRE1J - Tl9PUFNfVVNFUl9TRUNSRVRfS0VZIl0sCiAgICAgICAgICAgICAgICAgICAgICAgIGluZm9fY2Fw - X3N1cHBvcnRlZCwKICAgICAgICAgICAgICAgICAgICAgICAgZXJyLAogICAgICAgICAgICAgICAg - ICAgICkgPSBzZWxmLmNyZWF0ZV9yZ3dfYWRtaW5fb3BzX3VzZXIoKQogICAgICAgICAgICAgICAg - ICAgIGVyciA9IHNlbGYudmFsaWRhdGVfcmd3X2VuZHBvaW50KGluZm9fY2FwX3N1cHBvcnRlZCkK - ICAgICAgICAgICAgICAgICAgICBpZiBzZWxmLl9hcmdfcGFyc2VyLnJnd190bHNfY2VydF9wYXRo - OgogICAgICAgICAgICAgICAgICAgICAgICBzZWxmLm91dF9tYXBbIlJHV19UTFNfQ0VSVCJdID0g - KAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi52YWxpZGF0ZV9yZ3dfZW5kcG9pbnRf - dGxzX2NlcnQoKQogICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAg - IyBpZiB0aGVyZSBpcyBubyBlcnJvciwgc2V0IHRoZSBSR1dfRU5EUE9JTlQKICAgICAgICAgICAg - ICAgICAgICBpZiBlcnIgIT0gIi0xIjoKICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5vdXRf - bWFwWyJSR1dfRU5EUE9JTlQiXSA9IHNlbGYuX2FyZ19wYXJzZXIucmd3X2VuZHBvaW50CiAgICAg - ICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgICAgIGVyciA9ICJQbGVhc2UgcHJvdmlk - ZSBhbGwgdGhlIFJHVyBtdWx0aXNpdGUgcGFyYW1ldGVycyBvciBub25lIG9mIHRoZW0iCiAgICAg - ICAgICAgICAgICAgICAgc3lzLnN0ZGVyci53cml0ZShlcnIpCgogICAgZGVmIGdlbl9zaGVsbF9v - dXQoc2VsZik6CiAgICAgICAgc2VsZi5fZ2VuX291dHB1dF9tYXAoKQogICAgICAgIHNoT3V0SU8g - PSBTdHJpbmdJTygpCiAgICAgICAgZm9yIGssIHYgaW4gc2VsZi5vdXRfbWFwLml0ZW1zKCk6CiAg - ICAgICAgICAgIGlmIHYgYW5kIGsgbm90IGluIHNlbGYuX2V4Y2x1ZGVkX2tleXM6CiAgICAgICAg - ICAgICAgICBzaE91dElPLndyaXRlKGYiZXhwb3J0IHtrfT17dn17TElORVNFUH0iKQogICAgICAg - IHNoT3V0ID0gc2hPdXRJTy5nZXR2YWx1ZSgpCiAgICAgICAgc2hPdXRJTy5jbG9zZSgpCiAgICAg - ICAgcmV0dXJuIHNoT3V0CgogICAgZGVmIGdlbl9qc29uX291dChzZWxmKToKICAgICAgICBzZWxm - Ll9nZW5fb3V0cHV0X21hcCgpCiAgICAgICAgaWYgc2VsZi5fYXJnX3BhcnNlci5kcnlfcnVuOgog - ICAgICAgICAgICByZXR1cm4gIiIKICAgICAgICBqc29uX291dCA9IFsKICAgICAgICAgICAgewog - ICAgICAgICAgICAgICAgIm5hbWUiOiAiZXh0ZXJuYWwtY2x1c3Rlci11c2VyLWNvbW1hbmQiLAog - ICAgICAgICAgICAgICAgImtpbmQiOiAiQ29uZmlnTWFwIiwKICAgICAgICAgICAgICAgICJkYXRh - IjogewogICAgICAgICAgICAgICAgICAgICJhcmdzIjogc2VsZi5vdXRfbWFwWyJBUkdTIl0sCiAg - ICAgICAgICAgICAgICB9LAogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAg - ICAgICAibmFtZSI6ICJyb29rLWNlcGgtbW9uLWVuZHBvaW50cyIsCiAgICAgICAgICAgICAgICAi - a2luZCI6ICJDb25maWdNYXAiLAogICAgICAgICAgICAgICAgImRhdGEiOiB7CiAgICAgICAgICAg - ICAgICAgICAgImRhdGEiOiBzZWxmLm91dF9tYXBbIlJPT0tfRVhURVJOQUxfQ0VQSF9NT05fREFU - QSJdLAogICAgICAgICAgICAgICAgICAgICJtYXhNb25JZCI6ICIwIiwKICAgICAgICAgICAgICAg - ICAgICAibWFwcGluZyI6ICJ7fSIsCiAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICB9LAog - ICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAibmFtZSI6ICJyb29rLWNlcGgtbW9uIiwKICAg - ICAgICAgICAgICAgICJraW5kIjogIlNlY3JldCIsCiAgICAgICAgICAgICAgICAiZGF0YSI6IHsK - ICAgICAgICAgICAgICAgICAgICAiYWRtaW4tc2VjcmV0IjogImFkbWluLXNlY3JldCIsCiAgICAg - ICAgICAgICAgICAgICAgImZzaWQiOiBzZWxmLm91dF9tYXBbIlJPT0tfRVhURVJOQUxfRlNJRCJd - LAogICAgICAgICAgICAgICAgICAgICJtb24tc2VjcmV0IjogIm1vbi1zZWNyZXQiLAogICAgICAg - ICAgICAgICAgfSwKICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAg - Im5hbWUiOiAicm9vay1jZXBoLW9wZXJhdG9yLWNyZWRzIiwKICAgICAgICAgICAgICAgICJraW5k - IjogIlNlY3JldCIsCiAgICAgICAgICAgICAgICAiZGF0YSI6IHsKICAgICAgICAgICAgICAgICAg - ICAidXNlcklEIjogc2VsZi5vdXRfbWFwWyJST09LX0VYVEVSTkFMX1VTRVJOQU1FIl0sCiAgICAg - ICAgICAgICAgICAgICAgInVzZXJLZXkiOiBzZWxmLm91dF9tYXBbIlJPT0tfRVhURVJOQUxfVVNF - Ul9TRUNSRVQiXSwKICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgIH0sCiAgICAgICAgXQoK - ICAgICAgICAjIGlmICdNT05JVE9SSU5HX0VORFBPSU5UJyBleGlzdHMsIHRoZW4gb25seSBhZGQg - J21vbml0b3JpbmctZW5kcG9pbnQnIHRvIENsdXN0ZXIKICAgICAgICBpZiAoCiAgICAgICAgICAg - IHNlbGYub3V0X21hcFsiTU9OSVRPUklOR19FTkRQT0lOVCJdCiAgICAgICAgICAgIGFuZCBzZWxm - Lm91dF9tYXBbIk1PTklUT1JJTkdfRU5EUE9JTlRfUE9SVCJdCiAgICAgICAgKToKICAgICAgICAg - ICAganNvbl9vdXQuYXBwZW5kKAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAg - ICJuYW1lIjogIm1vbml0b3JpbmctZW5kcG9pbnQiLAogICAgICAgICAgICAgICAgICAgICJraW5k - IjogIkNlcGhDbHVzdGVyIiwKICAgICAgICAgICAgICAgICAgICAiZGF0YSI6IHsKICAgICAgICAg - ICAgICAgICAgICAgICAgIk1vbml0b3JpbmdFbmRwb2ludCI6IHNlbGYub3V0X21hcFsiTU9OSVRP - UklOR19FTkRQT0lOVCJdLAogICAgICAgICAgICAgICAgICAgICAgICAiTW9uaXRvcmluZ1BvcnQi - OiBzZWxmLm91dF9tYXBbIk1PTklUT1JJTkdfRU5EUE9JTlRfUE9SVCJdLAogICAgICAgICAgICAg - ICAgICAgIH0sCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICkKCiAgICAgICAgIyBpZiAn - Q1NJX1JCRF9OT0RFX1NFQ1JFVCcgZXhpc3RzLCB0aGVuIG9ubHkgYWRkICdyb29rLWNzaS1yYmQt - cHJvdmlzaW9uZXInIFNlY3JldAogICAgICAgIGlmICgKICAgICAgICAgICAgc2VsZi5vdXRfbWFw - WyJDU0lfUkJEX05PREVfU0VDUkVUIl0KICAgICAgICAgICAgYW5kIHNlbGYub3V0X21hcFsiQ1NJ - X1JCRF9OT0RFX1NFQ1JFVF9OQU1FIl0KICAgICAgICApOgogICAgICAgICAgICBqc29uX291dC5h - cHBlbmQoCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgIm5hbWUiOiBmInJv - b2ste3NlbGYub3V0X21hcFsnQ1NJX1JCRF9OT0RFX1NFQ1JFVF9OQU1FJ119IiwKICAgICAgICAg + YWlsdXJlX2RvbWFpbl92YWx1ZXMgPT0gIiIKICAgICAgICAgICAgICAgICkKICAgICAgICAgICAg + KQogICAgICAgICAgICBvciAoCiAgICAgICAgICAgICAgICBzZWxmLl9hcmdfcGFyc2VyLnRvcG9s + b2d5X2ZhaWx1cmVfZG9tYWluX2xhYmVsICE9ICIiCiAgICAgICAgICAgICAgICBhbmQgKAogICAg + ICAgICAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIudG9wb2xvZ3lfcG9vbHMgPT0gIiIKICAg + ICAgICAgICAgICAgICAgICBvciBzZWxmLl9hcmdfcGFyc2VyLnRvcG9sb2d5X2ZhaWx1cmVfZG9t + YWluX3ZhbHVlcyA9PSAiIgogICAgICAgICAgICAgICAgKQogICAgICAgICAgICApCiAgICAgICAg + ICAgIG9yICgKICAgICAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIudG9wb2xvZ3lfZmFpbHVy + ZV9kb21haW5fdmFsdWVzICE9ICIiCiAgICAgICAgICAgICAgICBhbmQgKAogICAgICAgICAgICAg + ICAgICAgIHNlbGYuX2FyZ19wYXJzZXIudG9wb2xvZ3lfcG9vbHMgPT0gIiIKICAgICAgICAgICAg + ICAgICAgICBvciBzZWxmLl9hcmdfcGFyc2VyLnRvcG9sb2d5X2ZhaWx1cmVfZG9tYWluX2xhYmVs + ID09ICIiCiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICkKICAgICAgICApOgogICAgICAg + ICAgICByYWlzZSBFeGVjdXRpb25GYWlsdXJlRXhjZXB0aW9uKAogICAgICAgICAgICAgICAgInBy + b3ZpZGUgYWxsIHRoZSB0b3BvbG9neSBmbGFncyAtLXRvcG9sb2d5LXBvb2xzLCAtLXRvcG9sb2d5 + LWZhaWx1cmUtZG9tYWluLWxhYmVsLCAtLXRvcG9sb2d5LWZhaWx1cmUtZG9tYWluLXZhbHVlcyIK + ICAgICAgICAgICAgKQoKICAgIGRlZiB2YWxpZGF0ZV90b3BvbG9neV92YWx1ZXMoc2VsZiwgdG9w + b2xvZ3lfcG9vbHMsIHRvcG9sb2d5X2ZkKToKICAgICAgICBpZiBsZW4odG9wb2xvZ3lfcG9vbHMp + ICE9IGxlbih0b3BvbG9neV9mZCk6CiAgICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1cmVF + eGNlcHRpb24oCiAgICAgICAgICAgICAgICBmIlRoZSBwcm92aWRlZCB0b3BvbG9neSBwb29scywg + J3t0b3BvbG9neV9wb29sc30nLCBhbmQgIgogICAgICAgICAgICAgICAgZiJ0b3BvbG9neSBmYWls + dXJlIGRvbWFpbiwgJ3t0b3BvbG9neV9mZH0nLCIKICAgICAgICAgICAgICAgIGYiYXJlIG9mIGRp + ZmZlcmVudCBsZW5ndGgsICd7bGVuKHRvcG9sb2d5X3Bvb2xzKX0nIGFuZCAne2xlbih0b3BvbG9n + eV9mZCl9JyByZXNwY3RpdmVseSIKICAgICAgICAgICAgKQogICAgICAgIHJldHVybgoKICAgIGRl + ZiB2YWxpZGF0ZV90b3BvbG9neV9yYmRfcG9vbHMoc2VsZiwgdG9wb2xvZ3lfcmJkX3Bvb2xzKToK + ICAgICAgICBmb3IgcG9vbCBpbiB0b3BvbG9neV9yYmRfcG9vbHM6CiAgICAgICAgICAgIHNlbGYu + dmFsaWRhdGVfcmJkX3Bvb2wocG9vbCkKCiAgICBkZWYgaW5pdF90b3BvbG9neV9yYmRfcG9vbHMo + c2VsZiwgdG9wb2xvZ3lfcmJkX3Bvb2xzKToKICAgICAgICBmb3IgcG9vbCBpbiB0b3BvbG9neV9y + YmRfcG9vbHM6CiAgICAgICAgICAgIHNlbGYuaW5pdF9yYmRfcG9vbChwb29sKQoKICAgICMgdGhp + cyB3aWxsIHJldHVybiB0aGUgZmluYWwgYXJncyB0aGF0IHNjcmlwdCB1c2VzIHRvIHByb2Nlc3MK + ICAgICMgdGhlIHByaW9yaXR5IHRvIHNldCBhIHBhcnRpY3VsYXIgdmFsdWUgaXMsCiAgICAjIGNv + bW1hbmQtbGluZS1hcmdzID4gY29uZmlnLmluaSBmaWxlIHZhbHVlcyA+IGRlZmF1bHQgdmFsdWVz + CiAgICBkZWYgZ2V0RmluYWxVc2VkQXJncyhzZWxmKToKICAgICAgICBhcmd1bWVudCA9IGYiW0Nv + bmZpZ3VyYXRpb25zXVxuIgogICAgICAgIGZvciBhcmcgaW4gdmFycyhzZWxmLl9hcmdfcGFyc2Vy + KToKICAgICAgICAgICAgaWYgc3RyKGdldGF0dHIoc2VsZi5fYXJnX3BhcnNlciwgYXJnKSk6CiAg + ICAgICAgICAgICAgICAjIHB5dGhvbiB0cmVhdHMgZmxhZy1uYW1lIGFzIGZsYWdfbmFtZSBpbnRl + cm5hbGx5LCBzbyBjb252ZXJ0aW5nIGJhY2sgdG8gZmxhZy1uYW1lLAogICAgICAgICAgICAgICAg + IyBzbyB3ZSBjYW4gZ2V0IHRob3NlIHZhbHVlcyBmcm9tIGNvbmZpZyBmaWxlCiAgICAgICAgICAg + ICAgICBhcmdWYWx1ZSA9IGFyZy5yZXBsYWNlKCJfIiwgIi0iKQogICAgICAgICAgICAgICAgIyBk + byBub3QgYWRkIHRoZSBjb25maWctZmlsZSBmbGFnIGFuZCBhbHNvIG5vdCBhZGQgdGhlIGJvb2xl + YW4gZmxhZ3Mgd2hpY2ggYXJlIHNldCB0byBGYWxzZQogICAgICAgICAgICAgICAgIyBiZWNhdXNl + IGNvbmZpZy5pbmkgZmlsZSB0cmVhdHMgYm9vbGVhbiBmbGFncyBhcyBUcnVlIGFsd2F5cwogICAg + ICAgICAgICAgICAgaWYgKAogICAgICAgICAgICAgICAgICAgIGFyZ1ZhbHVlICE9ICJjb25maWct + ZmlsZSIKICAgICAgICAgICAgICAgICAgICBhbmQgZ2V0YXR0cihzZWxmLl9hcmdfcGFyc2VyLCBh + cmcpICE9IEZhbHNlCiAgICAgICAgICAgICAgICApOgogICAgICAgICAgICAgICAgICAgIGFyZ3Vt + ZW50ICs9IGYie2FyZ1ZhbHVlfSA9IHtzdHIoZ2V0YXR0cihzZWxmLl9hcmdfcGFyc2VyLCBhcmcp + KX1cbiIKICAgICAgICByZXR1cm4gYXJndW1lbnQKCiAgICBkZWYgX2dlbl9vdXRwdXRfbWFwKHNl + bGYpOgogICAgICAgIGlmIHNlbGYub3V0X21hcDoKICAgICAgICAgICAgcmV0dXJuCiAgICAgICAg + IyBzdXBwb3J0IGxlZ2FjeSBmbGFnIHdpdGggdXBncmFkZXMKICAgICAgICBpZiBzZWxmLl9hcmdf + cGFyc2VyLmNsdXN0ZXJfbmFtZToKICAgICAgICAgICAgc2VsZi5fYXJnX3BhcnNlci5rOHNfY2x1 + c3Rlcl9uYW1lID0gc2VsZi5fYXJnX3BhcnNlci5jbHVzdGVyX25hbWUKICAgICAgICBzZWxmLl9h + cmdfcGFyc2VyLms4c19jbHVzdGVyX25hbWUgPSAoCiAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJz + ZXIuazhzX2NsdXN0ZXJfbmFtZS5sb3dlcigpCiAgICAgICAgKSAgIyBhbHdheXMgY29udmVydCBj + bHVzdGVyIG5hbWUgdG8gbG93ZXJjYXNlIGNoYXJhY3RlcnMKICAgICAgICBzZWxmLnZhbGlkYXRl + X3JiZF9wb29sKHNlbGYuX2FyZ19wYXJzZXIucmJkX2RhdGFfcG9vbF9uYW1lKQogICAgICAgIHNl + bGYuaW5pdF9yYmRfcG9vbChzZWxmLl9hcmdfcGFyc2VyLnJiZF9kYXRhX3Bvb2xfbmFtZSkKICAg + ICAgICBzZWxmLnZhbGlkYXRlX3JhZG9zX25hbWVzcGFjZSgpCiAgICAgICAgc2VsZi5fZXhjbHVk + ZWRfa2V5cy5hZGQoIks4U19DTFVTVEVSX05BTUUiKQogICAgICAgIHNlbGYuZ2V0X2NlcGhmc19k + YXRhX3Bvb2xfZGV0YWlscygpCiAgICAgICAgIyBkb3VibGUgc3RyaW5nIG5lZWRlZCBmb3IgdXBz + dHJlYW0gZXhwb3J0cyBvZiBmbGFncwogICAgICAgIHNlbGYub3V0X21hcFsiQVJHUyJdID0gZici + e3NlbGYuZ2V0RmluYWxVc2VkQXJncygpfSInCiAgICAgICAgc2VsZi5vdXRfbWFwWyJOQU1FU1BB + Q0UiXSA9IHNlbGYuX2FyZ19wYXJzZXIubmFtZXNwYWNlCiAgICAgICAgc2VsZi5vdXRfbWFwWyJL + OFNfQ0xVU1RFUl9OQU1FIl0gPSBzZWxmLl9hcmdfcGFyc2VyLms4c19jbHVzdGVyX25hbWUKICAg + ICAgICBzZWxmLm91dF9tYXBbIlJPT0tfRVhURVJOQUxfRlNJRCJdID0gc2VsZi5nZXRfZnNpZCgp + CiAgICAgICAgc2VsZi5vdXRfbWFwWyJST09LX0VYVEVSTkFMX1VTRVJOQU1FIl0gPSBzZWxmLnJ1 + bl9hc191c2VyCiAgICAgICAgc2VsZi5vdXRfbWFwWyJST09LX0VYVEVSTkFMX0NFUEhfTU9OX0RB + VEEiXSA9IHNlbGYuZ2V0X2NlcGhfZXh0ZXJuYWxfbW9uX2RhdGEoKQogICAgICAgIHNlbGYub3V0 + X21hcFsiUk9PS19FWFRFUk5BTF9VU0VSX1NFQ1JFVCJdID0gc2VsZi5jcmVhdGVfY2hlY2tlcktl + eSgKICAgICAgICAgICAgImNsaWVudC5oZWFsdGhjaGVja2VyIgogICAgICAgICkKICAgICAgICBz + ZWxmLm91dF9tYXBbIlJPT0tfRVhURVJOQUxfREFTSEJPQVJEX0xJTksiXSA9IHNlbGYuZ2V0X2Nl + cGhfZGFzaGJvYXJkX2xpbmsoKQogICAgICAgICgKICAgICAgICAgICAgc2VsZi5vdXRfbWFwWyJD + U0lfUkJEX05PREVfU0VDUkVUIl0sCiAgICAgICAgICAgIHNlbGYub3V0X21hcFsiQ1NJX1JCRF9O + T0RFX1NFQ1JFVF9OQU1FIl0sCiAgICAgICAgKSA9IHNlbGYuY3JlYXRlX2NlcGhDU0lLZXlyaW5n + X3VzZXIoImNsaWVudC5jc2ktcmJkLW5vZGUiKQogICAgICAgICgKICAgICAgICAgICAgc2VsZi5v + dXRfbWFwWyJDU0lfUkJEX1BST1ZJU0lPTkVSX1NFQ1JFVCJdLAogICAgICAgICAgICBzZWxmLm91 + dF9tYXBbIkNTSV9SQkRfUFJPVklTSU9ORVJfU0VDUkVUX05BTUUiXSwKICAgICAgICApID0gc2Vs + Zi5jcmVhdGVfY2VwaENTSUtleXJpbmdfdXNlcigiY2xpZW50LmNzaS1yYmQtcHJvdmlzaW9uZXIi + KQogICAgICAgIHNlbGYub3V0X21hcFsiQ0VQSEZTX1BPT0xfTkFNRSJdID0gc2VsZi5fYXJnX3Bh + cnNlci5jZXBoZnNfZGF0YV9wb29sX25hbWUKICAgICAgICBzZWxmLm91dF9tYXBbIkNFUEhGU19N + RVRBREFUQV9QT09MX05BTUUiXSA9ICgKICAgICAgICAgICAgc2VsZi5fYXJnX3BhcnNlci5jZXBo + ZnNfbWV0YWRhdGFfcG9vbF9uYW1lCiAgICAgICAgKQogICAgICAgIHNlbGYub3V0X21hcFsiQ0VQ + SEZTX0ZTX05BTUUiXSA9IHNlbGYuX2FyZ19wYXJzZXIuY2VwaGZzX2ZpbGVzeXN0ZW1fbmFtZQog + ICAgICAgIHNlbGYub3V0X21hcFsiUkVTVFJJQ1RFRF9BVVRIX1BFUk1JU1NJT04iXSA9ICgKICAg + ICAgICAgICAgc2VsZi5fYXJnX3BhcnNlci5yZXN0cmljdGVkX2F1dGhfcGVybWlzc2lvbgogICAg + ICAgICkKICAgICAgICBzZWxmLm91dF9tYXBbIlJBRE9TX05BTUVTUEFDRSJdID0gc2VsZi5fYXJn + X3BhcnNlci5yYWRvc19uYW1lc3BhY2UKICAgICAgICBzZWxmLm91dF9tYXBbIlNVQlZPTFVNRV9H + Uk9VUCJdID0gc2VsZi5fYXJnX3BhcnNlci5zdWJ2b2x1bWVfZ3JvdXAKICAgICAgICBzZWxmLm91 + dF9tYXBbIkNTSV9DRVBIRlNfTk9ERV9TRUNSRVQiXSA9ICIiCiAgICAgICAgc2VsZi5vdXRfbWFw + WyJDU0lfQ0VQSEZTX1BST1ZJU0lPTkVSX1NFQ1JFVCJdID0gIiIKICAgICAgICAjIGNyZWF0ZSBD + ZXBoRlMgbm9kZSBhbmQgcHJvdmlzaW9uZXIga2V5cmluZyBvbmx5IHdoZW4gTURTIGV4aXN0cwog + ICAgICAgIGlmIHNlbGYub3V0X21hcFsiQ0VQSEZTX0ZTX05BTUUiXSBhbmQgc2VsZi5vdXRfbWFw + WyJDRVBIRlNfUE9PTF9OQU1FIl06CiAgICAgICAgICAgICgKICAgICAgICAgICAgICAgIHNlbGYu + b3V0X21hcFsiQ1NJX0NFUEhGU19OT0RFX1NFQ1JFVCJdLAogICAgICAgICAgICAgICAgc2VsZi5v + dXRfbWFwWyJDU0lfQ0VQSEZTX05PREVfU0VDUkVUX05BTUUiXSwKICAgICAgICAgICAgKSA9IHNl + bGYuY3JlYXRlX2NlcGhDU0lLZXlyaW5nX3VzZXIoImNsaWVudC5jc2ktY2VwaGZzLW5vZGUiKQog + ICAgICAgICAgICAoCiAgICAgICAgICAgICAgICBzZWxmLm91dF9tYXBbIkNTSV9DRVBIRlNfUFJP + VklTSU9ORVJfU0VDUkVUIl0sCiAgICAgICAgICAgICAgICBzZWxmLm91dF9tYXBbIkNTSV9DRVBI + RlNfUFJPVklTSU9ORVJfU0VDUkVUX05BTUUiXSwKICAgICAgICAgICAgKSA9IHNlbGYuY3JlYXRl + X2NlcGhDU0lLZXlyaW5nX3VzZXIoImNsaWVudC5jc2ktY2VwaGZzLXByb3Zpc2lvbmVyIikKICAg + ICAgICAgICAgIyBjcmVhdGUgdGhlIGRlZmF1bHQgImNzaSIgc3Vidm9sdW1lZ3JvdXAKICAgICAg + ICAgICAgc2VsZi5nZXRfb3JfY3JlYXRlX3N1YnZvbHVtZV9ncm91cCgKICAgICAgICAgICAgICAg + ICJjc2kiLCBzZWxmLl9hcmdfcGFyc2VyLmNlcGhmc19maWxlc3lzdGVtX25hbWUKICAgICAgICAg + ICAgKQogICAgICAgICAgICAjIHBpbiB0aGUgZGVmYXVsdCAiY3NpIiBzdWJ2b2x1bWVncm91cAog + ICAgICAgICAgICBzZWxmLnBpbl9zdWJ2b2x1bWUoCiAgICAgICAgICAgICAgICAiY3NpIiwgc2Vs + Zi5fYXJnX3BhcnNlci5jZXBoZnNfZmlsZXN5c3RlbV9uYW1lLCAiZGlzdHJpYnV0ZWQiLCAiMSIK + ICAgICAgICAgICAgKQogICAgICAgICAgICBpZiBzZWxmLm91dF9tYXBbIlNVQlZPTFVNRV9HUk9V + UCJdOgogICAgICAgICAgICAgICAgc2VsZi5nZXRfb3JfY3JlYXRlX3N1YnZvbHVtZV9ncm91cCgK + ICAgICAgICAgICAgICAgICAgICBzZWxmLl9hcmdfcGFyc2VyLnN1YnZvbHVtZV9ncm91cCwKICAg + ICAgICAgICAgICAgICAgICBzZWxmLl9hcmdfcGFyc2VyLmNlcGhmc19maWxlc3lzdGVtX25hbWUs + CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICBzZWxmLnBpbl9zdWJ2b2x1bWUoCiAg + ICAgICAgICAgICAgICAgICAgc2VsZi5fYXJnX3BhcnNlci5zdWJ2b2x1bWVfZ3JvdXAsCiAgICAg + ICAgICAgICAgICAgICAgc2VsZi5fYXJnX3BhcnNlci5jZXBoZnNfZmlsZXN5c3RlbV9uYW1lLAog + ICAgICAgICAgICAgICAgICAgICJkaXN0cmlidXRlZCIsCiAgICAgICAgICAgICAgICAgICAgIjEi + LAogICAgICAgICAgICAgICAgKQogICAgICAgIHNlbGYub3V0X21hcFsiUkdXX1RMU19DRVJUIl0g + PSAiIgogICAgICAgIHNlbGYub3V0X21hcFsiTU9OSVRPUklOR19FTkRQT0lOVCJdID0gIiIKICAg + ICAgICBzZWxmLm91dF9tYXBbIk1PTklUT1JJTkdfRU5EUE9JTlRfUE9SVCJdID0gIiIKICAgICAg + ICBpZiBub3Qgc2VsZi5fYXJnX3BhcnNlci5za2lwX21vbml0b3JpbmdfZW5kcG9pbnQ6CiAgICAg + ICAgICAgICgKICAgICAgICAgICAgICAgIHNlbGYub3V0X21hcFsiTU9OSVRPUklOR19FTkRQT0lO + VCJdLAogICAgICAgICAgICAgICAgc2VsZi5vdXRfbWFwWyJNT05JVE9SSU5HX0VORFBPSU5UX1BP + UlQiXSwKICAgICAgICAgICAgKSA9IHNlbGYuZ2V0X2FjdGl2ZV9hbmRfc3RhbmRieV9tZ3JzKCkK + ICAgICAgICBzZWxmLm91dF9tYXBbIlJCRF9QT09MX05BTUUiXSA9IHNlbGYuX2FyZ19wYXJzZXIu + cmJkX2RhdGFfcG9vbF9uYW1lCiAgICAgICAgc2VsZi5vdXRfbWFwWyJSQkRfTUVUQURBVEFfRUNf + UE9PTF9OQU1FIl0gPSAoCiAgICAgICAgICAgIHNlbGYudmFsaWRhdGVfcmJkX21ldGFkYXRhX2Vj + X3Bvb2xfbmFtZSgpCiAgICAgICAgKQogICAgICAgIHNlbGYub3V0X21hcFsiVE9QT0xPR1lfUE9P + TFMiXSA9IHNlbGYuX2FyZ19wYXJzZXIudG9wb2xvZ3lfcG9vbHMKICAgICAgICBzZWxmLm91dF9t + YXBbIlRPUE9MT0dZX0ZBSUxVUkVfRE9NQUlOX0xBQkVMIl0gPSAoCiAgICAgICAgICAgIHNlbGYu + X2FyZ19wYXJzZXIudG9wb2xvZ3lfZmFpbHVyZV9kb21haW5fbGFiZWwKICAgICAgICApCiAgICAg + ICAgc2VsZi5vdXRfbWFwWyJUT1BPTE9HWV9GQUlMVVJFX0RPTUFJTl9WQUxVRVMiXSA9ICgKICAg + ICAgICAgICAgc2VsZi5fYXJnX3BhcnNlci50b3BvbG9neV9mYWlsdXJlX2RvbWFpbl92YWx1ZXMK + ICAgICAgICApCiAgICAgICAgaWYgKAogICAgICAgICAgICBzZWxmLl9hcmdfcGFyc2VyLnRvcG9s + b2d5X3Bvb2xzICE9ICIiCiAgICAgICAgICAgIGFuZCBzZWxmLl9hcmdfcGFyc2VyLnRvcG9sb2d5 + X2ZhaWx1cmVfZG9tYWluX2xhYmVsICE9ICIiCiAgICAgICAgICAgIGFuZCBzZWxmLl9hcmdfcGFy + c2VyLnRvcG9sb2d5X2ZhaWx1cmVfZG9tYWluX3ZhbHVlcyAhPSAiIgogICAgICAgICk6CiAgICAg + ICAgICAgIHNlbGYudmFsaWRhdGVfdG9wb2xvZ3lfdmFsdWVzKAogICAgICAgICAgICAgICAgc2Vs + Zi5jb252ZXJ0X2NvbW1hX3NlcGFyYXRlZF90b19hcnJheShzZWxmLm91dF9tYXBbIlRPUE9MT0dZ + X1BPT0xTIl0pLAogICAgICAgICAgICAgICAgc2VsZi5jb252ZXJ0X2NvbW1hX3NlcGFyYXRlZF90 + b19hcnJheSgKICAgICAgICAgICAgICAgICAgICBzZWxmLm91dF9tYXBbIlRPUE9MT0dZX0ZBSUxV + UkVfRE9NQUlOX1ZBTFVFUyJdCiAgICAgICAgICAgICAgICApLAogICAgICAgICAgICApCiAgICAg + ICAgICAgIHNlbGYudmFsaWRhdGVfdG9wb2xvZ3lfcmJkX3Bvb2xzKAogICAgICAgICAgICAgICAg + c2VsZi5jb252ZXJ0X2NvbW1hX3NlcGFyYXRlZF90b19hcnJheShzZWxmLm91dF9tYXBbIlRPUE9M + T0dZX1BPT0xTIl0pCiAgICAgICAgICAgICkKICAgICAgICAgICAgc2VsZi5pbml0X3RvcG9sb2d5 + X3JiZF9wb29scygKICAgICAgICAgICAgICAgIHNlbGYuY29udmVydF9jb21tYV9zZXBhcmF0ZWRf + dG9fYXJyYXkoc2VsZi5vdXRfbWFwWyJUT1BPTE9HWV9QT09MUyJdKQogICAgICAgICAgICApCiAg + ICAgICAgZWxzZToKICAgICAgICAgICAgc2VsZi5yYWlzZV9leGNlcHRpb25faWZfYW55X3RvcG9s + b2d5X2ZsYWdfaXNfbWlzc2luZygpCgogICAgICAgIHNlbGYub3V0X21hcFsiUkdXX1BPT0xfUFJF + RklYIl0gPSBzZWxmLl9hcmdfcGFyc2VyLnJnd19wb29sX3ByZWZpeAogICAgICAgIHNlbGYub3V0 + X21hcFsiUkdXX0VORFBPSU5UIl0gPSAiIgogICAgICAgIGlmIHNlbGYuX2FyZ19wYXJzZXIucmd3 + X2VuZHBvaW50OgogICAgICAgICAgICBpZiBzZWxmLl9hcmdfcGFyc2VyLmRyeV9ydW46CiAgICAg + ICAgICAgICAgICBzZWxmLmNyZWF0ZV9yZ3dfYWRtaW5fb3BzX3VzZXIoKQogICAgICAgICAgICBl + bHNlOgogICAgICAgICAgICAgICAgaWYgKAogICAgICAgICAgICAgICAgICAgIHNlbGYuX2FyZ19w + YXJzZXIucmd3X3JlYWxtX25hbWUgIT0gIiIKICAgICAgICAgICAgICAgICAgICBhbmQgc2VsZi5f + YXJnX3BhcnNlci5yZ3dfem9uZWdyb3VwX25hbWUgIT0gIiIKICAgICAgICAgICAgICAgICAgICBh + bmQgc2VsZi5fYXJnX3BhcnNlci5yZ3dfem9uZV9uYW1lICE9ICIiCiAgICAgICAgICAgICAgICAp + OgogICAgICAgICAgICAgICAgICAgIGVyciA9IHNlbGYudmFsaWRhdGVfcmd3X211bHRpc2l0ZSgK + ICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5fYXJnX3BhcnNlci5yZ3dfcmVhbG1fbmFtZSwg + InJlYWxtIgogICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICBlcnIgPSBz + ZWxmLnZhbGlkYXRlX3Jnd19tdWx0aXNpdGUoCiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYu + X2FyZ19wYXJzZXIucmd3X3pvbmVncm91cF9uYW1lLCAiem9uZWdyb3VwIgogICAgICAgICAgICAg + ICAgICAgICkKICAgICAgICAgICAgICAgICAgICBlcnIgPSBzZWxmLnZhbGlkYXRlX3Jnd19tdWx0 + aXNpdGUoCiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIucmd3X3pvbmVf + bmFtZSwgInpvbmUiCiAgICAgICAgICAgICAgICAgICAgKQoKICAgICAgICAgICAgICAgIGlmICgK + ICAgICAgICAgICAgICAgICAgICBzZWxmLl9hcmdfcGFyc2VyLnJnd19yZWFsbV9uYW1lID09ICIi + CiAgICAgICAgICAgICAgICAgICAgYW5kIHNlbGYuX2FyZ19wYXJzZXIucmd3X3pvbmVncm91cF9u + YW1lID09ICIiCiAgICAgICAgICAgICAgICAgICAgYW5kIHNlbGYuX2FyZ19wYXJzZXIucmd3X3pv + bmVfbmFtZSA9PSAiIgogICAgICAgICAgICAgICAgKSBvciAoCiAgICAgICAgICAgICAgICAgICAg + c2VsZi5fYXJnX3BhcnNlci5yZ3dfcmVhbG1fbmFtZSAhPSAiIgogICAgICAgICAgICAgICAgICAg + IGFuZCBzZWxmLl9hcmdfcGFyc2VyLnJnd196b25lZ3JvdXBfbmFtZSAhPSAiIgogICAgICAgICAg + ICAgICAgICAgIGFuZCBzZWxmLl9hcmdfcGFyc2VyLnJnd196b25lX25hbWUgIT0gIiIKICAgICAg + ICAgICAgICAgICk6CiAgICAgICAgICAgICAgICAgICAgKAogICAgICAgICAgICAgICAgICAgICAg + ICBzZWxmLm91dF9tYXBbIlJHV19BRE1JTl9PUFNfVVNFUl9BQ0NFU1NfS0VZIl0sCiAgICAgICAg + ICAgICAgICAgICAgICAgIHNlbGYub3V0X21hcFsiUkdXX0FETUlOX09QU19VU0VSX1NFQ1JFVF9L + RVkiXSwKICAgICAgICAgICAgICAgICAgICAgICAgaW5mb19jYXBfc3VwcG9ydGVkLAogICAgICAg + ICAgICAgICAgICAgICAgICBlcnIsCiAgICAgICAgICAgICAgICAgICAgKSA9IHNlbGYuY3JlYXRl + X3Jnd19hZG1pbl9vcHNfdXNlcigpCiAgICAgICAgICAgICAgICAgICAgZXJyID0gc2VsZi52YWxp + ZGF0ZV9yZ3dfZW5kcG9pbnQoaW5mb19jYXBfc3VwcG9ydGVkKQogICAgICAgICAgICAgICAgICAg + IGlmIHNlbGYuX2FyZ19wYXJzZXIucmd3X3Rsc19jZXJ0X3BhdGg6CiAgICAgICAgICAgICAgICAg + ICAgICAgIHNlbGYub3V0X21hcFsiUkdXX1RMU19DRVJUIl0gPSAoCiAgICAgICAgICAgICAgICAg + ICAgICAgICAgICBzZWxmLnZhbGlkYXRlX3Jnd19lbmRwb2ludF90bHNfY2VydCgpCiAgICAgICAg + ICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAjIGlmIHRoZXJlIGlzIG5vIGVy + cm9yLCBzZXQgdGhlIFJHV19FTkRQT0lOVAogICAgICAgICAgICAgICAgICAgIGlmIGVyciAhPSAi + LTEiOgogICAgICAgICAgICAgICAgICAgICAgICBzZWxmLm91dF9tYXBbIlJHV19FTkRQT0lOVCJd + ID0gc2VsZi5fYXJnX3BhcnNlci5yZ3dfZW5kcG9pbnQKICAgICAgICAgICAgICAgIGVsc2U6CiAg + ICAgICAgICAgICAgICAgICAgZXJyID0gIlBsZWFzZSBwcm92aWRlIGFsbCB0aGUgUkdXIG11bHRp + c2l0ZSBwYXJhbWV0ZXJzIG9yIG5vbmUgb2YgdGhlbSIKICAgICAgICAgICAgICAgICAgICBzeXMu + c3RkZXJyLndyaXRlKGVycikKCiAgICBkZWYgZ2VuX3NoZWxsX291dChzZWxmKToKICAgICAgICBz + ZWxmLl9nZW5fb3V0cHV0X21hcCgpCiAgICAgICAgc2hPdXRJTyA9IFN0cmluZ0lPKCkKICAgICAg + ICBmb3IgaywgdiBpbiBzZWxmLm91dF9tYXAuaXRlbXMoKToKICAgICAgICAgICAgaWYgdiBhbmQg + ayBub3QgaW4gc2VsZi5fZXhjbHVkZWRfa2V5czoKICAgICAgICAgICAgICAgIHNoT3V0SU8ud3Jp + dGUoZiJleHBvcnQge2t9PXt2fXtMSU5FU0VQfSIpCiAgICAgICAgc2hPdXQgPSBzaE91dElPLmdl + dHZhbHVlKCkKICAgICAgICBzaE91dElPLmNsb3NlKCkKICAgICAgICByZXR1cm4gc2hPdXQKCiAg + ICBkZWYgZ2VuX2pzb25fb3V0KHNlbGYpOgogICAgICAgIHNlbGYuX2dlbl9vdXRwdXRfbWFwKCkK + ICAgICAgICBpZiBzZWxmLl9hcmdfcGFyc2VyLmRyeV9ydW46CiAgICAgICAgICAgIHJldHVybiAi + IgogICAgICAgIGpzb25fb3V0ID0gWwogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAibmFt + ZSI6ICJleHRlcm5hbC1jbHVzdGVyLXVzZXItY29tbWFuZCIsCiAgICAgICAgICAgICAgICAia2lu + ZCI6ICJDb25maWdNYXAiLAogICAgICAgICAgICAgICAgImRhdGEiOiB7CiAgICAgICAgICAgICAg + ICAgICAgImFyZ3MiOiBzZWxmLm91dF9tYXBbIkFSR1MiXSwKICAgICAgICAgICAgICAgIH0sCiAg + ICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJuYW1lIjogInJvb2st + Y2VwaC1tb24tZW5kcG9pbnRzIiwKICAgICAgICAgICAgICAgICJraW5kIjogIkNvbmZpZ01hcCIs + CiAgICAgICAgICAgICAgICAiZGF0YSI6IHsKICAgICAgICAgICAgICAgICAgICAiZGF0YSI6IHNl + bGYub3V0X21hcFsiUk9PS19FWFRFUk5BTF9DRVBIX01PTl9EQVRBIl0sCiAgICAgICAgICAgICAg + ICAgICAgIm1heE1vbklkIjogIjAiLAogICAgICAgICAgICAgICAgICAgICJtYXBwaW5nIjogInt9 + IiwKICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAg + ICAgICAgICAgICJuYW1lIjogInJvb2stY2VwaC1tb24iLAogICAgICAgICAgICAgICAgImtpbmQi + OiAiU2VjcmV0IiwKICAgICAgICAgICAgICAgICJkYXRhIjogewogICAgICAgICAgICAgICAgICAg + ICJhZG1pbi1zZWNyZXQiOiAiYWRtaW4tc2VjcmV0IiwKICAgICAgICAgICAgICAgICAgICAiZnNp + ZCI6IHNlbGYub3V0X21hcFsiUk9PS19FWFRFUk5BTF9GU0lEIl0sCiAgICAgICAgICAgICAgICAg + ICAgIm1vbi1zZWNyZXQiOiAibW9uLXNlY3JldCIsCiAgICAgICAgICAgICAgICB9LAogICAgICAg + ICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAibmFtZSI6ICJyb29rLWNlcGgt + b3BlcmF0b3ItY3JlZHMiLAogICAgICAgICAgICAgICAgImtpbmQiOiAiU2VjcmV0IiwKICAgICAg + ICAgICAgICAgICJkYXRhIjogewogICAgICAgICAgICAgICAgICAgICJ1c2VySUQiOiBzZWxmLm91 + dF9tYXBbIlJPT0tfRVhURVJOQUxfVVNFUk5BTUUiXSwKICAgICAgICAgICAgICAgICAgICAidXNl + cktleSI6IHNlbGYub3V0X21hcFsiUk9PS19FWFRFUk5BTF9VU0VSX1NFQ1JFVCJdLAogICAgICAg + ICAgICAgICAgfSwKICAgICAgICAgICAgfSwKICAgICAgICBdCgogICAgICAgICMgaWYgJ01PTklU + T1JJTkdfRU5EUE9JTlQnIGV4aXN0cywgdGhlbiBvbmx5IGFkZCAnbW9uaXRvcmluZy1lbmRwb2lu + dCcgdG8gQ2x1c3RlcgogICAgICAgIGlmICgKICAgICAgICAgICAgc2VsZi5vdXRfbWFwWyJNT05J + VE9SSU5HX0VORFBPSU5UIl0KICAgICAgICAgICAgYW5kIHNlbGYub3V0X21hcFsiTU9OSVRPUklO + R19FTkRQT0lOVF9QT1JUIl0KICAgICAgICApOgogICAgICAgICAgICBqc29uX291dC5hcHBlbmQo + CiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgIm5hbWUiOiAibW9uaXRvcmlu + Zy1lbmRwb2ludCIsCiAgICAgICAgICAgICAgICAgICAgImtpbmQiOiAiQ2VwaENsdXN0ZXIiLAog + ICAgICAgICAgICAgICAgICAgICJkYXRhIjogewogICAgICAgICAgICAgICAgICAgICAgICAiTW9u + aXRvcmluZ0VuZHBvaW50Ijogc2VsZi5vdXRfbWFwWyJNT05JVE9SSU5HX0VORFBPSU5UIl0sCiAg + ICAgICAgICAgICAgICAgICAgICAgICJNb25pdG9yaW5nUG9ydCI6IHNlbGYub3V0X21hcFsiTU9O + SVRPUklOR19FTkRQT0lOVF9QT1JUIl0sCiAgICAgICAgICAgICAgICAgICAgfSwKICAgICAgICAg + ICAgICAgIH0KICAgICAgICAgICAgKQoKICAgICAgICAjIGlmICdDU0lfUkJEX05PREVfU0VDUkVU + JyBleGlzdHMsIHRoZW4gb25seSBhZGQgJ3Jvb2stY3NpLXJiZC1wcm92aXNpb25lcicgU2VjcmV0 + CiAgICAgICAgaWYgKAogICAgICAgICAgICBzZWxmLm91dF9tYXBbIkNTSV9SQkRfTk9ERV9TRUNS + RVQiXQogICAgICAgICAgICBhbmQgc2VsZi5vdXRfbWFwWyJDU0lfUkJEX05PREVfU0VDUkVUX05B + TUUiXQogICAgICAgICk6CiAgICAgICAgICAgIGpzb25fb3V0LmFwcGVuZCgKICAgICAgICAgICAg + ICAgIHsKICAgICAgICAgICAgICAgICAgICAibmFtZSI6IGYicm9vay17c2VsZi5vdXRfbWFwWydD + U0lfUkJEX05PREVfU0VDUkVUX05BTUUnXX0iLAogICAgICAgICAgICAgICAgICAgICJraW5kIjog + IlNlY3JldCIsCiAgICAgICAgICAgICAgICAgICAgImRhdGEiOiB7CiAgICAgICAgICAgICAgICAg + ICAgICAgICJ1c2VySUQiOiBzZWxmLm91dF9tYXBbIkNTSV9SQkRfTk9ERV9TRUNSRVRfTkFNRSJd + LAogICAgICAgICAgICAgICAgICAgICAgICAidXNlcktleSI6IHNlbGYub3V0X21hcFsiQ1NJX1JC + RF9OT0RFX1NFQ1JFVCJdLAogICAgICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICB9 + CiAgICAgICAgICAgICkKICAgICAgICAjIGlmICdDU0lfUkJEX1BST1ZJU0lPTkVSX1NFQ1JFVCcg + ZXhpc3RzLCB0aGVuIG9ubHkgYWRkICdyb29rLWNzaS1yYmQtcHJvdmlzaW9uZXInIFNlY3JldAog + ICAgICAgIGlmICgKICAgICAgICAgICAgc2VsZi5vdXRfbWFwWyJDU0lfUkJEX1BST1ZJU0lPTkVS + X1NFQ1JFVCJdCiAgICAgICAgICAgIGFuZCBzZWxmLm91dF9tYXBbIkNTSV9SQkRfUFJPVklTSU9O + RVJfU0VDUkVUX05BTUUiXQogICAgICAgICk6CiAgICAgICAgICAgIGpzb25fb3V0LmFwcGVuZCgK + ICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAibmFtZSI6IGYicm9vay17c2Vs + Zi5vdXRfbWFwWydDU0lfUkJEX1BST1ZJU0lPTkVSX1NFQ1JFVF9OQU1FJ119IiwKICAgICAgICAg ICAgICAgICAgICAia2luZCI6ICJTZWNyZXQiLAogICAgICAgICAgICAgICAgICAgICJkYXRhIjog ewogICAgICAgICAgICAgICAgICAgICAgICAidXNlcklEIjogc2VsZi5vdXRfbWFwWyJDU0lfUkJE - X05PREVfU0VDUkVUX05BTUUiXSwKICAgICAgICAgICAgICAgICAgICAgICAgInVzZXJLZXkiOiBz - ZWxmLm91dF9tYXBbIkNTSV9SQkRfTk9ERV9TRUNSRVQiXSwKICAgICAgICAgICAgICAgICAgICB9 - LAogICAgICAgICAgICAgICAgfQogICAgICAgICAgICApCiAgICAgICAgIyBpZiAnQ1NJX1JCRF9Q - Uk9WSVNJT05FUl9TRUNSRVQnIGV4aXN0cywgdGhlbiBvbmx5IGFkZCAncm9vay1jc2ktcmJkLXBy - b3Zpc2lvbmVyJyBTZWNyZXQKICAgICAgICBpZiAoCiAgICAgICAgICAgIHNlbGYub3V0X21hcFsi - Q1NJX1JCRF9QUk9WSVNJT05FUl9TRUNSRVQiXQogICAgICAgICAgICBhbmQgc2VsZi5vdXRfbWFw - WyJDU0lfUkJEX1BST1ZJU0lPTkVSX1NFQ1JFVF9OQU1FIl0KICAgICAgICApOgogICAgICAgICAg - ICBqc29uX291dC5hcHBlbmQoCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAg - Im5hbWUiOiBmInJvb2ste3NlbGYub3V0X21hcFsnQ1NJX1JCRF9QUk9WSVNJT05FUl9TRUNSRVRf - TkFNRSddfSIsCiAgICAgICAgICAgICAgICAgICAgImtpbmQiOiAiU2VjcmV0IiwKICAgICAgICAg - ICAgICAgICAgICAiZGF0YSI6IHsKICAgICAgICAgICAgICAgICAgICAgICAgInVzZXJJRCI6IHNl - bGYub3V0X21hcFsiQ1NJX1JCRF9QUk9WSVNJT05FUl9TRUNSRVRfTkFNRSJdLAogICAgICAgICAg - ICAgICAgICAgICAgICAidXNlcktleSI6IHNlbGYub3V0X21hcFsiQ1NJX1JCRF9QUk9WSVNJT05F - Ul9TRUNSRVQiXSwKICAgICAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAgfQogICAg - ICAgICAgICApCiAgICAgICAgIyBpZiAnQ1NJX0NFUEhGU19QUk9WSVNJT05FUl9TRUNSRVQnIGV4 - aXN0cywgdGhlbiBvbmx5IGFkZCAncm9vay1jc2ktY2VwaGZzLXByb3Zpc2lvbmVyJyBTZWNyZXQK - ICAgICAgICBpZiAoCiAgICAgICAgICAgIHNlbGYub3V0X21hcFsiQ1NJX0NFUEhGU19QUk9WSVNJ - T05FUl9TRUNSRVQiXQogICAgICAgICAgICBhbmQgc2VsZi5vdXRfbWFwWyJDU0lfQ0VQSEZTX1BS - T1ZJU0lPTkVSX1NFQ1JFVF9OQU1FIl0KICAgICAgICApOgogICAgICAgICAgICBqc29uX291dC5h - cHBlbmQoCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgIm5hbWUiOiBmInJv - b2ste3NlbGYub3V0X21hcFsnQ1NJX0NFUEhGU19QUk9WSVNJT05FUl9TRUNSRVRfTkFNRSddfSIs - CiAgICAgICAgICAgICAgICAgICAgImtpbmQiOiAiU2VjcmV0IiwKICAgICAgICAgICAgICAgICAg - ICAiZGF0YSI6IHsKICAgICAgICAgICAgICAgICAgICAgICAgImFkbWluSUQiOiBzZWxmLm91dF9t - YXBbIkNTSV9DRVBIRlNfUFJPVklTSU9ORVJfU0VDUkVUX05BTUUiXSwKICAgICAgICAgICAgICAg - ICAgICAgICAgImFkbWluS2V5Ijogc2VsZi5vdXRfbWFwWyJDU0lfQ0VQSEZTX1BST1ZJU0lPTkVS - X1NFQ1JFVCJdLAogICAgICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICB9CiAgICAg - ICAgICAgICkKICAgICAgICAjIGlmICdDU0lfQ0VQSEZTX05PREVfU0VDUkVUJyBleGlzdHMsIHRo - ZW4gb25seSBhZGQgJ3Jvb2stY3NpLWNlcGhmcy1ub2RlJyBTZWNyZXQKICAgICAgICBpZiAoCiAg - ICAgICAgICAgIHNlbGYub3V0X21hcFsiQ1NJX0NFUEhGU19OT0RFX1NFQ1JFVCJdCiAgICAgICAg - ICAgIGFuZCBzZWxmLm91dF9tYXBbIkNTSV9DRVBIRlNfTk9ERV9TRUNSRVRfTkFNRSJdCiAgICAg - ICAgKToKICAgICAgICAgICAganNvbl9vdXQuYXBwZW5kKAogICAgICAgICAgICAgICAgewogICAg - ICAgICAgICAgICAgICAgICJuYW1lIjogZiJyb29rLXtzZWxmLm91dF9tYXBbJ0NTSV9DRVBIRlNf - Tk9ERV9TRUNSRVRfTkFNRSddfSIsCiAgICAgICAgICAgICAgICAgICAgImtpbmQiOiAiU2VjcmV0 - IiwKICAgICAgICAgICAgICAgICAgICAiZGF0YSI6IHsKICAgICAgICAgICAgICAgICAgICAgICAg - ImFkbWluSUQiOiBzZWxmLm91dF9tYXBbIkNTSV9DRVBIRlNfTk9ERV9TRUNSRVRfTkFNRSJdLAog - ICAgICAgICAgICAgICAgICAgICAgICAiYWRtaW5LZXkiOiBzZWxmLm91dF9tYXBbIkNTSV9DRVBI - RlNfTk9ERV9TRUNSRVQiXSwKICAgICAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAg - fQogICAgICAgICAgICApCiAgICAgICAgIyBpZiAnUk9PS19FWFRFUk5BTF9EQVNIQk9BUkRfTElO - SycgZXhpc3RzLCB0aGVuIG9ubHkgYWRkICdyb29rLWNlcGgtZGFzaGJvYXJkLWxpbmsnIFNlY3Jl - dAogICAgICAgIGlmIHNlbGYub3V0X21hcFsiUk9PS19FWFRFUk5BTF9EQVNIQk9BUkRfTElOSyJd - OgogICAgICAgICAgICBqc29uX291dC5hcHBlbmQoCiAgICAgICAgICAgICAgICB7CiAgICAgICAg - ICAgICAgICAgICAgIm5hbWUiOiAicm9vay1jZXBoLWRhc2hib2FyZC1saW5rIiwKICAgICAgICAg - ICAgICAgICAgICAia2luZCI6ICJTZWNyZXQiLAogICAgICAgICAgICAgICAgICAgICJkYXRhIjog - ewogICAgICAgICAgICAgICAgICAgICAgICAidXNlcklEIjogImNlcGgtZGFzaGJvYXJkLWxpbmsi - LAogICAgICAgICAgICAgICAgICAgICAgICAidXNlcktleSI6IHNlbGYub3V0X21hcFsiUk9PS19F - WFRFUk5BTF9EQVNIQk9BUkRfTElOSyJdLAogICAgICAgICAgICAgICAgICAgIH0sCiAgICAgICAg - ICAgICAgICB9CiAgICAgICAgICAgICkKICAgICAgICAjIGlmICdSQURPU19OQU1FU1BBQ0UnIGV4 - aXN0cywgdGhlbiBvbmx5IGFkZCB0aGUgIlJBRE9TX05BTUVTUEFDRSIgbmFtZXNwYWNlCiAgICAg - ICAgaWYgKAogICAgICAgICAgICBzZWxmLm91dF9tYXBbIlJBRE9TX05BTUVTUEFDRSJdCiAgICAg - ICAgICAgIGFuZCBzZWxmLm91dF9tYXBbIlJFU1RSSUNURURfQVVUSF9QRVJNSVNTSU9OIl0KICAg - ICAgICAgICAgYW5kIG5vdCBzZWxmLm91dF9tYXBbIlJCRF9NRVRBREFUQV9FQ19QT09MX05BTUUi - XQogICAgICAgICk6CiAgICAgICAgICAgIGpzb25fb3V0LmFwcGVuZCgKICAgICAgICAgICAgICAg - IHsKICAgICAgICAgICAgICAgICAgICAibmFtZSI6ICJyYWRvcy1uYW1lc3BhY2UiLAogICAgICAg - ICAgICAgICAgICAgICJraW5kIjogIkNlcGhCbG9ja1Bvb2xSYWRvc05hbWVzcGFjZSIsCiAgICAg - ICAgICAgICAgICAgICAgImRhdGEiOiB7CiAgICAgICAgICAgICAgICAgICAgICAgICJyYWRvc05h - bWVzcGFjZU5hbWUiOiBzZWxmLm91dF9tYXBbIlJBRE9TX05BTUVTUEFDRSJdLAogICAgICAgICAg - ICAgICAgICAgICAgICAicG9vbCI6IHNlbGYub3V0X21hcFsiUkJEX1BPT0xfTkFNRSJdLAogICAg - ICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICkKICAgICAg + X1BST1ZJU0lPTkVSX1NFQ1JFVF9OQU1FIl0sCiAgICAgICAgICAgICAgICAgICAgICAgICJ1c2Vy + S2V5Ijogc2VsZi5vdXRfbWFwWyJDU0lfUkJEX1BST1ZJU0lPTkVSX1NFQ1JFVCJdLAogICAgICAg + ICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICkKICAgICAgICAj + IGlmICdDU0lfQ0VQSEZTX1BST1ZJU0lPTkVSX1NFQ1JFVCcgZXhpc3RzLCB0aGVuIG9ubHkgYWRk + ICdyb29rLWNzaS1jZXBoZnMtcHJvdmlzaW9uZXInIFNlY3JldAogICAgICAgIGlmICgKICAgICAg + ICAgICAgc2VsZi5vdXRfbWFwWyJDU0lfQ0VQSEZTX1BST1ZJU0lPTkVSX1NFQ1JFVCJdCiAgICAg + ICAgICAgIGFuZCBzZWxmLm91dF9tYXBbIkNTSV9DRVBIRlNfUFJPVklTSU9ORVJfU0VDUkVUX05B + TUUiXQogICAgICAgICk6CiAgICAgICAgICAgIGpzb25fb3V0LmFwcGVuZCgKICAgICAgICAgICAg + ICAgIHsKICAgICAgICAgICAgICAgICAgICAibmFtZSI6IGYicm9vay17c2VsZi5vdXRfbWFwWydD + U0lfQ0VQSEZTX1BST1ZJU0lPTkVSX1NFQ1JFVF9OQU1FJ119IiwKICAgICAgICAgICAgICAgICAg + ICAia2luZCI6ICJTZWNyZXQiLAogICAgICAgICAgICAgICAgICAgICJkYXRhIjogewogICAgICAg + ICAgICAgICAgICAgICAgICAiYWRtaW5JRCI6IHNlbGYub3V0X21hcFsiQ1NJX0NFUEhGU19QUk9W + SVNJT05FUl9TRUNSRVRfTkFNRSJdLAogICAgICAgICAgICAgICAgICAgICAgICAiYWRtaW5LZXki + OiBzZWxmLm91dF9tYXBbIkNTSV9DRVBIRlNfUFJPVklTSU9ORVJfU0VDUkVUIl0sCiAgICAgICAg + ICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgKQogICAgICAgICMg + aWYgJ0NTSV9DRVBIRlNfTk9ERV9TRUNSRVQnIGV4aXN0cywgdGhlbiBvbmx5IGFkZCAncm9vay1j + c2ktY2VwaGZzLW5vZGUnIFNlY3JldAogICAgICAgIGlmICgKICAgICAgICAgICAgc2VsZi5vdXRf + bWFwWyJDU0lfQ0VQSEZTX05PREVfU0VDUkVUIl0KICAgICAgICAgICAgYW5kIHNlbGYub3V0X21h + cFsiQ1NJX0NFUEhGU19OT0RFX1NFQ1JFVF9OQU1FIl0KICAgICAgICApOgogICAgICAgICAgICBq + c29uX291dC5hcHBlbmQoCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgIm5h + bWUiOiBmInJvb2ste3NlbGYub3V0X21hcFsnQ1NJX0NFUEhGU19OT0RFX1NFQ1JFVF9OQU1FJ119 + IiwKICAgICAgICAgICAgICAgICAgICAia2luZCI6ICJTZWNyZXQiLAogICAgICAgICAgICAgICAg + ICAgICJkYXRhIjogewogICAgICAgICAgICAgICAgICAgICAgICAiYWRtaW5JRCI6IHNlbGYub3V0 + X21hcFsiQ1NJX0NFUEhGU19OT0RFX1NFQ1JFVF9OQU1FIl0sCiAgICAgICAgICAgICAgICAgICAg + ICAgICJhZG1pbktleSI6IHNlbGYub3V0X21hcFsiQ1NJX0NFUEhGU19OT0RFX1NFQ1JFVCJdLAog + ICAgICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICkKICAg + ICAgICAjIGlmICdST09LX0VYVEVSTkFMX0RBU0hCT0FSRF9MSU5LJyBleGlzdHMsIHRoZW4gb25s + eSBhZGQgJ3Jvb2stY2VwaC1kYXNoYm9hcmQtbGluaycgU2VjcmV0CiAgICAgICAgaWYgc2VsZi5v + dXRfbWFwWyJST09LX0VYVEVSTkFMX0RBU0hCT0FSRF9MSU5LIl06CiAgICAgICAgICAgIGpzb25f + b3V0LmFwcGVuZCgKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAibmFtZSI6 + ICJyb29rLWNlcGgtZGFzaGJvYXJkLWxpbmsiLAogICAgICAgICAgICAgICAgICAgICJraW5kIjog + IlNlY3JldCIsCiAgICAgICAgICAgICAgICAgICAgImRhdGEiOiB7CiAgICAgICAgICAgICAgICAg + ICAgICAgICJ1c2VySUQiOiAiY2VwaC1kYXNoYm9hcmQtbGluayIsCiAgICAgICAgICAgICAgICAg + ICAgICAgICJ1c2VyS2V5Ijogc2VsZi5vdXRfbWFwWyJST09LX0VYVEVSTkFMX0RBU0hCT0FSRF9M + SU5LIl0sCiAgICAgICAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAgIH0KICAgICAgICAg + ICAgKQogICAgICAgICMgaWYgJ1JBRE9TX05BTUVTUEFDRScgZXhpc3RzLCB0aGVuIG9ubHkgYWRk + IHRoZSAiUkFET1NfTkFNRVNQQUNFIiBuYW1lc3BhY2UKICAgICAgICBpZiAoCiAgICAgICAgICAg + IHNlbGYub3V0X21hcFsiUkFET1NfTkFNRVNQQUNFIl0KICAgICAgICAgICAgYW5kIHNlbGYub3V0 + X21hcFsiUkVTVFJJQ1RFRF9BVVRIX1BFUk1JU1NJT04iXQogICAgICAgICAgICBhbmQgbm90IHNl + bGYub3V0X21hcFsiUkJEX01FVEFEQVRBX0VDX1BPT0xfTkFNRSJdCiAgICAgICAgKToKICAgICAg ICAgICAganNvbl9vdXQuYXBwZW5kKAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAg - ICAgICJuYW1lIjogImNlcGgtcmJkLXJhZG9zLW5hbWVzcGFjZSIsCiAgICAgICAgICAgICAgICAg - ICAgImtpbmQiOiAiU3RvcmFnZUNsYXNzIiwKICAgICAgICAgICAgICAgICAgICAiZGF0YSI6IHsK - ICAgICAgICAgICAgICAgICAgICAgICAgInBvb2wiOiBzZWxmLm91dF9tYXBbIlJCRF9QT09MX05B - TUUiXSwKICAgICAgICAgICAgICAgICAgICAgICAgImNzaS5zdG9yYWdlLms4cy5pby9wcm92aXNp - b25lci1zZWNyZXQtbmFtZSI6IGYicm9vay17c2VsZi5vdXRfbWFwWydDU0lfUkJEX1BST1ZJU0lP - TkVSX1NFQ1JFVF9OQU1FJ119IiwKICAgICAgICAgICAgICAgICAgICAgICAgImNzaS5zdG9yYWdl - Lms4cy5pby9jb250cm9sbGVyLWV4cGFuZC1zZWNyZXQtbmFtZSI6IGYicm9vay17c2VsZi5vdXRf - bWFwWydDU0lfUkJEX1BST1ZJU0lPTkVSX1NFQ1JFVF9OQU1FJ119IiwKICAgICAgICAgICAgICAg - ICAgICAgICAgImNzaS5zdG9yYWdlLms4cy5pby9ub2RlLXN0YWdlLXNlY3JldC1uYW1lIjogZiJy - b29rLXtzZWxmLm91dF9tYXBbJ0NTSV9SQkRfTk9ERV9TRUNSRVRfTkFNRSddfSIsCiAgICAgICAg - ICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgKQogICAgICAgIGVs - c2U6CiAgICAgICAgICAgIGlmIHNlbGYub3V0X21hcFsiUkJEX01FVEFEQVRBX0VDX1BPT0xfTkFN - RSJdOgogICAgICAgICAgICAgICAganNvbl9vdXQuYXBwZW5kKAogICAgICAgICAgICAgICAgICAg - IHsKICAgICAgICAgICAgICAgICAgICAgICAgIm5hbWUiOiAiY2VwaC1yYmQiLAogICAgICAgICAg - ICAgICAgICAgICAgICAia2luZCI6ICJTdG9yYWdlQ2xhc3MiLAogICAgICAgICAgICAgICAgICAg - ICAgICAiZGF0YSI6IHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJkYXRhUG9vbCI6IHNl - bGYub3V0X21hcFsiUkJEX1BPT0xfTkFNRSJdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAg - InBvb2wiOiBzZWxmLm91dF9tYXBbIlJCRF9NRVRBREFUQV9FQ19QT09MX05BTUUiXSwKICAgICAg - ICAgICAgICAgICAgICAgICAgICAgICJjc2kuc3RvcmFnZS5rOHMuaW8vcHJvdmlzaW9uZXItc2Vj - cmV0LW5hbWUiOiBmInJvb2ste3NlbGYub3V0X21hcFsnQ1NJX1JCRF9QUk9WSVNJT05FUl9TRUNS - RVRfTkFNRSddfSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY3NpLnN0b3JhZ2Uuazhz - LmlvL2NvbnRyb2xsZXItZXhwYW5kLXNlY3JldC1uYW1lIjogZiJyb29rLXtzZWxmLm91dF9tYXBb - J0NTSV9SQkRfUFJPVklTSU9ORVJfU0VDUkVUX05BTUUnXX0iLAogICAgICAgICAgICAgICAgICAg - ICAgICAgICAgImNzaS5zdG9yYWdlLms4cy5pby9ub2RlLXN0YWdlLXNlY3JldC1uYW1lIjogZiJy - b29rLXtzZWxmLm91dF9tYXBbJ0NTSV9SQkRfTk9ERV9TRUNSRVRfTkFNRSddfSIsCiAgICAgICAg - ICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAg - KQogICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAganNvbl9vdXQuYXBwZW5kKAogICAg - ICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAgICAgIm5hbWUiOiAiY2VwaC1y - YmQiLAogICAgICAgICAgICAgICAgICAgICAgICAia2luZCI6ICJTdG9yYWdlQ2xhc3MiLAogICAg - ICAgICAgICAgICAgICAgICAgICAiZGF0YSI6IHsKICAgICAgICAgICAgICAgICAgICAgICAgICAg - ICJwb29sIjogc2VsZi5vdXRfbWFwWyJSQkRfUE9PTF9OQU1FIl0sCiAgICAgICAgICAgICAgICAg + ICAgICJuYW1lIjogInJhZG9zLW5hbWVzcGFjZSIsCiAgICAgICAgICAgICAgICAgICAgImtpbmQi + OiAiQ2VwaEJsb2NrUG9vbFJhZG9zTmFtZXNwYWNlIiwKICAgICAgICAgICAgICAgICAgICAiZGF0 + YSI6IHsKICAgICAgICAgICAgICAgICAgICAgICAgInJhZG9zTmFtZXNwYWNlTmFtZSI6IHNlbGYu + b3V0X21hcFsiUkFET1NfTkFNRVNQQUNFIl0sCiAgICAgICAgICAgICAgICAgICAgICAgICJwb29s + Ijogc2VsZi5vdXRfbWFwWyJSQkRfUE9PTF9OQU1FIl0sCiAgICAgICAgICAgICAgICAgICAgfSwK + ICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgKQogICAgICAgICAgICBqc29uX291dC5hcHBl + bmQoCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgIm5hbWUiOiAiY2VwaC1y + YmQtcmFkb3MtbmFtZXNwYWNlIiwKICAgICAgICAgICAgICAgICAgICAia2luZCI6ICJTdG9yYWdl + Q2xhc3MiLAogICAgICAgICAgICAgICAgICAgICJkYXRhIjogewogICAgICAgICAgICAgICAgICAg + ICAgICAicG9vbCI6IHNlbGYub3V0X21hcFsiUkJEX1BPT0xfTkFNRSJdLAogICAgICAgICAgICAg ICAgICAgICAgICAiY3NpLnN0b3JhZ2UuazhzLmlvL3Byb3Zpc2lvbmVyLXNlY3JldC1uYW1lIjog ZiJyb29rLXtzZWxmLm91dF9tYXBbJ0NTSV9SQkRfUFJPVklTSU9ORVJfU0VDUkVUX05BTUUnXX0i - LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgImNzaS5zdG9yYWdlLms4cy5pby9jb250cm9s - bGVyLWV4cGFuZC1zZWNyZXQtbmFtZSI6IGYicm9vay17c2VsZi5vdXRfbWFwWydDU0lfUkJEX1BS - T1ZJU0lPTkVSX1NFQ1JFVF9OQU1FJ119IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJj - c2kuc3RvcmFnZS5rOHMuaW8vbm9kZS1zdGFnZS1zZWNyZXQtbmFtZSI6IGYicm9vay17c2VsZi5v - dXRfbWFwWydDU0lfUkJEX05PREVfU0VDUkVUX05BTUUnXX0iLAogICAgICAgICAgICAgICAgICAg - ICAgICB9LAogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKCiAgICAgICAg - IyBpZiAnVE9QT0xPR1lfUE9PTFMnLCAnVE9QT0xPR1lfRkFJTFVSRV9ET01BSU5fTEFCRUwnLCAn - VE9QT0xPR1lfRkFJTFVSRV9ET01BSU5fVkFMVUVTJyAgZXhpc3RzLAogICAgICAgICMgdGhlbiBv - bmx5IGFkZCAndG9wb2xvZ3knIFN0b3JhZ2VDbGFzcwogICAgICAgIGlmICgKICAgICAgICAgICAg - c2VsZi5vdXRfbWFwWyJUT1BPTE9HWV9QT09MUyJdCiAgICAgICAgICAgIGFuZCBzZWxmLm91dF9t - YXBbIlRPUE9MT0dZX0ZBSUxVUkVfRE9NQUlOX0xBQkVMIl0KICAgICAgICAgICAgYW5kIHNlbGYu - b3V0X21hcFsiVE9QT0xPR1lfRkFJTFVSRV9ET01BSU5fVkFMVUVTIl0KICAgICAgICApOgogICAg - ICAgICAgICBqc29uX291dC5hcHBlbmQoCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAg - ICAgICAgIm5hbWUiOiAiY2VwaC1yYmQtdG9wb2xvZ3kiLAogICAgICAgICAgICAgICAgICAgICJr - aW5kIjogIlN0b3JhZ2VDbGFzcyIsCiAgICAgICAgICAgICAgICAgICAgImRhdGEiOiB7CiAgICAg - ICAgICAgICAgICAgICAgICAgICJ0b3BvbG9neUZhaWx1cmVEb21haW5MYWJlbCI6IHNlbGYub3V0 - X21hcFsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUT1BPTE9HWV9GQUlMVVJFX0RPTUFJ - Tl9MQUJFTCIKICAgICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAg - ICAgInRvcG9sb2d5RmFpbHVyZURvbWFpblZhbHVlcyI6IHNlbGYub3V0X21hcFsKICAgICAgICAg - ICAgICAgICAgICAgICAgICAgICJUT1BPTE9HWV9GQUlMVVJFX0RPTUFJTl9WQUxVRVMiCiAgICAg - ICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgICAgICJ0b3BvbG9neVBv - b2xzIjogc2VsZi5vdXRfbWFwWyJUT1BPTE9HWV9QT09MUyJdLAogICAgICAgICAgICAgICAgICAg - ICAgICAiY3NpLnN0b3JhZ2UuazhzLmlvL3Byb3Zpc2lvbmVyLXNlY3JldC1uYW1lIjogZiJyb29r - LXtzZWxmLm91dF9tYXBbJ0NTSV9SQkRfUFJPVklTSU9ORVJfU0VDUkVUX05BTUUnXX0iLAogICAg - ICAgICAgICAgICAgICAgICAgICAiY3NpLnN0b3JhZ2UuazhzLmlvL2NvbnRyb2xsZXItZXhwYW5k - LXNlY3JldC1uYW1lIjogZiJyb29rLXtzZWxmLm91dF9tYXBbJ0NTSV9SQkRfUFJPVklTSU9ORVJf - U0VDUkVUX05BTUUnXX0iLAogICAgICAgICAgICAgICAgICAgICAgICAiY3NpLnN0b3JhZ2Uuazhz - LmlvL25vZGUtc3RhZ2Utc2VjcmV0LW5hbWUiOiBmInJvb2ste3NlbGYub3V0X21hcFsnQ1NJX1JC - RF9OT0RFX1NFQ1JFVF9OQU1FJ119IiwKICAgICAgICAgICAgICAgICAgICB9LAogICAgICAgICAg - ICAgICAgfQogICAgICAgICAgICApCgogICAgICAgICMgaWYgJ0NFUEhGU19GU19OQU1FJyBleGlz - dHMsIHRoZW4gb25seSBhZGQgJ2NlcGhmcycgU3RvcmFnZUNsYXNzCiAgICAgICAgaWYgc2VsZi5v - dXRfbWFwWyJDRVBIRlNfRlNfTkFNRSJdOgogICAgICAgICAgICBqc29uX291dC5hcHBlbmQoCiAg - ICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgIm5hbWUiOiAiY2VwaGZzIiwKICAg - ICAgICAgICAgICAgICAgICAia2luZCI6ICJTdG9yYWdlQ2xhc3MiLAogICAgICAgICAgICAgICAg - ICAgICJkYXRhIjogewogICAgICAgICAgICAgICAgICAgICAgICAiZnNOYW1lIjogc2VsZi5vdXRf - bWFwWyJDRVBIRlNfRlNfTkFNRSJdLAogICAgICAgICAgICAgICAgICAgICAgICAicG9vbCI6IHNl - bGYub3V0X21hcFsiQ0VQSEZTX1BPT0xfTkFNRSJdLAogICAgICAgICAgICAgICAgICAgICAgICAi - Y3NpLnN0b3JhZ2UuazhzLmlvL3Byb3Zpc2lvbmVyLXNlY3JldC1uYW1lIjogZiJyb29rLXtzZWxm - Lm91dF9tYXBbJ0NTSV9DRVBIRlNfUFJPVklTSU9ORVJfU0VDUkVUX05BTUUnXX0iLAogICAgICAg - ICAgICAgICAgICAgICAgICAiY3NpLnN0b3JhZ2UuazhzLmlvL2NvbnRyb2xsZXItZXhwYW5kLXNl - Y3JldC1uYW1lIjogZiJyb29rLXtzZWxmLm91dF9tYXBbJ0NTSV9DRVBIRlNfUFJPVklTSU9ORVJf - U0VDUkVUX05BTUUnXX0iLAogICAgICAgICAgICAgICAgICAgICAgICAiY3NpLnN0b3JhZ2Uuazhz - LmlvL25vZGUtc3RhZ2Utc2VjcmV0LW5hbWUiOiBmInJvb2ste3NlbGYub3V0X21hcFsnQ1NJX0NF - UEhGU19OT0RFX1NFQ1JFVF9OQU1FJ119IiwKICAgICAgICAgICAgICAgICAgICB9LAogICAgICAg - ICAgICAgICAgfQogICAgICAgICAgICApCiAgICAgICAgIyBpZiAnUkdXX0VORFBPSU5UJyBleGlz - dHMsIHRoZW4gb25seSBhZGQgJ2NlcGgtcmd3JyBTdG9yYWdlQ2xhc3MKICAgICAgICBpZiBzZWxm - Lm91dF9tYXBbIlJHV19FTkRQT0lOVCJdOgogICAgICAgICAgICBqc29uX291dC5hcHBlbmQoCiAg - ICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgIm5hbWUiOiAiY2VwaC1yZ3ciLAog - ICAgICAgICAgICAgICAgICAgICJraW5kIjogIlN0b3JhZ2VDbGFzcyIsCiAgICAgICAgICAgICAg - ICAgICAgImRhdGEiOiB7CiAgICAgICAgICAgICAgICAgICAgICAgICJlbmRwb2ludCI6IHNlbGYu - b3V0X21hcFsiUkdXX0VORFBPSU5UIl0sCiAgICAgICAgICAgICAgICAgICAgICAgICJwb29sUHJl - Zml4Ijogc2VsZi5vdXRfbWFwWyJSR1dfUE9PTF9QUkVGSVgiXSwKICAgICAgICAgICAgICAgICAg - ICB9LAogICAgICAgICAgICAgICAgfQogICAgICAgICAgICApCiAgICAgICAgICAgIGpzb25fb3V0 - LmFwcGVuZCgKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAibmFtZSI6ICJy - Z3ctYWRtaW4tb3BzLXVzZXIiLAogICAgICAgICAgICAgICAgICAgICJraW5kIjogIlNlY3JldCIs - CiAgICAgICAgICAgICAgICAgICAgImRhdGEiOiB7CiAgICAgICAgICAgICAgICAgICAgICAgICJh - Y2Nlc3NLZXkiOiBzZWxmLm91dF9tYXBbIlJHV19BRE1JTl9PUFNfVVNFUl9BQ0NFU1NfS0VZIl0s - CiAgICAgICAgICAgICAgICAgICAgICAgICJzZWNyZXRLZXkiOiBzZWxmLm91dF9tYXBbIlJHV19B - RE1JTl9PUFNfVVNFUl9TRUNSRVRfS0VZIl0sCiAgICAgICAgICAgICAgICAgICAgfSwKICAgICAg - ICAgICAgICAgIH0KICAgICAgICAgICAgKQogICAgICAgICMgaWYgJ1JHV19UTFNfQ0VSVCcgZXhp - c3RzLCB0aGVuIG9ubHkgYWRkIHRoZSAiY2VwaC1yZ3ctdGxzLWNlcnQiIHNlY3JldAogICAgICAg - IGlmIHNlbGYub3V0X21hcFsiUkdXX1RMU19DRVJUIl06CiAgICAgICAgICAgIGpzb25fb3V0LmFw + LAogICAgICAgICAgICAgICAgICAgICAgICAiY3NpLnN0b3JhZ2UuazhzLmlvL2NvbnRyb2xsZXIt + ZXhwYW5kLXNlY3JldC1uYW1lIjogZiJyb29rLXtzZWxmLm91dF9tYXBbJ0NTSV9SQkRfUFJPVklT + SU9ORVJfU0VDUkVUX05BTUUnXX0iLAogICAgICAgICAgICAgICAgICAgICAgICAiY3NpLnN0b3Jh + Z2UuazhzLmlvL25vZGUtc3RhZ2Utc2VjcmV0LW5hbWUiOiBmInJvb2ste3NlbGYub3V0X21hcFsn + Q1NJX1JCRF9OT0RFX1NFQ1JFVF9OQU1FJ119IiwKICAgICAgICAgICAgICAgICAgICB9LAogICAg + ICAgICAgICAgICAgfQogICAgICAgICAgICApCiAgICAgICAgZWxzZToKICAgICAgICAgICAgaWYg + c2VsZi5vdXRfbWFwWyJSQkRfTUVUQURBVEFfRUNfUE9PTF9OQU1FIl06CiAgICAgICAgICAgICAg + ICBqc29uX291dC5hcHBlbmQoCiAgICAgICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAg + ICAgICAgICAibmFtZSI6ICJjZXBoLXJiZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICJraW5k + IjogIlN0b3JhZ2VDbGFzcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICJkYXRhIjogewogICAg + ICAgICAgICAgICAgICAgICAgICAgICAgImRhdGFQb29sIjogc2VsZi5vdXRfbWFwWyJSQkRfUE9P + TF9OQU1FIl0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAicG9vbCI6IHNlbGYub3V0X21h + cFsiUkJEX01FVEFEQVRBX0VDX1BPT0xfTkFNRSJdLAogICAgICAgICAgICAgICAgICAgICAgICAg + ICAgImNzaS5zdG9yYWdlLms4cy5pby9wcm92aXNpb25lci1zZWNyZXQtbmFtZSI6IGYicm9vay17 + c2VsZi5vdXRfbWFwWydDU0lfUkJEX1BST1ZJU0lPTkVSX1NFQ1JFVF9OQU1FJ119IiwKICAgICAg + ICAgICAgICAgICAgICAgICAgICAgICJjc2kuc3RvcmFnZS5rOHMuaW8vY29udHJvbGxlci1leHBh + bmQtc2VjcmV0LW5hbWUiOiBmInJvb2ste3NlbGYub3V0X21hcFsnQ1NJX1JCRF9QUk9WSVNJT05F + Ul9TRUNSRVRfTkFNRSddfSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY3NpLnN0b3Jh + Z2UuazhzLmlvL25vZGUtc3RhZ2Utc2VjcmV0LW5hbWUiOiBmInJvb2ste3NlbGYub3V0X21hcFsn + Q1NJX1JCRF9OT0RFX1NFQ1JFVF9OQU1FJ119IiwKICAgICAgICAgICAgICAgICAgICAgICAgfSwK + ICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgIGVsc2U6 + CiAgICAgICAgICAgICAgICBqc29uX291dC5hcHBlbmQoCiAgICAgICAgICAgICAgICAgICAgewog + ICAgICAgICAgICAgICAgICAgICAgICAibmFtZSI6ICJjZXBoLXJiZCIsCiAgICAgICAgICAgICAg + ICAgICAgICAgICJraW5kIjogIlN0b3JhZ2VDbGFzcyIsCiAgICAgICAgICAgICAgICAgICAgICAg + ICJkYXRhIjogewogICAgICAgICAgICAgICAgICAgICAgICAgICAgInBvb2wiOiBzZWxmLm91dF9t + YXBbIlJCRF9QT09MX05BTUUiXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjc2kuc3Rv + cmFnZS5rOHMuaW8vcHJvdmlzaW9uZXItc2VjcmV0LW5hbWUiOiBmInJvb2ste3NlbGYub3V0X21h + cFsnQ1NJX1JCRF9QUk9WSVNJT05FUl9TRUNSRVRfTkFNRSddfSIsCiAgICAgICAgICAgICAgICAg + ICAgICAgICAgICAiY3NpLnN0b3JhZ2UuazhzLmlvL2NvbnRyb2xsZXItZXhwYW5kLXNlY3JldC1u + YW1lIjogZiJyb29rLXtzZWxmLm91dF9tYXBbJ0NTSV9SQkRfUFJPVklTSU9ORVJfU0VDUkVUX05B + TUUnXX0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgImNzaS5zdG9yYWdlLms4cy5pby9u + b2RlLXN0YWdlLXNlY3JldC1uYW1lIjogZiJyb29rLXtzZWxmLm91dF9tYXBbJ0NTSV9SQkRfTk9E + RV9TRUNSRVRfTkFNRSddfSIsCiAgICAgICAgICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAg + ICAgICAgICAgfQogICAgICAgICAgICAgICAgKQoKICAgICAgICAjIGlmICdUT1BPTE9HWV9QT09M + UycsICdUT1BPTE9HWV9GQUlMVVJFX0RPTUFJTl9MQUJFTCcsICdUT1BPTE9HWV9GQUlMVVJFX0RP + TUFJTl9WQUxVRVMnICBleGlzdHMsCiAgICAgICAgIyB0aGVuIG9ubHkgYWRkICd0b3BvbG9neScg + U3RvcmFnZUNsYXNzCiAgICAgICAgaWYgKAogICAgICAgICAgICBzZWxmLm91dF9tYXBbIlRPUE9M + T0dZX1BPT0xTIl0KICAgICAgICAgICAgYW5kIHNlbGYub3V0X21hcFsiVE9QT0xPR1lfRkFJTFVS + RV9ET01BSU5fTEFCRUwiXQogICAgICAgICAgICBhbmQgc2VsZi5vdXRfbWFwWyJUT1BPTE9HWV9G + QUlMVVJFX0RPTUFJTl9WQUxVRVMiXQogICAgICAgICk6CiAgICAgICAgICAgIGpzb25fb3V0LmFw cGVuZCgKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAibmFtZSI6ICJjZXBo - LXJndy10bHMtY2VydCIsCiAgICAgICAgICAgICAgICAgICAgImtpbmQiOiAiU2VjcmV0IiwKICAg - ICAgICAgICAgICAgICAgICAiZGF0YSI6IHsKICAgICAgICAgICAgICAgICAgICAgICAgImNlcnQi - OiBzZWxmLm91dF9tYXBbIlJHV19UTFNfQ0VSVCJdLAogICAgICAgICAgICAgICAgICAgIH0sCiAg - ICAgICAgICAgICAgICB9CiAgICAgICAgICAgICkKCiAgICAgICAgcmV0dXJuIGpzb24uZHVtcHMo - anNvbl9vdXQpICsgTElORVNFUAoKICAgIGRlZiB1cGdyYWRlX3VzZXJzX3Blcm1pc3Npb25zKHNl - bGYpOgogICAgICAgIHVzZXJzID0gWwogICAgICAgICAgICAiY2xpZW50LmNzaS1jZXBoZnMtbm9k - ZSIsCiAgICAgICAgICAgICJjbGllbnQuY3NpLWNlcGhmcy1wcm92aXNpb25lciIsCiAgICAgICAg - ICAgICJjbGllbnQuY3NpLXJiZC1ub2RlIiwKICAgICAgICAgICAgImNsaWVudC5jc2ktcmJkLXBy - b3Zpc2lvbmVyIiwKICAgICAgICAgICAgImNsaWVudC5oZWFsdGhjaGVja2VyIiwKICAgICAgICBd - CiAgICAgICAgaWYgc2VsZi5ydW5fYXNfdXNlciAhPSAiIiBhbmQgc2VsZi5ydW5fYXNfdXNlciBu - b3QgaW4gdXNlcnM6CiAgICAgICAgICAgIHVzZXJzLmFwcGVuZChzZWxmLnJ1bl9hc191c2VyKQog - ICAgICAgIGZvciB1c2VyIGluIHVzZXJzOgogICAgICAgICAgICBzZWxmLnVwZ3JhZGVfdXNlcl9w - ZXJtaXNzaW9ucyh1c2VyKQoKICAgIGRlZiBnZXRfcmd3X3Bvb2xfbmFtZV9kdXJpbmdfdXBncmFk - ZShzZWxmLCB1c2VyLCBjYXBzKToKICAgICAgICBpZiB1c2VyID09ICJjbGllbnQuaGVhbHRoY2hl - Y2tlciI6CiAgICAgICAgICAgICMgd2hlbiBhZG1pbiBoYXMgbm90IHByb3ZpZGVkIHJndyBwb29s - IG5hbWUgZHVyaW5nIHVwZ3JhZGUsCiAgICAgICAgICAgICMgZ2V0IHRoZSByZ3cgcG9vbCBuYW1l - IGZyb20gY2xpZW50LmhlYWx0aGNoZWNrZXIgdXNlciB3aGljaCB3YXMgdXNlZCBkdXJpbmcgY29u - bmVjdGlvbgogICAgICAgICAgICBpZiBub3Qgc2VsZi5fYXJnX3BhcnNlci5yZ3dfcG9vbF9wcmVm - aXg6CiAgICAgICAgICAgICAgICAjIFRvIGdldCB2YWx1ZSAnZGVmYXVsdCcgd2hpY2ggaXMgcmd3 - IHBvb2wgbmFtZSBmcm9tICdhbGxvdyByd3ggcG9vbD1kZWZhdWx0LnJndy5tZXRhJwogICAgICAg - ICAgICAgICAgcGF0dGVybiA9IHIicG9vbD0oLio/KVwucmd3XC5tZXRhIgogICAgICAgICAgICAg - ICAgbWF0Y2ggPSByZS5zZWFyY2gocGF0dGVybiwgY2FwcykKICAgICAgICAgICAgICAgIGlmIG1h - dGNoOgogICAgICAgICAgICAgICAgICAgIHNlbGYuX2FyZ19wYXJzZXIucmd3X3Bvb2xfcHJlZml4 - ID0gbWF0Y2guZ3JvdXAoMSkKICAgICAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICAg - ICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlvbigKICAgICAgICAgICAgICAgICAgICAg - ICAgImZhaWxlZCB0byBnZXQgcmd3IHBvb2wgbmFtZSBmb3IgdXBncmFkZSIKICAgICAgICAgICAg - ICAgICAgICApCgogICAgZGVmIHVwZ3JhZGVfdXNlcl9wZXJtaXNzaW9ucyhzZWxmLCB1c2VyKToK - ICAgICAgICAjIGNoZWNrIHdoZXRoZXIgdGhlIGdpdmVuIHVzZXIgZXhpc3RzIG9yIG5vdAogICAg - ICAgIGNtZF9qc29uID0geyJwcmVmaXgiOiAiYXV0aCBnZXQiLCAiZW50aXR5IjogZiJ7dXNlcn0i - LCAiZm9ybWF0IjogImpzb24ifQogICAgICAgIHJldF92YWwsIGpzb25fb3V0LCBlcnJfbXNnID0g - c2VsZi5fY29tbW9uX2NtZF9qc29uX2dlbihjbWRfanNvbikKICAgICAgICBpZiByZXRfdmFsICE9 - IDAgb3IgbGVuKGpzb25fb3V0KSA9PSAwOgogICAgICAgICAgICBwcmludChmInVzZXIge3VzZXJ9 - IG5vdCBmb3VuZCBmb3IgdXBncmFkaW5nLiIpCiAgICAgICAgICAgIHJldHVybgogICAgICAgIGV4 - aXN0aW5nX2NhcHMgPSBqc29uX291dFswXVsiY2FwcyJdCiAgICAgICAgc2VsZi5nZXRfcmd3X3Bv - b2xfbmFtZV9kdXJpbmdfdXBncmFkZSh1c2VyLCBzdHIoZXhpc3RpbmdfY2FwcykpCiAgICAgICAg - bmV3X2NhcCwgXyA9IHNlbGYuZ2V0X2NhcHNfYW5kX2VudGl0eSh1c2VyKQogICAgICAgIGNhcF9r - ZXlzID0gWyJtb24iLCAibWdyIiwgIm9zZCIsICJtZHMiXQogICAgICAgIGNhcHMgPSBbXQogICAg - ICAgIGZvciBlYWNoQ2FwIGluIGNhcF9rZXlzOgogICAgICAgICAgICBjdXJfY2FwX3ZhbHVlcyA9 - IGV4aXN0aW5nX2NhcHMuZ2V0KGVhY2hDYXAsICIiKQogICAgICAgICAgICBuZXdfY2FwX3ZhbHVl - cyA9IG5ld19jYXAuZ2V0KGVhY2hDYXAsICIiKQogICAgICAgICAgICBjdXJfY2FwX3Blcm1fbGlz - dCA9IFsKICAgICAgICAgICAgICAgIHguc3RyaXAoKSBmb3IgeCBpbiBjdXJfY2FwX3ZhbHVlcy5z - cGxpdCgiLCIpIGlmIHguc3RyaXAoKQogICAgICAgICAgICBdCiAgICAgICAgICAgIG5ld19jYXBf - cGVybV9saXN0ID0gWwogICAgICAgICAgICAgICAgeC5zdHJpcCgpIGZvciB4IGluIG5ld19jYXBf - dmFsdWVzLnNwbGl0KCIsIikgaWYgeC5zdHJpcCgpCiAgICAgICAgICAgIF0KICAgICAgICAgICAg - IyBhcHBlbmQgbmV3X2NhcF9saXN0IHRvIGN1cl9jYXBfbGlzdCB0byBtYWludGFpbiB0aGUgb3Jk - ZXIgb2YgY2FwcwogICAgICAgICAgICBjdXJfY2FwX3Blcm1fbGlzdC5leHRlbmQobmV3X2NhcF9w - ZXJtX2xpc3QpCiAgICAgICAgICAgICMgZWxpbWluYXRlIGR1cGxpY2F0ZXMgd2l0aG91dCB1c2lu - ZyAnc2V0JwogICAgICAgICAgICAjIHNldCByZS1vcmRlcnMgaXRlbXMgaW4gdGhlIGxpc3QgYW5k - IHdlIGhhdmUgdG8ga2VlcCB0aGUgb3JkZXIKICAgICAgICAgICAgbmV3X2NhcF9saXN0ID0gW10K - ICAgICAgICAgICAgW25ld19jYXBfbGlzdC5hcHBlbmQoeCkgZm9yIHggaW4gY3VyX2NhcF9wZXJt - X2xpc3QgaWYgeCBub3QgaW4gbmV3X2NhcF9saXN0XQogICAgICAgICAgICBleGlzdGluZ19jYXBz - W2VhY2hDYXBdID0gIiwgIi5qb2luKG5ld19jYXBfbGlzdCkKICAgICAgICAgICAgaWYgZXhpc3Rp - bmdfY2Fwc1tlYWNoQ2FwXToKICAgICAgICAgICAgICAgIGNhcHMuYXBwZW5kKGVhY2hDYXApCiAg - ICAgICAgICAgICAgICBjYXBzLmFwcGVuZChleGlzdGluZ19jYXBzW2VhY2hDYXBdKQogICAgICAg - IGNtZF9qc29uID0gewogICAgICAgICAgICAicHJlZml4IjogImF1dGggY2FwcyIsCiAgICAgICAg - ICAgICJlbnRpdHkiOiB1c2VyLAogICAgICAgICAgICAiY2FwcyI6IGNhcHMsCiAgICAgICAgICAg - ICJmb3JtYXQiOiAianNvbiIsCiAgICAgICAgfQogICAgICAgIHJldF92YWwsIGpzb25fb3V0LCBl - cnJfbXNnID0gc2VsZi5fY29tbW9uX2NtZF9qc29uX2dlbihjbWRfanNvbikKICAgICAgICBpZiBy - ZXRfdmFsICE9IDA6CiAgICAgICAgICAgIHJhaXNlIEV4ZWN1dGlvbkZhaWx1cmVFeGNlcHRpb24o - CiAgICAgICAgICAgICAgICBmIidhdXRoIGNhcHMge3VzZXJ9JyBjb21tYW5kIGZhaWxlZC5cbiBF - cnJvcjoge2Vycl9tc2d9IgogICAgICAgICAgICApCiAgICAgICAgcHJpbnQoZiJVcGRhdGVkIHVz - ZXIge3VzZXJ9IHN1Y2Nlc3NmdWxseS4iKQoKICAgIGRlZiBtYWluKHNlbGYpOgogICAgICAgIGdl - bmVyYXRlZF9vdXRwdXQgPSAiIgogICAgICAgIGlmIHNlbGYuX2FyZ19wYXJzZXIudXBncmFkZToK - ICAgICAgICAgICAgc2VsZi51cGdyYWRlX3VzZXJzX3Blcm1pc3Npb25zKCkKICAgICAgICBlbGlm - IHNlbGYuX2FyZ19wYXJzZXIuZm9ybWF0ID09ICJqc29uIjoKICAgICAgICAgICAgZ2VuZXJhdGVk - X291dHB1dCA9IHNlbGYuZ2VuX2pzb25fb3V0KCkKICAgICAgICBlbGlmIHNlbGYuX2FyZ19wYXJz - ZXIuZm9ybWF0ID09ICJiYXNoIjoKICAgICAgICAgICAgZ2VuZXJhdGVkX291dHB1dCA9IHNlbGYu - Z2VuX3NoZWxsX291dCgpCiAgICAgICAgZWxzZToKICAgICAgICAgICAgcmFpc2UgRXhlY3V0aW9u - RmFpbHVyZUV4Y2VwdGlvbigKICAgICAgICAgICAgICAgIGYiVW5zdXBwb3J0ZWQgZm9ybWF0OiB7 - c2VsZi5fYXJnX3BhcnNlci5mb3JtYXR9IgogICAgICAgICAgICApCiAgICAgICAgcHJpbnQoZ2Vu - ZXJhdGVkX291dHB1dCkKICAgICAgICBpZiBzZWxmLm91dHB1dF9maWxlIGFuZCBnZW5lcmF0ZWRf - b3V0cHV0OgogICAgICAgICAgICBmT3V0ID0gb3BlbihzZWxmLm91dHB1dF9maWxlLCBtb2RlPSJ3 - IiwgZW5jb2Rpbmc9IlVURi04IikKICAgICAgICAgICAgZk91dC53cml0ZShnZW5lcmF0ZWRfb3V0 - cHV0KQogICAgICAgICAgICBmT3V0LmNsb3NlKCkKCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMj - IyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIE1BSU4gIyMjIyMj - IyMjIyMjIyMjIyMjIyMjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMj - IyMjIyMjIwppZiBfX25hbWVfXyA9PSAiX19tYWluX18iOgogICAgcmpPYmogPSBSYWRvc0pTT04o - KQogICAgdHJ5OgogICAgICAgIHJqT2JqLm1haW4oKQogICAgZXhjZXB0IEV4ZWN1dGlvbkZhaWx1 - cmVFeGNlcHRpb24gYXMgZXJyOgogICAgICAgIHByaW50KGYiRXhlY3V0aW9uIEZhaWxlZDoge2Vy - cn0iKQogICAgICAgIHJhaXNlIGVycgogICAgZXhjZXB0IEtleUVycm9yIGFzIGtFcnI6CiAgICAg - ICAgcHJpbnQoZiJLZXlFcnJvcjoge2tFcnJ9IikKICAgIGV4Y2VwdCBPU0Vycm9yIGFzIG9zRXJy - OgogICAgICAgIHByaW50KGYiRXJyb3Igd2hpbGUgdHJ5aW5nIHRvIG91dHB1dCB0aGUgZGF0YTog - e29zRXJyfSIpCiAgICBmaW5hbGx5OgogICAgICAgIHJqT2JqLnNodXRkb3duKCkK + LXJiZC10b3BvbG9neSIsCiAgICAgICAgICAgICAgICAgICAgImtpbmQiOiAiU3RvcmFnZUNsYXNz + IiwKICAgICAgICAgICAgICAgICAgICAiZGF0YSI6IHsKICAgICAgICAgICAgICAgICAgICAgICAg + InRvcG9sb2d5RmFpbHVyZURvbWFpbkxhYmVsIjogc2VsZi5vdXRfbWFwWwogICAgICAgICAgICAg + ICAgICAgICAgICAgICAgIlRPUE9MT0dZX0ZBSUxVUkVfRE9NQUlOX0xBQkVMIgogICAgICAgICAg + ICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICAgICAidG9wb2xvZ3lGYWlsdXJl + RG9tYWluVmFsdWVzIjogc2VsZi5vdXRfbWFwWwogICAgICAgICAgICAgICAgICAgICAgICAgICAg + IlRPUE9MT0dZX0ZBSUxVUkVfRE9NQUlOX1ZBTFVFUyIKICAgICAgICAgICAgICAgICAgICAgICAg + XSwKICAgICAgICAgICAgICAgICAgICAgICAgInRvcG9sb2d5UG9vbHMiOiBzZWxmLm91dF9tYXBb + IlRPUE9MT0dZX1BPT0xTIl0sCiAgICAgICAgICAgICAgICAgICAgICAgICJjc2kuc3RvcmFnZS5r + OHMuaW8vcHJvdmlzaW9uZXItc2VjcmV0LW5hbWUiOiBmInJvb2ste3NlbGYub3V0X21hcFsnQ1NJ + X1JCRF9QUk9WSVNJT05FUl9TRUNSRVRfTkFNRSddfSIsCiAgICAgICAgICAgICAgICAgICAgICAg + ICJjc2kuc3RvcmFnZS5rOHMuaW8vY29udHJvbGxlci1leHBhbmQtc2VjcmV0LW5hbWUiOiBmInJv + b2ste3NlbGYub3V0X21hcFsnQ1NJX1JCRF9QUk9WSVNJT05FUl9TRUNSRVRfTkFNRSddfSIsCiAg + ICAgICAgICAgICAgICAgICAgICAgICJjc2kuc3RvcmFnZS5rOHMuaW8vbm9kZS1zdGFnZS1zZWNy + ZXQtbmFtZSI6IGYicm9vay17c2VsZi5vdXRfbWFwWydDU0lfUkJEX05PREVfU0VDUkVUX05BTUUn + XX0iLAogICAgICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAg + ICkKCiAgICAgICAgIyBpZiAnQ0VQSEZTX0ZTX05BTUUnIGV4aXN0cywgdGhlbiBvbmx5IGFkZCAn + Y2VwaGZzJyBTdG9yYWdlQ2xhc3MKICAgICAgICBpZiBzZWxmLm91dF9tYXBbIkNFUEhGU19GU19O + QU1FIl06CiAgICAgICAgICAgIGpzb25fb3V0LmFwcGVuZCgKICAgICAgICAgICAgICAgIHsKICAg + ICAgICAgICAgICAgICAgICAibmFtZSI6ICJjZXBoZnMiLAogICAgICAgICAgICAgICAgICAgICJr + aW5kIjogIlN0b3JhZ2VDbGFzcyIsCiAgICAgICAgICAgICAgICAgICAgImRhdGEiOiB7CiAgICAg + ICAgICAgICAgICAgICAgICAgICJmc05hbWUiOiBzZWxmLm91dF9tYXBbIkNFUEhGU19GU19OQU1F + Il0sCiAgICAgICAgICAgICAgICAgICAgICAgICJwb29sIjogc2VsZi5vdXRfbWFwWyJDRVBIRlNf + UE9PTF9OQU1FIl0sCiAgICAgICAgICAgICAgICAgICAgICAgICJjc2kuc3RvcmFnZS5rOHMuaW8v + cHJvdmlzaW9uZXItc2VjcmV0LW5hbWUiOiBmInJvb2ste3NlbGYub3V0X21hcFsnQ1NJX0NFUEhG + U19QUk9WSVNJT05FUl9TRUNSRVRfTkFNRSddfSIsCiAgICAgICAgICAgICAgICAgICAgICAgICJj + c2kuc3RvcmFnZS5rOHMuaW8vY29udHJvbGxlci1leHBhbmQtc2VjcmV0LW5hbWUiOiBmInJvb2st + e3NlbGYub3V0X21hcFsnQ1NJX0NFUEhGU19QUk9WSVNJT05FUl9TRUNSRVRfTkFNRSddfSIsCiAg + ICAgICAgICAgICAgICAgICAgICAgICJjc2kuc3RvcmFnZS5rOHMuaW8vbm9kZS1zdGFnZS1zZWNy + ZXQtbmFtZSI6IGYicm9vay17c2VsZi5vdXRfbWFwWydDU0lfQ0VQSEZTX05PREVfU0VDUkVUX05B + TUUnXX0iLAogICAgICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICB9CiAgICAgICAg + ICAgICkKICAgICAgICAjIGlmICdSR1dfRU5EUE9JTlQnIGV4aXN0cywgdGhlbiBvbmx5IGFkZCAn + Y2VwaC1yZ3cnIFN0b3JhZ2VDbGFzcwogICAgICAgIGlmIHNlbGYub3V0X21hcFsiUkdXX0VORFBP + SU5UIl06CiAgICAgICAgICAgIGpzb25fb3V0LmFwcGVuZCgKICAgICAgICAgICAgICAgIHsKICAg + ICAgICAgICAgICAgICAgICAibmFtZSI6ICJjZXBoLXJndyIsCiAgICAgICAgICAgICAgICAgICAg + ImtpbmQiOiAiU3RvcmFnZUNsYXNzIiwKICAgICAgICAgICAgICAgICAgICAiZGF0YSI6IHsKICAg + ICAgICAgICAgICAgICAgICAgICAgImVuZHBvaW50Ijogc2VsZi5vdXRfbWFwWyJSR1dfRU5EUE9J + TlQiXSwKICAgICAgICAgICAgICAgICAgICAgICAgInBvb2xQcmVmaXgiOiBzZWxmLm91dF9tYXBb + IlJHV19QT09MX1BSRUZJWCJdLAogICAgICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAg + ICB9CiAgICAgICAgICAgICkKICAgICAgICAgICAganNvbl9vdXQuYXBwZW5kKAogICAgICAgICAg + ICAgICAgewogICAgICAgICAgICAgICAgICAgICJuYW1lIjogInJndy1hZG1pbi1vcHMtdXNlciIs + CiAgICAgICAgICAgICAgICAgICAgImtpbmQiOiAiU2VjcmV0IiwKICAgICAgICAgICAgICAgICAg + ICAiZGF0YSI6IHsKICAgICAgICAgICAgICAgICAgICAgICAgImFjY2Vzc0tleSI6IHNlbGYub3V0 + X21hcFsiUkdXX0FETUlOX09QU19VU0VSX0FDQ0VTU19LRVkiXSwKICAgICAgICAgICAgICAgICAg + ICAgICAgInNlY3JldEtleSI6IHNlbGYub3V0X21hcFsiUkdXX0FETUlOX09QU19VU0VSX1NFQ1JF + VF9LRVkiXSwKICAgICAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAgfQogICAgICAg + ICAgICApCiAgICAgICAgIyBpZiAnUkdXX1RMU19DRVJUJyBleGlzdHMsIHRoZW4gb25seSBhZGQg + dGhlICJjZXBoLXJndy10bHMtY2VydCIgc2VjcmV0CiAgICAgICAgaWYgc2VsZi5vdXRfbWFwWyJS + R1dfVExTX0NFUlQiXToKICAgICAgICAgICAganNvbl9vdXQuYXBwZW5kKAogICAgICAgICAgICAg + ICAgewogICAgICAgICAgICAgICAgICAgICJuYW1lIjogImNlcGgtcmd3LXRscy1jZXJ0IiwKICAg + ICAgICAgICAgICAgICAgICAia2luZCI6ICJTZWNyZXQiLAogICAgICAgICAgICAgICAgICAgICJk + YXRhIjogewogICAgICAgICAgICAgICAgICAgICAgICAiY2VydCI6IHNlbGYub3V0X21hcFsiUkdX + X1RMU19DRVJUIl0sCiAgICAgICAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAgIH0KICAg + ICAgICAgICAgKQoKICAgICAgICByZXR1cm4ganNvbi5kdW1wcyhqc29uX291dCkgKyBMSU5FU0VQ + CgogICAgZGVmIHVwZ3JhZGVfdXNlcnNfcGVybWlzc2lvbnMoc2VsZik6CiAgICAgICAgdXNlcnMg + PSBbCiAgICAgICAgICAgICJjbGllbnQuY3NpLWNlcGhmcy1ub2RlIiwKICAgICAgICAgICAgImNs + aWVudC5jc2ktY2VwaGZzLXByb3Zpc2lvbmVyIiwKICAgICAgICAgICAgImNsaWVudC5jc2ktcmJk + LW5vZGUiLAogICAgICAgICAgICAiY2xpZW50LmNzaS1yYmQtcHJvdmlzaW9uZXIiLAogICAgICAg + ICAgICAiY2xpZW50LmhlYWx0aGNoZWNrZXIiLAogICAgICAgIF0KICAgICAgICBpZiBzZWxmLnJ1 + bl9hc191c2VyICE9ICIiIGFuZCBzZWxmLnJ1bl9hc191c2VyIG5vdCBpbiB1c2VyczoKICAgICAg + ICAgICAgdXNlcnMuYXBwZW5kKHNlbGYucnVuX2FzX3VzZXIpCiAgICAgICAgZm9yIHVzZXIgaW4g + dXNlcnM6CiAgICAgICAgICAgIHNlbGYudXBncmFkZV91c2VyX3Blcm1pc3Npb25zKHVzZXIpCgog + ICAgZGVmIGdldF9yZ3dfcG9vbF9uYW1lX2R1cmluZ191cGdyYWRlKHNlbGYsIHVzZXIsIGNhcHMp + OgogICAgICAgIGlmIHVzZXIgPT0gImNsaWVudC5oZWFsdGhjaGVja2VyIjoKICAgICAgICAgICAg + IyB3aGVuIGFkbWluIGhhcyBub3QgcHJvdmlkZWQgcmd3IHBvb2wgbmFtZSBkdXJpbmcgdXBncmFk + ZSwKICAgICAgICAgICAgIyBnZXQgdGhlIHJndyBwb29sIG5hbWUgZnJvbSBjbGllbnQuaGVhbHRo + Y2hlY2tlciB1c2VyIHdoaWNoIHdhcyB1c2VkIGR1cmluZyBjb25uZWN0aW9uCiAgICAgICAgICAg + IGlmIG5vdCBzZWxmLl9hcmdfcGFyc2VyLnJnd19wb29sX3ByZWZpeDoKICAgICAgICAgICAgICAg + ICMgVG8gZ2V0IHZhbHVlICdkZWZhdWx0JyB3aGljaCBpcyByZ3cgcG9vbCBuYW1lIGZyb20gJ2Fs + bG93IHJ3eCBwb29sPWRlZmF1bHQucmd3Lm1ldGEnCiAgICAgICAgICAgICAgICBwYXR0ZXJuID0g + ciJwb29sPSguKj8pXC5yZ3dcLm1ldGEiCiAgICAgICAgICAgICAgICBtYXRjaCA9IHJlLnNlYXJj + aChwYXR0ZXJuLCBjYXBzKQogICAgICAgICAgICAgICAgaWYgbWF0Y2g6CiAgICAgICAgICAgICAg + ICAgICAgc2VsZi5fYXJnX3BhcnNlci5yZ3dfcG9vbF9wcmVmaXggPSBtYXRjaC5ncm91cCgxKQog + ICAgICAgICAgICAgICAgZWxzZToKICAgICAgICAgICAgICAgICAgICByYWlzZSBFeGVjdXRpb25G + YWlsdXJlRXhjZXB0aW9uKAogICAgICAgICAgICAgICAgICAgICAgICAiZmFpbGVkIHRvIGdldCBy + Z3cgcG9vbCBuYW1lIGZvciB1cGdyYWRlIgogICAgICAgICAgICAgICAgICAgICkKCiAgICBkZWYg + dXBncmFkZV91c2VyX3Blcm1pc3Npb25zKHNlbGYsIHVzZXIpOgogICAgICAgICMgY2hlY2sgd2hl + dGhlciB0aGUgZ2l2ZW4gdXNlciBleGlzdHMgb3Igbm90CiAgICAgICAgY21kX2pzb24gPSB7InBy + ZWZpeCI6ICJhdXRoIGdldCIsICJlbnRpdHkiOiBmInt1c2VyfSIsICJmb3JtYXQiOiAianNvbiJ9 + CiAgICAgICAgcmV0X3ZhbCwganNvbl9vdXQsIGVycl9tc2cgPSBzZWxmLl9jb21tb25fY21kX2pz + b25fZ2VuKGNtZF9qc29uKQogICAgICAgIGlmIHJldF92YWwgIT0gMCBvciBsZW4oanNvbl9vdXQp + ID09IDA6CiAgICAgICAgICAgIHByaW50KGYidXNlciB7dXNlcn0gbm90IGZvdW5kIGZvciB1cGdy + YWRpbmcuIikKICAgICAgICAgICAgcmV0dXJuCiAgICAgICAgZXhpc3RpbmdfY2FwcyA9IGpzb25f + b3V0WzBdWyJjYXBzIl0KICAgICAgICBzZWxmLmdldF9yZ3dfcG9vbF9uYW1lX2R1cmluZ191cGdy + YWRlKHVzZXIsIHN0cihleGlzdGluZ19jYXBzKSkKICAgICAgICBuZXdfY2FwLCBfID0gc2VsZi5n + ZXRfY2Fwc19hbmRfZW50aXR5KHVzZXIpCiAgICAgICAgY2FwX2tleXMgPSBbIm1vbiIsICJtZ3Ii + LCAib3NkIiwgIm1kcyJdCiAgICAgICAgY2FwcyA9IFtdCiAgICAgICAgZm9yIGVhY2hDYXAgaW4g + Y2FwX2tleXM6CiAgICAgICAgICAgIGN1cl9jYXBfdmFsdWVzID0gZXhpc3RpbmdfY2Fwcy5nZXQo + ZWFjaENhcCwgIiIpCiAgICAgICAgICAgIG5ld19jYXBfdmFsdWVzID0gbmV3X2NhcC5nZXQoZWFj + aENhcCwgIiIpCiAgICAgICAgICAgIGN1cl9jYXBfcGVybV9saXN0ID0gWwogICAgICAgICAgICAg + ICAgeC5zdHJpcCgpIGZvciB4IGluIGN1cl9jYXBfdmFsdWVzLnNwbGl0KCIsIikgaWYgeC5zdHJp + cCgpCiAgICAgICAgICAgIF0KICAgICAgICAgICAgbmV3X2NhcF9wZXJtX2xpc3QgPSBbCiAgICAg + ICAgICAgICAgICB4LnN0cmlwKCkgZm9yIHggaW4gbmV3X2NhcF92YWx1ZXMuc3BsaXQoIiwiKSBp + ZiB4LnN0cmlwKCkKICAgICAgICAgICAgXQogICAgICAgICAgICAjIGFwcGVuZCBuZXdfY2FwX2xp + c3QgdG8gY3VyX2NhcF9saXN0IHRvIG1haW50YWluIHRoZSBvcmRlciBvZiBjYXBzCiAgICAgICAg + ICAgIGN1cl9jYXBfcGVybV9saXN0LmV4dGVuZChuZXdfY2FwX3Blcm1fbGlzdCkKICAgICAgICAg + ICAgIyBlbGltaW5hdGUgZHVwbGljYXRlcyB3aXRob3V0IHVzaW5nICdzZXQnCiAgICAgICAgICAg + ICMgc2V0IHJlLW9yZGVycyBpdGVtcyBpbiB0aGUgbGlzdCBhbmQgd2UgaGF2ZSB0byBrZWVwIHRo + ZSBvcmRlcgogICAgICAgICAgICBuZXdfY2FwX2xpc3QgPSBbXQogICAgICAgICAgICBbbmV3X2Nh + cF9saXN0LmFwcGVuZCh4KSBmb3IgeCBpbiBjdXJfY2FwX3Blcm1fbGlzdCBpZiB4IG5vdCBpbiBu + ZXdfY2FwX2xpc3RdCiAgICAgICAgICAgIGV4aXN0aW5nX2NhcHNbZWFjaENhcF0gPSAiLCAiLmpv + aW4obmV3X2NhcF9saXN0KQogICAgICAgICAgICBpZiBleGlzdGluZ19jYXBzW2VhY2hDYXBdOgog + ICAgICAgICAgICAgICAgY2Fwcy5hcHBlbmQoZWFjaENhcCkKICAgICAgICAgICAgICAgIGNhcHMu + YXBwZW5kKGV4aXN0aW5nX2NhcHNbZWFjaENhcF0pCiAgICAgICAgY21kX2pzb24gPSB7CiAgICAg + ICAgICAgICJwcmVmaXgiOiAiYXV0aCBjYXBzIiwKICAgICAgICAgICAgImVudGl0eSI6IHVzZXIs + CiAgICAgICAgICAgICJjYXBzIjogY2FwcywKICAgICAgICAgICAgImZvcm1hdCI6ICJqc29uIiwK + ICAgICAgICB9CiAgICAgICAgcmV0X3ZhbCwganNvbl9vdXQsIGVycl9tc2cgPSBzZWxmLl9jb21t + b25fY21kX2pzb25fZ2VuKGNtZF9qc29uKQogICAgICAgIGlmIHJldF92YWwgIT0gMDoKICAgICAg + ICAgICAgcmFpc2UgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlvbigKICAgICAgICAgICAgICAgIGYi + J2F1dGggY2FwcyB7dXNlcn0nIGNvbW1hbmQgZmFpbGVkLlxuIEVycm9yOiB7ZXJyX21zZ30iCiAg + ICAgICAgICAgICkKICAgICAgICBwcmludChmIlVwZGF0ZWQgdXNlciB7dXNlcn0gc3VjY2Vzc2Z1 + bGx5LiIpCgogICAgZGVmIG1haW4oc2VsZik6CiAgICAgICAgZ2VuZXJhdGVkX291dHB1dCA9ICIi + CiAgICAgICAgaWYgc2VsZi5fYXJnX3BhcnNlci51cGdyYWRlOgogICAgICAgICAgICBzZWxmLnVw + Z3JhZGVfdXNlcnNfcGVybWlzc2lvbnMoKQogICAgICAgIGVsaWYgc2VsZi5fYXJnX3BhcnNlci5m + b3JtYXQgPT0gImpzb24iOgogICAgICAgICAgICBnZW5lcmF0ZWRfb3V0cHV0ID0gc2VsZi5nZW5f + anNvbl9vdXQoKQogICAgICAgIGVsaWYgc2VsZi5fYXJnX3BhcnNlci5mb3JtYXQgPT0gImJhc2gi + OgogICAgICAgICAgICBnZW5lcmF0ZWRfb3V0cHV0ID0gc2VsZi5nZW5fc2hlbGxfb3V0KCkKICAg + ICAgICBlbHNlOgogICAgICAgICAgICByYWlzZSBFeGVjdXRpb25GYWlsdXJlRXhjZXB0aW9uKAog + ICAgICAgICAgICAgICAgZiJVbnN1cHBvcnRlZCBmb3JtYXQ6IHtzZWxmLl9hcmdfcGFyc2VyLmZv + cm1hdH0iCiAgICAgICAgICAgICkKICAgICAgICBwcmludChnZW5lcmF0ZWRfb3V0cHV0KQogICAg + ICAgIGlmIHNlbGYub3V0cHV0X2ZpbGUgYW5kIGdlbmVyYXRlZF9vdXRwdXQ6CiAgICAgICAgICAg + IGZPdXQgPSBvcGVuKHNlbGYub3V0cHV0X2ZpbGUsIG1vZGU9InciLCBlbmNvZGluZz0iVVRGLTgi + KQogICAgICAgICAgICBmT3V0LndyaXRlKGdlbmVyYXRlZF9vdXRwdXQpCiAgICAgICAgICAgIGZP + dXQuY2xvc2UoKQoKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMj + IyMjIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMgTUFJTiAjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyMj + IyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCmlmIF9fbmFtZV9f + ID09ICJfX21haW5fXyI6CiAgICByak9iaiA9IFJhZG9zSlNPTigpCiAgICB0cnk6CiAgICAgICAg + cmpPYmoubWFpbigpCiAgICBleGNlcHQgRXhlY3V0aW9uRmFpbHVyZUV4Y2VwdGlvbiBhcyBlcnI6 + CiAgICAgICAgcHJpbnQoZiJFeGVjdXRpb24gRmFpbGVkOiB7ZXJyfSIpCiAgICAgICAgcmFpc2Ug + ZXJyCiAgICBleGNlcHQgS2V5RXJyb3IgYXMga0VycjoKICAgICAgICBwcmludChmIktleUVycm9y + OiB7a0Vycn0iKQogICAgZXhjZXB0IE9TRXJyb3IgYXMgb3NFcnI6CiAgICAgICAgcHJpbnQoZiJF + cnJvciB3aGlsZSB0cnlpbmcgdG8gb3V0cHV0IHRoZSBkYXRhOiB7b3NFcnJ9IikKICAgIGZpbmFs + bHk6CiAgICAgICAgcmpPYmouc2h1dGRvd24oKQo= name: rook-ceph-operator.v4.17.0 namespace: placeholder spec: @@ -3051,11 +3052,6 @@ spec: configMapKeyRef: key: ROOK_CURRENT_NAMESPACE_ONLY name: ocs-operator-config - - name: CSI_DISABLE_HOLDER_PODS - valueFrom: - configMapKeyRef: - key: CSI_DISABLE_HOLDER_PODS - name: ocs-operator-config - name: ROOK_ALLOW_MULTIPLE_FILESYSTEMS value: "false" - name: ROOK_LOG_LEVEL @@ -3452,7 +3448,21 @@ spec: resources: - csiaddonsnodes verbs: + - get - create + - update + - apiGroups: + - "" + resources: + - pods + verbs: + - get + - apiGroups: + - apps + resources: + - replicasets + verbs: + - get serviceAccountName: rook-csi-cephfs-provisioner-sa - rules: - apiGroups: @@ -3460,7 +3470,21 @@ spec: resources: - csiaddonsnodes verbs: + - get - create + - update + - apiGroups: + - "" + resources: + - pods + verbs: + - get + - apiGroups: + - apps + resources: + - replicasets + verbs: + - get serviceAccountName: rook-csi-rbd-plugin-sa - rules: - apiGroups: @@ -3479,7 +3503,21 @@ spec: resources: - csiaddonsnodes verbs: + - get - create + - update + - apiGroups: + - "" + resources: + - pods + verbs: + - get + - apiGroups: + - apps + resources: + - replicasets + verbs: + - get serviceAccountName: rook-csi-rbd-provisioner-sa strategy: deployment installModes: diff --git a/cmd/rook/ceph/cleanup.go b/cmd/rook/ceph/cleanup.go index f158619d9b63..0a2dea1fde86 100644 --- a/cmd/rook/ceph/cleanup.go +++ b/cmd/rook/ceph/cleanup.go @@ -62,6 +62,12 @@ var cleanUpRadosNamespaceCmd = &cobra.Command{ Short: "Starts the cleanup process for a CephBlockPoolRadosNamespace", } +var cleanUpBlockPoolCmd = &cobra.Command{ + // the subcommand matches CRD kind of the custom resource to be cleaned up + Use: "CephBlockPool", + Short: "Starts the cleanup process for a CephBlockPool", +} + func init() { cleanUpHostCmd.Flags().StringVar(&dataDirHostPath, "data-dir-host-path", "", "dataDirHostPath on the node") cleanUpHostCmd.Flags().StringVar(&namespaceDir, "namespace-dir", "", "dataDirHostPath on the node") @@ -74,11 +80,12 @@ func init() { flags.SetFlagsFromEnv(cleanUpHostCmd.Flags(), rook.RookEnvVarPrefix) flags.SetFlagsFromEnv(cleanUpSubVolumeGroupCmd.Flags(), rook.RookEnvVarPrefix) - cleanUpCmd.AddCommand(cleanUpHostCmd, cleanUpSubVolumeGroupCmd, cleanUpRadosNamespaceCmd) + cleanUpCmd.AddCommand(cleanUpHostCmd, cleanUpSubVolumeGroupCmd, cleanUpRadosNamespaceCmd, cleanUpBlockPoolCmd) cleanUpHostCmd.RunE = startHostCleanUp cleanUpSubVolumeGroupCmd.RunE = startSubVolumeGroupCleanUp cleanUpRadosNamespaceCmd.RunE = startRadosNamespaceCleanup + cleanUpBlockPoolCmd.RunE = startBlockPoolCleanup } func startHostCleanUp(cmd *cobra.Command, args []string) error { @@ -174,3 +181,25 @@ func startRadosNamespaceCleanup(cmd *cobra.Command, args []string) error { return nil } + +func startBlockPoolCleanup(cmd *cobra.Command, args []string) error { + rook.SetLogLevel() + rook.LogStartupInfo(cleanUpRadosNamespaceCmd.Flags()) + + ctx := cmd.Context() + context := createContext() + namespace := os.Getenv(k8sutil.PodNamespaceEnvVar) + clusterInfo := client.AdminClusterInfo(ctx, namespace, "") + + poolName := os.Getenv(opcontroller.CephBlockPoolNameEnv) + if poolName == "" { + rook.TerminateFatal(fmt.Errorf("cephblockpool name is not available in the pod environment variables")) + } + + err := cleanup.BlockPoolCleanup(context, clusterInfo, poolName) + if err != nil { + rook.TerminateFatal(fmt.Errorf("failed to cleanup cephBlockPool %q resource %v", poolName, err)) + } + + return nil +} diff --git a/deploy/charts/rook-ceph-cluster/values.yaml b/deploy/charts/rook-ceph-cluster/values.yaml index 7de9fdebb169..47297069d216 100644 --- a/deploy/charts/rook-ceph-cluster/values.yaml +++ b/deploy/charts/rook-ceph-cluster/values.yaml @@ -100,7 +100,7 @@ cephClusterSpec: # Do not set to true in production. allowUnsupported: false - # The path on the host where configuration files will be persisted. Must be specified. + # The path on the host where configuration files will be persisted. Must be specified. If there are multiple clusters, the directory must be unique for each cluster. # Important: if you reinstall the cluster, make sure you delete this directory from each host or else the mons will fail to start on the new cluster. # In Minikube, the '/data' directory is configured to persist across reboots. Use "/data/rook" in Minikube environment. dataDirHostPath: /var/lib/rook diff --git a/deploy/charts/rook-ceph/templates/configmap.yaml b/deploy/charts/rook-ceph/templates/configmap.yaml index c29dbcd74fc9..1acc2c5e871d 100644 --- a/deploy/charts/rook-ceph/templates/configmap.yaml +++ b/deploy/charts/rook-ceph/templates/configmap.yaml @@ -38,7 +38,6 @@ data: CSI_ENABLE_ENCRYPTION: {{ .Values.csi.enableCSIEncryption | quote }} CSI_ENABLE_OMAP_GENERATOR: {{ .Values.csi.enableOMAPGenerator | quote }} CSI_ENABLE_HOST_NETWORK: {{ .Values.csi.enableCSIHostNetwork | quote }} - CSI_DISABLE_HOLDER_PODS: {{ .Values.csi.disableHolderPods | quote }} CSI_ENABLE_METADATA: {{ .Values.csi.enableMetadata | quote }} CSI_ENABLE_VOLUME_GROUP_SNAPSHOT: {{ .Values.csi.enableVolumeGroupSnapshot | quote }} {{- if .Values.csi.csiDriverNamePrefix }} @@ -170,9 +169,6 @@ data: {{- if .Values.csi.nfsProvisionerNodeAffinity }} CSI_NFS_PROVISIONER_NODE_AFFINITY: {{ .Values.csi.nfsProvisionerNodeAffinity }} {{- end }} -{{- if .Values.csi.allowUnsupportedVersion }} - ROOK_CSI_ALLOW_UNSUPPORTED_VERSION: {{ .Values.csi.allowUnsupportedVersion | quote }} -{{- end }} {{- if .Values.csi.pluginTolerations }} CSI_PLUGIN_TOLERATIONS: {{ toYaml .Values.csi.pluginTolerations | quote }} {{- end }} diff --git a/deploy/charts/rook-ceph/templates/resources.yaml b/deploy/charts/rook-ceph/templates/resources.yaml index 12c2d1ffbaa8..a27d431abf22 100644 --- a/deploy/charts/rook-ceph/templates/resources.yaml +++ b/deploy/charts/rook-ceph/templates/resources.yaml @@ -109,9 +109,142 @@ spec: type: string nullable: true type: object + mirroringInfo: + description: MirroringInfoSpec is the status of the pool/radosnamespace mirroring + properties: + details: + type: string + lastChanged: + type: string + lastChecked: + type: string + mode: + description: Mode is the mirroring mode + type: string + peers: + description: Peers are the list of peer sites connected to that cluster + items: + description: PeersSpec contains peer details + properties: + client_name: + description: ClientName is the CephX user used to connect to the peer + type: string + direction: + description: Direction is the peer mirroring direction + type: string + mirror_uuid: + description: MirrorUUID is the mirror UUID + type: string + site_name: + description: SiteName is the current site name + type: string + uuid: + description: UUID is the peer UUID + type: string + type: object + type: array + site_name: + description: SiteName is the current site name + type: string + type: object + mirroringStatus: + description: MirroringStatusSpec is the status of the pool/radosNamespace mirroring + properties: + details: + description: Details contains potential status errors + type: string + lastChanged: + description: LastChanged is the last time time the status last changed + type: string + lastChecked: + description: LastChecked is the last time time the status was checked + type: string + summary: + description: Summary is the mirroring status summary + properties: + daemon_health: + description: DaemonHealth is the health of the mirroring daemon + type: string + health: + description: Health is the mirroring health + type: string + image_health: + description: ImageHealth is the health of the mirrored image + type: string + states: + description: States is the various state for all mirrored images + nullable: true + properties: + error: + description: Error is when the mirroring state is errored + type: integer + replaying: + description: Replaying is when the replay of the mirroring journal is on-going + type: integer + starting_replay: + description: StartingReplay is when the replay of the mirroring journal starts + type: integer + stopped: + description: Stopped is when the mirroring state is stopped + type: integer + stopping_replay: + description: StopReplaying is when the replay of the mirroring journal stops + type: integer + syncing: + description: Syncing is when the image is syncing + type: integer + unknown: + description: Unknown is when the mirroring state is unknown + type: integer + type: object + type: object + type: object phase: description: ConditionType represent a resource's status type: string + snapshotScheduleStatus: + description: SnapshotScheduleStatusSpec is the status of the snapshot schedule + properties: + details: + description: Details contains potential status errors + type: string + lastChanged: + description: LastChanged is the last time time the status last changed + type: string + lastChecked: + description: LastChecked is the last time time the status was checked + type: string + snapshotSchedules: + description: SnapshotSchedules is the list of snapshots scheduled + items: + description: SnapshotSchedulesSpec is the list of snapshot scheduled for images in a pool + properties: + image: + description: Image is the mirrored image + type: string + items: + description: Items is the list schedules times for a given snapshot + items: + description: SnapshotSchedule is a schedule + properties: + interval: + description: Interval is the interval in which snapshots will be taken + type: string + start_time: + description: StartTime is the snapshot starting time + type: string + type: object + type: array + namespace: + description: Namespace is the RADOS namespace the image is part of + type: string + pool: + description: Pool is the pool name + type: string + type: object + nullable: true + type: array + type: object type: object x-kubernetes-preserve-unknown-fields: true required: @@ -405,7 +538,7 @@ spec: nullable: true type: object mirroringInfo: - description: MirroringInfoSpec is the status of the pool mirroring + description: MirroringInfoSpec is the status of the pool/radosnamespace mirroring properties: details: type: string @@ -443,7 +576,7 @@ spec: type: string type: object mirroringStatus: - description: MirroringStatusSpec is the status of the pool mirroring + description: MirroringStatusSpec is the status of the pool/radosNamespace mirroring properties: details: description: Details contains potential status errors @@ -3645,6 +3778,9 @@ spec: type: array onlyApplyOSDPlacement: type: boolean + scheduleAlways: + description: Whether to always schedule OSDs on a node even if the node is not currently scheduleable or ready + type: boolean storageClassDeviceSets: items: description: StorageClassDeviceSet is a storage class device set @@ -12383,6 +12519,11 @@ spec: description: The data pool used to store ObjectStore objects data. minLength: 1 type: string + default: + description: |- + Sets given placement as default. Only one placement in the list can be marked as default. + Default is false. + type: boolean metadataPoolName: description: The metadata pool used to store ObjectStore bucket index. minLength: 1 @@ -13305,6 +13446,11 @@ spec: description: The data pool used to store ObjectStore objects data. minLength: 1 type: string + default: + description: |- + Sets given placement as default. Only one placement in the list can be marked as default. + Default is false. + type: boolean metadataPoolName: description: The metadata pool used to store ObjectStore bucket index. minLength: 1 diff --git a/deploy/charts/rook-ceph/templates/role.yaml b/deploy/charts/rook-ceph/templates/role.yaml index 343c2527b021..b7d34d825dff 100644 --- a/deploy/charts/rook-ceph/templates/role.yaml +++ b/deploy/charts/rook-ceph/templates/role.yaml @@ -74,7 +74,13 @@ rules: {{- if and .Values.csi.csiAddons .Values.csi.csiAddons.enabled }} - apiGroups: ["csiaddons.openshift.io"] resources: ["csiaddonsnodes"] - verbs: ["create"] + verbs: ["get", "create", "update"] + - apiGroups: [""] + resources: ["pods"] + verbs: ["get"] + - apiGroups: ["apps"] + resources: ["replicasets"] + verbs: ["get"] {{- end }} --- {{- if and .Values.csi.csiAddons .Values.csi.csiAddons.enabled }} @@ -86,7 +92,13 @@ metadata: rules: - apiGroups: ["csiaddons.openshift.io"] resources: ["csiaddonsnodes"] - verbs: ["create"] + verbs: ["get", "create", "update"] + - apiGroups: [""] + resources: ["pods"] + verbs: ["get"] + - apiGroups: ["apps"] + resources: ["replicasets"] + verbs: ["get"] --- {{- end }} kind: Role @@ -101,6 +113,12 @@ rules: {{- if and .Values.csi.csiAddons .Values.csi.csiAddons.enabled }} - apiGroups: ["csiaddons.openshift.io"] resources: ["csiaddonsnodes"] - verbs: ["create"] + verbs: ["get", "create", "update"] + - apiGroups: [""] + resources: ["pods"] + verbs: ["get"] + - apiGroups: ["apps"] + resources: ["replicasets"] + verbs: ["get"] {{- end }} {{- end }} diff --git a/deploy/charts/rook-ceph/values.yaml b/deploy/charts/rook-ceph/values.yaml index 7e3d47bb3c04..8b5ceb82f197 100644 --- a/deploy/charts/rook-ceph/values.yaml +++ b/deploy/charts/rook-ceph/values.yaml @@ -88,10 +88,6 @@ csi: # in some network configurations where the SDN does not provide access to an external cluster or # there is significant drop in read/write performance enableCSIHostNetwork: true - # -- Deprecation note: Rook uses "holder" pods to allow CSI to connect to the multus public network - # without needing hosts to the network. Holder pods are being removed. See issue for details: - # https://github.com/rook/rook/issues/13055. New Rook deployments should set this to "true". - disableHolderPods: true # -- Enable Snapshotter in CephFS provisioner pod enableCephfsSnapshotter: true # -- Enable Snapshotter in NFS provisioner pod @@ -183,9 +179,6 @@ csi: # -- Set GRPC timeout for csi containers (in seconds). It should be >= 120. If this value is not set or is invalid, it defaults to 150 grpcTimeoutInSeconds: 150 - # -- Allow starting an unsupported ceph-csi image - allowUnsupportedVersion: false - # -- Burst to use while communicating with the kubernetes apiserver. kubeApiBurst: @@ -640,7 +633,7 @@ enforceHostNetwork: false disableDeviceHotplug: false # -- The revision history limit for all pods created by Rook. If blank, the K8s default is 10. -revisionHistoryLimit: +revisionHistoryLimit: # -- Blacklist certain disks according to the regex provided. discoverDaemonUdev: diff --git a/deploy/examples/cluster-external-management.yaml b/deploy/examples/cluster-external-management.yaml index 156e968df17f..f1ef32560b3c 100644 --- a/deploy/examples/cluster-external-management.yaml +++ b/deploy/examples/cluster-external-management.yaml @@ -16,6 +16,7 @@ metadata: spec: external: enable: true + # If there are multiple clusters, the directory must be unique for each cluster. dataDirHostPath: /var/lib/rook # providing an image is required, if you want to create other CRs (rgw, mds, nfs) cephVersion: diff --git a/deploy/examples/cluster-on-local-pvc.yaml b/deploy/examples/cluster-on-local-pvc.yaml index 0d92793f4cc3..c93b52af8225 100644 --- a/deploy/examples/cluster-on-local-pvc.yaml +++ b/deploy/examples/cluster-on-local-pvc.yaml @@ -162,6 +162,7 @@ metadata: name: rook-ceph namespace: rook-ceph # namespace:cluster spec: + # If there are multiple clusters, the directory must be unique for each cluster. dataDirHostPath: /var/lib/rook mon: count: 3 diff --git a/deploy/examples/cluster-on-pvc-minikube.yaml b/deploy/examples/cluster-on-pvc-minikube.yaml index 3900fc3eff05..00f56a72607e 100644 --- a/deploy/examples/cluster-on-pvc-minikube.yaml +++ b/deploy/examples/cluster-on-pvc-minikube.yaml @@ -128,6 +128,7 @@ metadata: name: my-cluster namespace: rook-ceph # namespace:cluster spec: + # If there are multiple clusters, the directory must be unique for each cluster. dataDirHostPath: /var/lib/rook mon: count: 1 diff --git a/deploy/examples/cluster-on-pvc.yaml b/deploy/examples/cluster-on-pvc.yaml index 01017800ce48..398de65cf28a 100644 --- a/deploy/examples/cluster-on-pvc.yaml +++ b/deploy/examples/cluster-on-pvc.yaml @@ -12,6 +12,7 @@ metadata: name: rook-ceph namespace: rook-ceph # namespace:cluster spec: + # If there are multiple clusters, the directory must be unique for each cluster. dataDirHostPath: /var/lib/rook mon: # Set the number of mons to be started. Generally recommended to be 3. diff --git a/deploy/examples/cluster-stretched-aws.yaml b/deploy/examples/cluster-stretched-aws.yaml index c286e7dcc943..48796dfe26c4 100644 --- a/deploy/examples/cluster-stretched-aws.yaml +++ b/deploy/examples/cluster-stretched-aws.yaml @@ -14,6 +14,7 @@ metadata: name: rook-ceph namespace: rook-ceph # namespace:cluster spec: + # If there are multiple clusters, the directory must be unique for each cluster. dataDirHostPath: /var/lib/rook mon: # Five mons must be created for stretch mode diff --git a/deploy/examples/cluster-stretched.yaml b/deploy/examples/cluster-stretched.yaml index 7f582754ab26..5d595f3ca4cd 100644 --- a/deploy/examples/cluster-stretched.yaml +++ b/deploy/examples/cluster-stretched.yaml @@ -14,6 +14,7 @@ metadata: name: rook-ceph namespace: rook-ceph # namespace:cluster spec: + # If there are multiple clusters, the directory must be unique for each cluster. dataDirHostPath: /var/lib/rook mon: # Five mons must be created for stretch mode diff --git a/deploy/examples/cluster.yaml b/deploy/examples/cluster.yaml index 345897fb58bd..70b4068757b9 100644 --- a/deploy/examples/cluster.yaml +++ b/deploy/examples/cluster.yaml @@ -26,7 +26,7 @@ spec: # Future versions such as Tentacle (v20) would require this to be set to `true`. # Do not set to true in production. allowUnsupported: false - # The path on the host where configuration files will be persisted. Must be specified. + # The path on the host where configuration files will be persisted. Must be specified. If there are multiple clusters, the directory must be unique for each cluster. # Important: if you reinstall the cluster, make sure you delete this directory from each host or else the mons will fail to start on the new cluster. # In Minikube, the '/data' directory is configured to persist across reboots. Use "/data/rook" in Minikube environment. dataDirHostPath: /var/lib/rook @@ -251,6 +251,7 @@ spec: # logcollector: # cleanup: # exporter: + # cmd-reporter: # The option to automatically remove OSDs that are out and are safe to destroy. removeOSDsIfOutAndSafeToRemove: false priorityClassNames: @@ -285,6 +286,9 @@ spec: # config: # configuration can be specified at the node level which overrides the cluster level config # - name: "172.17.4.301" # deviceFilter: "^sd." + # Whether to always schedule OSD pods on nodes declared explicitly in the "nodes" section, even if they are + # temporarily not schedulable. If set to true, consider adding placement tolerations for unschedulable nodes. + scheduleAlways: false # when onlyApplyOSDPlacement is false, will merge both placement.All() and placement.osd onlyApplyOSDPlacement: false # Time for which an OSD pod will sleep before restarting, if it stopped due to flapping diff --git a/deploy/examples/common.yaml b/deploy/examples/common.yaml index bb7703389f8c..9514c26cf0be 100644 --- a/deploy/examples/common.yaml +++ b/deploy/examples/common.yaml @@ -779,7 +779,13 @@ rules: verbs: ["get", "watch", "list", "delete", "update", "create"] - apiGroups: ["csiaddons.openshift.io"] resources: ["csiaddonsnodes"] - verbs: ["create"] + verbs: ["get", "create", "update"] + - apiGroups: [""] + resources: ["pods"] + verbs: ["get"] + - apiGroups: ["apps"] + resources: ["replicasets"] + verbs: ["get"] --- kind: Role apiVersion: rbac.authorization.k8s.io/v1 @@ -789,7 +795,13 @@ metadata: rules: - apiGroups: ["csiaddons.openshift.io"] resources: ["csiaddonsnodes"] - verbs: ["create"] + verbs: ["get", "create", "update"] + - apiGroups: [""] + resources: ["pods"] + verbs: ["get"] + - apiGroups: ["apps"] + resources: ["replicasets"] + verbs: ["get"] --- kind: Role apiVersion: rbac.authorization.k8s.io/v1 @@ -802,7 +814,13 @@ rules: verbs: ["get", "watch", "list", "delete", "update", "create"] - apiGroups: ["csiaddons.openshift.io"] resources: ["csiaddonsnodes"] - verbs: ["create"] + verbs: ["get", "create", "update"] + - apiGroups: [""] + resources: ["pods"] + verbs: ["get"] + - apiGroups: ["apps"] + resources: ["replicasets"] + verbs: ["get"] --- kind: Role apiVersion: rbac.authorization.k8s.io/v1 diff --git a/deploy/examples/crds.yaml b/deploy/examples/crds.yaml index 1ffc720b8548..b0fca4919eec 100644 --- a/deploy/examples/crds.yaml +++ b/deploy/examples/crds.yaml @@ -112,9 +112,142 @@ spec: type: string nullable: true type: object + mirroringInfo: + description: MirroringInfoSpec is the status of the pool/radosnamespace mirroring + properties: + details: + type: string + lastChanged: + type: string + lastChecked: + type: string + mode: + description: Mode is the mirroring mode + type: string + peers: + description: Peers are the list of peer sites connected to that cluster + items: + description: PeersSpec contains peer details + properties: + client_name: + description: ClientName is the CephX user used to connect to the peer + type: string + direction: + description: Direction is the peer mirroring direction + type: string + mirror_uuid: + description: MirrorUUID is the mirror UUID + type: string + site_name: + description: SiteName is the current site name + type: string + uuid: + description: UUID is the peer UUID + type: string + type: object + type: array + site_name: + description: SiteName is the current site name + type: string + type: object + mirroringStatus: + description: MirroringStatusSpec is the status of the pool/radosNamespace mirroring + properties: + details: + description: Details contains potential status errors + type: string + lastChanged: + description: LastChanged is the last time time the status last changed + type: string + lastChecked: + description: LastChecked is the last time time the status was checked + type: string + summary: + description: Summary is the mirroring status summary + properties: + daemon_health: + description: DaemonHealth is the health of the mirroring daemon + type: string + health: + description: Health is the mirroring health + type: string + image_health: + description: ImageHealth is the health of the mirrored image + type: string + states: + description: States is the various state for all mirrored images + nullable: true + properties: + error: + description: Error is when the mirroring state is errored + type: integer + replaying: + description: Replaying is when the replay of the mirroring journal is on-going + type: integer + starting_replay: + description: StartingReplay is when the replay of the mirroring journal starts + type: integer + stopped: + description: Stopped is when the mirroring state is stopped + type: integer + stopping_replay: + description: StopReplaying is when the replay of the mirroring journal stops + type: integer + syncing: + description: Syncing is when the image is syncing + type: integer + unknown: + description: Unknown is when the mirroring state is unknown + type: integer + type: object + type: object + type: object phase: description: ConditionType represent a resource's status type: string + snapshotScheduleStatus: + description: SnapshotScheduleStatusSpec is the status of the snapshot schedule + properties: + details: + description: Details contains potential status errors + type: string + lastChanged: + description: LastChanged is the last time time the status last changed + type: string + lastChecked: + description: LastChecked is the last time time the status was checked + type: string + snapshotSchedules: + description: SnapshotSchedules is the list of snapshots scheduled + items: + description: SnapshotSchedulesSpec is the list of snapshot scheduled for images in a pool + properties: + image: + description: Image is the mirrored image + type: string + items: + description: Items is the list schedules times for a given snapshot + items: + description: SnapshotSchedule is a schedule + properties: + interval: + description: Interval is the interval in which snapshots will be taken + type: string + start_time: + description: StartTime is the snapshot starting time + type: string + type: object + type: array + namespace: + description: Namespace is the RADOS namespace the image is part of + type: string + pool: + description: Pool is the pool name + type: string + type: object + nullable: true + type: array + type: object type: object x-kubernetes-preserve-unknown-fields: true required: @@ -407,7 +540,7 @@ spec: nullable: true type: object mirroringInfo: - description: MirroringInfoSpec is the status of the pool mirroring + description: MirroringInfoSpec is the status of the pool/radosnamespace mirroring properties: details: type: string @@ -445,7 +578,7 @@ spec: type: string type: object mirroringStatus: - description: MirroringStatusSpec is the status of the pool mirroring + description: MirroringStatusSpec is the status of the pool/radosNamespace mirroring properties: details: description: Details contains potential status errors @@ -3643,6 +3776,9 @@ spec: type: array onlyApplyOSDPlacement: type: boolean + scheduleAlways: + description: Whether to always schedule OSDs on a node even if the node is not currently scheduleable or ready + type: boolean storageClassDeviceSets: items: description: StorageClassDeviceSet is a storage class device set @@ -12374,6 +12510,11 @@ spec: description: The data pool used to store ObjectStore objects data. minLength: 1 type: string + default: + description: |- + Sets given placement as default. Only one placement in the list can be marked as default. + Default is false. + type: boolean metadataPoolName: description: The metadata pool used to store ObjectStore bucket index. minLength: 1 @@ -13293,6 +13434,11 @@ spec: description: The data pool used to store ObjectStore objects data. minLength: 1 type: string + default: + description: |- + Sets given placement as default. Only one placement in the list can be marked as default. + Default is false. + type: boolean metadataPoolName: description: The metadata pool used to store ObjectStore bucket index. minLength: 1 diff --git a/deploy/examples/create-external-cluster-resources.py b/deploy/examples/create-external-cluster-resources.py index a1c5f52b827e..e704619c3e41 100644 --- a/deploy/examples/create-external-cluster-resources.py +++ b/deploy/examples/create-external-cluster-resources.py @@ -377,7 +377,7 @@ def gen_arg_parser(cls, args_to_parse=None): "--rgw-tls-cert-path", default="", required=False, - help="RADOS Gateway endpoint TLS certificate", + help="RADOS Gateway endpoint TLS certificate (or intermediate signing certificate)", ) output_group.add_argument( "--rgw-skip-tls", diff --git a/deploy/examples/operator-openshift.yaml b/deploy/examples/operator-openshift.yaml index f98192bcab81..7773813e439d 100644 --- a/deploy/examples/operator-openshift.yaml +++ b/deploy/examples/operator-openshift.yaml @@ -139,11 +139,6 @@ data: # there is significant drop in read/write performance. # CSI_ENABLE_HOST_NETWORK: "true" - # Deprecation note: Rook uses "holder" pods to allow CSI to connect to the multus public network - # without needing hosts to the network. Holder pods are being removed. See issue for details: - # https://github.com/rook/rook/issues/13055. New Rook deployments should set this to "true". - CSI_DISABLE_HOLDER_PODS: "true" - # Set logging level for cephCSI containers maintained by the cephCSI. # Supported values from 0 to 5. 0 for general useful logs, 5 for trace level verbosity. # CSI_LOG_LEVEL: "0" @@ -188,9 +183,6 @@ data: # supported values are documented at https://kubernetes-csi.github.io/docs/support-fsgroup.html CSI_NFS_FSGROUPPOLICY: "File" - # (Optional) Allow starting unsupported ceph-csi image - ROOK_CSI_ALLOW_UNSUPPORTED_VERSION: "false" - # (Optional) control the host mount of /etc/selinux for csi plugin pods. CSI_PLUGIN_ENABLE_SELINUX_HOST_MOUNT: "false" @@ -696,11 +688,6 @@ spec: configMapKeyRef: key: ROOK_CURRENT_NAMESPACE_ONLY name: ocs-operator-config - - name: CSI_DISABLE_HOLDER_PODS - valueFrom: - configMapKeyRef: - key: CSI_DISABLE_HOLDER_PODS - name: ocs-operator-config - name: ROOK_ALLOW_MULTIPLE_FILESYSTEMS value: "false" - name: ROOK_LOG_LEVEL diff --git a/deploy/examples/operator.yaml b/deploy/examples/operator.yaml index 0533051fffcc..b11549be5d32 100644 --- a/deploy/examples/operator.yaml +++ b/deploy/examples/operator.yaml @@ -51,11 +51,6 @@ data: # there is significant drop in read/write performance. # CSI_ENABLE_HOST_NETWORK: "true" - # Deprecation note: Rook uses "holder" pods to allow CSI to connect to the multus public network - # without needing hosts to the network. Holder pods are being removed. See issue for details: - # https://github.com/rook/rook/issues/13055. New Rook deployments should set this to "true". - CSI_DISABLE_HOLDER_PODS: "true" - # Set to true to enable adding volume metadata on the CephFS subvolume and RBD images. # Not all users might be interested in getting volume/snapshot details as metadata on CephFS subvolume and RBD images. # Hence enable metadata is false by default. @@ -118,9 +113,6 @@ data: # supported values are documented at https://kubernetes-csi.github.io/docs/support-fsgroup.html CSI_NFS_FSGROUPPOLICY: "File" - # (Optional) Allow starting unsupported ceph-csi image - ROOK_CSI_ALLOW_UNSUPPORTED_VERSION: "false" - # (Optional) control the host mount of /etc/selinux for csi plugin pods. CSI_PLUGIN_ENABLE_SELINUX_HOST_MOUNT: "false" diff --git a/design/ceph/multus-network.md b/design/ceph/multus-network.md index 045cba88b3a2..90190468396b 100644 --- a/design/ceph/multus-network.md +++ b/design/ceph/multus-network.md @@ -93,50 +93,6 @@ network. The design for mitigating the issue is to add a new DaemonSet that will own the network for all CephFS mounts as well as RBD mapped devices. The `csi-{cephfs,rbd}plugin` DaemonSet are left untouched. -#### New "holder" DaemonSet -The Rook-Ceph Operator's CSI controller creates a `csi-plugin-holder` DaemonSet configured to use the -`network.selectors.public` network specified for the CephCluster. This DaemonSet runs on all the -nodes along side the `csi-{cephfs,rbd}plugin` DaemonSet. - -This Pod should only be stopped and restarted when a node is stopped so that volume operations do -not become blocked. The Rook-Ceph Operator's CSI controller should set the DaemonSet's update -strategy to `OnDelete` so that the pods do not get deleted if the DaemonSet is updated while also -ensuring that the pods will be updated on the next node reboot (or node drain). - -The new holder DaemonSet only contains a single container called `holder`, the container -responsible for pinning the network for filesystem mounts and mapped block devices. It is used as a passthrough by -the Ceph-CSI plugin pod which when mounting or mapping will use the network namespace of that holder -pod. - -One task of the Holder container is to pass the required PID into the `csi-plugin` pod. To -solve this, the container will create a symlink to an equivalent of `/proc/$$/ns/net` in the -`hostPath` volume shared with the `csi-plugin` pod. Then it will sleep forever. -In order to support multiple Ceph-CSI consuming multiple Ceph clusters, the name of the symlink should be based on the Ceph -cluster FSID. The complete name of the symlink can be decided during the implementation phase of the -design. -That symlink name will be stored in the Ceph-CSI configmap with a key name that we will define -during the implementation. - -#### Interactions between components -When the Ceph-CSI plugin mounts or maps a block device it will use the network namespace of the -Holder pod. This is achieved by using `nsenter` to enter the network namespace of the Holder pod. -Some changes are expected as part of the mounting/mapping method in today's `csi-plugin` pod. -Instead of invoking `rbd map ...`, invoke `nsenter --net= rbd map ...` (and same for `mount -t ceph ...`). The `csi-plugin` -pod is already privileged, it already adds `CAP_SYS_ADMIN`. The only missing piece is to expose the host -PID namespace with `hostPID: true` on the `csi-cephfsplugin` DaemonSet (RBD already has it). - -Cleaning up the symlink is not a requirement nor a big issue. Once the Holder container stops, its -network namespace goes away with it. So at worst, we end up with a broken symlink. - -When a new node is added, both DaemonSets are started, and the -process described above occurs on the node. - -The initial implementation of this design is limited to supporting a single CephCluster with -Multus. -Until we stop using HostNetwork entirely it is impossible to support multiple CephClusters with and -without Multus enabled. - ## Accepted proposal So far, the team has decided to go with the [whereabouts](https://github.com/dougbtv/whereabouts) IPAM. diff --git a/go.mod b/go.mod index db922fc34d1e..2eeb5de1261d 100644 --- a/go.mod +++ b/go.mod @@ -45,14 +45,14 @@ require ( golang.org/x/sync v0.8.0 gopkg.in/ini.v1 v1.67.0 gopkg.in/yaml.v2 v2.4.0 - k8s.io/api v0.31.1 - k8s.io/apiextensions-apiserver v0.31.1 - k8s.io/apimachinery v0.31.1 - k8s.io/cli-runtime v0.31.1 - k8s.io/client-go v0.31.1 - k8s.io/cloud-provider v0.31.1 + k8s.io/api v0.31.2 + k8s.io/apiextensions-apiserver v0.31.2 + k8s.io/apimachinery v0.31.2 + k8s.io/cli-runtime v0.31.2 + k8s.io/client-go v0.31.2 + k8s.io/cloud-provider v0.31.2 k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 - sigs.k8s.io/controller-runtime v0.19.0 + sigs.k8s.io/controller-runtime v0.19.1 sigs.k8s.io/mcs-api v0.1.0 sigs.k8s.io/yaml v1.4.0 ) diff --git a/go.sum b/go.sum index a23d2eeb71c2..5a29b130a639 100644 --- a/go.sum +++ b/go.sum @@ -1605,15 +1605,15 @@ k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ= k8s.io/api v0.23.5/go.mod h1:Na4XuKng8PXJ2JsploYYrivXrINeTaycCGcYgF91Xm8= k8s.io/api v0.26.0/go.mod h1:k6HDTaIFC8yn1i6pSClSqIwLABIcLV9l5Q4EcngKnQg= -k8s.io/api v0.31.1 h1:Xe1hX/fPW3PXYYv8BlozYqw63ytA92snr96zMW9gWTU= -k8s.io/api v0.31.1/go.mod h1:sbN1g6eY6XVLeqNsZGLnI5FwVseTrZX7Fv3O26rhAaI= +k8s.io/api v0.31.2 h1:3wLBbL5Uom/8Zy98GRPXpJ254nEFpl+hwndmk9RwmL0= +k8s.io/api v0.31.2/go.mod h1:bWmGvrGPssSK1ljmLzd3pwCQ9MgoTsRCuK35u6SygUk= k8s.io/apiextensions-apiserver v0.0.0-20190409022649-727a075fdec8/go.mod h1:IxkesAMoaCRoLrPJdZNZUQp9NfZnzqaVzLhb2VEQzXE= k8s.io/apiextensions-apiserver v0.18.2/go.mod h1:q3faSnRGmYimiocj6cHQ1I3WpLqmDgJFlKL37fC4ZvY= k8s.io/apiextensions-apiserver v0.18.3/go.mod h1:TMsNGs7DYpMXd+8MOCX8KzPOCx8fnZMoIGB24m03+JE= k8s.io/apiextensions-apiserver v0.18.4/go.mod h1:NYeyeYq4SIpFlPxSAB6jHPIdvu3hL0pc36wuRChybio= k8s.io/apiextensions-apiserver v0.20.1/go.mod h1:ntnrZV+6a3dB504qwC5PN/Yg9PBiDNt1EVqbW2kORVk= -k8s.io/apiextensions-apiserver v0.31.1 h1:L+hwULvXx+nvTYX/MKM3kKMZyei+UiSXQWciX/N6E40= -k8s.io/apiextensions-apiserver v0.31.1/go.mod h1:tWMPR3sgW+jsl2xm9v7lAyRF1rYEK71i9G5dRtkknoQ= +k8s.io/apiextensions-apiserver v0.31.2 h1:W8EwUb8+WXBLu56ser5IudT2cOho0gAKeTOnywBLxd0= +k8s.io/apiextensions-apiserver v0.31.2/go.mod h1:i+Geh+nGCJEGiCGR3MlBDkS7koHIIKWVfWeRFiOsUcM= k8s.io/apimachinery v0.0.0-20190404173353-6a84e37a896d/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= k8s.io/apimachinery v0.18.2/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= k8s.io/apimachinery v0.18.3/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= @@ -1625,14 +1625,14 @@ k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRp k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= k8s.io/apimachinery v0.23.5/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM= k8s.io/apimachinery v0.26.0/go.mod h1:tnPmbONNJ7ByJNz9+n9kMjNP8ON+1qoAIIC70lztu74= -k8s.io/apimachinery v0.31.1 h1:mhcUBbj7KUjaVhyXILglcVjuS4nYXiwC+KKFBgIVy7U= -k8s.io/apimachinery v0.31.1/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= +k8s.io/apimachinery v0.31.2 h1:i4vUt2hPK56W6mlT7Ry+AO8eEsyxMD1U44NR22CLTYw= +k8s.io/apimachinery v0.31.2/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= k8s.io/apiserver v0.18.2/go.mod h1:Xbh066NqrZO8cbsoenCwyDJ1OSi8Ag8I2lezeHxzwzw= k8s.io/apiserver v0.18.3/go.mod h1:tHQRmthRPLUtwqsOnJJMoI8SW3lnoReZeE861lH8vUw= k8s.io/apiserver v0.18.4/go.mod h1:q+zoFct5ABNnYkGIaGQ3bcbUNdmPyOCoEBcg51LChY8= k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= -k8s.io/cli-runtime v0.31.1 h1:/ZmKhmZ6hNqDM+yf9s3Y4KEYakNXUn5sod2LWGGwCuk= -k8s.io/cli-runtime v0.31.1/go.mod h1:pKv1cDIaq7ehWGuXQ+A//1OIF+7DI+xudXtExMCbe9U= +k8s.io/cli-runtime v0.31.2 h1:7FQt4C4Xnqx8V1GJqymInK0FFsoC+fAZtbLqgXYVOLQ= +k8s.io/cli-runtime v0.31.2/go.mod h1:XROyicf+G7rQ6FQJMbeDV9jqxzkWXTYD6Uxd15noe0Q= k8s.io/client-go v0.18.2/go.mod h1:Xcm5wVGXX9HAA2JJ2sSBUn3tCJ+4SVlCbl2MNNv+CIU= k8s.io/client-go v0.18.3/go.mod h1:4a/dpQEvzAhT1BbuWW09qvIaGw6Gbu1gZYiQZIi1DMw= k8s.io/client-go v0.18.4/go.mod h1:f5sXwL4yAZRkAtzOxRWUhA/N8XzGCb+nPZI8PfobZ9g= @@ -1641,10 +1641,10 @@ k8s.io/client-go v0.19.2/go.mod h1:S5wPhCqyDNAlzM9CnEdgTGV4OqhsW3jGO1UM1epwfJA= k8s.io/client-go v0.20.0/go.mod h1:4KWh/g+Ocd8KkCwKF8vUNnmqgv+EVnQDK4MBF4oB5tY= k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= k8s.io/client-go v0.23.5/go.mod h1:flkeinTO1CirYgzMPRWxUCnV0G4Fbu2vLhYCObnt/r4= -k8s.io/client-go v0.31.1 h1:f0ugtWSbWpxHR7sjVpQwuvw9a3ZKLXX0u0itkFXufb0= -k8s.io/client-go v0.31.1/go.mod h1:sKI8871MJN2OyeqRlmA4W4KM9KBdBUpDLu/43eGemCg= -k8s.io/cloud-provider v0.31.1 h1:40b6AgDizwm5eWratZbqubTHMob25VWr6NX2Ei5TwZA= -k8s.io/cloud-provider v0.31.1/go.mod h1:xAdkE7fdZdu9rKLuOZUMBfagu7bM+bas3iPux/2nLGg= +k8s.io/client-go v0.31.2 h1:Y2F4dxU5d3AQj+ybwSMqQnpZH9F30//1ObxOKlTI9yc= +k8s.io/client-go v0.31.2/go.mod h1:NPa74jSVR/+eez2dFsEIHNa+3o09vtNaWwWwb1qSxSs= +k8s.io/cloud-provider v0.31.2 h1:ZdstxJOcHzP45j8giE79VJmgNckBbw1ldtIqnhZvKIA= +k8s.io/cloud-provider v0.31.2/go.mod h1:+4L8YpYCEx1Ko5EKS/PzXyBY5YREwDKChsJjAxHRf08= k8s.io/code-generator v0.18.2/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc= k8s.io/code-generator v0.18.3/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= k8s.io/code-generator v0.18.4/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= @@ -1699,8 +1699,8 @@ sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7/go.mod h1:PHgbrJT sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/controller-runtime v0.2.2/go.mod h1:9dyohw3ZtoXQuV1e766PHUn+cmrRCIcBh6XIMFNMZ+I= sigs.k8s.io/controller-runtime v0.6.1/go.mod h1:XRYBPdbf5XJu9kpS84VJiZ7h/u1hF3gEORz0efEja7A= -sigs.k8s.io/controller-runtime v0.19.0 h1:nWVM7aq+Il2ABxwiCizrVDSlmDcshi9llbaFbC0ji/Q= -sigs.k8s.io/controller-runtime v0.19.0/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= +sigs.k8s.io/controller-runtime v0.19.1 h1:Son+Q40+Be3QWb+niBXAg2vFiYWolDjjRfO8hn/cxOk= +sigs.k8s.io/controller-runtime v0.19.1/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= sigs.k8s.io/controller-tools v0.3.0/go.mod h1:enhtKGfxZD1GFEoMgP8Fdbu+uKQ/cq1/WGJhdVChfvI= sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= diff --git a/pkg/apis/ceph.rook.io/v1/resources.go b/pkg/apis/ceph.rook.io/v1/resources.go index b87089fdea56..daebe4aafc2e 100644 --- a/pkg/apis/ceph.rook.io/v1/resources.go +++ b/pkg/apis/ceph.rook.io/v1/resources.go @@ -31,6 +31,8 @@ const ( ResourcesKeyOSD = "osd" // ResourcesKeyPrepareOSD represents the name of resource in the CR for the osd prepare job ResourcesKeyPrepareOSD = "prepareosd" + // ResourcesKeyCmdReporter represents the name of resource in the CR for the detect version and network jobs + ResourcesKeyCmdReporter = "cmd-reporter" // ResourcesKeyMDS represents the name of resource in the CR for the mds ResourcesKeyMDS = "mds" // ResourcesKeyCrashCollector represents the name of resource in the CR for the crash @@ -47,22 +49,22 @@ const ( ResourcesKeyCephExporter = "exporter" ) -// GetMgrResources returns the placement for the MGR service +// GetMgrResources returns the resources for the MGR service func GetMgrResources(p ResourceSpec) v1.ResourceRequirements { return p[ResourcesKeyMgr] } -// GetMgrSidecarResources returns the placement for the MGR sidecar container +// GetMgrSidecarResources returns the resources for the MGR sidecar container func GetMgrSidecarResources(p ResourceSpec) v1.ResourceRequirements { return p[ResourcesKeyMgrSidecar] } -// GetMonResources returns the placement for the monitors +// GetMonResources returns the resources for the monitors func GetMonResources(p ResourceSpec) v1.ResourceRequirements { return p[ResourcesKeyMon] } -// GetOSDResources returns the placement for all OSDs or for OSDs of specified device class (hdd, nvme, ssd) +// GetOSDResources returns the resources for all OSDs or for OSDs of specified device class (hdd, nvme, ssd) func GetOSDResources(p ResourceSpec, deviceClass string) v1.ResourceRequirements { if deviceClass == "" { return p[ResourcesKeyOSD] @@ -80,27 +82,32 @@ func getOSDResourceKeyForDeviceClass(deviceClass string) string { return ResourcesKeyOSD + "-" + deviceClass } -// GetPrepareOSDResources returns the placement for the OSDs prepare job +// GetPrepareOSDResources returns the resources for the OSDs prepare job func GetPrepareOSDResources(p ResourceSpec) v1.ResourceRequirements { return p[ResourcesKeyPrepareOSD] } -// GetCrashCollectorResources returns the placement for the crash daemon +// GetCmdReporterResources returns the resources for the detect version job +func GetCmdReporterResources(p ResourceSpec) v1.ResourceRequirements { + return p[ResourcesKeyCmdReporter] +} + +// GetCrashCollectorResources returns the resources for the crash daemon func GetCrashCollectorResources(p ResourceSpec) v1.ResourceRequirements { return p[ResourcesKeyCrashCollector] } -// GetLogCollectorResources returns the placement for the crash daemon +// GetLogCollectorResources returns the resources for the logo collector func GetLogCollectorResources(p ResourceSpec) v1.ResourceRequirements { return p[ResourcesKeyLogCollector] } -// GetCleanupResources returns the placement for the cleanup job +// GetCleanupResources returns the resources for the cleanup job func GetCleanupResources(p ResourceSpec) v1.ResourceRequirements { return p[ResourcesKeyCleanup] } -// GetCephExporterResources returns the placement for the cleanup job +// GetCephExporterResources returns the resources for the cleanup job func GetCephExporterResources(p ResourceSpec) v1.ResourceRequirements { return p[ResourcesKeyCephExporter] } diff --git a/pkg/apis/ceph.rook.io/v1/types.go b/pkg/apis/ceph.rook.io/v1/types.go index 61812212b663..29db7c730fdc 100755 --- a/pkg/apis/ceph.rook.io/v1/types.go +++ b/pkg/apis/ceph.rook.io/v1/types.go @@ -861,11 +861,11 @@ type CephBlockPoolStatus struct { Conditions []Condition `json:"conditions,omitempty"` } -// MirroringStatusSpec is the status of the pool mirroring +// MirroringStatusSpec is the status of the pool/radosNamespace mirroring type MirroringStatusSpec struct { - // PoolMirroringStatus is the mirroring status of a pool + // MirroringStatus is the mirroring status of a pool/radosNamespace // +optional - PoolMirroringStatus `json:",inline"` + MirroringStatus `json:",inline"` // LastChecked is the last time time the status was checked // +optional LastChecked string `json:"lastChecked,omitempty"` @@ -877,15 +877,15 @@ type MirroringStatusSpec struct { Details string `json:"details,omitempty"` } -// PoolMirroringStatus is the pool mirror status -type PoolMirroringStatus struct { +// MirroringStatus is the pool/radosNamespace mirror status +type MirroringStatus struct { // Summary is the mirroring status summary // +optional - Summary *PoolMirroringStatusSummarySpec `json:"summary,omitempty"` + Summary *MirroringStatusSummarySpec `json:"summary,omitempty"` } -// PoolMirroringStatusSummarySpec is the summary output of the command -type PoolMirroringStatusSummarySpec struct { +// MirroringStatusSummarySpec is the summary output of the command +type MirroringStatusSummarySpec struct { // Health is the mirroring health // +optional Health string `json:"health,omitempty"` @@ -926,10 +926,10 @@ type StatesSpec struct { Error int `json:"error,omitempty"` } -// MirroringInfoSpec is the status of the pool mirroring +// MirroringInfoSpec is the status of the pool/radosnamespace mirroring type MirroringInfoSpec struct { // +optional - *PoolMirroringInfo `json:",inline"` + *MirroringInfo `json:",inline"` // +optional LastChecked string `json:"lastChecked,omitempty"` // +optional @@ -938,8 +938,8 @@ type MirroringInfoSpec struct { Details string `json:"details,omitempty"` } -// PoolMirroringInfo is the mirroring info of a given pool -type PoolMirroringInfo struct { +// MirroringInfo is the mirroring info of a given pool/radosnamespace +type MirroringInfo struct { // Mode is the mirroring mode // +optional Mode string `json:"mode,omitempty"` @@ -1563,6 +1563,11 @@ type PoolPlacementSpec struct { // +kubebuilder:validation:Pattern=`^[a-zA-Z0-9._/-]+$` Name string `json:"name"` + // Sets given placement as default. Only one placement in the list can be marked as default. + // Default is false. + // +optional + Default bool `json:"default"` + // The metadata pool used to store ObjectStore bucket index. // +kubebuilder:validation:Required // +kubebuilder:validation:MinLength=1 @@ -3032,6 +3037,9 @@ type StorageScopeSpec struct { // +optional UseAllNodes bool `json:"useAllNodes,omitempty"` // +optional + // Whether to always schedule OSDs on a node even if the node is not currently scheduleable or ready + ScheduleAlways bool `json:"scheduleAlways,omitempty"` + // +optional OnlyApplyOSDPlacement bool `json:"onlyApplyOSDPlacement,omitempty"` // +kubebuilder:pruning:PreserveUnknownFields // +nullable @@ -3386,6 +3394,12 @@ type CephBlockPoolRadosNamespaceStatus struct { // +optional // +nullable Info map[string]string `json:"info,omitempty"` + // +optional + MirroringStatus *MirroringStatusSpec `json:"mirroringStatus,omitempty"` + // +optional + MirroringInfo *MirroringInfoSpec `json:"mirroringInfo,omitempty"` + // +optional + SnapshotScheduleStatus *SnapshotScheduleStatusSpec `json:"snapshotScheduleStatus,omitempty"` } // Represents the source of a volume to mount. diff --git a/pkg/apis/ceph.rook.io/v1/zz_generated.deepcopy.go b/pkg/apis/ceph.rook.io/v1/zz_generated.deepcopy.go index e653d3869f9b..92e443c3e9c1 100644 --- a/pkg/apis/ceph.rook.io/v1/zz_generated.deepcopy.go +++ b/pkg/apis/ceph.rook.io/v1/zz_generated.deepcopy.go @@ -482,6 +482,21 @@ func (in *CephBlockPoolRadosNamespaceStatus) DeepCopyInto(out *CephBlockPoolRado (*out)[key] = val } } + if in.MirroringStatus != nil { + in, out := &in.MirroringStatus, &out.MirroringStatus + *out = new(MirroringStatusSpec) + (*in).DeepCopyInto(*out) + } + if in.MirroringInfo != nil { + in, out := &in.MirroringInfo, &out.MirroringInfo + *out = new(MirroringInfoSpec) + (*in).DeepCopyInto(*out) + } + if in.SnapshotScheduleStatus != nil { + in, out := &in.SnapshotScheduleStatus, &out.SnapshotScheduleStatus + *out = new(SnapshotScheduleStatusSpec) + (*in).DeepCopyInto(*out) + } return } @@ -3083,12 +3098,33 @@ func (in *MirrorHealthCheckSpec) DeepCopy() *MirrorHealthCheckSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MirroringInfo) DeepCopyInto(out *MirroringInfo) { + *out = *in + if in.Peers != nil { + in, out := &in.Peers, &out.Peers + *out = make([]PeersSpec, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MirroringInfo. +func (in *MirroringInfo) DeepCopy() *MirroringInfo { + if in == nil { + return nil + } + out := new(MirroringInfo) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MirroringInfoSpec) DeepCopyInto(out *MirroringInfoSpec) { *out = *in - if in.PoolMirroringInfo != nil { - in, out := &in.PoolMirroringInfo, &out.PoolMirroringInfo - *out = new(PoolMirroringInfo) + if in.MirroringInfo != nil { + in, out := &in.MirroringInfo, &out.MirroringInfo + *out = new(MirroringInfo) (*in).DeepCopyInto(*out) } return @@ -3151,10 +3187,31 @@ func (in *MirroringSpec) DeepCopy() *MirroringSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MirroringStatus) DeepCopyInto(out *MirroringStatus) { + *out = *in + if in.Summary != nil { + in, out := &in.Summary, &out.Summary + *out = new(MirroringStatusSummarySpec) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MirroringStatus. +func (in *MirroringStatus) DeepCopy() *MirroringStatus { + if in == nil { + return nil + } + out := new(MirroringStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MirroringStatusSpec) DeepCopyInto(out *MirroringStatusSpec) { *out = *in - in.PoolMirroringStatus.DeepCopyInto(&out.PoolMirroringStatus) + in.MirroringStatus.DeepCopyInto(&out.MirroringStatus) return } @@ -3168,6 +3225,23 @@ func (in *MirroringStatusSpec) DeepCopy() *MirroringStatusSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MirroringStatusSummarySpec) DeepCopyInto(out *MirroringStatusSummarySpec) { + *out = *in + out.States = in.States + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MirroringStatusSummarySpec. +func (in *MirroringStatusSummarySpec) DeepCopy() *MirroringStatusSummarySpec { + if in == nil { + return nil + } + out := new(MirroringStatusSummarySpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Module) DeepCopyInto(out *Module) { *out = *in @@ -4059,65 +4133,6 @@ func (in *PlacementStorageClassSpec) DeepCopy() *PlacementStorageClassSpec { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PoolMirroringInfo) DeepCopyInto(out *PoolMirroringInfo) { - *out = *in - if in.Peers != nil { - in, out := &in.Peers, &out.Peers - *out = make([]PeersSpec, len(*in)) - copy(*out, *in) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PoolMirroringInfo. -func (in *PoolMirroringInfo) DeepCopy() *PoolMirroringInfo { - if in == nil { - return nil - } - out := new(PoolMirroringInfo) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PoolMirroringStatus) DeepCopyInto(out *PoolMirroringStatus) { - *out = *in - if in.Summary != nil { - in, out := &in.Summary, &out.Summary - *out = new(PoolMirroringStatusSummarySpec) - **out = **in - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PoolMirroringStatus. -func (in *PoolMirroringStatus) DeepCopy() *PoolMirroringStatus { - if in == nil { - return nil - } - out := new(PoolMirroringStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PoolMirroringStatusSummarySpec) DeepCopyInto(out *PoolMirroringStatusSummarySpec) { - *out = *in - out.States = in.States - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PoolMirroringStatusSummarySpec. -func (in *PoolMirroringStatusSummarySpec) DeepCopy() *PoolMirroringStatusSummarySpec { - if in == nil { - return nil - } - out := new(PoolMirroringStatusSummarySpec) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PoolPlacementSpec) DeepCopyInto(out *PoolPlacementSpec) { *out = *in diff --git a/pkg/apis/go.mod b/pkg/apis/go.mod index 2626abd58642..cbaa66097259 100644 --- a/pkg/apis/go.mod +++ b/pkg/apis/go.mod @@ -21,8 +21,8 @@ require ( github.com/libopenstorage/secrets v0.0.0-20240416031220-a17cf7f72c6c github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.9.0 - k8s.io/api v0.31.1 - k8s.io/apimachinery v0.31.1 + k8s.io/api v0.31.2 + k8s.io/apimachinery v0.31.2 ) require ( @@ -36,7 +36,7 @@ require ( github.com/onsi/gomega v1.34.2 // indirect github.com/x448/float16 v0.8.4 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - k8s.io/client-go v0.31.1 // indirect + k8s.io/client-go v0.31.2 // indirect k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/pkg/apis/go.sum b/pkg/apis/go.sum index f0be261e2938..1bd4a99ba98f 100644 --- a/pkg/apis/go.sum +++ b/pkg/apis/go.sum @@ -1408,8 +1408,8 @@ k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ= k8s.io/api v0.23.5/go.mod h1:Na4XuKng8PXJ2JsploYYrivXrINeTaycCGcYgF91Xm8= k8s.io/api v0.26.0/go.mod h1:k6HDTaIFC8yn1i6pSClSqIwLABIcLV9l5Q4EcngKnQg= -k8s.io/api v0.31.1 h1:Xe1hX/fPW3PXYYv8BlozYqw63ytA92snr96zMW9gWTU= -k8s.io/api v0.31.1/go.mod h1:sbN1g6eY6XVLeqNsZGLnI5FwVseTrZX7Fv3O26rhAaI= +k8s.io/api v0.31.2 h1:3wLBbL5Uom/8Zy98GRPXpJ254nEFpl+hwndmk9RwmL0= +k8s.io/api v0.31.2/go.mod h1:bWmGvrGPssSK1ljmLzd3pwCQ9MgoTsRCuK35u6SygUk= k8s.io/apiextensions-apiserver v0.0.0-20190409022649-727a075fdec8/go.mod h1:IxkesAMoaCRoLrPJdZNZUQp9NfZnzqaVzLhb2VEQzXE= k8s.io/apiextensions-apiserver v0.18.3/go.mod h1:TMsNGs7DYpMXd+8MOCX8KzPOCx8fnZMoIGB24m03+JE= k8s.io/apiextensions-apiserver v0.20.1/go.mod h1:ntnrZV+6a3dB504qwC5PN/Yg9PBiDNt1EVqbW2kORVk= @@ -1422,8 +1422,8 @@ k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRp k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= k8s.io/apimachinery v0.23.5/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM= k8s.io/apimachinery v0.26.0/go.mod h1:tnPmbONNJ7ByJNz9+n9kMjNP8ON+1qoAIIC70lztu74= -k8s.io/apimachinery v0.31.1 h1:mhcUBbj7KUjaVhyXILglcVjuS4nYXiwC+KKFBgIVy7U= -k8s.io/apimachinery v0.31.1/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= +k8s.io/apimachinery v0.31.2 h1:i4vUt2hPK56W6mlT7Ry+AO8eEsyxMD1U44NR22CLTYw= +k8s.io/apimachinery v0.31.2/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= k8s.io/apiserver v0.18.3/go.mod h1:tHQRmthRPLUtwqsOnJJMoI8SW3lnoReZeE861lH8vUw= k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= k8s.io/client-go v0.18.3/go.mod h1:4a/dpQEvzAhT1BbuWW09qvIaGw6Gbu1gZYiQZIi1DMw= @@ -1432,8 +1432,8 @@ k8s.io/client-go v0.19.2/go.mod h1:S5wPhCqyDNAlzM9CnEdgTGV4OqhsW3jGO1UM1epwfJA= k8s.io/client-go v0.20.0/go.mod h1:4KWh/g+Ocd8KkCwKF8vUNnmqgv+EVnQDK4MBF4oB5tY= k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= k8s.io/client-go v0.23.5/go.mod h1:flkeinTO1CirYgzMPRWxUCnV0G4Fbu2vLhYCObnt/r4= -k8s.io/client-go v0.31.1 h1:f0ugtWSbWpxHR7sjVpQwuvw9a3ZKLXX0u0itkFXufb0= -k8s.io/client-go v0.31.1/go.mod h1:sKI8871MJN2OyeqRlmA4W4KM9KBdBUpDLu/43eGemCg= +k8s.io/client-go v0.31.2 h1:Y2F4dxU5d3AQj+ybwSMqQnpZH9F30//1ObxOKlTI9yc= +k8s.io/client-go v0.31.2/go.mod h1:NPa74jSVR/+eez2dFsEIHNa+3o09vtNaWwWwb1qSxSs= k8s.io/code-generator v0.18.3/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= k8s.io/code-generator v0.19.0/go.mod h1:moqLn7w0t9cMs4+5CQyxnfA/HV8MF6aAVENF+WZZhgk= k8s.io/code-generator v0.20.0/go.mod h1:UsqdF+VX4PU2g46NC2JRs4gc+IfrctnwHb76RNbWHJg= diff --git a/pkg/daemon/ceph/cleanup/radosnamespace.go b/pkg/daemon/ceph/cleanup/radosnamespace.go index 1ebb6f09a761..a7381b0d180f 100644 --- a/pkg/daemon/ceph/cleanup/radosnamespace.go +++ b/pkg/daemon/ceph/cleanup/radosnamespace.go @@ -17,6 +17,8 @@ limitations under the License. package cleanup import ( + "fmt" + "github.com/pkg/errors" "github.com/rook/rook/pkg/clusterd" "github.com/rook/rook/pkg/daemon/ceph/client" @@ -26,46 +28,67 @@ import ( func RadosNamespaceCleanup(context *clusterd.Context, clusterInfo *client.ClusterInfo, poolName, radosNamespace string) error { logger.Infof("starting clean up of CephBlockPoolRadosNamespace %q resources in cephblockpool %q", radosNamespace, poolName) + err := cleanupImages(context, clusterInfo, poolName, radosNamespace) + if err != nil { + logger.Errorf("failed to clean up CephBlockPoolRadosNamespace %q resources in cephblockpool %q", radosNamespace, poolName) + return err + } + + logger.Infof("successfully cleaned up CephBlockPoolRadosNamespace %q resources in cephblockpool %q", radosNamespace, poolName) + return nil +} + +func cleanupImages(context *clusterd.Context, clusterInfo *client.ClusterInfo, poolName, radosNamespace string) error { + msg := fmt.Sprintf("cephblockpool %q", poolName) + if radosNamespace != "" { + msg = fmt.Sprintf("%s in rados namespace %q", msg, radosNamespace) + } images, err := cephclient.ListImagesInRadosNamespace(context, clusterInfo, poolName, radosNamespace) if err != nil { - return errors.Wrapf(err, "failed to list images in cephblockpool %q in rados namespace %q", poolName, radosNamespace) + return errors.Wrapf(err, "failed to list images in %s", msg) } var retErr error for _, image := range images { snaps, err := cephclient.ListSnapshotsInRadosNamespace(context, clusterInfo, poolName, image.Name, radosNamespace) if err != nil { - retErr = errors.Wrapf(err, "failed to list snapshots for the image %q in cephblockpool %q in rados namespace %q.", image.Name, poolName, radosNamespace) + retErr = errors.Wrapf(err, "failed to list snapshots for the image %q in %s", image.Name, msg) logger.Error(retErr) } for _, snap := range snaps { err := cephclient.DeleteSnapshotInRadosNamespace(context, clusterInfo, poolName, image.Name, snap.Name, radosNamespace) if err != nil { - retErr = errors.Wrapf(err, "failed to delete snapshot %q of the image %q in cephblockpool %q in rados namespace %q.", snap.Name, image.Name, poolName, radosNamespace) + retErr = errors.Wrapf(err, "failed to delete snapshot %q of the image %q in %s", snap.Name, image.Name, msg) logger.Error(retErr) } else { - logger.Infof("successfully deleted snapshot %q of image %q in cephblockpool %q in rados namespace %q", snap.Name, image.Name, poolName, radosNamespace) + logger.Infof("successfully deleted snapshot %q of image %q in %s", snap.Name, image.Name, msg) } } err = cephclient.MoveImageToTrashInRadosNamespace(context, clusterInfo, poolName, image.Name, radosNamespace) if err != nil { - retErr = errors.Wrapf(err, "failed to move image %q to trash in cephblockpool %q in rados namespace %q.", image.Name, poolName, radosNamespace) + retErr = errors.Wrapf(err, "failed to move image %q to trash in %s", image.Name, msg) logger.Error(retErr) } err = cephclient.DeleteImageFromTrashInRadosNamespace(context, clusterInfo, poolName, image.ID, radosNamespace) if err != nil { - retErr = errors.Wrapf(err, "failed to add task to remove image %q from trash in cephblockpool %q in rados namespace %q.", image.Name, poolName, radosNamespace) + retErr = errors.Wrapf(err, "failed to add task to remove image %q from trash in %s", image.Name, msg) logger.Error(retErr) } } + return retErr +} - if retErr != nil { - logger.Errorf("failed to clean up CephBlockPoolRadosNamespace %q resources in cephblockpool %q", radosNamespace, poolName) - return retErr +func BlockPoolCleanup(context *clusterd.Context, clusterInfo *client.ClusterInfo, poolName string) error { + logger.Infof("starting clean up of CephBlockPool %q resource", poolName) + + err := cleanupImages(context, clusterInfo, poolName, "") + if err != nil { + logger.Errorf("failed to clean up CephBlockPool %q resource", poolName) + return err } - logger.Infof("successfully cleaned up CephBlockPoolRadosNamespace %q resources in cephblockpool %q", radosNamespace, poolName) + logger.Infof("successfully cleaned up CephBlockPool %q resource", poolName) return nil } diff --git a/pkg/daemon/ceph/cleanup/radosnamespace_test.go b/pkg/daemon/ceph/cleanup/radosnamespace_test.go index eb6d7aca2cb0..6010982e43da 100644 --- a/pkg/daemon/ceph/cleanup/radosnamespace_test.go +++ b/pkg/daemon/ceph/cleanup/radosnamespace_test.go @@ -90,3 +90,56 @@ func TestRadosNamespace(t *testing.T) { assert.NoError(t, err) }) } + +func TestBlockPoolCleanup(t *testing.T) { + clusterInfo := cephclient.AdminTestClusterInfo("mycluster") + poolName := "test-pool" + + t.Run("no images in blockpool", func(t *testing.T) { + executor := &exectest.MockExecutor{} + executor.MockExecuteCommandWithOutput = func(command string, args ...string) (string, error) { + logger.Infof("Command: %s %v", command, args) + if args[0] == "ls" && args[1] == "-l" { + assert.Equal(t, poolName, args[2]) + return "", nil + } + return "", errors.New("unknown command") + } + context := &clusterd.Context{Executor: executor} + err := BlockPoolCleanup(context, clusterInfo, poolName) + assert.NoError(t, err) + }) + + t.Run("images with snapshots available in blockpool", func(t *testing.T) { + executor := &exectest.MockExecutor{} + executor.MockExecuteCommandWithOutput = func(command string, args ...string) (string, error) { + logger.Infof("Command: %s %v", command, args) + // list all subvolumes in subvolumegroup + if args[0] == "ls" && args[1] == "-l" { + assert.Equal(t, poolName, args[2]) + return mockImageLSResponse, nil + } + if args[0] == "snap" && args[1] == "ls" { + assert.Equal(t, "test-pool/csi-vol-136268e8-5386-4453-a6bd-9dca381d187d", args[2]) + return mockSnapshotsResponse, nil + } + if args[0] == "snap" && args[1] == "rm" { + assert.Equal(t, "test-pool/csi-vol-136268e8-5386-4453-a6bd-9dca381d187d@snap1", args[2]) + return "", nil + } + if args[0] == "trash" && args[1] == "mv" { + assert.Equal(t, "test-pool/csi-vol-136268e8-5386-4453-a6bd-9dca381d187d", args[2]) + return "", nil + } + if args[0] == "rbd" && args[1] == "task" && args[2] == "add" && args[3] == "trash" { + // pool-name/image-id + assert.Equal(t, "test-pool/16e35cfa56a7", args[5]) + return "", nil + } + return "", errors.New("unknown command") + } + context := &clusterd.Context{Executor: executor} + err := BlockPoolCleanup(context, clusterInfo, poolName) + assert.NoError(t, err) + }) +} diff --git a/pkg/daemon/ceph/client/filesystem.go b/pkg/daemon/ceph/client/filesystem.go index 048f7ce1bd0d..1798a9411fbd 100644 --- a/pkg/daemon/ceph/client/filesystem.go +++ b/pkg/daemon/ceph/client/filesystem.go @@ -20,6 +20,7 @@ import ( ctx "context" "encoding/json" "fmt" + "regexp" "strconv" "syscall" "time" @@ -362,14 +363,14 @@ func deleteFSPool(context *clusterd.Context, clusterInfo *ClusterInfo, poolNames } // WaitForNoStandbys waits for all standbys go away -func WaitForNoStandbys(context *clusterd.Context, clusterInfo *ClusterInfo, retryInterval, timeout time.Duration) error { +func WaitForNoStandbys(context *clusterd.Context, clusterInfo *ClusterInfo, fsName string, retryInterval, timeout time.Duration) error { err := wait.PollUntilContextTimeout(clusterInfo.Context, retryInterval, timeout, true, func(ctx ctx.Context) (bool, error) { mdsDump, err := GetMDSDump(context, clusterInfo) if err != nil { logger.Errorf("failed to get fs dump. %v", err) return false, nil } - return len(mdsDump.Standbys) == 0, nil + return !filesystemHasStandby(mdsDump, fsName), nil }) if err != nil { @@ -378,6 +379,21 @@ func WaitForNoStandbys(context *clusterd.Context, clusterInfo *ClusterInfo, retr return nil } +func filesystemHasStandby(dump *MDSDump, fsName string) bool { + for _, standby := range dump.Standbys { + // The mds dump does not explicitly return the name of the filesystem that the + // daemon belongs to, so the matching to the filesystem name is based on the mds daemon name + // with a regular expression comparison with the expected suffix. + // For example, if the filesystem is "myfs", the standby name may be "myfs-a" or "myfs-b". + matchString := fmt.Sprintf("^%s-[a-z]{1}$", fsName) + matched, _ := regexp.MatchString(matchString, standby.Name) + if matched { + return true + } + } + return false +} + func GetMDSDump(context *clusterd.Context, clusterInfo *ClusterInfo) (*MDSDump, error) { args := []string{"fs", "dump"} cmd := NewCephCommand(context, clusterInfo, args) diff --git a/pkg/daemon/ceph/client/filesystem_test.go b/pkg/daemon/ceph/client/filesystem_test.go index e23a8412891a..2fcb89992109 100644 --- a/pkg/daemon/ceph/client/filesystem_test.go +++ b/pkg/daemon/ceph/client/filesystem_test.go @@ -520,9 +520,33 @@ func TestGetMDSDump(t *testing.T) { assert.Error(t, err) } +func TestFSHasStandby(t *testing.T) { + // Not found in an empty list + fsName := "foo" + dump := &MDSDump{} + assert.False(t, filesystemHasStandby(dump, fsName)) + + // Not found with a non-matching name + dump = &MDSDump{Standbys: []MDSStandBy{{Name: "foo-cd"}}} + assert.False(t, filesystemHasStandby(dump, fsName)) + + // Found in the list with -a suffix + dump = &MDSDump{Standbys: []MDSStandBy{{Name: "foo-a"}}} + assert.True(t, filesystemHasStandby(dump, fsName)) + + // Found in the list with -c suffix + dump = &MDSDump{Standbys: []MDSStandBy{{Name: "foo-c"}}} + assert.True(t, filesystemHasStandby(dump, fsName)) + + // Does not match another filesystem + fsName = "bar" + assert.False(t, filesystemHasStandby(dump, fsName)) +} + func TestWaitForNoStandbys(t *testing.T) { executor := &exectest.MockExecutor{} context := &clusterd.Context{Executor: executor} + fsName := "rook-ceph-filesystem" executor.MockExecuteCommandWithOutput = func(command string, args ...string) (string, error) { logger.Infof("Command: %s %v", command, args) if args[0] == "fs" { @@ -542,7 +566,7 @@ func TestWaitForNoStandbys(t *testing.T) { return "", errors.Errorf("unexpected ceph command %q", args) } - err := WaitForNoStandbys(context, AdminTestClusterInfo("mycluster"), time.Millisecond, 5*time.Millisecond) + err := WaitForNoStandbys(context, AdminTestClusterInfo("mycluster"), fsName, time.Millisecond, 5*time.Millisecond) assert.Error(t, err) executor.MockExecuteCommandWithOutput = func(command string, args ...string) (string, error) { @@ -555,7 +579,7 @@ func TestWaitForNoStandbys(t *testing.T) { return "", errors.Errorf("unexpected ceph command %q", args) } - err = WaitForNoStandbys(context, AdminTestClusterInfo("mycluster"), time.Millisecond, 5*time.Millisecond) + err = WaitForNoStandbys(context, AdminTestClusterInfo("mycluster"), fsName, time.Millisecond, 5*time.Millisecond) assert.Error(t, err) firstCall := true @@ -582,7 +606,7 @@ func TestWaitForNoStandbys(t *testing.T) { } return "", errors.Errorf("unexpected ceph command %q", args) } - err = WaitForNoStandbys(context, AdminTestClusterInfo("mycluster"), time.Millisecond, 5*time.Millisecond) + err = WaitForNoStandbys(context, AdminTestClusterInfo("mycluster"), fsName, time.Millisecond, 5*time.Millisecond) assert.NoError(t, err) } diff --git a/pkg/daemon/ceph/client/image.go b/pkg/daemon/ceph/client/image.go index f16fa2334277..8ea707d9cc75 100644 --- a/pkg/daemon/ceph/client/image.go +++ b/pkg/daemon/ceph/client/image.go @@ -85,7 +85,10 @@ func ListImagesInRadosNamespace(context *clusterd.Context, clusterInfo *ClusterI // ListSnapshotsInRadosNamespace lists all the snapshots created for an image in a cephblockpool in a given rados namespace func ListSnapshotsInRadosNamespace(context *clusterd.Context, clusterInfo *ClusterInfo, poolName, imageName, namespace string) ([]CephBlockImageSnapshot, error) { snapshots := []CephBlockImageSnapshot{} - args := []string{"snap", "ls", getImageSpec(imageName, poolName), "--namespace", namespace} + args := []string{"snap", "ls", getImageSpec(imageName, poolName)} + if namespace != "" { + args = append(args, "--namespace", namespace) + } cmd := NewRBDCommand(context, clusterInfo, args) cmd.JsonOutput = true buf, err := cmd.Run() @@ -101,7 +104,10 @@ func ListSnapshotsInRadosNamespace(context *clusterd.Context, clusterInfo *Clust // DeleteSnapshotInRadosNamespace deletes a image snapshot created in block pool in a given rados namespace func DeleteSnapshotInRadosNamespace(context *clusterd.Context, clusterInfo *ClusterInfo, poolName, imageName, snapshot, namespace string) error { - args := []string{"snap", "rm", getImageSnapshotSpec(poolName, imageName, snapshot), "--namespace", namespace} + args := []string{"snap", "rm", getImageSnapshotSpec(poolName, imageName, snapshot)} + if namespace != "" { + args = append(args, "--namespace", namespace) + } cmd := NewRBDCommand(context, clusterInfo, args) _, err := cmd.Run() if err != nil { @@ -112,7 +118,10 @@ func DeleteSnapshotInRadosNamespace(context *clusterd.Context, clusterInfo *Clus // MoveImageToTrashInRadosNamespace moves the cephblockpool image to trash in the rados namespace func MoveImageToTrashInRadosNamespace(context *clusterd.Context, clusterInfo *ClusterInfo, poolName, imageName, namespace string) error { - args := []string{"trash", "mv", getImageSpec(imageName, poolName), "--namespace", namespace} + args := []string{"trash", "mv", getImageSpec(imageName, poolName)} + if namespace != "" { + args = append(args, "--namespace", namespace) + } cmd := NewRBDCommand(context, clusterInfo, args) _, err := cmd.Run() if err != nil { @@ -268,8 +277,12 @@ func getImageSpec(name, poolName string) string { } func getImageSpecInRadosNamespace(poolName, namespace, imageID string) string { + if namespace == "" { + return fmt.Sprintf("%s/%s", poolName, imageID) + } return fmt.Sprintf("%s/%s/%s", poolName, namespace, imageID) } + func getImageSnapshotSpec(poolName, imageName, snapshot string) string { return fmt.Sprintf("%s/%s@%s", poolName, imageName, snapshot) } diff --git a/pkg/daemon/ceph/client/mirror.go b/pkg/daemon/ceph/client/mirror.go index 0837cb761590..e153a3d578f9 100644 --- a/pkg/daemon/ceph/client/mirror.go +++ b/pkg/daemon/ceph/client/mirror.go @@ -165,7 +165,7 @@ func RemoveClusterPeer(context *clusterd.Context, clusterInfo *ClusterInfo, pool } // GetPoolMirroringStatus prints the pool mirroring status -func GetPoolMirroringStatus(context *clusterd.Context, clusterInfo *ClusterInfo, poolName string) (*cephv1.PoolMirroringStatus, error) { +func GetPoolMirroringStatus(context *clusterd.Context, clusterInfo *ClusterInfo, poolName string) (*cephv1.MirroringStatus, error) { logger.Debugf("retrieving mirroring pool %q status", poolName) // Build command @@ -179,7 +179,7 @@ func GetPoolMirroringStatus(context *clusterd.Context, clusterInfo *ClusterInfo, return nil, errors.Wrapf(err, "failed to retrieve mirroring pool %q status", poolName) } - var poolMirroringStatus cephv1.PoolMirroringStatus + var poolMirroringStatus cephv1.MirroringStatus if err := json.Unmarshal([]byte(buf), &poolMirroringStatus); err != nil { return nil, errors.Wrap(err, "failed to unmarshal mirror pool status response") } @@ -211,7 +211,8 @@ func GetMirroredPoolImages(context *clusterd.Context, clusterInfo *ClusterInfo, } // GetPoolMirroringInfo prints the pool mirroring information -func GetPoolMirroringInfo(context *clusterd.Context, clusterInfo *ClusterInfo, poolName string) (*cephv1.PoolMirroringInfo, error) { +// `poolName` is the name of the pool or the pool/radosNamespace +func GetPoolMirroringInfo(context *clusterd.Context, clusterInfo *ClusterInfo, poolName string) (*cephv1.MirroringInfo, error) { logger.Debugf("retrieving mirroring pool %q info", poolName) // Build command @@ -226,7 +227,7 @@ func GetPoolMirroringInfo(context *clusterd.Context, clusterInfo *ClusterInfo, p } // Unmarshal JSON into Go struct - var poolMirroringInfo cephv1.PoolMirroringInfo + var poolMirroringInfo cephv1.MirroringInfo if err := json.Unmarshal(buf, &poolMirroringInfo); err != nil { return nil, errors.Wrap(err, "failed to unmarshal mirror pool info response") } @@ -280,17 +281,18 @@ func removeSnapshotSchedule(context *clusterd.Context, clusterInfo *ClusterInfo, return nil } -func EnableSnapshotSchedules(context *clusterd.Context, clusterInfo *ClusterInfo, pool string, snapshotSchedules []cephv1.SnapshotScheduleSpec) error { +// `poolName` is the name of the pool or the pool/radosNamespace +func EnableSnapshotSchedules(context *clusterd.Context, clusterInfo *ClusterInfo, poolName string, snapshotSchedules []cephv1.SnapshotScheduleSpec) error { logger.Info("resetting current snapshot schedules in cluster namespace %q", clusterInfo.Namespace) // Reset any existing schedules - err := removeSnapshotSchedules(context, clusterInfo, pool) + err := removeSnapshotSchedules(context, clusterInfo, poolName) if err != nil { logger.Errorf("failed to remove snapshot schedules. %v", err) } // Enable all the snap schedules for _, snapSchedule := range snapshotSchedules { - err := enableSnapshotSchedule(context, clusterInfo, snapSchedule, pool) + err := enableSnapshotSchedule(context, clusterInfo, snapSchedule, poolName) if err != nil { return errors.Wrap(err, "failed to enable snapshot schedule") } diff --git a/pkg/daemon/ceph/client/mirror_health.go b/pkg/daemon/ceph/client/mirror_health.go new file mode 100644 index 000000000000..9bb99d29663c --- /dev/null +++ b/pkg/daemon/ceph/client/mirror_health.go @@ -0,0 +1,225 @@ +/* +Copyright 2020 The Rook Authors. 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. +*/ + +package client + +import ( + "context" + "time" + + cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1" + "github.com/rook/rook/pkg/clusterd" + "github.com/rook/rook/pkg/operator/ceph/reporting" + kerrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var ( + defaultHealthCheckInterval = 1 * time.Minute +) + +type mirrorChecker struct { + context *clusterd.Context + interval *time.Duration + client client.Client + clusterInfo *ClusterInfo + namespacedName types.NamespacedName + monitoringSpec *cephv1.NamedPoolSpec + objectType client.Object +} + +// newMirrorChecker creates a new HealthChecker object +func NewMirrorChecker(context *clusterd.Context, client client.Client, clusterInfo *ClusterInfo, namespacedName types.NamespacedName, monitoringSpec *cephv1.NamedPoolSpec, object client.Object) *mirrorChecker { + c := &mirrorChecker{ + context: context, + interval: &defaultHealthCheckInterval, + clusterInfo: clusterInfo, + namespacedName: namespacedName, + client: client, + monitoringSpec: monitoringSpec, + objectType: object, + } + + // allow overriding the check interval + checkInterval := monitoringSpec.StatusCheck.Mirror.Interval + if checkInterval != nil { + logger.Infof("mirroring status check interval for %q is %q", namespacedName.Name, checkInterval.Duration.String()) + c.interval = &checkInterval.Duration + } + + return c +} + +// checkMirroring periodically checks the health of the cluster +func (c *mirrorChecker) CheckMirroring(context context.Context) { + // check the mirroring health immediately before starting the loop + err := c.CheckMirroringHealth() + if err != nil { + c.UpdateStatusMirroring(nil, nil, nil, err.Error()) + logger.Debugf("failed to check mirroring status for %q. %v", c.namespacedName.Name, err) + } + + for { + select { + case <-context.Done(): + logger.Infof("stopping monitoring mirroring status for %q", c.namespacedName.Name) + return + + case <-time.After(*c.interval): + logger.Debugf("checking mirroring status for %q", c.namespacedName.Name) + err := c.CheckMirroringHealth() + if err != nil { + c.UpdateStatusMirroring(nil, nil, nil, err.Error()) + logger.Debugf("failed to check mirroring status for %q. %v", c.namespacedName.Name, err) + } + } + } +} + +func (c *mirrorChecker) CheckMirroringHealth() error { + // Check mirroring status + mirrorStatus, err := GetPoolMirroringStatus(c.context, c.clusterInfo, c.monitoringSpec.Name) + if err != nil { + c.UpdateStatusMirroring(nil, nil, nil, err.Error()) + } + + // Check mirroring info + mirrorInfo, err := GetPoolMirroringInfo(c.context, c.clusterInfo, c.monitoringSpec.Name) + if err != nil { + c.UpdateStatusMirroring(nil, nil, nil, err.Error()) + } + + // If snapshot scheduling is enabled let's add it to the status + // snapSchedStatus := cephclient.SnapshotScheduleStatus{} + snapSchedStatus := []cephv1.SnapshotSchedulesSpec{} + if c.monitoringSpec.Mirroring.SnapshotSchedulesEnabled() { + snapSchedStatus, err = ListSnapshotSchedulesRecursively(c.context, c.clusterInfo, c.monitoringSpec.Name) + if err != nil { + c.UpdateStatusMirroring(nil, nil, nil, err.Error()) + } + } + + // On success + c.UpdateStatusMirroring(mirrorStatus.Summary, mirrorInfo, snapSchedStatus, "") + + return nil +} + +// updateStatusBucket updates an object with a given status +func (c *mirrorChecker) UpdateStatusMirroring(mirrorStatus *cephv1.MirroringStatusSummarySpec, mirrorInfo *cephv1.MirroringInfo, snapSchedStatus []cephv1.SnapshotSchedulesSpec, details string) { + switch c.objectType.(type) { + case *cephv1.CephBlockPool: + updatePoolStatusMirroring(c, mirrorStatus, mirrorInfo, snapSchedStatus, details) + + case *cephv1.CephBlockPoolRadosNamespace: + updateRadosNamespaceStatusMirroring(c, mirrorStatus, mirrorInfo, snapSchedStatus, details) + } +} + +func updatePoolStatusMirroring(c *mirrorChecker, mirrorStatus *cephv1.MirroringStatusSummarySpec, mirrorInfo *cephv1.MirroringInfo, snapSchedStatus []cephv1.SnapshotSchedulesSpec, details string) { + blockPool := &cephv1.CephBlockPool{} + if err := c.client.Get(c.clusterInfo.Context, c.namespacedName, blockPool); err != nil { + if kerrors.IsNotFound(err) { + logger.Debug("CephBlockPool %q resource not found for updating the mirroring status, ignoring.", blockPool) + return + } + logger.Warningf("failed to retrieve ceph block pool %q to update mirroring status. %v", c.namespacedName.Name, err) + return + } + if blockPool.Status == nil { + blockPool.Status = &cephv1.CephBlockPoolStatus{} + } + + // Update the CephBlockPool CR status field + blockPool.Status.MirroringStatus, blockPool.Status.MirroringInfo, blockPool.Status.SnapshotScheduleStatus = toCustomResourceStatus(blockPool.Status.MirroringStatus, mirrorStatus, blockPool.Status.MirroringInfo, mirrorInfo, blockPool.Status.SnapshotScheduleStatus, snapSchedStatus, details) + if err := reporting.UpdateStatus(c.client, blockPool); err != nil { + logger.Errorf("failed to set ceph block pool %q mirroring status. %v", c.namespacedName.Name, err) + return + } + + logger.Debugf("ceph block pool %q mirroring status updated", c.namespacedName.Name) +} + +func updateRadosNamespaceStatusMirroring(c *mirrorChecker, mirrorStatus *cephv1.MirroringStatusSummarySpec, mirrorInfo *cephv1.MirroringInfo, snapSchedStatus []cephv1.SnapshotSchedulesSpec, details string) { + radosNamespace := &cephv1.CephBlockPoolRadosNamespace{} + if err := c.client.Get(c.clusterInfo.Context, c.namespacedName, radosNamespace); err != nil { + if kerrors.IsNotFound(err) { + logger.Debug("CephBlockPoolRadosNamespace %q resource not found for updating the mirroring status, ignoring.", radosNamespace) + return + } + logger.Warningf("failed to retrieve ceph block pool rados namespace %q to update mirroring status. %v", c.namespacedName.Name, err) + return + } + if radosNamespace.Status == nil { + radosNamespace.Status = &cephv1.CephBlockPoolRadosNamespaceStatus{} + } + + // Update the CephBlockPoolRadosNamespace CR status field + radosNamespace.Status.MirroringStatus, radosNamespace.Status.MirroringInfo, radosNamespace.Status.SnapshotScheduleStatus = toCustomResourceStatus(radosNamespace.Status.MirroringStatus, mirrorStatus, radosNamespace.Status.MirroringInfo, mirrorInfo, radosNamespace.Status.SnapshotScheduleStatus, snapSchedStatus, details) + if err := reporting.UpdateStatus(c.client, radosNamespace); err != nil { + logger.Errorf("failed to set ceph block pool rados namespace %q mirroring status. %v", c.namespacedName.Name, err) + return + } +} + +func toCustomResourceStatus(currentStatus *cephv1.MirroringStatusSpec, mirroringStatus *cephv1.MirroringStatusSummarySpec, + currentInfo *cephv1.MirroringInfoSpec, mirroringInfo *cephv1.MirroringInfo, + currentSnapSchedStatus *cephv1.SnapshotScheduleStatusSpec, snapSchedStatus []cephv1.SnapshotSchedulesSpec, + details string) (*cephv1.MirroringStatusSpec, *cephv1.MirroringInfoSpec, *cephv1.SnapshotScheduleStatusSpec) { + mirroringStatusSpec := &cephv1.MirroringStatusSpec{} + mirroringInfoSpec := &cephv1.MirroringInfoSpec{} + snapshotScheduleStatusSpec := &cephv1.SnapshotScheduleStatusSpec{} + + // mirroringStatus will be nil in case of an error to fetch it + if mirroringStatus != nil { + mirroringStatusSpec.LastChecked = time.Now().UTC().Format(time.RFC3339) + mirroringStatusSpec.MirroringStatus.Summary = mirroringStatus + } + + // Always display the details, typically an error + mirroringStatusSpec.Details = details + + if currentStatus != nil { + mirroringStatusSpec.LastChanged = currentStatus.LastChanged + } + + // mirroringInfo will be nil in case of an error to fetch it + if mirroringInfo != nil { + mirroringInfoSpec.LastChecked = time.Now().UTC().Format(time.RFC3339) + mirroringInfoSpec.MirroringInfo = mirroringInfo + } + // Always display the details, typically an error + mirroringInfoSpec.Details = details + + if currentInfo != nil { + mirroringInfoSpec.LastChanged = currentInfo.LastChecked + } + + // snapSchedStatus will be nil in case of an error to fetch it + if len(snapSchedStatus) != 0 { + snapshotScheduleStatusSpec.LastChecked = time.Now().UTC().Format(time.RFC3339) + snapshotScheduleStatusSpec.SnapshotSchedules = snapSchedStatus + } + // Always display the details, typically an error + snapshotScheduleStatusSpec.Details = details + + if currentSnapSchedStatus != nil { + snapshotScheduleStatusSpec.LastChanged = currentSnapSchedStatus.LastChecked + } + + return mirroringStatusSpec, mirroringInfoSpec, snapshotScheduleStatusSpec +} diff --git a/pkg/daemon/ceph/client/mirror_health_test.go b/pkg/daemon/ceph/client/mirror_health_test.go new file mode 100644 index 000000000000..42951743964d --- /dev/null +++ b/pkg/daemon/ceph/client/mirror_health_test.go @@ -0,0 +1,43 @@ +package client + +import ( + "testing" + + cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1" + "github.com/stretchr/testify/assert" +) + +func TestToCustomResourceStatus(t *testing.T) { + mirroringStatus := &cephv1.MirroringStatusSummarySpec{} + mirroringStatus.Health = "HEALTH_OK" + mirroringInfo := &cephv1.MirroringInfo{ + Mode: "pool", + SiteName: "rook-ceph-emea", + Peers: []cephv1.PeersSpec{ + {UUID: "82656994-3314-4996-ac4c-263c2c9fd081"}, + }, + } + + // Test 1: Empty so it's disabled + { + newMirroringStatus, newMirroringInfo, _ := toCustomResourceStatus(&cephv1.MirroringStatusSpec{}, mirroringStatus, &cephv1.MirroringInfoSpec{}, mirroringInfo, &cephv1.SnapshotScheduleStatusSpec{}, []cephv1.SnapshotSchedulesSpec{}, "") + assert.NotEmpty(t, newMirroringStatus.MirroringStatus) + assert.Equal(t, "HEALTH_OK", newMirroringStatus.MirroringStatus.Summary.Health) + assert.Equal(t, "pool", newMirroringInfo.Mode) + } + + // Test 2: snap sched + { + snapSchedStatus := []cephv1.SnapshotSchedulesSpec{ + { + Pool: "my-pool", + Image: "pool/image", + }, + } + newMirroringStatus, newMirroringInfo, newSnapshotScheduleStatus := toCustomResourceStatus(&cephv1.MirroringStatusSpec{}, mirroringStatus, &cephv1.MirroringInfoSpec{}, mirroringInfo, &cephv1.SnapshotScheduleStatusSpec{}, snapSchedStatus, "") + assert.NotEmpty(t, newMirroringStatus.MirroringStatus) + assert.Equal(t, "HEALTH_OK", newMirroringStatus.MirroringStatus.Summary.Health) + assert.NotEmpty(t, newMirroringInfo.Mode, "pool") + assert.NotEmpty(t, newSnapshotScheduleStatus) + } +} diff --git a/pkg/daemon/ceph/osd/kms/kms.go b/pkg/daemon/ceph/osd/kms/kms.go index de555e425320..24763f002ac3 100644 --- a/pkg/daemon/ceph/osd/kms/kms.go +++ b/pkg/daemon/ceph/osd/kms/kms.go @@ -238,6 +238,25 @@ func (c *Config) UpdateSecret(secretName, secretValue string) error { return nil } + if c.IsVault() { + // Store the secret in Vault + v, err := InitVault(c.ClusterInfo.Context, c.context, c.ClusterInfo.Namespace, c.clusterSpec.Security.KeyManagementService.ConnectionDetails) + if err != nil { + return errors.Wrap(err, "failed to init vault kms") + } + k := buildVaultKeyContext(c.clusterSpec.Security.KeyManagementService.ConnectionDetails) + // Build Secret + secretName = GenerateOSDEncryptionSecretName(secretName) + data := make(map[string]interface{}) + data[secretName] = secretValue + + _, err = v.PutSecret(secretName, data, k) + if err != nil { + return errors.Wrapf(err, "failed to put secret %q in vault kms", secretName) + } + + return nil + } return errors.Errorf("update secret is not supported for the %q KMS", c.Provider) } diff --git a/pkg/operator/ceph/cluster/cephstatus.go b/pkg/operator/ceph/cluster/cephstatus.go index 8c8bfe20730d..7f7e86a1a32f 100644 --- a/pkg/operator/ceph/cluster/cephstatus.go +++ b/pkg/operator/ceph/cluster/cephstatus.go @@ -314,11 +314,8 @@ func (c *cephStatusChecker) getRookPodsOnNode(node string) ([]v1.Pod, error) { appLabels := []string{ "csi-rbdplugin-provisioner", "csi-rbdplugin", - "csi-rbdplugin-holder", - "csi-cephfsplugin-holder", "csi-cephfsplugin-provisioner", "csi-cephfsplugin", - "csi-nfsplugin-holder", "csi-nfsplugin-provisioner", "csi-nfsplugin", "rook-ceph-operator", diff --git a/pkg/operator/ceph/cluster/cephstatus_test.go b/pkg/operator/ceph/cluster/cephstatus_test.go index d464f3a529bb..183a4b4c5a95 100644 --- a/pkg/operator/ceph/cluster/cephstatus_test.go +++ b/pkg/operator/ceph/cluster/cephstatus_test.go @@ -324,13 +324,10 @@ func TestGetRookPodsOnNode(t *testing.T) { {"app": "rook-ceph-osd"}, {"app": "csi-rbdplugin-provisioner"}, {"app": "csi-rbdplugin"}, - {"app": "csi-rbdplugin-holder"}, {"app": "csi-cephfsplugin-provisioner"}, {"app": "csi-cephfsplugin"}, - {"app": "csi-cephfsplugin-holder"}, {"app": "csi-nfsplugin-provisioner"}, {"app": "csi-nfsplugin"}, - {"app": "csi-nfsplugin-holder"}, {"app": "rook-ceph-operator"}, {"app": "rook-ceph-crashcollector"}, {"app": "rook-ceph-mgr"}, @@ -366,7 +363,7 @@ func TestGetRookPodsOnNode(t *testing.T) { pods, err := c.getRookPodsOnNode("node0") assert.NoError(t, err) // A pod is having two matching labels and its returned only once - assert.Equal(t, 17, len(pods)) + assert.Equal(t, 14, len(pods)) podNames := []string{} for _, pod := range pods { diff --git a/pkg/operator/ceph/cluster/mon/spec.go b/pkg/operator/ceph/cluster/mon/spec.go index 161d77e20c17..430c2dbdbcd5 100644 --- a/pkg/operator/ceph/cluster/mon/spec.go +++ b/pkg/operator/ceph/cluster/mon/spec.go @@ -58,6 +58,9 @@ func (c *Cluster) getLabels(monConfig *monConfig, canary, includeNewLabels bool) if monConfig.Zone != "" { labels["zone"] = monConfig.Zone } + if !canary { + labels["mon_daemon"] = "true" + } } return labels diff --git a/pkg/operator/ceph/cluster/osd/key_rotation.go b/pkg/operator/ceph/cluster/osd/key_rotation.go index 6401a8eb4b7d..e69973310fba 100644 --- a/pkg/operator/ceph/cluster/osd/key_rotation.go +++ b/pkg/operator/ceph/cluster/osd/key_rotation.go @@ -94,6 +94,12 @@ func (c *Cluster) getKeyRotationContainer(osdProps osdProperties, volumeMounts [ RunAsUser: &runAsUser, RunAsNonRoot: &runAsNonRoot, ReadOnlyRootFilesystem: &readOnlyRootFilesystem, + Capabilities: &v1.Capabilities{ + Add: []v1.Capability{}, + Drop: []v1.Capability{ + "NET_RAW", + }, + }, }, Resources: osdProps.resources, } @@ -137,6 +143,12 @@ func (c *Cluster) getKeyRotationPodTemplateSpec(osdProps osdProperties, osd OSDI devices = append(devices, encryptionBlockDestinationCopy(devicesBasePath, bluestoreWalName)) } + if c.spec.Security.KeyManagementService.IsVaultKMS() { + volumeTLS, volumeMountTLS := kms.VaultVolumeAndMount(c.spec.Security.KeyManagementService.ConnectionDetails, "") + volumes = append(volumes, volumeTLS) + volumeMounts = append(volumeMounts, volumeMountTLS) + } + keyRotationContainer, err := c.getKeyRotationContainer(osdProps, volumeMounts, devices) if err != nil { return nil, errors.Wrap(err, "failed to generate key rotation container") diff --git a/pkg/operator/ceph/cluster/osd/provision_spec.go b/pkg/operator/ceph/cluster/osd/provision_spec.go index 48147c486c7f..25521c88aa9d 100644 --- a/pkg/operator/ceph/cluster/osd/provision_spec.go +++ b/pkg/operator/ceph/cluster/osd/provision_spec.go @@ -342,6 +342,12 @@ func (c *Cluster) provisionOSDContainer(osdProps osdProperties, copyBinariesMoun RunAsUser: &runAsUser, RunAsNonRoot: &runAsNonRoot, ReadOnlyRootFilesystem: &readOnlyRootFilesystem, + Capabilities: &v1.Capabilities{ + Add: []v1.Capability{}, + Drop: []v1.Capability{ + "NET_RAW", + }, + }, }, Resources: cephv1.GetPrepareOSDResources(c.spec.Resources), } diff --git a/pkg/operator/ceph/cluster/osd/spec.go b/pkg/operator/ceph/cluster/osd/spec.go index f1ab7516b710..e67449f8874c 100644 --- a/pkg/operator/ceph/cluster/osd/spec.go +++ b/pkg/operator/ceph/cluster/osd/spec.go @@ -482,6 +482,12 @@ func (c *Cluster) makeDeployment(osdProps osdProperties, osd *OSDInfo, provision Privileged: &privileged, RunAsUser: &runAsUser, ReadOnlyRootFilesystem: &readOnlyRootFilesystem, + Capabilities: &v1.Capabilities{ + Add: []v1.Capability{}, + Drop: []v1.Capability{ + "NET_RAW", + }, + }, } // needed for luksOpen synchronization when devices are encrypted and the osd is prepared with LVM @@ -867,10 +873,13 @@ func (c *Cluster) getActivateOSDInitContainer(configDir, namespace, osdID string adminKeyringVol, adminKeyringVolMount := cephkey.Volume().Admin(), cephkey.VolumeMount().Admin() volume = append(volume, adminKeyringVol) + udevVolume := v1.Volume{Name: "udev", VolumeSource: v1.VolumeSource{HostPath: &v1.HostPathVolumeSource{Path: "/run/udev"}}} + volume = append(volume, udevVolume) volMounts := []v1.VolumeMount{ {Name: activateOSDVolumeName, MountPath: activateOSDMountPathID}, {Name: "devices", MountPath: "/dev"}, {Name: k8sutil.ConfigOverrideName, ReadOnly: true, MountPath: opconfig.EtcCephDir}, + {Name: "udev", MountPath: "/run/udev"}, adminKeyringVolMount, } @@ -910,6 +919,9 @@ func getBlockDevMapperContext() *v1.SecurityContext { Add: []v1.Capability{ "MKNOD", }, + Drop: []v1.Capability{ + "NET_RAW", + }, }, Privileged: &privileged, } diff --git a/pkg/operator/ceph/cluster/osd/spec_test.go b/pkg/operator/ceph/cluster/osd/spec_test.go index 5f5a9579be39..f04495fb46f6 100644 --- a/pkg/operator/ceph/cluster/osd/spec_test.go +++ b/pkg/operator/ceph/cluster/osd/spec_test.go @@ -143,10 +143,10 @@ func testPodDevices(t *testing.T, dataDir, deviceName string, allDevices bool) { assert.Equal(t, corev1.RestartPolicyAlways, deployment.Spec.Template.Spec.RestartPolicy) assert.Equal(t, "my-priority-class", deployment.Spec.Template.Spec.PriorityClassName) if devMountNeeded && len(dataDir) > 0 { - assert.Equal(t, 9, len(deployment.Spec.Template.Spec.Volumes)) + assert.Equal(t, 10, len(deployment.Spec.Template.Spec.Volumes)) } if devMountNeeded && len(dataDir) == 0 { - assert.Equal(t, 9, len(deployment.Spec.Template.Spec.Volumes)) + assert.Equal(t, 10, len(deployment.Spec.Template.Spec.Volumes)) } if !devMountNeeded && len(dataDir) > 0 { assert.Equal(t, 1, len(deployment.Spec.Template.Spec.Volumes)) @@ -164,7 +164,7 @@ func testPodDevices(t *testing.T, dataDir, deviceName string, allDevices bool) { initCont := deployment.Spec.Template.Spec.InitContainers[0] assert.Equal(t, "quay.io/ceph/ceph:v15", initCont.Image) assert.Equal(t, "activate", initCont.Name) - assert.Equal(t, 4, len(initCont.VolumeMounts)) + assert.Equal(t, 5, len(initCont.VolumeMounts)) initCont = deployment.Spec.Template.Spec.InitContainers[1] assert.Equal(t, "quay.io/ceph/ceph:v15", initCont.Image) assert.Equal(t, "expand-bluefs", initCont.Name) diff --git a/pkg/operator/ceph/cluster/rbd/controller.go b/pkg/operator/ceph/cluster/rbd/controller.go index 9a8c6b594f9a..09dc827bbb2c 100644 --- a/pkg/operator/ceph/cluster/rbd/controller.go +++ b/pkg/operator/ceph/cluster/rbd/controller.go @@ -83,7 +83,7 @@ type ReconcileCephRBDMirror struct { // peerSpec represents peer details type peerSpec struct { - info *cephv1.PoolMirroringInfo + info *cephv1.MirroringInfo poolName string direction string } diff --git a/pkg/operator/ceph/cluster/watcher.go b/pkg/operator/ceph/cluster/watcher.go index 41cd44c1b533..a99d9f545d58 100644 --- a/pkg/operator/ceph/cluster/watcher.go +++ b/pkg/operator/ceph/cluster/watcher.go @@ -100,7 +100,7 @@ func (c *clientCluster) onK8sNode(ctx context.Context, object runtime.Object, op return false } - if !k8sutil.GetNodeSchedulable(*node) { + if !k8sutil.GetNodeSchedulable(*node, false) { logger.Debugf("node watcher: skipping cluster update. added node %q is unschedulable", node.Labels[corev1.LabelHostname]) return false } @@ -123,7 +123,7 @@ func (c *clientCluster) onK8sNode(ctx context.Context, object runtime.Object, op logger.Debugf("node %q is ready, checking if it can run OSDs", node.Name) nodesCheckedForReconcile.Insert(node.Name) - err := k8sutil.ValidNode(*node, cephv1.GetOSDPlacement(cluster.Spec.Placement)) + err := k8sutil.ValidNode(*node, cephv1.GetOSDPlacement(cluster.Spec.Placement), cluster.Spec.Storage.ScheduleAlways) if err == nil { nodeName := node.Name hostname, ok := node.Labels[corev1.LabelHostname] diff --git a/pkg/operator/ceph/controller/network.go b/pkg/operator/ceph/controller/network.go index b97cb454af1f..3b96c9623379 100644 --- a/pkg/operator/ceph/controller/network.go +++ b/pkg/operator/ceph/controller/network.go @@ -252,6 +252,7 @@ func discoverAddressRanges( rookImage, rookImage, clusterSpec.CephVersion.ImagePullPolicy, + clusterSpec.Resources, ) if err != nil { return ranges, errors.Wrapf(err, "failed to set up ceph %q network canary", cephNetwork) diff --git a/pkg/operator/ceph/controller/network_test.go b/pkg/operator/ceph/controller/network_test.go index 8cc5beab1eb3..afb967b19a41 100644 --- a/pkg/operator/ceph/controller/network_test.go +++ b/pkg/operator/ceph/controller/network_test.go @@ -54,9 +54,9 @@ func (m *mockCmdReporter) Run(ctx context.Context, timeout time.Duration) (stdou } // returns a newCmdReporter function that returns the given mockCmdReporter and error -func mockNewCmdReporter(m *mockCmdReporter, err error) func(clientset kubernetes.Interface, ownerInfo *k8sutil.OwnerInfo, appName string, jobName string, jobNamespace string, cmd []string, args []string, rookImage string, runImage string, imagePullPolicy v1.PullPolicy) (cmdreporter.CmdReporterInterface, error) { - return func(clientset kubernetes.Interface, ownerInfo *k8sutil.OwnerInfo, appName, jobName, jobNamespace string, cmd, args []string, rookImage, runImage string, imagePullPolicy v1.PullPolicy) (cmdreporter.CmdReporterInterface, error) { - job, err := cmdreporter.MockCmdReporterJob(clientset, ownerInfo, appName, jobName, jobNamespace, cmd, args, rookImage, runImage, imagePullPolicy) +func mockNewCmdReporter(m *mockCmdReporter, err error) func(clientset kubernetes.Interface, ownerInfo *k8sutil.OwnerInfo, appName string, jobName string, jobNamespace string, cmd []string, args []string, rookImage string, runImage string, imagePullPolicy v1.PullPolicy, resources cephv1.ResourceSpec) (cmdreporter.CmdReporterInterface, error) { + return func(clientset kubernetes.Interface, ownerInfo *k8sutil.OwnerInfo, appName, jobName, jobNamespace string, cmd, args []string, rookImage, runImage string, imagePullPolicy v1.PullPolicy, resources cephv1.ResourceSpec) (cmdreporter.CmdReporterInterface, error) { + job, err := cmdreporter.MockCmdReporterJob(clientset, ownerInfo, appName, jobName, jobNamespace, cmd, args, rookImage, runImage, imagePullPolicy, resources) if err != nil { // okay to panic here because this is a unit test setup failure, not part of code testing panic(fmt.Sprintf("error setting up mock CmdReporter job: %v", err)) @@ -82,7 +82,6 @@ func newTestConfigsWithNetworkSpec(n cephv1.NetworkSpec) (*clusterd.Context, *ce func Test_discoverAddressRanges(t *testing.T) { oldNewCmdReporter := newCmdReporter defer func() { newCmdReporter = oldNewCmdReporter }() - t.Run("public network selected", func(t *testing.T) { clusterdCtx, clusterSpec, clusterInfo := newTestConfigsWithNetworkSpec( cephv1.NetworkSpec{ diff --git a/pkg/operator/ceph/controller/spec.go b/pkg/operator/ceph/controller/spec.go index 73c5a424ef68..b37d5e49f437 100644 --- a/pkg/operator/ceph/controller/spec.go +++ b/pkg/operator/ceph/controller/spec.go @@ -729,6 +729,12 @@ func PodSecurityContext() *v1.SecurityContext { return &v1.SecurityContext{ Privileged: &privileged, + Capabilities: &v1.Capabilities{ + Add: []v1.Capability{}, + Drop: []v1.Capability{ + "NET_RAW", + }, + }, } } @@ -754,6 +760,12 @@ func PrivilegedContext(runAsRoot bool) *v1.SecurityContext { sec.RunAsUser = &rootUser } + sec.Capabilities = &v1.Capabilities{ + Add: []v1.Capability{}, + Drop: []v1.Capability{ + "NET_RAW", + }, + } return sec } diff --git a/pkg/operator/ceph/controller/version.go b/pkg/operator/ceph/controller/version.go index 915672fda7d2..fa3d91f01eee 100644 --- a/pkg/operator/ceph/controller/version.go +++ b/pkg/operator/ceph/controller/version.go @@ -74,6 +74,7 @@ func DetectCephVersion(ctx context.Context, rookImage, namespace, jobName string rookImage, cephImage, cephClusterSpec.CephVersion.ImagePullPolicy, + cephClusterSpec.Resources, ) if err != nil { return nil, errors.Wrap(err, "failed to set up ceph version job") diff --git a/pkg/operator/ceph/csi/controller.go b/pkg/operator/ceph/csi/controller.go index 31c9d7924a0f..b9c6c5034eb9 100644 --- a/pkg/operator/ceph/csi/controller.go +++ b/pkg/operator/ceph/csi/controller.go @@ -43,7 +43,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/version" ) const ( @@ -52,23 +51,15 @@ const ( // ReconcileCSI reconciles a ceph-csi driver type ReconcileCSI struct { - scheme *runtime.Scheme - client client.Client - context *clusterd.Context - opManagerContext context.Context - opConfig opcontroller.OperatorConfig - clustersWithHolder []ClusterDetail + scheme *runtime.Scheme + client client.Client + context *clusterd.Context + opManagerContext context.Context + opConfig opcontroller.OperatorConfig // the first cluster CR which will determine some settings for the csi driver firstCephCluster *cephv1.ClusterSpec } -// ClusterDetail is a struct that holds the information of a cluster, it knows its internals (like -// FSID through clusterInfo) and the Kubernetes object that represents it (like the CephCluster CRD) -type ClusterDetail struct { - cluster *cephv1.CephCluster - clusterInfo *cephclient.ClusterInfo -} - // Add creates a new Ceph CSI Controller and adds it to the Manager. The Manager will set fields on the Controller // and Start it when the Manager is Started. func Add(mgr manager.Manager, context *clusterd.Context, opManagerContext context.Context, opConfig opcontroller.OperatorConfig) error { @@ -78,12 +69,11 @@ func Add(mgr manager.Manager, context *clusterd.Context, opManagerContext contex // newReconciler returns a new reconcile.Reconciler func newReconciler(mgr manager.Manager, context *clusterd.Context, opManagerContext context.Context, opConfig opcontroller.OperatorConfig) reconcile.Reconciler { return &ReconcileCSI{ - scheme: mgr.GetScheme(), - client: mgr.GetClient(), - context: context, - opConfig: opConfig, - opManagerContext: opManagerContext, - clustersWithHolder: []ClusterDetail{}, + scheme: mgr.GetScheme(), + client: mgr.GetClient(), + context: context, + opConfig: opConfig, + opManagerContext: opManagerContext, } } @@ -187,11 +177,6 @@ func (r *ReconcileCSI) reconcile(request reconcile.Request) (reconcile.Result, e r.opConfig.Parameters = opConfig.Data } - serverVersion, err := r.context.Clientset.Discovery().ServerVersion() - if err != nil { - return opcontroller.ImmediateRetryResult, errors.Wrap(err, "failed to get server version") - } - enableCSIOperator, err = strconv.ParseBool(k8sutil.GetValue(r.opConfig.Parameters, "ROOK_USE_CSI_OPERATOR", "false")) if err != nil { return reconcileResult, errors.Wrap(err, "unable to parse value for 'ROOK_USE_CSI_OPERATOR'") @@ -212,7 +197,7 @@ func (r *ReconcileCSI) reconcile(request reconcile.Request) (reconcile.Result, e if kerrors.IsNotFound(err) { logger.Debug("no ceph cluster found not deploying ceph csi driver") EnableRBD, EnableCephFS, EnableNFS = false, false, false - err = r.stopDrivers(serverVersion) + err = r.stopDrivers() if err != nil { return opcontroller.ImmediateRetryResult, errors.Wrap(err, "failed to stop Drivers") } @@ -227,7 +212,7 @@ func (r *ReconcileCSI) reconcile(request reconcile.Request) (reconcile.Result, e if len(cephClusters.Items) == 0 { logger.Debug("no ceph cluster found not deploying ceph csi driver") EnableRBD, EnableCephFS, EnableNFS = false, false, false - err = r.stopDrivers(serverVersion) + err = r.stopDrivers() if err != nil { return opcontroller.ImmediateRetryResult, errors.Wrap(err, "failed to stop Drivers") } @@ -250,22 +235,6 @@ func (r *ReconcileCSI) reconcile(request reconcile.Request) (reconcile.Result, e } CustomCSICephConfigExists = exists - csiHostNetworkEnabled, err := strconv.ParseBool(k8sutil.GetValue(r.opConfig.Parameters, "CSI_ENABLE_HOST_NETWORK", "true")) - if err != nil { - return reconcile.Result{}, errors.Wrap(err, "failed to parse value for 'CSI_ENABLE_HOST_NETWORK'") - } - - csiDisableHolders, err := strconv.ParseBool(k8sutil.GetValue(r.opConfig.Parameters, "CSI_DISABLE_HOLDER_PODS", "false")) - if err != nil { - return reconcile.Result{}, errors.Wrap(err, "failed to parse value for 'CSI_DISABLE_HOLDER_PODS'") - } - - // begin each reconcile with the assumption that holder pods won't be deployed - // the loop below will determine with each reconcile if they need deployed - // without this, holder pods won't be removed unless the operator is restarted - r.clustersWithHolder = []ClusterDetail{} - holderEnabled = false - for i, cluster := range cephClusters.Items { if !cluster.DeletionTimestamp.IsZero() { logger.Debugf("ceph cluster %q is being deleting, no need to reconcile the csi driver", request.NamespacedName) @@ -295,36 +264,21 @@ func (r *ReconcileCSI) reconcile(request reconcile.Request) (reconcile.Result, e } clusterInfo.OwnerInfo = k8sutil.NewOwnerInfo(&cephClusters.Items[i], r.scheme) - // is holder enabled for this cluster? - thisHolderEnabled := (!csiHostNetworkEnabled || cluster.Spec.Network.IsMultus()) && !csiDisableHolders - - // Do we have a multus cluster or csi host network disabled? - // If so deploy the plugin holder with the fsid attached - if thisHolderEnabled { - logger.Debugf("cluster %q: deploying the ceph-csi plugin holder", cluster.Name) - r.clustersWithHolder = append(r.clustersWithHolder, ClusterDetail{cluster: &cephClusters.Items[i], clusterInfo: clusterInfo}) - - // holder pods are enabled globally if any cluster needs a holder pod - holderEnabled = true - } else { - logger.Debugf("cluster %q: not deploying the ceph-csi plugin holder", request.NamespacedName) - } - - // if holder pods were disabled, the controller needs to update the configmap for each - // cephcluster to remove the net namespace file path + // ensure any remaining holder-related configs are cleared + holderEnabled = false err = reconcileSaveCSIDriverOptions(r.context.Clientset, cluster.Namespace, clusterInfo) if err != nil { return opcontroller.ImmediateRetryResult, errors.Wrapf(err, "failed to update CSI driver options for cluster %q", cluster.Name) } - // Skip the new CSI-operator creation when holder pod is enabled until multus support is added in the CSI operator + // disable Rook-managed CSI drivers if CSI operator is enabled if EnableCSIOperator() { logger.Info("disabling csi-driver since EnableCSIOperator is true") - err := r.stopDrivers(serverVersion) + err := r.stopDrivers() if err != nil { return opcontroller.ImmediateRetryResult, errors.Wrap(err, "failed to stop csi Drivers") } - err = r.reconcileOperatorConfig(cluster, clusterInfo, serverVersion) + err = r.reconcileOperatorConfig(cluster, clusterInfo) if err != nil { return opcontroller.ImmediateRetryResult, errors.Wrap(err, "failed to reconcile csi-op config CR") } @@ -333,7 +287,7 @@ func (r *ReconcileCSI) reconcile(request reconcile.Request) (reconcile.Result, e } if !disableCSI && !EnableCSIOperator() { - err = r.validateAndConfigureDrivers(serverVersion, ownerInfo) + err = r.validateAndConfigureDrivers(ownerInfo) if err != nil { return opcontroller.ImmediateRetryResult, errors.Wrap(err, "failed to configure ceph csi") } @@ -342,8 +296,8 @@ func (r *ReconcileCSI) reconcile(request reconcile.Request) (reconcile.Result, e return reconcileResult, nil } -func (r *ReconcileCSI) reconcileOperatorConfig(cluster cephv1.CephCluster, clusterInfo *cephclient.ClusterInfo, serverVersion *version.Info) error { - if err := r.setParams(serverVersion); err != nil { +func (r *ReconcileCSI) reconcileOperatorConfig(cluster cephv1.CephCluster, clusterInfo *cephclient.ClusterInfo) error { + if err := r.setParams(); err != nil { return errors.Wrapf(err, "failed to configure CSI parameters") } diff --git a/pkg/operator/ceph/csi/controller_test.go b/pkg/operator/ceph/csi/controller_test.go index 2860c6d673f4..2df439ceff61 100644 --- a/pkg/operator/ceph/csi/controller_test.go +++ b/pkg/operator/ceph/csi/controller_test.go @@ -61,7 +61,6 @@ func TestCephCSIController(t *testing.T) { t.Setenv(k8sutil.PodNameEnvVar, "rook-ceph-operator") t.Setenv(k8sutil.PodNamespaceEnvVar, namespace) - t.Setenv("ROOK_CSI_ALLOW_UNSUPPORTED_VERSION", "true") CSIParam = Param{ CSIPluginImage: "image", RegistrarImage: "image", @@ -264,12 +263,10 @@ func TestCephCSIController(t *testing.T) { ds, err := c.Clientset.AppsV1().DaemonSets(namespace).List(ctx, metav1.ListOptions{}) assert.NoError(t, err) - assert.Equal(t, 4, len(ds.Items), ds) + assert.Equal(t, 2, len(ds.Items), ds) assert.Equal(t, "csi-cephfsplugin", ds.Items[0].Name) - assert.Equal(t, "csi-cephfsplugin-holder-rook-ceph", ds.Items[1].Name) - assert.Equal(t, "csi-rbdplugin", ds.Items[2].Name) - assert.Equal(t, "csi-rbdplugin-holder-rook-ceph", ds.Items[3].Name) - assert.Equal(t, `[{"name":"public-net","namespace":"rook-ceph"}]`, ds.Items[1].Spec.Template.Annotations["k8s.v1.cni.cncf.io/networks"], ds.Items[1].Spec.Template.Annotations) + assert.Equal(t, "csi-rbdplugin", ds.Items[1].Name) + assert.Equal(t, ``, ds.Items[1].Spec.Template.Annotations["k8s.v1.cni.cncf.io/networks"], ds.Items[1].Spec.Template.Annotations) assert.Equal(t, []string{namespace}, saveCSIDriverOptionsCalledForClusterNS) }) diff --git a/pkg/operator/ceph/csi/csi.go b/pkg/operator/ceph/csi/csi.go index 4313eb0ef32a..b1ab03618a26 100644 --- a/pkg/operator/ceph/csi/csi.go +++ b/pkg/operator/ceph/csi/csi.go @@ -28,16 +28,14 @@ import ( "github.com/pkg/errors" kerrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/version" ) -func (r *ReconcileCSI) validateAndConfigureDrivers(serverVersion *version.Info, ownerInfo *k8sutil.OwnerInfo) error { +func (r *ReconcileCSI) validateAndConfigureDrivers(ownerInfo *k8sutil.OwnerInfo) error { var ( - v *CephCSIVersion err error ) - if err = r.setParams(serverVersion); err != nil { + if err = r.setParams(); err != nil { return errors.Wrapf(err, "failed to configure CSI parameters") } @@ -45,25 +43,17 @@ func (r *ReconcileCSI) validateAndConfigureDrivers(serverVersion *version.Info, return errors.Wrapf(err, "failed to validate CSI parameters") } - if !AllowUnsupported && CSIEnabled() { - if v, err = r.validateCSIVersion(ownerInfo); err != nil { - return errors.Wrapf(err, "invalid csi version") - } - } else { - logger.Info("skipping csi version check, since unsupported versions are allowed or csi is disabled") - } - if CSIEnabled() { - if err = r.startDrivers(serverVersion, ownerInfo, v); err != nil { + if err = r.startDrivers(ownerInfo); err != nil { return errors.Wrap(err, "failed to start ceph csi drivers") } } // Check whether RBD or CephFS needs to be disabled - return r.stopDrivers(serverVersion) + return r.stopDrivers() } -func (r *ReconcileCSI) setParams(ver *version.Info) error { +func (r *ReconcileCSI) setParams() error { var err error if EnableRBD, err = strconv.ParseBool(k8sutil.GetValue(r.opConfig.Parameters, "ROOK_CSI_ENABLE_RBD", "true")); err != nil { @@ -78,10 +68,6 @@ func (r *ReconcileCSI) setParams(ver *version.Info) error { return errors.Wrap(err, "unable to parse value for 'ROOK_CSI_ENABLE_NFS'") } - if AllowUnsupported, err = strconv.ParseBool(k8sutil.GetValue(r.opConfig.Parameters, "ROOK_CSI_ALLOW_UNSUPPORTED_VERSION", "false")); err != nil { - return errors.Wrap(err, "unable to parse value for 'ROOK_CSI_ALLOW_UNSUPPORTED_VERSION'") - } - if CSIParam.EnableCSIHostNetwork, err = strconv.ParseBool(k8sutil.GetValue(r.opConfig.Parameters, "CSI_ENABLE_HOST_NETWORK", "true")); err != nil { return errors.Wrap(err, "failed to parse value for 'CSI_ENABLE_HOST_NETWORK'") } @@ -139,10 +125,7 @@ func (r *ReconcileCSI) setParams(ver *version.Info) error { CSIParam.EnableOMAPGenerator = true } - // CSIDriver SeLinuxMount option is only available from kubernetes version 1.25. - if ver.Major == kubeMinMajor && ver.Minor >= kubeMinVerForCSIDriverSeLinuxMount { - CSIParam.EnableCSIDriverSeLinuxMount = true - } + CSIParam.EnableCSIDriverSeLinuxMount = true CSIParam.EnableRBDSnapshotter = true if strings.EqualFold(k8sutil.GetValue(r.opConfig.Parameters, "CSI_ENABLE_RBD_SNAPSHOTTER", "true"), "false") { @@ -213,8 +196,6 @@ func (r *ReconcileCSI) setParams(ver *version.Info) error { CSIParam.EnablePluginSelinuxHostMount = true } - logger.Infof("Kubernetes version is %s.%s", ver.Major, ver.Minor) - logLevel := k8sutil.GetValue(r.opConfig.Parameters, "CSI_LOG_LEVEL", "") CSIParam.LogLevel = defaultLogLevel if logLevel != "" { diff --git a/pkg/operator/ceph/csi/operator_config_test.go b/pkg/operator/ceph/csi/operator_config_test.go index 4beb6a9a52f3..33f10c2a51f9 100644 --- a/pkg/operator/ceph/csi/operator_config_test.go +++ b/pkg/operator/ceph/csi/operator_config_test.go @@ -46,7 +46,6 @@ func TestReconcileCSI_createOrUpdateOperatorConfig(t *testing.T) { opConfig: opcontroller.OperatorConfig{ OperatorNamespace: "test", }, - clustersWithHolder: []ClusterDetail{}, } cluster := &cephv1.CephCluster{ ObjectMeta: metav1.ObjectMeta{ diff --git a/pkg/operator/ceph/csi/operator_driver_test.go b/pkg/operator/ceph/csi/operator_driver_test.go index c1c0c2831c3b..647cd6fa2f3f 100644 --- a/pkg/operator/ceph/csi/operator_driver_test.go +++ b/pkg/operator/ceph/csi/operator_driver_test.go @@ -48,7 +48,6 @@ func TestReconcileCSI_createOrUpdateDriverResources(t *testing.T) { opConfig: opcontroller.OperatorConfig{ OperatorNamespace: "test", }, - clustersWithHolder: []ClusterDetail{}, } cluster := &cephv1.CephCluster{ ObjectMeta: metav1.ObjectMeta{ diff --git a/pkg/operator/ceph/csi/spec.go b/pkg/operator/ceph/csi/spec.go index de30e74a87c0..f3e14a68187c 100644 --- a/pkg/operator/ceph/csi/spec.go +++ b/pkg/operator/ceph/csi/spec.go @@ -21,16 +21,11 @@ import ( _ "embed" "fmt" "path" - "strconv" "strings" "time" - cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1" - "github.com/rook/rook/pkg/operator/ceph/cluster/telemetry" opcontroller "github.com/rook/rook/pkg/operator/ceph/controller" "github.com/rook/rook/pkg/operator/k8sutil" - "github.com/rook/rook/pkg/operator/k8sutil/cmdreporter" - "sigs.k8s.io/controller-runtime/pkg/client" "github.com/pkg/errors" apps "k8s.io/api/apps/v1" @@ -38,11 +33,7 @@ import ( k8scsi "k8s.io/api/storage/v1beta1" kerrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/version" "k8s.io/client-go/kubernetes" - - cephcsi "github.com/ceph/ceph-csi/api/deploy/kubernetes" ) type Param struct { @@ -115,15 +106,6 @@ type templateParam struct { Namespace string } -type driverDetails struct { - name string - fullName string - holderTemplate string - toleration string - nodeAffinity string - resource string -} - var ( CSIParam Param @@ -131,7 +113,6 @@ var ( EnableCephFS = false EnableNFS = false enableCSIOperator = false - AllowUnsupported = false CustomCSICephConfigExists = false // driver names @@ -164,8 +145,6 @@ var ( // Local package template path for RBD //go:embed template/rbd/csi-rbdplugin.yaml RBDPluginTemplatePath string - //go:embed template/rbd/csi-rbdplugin-holder.yaml - RBDPluginHolderTemplatePath string //go:embed template/rbd/csi-rbdplugin-provisioner-dep.yaml RBDProvisionerDepTemplatePath string //go:embed template/rbd/csi-rbdplugin-svc.yaml @@ -174,8 +153,6 @@ var ( // Local package template path for CephFS //go:embed template/cephfs/csi-cephfsplugin.yaml CephFSPluginTemplatePath string - //go:embed template/cephfs/csi-cephfsplugin-holder.yaml - CephFSPluginHolderTemplatePath string //go:embed template/cephfs/csi-cephfsplugin-provisioner-dep.yaml CephFSProvisionerDepTemplatePath string //go:embed template/cephfs/csi-cephfsplugin-svc.yaml @@ -186,8 +163,6 @@ var ( NFSPluginTemplatePath string //go:embed template/nfs/csi-nfsplugin-provisioner-dep.yaml NFSProvisionerDepTemplatePath string - //go:embed template/nfs/csi-nfsplugin-holder.yaml - NFSPluginHolderTemplatePath string //go:embed template/csi-logrotate-sidecar.yaml LogrotateTemplatePath string @@ -198,9 +173,6 @@ var ( ) const ( - kubeMinMajor = "1" - kubeMinVerForCSIDriverSeLinuxMount = "25" - // common tolerations and node affinity provisionerTolerationsEnv = "CSI_PROVISIONER_TOLERATIONS" provisionerNodeAffinityEnv = "CSI_PROVISIONER_NODE_AFFINITY" @@ -254,7 +226,6 @@ const ( DefaultRBDLivenessMerticsPort uint16 = 9080 DefaultCSIAddonsPort uint16 = 9070 - detectCSIVersionName = "rook-ceph-csi-detect-version" // default log level for csi containers defaultLogLevel uint8 = 0 defaultSidecarLogLevel uint8 = 0 @@ -324,7 +295,7 @@ func validateCSIParam() error { return nil } -func (r *ReconcileCSI) startDrivers(ver *version.Info, ownerInfo *k8sutil.OwnerInfo, v *CephCSIVersion) error { +func (r *ReconcileCSI) startDrivers(ownerInfo *k8sutil.OwnerInfo) error { var ( err error rbdPlugin, cephfsPlugin, nfsPlugin *apps.DaemonSet @@ -333,8 +304,6 @@ func (r *ReconcileCSI) startDrivers(ver *version.Info, ownerInfo *k8sutil.OwnerI csiDriverobj v1CsiDriver ) - enabledDrivers := make([]driverDetails, 0) - tp := templateParam{ Param: CSIParam, Namespace: r.opConfig.OperatorNamespace, @@ -391,14 +360,6 @@ func (r *ReconcileCSI) startDrivers(ver *version.Info, ownerInfo *k8sutil.OwnerI } rbdService.Namespace = r.opConfig.OperatorNamespace } - enabledDrivers = append(enabledDrivers, driverDetails{ - name: RBDDriverShortName, - fullName: RBDDriverName, - holderTemplate: RBDPluginHolderTemplatePath, - nodeAffinity: rbdPluginNodeAffinityEnv, - toleration: rbdPluginTolerationsEnv, - resource: rbdPluginResource, - }) } if EnableCephFS { tp.CsiComponentName = nodePlugin @@ -429,14 +390,6 @@ func (r *ReconcileCSI) startDrivers(ver *version.Info, ownerInfo *k8sutil.OwnerI } cephfsService.Namespace = r.opConfig.OperatorNamespace } - enabledDrivers = append(enabledDrivers, driverDetails{ - name: CephFSDriverShortName, - fullName: CephFSDriverName, - holderTemplate: CephFSPluginHolderTemplatePath, - nodeAffinity: cephFSPluginNodeAffinityEnv, - toleration: cephFSPluginTolerationsEnv, - resource: cephFSPluginResource, - }) } if EnableNFS { @@ -459,15 +412,6 @@ func (r *ReconcileCSI) startDrivers(ver *version.Info, ownerInfo *k8sutil.OwnerI applyLogrotateSidecar(&nfsProvisionerDeployment.Spec.Template, "csi-nfs-deployment-log-collector", LogrotateTemplatePath, tp) } nfsProvisionerDeployment.Spec.Template.Spec.HostNetwork = opcontroller.EnforceHostNetwork() - - enabledDrivers = append(enabledDrivers, driverDetails{ - name: NFSDriverShortName, - fullName: NFSDriverName, - holderTemplate: NFSPluginHolderTemplatePath, - nodeAffinity: nfsPluginNodeAffinityEnv, - toleration: nfsPluginTolerationsEnv, - resource: nfsPluginResource, - }) } // get common provisioner tolerations and node affinity @@ -478,13 +422,6 @@ func (r *ReconcileCSI) startDrivers(ver *version.Info, ownerInfo *k8sutil.OwnerI pluginTolerations := getToleration(r.opConfig.Parameters, pluginTolerationsEnv, []corev1.Toleration{}) pluginNodeAffinity := getNodeAffinity(r.opConfig.Parameters, pluginNodeAffinityEnv, &corev1.NodeAffinity{}) - // Deploy the CSI Holder DaemonSet if Multus is enabled or - // EnableCSIHostNetwork is disabled. - err = r.configureHolders(enabledDrivers, tp, pluginTolerations, pluginNodeAffinity) - if err != nil { - return errors.Wrap(err, "failed to configure holder") - } - if rbdPlugin != nil { // get RBD plugin tolerations and node affinity, defaults to common tolerations and node affinity if not specified rbdPluginTolerations := getToleration(r.opConfig.Parameters, rbdPluginTolerationsEnv, pluginTolerations) @@ -505,9 +442,6 @@ func (r *ReconcileCSI) startDrivers(ver *version.Info, ownerInfo *k8sutil.OwnerI if err != nil { return errors.Wrapf(err, "failed to apply network config to rbd plugin daemonset %q", rbdPlugin.Name) } - if holderEnabled { - rbdPlugin.Spec.Template.Spec.HostNetwork = false - } err = k8sutil.CreateDaemonSet(r.opManagerContext, r.opConfig.OperatorNamespace, r.context.Clientset, rbdPlugin) if err != nil { return errors.Wrapf(err, "failed to start rbdplugin daemonset %q", rbdPlugin.Name) @@ -577,11 +511,6 @@ func (r *ReconcileCSI) startDrivers(ver *version.Info, ownerInfo *k8sutil.OwnerI if err != nil { return errors.Wrapf(err, "failed to apply network config to cephfs plugin daemonset %q", cephfsPlugin.Name) } - if holderEnabled { - cephfsPlugin.Spec.Template.Spec.HostNetwork = false - // HostPID is used to communicate with the network namespace - cephfsPlugin.Spec.Template.Spec.HostPID = true - } err = k8sutil.CreateDaemonSet(r.opManagerContext, r.opConfig.OperatorNamespace, r.context.Clientset, cephfsPlugin) if err != nil { @@ -652,11 +581,6 @@ func (r *ReconcileCSI) startDrivers(ver *version.Info, ownerInfo *k8sutil.OwnerI if err != nil { return errors.Wrapf(err, "failed to apply network config to nfs plugin daemonset %q", nfsPlugin.Name) } - if holderEnabled { - nfsPlugin.Spec.Template.Spec.HostNetwork = false - // HostPID is used to communicate with the network namespace - nfsPlugin.Spec.Template.Spec.HostPID = true - } err = k8sutil.CreateDaemonSet(r.opManagerContext, r.opConfig.OperatorNamespace, r.context.Clientset, nfsPlugin) if err != nil { @@ -726,14 +650,14 @@ func (r *ReconcileCSI) startDrivers(ver *version.Info, ownerInfo *k8sutil.OwnerI return nil } -func (r *ReconcileCSI) stopDrivers(ver *version.Info) error { +func (r *ReconcileCSI) stopDrivers() error { RBDDriverName = fmt.Sprintf("%s.rbd.csi.ceph.com", r.opConfig.OperatorNamespace) CephFSDriverName = fmt.Sprintf("%s.cephfs.csi.ceph.com", r.opConfig.OperatorNamespace) NFSDriverName = fmt.Sprintf("%s.nfs.csi.ceph.com", r.opConfig.OperatorNamespace) if !EnableRBD || EnableCSIOperator() { logger.Debugf("either EnableRBD if `false` or EnableCSIOperator is `true`, `EnableRBD is %t` and `EnableCSIOperator is %t", EnableRBD, EnableCSIOperator()) - err := r.deleteCSIDriverResources(ver, CsiRBDPlugin, csiRBDProvisioner, "csi-rbdplugin-metrics", RBDDriverName) + err := r.deleteCSIDriverResources(CsiRBDPlugin, csiRBDProvisioner, "csi-rbdplugin-metrics", RBDDriverName) if err != nil { return errors.Wrap(err, "failed to remove CSI Ceph RBD driver") } @@ -742,7 +666,7 @@ func (r *ReconcileCSI) stopDrivers(ver *version.Info) error { if !EnableCephFS || EnableCSIOperator() { logger.Debugf("either EnableCephFS if `false` or EnableCSIOperator is `true`, `EnableCephFS is %t` and `EnableCSIOperator is %t", EnableRBD, EnableCSIOperator()) - err := r.deleteCSIDriverResources(ver, CsiCephFSPlugin, csiCephFSProvisioner, "csi-cephfsplugin-metrics", CephFSDriverName) + err := r.deleteCSIDriverResources(CsiCephFSPlugin, csiCephFSProvisioner, "csi-cephfsplugin-metrics", CephFSDriverName) if err != nil { return errors.Wrap(err, "failed to remove CSI CephFS driver") } @@ -751,7 +675,7 @@ func (r *ReconcileCSI) stopDrivers(ver *version.Info) error { if !EnableNFS || EnableCSIOperator() { logger.Debugf("either EnableNFS if `false` or EnableCSIOperator is `true`, `EnableNFS is %t` and `EnableCSIOperator is %t", EnableRBD, EnableCSIOperator()) - err := r.deleteCSIDriverResources(ver, CsiNFSPlugin, csiNFSProvisioner, "csi-nfsplugin-metrics", NFSDriverName) + err := r.deleteCSIDriverResources(CsiNFSPlugin, csiNFSProvisioner, "csi-nfsplugin-metrics", NFSDriverName) if err != nil { return errors.Wrap(err, "failed to remove CSI NFS driver") } @@ -761,7 +685,7 @@ func (r *ReconcileCSI) stopDrivers(ver *version.Info) error { return nil } -func (r *ReconcileCSI) deleteCSIDriverResources(ver *version.Info, daemonset, deployment, service, driverName string) error { +func (r *ReconcileCSI) deleteCSIDriverResources(daemonset, deployment, service, driverName string) error { csiDriverobj := v1CsiDriver{} err := k8sutil.DeleteDaemonset(r.opManagerContext, r.context.Clientset, r.opConfig.OperatorNamespace, daemonset) if err != nil { @@ -805,226 +729,6 @@ func (r *ReconcileCSI) applyCephClusterNetworkConfig(ctx context.Context, object return nil } -// ValidateCSIVersion checks if the configured ceph-csi image is supported -func (r *ReconcileCSI) validateCSIVersion(ownerInfo *k8sutil.OwnerInfo) (*CephCSIVersion, error) { - timeout := 15 * time.Minute - - logger.Infof("detecting the ceph csi image version for image %q", CSIParam.CSIPluginImage) - - versionReporter, err := cmdreporter.New( - r.context.Clientset, - ownerInfo, - detectCSIVersionName, - detectCSIVersionName, - r.opConfig.OperatorNamespace, - []string{"cephcsi"}, - []string{"--version"}, - r.opConfig.Image, - CSIParam.CSIPluginImage, - corev1.PullPolicy(CSIParam.ImagePullPolicy), - ) - if err != nil { - return nil, errors.Wrap(err, "failed to set up ceph CSI version job") - } - - job := versionReporter.Job() - job.Spec.Template.Spec.ServiceAccountName = r.opConfig.ServiceAccount - - // Apply csi provisioner toleration and affinity for csi version check job - job.Spec.Template.Spec.Tolerations = getToleration(r.opConfig.Parameters, provisionerTolerationsEnv, []corev1.Toleration{}) - job.Spec.Template.Spec.Affinity = &corev1.Affinity{ - NodeAffinity: getNodeAffinity(r.opConfig.Parameters, provisionerNodeAffinityEnv, &corev1.NodeAffinity{}), - } - if r.firstCephCluster != nil { - cephv1.GetCmdReporterAnnotations(r.firstCephCluster.Annotations).ApplyToObjectMeta(&job.Spec.Template.ObjectMeta) - cephv1.GetCmdReporterLabels(r.firstCephCluster.Labels).ApplyToObjectMeta(&job.Spec.Template.ObjectMeta) - } - - stdout, _, retcode, err := versionReporter.Run(r.opManagerContext, timeout) - if err != nil { - return nil, errors.Wrap(err, "failed to complete ceph CSI version job") - } - - if retcode != 0 { - return nil, errors.Errorf("ceph CSI version job returned %d", retcode) - } - - version, err := extractCephCSIVersion(stdout) - if err != nil { - return nil, errors.Wrap(err, "failed to extract ceph CSI version") - } - logger.Infof("Detected ceph CSI image version: %q", version) - - // Set the CSI version on a package variable so that each cluster reporting the - // telemetry can report the same CSI version - telemetry.CSIVersion = version.String() - - if !version.Supported() { - return nil, errors.Errorf("ceph CSI image needs to be at least version %q", minimum.String()) - } - return version, nil -} - -func (r *ReconcileCSI) configureHolders(enabledDrivers []driverDetails, tp templateParam, pluginTolerations []corev1.Toleration, pluginNodeAffinity *corev1.NodeAffinity) error { - for _, cluster := range r.clustersWithHolder { - for _, driver := range enabledDrivers { - err := r.configureHolder(driver, cluster, tp, pluginTolerations, pluginNodeAffinity) - if err != nil { - return errors.Wrapf(err, "failed to configure holder %q for %q/%q", driver.name, cluster.cluster.Name, cluster.cluster.Namespace) - } - } - } - - return nil -} - -func (r *ReconcileCSI) configureHolder(driver driverDetails, c ClusterDetail, tp templateParam, pluginTolerations []corev1.Toleration, pluginNodeAffinity *corev1.NodeAffinity) error { - cephPluginHolder, err := templateToDaemonSet("cephpluginholder", driver.holderTemplate, tp) - if err != nil { - return errors.Wrapf(err, "failed to load ceph %q plugin holder template", driver.fullName) - } - - // As the plugin holder daemonset is created in the operator namespace, we - // need to set the owner reference to the cluster namespace only if the - // operator and cluster are created in same namespace so that the - // plugin holder daemonset is deleted when the cluster is deleted. - if r.opConfig.OperatorNamespace == c.cluster.Namespace { - err = c.clusterInfo.OwnerInfo.SetControllerReference(cephPluginHolder) - if err != nil { - return errors.Wrapf(err, "failed to set owner reference to plugin holder %q", driver.fullName) - } - } - holderPluginTolerations := getToleration(r.opConfig.Parameters, driver.toleration, pluginTolerations) - holderPluginNodeAffinity := getNodeAffinity(r.opConfig.Parameters, driver.nodeAffinity, pluginNodeAffinity) - // apply driver's plugin tolerations and node affinity - applyToPodSpec(&cephPluginHolder.Spec.Template.Spec, holderPluginNodeAffinity, holderPluginTolerations) - - // apply resource request and limit from corresponding plugin container - applyResourcesToContainers(r.opConfig.Parameters, driver.resource, &cephPluginHolder.Spec.Template.Spec) - - // Append the CEPH_CLUSTER_NAMESPACE env var so that the main container can use it to create the network - // namespace symlink to the Kubelet plugin directory - cephPluginHolder.Spec.Template.Spec.Containers[0].Env = append( - cephPluginHolder.Spec.Template.Spec.Containers[0].Env, - corev1.EnvVar{ - Name: "CEPH_CLUSTER_NAMESPACE", - Value: c.cluster.Namespace, - }, - ) - - // Append the driver name so that the symlink file goes into the right location on the - // kubelet plugin directory - cephPluginHolder.Spec.Template.Spec.Containers[0].Env = append( - cephPluginHolder.Spec.Template.Spec.Containers[0].Env, - corev1.EnvVar{ - Name: "ROOK_CEPH_CSI_DRIVER_NAME", - Value: driver.fullName, - }, - ) - - // Make the DS name unique per Ceph cluster - cephPluginHolder.Name = fmt.Sprintf("%s-%s", cephPluginHolder.Name, c.cluster.Name) - cephPluginHolder.Spec.Template.Name = cephPluginHolder.Name - cephPluginHolder.Spec.Template.Spec.Containers[0].Name = fmt.Sprintf("%s-%s", cephPluginHolder.Spec.Template.Spec.Containers[0].Name, c.cluster.Name) - - // Add default labels - k8sutil.AddRookVersionLabelToDaemonSet(cephPluginHolder) - - // If multus is enabled, add the multus plugin label - if c.cluster.Spec.Network.IsMultus() { - // Apply Multus annotations to daemonset spec - err = k8sutil.ApplyMultus(c.cluster.GetNamespace(), &c.cluster.Spec.Network, &cephPluginHolder.Spec.Template.ObjectMeta) - if err != nil { - return errors.Wrapf(err, "failed to apply multus configuration for holder %q in cluster %q", cephPluginHolder.Name, c.cluster.Namespace) - } - } - // Finally create the DaemonSet - _, err = r.context.Clientset.AppsV1().DaemonSets(r.opConfig.OperatorNamespace).Create(r.opManagerContext, cephPluginHolder, metav1.CreateOptions{}) - if err != nil { - if kerrors.IsAlreadyExists(err) { - _, err = r.context.Clientset.AppsV1().DaemonSets(r.opConfig.OperatorNamespace).Update(r.opManagerContext, cephPluginHolder, metav1.UpdateOptions{}) - if err != nil { - return errors.Wrapf(err, "failed to update ceph plugin holder daemonset %q", cephPluginHolder.Name) - } - logger.Debugf("holder %q already exists for cluster %q, updating it, restart holder pods to take effect of update", cephPluginHolder.Name, c.cluster.Namespace) - } else { - return errors.Wrapf(err, "failed to start ceph plugin holder daemonset %q", cephPluginHolder.Name) - } - } - - clusterConfigEntry := &CSIClusterConfigEntry{ - ClusterInfo: cephcsi.ClusterInfo{ - Monitors: MonEndpoints(c.clusterInfo.Monitors, c.cluster.Spec.RequireMsgr2()), - RBD: cephcsi.RBD{}, - CephFS: cephcsi.CephFS{ - FuseMountOptions: c.clusterInfo.CSIDriverSpec.CephFS.FuseMountOptions, - KernelMountOptions: c.clusterInfo.CSIDriverSpec.CephFS.KernelMountOptions, - }, - NFS: cephcsi.NFS{}, - ReadAffinity: cephcsi.ReadAffinity{ - Enabled: c.clusterInfo.CSIDriverSpec.ReadAffinity.Enabled, - CrushLocationLabels: c.clusterInfo.CSIDriverSpec.ReadAffinity.CrushLocationLabels, - }, - }, - } - - netNamespaceFilePath := generateNetNamespaceFilePath(CSIParam.KubeletDirPath, driver.fullName, c.cluster.Namespace) - if driver.name == RBDDriverShortName { - clusterConfigEntry.RBD.NetNamespaceFilePath = netNamespaceFilePath - } - if driver.name == CephFSDriverShortName { - clusterConfigEntry.CephFS.NetNamespaceFilePath = netNamespaceFilePath - } - if driver.name == NFSDriverShortName { - clusterConfigEntry.NFS.NetNamespaceFilePath = netNamespaceFilePath - } - - // Save the path of the network namespace file for ceph-csi to use - clusterId := c.cluster.Namespace // cluster ID is same as cluster namespace for CephClusters - err = SaveClusterConfig(r.context.Clientset, clusterId, c.cluster.Namespace, c.clusterInfo, clusterConfigEntry) - if err != nil { - return errors.Wrapf(err, "failed to save cluster config for csi holder %q", driver.fullName) - } - return nil -} - -func GenerateNetNamespaceFilePath(ctx context.Context, client client.Client, clusterNamespace, opNamespace, driverName string) (string, error) { - var driverSuffix string - opNamespaceName := types.NamespacedName{Name: opcontroller.OperatorSettingConfigMapName, Namespace: opNamespace} - opConfig := &corev1.ConfigMap{} - err := client.Get(ctx, opNamespaceName, opConfig) - if err != nil && !kerrors.IsNotFound(err) { - return "", errors.Wrap(err, "failed to get operator's configmap") - } - - // net namespace file path is empty string if holder pods are disabled - csiDisableHolders, err := strconv.ParseBool(k8sutil.GetValue(opConfig.Data, "CSI_DISABLE_HOLDER_PODS", "false")) - if err != nil { - return "", errors.Wrap(err, "failed to parse value for 'CSI_DISABLE_HOLDER_PODS'") - } - if csiDisableHolders { - return "", nil - } - - switch driverName { - case RBDDriverShortName: - driverSuffix = rbdDriverSuffix - case CephFSDriverShortName: - driverSuffix = cephFSDriverSuffix - default: - return "", errors.Errorf("unsupported driver name %q", driverName) - } - - kubeletDirPath := k8sutil.GetValue(opConfig.Data, "ROOK_CSI_KUBELET_DIR_PATH", DefaultKubeletDirPath) - driverFullName := fmt.Sprintf("%s.%s", opNamespace, driverSuffix) - - return generateNetNamespaceFilePath(kubeletDirPath, driverFullName, clusterNamespace), nil -} - -func generateNetNamespaceFilePath(kubeletDirPath, driverFullName, clusterNamespace string) string { - return fmt.Sprintf("%s/plugins/%s/%s.net.ns", kubeletDirPath, driverFullName, clusterNamespace) -} - func validateCSIDriverNamePrefix(ctx context.Context, clientset kubernetes.Interface, namespace, driverNamePrefix string) error { if EnableRBD { rbdDriverNamePrefix, err := getCSIDriverNamePrefixFromDeployment(ctx, clientset, namespace, csiRBDProvisioner, "csi-rbdplugin") @@ -1106,5 +810,5 @@ func getPrefixFromArg(arg string) (string, bool) { } func EnableCSIOperator() bool { - return enableCSIOperator && !IsHolderEnabled() + return enableCSIOperator } diff --git a/pkg/operator/ceph/csi/spec_test.go b/pkg/operator/ceph/csi/spec_test.go index 5e75fdfbf4d7..603ec9f46d30 100644 --- a/pkg/operator/ceph/csi/spec_test.go +++ b/pkg/operator/ceph/csi/spec_test.go @@ -21,117 +21,13 @@ import ( _ "embed" "testing" - cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1" - rookclient "github.com/rook/rook/pkg/client/clientset/versioned/fake" - "github.com/rook/rook/pkg/clusterd" - cephclient "github.com/rook/rook/pkg/daemon/ceph/client" - opcontroller "github.com/rook/rook/pkg/operator/ceph/controller" - "github.com/rook/rook/pkg/operator/k8sutil" - testop "github.com/rook/rook/pkg/operator/test" "github.com/stretchr/testify/assert" apps "k8s.io/api/apps/v1" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" kfake "k8s.io/client-go/kubernetes/fake" - "sigs.k8s.io/controller-runtime/pkg/client/fake" ) -func TestReconcileCSI_configureHolders(t *testing.T) { - r := &ReconcileCSI{ - context: &clusterd.Context{ - Clientset: testop.New(t, 1), - RookClientset: rookclient.NewSimpleClientset(), - }, - opManagerContext: context.TODO(), - opConfig: opcontroller.OperatorConfig{}, - clustersWithHolder: []ClusterDetail{}, - } - - t.Run("no clusters, noop", func(t *testing.T) { - err := r.configureHolders([]driverDetails{}, templateParam{}, []v1.Toleration{}, nil) - assert.NoError(t, err) - }) - - t.Run("one multus cluster", func(t *testing.T) { - r.opConfig.OperatorNamespace = "rook-ceph" - driverDetails := []driverDetails{ - { - name: "rbd", - fullName: "rbd.csi.ceph.com", - holderTemplate: CephFSPluginHolderTemplatePath, - nodeAffinity: cephFSPluginNodeAffinityEnv, - toleration: cephFSPluginTolerationsEnv, - }, - } - tp := templateParam{ - Param: CSIParam, - Namespace: r.opConfig.OperatorNamespace, - } - - r.clustersWithHolder = []ClusterDetail{ - { - cluster: &cephv1.CephCluster{ - ObjectMeta: metav1.ObjectMeta{Namespace: "rook-ceph", Name: "my-cluster"}, - Spec: cephv1.ClusterSpec{}, - }, - clusterInfo: &cephclient.ClusterInfo{ - Monitors: map[string]*cephclient.MonInfo{"a": {Name: "a", Endpoint: "10.0.0.1:6789"}}, - OwnerInfo: cephclient.NewMinimumOwnerInfoWithOwnerRef()}, - }, - } - - t.Setenv(k8sutil.PodNamespaceEnvVar, "rook-ceph") - _, err := r.context.Clientset.CoreV1().ConfigMaps("rook-ceph").Create(r.opManagerContext, &v1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: ConfigName, Namespace: "rook-ceph"}, Data: map[string]string{}}, metav1.CreateOptions{}) - assert.NoError(t, err) - - err = r.configureHolders(driverDetails, tp, []v1.Toleration{}, nil) - assert.NoError(t, err) - }) -} - -func TestGenerateNetNamespaceFilePath(t *testing.T) { - ctx := context.TODO() - - t.Run("generate with no op configmap available and non supported driver name", func(t *testing.T) { - client := fake.NewClientBuilder().Build() - netNsFilePath, err := GenerateNetNamespaceFilePath(ctx, client, "rook-ceph", "rook-ceph", "foo") - assert.Error(t, err) - assert.Empty(t, "", netNsFilePath) - }) - - t.Run("generate with no op configmap available for rbd", func(t *testing.T) { - client := fake.NewClientBuilder().Build() - netNsFilePath, err := GenerateNetNamespaceFilePath(ctx, client, "rook-ceph", "rook-ceph", "rbd") - assert.NoError(t, err) - assert.Equal(t, "/var/lib/kubelet/plugins/rook-ceph.rbd.csi.ceph.com/rook-ceph.net.ns", netNsFilePath) - }) - - t.Run("generate with no op configmap available for cephfs", func(t *testing.T) { - client := fake.NewClientBuilder().Build() - netNsFilePath, err := GenerateNetNamespaceFilePath(ctx, client, "rook-ceph", "rook-ceph", "cephfs") - assert.NoError(t, err) - assert.Equal(t, "/var/lib/kubelet/plugins/rook-ceph.cephfs.csi.ceph.com/rook-ceph.net.ns", netNsFilePath) - }) - - t.Run("generate with op configmap for cephfs", func(t *testing.T) { - opCm := &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: opcontroller.OperatorSettingConfigMapName, - Namespace: "rook-ceph", - }, - Data: map[string]string{"ROOK_CSI_KUBELET_DIR_PATH": "/foo"}, - } - object := []runtime.Object{ - opCm, - } - client := fake.NewClientBuilder().WithRuntimeObjects(object...).Build() - netNsFilePath, err := GenerateNetNamespaceFilePath(ctx, client, "rook-ceph", "rook-ceph", "cephfs") - assert.NoError(t, err) - assert.Equal(t, "/foo/plugins/rook-ceph.cephfs.csi.ceph.com/rook-ceph.net.ns", netNsFilePath) - }) -} - func Test_getCSIDriverNamePrefixFromDeployment(t *testing.T) { namespace := "test" deployment := func(name, containerName, drivernameSuffix string) *apps.Deployment { diff --git a/pkg/operator/ceph/csi/template/cephfs/csi-cephfsplugin-holder.yaml b/pkg/operator/ceph/csi/template/cephfs/csi-cephfsplugin-holder.yaml deleted file mode 100644 index f29659b298d7..000000000000 --- a/pkg/operator/ceph/csi/template/cephfs/csi-cephfsplugin-holder.yaml +++ /dev/null @@ -1,67 +0,0 @@ -# This DaemonSet is only active when the cluster is deployed with Multus enabled or EnableCSIHostNetwork -# is set to false. Hopefully in the future it will be part of every Ceph-CSI deployment. Its role is to -# "hold" the Ceph Filesystem mounts that are created by the CSI driver. Essentially, it exposes its -# network namespace into the Kubelet plugin directly and Ceph-CSI picks it up. When mounting, the Ceph-CSI -# driver will use the network namespace of the DaemonSet instead of its own (the plugin pod). This pod -# is not expected to be updated nor restarted unless the node reboots. -kind: DaemonSet -apiVersion: apps/v1 -metadata: - name: csi-cephfsplugin-holder - namespace: {{ .Namespace }} -spec: - selector: - matchLabels: - app: csi-cephfsplugin-holder - updateStrategy: - # DO NOT CHANGE THE STRATEGY - # The pod is not supposed to be restarted on updates, it should never receive updates too. - # If it does then the connectivity to the Ceph cluster will be lost and the client I/O will - # fail. - type: OnDelete - template: - metadata: - labels: - app: csi-cephfsplugin-holder - {{ range $key, $value := .CSICephFSPodLabels }} - {{ $key }}: "{{ $value }}" - {{ end }} - spec: - # HostPID is needed to expose the correct process ID network namespace and not the process namespace - hostPID: true - securityContext: {} - serviceAccountName: rook-csi-cephfs-plugin-sa - {{ if .PluginPriorityClassName }} - priorityClassName: {{ .PluginPriorityClassName }} - {{ end }} - containers: - - name: csi-cephfsplugin-holder - # This is necessary for the Bidirectional mount propagation - securityContext: - privileged: true - capabilities: - drop: ["ALL"] - image: {{ .CSIPluginImage }} - command: - - "/bin/sh" - - "-c" - # the third $ allows the "$$" to be interpreted so it can return the current bash process ID - args: - - "ln - --force - --symbolic - --verbose - /proc/$$$/ns/net - {{ .KubeletDirPath }}/plugins/$ROOK_CEPH_CSI_DRIVER_NAME/$CEPH_CLUSTER_NAMESPACE.net.ns - && - sleep - infinity" - volumeMounts: - - name: plugin-mount-dir - mountPath: "{{ .KubeletDirPath }}/plugins" - mountPropagation: "Bidirectional" - volumes: - - name: plugin-mount-dir - hostPath: - path: "{{ .KubeletDirPath }}/plugins" - type: Directory diff --git a/pkg/operator/ceph/csi/template/cephfs/csi-cephfsplugin-provisioner-dep.yaml b/pkg/operator/ceph/csi/template/cephfs/csi-cephfsplugin-provisioner-dep.yaml index d78fc1cbe890..35fa8d0c179d 100644 --- a/pkg/operator/ceph/csi/template/cephfs/csi-cephfsplugin-provisioner-dep.yaml +++ b/pkg/operator/ceph/csi/template/cephfs/csi-cephfsplugin-provisioner-dep.yaml @@ -256,6 +256,7 @@ spec: securityContext: privileged: true capabilities: + add: [] drop: ["ALL"] {{ end }} volumeMounts: diff --git a/pkg/operator/ceph/csi/template/cephfs/csi-cephfsplugin.yaml b/pkg/operator/ceph/csi/template/cephfs/csi-cephfsplugin.yaml index bd4bac53cb29..6d92de1ab1e8 100644 --- a/pkg/operator/ceph/csi/template/cephfs/csi-cephfsplugin.yaml +++ b/pkg/operator/ceph/csi/template/cephfs/csi-cephfsplugin.yaml @@ -39,6 +39,7 @@ spec: securityContext: privileged: true capabilities: + add: [] drop: ["ALL"] image: {{ .RegistrarImage }} imagePullPolicy: {{ .ImagePullPolicy }} @@ -144,6 +145,7 @@ spec: securityContext: privileged: true capabilities: + add: [] drop: ["ALL"] image: {{ .CSIPluginImage }} args: diff --git a/pkg/operator/ceph/csi/template/nfs/csi-nfsplugin-holder.yaml b/pkg/operator/ceph/csi/template/nfs/csi-nfsplugin-holder.yaml deleted file mode 100644 index 240d4b6b5dbb..000000000000 --- a/pkg/operator/ceph/csi/template/nfs/csi-nfsplugin-holder.yaml +++ /dev/null @@ -1,67 +0,0 @@ -# This DaemonSet is only active when the cluster is deployed with Multus enabled or EnableCSIHostNetwork -# is set to false. Hopefully in the future it will be part of every Ceph-CSI deployment. Its role is to -# "hold" the Ceph Filesystem mounts that are created by the CSI driver. Essentially, it exposes its -# network namespace into the Kubelet plugin directly and Ceph-CSI picks it up. When mounting, the Ceph-CSI -# driver will use the network namespace of the DaemonSet instead of its own (the plugin pod). This pod -# is not expected to be updated nor restarted unless the node reboots. -kind: DaemonSet -apiVersion: apps/v1 -metadata: - name: csi-nfsplugin-holder - namespace: {{ .Namespace }} -spec: - selector: - matchLabels: - app: csi-nfsplugin-holder - updateStrategy: - # DO NOT CHANGE THE STRATEGY - # The pod is not supposed to be restarted on updates, it should never receive updates too. - # If it does then the connectivity to the Ceph cluster will be lost and the client I/O will - # fail. - type: OnDelete - template: - metadata: - labels: - app: csi-nfsplugin-holder - {{ range $key, $value := .CSINFSPodLabels }} - {{ $key }}: "{{ $value }}" - {{ end }} - spec: - # HostPID is needed to expose the correct process ID network namespace and not the process namespace - hostPID: true - securityContext: {} - serviceAccountName: rook-csi-nfs-plugin-sa - {{ if .PluginPriorityClassName }} - priorityClassName: {{ .PluginPriorityClassName }} - {{ end }} - containers: - - name: csi-nfsplugin-holder - # This is necessary for the Bidirectional mount propagation - securityContext: - privileged: true - capabilities: - drop: ["ALL"] - image: {{ .CSIPluginImage }} - command: - - "/bin/sh" - - "-c" - # the third $ allows the "$$" to be interpreted so it can return the current bash process ID - args: - - "ln - --force - --symbolic - --verbose - /proc/$$$/ns/net - {{ .KubeletDirPath }}/plugins/$ROOK_CEPH_CSI_DRIVER_NAME/$CEPH_CLUSTER_NAMESPACE.net.ns - && - sleep - infinity" - volumeMounts: - - name: plugin-mount-dir - mountPath: "{{ .KubeletDirPath }}/plugins" - mountPropagation: "Bidirectional" - volumes: - - name: plugin-mount-dir - hostPath: - path: "{{ .KubeletDirPath }}/plugins" - type: Directory diff --git a/pkg/operator/ceph/csi/template/nfs/csi-nfsplugin-provisioner-dep.yaml b/pkg/operator/ceph/csi/template/nfs/csi-nfsplugin-provisioner-dep.yaml index 9411546f2b0c..a62473bb1d8c 100644 --- a/pkg/operator/ceph/csi/template/nfs/csi-nfsplugin-provisioner-dep.yaml +++ b/pkg/operator/ceph/csi/template/nfs/csi-nfsplugin-provisioner-dep.yaml @@ -44,6 +44,10 @@ spec: - name: ADDRESS value: /csi/csi-provisioner.sock imagePullPolicy: {{ .ImagePullPolicy }} + securityContext: + capabilities: + add: [] + drop: ["ALL"] volumeMounts: - name: socket-dir mountPath: /csi @@ -71,6 +75,10 @@ spec: - name: ADDRESS value: unix:///csi/csi-provisioner.sock imagePullPolicy: {{ .ImagePullPolicy }} + securityContext: + capabilities: + add: [] + drop: ["ALL"] volumeMounts: - name: socket-dir mountPath: /csi @@ -98,6 +106,10 @@ spec: - name: ADDRESS value: unix:///csi/csi-provisioner.sock imagePullPolicy: {{ .ImagePullPolicy }} + securityContext: + capabilities: + add: [] + drop: ["ALL"] volumeMounts: - name: socket-dir mountPath: /csi @@ -125,6 +137,10 @@ spec: - name: ADDRESS value: unix:///csi/csi-provisioner.sock imagePullPolicy: {{ .ImagePullPolicy }} + securityContext: + capabilities: + add: [] + drop: ["ALL"] volumeMounts: - name: socket-dir mountPath: /csi diff --git a/pkg/operator/ceph/csi/template/nfs/csi-nfsplugin.yaml b/pkg/operator/ceph/csi/template/nfs/csi-nfsplugin.yaml index a0d16acf6ea9..d6b7e8d18bba 100644 --- a/pkg/operator/ceph/csi/template/nfs/csi-nfsplugin.yaml +++ b/pkg/operator/ceph/csi/template/nfs/csi-nfsplugin.yaml @@ -33,6 +33,7 @@ spec: # created by privileged CSI driver container. securityContext: capabilities: + add: [] drop: ["ALL"] privileged: true image: {{ .RegistrarImage }} diff --git a/pkg/operator/ceph/csi/template/rbd/csi-rbdplugin-holder.yaml b/pkg/operator/ceph/csi/template/rbd/csi-rbdplugin-holder.yaml deleted file mode 100644 index c8f11c5cc247..000000000000 --- a/pkg/operator/ceph/csi/template/rbd/csi-rbdplugin-holder.yaml +++ /dev/null @@ -1,67 +0,0 @@ -# This DaemonSet is only active when the cluster is deployed with Multus enabled or EnableCSIHostNetwork -# is set to false. Hopefully in the future it will be part of every Ceph-CSI deployment. Its role is -# to "hold" the network RBD block mapping that are created by the CSI driver. Essentially, it exposes -# its network namespace into the Kubelet plugin directly and Ceph-CSI picks it up. When mapping an RBD -# image, the Ceph-CSI driver will use the network namespace of the DaemonSet instead of its own (the plugin pod). -# This pod is not expected to be updated nor restarted unless the node reboots. -kind: DaemonSet -apiVersion: apps/v1 -metadata: - name: csi-rbdplugin-holder - namespace: {{ .Namespace }} -spec: - selector: - matchLabels: - app: csi-rbdplugin-holder - updateStrategy: - # DO NOT CHANGE THE STRATEGY - # The pod is not supposed to be restarted on updates, it should never receive updates too. - # If it does then the connectivity to the Ceph cluster will be lost and the client I/O will - # fail. - type: OnDelete - template: - metadata: - labels: - app: csi-rbdplugin-holder - {{ range $key, $value := .CSIRBDPodLabels }} - {{ $key }}: "{{ $value }}" - {{ end }} - spec: - # HostPID is needed to expose the correct process ID network namespace and not the process namespace - hostPID: true - securityContext: {} - serviceAccountName: rook-csi-rbd-plugin-sa - {{ if .PluginPriorityClassName }} - priorityClassName: {{ .PluginPriorityClassName }} - {{ end }} - containers: - - name: csi-rbdplugin-holder - # This is necessary for the Bidirectional mount propagation - securityContext: - privileged: true - capabilities: - drop: ["ALL"] - image: {{ .CSIPluginImage }} - command: - - "/bin/sh" - - "-c" - # the third $ allows the "$$" to be interpreted so it can return the current bash process ID - args: - - "ln - --force - --symbolic - --verbose - /proc/$$$/ns/net - {{ .KubeletDirPath }}/plugins/$ROOK_CEPH_CSI_DRIVER_NAME/$CEPH_CLUSTER_NAMESPACE.net.ns - && - sleep - infinity" - volumeMounts: - - name: plugin-mount-dir - mountPath: "{{ .KubeletDirPath }}/plugins" - mountPropagation: "Bidirectional" - volumes: - - name: plugin-mount-dir - hostPath: - path: "{{ .KubeletDirPath }}/plugins" - type: Directory diff --git a/pkg/operator/ceph/csi/template/rbd/csi-rbdplugin-provisioner-dep.yaml b/pkg/operator/ceph/csi/template/rbd/csi-rbdplugin-provisioner-dep.yaml index 741b362b9da0..23a019bc035b 100644 --- a/pkg/operator/ceph/csi/template/rbd/csi-rbdplugin-provisioner-dep.yaml +++ b/pkg/operator/ceph/csi/template/rbd/csi-rbdplugin-provisioner-dep.yaml @@ -209,6 +209,7 @@ spec: securityContext: privileged: true capabilities: + add: [] drop: ["ALL"] {{ end }} volumeMounts: @@ -267,6 +268,7 @@ spec: securityContext: privileged: true capabilities: + add: [] drop: ["ALL"] {{ end }} volumeMounts: diff --git a/pkg/operator/ceph/csi/template/rbd/csi-rbdplugin.yaml b/pkg/operator/ceph/csi/template/rbd/csi-rbdplugin.yaml index fb0a3fca5d9a..99adaa2c6491 100644 --- a/pkg/operator/ceph/csi/template/rbd/csi-rbdplugin.yaml +++ b/pkg/operator/ceph/csi/template/rbd/csi-rbdplugin.yaml @@ -40,6 +40,7 @@ spec: securityContext: privileged: true capabilities: + add: [] drop: ["ALL"] image: {{ .RegistrarImage }} imagePullPolicy: {{ .ImagePullPolicy }} @@ -153,6 +154,7 @@ spec: securityContext: privileged: true capabilities: + add: [] drop: ["ALL"] image: {{ .CSIAddonsImage }} args : @@ -204,6 +206,7 @@ spec: securityContext: privileged: true capabilities: + add: [] drop: ["ALL"] image: {{ .CSIPluginImage }} args: diff --git a/pkg/operator/ceph/csi/version.go b/pkg/operator/ceph/csi/version.go deleted file mode 100644 index aa4d9bb26050..000000000000 --- a/pkg/operator/ceph/csi/version.go +++ /dev/null @@ -1,114 +0,0 @@ -/* -Copyright 2020 The Rook Authors. 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. -*/ - -package csi - -import ( - "fmt" - "regexp" - "strconv" - - "github.com/pkg/errors" -) - -var ( - //minimum supported version is 3.10.0 - minimum = CephCSIVersion{3, 11, 0} - //supportedCSIVersions are versions that rook supports - releasev312 = CephCSIVersion{3, 12, 0} - - supportedCSIVersions = []CephCSIVersion{ - minimum, - releasev312, - } - - // for parsing the output of `cephcsi` - versionCSIPattern = regexp.MustCompile(`v(\d+)\.(\d+)\.(\d+)`) -) - -// CephCSIVersion represents the Ceph CSI version format -type CephCSIVersion struct { - Major int - Minor int - Bugfix int -} - -func (v *CephCSIVersion) String() string { - return fmt.Sprintf("v%d.%d.%d", - v.Major, v.Minor, v.Bugfix) -} - -// Supported checks if the detected version is part of the known supported CSI versions -func (v *CephCSIVersion) Supported() bool { - if !v.isAtLeast(&minimum) { - return false - } - - // if AllowUnsupported is set also a csi-image greater than the supported ones are allowed - if AllowUnsupported { - return true - } - for _, sv := range supportedCSIVersions { - if v.Major == sv.Major { - if v.Minor == sv.Minor { - if v.Bugfix >= sv.Bugfix { - return true - } - } - } - } - return false -} - -func (v *CephCSIVersion) isAtLeast(version *CephCSIVersion) bool { - if v.Major > version.Major { - return true - } - if v.Major == version.Major && v.Minor >= version.Minor { - if v.Minor > version.Minor { - return true - } - if v.Bugfix >= version.Bugfix { - return true - } - } - return false -} - -// extractCephCSIVersion extracts the major, minor and extra digit of a Ceph CSI release -func extractCephCSIVersion(src string) (*CephCSIVersion, error) { - m := versionCSIPattern.FindStringSubmatch(src) - if m == nil || len(m) < 3 { - return nil, errors.Errorf("failed to parse version from: %q", CSIParam.CSIPluginImage) - } - - major, err := strconv.Atoi(m[1]) - if err != nil { - return nil, errors.Wrapf(err, "failed to parse version major part: %q", m[0]) - } - - minor, err := strconv.Atoi(m[2]) - if err != nil { - return nil, errors.Wrapf(err, "failed to parse version minor part: %q", m[1]) - } - - bugfix, err := strconv.Atoi(m[3]) - if err != nil { - return nil, errors.Wrapf(err, "failed to parse version bugfix part: %q", m[2]) - } - - return &CephCSIVersion{major, minor, bugfix}, nil -} diff --git a/pkg/operator/ceph/csi/version_test.go b/pkg/operator/ceph/csi/version_test.go deleted file mode 100644 index 7bd518c6b0d6..000000000000 --- a/pkg/operator/ceph/csi/version_test.go +++ /dev/null @@ -1,129 +0,0 @@ -/* -Copyright 2020 The Rook Authors. 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. -*/ - -package csi - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -var ( - testMinVersion = CephCSIVersion{3, 11, 0} - testReleaseV390 = CephCSIVersion{3, 9, 0} - testReleaseV391 = CephCSIVersion{3, 9, 1} - testreleasev310 = CephCSIVersion{3, 10, 0} - testReleaseV3101 = CephCSIVersion{3, 10, 1} - testReleaseV3102 = CephCSIVersion{3, 10, 2} - testReleaseV3110 = CephCSIVersion{3, 11, 0} - testReleaseV3120 = CephCSIVersion{3, 12, 0} - - testVersionUnsupported = CephCSIVersion{4, 0, 0} -) - -func TestIsAtLeast(t *testing.T) { - // Test version which is smaller - var version = CephCSIVersion{1, 40, 10} - ret := testMinVersion.isAtLeast(&version) - assert.Equal(t, true, ret) - - // Test version which is equal - ret = testMinVersion.isAtLeast(&testMinVersion) - assert.Equal(t, true, ret) - - // Test for 3.9.0 - ret = testReleaseV390.isAtLeast(&testMinVersion) - assert.Equal(t, false, ret) - - // Test for 3.9.1 - ret = testReleaseV391.isAtLeast(&testMinVersion) - assert.Equal(t, false, ret) - - // Test for 3.10.0 - ret = testreleasev310.isAtLeast(&testReleaseV390) - assert.Equal(t, true, ret) - - // Test for 3.10.1 - ret = testReleaseV3101.isAtLeast(&testReleaseV3101) - assert.Equal(t, true, ret) - - // Test for 3.10.2 - ret = testReleaseV3102.isAtLeast(&testReleaseV3102) - assert.Equal(t, true, ret) - - // Test for 3.11.0 - ret = testReleaseV3110.isAtLeast(&testReleaseV3110) - assert.Equal(t, true, ret) - - // Test for 3.12.0 - ret = testReleaseV3120.isAtLeast(&testReleaseV3120) - assert.Equal(t, true, ret) - -} - -func TestSupported(t *testing.T) { - AllowUnsupported = false - ret := testMinVersion.Supported() - assert.Equal(t, true, ret) - - ret = testVersionUnsupported.Supported() - assert.Equal(t, false, ret) - - // 3.9.x is not supported after 3.11.0 release - ret = testReleaseV390.Supported() - assert.Equal(t, false, ret) - - ret = testReleaseV391.Supported() - assert.Equal(t, false, ret) - - ret = testreleasev310.Supported() - assert.Equal(t, false, ret) - - ret = testReleaseV3101.Supported() - assert.Equal(t, false, ret) - - ret = testReleaseV3110.Supported() - assert.Equal(t, true, ret) - - ret = testReleaseV3120.Supported() - assert.Equal(t, true, ret) -} - -func Test_extractCephCSIVersion(t *testing.T) { - expectedVersion := CephCSIVersion{3, 0, 0} - csiString := []byte(`Cephcsi Version: v3.0.0 - Git Commit: e58d537a07ca0184f67d33db85bf6b4911624b44 - Go Version: go1.12.15 - Compiler: gc - Platform: linux/amd64 - `) - version, err := extractCephCSIVersion(string(csiString)) - - assert.Equal(t, &expectedVersion, version) - assert.Nil(t, err) - - csiString = []byte(`Cephcsi Version: rubbish - Git Commit: e58d537a07ca0184f67d33db85bf6b4911624b44 - Go Version: go1.12.15 - Compiler: gc - Platform: linux/amd64 - `) - version, err = extractCephCSIVersion(string(csiString)) - - assert.Nil(t, version) - assert.Contains(t, err.Error(), "failed to parse version from") -} diff --git a/pkg/operator/ceph/file/mds/mds.go b/pkg/operator/ceph/file/mds/mds.go index a315101777d3..de2656f3495c 100644 --- a/pkg/operator/ceph/file/mds/mds.go +++ b/pkg/operator/ceph/file/mds/mds.go @@ -290,7 +290,7 @@ func (c *Cluster) upgradeMDS() error { return errors.Wrap(err, "failed to scale down deployments during upgrade") } logger.Debugf("waiting for all standbys gone") - if err := cephclient.WaitForNoStandbys(c.context, c.clusterInfo, 3*time.Second, 120*time.Second); err != nil { + if err := cephclient.WaitForNoStandbys(c.context, c.clusterInfo, c.fs.Name, 3*time.Second, 120*time.Second); err != nil { return errors.Wrap(err, "failed to wait for stopping all standbys") } diff --git a/pkg/operator/ceph/file/subvolumegroup/controller.go b/pkg/operator/ceph/file/subvolumegroup/controller.go index 5e7cb80f7ef9..d74abe1492aa 100644 --- a/pkg/operator/ceph/file/subvolumegroup/controller.go +++ b/pkg/operator/ceph/file/subvolumegroup/controller.go @@ -311,15 +311,7 @@ func (r *ReconcileCephFilesystemSubVolumeGroup) updateClusterConfig(cephFilesyst }, } - // If the cluster has Multus enabled we need to append the network namespace of the driver's - // holder DaemonSet in the csi configmap - if cephCluster.Spec.Network.IsMultus() { - netNamespaceFilePath, err := csi.GenerateNetNamespaceFilePath(r.opManagerContext, r.client, cephCluster.Namespace, r.opConfig.OperatorNamespace, csi.CephFSDriverShortName) - if err != nil { - return errors.Wrap(err, "failed to generate cephfs net namespace file path") - } - csiClusterConfigEntry.CephFS.NetNamespaceFilePath = netNamespaceFilePath - } + csiClusterConfigEntry.CephFS.NetNamespaceFilePath = "" err := csi.SaveClusterConfig(r.context.Clientset, buildClusterID(cephFilesystemSubVolumeGroup), cephCluster.Namespace, r.clusterInfo, &csiClusterConfigEntry) if err != nil { diff --git a/pkg/operator/ceph/object/bucket/provisioner.go b/pkg/operator/ceph/object/bucket/provisioner.go index 831362102a17..074905625506 100644 --- a/pkg/operator/ceph/object/bucket/provisioner.go +++ b/pkg/operator/ceph/object/bucket/provisioner.go @@ -57,8 +57,10 @@ type Provisioner struct { } type additionalConfigSpec struct { - maxObjects *int64 - maxSize *int64 + maxObjects *int64 + maxSize *int64 + bucketMaxObjects *int64 + bucketMaxSize *int64 } var _ apibkt.Provisioner = &Provisioner{} @@ -578,6 +580,20 @@ func (p *Provisioner) setAdditionalSettings(options *apibkt.BucketOptions) error return errors.Wrap(err, "failed to process additionalConfig") } + err = p.setUserQuota(additionalConfig) + if err != nil { + return errors.Wrap(err, "failed to set user quota") + } + + err = p.setBucketQuota(additionalConfig) + if err != nil { + return errors.Wrap(err, "failed to set bucket quota") + } + + return nil +} + +func (p *Provisioner) setUserQuota(additionalConfig *additionalConfigSpec) error { liveQuota, err := p.adminOpsClient.GetUserQuota(p.clusterInfo.Context, admin.QuotaSpec{UID: p.cephUserName}) if err != nil { return errors.Wrapf(err, "failed to fetch user %q", p.cephUserName) @@ -628,6 +644,59 @@ func (p *Provisioner) setAdditionalSettings(options *apibkt.BucketOptions) error return nil } +func (p *Provisioner) setBucketQuota(additionalConfig *additionalConfigSpec) error { + bucket, err := p.adminOpsClient.GetBucketInfo(p.clusterInfo.Context, admin.Bucket{Bucket: p.bucketName}) + if err != nil { + return errors.Wrapf(err, "failed to fetch bucket %q", p.bucketName) + } + liveQuota := bucket.BucketQuota + + // Copy only the fields that are actively managed by the provisioner to + // prevent passing back undesirable combinations of fields. It is + // known to be problematic to set both MaxSize and MaxSizeKB. + currentQuota := admin.QuotaSpec{ + Enabled: liveQuota.Enabled, + MaxObjects: liveQuota.MaxObjects, + MaxSize: liveQuota.MaxSize, + } + targetQuota := currentQuota + + // enable or disable quota for user + quotaEnabled := (additionalConfig.bucketMaxObjects != nil) || (additionalConfig.bucketMaxSize != nil) + + targetQuota.Enabled = "aEnabled + + if additionalConfig.bucketMaxObjects != nil { + targetQuota.MaxObjects = additionalConfig.bucketMaxObjects + } else if currentQuota.MaxObjects != nil && *currentQuota.MaxObjects >= 0 { + // if the existing value is already negative, we don't want to change it + var objects int64 = -1 + targetQuota.MaxObjects = &objects + } + + if additionalConfig.bucketMaxSize != nil { + targetQuota.MaxSize = additionalConfig.bucketMaxSize + } else if currentQuota.MaxSize != nil && *currentQuota.MaxSize >= 0 { + // if the existing value is already negative, we don't want to change it + var size int64 = -1 + targetQuota.MaxSize = &size + } + + diff := cmp.Diff(currentQuota, targetQuota) + if diff != "" { + logger.Debugf("Quota for bucket %q has changed. diff:%s", p.bucketName, diff) + // UID & Bucket are not set in the QuotaSpec returned by GetBucketInfo() + targetQuota.UID = p.cephUserName + targetQuota.Bucket = p.bucketName + err = p.adminOpsClient.SetIndividualBucketQuota(p.clusterInfo.Context, targetQuota) + if err != nil { + return errors.Wrapf(err, "failed to set bucket %q quota enabled=%v %+v", p.bucketName, quotaEnabled, additionalConfig) + } + } + + return nil +} + func (p *Provisioner) setTlsCaCert() error { objStore, err := p.getObjectStore() if err != nil { diff --git a/pkg/operator/ceph/object/bucket/provisioner_test.go b/pkg/operator/ceph/object/bucket/provisioner_test.go index e9af29131948..467b0a54fa0a 100644 --- a/pkg/operator/ceph/object/bucket/provisioner_test.go +++ b/pkg/operator/ceph/object/bucket/provisioner_test.go @@ -40,6 +40,11 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) +const ( + userPath = "rgw.test/admin/user" + bucketPath = "rgw.test/admin/bucket" +) + func TestPopulateDomainAndPort(t *testing.T) { ctx := context.TODO() store := "test-store" @@ -142,40 +147,42 @@ func TestQuanityToInt64(t *testing.T) { } func TestProvisioner_setAdditionalSettings(t *testing.T) { - newProvisioner := func(t *testing.T, getUserResult string, putValsSeen *[]string) *Provisioner { + newProvisioner := func(t *testing.T, getResult *map[string]string, getSeen, putSeen *map[string][]string) *Provisioner { mockClient := &object.MockClient{ MockDo: func(req *http.Request) (*http.Response, error) { + path := req.URL.Path + // t.Logf("HTTP req: %#v", req) - t.Logf("HTTP %s: %s %s", req.Method, req.URL.Path, req.URL.RawQuery) - - assert.Contains(t, req.URL.RawQuery, "&uid=bob") - - if req.Method == http.MethodGet { - if req.URL.Path == "my.endpoint.net/admin/user" { - statusCode := 200 - if getUserResult == "" { - statusCode = 500 - } - return &http.Response{ - StatusCode: statusCode, - Body: io.NopCloser(bytes.NewReader([]byte(getUserResult))), - }, nil - } + t.Logf("HTTP %s: %s %s", req.Method, path, req.URL.RawQuery) + + statusCode := 200 + if _, ok := (*getResult)[path]; !ok { + // path not configured + statusCode = 500 } - if req.Method == http.MethodPut { - if req.URL.Path == "my.endpoint.net/admin/user" { - *putValsSeen = append(*putValsSeen, req.URL.RawQuery) - return &http.Response{ - StatusCode: 200, - Body: io.NopCloser(bytes.NewReader([]byte(`[]`))), - }, nil + responseBody := []byte(`[]`) + + switch method := req.Method; method { + case http.MethodGet: + (*getSeen)[path] = append((*getSeen)[path], req.URL.RawQuery) + responseBody = []byte((*getResult)[path]) + case http.MethodPut: + if (*putSeen)[path] == nil { + (*putSeen)[path] = []string{} } + (*putSeen)[path] = append((*putSeen)[path], req.URL.RawQuery) + default: + panic(fmt.Sprintf("unexpected request: %q. method %q. path %q", req.URL.RawQuery, req.Method, path)) } - panic(fmt.Sprintf("unexpected request: %q. method %q. path %q", req.URL.RawQuery, req.Method, req.URL.Path)) + + return &http.Response{ + StatusCode: statusCode, + Body: io.NopCloser(bytes.NewReader(responseBody)), + }, nil }, } - adminClient, err := admin.New("my.endpoint.net", "accesskey", "secretkey", mockClient) + adminClient, err := admin.New("rgw.test", "accesskey", "secretkey", mockClient) assert.NoError(t, err) p := &Provisioner{ @@ -189,12 +196,16 @@ func TestProvisioner_setAdditionalSettings(t *testing.T) { return p } - t.Run("quota should remain disabled", func(t *testing.T) { - putValsSeen := []string{} - p := newProvisioner(t, - `{"enabled":false,"check_on_raw":false,"max_size":-1024,"max_size_kb":0,"max_objects":-1}`, - &putValsSeen, - ) + t.Run("user and bucket quota should remain disabled", func(t *testing.T) { + getResult := map[string]string{ + userPath: `{"enabled":false,"check_on_raw":false,"max_size":-1024,"max_size_kb":0,"max_objects":-1}`, + bucketPath: `{"bucket_quota":{"enabled":false,"check_on_raw":false,"max_size":-1024,"max_size_kb":0,"max_objects":-1}}`, + } + getSeen := map[string][]string{} + putSeen := map[string][]string{} + + p := newProvisioner(t, &getResult, &getSeen, &putSeen) + p.setBucketName("bob") err := p.setAdditionalSettings(&apibkt.BucketOptions{ ObjectBucketClaim: &v1alpha1.ObjectBucketClaim{ @@ -204,15 +215,26 @@ func TestProvisioner_setAdditionalSettings(t *testing.T) { }, }) assert.NoError(t, err) - assert.Len(t, putValsSeen, 0) + + assert.Len(t, getSeen[userPath], 1) + assert.Equal(t, numberOfCallsWithValue("uid=bob", getSeen[userPath]), 1) + assert.Len(t, getSeen[bucketPath], 1) + assert.Equal(t, numberOfCallsWithValue("bucket=bob", getSeen[bucketPath]), 1) + + assert.Len(t, putSeen[userPath], 0) // user quota should not be touched + assert.Len(t, putSeen[bucketPath], 0) // bucket quota should not be touched }) - t.Run("quota should be disabled", func(t *testing.T) { - putValsSeen := []string{} - p := newProvisioner(t, - `{"enabled":true,"check_on_raw":false,"max_size":-1024,"max_size_kb":0,"max_objects":2}`, - &putValsSeen, - ) + t.Run("user and bucket quota should be disabled", func(t *testing.T) { + getResult := map[string]string{ + userPath: `{"enabled":true,"check_on_raw":false,"max_size":-1024,"max_size_kb":0,"max_objects":2}`, + bucketPath: `{"owner": "bob","bucket_quota":{"enabled":true,"check_on_raw":false,"max_size":-1024,"max_size_kb":0,"max_objects":3}}`, + } + getSeen := map[string][]string{} + putSeen := map[string][]string{} + + p := newProvisioner(t, &getResult, &getSeen, &putSeen) + p.setBucketName("bob") err := p.setAdditionalSettings(&apibkt.BucketOptions{ ObjectBucketClaim: &v1alpha1.ObjectBucketClaim{ @@ -223,17 +245,27 @@ func TestProvisioner_setAdditionalSettings(t *testing.T) { }) assert.NoError(t, err) - // quota should be disabled, and that's it - assert.Len(t, putValsSeen, 1) - assert.Equal(t, 1, numberOfPutsWithValue(`enabled=false`, putValsSeen)) + assert.Len(t, getSeen[userPath], 1) + assert.Equal(t, numberOfCallsWithValue("uid=bob", getSeen[userPath]), 1) + assert.Len(t, getSeen[bucketPath], 1) + assert.Equal(t, numberOfCallsWithValue("bucket=bob", getSeen[bucketPath]), 1) + + assert.Len(t, putSeen[userPath], 1) + assert.Equal(t, 1, numberOfCallsWithValue("enabled=false", putSeen[userPath])) + assert.Len(t, putSeen[bucketPath], 1) + assert.Equal(t, 1, numberOfCallsWithValue("enabled=false", putSeen[bucketPath])) }) - t.Run("maxSize quota should be enabled", func(t *testing.T) { - putValsSeen := []string{} - p := newProvisioner(t, - `{"enabled":false,"check_on_raw":false,"max_size":-1024,"max_size_kb":0,"max_objects":-1}`, - &putValsSeen, - ) + t.Run("user maxSize quota should be enabled", func(t *testing.T) { + getResult := map[string]string{ + userPath: `{"enabled":false,"check_on_raw":false,"max_size":-1024,"max_size_kb":0,"max_objects":-1}`, + bucketPath: `{"bucket_quota":{"enabled":false,"check_on_raw":false,"max_size":-1,"max_size_kb":0,"max_objects":-1}}`, + } + getSeen := map[string][]string{} + putSeen := map[string][]string{} + + p := newProvisioner(t, &getResult, &getSeen, &putSeen) + p.setBucketName("bob") err := p.setAdditionalSettings(&apibkt.BucketOptions{ ObjectBucketClaim: &v1alpha1.ObjectBucketClaim{ @@ -246,104 +278,219 @@ func TestProvisioner_setAdditionalSettings(t *testing.T) { }) assert.NoError(t, err) - assert.Zero(t, numberOfPutsWithValue(`enabled=false`, putValsSeen)) // no puts should disable + assert.Len(t, getSeen[userPath], 1) + assert.Equal(t, numberOfCallsWithValue("uid=bob", getSeen[userPath]), 1) + assert.Len(t, getSeen[bucketPath], 1) + assert.Equal(t, numberOfCallsWithValue("bucket=bob", getSeen[bucketPath]), 1) - assert.NotEmpty(t, putWithValue(`enabled=true`, putValsSeen)) // at least one put enables + assert.Len(t, putSeen[userPath], 1) + assert.Equal(t, numberOfCallsWithValue("enabled=true", putSeen[userPath]), 1) + assert.Equal(t, numberOfCallsWithValue("max-size=2", putSeen[userPath]), 1) + assert.Len(t, putSeen[bucketPath], 0) // bucket quota should not be touched + }) + + t.Run("user maxObjects quota should be enabled", func(t *testing.T) { + getResult := map[string]string{ + userPath: `{"enabled":false,"check_on_raw":false,"max_size":-1024,"max_size_kb":0,"max_objects":-1}`, + bucketPath: `{"bucket_quota":{"enabled":false,"check_on_raw":false,"max_size":-1,"max_size_kb":0,"max_objects":-1}}`, + } + getSeen := map[string][]string{} + putSeen := map[string][]string{} - // there is only one time that max-size is set, and it's to the right value - assert.Equal(t, 1, numberOfPutsWithValue(`max-size`, putValsSeen)) - assert.NotEmpty(t, putWithValue(`max-size=2`, putValsSeen)) + p := newProvisioner(t, &getResult, &getSeen, &putSeen) + p.setBucketName("bob") + err := p.setAdditionalSettings(&apibkt.BucketOptions{ + ObjectBucketClaim: &v1alpha1.ObjectBucketClaim{ + Spec: v1alpha1.ObjectBucketClaimSpec{ + AdditionalConfig: map[string]string{ + "maxObjects": "2", + }, + }, + }, + }) + assert.NoError(t, err) + + assert.Len(t, getSeen[userPath], 1) + assert.Equal(t, numberOfCallsWithValue("uid=bob", getSeen[userPath]), 1) + assert.Len(t, getSeen[bucketPath], 1) + assert.Equal(t, numberOfCallsWithValue("bucket=bob", getSeen[bucketPath]), 1) + + assert.Len(t, putSeen[userPath], 1) + assert.Equal(t, numberOfCallsWithValue("enabled=true", putSeen[userPath]), 1) + assert.Equal(t, numberOfCallsWithValue("max-objects=2", putSeen[userPath]), 1) + assert.Len(t, putSeen[bucketPath], 0) // bucket quota should not be touched }) - t.Run("maxObjects quota should be enabled", func(t *testing.T) { - putValsSeen := []string{} - p := newProvisioner(t, - `{"enabled":false,"check_on_raw":false,"max_size":-1024,"max_size_kb":0,"max_objects":-1}`, - &putValsSeen, - ) + t.Run("user maxObjects and maxSize quotas should be enabled", func(t *testing.T) { + getResult := map[string]string{ + userPath: `{"enabled":false,"check_on_raw":false,"max_size":-1024,"max_size_kb":0,"max_objects":-1}`, + bucketPath: `{"bucket_quota":{"enabled":false,"check_on_raw":false,"max_size":-1,"max_size_kb":0,"max_objects":-1}}`, + } + getSeen := map[string][]string{} + putSeen := map[string][]string{} + + p := newProvisioner(t, &getResult, &getSeen, &putSeen) + p.setBucketName("bob") err := p.setAdditionalSettings(&apibkt.BucketOptions{ ObjectBucketClaim: &v1alpha1.ObjectBucketClaim{ Spec: v1alpha1.ObjectBucketClaimSpec{ AdditionalConfig: map[string]string{ "maxObjects": "2", + "maxSize": "3", }, }, }, }) assert.NoError(t, err) - assert.Zero(t, numberOfPutsWithValue(`enabled=false`, putValsSeen)) // no puts should disable + assert.Len(t, getSeen[userPath], 1) + assert.Equal(t, numberOfCallsWithValue("uid=bob", getSeen[userPath]), 1) + assert.Len(t, getSeen[bucketPath], 1) + assert.Equal(t, numberOfCallsWithValue("bucket=bob", getSeen[bucketPath]), 1) - assert.NotEmpty(t, putWithValue(`enabled=true`, putValsSeen)) // at least one put enables + assert.Len(t, putSeen[userPath], 1) + assert.Equal(t, numberOfCallsWithValue("enabled=true", putSeen[userPath]), 1) + assert.Equal(t, numberOfCallsWithValue("max-objects=2", putSeen[userPath]), 1) + assert.Equal(t, numberOfCallsWithValue("max-size=3", putSeen[userPath]), 1) + assert.Len(t, putSeen[bucketPath], 0) // bucket quota should not be touched + }) + + t.Run("user quotas are enabled and need updated enabled", func(t *testing.T) { + getResult := map[string]string{ + userPath: `{"enabled":true,"check_on_raw":false,"max_size":1,"max_size_kb":0,"max_objects":1}`, + bucketPath: `{"bucket_quota":{"enabled":false,"check_on_raw":false,"max_size":-1,"max_size_kb":0,"max_objects":-1}}`, + } + getSeen := map[string][]string{} + putSeen := map[string][]string{} - // there is only one time max-objects is set, and it's to the right value - assert.NotEmpty(t, putWithValue(`max-objects=2`, putValsSeen)) - assert.Equal(t, 1, numberOfPutsWithValue(`max-objects`, putValsSeen)) + p := newProvisioner(t, &getResult, &getSeen, &putSeen) + p.setBucketName("bob") + err := p.setAdditionalSettings(&apibkt.BucketOptions{ + ObjectBucketClaim: &v1alpha1.ObjectBucketClaim{ + Spec: v1alpha1.ObjectBucketClaimSpec{ + AdditionalConfig: map[string]string{ + "maxObjects": "12", + "maxSize": "13", + }, + }, + }, + }) + assert.NoError(t, err) + + assert.Len(t, getSeen[userPath], 1) + assert.Equal(t, numberOfCallsWithValue("uid=bob", getSeen[userPath]), 1) + assert.Len(t, getSeen[bucketPath], 1) + assert.Equal(t, numberOfCallsWithValue("bucket=bob", getSeen[bucketPath]), 1) + + assert.Len(t, putSeen[userPath], 1) + assert.Equal(t, numberOfCallsWithValue("enabled=true", putSeen[userPath]), 1) + assert.Equal(t, numberOfCallsWithValue("max-objects=12", putSeen[userPath]), 1) + assert.Equal(t, numberOfCallsWithValue("max-size=13", putSeen[userPath]), 1) + assert.Len(t, putSeen[bucketPath], 0) // bucket quota should not be touched }) - t.Run("maxObjects and maxSize quotas should be enabled", func(t *testing.T) { - putValsSeen := []string{} - p := newProvisioner(t, - `{"enabled":false,"check_on_raw":false,"max_size":-1024,"max_size_kb":0,"max_objects":-1}`, - &putValsSeen, - ) + t.Run("bucket maxObjects quota should be enabled", func(t *testing.T) { + getResult := map[string]string{ + userPath: `{"enabled":false,"check_on_raw":false,"max_size":-1024,"max_size_kb":0,"max_objects":-1}`, + bucketPath: `{"bucket_quota":{"enabled":false,"check_on_raw":false,"max_size":-1,"max_size_kb":0,"max_objects":-1}}`, + } + getSeen := map[string][]string{} + putSeen := map[string][]string{} + + p := newProvisioner(t, &getResult, &getSeen, &putSeen) + p.setBucketName("bob") err := p.setAdditionalSettings(&apibkt.BucketOptions{ ObjectBucketClaim: &v1alpha1.ObjectBucketClaim{ Spec: v1alpha1.ObjectBucketClaimSpec{ AdditionalConfig: map[string]string{ - "maxSize": "2", - "maxObjects": "3", + "bucketMaxObjects": "4", }, }, }, }) assert.NoError(t, err) - assert.Zero(t, numberOfPutsWithValue(`enabled=false`, putValsSeen)) // no puts should disable + assert.Len(t, getSeen[userPath], 1) + assert.Equal(t, numberOfCallsWithValue("uid=bob", getSeen[userPath]), 1) + assert.Len(t, getSeen[bucketPath], 1) + assert.Equal(t, numberOfCallsWithValue("bucket=bob", getSeen[bucketPath]), 1) - assert.NotEmpty(t, putWithValue(`enabled=true`, putValsSeen)) // at least one put enables + assert.Len(t, putSeen[userPath], 0) // user quota should not be touched + assert.Len(t, putSeen[bucketPath], 1) + assert.Equal(t, numberOfCallsWithValue("enabled=true", putSeen[bucketPath]), 1) + assert.Equal(t, numberOfCallsWithValue("max-objects=4", putSeen[bucketPath]), 1) + }) + + t.Run("bucket maxSize quota should be enabled", func(t *testing.T) { + getResult := map[string]string{ + userPath: `{"enabled":false,"check_on_raw":false,"max_size":-1024,"max_size_kb":0,"max_objects":-1}`, + bucketPath: `{"bucket_quota":{"enabled":false,"check_on_raw":false,"max_size":-1024,"max_size_kb":0,"max_objects":-1}}`, + } + getSeen := map[string][]string{} + putSeen := map[string][]string{} + + p := newProvisioner(t, &getResult, &getSeen, &putSeen) + p.setBucketName("bob") + + err := p.setAdditionalSettings(&apibkt.BucketOptions{ + ObjectBucketClaim: &v1alpha1.ObjectBucketClaim{ + Spec: v1alpha1.ObjectBucketClaimSpec{ + AdditionalConfig: map[string]string{ + "bucketMaxSize": "5", + }, + }, + }, + }) + assert.NoError(t, err) - // there is only one time that max-size is set, and it's to the right value - assert.Equal(t, 1, numberOfPutsWithValue(`max-size`, putValsSeen)) - assert.NotEmpty(t, putWithValue(`max-size=2`, putValsSeen)) + assert.Len(t, getSeen[userPath], 1) + assert.Equal(t, numberOfCallsWithValue("uid=bob", getSeen[userPath]), 1) + assert.Len(t, getSeen[bucketPath], 1) + assert.Equal(t, numberOfCallsWithValue("bucket=bob", getSeen[bucketPath]), 1) - // there is only one time max-objects is set, and it's to the right value - assert.NotEmpty(t, putWithValue(`max-objects=3`, putValsSeen)) - assert.Equal(t, 1, numberOfPutsWithValue(`max-objects`, putValsSeen)) + assert.Len(t, putSeen[userPath], 0) // user quota should not be touched + assert.Len(t, putSeen[bucketPath], 1) + assert.Equal(t, numberOfCallsWithValue("enabled=true", putSeen[bucketPath]), 1) + assert.Equal(t, numberOfCallsWithValue("max-size=5", putSeen[bucketPath]), 1) }) - t.Run("quotas are enabled and need updated enabled", func(t *testing.T) { - putValsSeen := []string{} - p := newProvisioner(t, - `{"enabled":true,"check_on_raw":false,"max_size":1,"max_size_kb":0,"max_objects":1}`, - &putValsSeen, - ) + t.Run("bucket quotas are enabled and need updated enabled", func(t *testing.T) { + getResult := map[string]string{ + userPath: `{"enabled":false,"check_on_raw":false,"max_size":-1024,"max_size_kb":0,"max_objects":-1}`, + bucketPath: `{"bucket_quota":{"enabled":true,"check_on_raw":false,"max_size":5,"max_size_kb":0,"max_objects":4}}`, + } + getSeen := map[string][]string{} + putSeen := map[string][]string{} + + p := newProvisioner(t, &getResult, &getSeen, &putSeen) + p.setBucketName("bob") err := p.setAdditionalSettings(&apibkt.BucketOptions{ ObjectBucketClaim: &v1alpha1.ObjectBucketClaim{ Spec: v1alpha1.ObjectBucketClaimSpec{ AdditionalConfig: map[string]string{ - "maxSize": "2", - "maxObjects": "3", + "bucketMaxObjects": "14", + "bucketMaxSize": "15", }, }, }, }) assert.NoError(t, err) - assert.Zero(t, numberOfPutsWithValue(`enabled=false`, putValsSeen)) // no puts should disable - - // there is only one time that max-size is set, and it's to the right value - assert.Equal(t, 1, numberOfPutsWithValue(`max-size`, putValsSeen)) - assert.NotEmpty(t, putWithValue(`max-size=2`, putValsSeen)) + assert.Len(t, getSeen[userPath], 1) + assert.Equal(t, numberOfCallsWithValue("uid=bob", getSeen[userPath]), 1) + assert.Len(t, getSeen[bucketPath], 1) + assert.Equal(t, numberOfCallsWithValue("bucket=bob", getSeen[bucketPath]), 1) - // there is only one time max-objects is set, and it's to the right value - assert.NotEmpty(t, putWithValue(`max-objects=3`, putValsSeen)) - assert.Equal(t, 1, numberOfPutsWithValue(`max-objects`, putValsSeen)) + assert.Len(t, putSeen[userPath], 0) // user quota should not be touched + assert.Len(t, putSeen[bucketPath], 1) + assert.Equal(t, numberOfCallsWithValue("enabled=true", putSeen[bucketPath]), 1) + assert.Equal(t, numberOfCallsWithValue("max-objects=14", putSeen[bucketPath]), 1) + assert.Equal(t, numberOfCallsWithValue("max-size=15", putSeen[bucketPath]), 1) }) } @@ -367,9 +514,21 @@ func TestProvisioner_additionalConfigSpecFromMap(t *testing.T) { var i int64 = 3 assert.Equal(t, additionalConfigSpec{maxSize: &i}, *spec) }) + + t.Run("bucketMaxObjects field should be set", func(t *testing.T) { + spec, err := additionalConfigSpecFromMap(map[string]string{"bucketMaxObjects": "4"}) + assert.NoError(t, err) + assert.Equal(t, additionalConfigSpec{bucketMaxObjects: &(&struct{ i int64 }{4}).i}, *spec) + }) + + t.Run("bucketMaxSize field should be set", func(t *testing.T) { + spec, err := additionalConfigSpecFromMap(map[string]string{"bucketMaxSize": "5"}) + assert.NoError(t, err) + assert.Equal(t, additionalConfigSpec{bucketMaxSize: &(&struct{ i int64 }{5}).i}, *spec) + }) } -func numberOfPutsWithValue(substr string, strs []string) int { +func numberOfCallsWithValue(substr string, strs []string) int { count := 0 for _, s := range strs { if strings.Contains(s, substr) { @@ -378,12 +537,3 @@ func numberOfPutsWithValue(substr string, strs []string) int { } return count } - -func putWithValue(substr string, strs []string) string { - for _, s := range strs { - if strings.Contains(s, substr) { - return s - } - } - return "" -} diff --git a/pkg/operator/ceph/object/bucket/util.go b/pkg/operator/ceph/object/bucket/util.go index fe75c9e0d50e..de1936d2649b 100644 --- a/pkg/operator/ceph/object/bucket/util.go +++ b/pkg/operator/ceph/object/bucket/util.go @@ -106,6 +106,20 @@ func additionalConfigSpecFromMap(config map[string]string) (*additionalConfigSpe } } + if _, ok := config["bucketMaxObjects"]; ok { + spec.bucketMaxObjects, err = quanityToInt64(config["bucketMaxObjects"]) + if err != nil { + return nil, errors.Wrapf(err, "failed to parse bucketMaxObjects quota") + } + } + + if _, ok := config["bucketMaxSize"]; ok { + spec.bucketMaxSize, err = quanityToInt64(config["bucketMaxSize"]) + if err != nil { + return nil, errors.Wrapf(err, "failed to parse bucketMaxSize quota") + } + } + return &spec, nil } diff --git a/pkg/operator/ceph/object/objectstore.go b/pkg/operator/ceph/object/objectstore.go index 63f28dbedded..e2e79304afd5 100644 --- a/pkg/operator/ceph/object/objectstore.go +++ b/pkg/operator/ceph/object/objectstore.go @@ -800,7 +800,8 @@ func ConfigureSharedPoolsForZone(objContext *Context, sharedPools cephv1.ObjectS if err != nil { return err } - zoneGroupUpdated, err := adjustZoneGroupPlacementTargets(zoneGroupConfig, zoneUpdated) + defaultPlacement := getDefaultPlacementName(sharedPools) + zoneGroupUpdated, err := adjustZoneGroupPlacementTargets(zoneGroupConfig, zoneUpdated, defaultPlacement) if err != nil { return err } @@ -1401,10 +1402,10 @@ func ValidateObjectStorePoolsConfig(metadataPool, dataPool cephv1.PoolSpec, shar return err } if !EmptyPool(dataPool) && sharedPools.DataPoolName != "" { - return fmt.Errorf("invalidObjStorePoolCofig: object store dataPool and sharedPools.dataPool=%s are mutually exclusive. Only one of them can be set.", sharedPools.DataPoolName) + return fmt.Errorf("invalidObjStorePoolConfig: object store dataPool and sharedPools.dataPool=%s are mutually exclusive. Only one of them can be set.", sharedPools.DataPoolName) } if !EmptyPool(metadataPool) && sharedPools.MetadataPoolName != "" { - return fmt.Errorf("invalidObjStorePoolCofig: object store metadataPool and sharedPools.metadataPool=%s are mutually exclusive. Only one of them can be set.", sharedPools.MetadataPoolName) + return fmt.Errorf("invalidObjStorePoolConfig: object store metadataPool and sharedPools.metadataPool=%s are mutually exclusive. Only one of them can be set.", sharedPools.MetadataPoolName) } return nil } diff --git a/pkg/operator/ceph/object/objectstore_test.go b/pkg/operator/ceph/object/objectstore_test.go index 4662349a53e5..f384d6c704c2 100644 --- a/pkg/operator/ceph/object/objectstore_test.go +++ b/pkg/operator/ceph/object/objectstore_test.go @@ -330,11 +330,12 @@ func TestConfigureStoreWithSharedPools(t *testing.T) { assert.True(t, zoneGroupGetCalled) assert.False(t, zoneGroupSetCalled) // zone group is set only if extra pool placements specified }) - t.Run("configure with default placement", func(t *testing.T) { + t.Run("configure with new default placement", func(t *testing.T) { sharedPools := cephv1.ObjectSharedPoolsSpec{ PoolPlacements: []cephv1.PoolPlacementSpec{ { - Name: defaultPlacementName, + Name: "default", + Default: true, MetadataPoolName: "test-meta", DataPoolName: "test-data", }, @@ -346,9 +347,11 @@ func TestConfigureStoreWithSharedPools(t *testing.T) { assert.True(t, zoneSetCalled) assert.False(t, placementModifyCalled) // mock returns applied namespases, no workaround needed assert.True(t, zoneGroupGetCalled) - assert.False(t, zoneGroupSetCalled) // zone group is set only if extra pool placements specified + assert.True(t, zoneGroupSetCalled) }) t.Run("data pool already set", func(t *testing.T) { + // reset + zoneGroupSetCalled = false // Simulate that the data pool has already been set and the zone update can be skipped sharedPools := cephv1.ObjectSharedPoolsSpec{ MetadataPoolName: "test-meta", @@ -370,7 +373,8 @@ func TestConfigureStoreWithSharedPools(t *testing.T) { sharedPools := cephv1.ObjectSharedPoolsSpec{ PoolPlacements: []cephv1.PoolPlacementSpec{ { - Name: defaultPlacementName, + Name: "default", + Default: true, MetadataPoolName: "test-meta", DataPoolName: "test-data", }, diff --git a/pkg/operator/ceph/object/s3-handlers.go b/pkg/operator/ceph/object/s3-handlers.go index a40614c700d3..13eccb8261d1 100644 --- a/pkg/operator/ceph/object/s3-handlers.go +++ b/pkg/operator/ceph/object/s3-handlers.go @@ -199,12 +199,18 @@ func (s *S3Agent) DeleteObjectInBucket(bucketname string, key string) (bool, err func BuildTransportTLS(tlsCert []byte, insecure bool) *http.Transport { //nolint:gosec // is enabled only for testing - tlsConfig := &tls.Config{MinVersion: tls.VersionTLS12, InsecureSkipVerify: insecure} + tlsConfig := &tls.Config{InsecureSkipVerify: insecure} + var caCertPool *x509.CertPool + var err error + caCertPool, err = x509.SystemCertPool() + if err != nil { + logger.Warningf("failed to load system cert pool; continuing without loading system certs") + caCertPool = x509.NewCertPool() // start with empty cert pool instead + } if len(tlsCert) > 0 { - caCertPool := x509.NewCertPool() caCertPool.AppendCertsFromPEM(tlsCert) - tlsConfig.RootCAs = caCertPool } + tlsConfig.RootCAs = caCertPool return &http.Transport{ TLSClientConfig: tlsConfig, diff --git a/pkg/operator/ceph/object/s3-handlers_test.go b/pkg/operator/ceph/object/s3-handlers_test.go index 308575397550..f7f20fe0ccaf 100644 --- a/pkg/operator/ceph/object/s3-handlers_test.go +++ b/pkg/operator/ceph/object/s3-handlers_test.go @@ -53,7 +53,7 @@ func TestNewS3Agent(t *testing.T) { insecure := true s3Agent, err := newS3Agent(accessKey, secretKey, endpoint, debug, nil, insecure) assert.NoError(t, err) - assert.Nil(t, s3Agent.Client.Config.HTTPClient.Transport.(*http.Transport).TLSClientConfig.RootCAs) + assert.NotNil(t, s3Agent.Client.Config.HTTPClient.Transport.(*http.Transport).TLSClientConfig.RootCAs) // still includes sys certs assert.True(t, s3Agent.Client.Config.HTTPClient.Transport.(*http.Transport).TLSClientConfig.InsecureSkipVerify) assert.False(t, *s3Agent.Client.Config.DisableSSL) }) diff --git a/pkg/operator/ceph/object/shared_pools.go b/pkg/operator/ceph/object/shared_pools.go index 7627a08a8a38..95bafb14c8af 100644 --- a/pkg/operator/ceph/object/shared_pools.go +++ b/pkg/operator/ceph/object/shared_pools.go @@ -13,14 +13,13 @@ import ( ) const ( - defaultPlacementName = "default" defaultPlacementCephConfigName = "default-placement" defaultPlacementStorageClass = "STANDARD" ) func IsNeedToCreateObjectStorePools(sharedPools cephv1.ObjectSharedPoolsSpec) bool { for _, pp := range sharedPools.PoolPlacements { - if pp.Name == defaultPlacementName { + if pp.Default { // No need to create pools. External pools from default placement will be used return false } @@ -33,14 +32,25 @@ func IsNeedToCreateObjectStorePools(sharedPools cephv1.ObjectSharedPoolsSpec) bo } func validatePoolPlacements(placements []cephv1.PoolPlacementSpec) error { + hasDefault := false names := make(map[string]struct{}, len(placements)) for _, p := range placements { + if hasDefault && p.Default { + return fmt.Errorf("invalidObjStorePoolConfig: only one placement can be set as default") + } + hasDefault = hasDefault || p.Default + if _, ok := names[p.Name]; ok { - return fmt.Errorf("invalidObjStorePoolCofig: invalid placement %s: placement names must be unique", p.Name) + return fmt.Errorf("invalidObjStorePoolConfig: invalid placement %s: placement names must be unique", p.Name) + } + + if p.Name == defaultPlacementCephConfigName && !p.Default { + return fmt.Errorf("invalidObjStorePoolConfig: placement with name %s must be marked as default", defaultPlacementCephConfigName) } + names[p.Name] = struct{}{} if err := validatePoolPlacementStorageClasses(p.StorageClasses); err != nil { - return fmt.Errorf("invalidObjStorePoolCofig: invalid placement %s: %w", p.Name, err) + return fmt.Errorf("invalidObjStorePoolConfig: invalid placement %s: %w", p.Name, err) } } return nil @@ -91,10 +101,19 @@ func adjustZonePlacementPools(zone map[string]interface{}, spec cephv1.ObjectSha return nil, fmt.Errorf("unable to get pool placement name for zone %s: %w", name, err) } // check if placement should be removed - if _, inSpec := fromSpec[placementID]; !inSpec && placementID != defaultPlacementCephConfigName { - // remove placement if it is not in spec, but don't remove default placement - idxToRemove[i] = struct{}{} - continue + if _, inSpec := fromSpec[placementID]; !inSpec { + if placementID == defaultPlacementCephConfigName { + // 'default-placement' should always be kept as a workaround for https://tracker.ceph.com/issues/68775. + // if user specified other placement as default, then copy pool names to 'default-placement' from it: + if userDefault, inSpec := fromSpec[getDefaultPlacementName(spec)]; inSpec { + // duplicate user defined default placement under 'default-placement' name in spec to update pools on the next step + fromSpec[defaultPlacementCephConfigName] = userDefault + } + } else { + // remove placement if it is not in spec + idxToRemove[i] = struct{}{} + continue + } } // update placement with values from spec: if pSpec, inSpec := fromSpec[placementID]; inSpec { @@ -144,6 +163,29 @@ func adjustZonePlacementPools(zone map[string]interface{}, spec cephv1.ObjectSha placements = append(placements, pObj) } + // sort placements array. + // Reason: 'radosgw-admin zone set --infile' sorts placement_pools by key before storing it in ceph + // and returns JSON with sorted placement_pools array. So we sort input array for easy comparison with applied JSON. + sort.Slice(placements, func(i, j int) bool { + pI, ok := placements[i].(map[string]interface{}) + if !ok { + return false + } + nameI, err := getObjProperty[string](pI, "key") + if err != nil { + return false + } + pJ, ok := placements[j].(map[string]interface{}) + if !ok { + return false + } + nameJ, err := getObjProperty[string](pJ, "key") + if err != nil { + return false + } + return nameI < nameJ + }) + _, err = updateObjProperty(zone, placements, "placement_pools") if err != nil { return nil, fmt.Errorf("unable to set pool placements for zone %q: %w", name, err) @@ -151,9 +193,18 @@ func adjustZonePlacementPools(zone map[string]interface{}, spec cephv1.ObjectSha return zone, nil } +func getDefaultPlacementName(spec cephv1.ObjectSharedPoolsSpec) string { + for _, p := range spec.PoolPlacements { + if p.Default { + return p.Name + } + } + return defaultPlacementCephConfigName +} + func getDefaultMetadataPool(spec cephv1.ObjectSharedPoolsSpec) string { for _, p := range spec.PoolPlacements { - if p.Name == defaultPlacementName { + if p.Default { return p.MetadataPoolName } } @@ -162,18 +213,9 @@ func getDefaultMetadataPool(spec cephv1.ObjectSharedPoolsSpec) string { // toZonePlacementPools converts pool placement CRD definition to zone config json format structures func toZonePlacementPools(spec cephv1.ObjectSharedPoolsSpec, ns string) map[string]ZonePlacementPool { - hasDefault := false res := make(map[string]ZonePlacementPool, len(spec.PoolPlacements)+1) - for _, pp := range spec.PoolPlacements { - name := pp.Name - if pp.Name == defaultPlacementName { - hasDefault = true - name = defaultPlacementCephConfigName - } - res[name] = toZonePlacementPool(pp, ns) - } - if !hasDefault && spec.DataPoolName != "" && spec.MetadataPoolName != "" { - // set shared pools as default if no default placement was provided + // map sharedPools if presented: + if spec.DataPoolName != "" && spec.MetadataPoolName != "" { res[defaultPlacementCephConfigName] = ZonePlacementPool{ Key: defaultPlacementCephConfigName, Val: ZonePlacementPoolVal{ @@ -193,14 +235,15 @@ func toZonePlacementPools(spec cephv1.ObjectSharedPoolsSpec, ns string) map[stri }, } } + // map pool placements: + for _, pp := range spec.PoolPlacements { + res[pp.Name] = toZonePlacementPool(pp, ns) + } return res } func toZonePlacementPool(spec cephv1.PoolPlacementSpec, ns string) ZonePlacementPool { - placementNS := ns - if spec.Name != defaultPlacementName { - placementNS += "." + spec.Name - } + placementNS := ns + "." + spec.Name // The extra pool is for omap data for multi-part uploads, so we use // the metadata pool instead of the data pool. nonECPool := spec.MetadataPoolName + ":" + placementNS + ".data.non-ec" @@ -218,15 +261,12 @@ func toZonePlacementPool(spec cephv1.PoolPlacementSpec, ns string) ZonePlacement DataPool: spec.DataPoolName + ":" + placementNS + ".data", }, }, - // Workaround: radosgw-admin set zone json command sets incorrect default value for placement inline_data field. + // Workaround: 'radosgw-admin set zone json' command sets incorrect default value for placement inline_data field. // So we should set default value (true) explicitly. // See: https://tracker.ceph.com/issues/67933 InlineData: true, }, } - if res.Key == defaultPlacementName { - res.Key = defaultPlacementCephConfigName - } for _, v := range spec.StorageClasses { res.Val.StorageClasses[v.Name] = ZonePlacementStorageClass{ DataPool: v.DataPoolName + ":" + ns + "." + v.Name, @@ -235,7 +275,7 @@ func toZonePlacementPool(spec cephv1.PoolPlacementSpec, ns string) ZonePlacement return res } -func adjustZoneGroupPlacementTargets(group, zone map[string]interface{}) (map[string]interface{}, error) { +func adjustZoneGroupPlacementTargets(group, zone map[string]interface{}, defaultPlacement string) (map[string]interface{}, error) { name, err := getObjProperty[string](group, "name") if err != nil { return nil, fmt.Errorf("unable to get zonegroup name: %w", err) @@ -247,7 +287,7 @@ func adjustZoneGroupPlacementTargets(group, zone map[string]interface{}) (map[st return nil, fmt.Errorf("unable to deep copy config for zonegroup %s: %w", name, err) } - _, err = updateObjProperty(group, defaultPlacementCephConfigName, "default_placement") + _, err = updateObjProperty(group, defaultPlacement, "default_placement") if err != nil { return nil, fmt.Errorf("unable to set default_placement for zonegroup %s: %w", name, err) } @@ -481,7 +521,7 @@ func updateZoneGroupJSON(objContext *Context, group map[string]interface{}) (map args := []string{"zonegroup", "set", zoneArg, "--infile=" + configFilename, realmArg, zoneGroupArg} updatedBytes, err := RunAdminCommandNoMultisite(objContext, false, args...) if err != nil { - return nil, errors.Wrap(err, "failed to set zone config") + return nil, errors.Wrap(err, fmt.Sprintf("failed to set zonegroup config %s", updatedBytes)) } updated := map[string]interface{}{} err = json.Unmarshal([]byte(updatedBytes), &updated) diff --git a/pkg/operator/ceph/object/shared_pools_test.go b/pkg/operator/ceph/object/shared_pools_test.go index 4ef29275f258..81f26b799887 100644 --- a/pkg/operator/ceph/object/shared_pools_test.go +++ b/pkg/operator/ceph/object/shared_pools_test.go @@ -24,6 +24,7 @@ func Test_validatePoolPlacements(t *testing.T) { placements: []cephv1.PoolPlacementSpec{ { Name: "name1", + Default: true, MetadataPoolName: "", // handled by CRD validation DataPoolName: "", // handled by CRD validation DataNonECPoolName: "", // handled by CRD validation @@ -31,6 +32,7 @@ func Test_validatePoolPlacements(t *testing.T) { }, { Name: "name2", + Default: false, MetadataPoolName: "", // handled by CRD validation DataPoolName: "", // handled by CRD validation DataNonECPoolName: "", // handled by CRD validation @@ -62,6 +64,78 @@ func Test_validatePoolPlacements(t *testing.T) { }, wantErr: true, }, + { + name: "invalid: more than one default placement", + args: args{ + placements: []cephv1.PoolPlacementSpec{ + { + Name: "one", + Default: true, + MetadataPoolName: "", // handled by CRD validation + DataPoolName: "", // handled by CRD validation + DataNonECPoolName: "", // handled by CRD validation + StorageClasses: []cephv1.PlacementStorageClassSpec{}, + }, + { + Name: "two", + Default: true, + MetadataPoolName: "", // handled by CRD validation + DataPoolName: "", // handled by CRD validation + DataNonECPoolName: "", // handled by CRD validation + StorageClasses: []cephv1.PlacementStorageClassSpec{}, + }, + }, + }, + wantErr: true, + }, + { + name: "invalid: non-default placement with reserved name", + args: args{ + placements: []cephv1.PoolPlacementSpec{ + { + Name: defaultPlacementCephConfigName, + Default: false, + MetadataPoolName: "", // handled by CRD validation + DataPoolName: "", // handled by CRD validation + DataNonECPoolName: "", // handled by CRD validation + StorageClasses: []cephv1.PlacementStorageClassSpec{}, + }, + { + Name: "two", + Default: true, + MetadataPoolName: "", // handled by CRD validation + DataPoolName: "", // handled by CRD validation + DataNonECPoolName: "", // handled by CRD validation + StorageClasses: []cephv1.PlacementStorageClassSpec{}, + }, + }, + }, + wantErr: true, + }, + { + name: "valid: default placement with reserved name", + args: args{ + placements: []cephv1.PoolPlacementSpec{ + { + Name: defaultPlacementCephConfigName, + Default: true, + MetadataPoolName: "", // handled by CRD validation + DataPoolName: "", // handled by CRD validation + DataNonECPoolName: "", // handled by CRD validation + StorageClasses: []cephv1.PlacementStorageClassSpec{}, + }, + { + Name: "two", + Default: false, + MetadataPoolName: "", // handled by CRD validation + DataPoolName: "", // handled by CRD validation + DataNonECPoolName: "", // handled by CRD validation + StorageClasses: []cephv1.PlacementStorageClassSpec{}, + }, + }, + }, + wantErr: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -165,7 +239,8 @@ func TestIsNeedToCreateObjectStorePools(t *testing.T) { PreserveRadosNamespaceDataOnDelete: false, PoolPlacements: []cephv1.PoolPlacementSpec{ { - Name: "default", + Name: "name", + Default: true, MetadataPoolName: "", // handled by CRD validation DataPoolName: "", // handled by CRD validation DataNonECPoolName: "", // handled by CRD validation @@ -221,7 +296,8 @@ func TestIsNeedToCreateObjectStorePools(t *testing.T) { PreserveRadosNamespaceDataOnDelete: false, PoolPlacements: []cephv1.PoolPlacementSpec{ { - Name: "fast", + Name: "default", + Default: false, MetadataPoolName: "", // handled by CRD validation DataPoolName: "", // handled by CRD validation DataNonECPoolName: "", // handled by CRD validation @@ -267,7 +343,8 @@ func Test_getDefaultMetadataPool(t *testing.T) { StorageClasses: []cephv1.PlacementStorageClassSpec{}, }, { - Name: defaultPlacementName, + Name: "some_name_2", + Default: true, MetadataPoolName: "meta2", DataPoolName: "data2", DataNonECPoolName: "data-non-ec2", @@ -294,7 +371,8 @@ func Test_getDefaultMetadataPool(t *testing.T) { StorageClasses: []cephv1.PlacementStorageClassSpec{}, }, { - Name: defaultPlacementName, + Name: "some_name_2", + Default: true, MetadataPoolName: "meta2", DataPoolName: "data2", DataNonECPoolName: "data-non-ec2", @@ -314,7 +392,8 @@ func Test_getDefaultMetadataPool(t *testing.T) { PreserveRadosNamespaceDataOnDelete: false, PoolPlacements: []cephv1.PoolPlacementSpec{ { - Name: "some_name", + Name: "default", + Default: false, MetadataPoolName: "meta1", DataPoolName: "data1", DataNonECPoolName: "data-non-ec1", @@ -334,7 +413,8 @@ func Test_getDefaultMetadataPool(t *testing.T) { PreserveRadosNamespaceDataOnDelete: false, PoolPlacements: []cephv1.PoolPlacementSpec{ { - Name: "some_name", + Name: "default", + Default: false, MetadataPoolName: "meta1", DataPoolName: "data1", DataNonECPoolName: "data-non-ec1", @@ -369,7 +449,8 @@ func Test_toZonePlacementPool(t *testing.T) { name: "map default placement without non-ec to config", args: args{ spec: cephv1.PoolPlacementSpec{ - Name: defaultPlacementName, + Name: defaultPlacementCephConfigName, + Default: true, MetadataPoolName: "meta", DataPoolName: "data", DataNonECPoolName: "", @@ -385,11 +466,11 @@ func Test_toZonePlacementPool(t *testing.T) { want: ZonePlacementPool{ Key: defaultPlacementCephConfigName, Val: ZonePlacementPoolVal{ - DataExtraPool: "meta:ns.data.non-ec", - IndexPool: "meta:ns.index", + DataExtraPool: "meta:ns.default-placement.data.non-ec", + IndexPool: "meta:ns.default-placement.index", StorageClasses: map[string]ZonePlacementStorageClass{ defaultPlacementStorageClass: { - DataPool: "data:ns.data", + DataPool: "data:ns.default-placement.data", }, "REDUCED_REDUNDANCY": { DataPool: "reduced:ns.REDUCED_REDUNDANCY", @@ -403,7 +484,8 @@ func Test_toZonePlacementPool(t *testing.T) { name: "map default placement to config", args: args{ spec: cephv1.PoolPlacementSpec{ - Name: defaultPlacementName, + Name: "fast", + Default: true, MetadataPoolName: "meta", DataPoolName: "data", DataNonECPoolName: "repl", @@ -417,13 +499,13 @@ func Test_toZonePlacementPool(t *testing.T) { ns: "ns", }, want: ZonePlacementPool{ - Key: defaultPlacementCephConfigName, + Key: "fast", Val: ZonePlacementPoolVal{ - DataExtraPool: "repl:ns.data.non-ec", - IndexPool: "meta:ns.index", + DataExtraPool: "repl:ns.fast.data.non-ec", + IndexPool: "meta:ns.fast.index", StorageClasses: map[string]ZonePlacementStorageClass{ defaultPlacementStorageClass: { - DataPool: "data:ns.data", + DataPool: "data:ns.fast.data", }, "REDUCED_REDUNDANCY": { DataPool: "reduced:ns.REDUCED_REDUNDANCY", @@ -433,37 +515,12 @@ func Test_toZonePlacementPool(t *testing.T) { }, }, }, - { - name: "map default placement without extra SC to config", - args: args{ - spec: cephv1.PoolPlacementSpec{ - Name: defaultPlacementName, - MetadataPoolName: "meta", - DataPoolName: "data", - DataNonECPoolName: "repl", - StorageClasses: []cephv1.PlacementStorageClassSpec{}, - }, - ns: "ns", - }, - want: ZonePlacementPool{ - Key: defaultPlacementCephConfigName, - Val: ZonePlacementPoolVal{ - DataExtraPool: "repl:ns.data.non-ec", - IndexPool: "meta:ns.index", - StorageClasses: map[string]ZonePlacementStorageClass{ - defaultPlacementStorageClass: { - DataPool: "data:ns.data", - }, - }, - InlineData: true, - }, - }, - }, { name: "map non-default placement without non-ec to config", args: args{ spec: cephv1.PoolPlacementSpec{ Name: "placement", + Default: false, MetadataPoolName: "meta", DataPoolName: "data", DataNonECPoolName: "", @@ -498,6 +555,7 @@ func Test_toZonePlacementPool(t *testing.T) { args: args{ spec: cephv1.PoolPlacementSpec{ Name: "placement", + Default: false, MetadataPoolName: "meta", DataPoolName: "data", DataNonECPoolName: "repl", @@ -572,7 +630,7 @@ func Test_toZonePlacementPools(t *testing.T) { }, }, { - name: "default placement overrides shared pools", + name: "shared pools not removed if default placement set", args: args{ spec: cephv1.ObjectSharedPoolsSpec{ MetadataPoolName: "meta", @@ -580,7 +638,8 @@ func Test_toZonePlacementPools(t *testing.T) { PreserveRadosNamespaceDataOnDelete: false, PoolPlacements: []cephv1.PoolPlacementSpec{ { - Name: defaultPlacementName, + Name: "some_name", + Default: true, MetadataPoolName: "meta1", DataPoolName: "data1", DataNonECPoolName: "data-non-ec", @@ -599,11 +658,24 @@ func Test_toZonePlacementPools(t *testing.T) { defaultPlacementCephConfigName: { Key: defaultPlacementCephConfigName, Val: ZonePlacementPoolVal{ - DataExtraPool: "data-non-ec:rgw-instance.data.non-ec", - IndexPool: "meta1:rgw-instance.index", + DataExtraPool: "meta:rgw-instance.buckets.non-ec", + IndexPool: "meta:rgw-instance.buckets.index", + StorageClasses: map[string]ZonePlacementStorageClass{ + "STANDARD": { + DataPool: "data:rgw-instance.buckets.data", + }, + }, + InlineData: true, + }, + }, + "some_name": { + Key: "some_name", + Val: ZonePlacementPoolVal{ + DataExtraPool: "data-non-ec:rgw-instance.some_name.data.non-ec", + IndexPool: "meta1:rgw-instance.some_name.index", StorageClasses: map[string]ZonePlacementStorageClass{ defaultPlacementStorageClass: { - DataPool: "data1:rgw-instance.data", + DataPool: "data1:rgw-instance.some_name.data", }, "REDUCED_REDUNDANCY": { DataPool: "reduced:rgw-instance.REDUCED_REDUNDANCY", @@ -962,7 +1034,8 @@ func Test_adjustZoneDefaultPools(t *testing.T) { PreserveRadosNamespaceDataOnDelete: false, PoolPlacements: []cephv1.PoolPlacementSpec{ { - Name: defaultPlacementName, + Name: "some_name", + Default: true, MetadataPoolName: "meta-pool", DataPoolName: "data-pool", }, @@ -1384,6 +1457,156 @@ func Test_adjustZonePlacementPools(t *testing.T) { } } ] +}`, + wantChanged: true, + wantErr: false, + }, + { + name: "sharedPools placement not removed if default set", + args: args{ + beforeJSON: `{ + "id": "f539c2c0-e1ed-4c42-9294-41742352eeae", + "name": "test", + "placement_pools": [ + { + "key": "default-placement", + "val": { + "index_pool": "test.rgw.buckets.index", + "storage_classes": { + "STANDARD": { + "data_pool": "test.rgw.buckets.data" + } + }, + "data_extra_pool": "test.rgw.buckets.non-ec", + "index_type": 5, + "inline_data": true + } + } + ] +}`, + spec: cephv1.ObjectSharedPoolsSpec{ + MetadataPoolName: "meta-pool", + DataPoolName: "data-pool", + PreserveRadosNamespaceDataOnDelete: false, + PoolPlacements: []cephv1.PoolPlacementSpec{ + { + Name: "slow", + Default: true, + MetadataPoolName: "slow-meta", + DataPoolName: "slow-data", + DataNonECPoolName: "slow-non-ec", + StorageClasses: []cephv1.PlacementStorageClassSpec{}, + }, + }, + }, + }, + wantJSON: `{ + "id": "f539c2c0-e1ed-4c42-9294-41742352eeae", + "name": "test", + "placement_pools": [ + { + "key": "default-placement", + "val": { + "index_pool": "meta-pool:test.buckets.index", + "storage_classes": { + "STANDARD": { + "data_pool": "data-pool:test.buckets.data" + } + }, + "data_extra_pool": "meta-pool:test.buckets.non-ec", + "index_type": 5, + "inline_data": true + } + }, + { + "key": "slow", + "val": { + "index_pool": "slow-meta:test.slow.index", + "storage_classes": { + "STANDARD": { + "data_pool": "slow-data:test.slow.data" + } + }, + "data_extra_pool": "slow-non-ec:test.slow.data.non-ec", + "inline_data": true + } + } + ] +}`, + wantChanged: true, + wantErr: false, + }, + { + name: "if sharedPools not set and default placement is set, then default placements values are copied to 'default-placement'", + args: args{ + beforeJSON: `{ + "id": "f539c2c0-e1ed-4c42-9294-41742352eeae", + "name": "test", + "placement_pools": [ + { + "key": "default-placement", + "val": { + "index_pool": "test.rgw.buckets.index", + "storage_classes": { + "STANDARD": { + "data_pool": "test.rgw.buckets.data" + } + }, + "data_extra_pool": "test.rgw.buckets.non-ec", + "index_type": 5, + "inline_data": true + } + } + ] +}`, + spec: cephv1.ObjectSharedPoolsSpec{ + MetadataPoolName: "", + DataPoolName: "", + PreserveRadosNamespaceDataOnDelete: false, + PoolPlacements: []cephv1.PoolPlacementSpec{ + { + Name: "slow", + Default: true, + MetadataPoolName: "slow-meta", + DataPoolName: "slow-data", + DataNonECPoolName: "slow-non-ec", + StorageClasses: []cephv1.PlacementStorageClassSpec{}, + }, + }, + }, + }, + wantJSON: `{ + "id": "f539c2c0-e1ed-4c42-9294-41742352eeae", + "name": "test", + "placement_pools": [ + { + "key": "default-placement", + "val": { + "index_pool": "slow-meta:test.slow.index", + "storage_classes": { + "STANDARD": { + "data_pool": "slow-data:test.slow.data" + } + }, + "data_extra_pool": "slow-non-ec:test.slow.data.non-ec", + "index_type": 5, + "inline_data": true + } + }, + { + "key": "slow", + "val": { + "index_pool": "slow-meta:test.slow.index", + "storage_classes": { + "STANDARD": { + "data_pool": "slow-data:test.slow.data" + } + }, + "data_extra_pool": "slow-non-ec:test.slow.data.non-ec", + "inline_data": true + } + } + ] }`, wantChanged: true, wantErr: false, @@ -1418,8 +1641,9 @@ func Test_adjustZonePlacementPools(t *testing.T) { func Test_adjustZoneGroupPlacementTargets(t *testing.T) { type args struct { - zone string - groupBefore string + zone string + groupBefore string + defaultPlacement string } tests := []struct { name string @@ -1431,6 +1655,7 @@ func Test_adjustZoneGroupPlacementTargets(t *testing.T) { { name: "nothing changed", args: args{ + defaultPlacement: defaultPlacementCephConfigName, groupBefore: `{ "id": "610c9e3d-19e7-40b0-9f88-03319c4bc65a", "name": "test", @@ -1492,6 +1717,7 @@ func Test_adjustZoneGroupPlacementTargets(t *testing.T) { { name: "default changed", args: args{ + defaultPlacement: defaultPlacementCephConfigName, groupBefore: `{ "id": "610c9e3d-19e7-40b0-9f88-03319c4bc65a", "name": "test", @@ -1553,6 +1779,7 @@ func Test_adjustZoneGroupPlacementTargets(t *testing.T) { { name: "storage class added", args: args{ + defaultPlacement: defaultPlacementCephConfigName, groupBefore: `{ "id": "610c9e3d-19e7-40b0-9f88-03319c4bc65a", "name": "test", @@ -1617,6 +1844,7 @@ func Test_adjustZoneGroupPlacementTargets(t *testing.T) { { name: "placement added", args: args{ + defaultPlacement: defaultPlacementCephConfigName, groupBefore: `{ "id": "610c9e3d-19e7-40b0-9f88-03319c4bc65a", "name": "test", @@ -1697,6 +1925,7 @@ func Test_adjustZoneGroupPlacementTargets(t *testing.T) { { name: "placement and sc removed", args: args{ + defaultPlacement: defaultPlacementCephConfigName, groupBefore: `{ "id": "610c9e3d-19e7-40b0-9f88-03319c4bc65a", "name": "test", @@ -1769,7 +1998,7 @@ func Test_adjustZoneGroupPlacementTargets(t *testing.T) { srcGroup := map[string]interface{}{} err = json.Unmarshal([]byte(tt.args.groupBefore), &srcGroup) assert.NoError(t, err) - changedGroup, err := adjustZoneGroupPlacementTargets(srcGroup, zj) + changedGroup, err := adjustZoneGroupPlacementTargets(srcGroup, zj, tt.args.defaultPlacement) orig := map[string]interface{}{} jErr := json.Unmarshal([]byte(tt.args.groupBefore), &orig) @@ -1869,3 +2098,76 @@ func Test_createPlacementTargetsFromZonePoolPlacements(t *testing.T) { }) } } + +func Test_getDefaultPlacementName(t *testing.T) { + type args struct { + spec cephv1.ObjectSharedPoolsSpec + } + tests := []struct { + name string + args args + want string + }{ + { + name: "no default placement set in spec", + args: args{ + spec: cephv1.ObjectSharedPoolsSpec{ + PoolPlacements: []cephv1.PoolPlacementSpec{ + { + Name: "one", + Default: false, + }, + { + Name: "two", + Default: false, + }, + }, + }, + }, + want: defaultPlacementCephConfigName, + }, + { + name: "first placement set as defaultu in spec", + args: args{ + spec: cephv1.ObjectSharedPoolsSpec{ + PoolPlacements: []cephv1.PoolPlacementSpec{ + { + Name: "one", + Default: true, + }, + { + Name: "two", + Default: false, + }, + }, + }, + }, + want: "one", + }, + { + name: "second placement set as default in spec", + args: args{ + spec: cephv1.ObjectSharedPoolsSpec{ + PoolPlacements: []cephv1.PoolPlacementSpec{ + { + Name: "one", + Default: false, + }, + { + Name: "two", + Default: true, + }, + }, + }, + }, + want: "two", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := getDefaultPlacementName(tt.args.spec); got != tt.want { + t.Errorf("getDefaultPlacementName() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/operator/ceph/pool/controller.go b/pkg/operator/ceph/pool/controller.go index 015d59dea098..728184ace6ae 100644 --- a/pkg/operator/ceph/pool/controller.go +++ b/pkg/operator/ceph/pool/controller.go @@ -21,6 +21,7 @@ import ( "context" "fmt" "reflect" + "sort" "strings" "github.com/coreos/pkg/capnslog" @@ -76,6 +77,7 @@ type ReconcileCephBlockPool struct { blockPoolContexts map[string]*blockPoolHealth opManagerContext context.Context recorder record.EventRecorder + opConfig opcontroller.OperatorConfig } type blockPoolHealth struct { @@ -87,11 +89,11 @@ type blockPoolHealth struct { // Add creates a new CephBlockPool Controller and adds it to the Manager. The Manager will set fields on the Controller // and Start it when the Manager is Started. func Add(mgr manager.Manager, context *clusterd.Context, opManagerContext context.Context, opConfig opcontroller.OperatorConfig) error { - return add(opManagerContext, mgr, newReconciler(mgr, context, opManagerContext)) + return add(opManagerContext, mgr, newReconciler(mgr, context, opManagerContext, opConfig)) } // newReconciler returns a new reconcile.Reconciler -func newReconciler(mgr manager.Manager, context *clusterd.Context, opManagerContext context.Context) reconcile.Reconciler { +func newReconciler(mgr manager.Manager, context *clusterd.Context, opManagerContext context.Context, opConfig opcontroller.OperatorConfig) reconcile.Reconciler { return &ReconcileCephBlockPool{ client: mgr.GetClient(), scheme: mgr.GetScheme(), @@ -99,6 +101,7 @@ func newReconciler(mgr manager.Manager, context *clusterd.Context, opManagerCont blockPoolContexts: make(map[string]*blockPoolHealth), opManagerContext: opManagerContext, recorder: mgr.GetEventRecorderFor("rook-" + controllerName), + opConfig: opConfig, } } @@ -245,6 +248,12 @@ func (r *ReconcileCephBlockPool) reconcile(request reconcile.Request) (reconcile logger.Infof("deleting pool %q", poolSpec.Name) err = deletePool(r.context, clusterInfo, &poolSpec) if err != nil { + if opcontroller.ForceDeleteRequested(cephBlockPool.GetAnnotations()) { + cleanupErr := r.cleanup(cephBlockPool, &cephCluster) + if cleanupErr != nil { + return reconcile.Result{}, *cephBlockPool, errors.Wrapf(cleanupErr, "failed to create clean up job for ceph blockpool %q", cephBlockPool.Name) + } + } return opcontroller.ImmediateRetryResult, *cephBlockPool, errors.Wrapf(err, "failed to delete pool %q. ", cephBlockPool.Name) } @@ -297,7 +306,7 @@ func (r *ReconcileCephBlockPool) reconcile(request reconcile.Request) (reconcile if err := configureRBDStats(r.context, clusterInfo, ""); err != nil { return reconcile.Result{}, *cephBlockPool, errors.Wrap(err, "failed to enable/disable stats collection for pool(s)") } - checker := newMirrorChecker(r.context, r.client, r.clusterInfo, request.NamespacedName, &poolSpec) + checker := cephclient.NewMirrorChecker(r.context, r.client, r.clusterInfo, request.NamespacedName, &poolSpec, cephBlockPool) // ADD PEERS logger.Debug("reconciling create rbd mirror peer configuration") if cephBlockPool.Spec.Mirroring.Enabled { @@ -316,8 +325,8 @@ func (r *ReconcileCephBlockPool) reconcile(request reconcile.Request) (reconcile if r.blockPoolContexts[blockPoolChannelKey].started { logger.Debug("pool monitoring go routine already running!") } else { - go checker.checkMirroring(r.blockPoolContexts[blockPoolChannelKey].internalCtx) r.blockPoolContexts[blockPoolChannelKey].started = true + go checker.CheckMirroring(r.blockPoolContexts[blockPoolChannelKey].internalCtx) } } @@ -353,7 +362,7 @@ func (r *ReconcileCephBlockPool) reconcile(request reconcile.Request) (reconcile if blockPoolContextsExists && r.blockPoolContexts[blockPoolChannelKey].started { r.cancelMirrorMonitoring(cephBlockPool) // Reset the MirrorHealthCheckSpec - checker.updateStatusMirroring(nil, nil, nil, "") + checker.UpdateStatusMirroring(nil, nil, nil, "") } } @@ -373,6 +382,20 @@ func (r *ReconcileCephBlockPool) reconcileCreatePool(clusterInfo *cephclient.Clu return reconcile.Result{}, nil } +func (r *ReconcileCephBlockPool) cleanup(cephblockpool *cephv1.CephBlockPool, cephCluster *cephv1.CephCluster) error { + logger.Infof("starting cleanup of the ceph resources for CephBlockPool %q in k8s namespace %q", cephblockpool.Name, cephblockpool.Namespace) + cleanupConfig := map[string]string{ + opcontroller.CephBlockPoolNameEnv: cephblockpool.Name, + } + cleanup := opcontroller.NewResourceCleanup(cephblockpool, cephCluster, r.opConfig.Image, cleanupConfig) + jobName := k8sutil.TruncateNodeNameForJob("cleanup-cephblockpool-%s", cephblockpool.Name) + err := cleanup.StartJob(r.clusterInfo.Context, r.context.Clientset, jobName) + if err != nil { + return errors.Wrapf(err, "failed to run clean up job to clean the cephblockpool %q", cephblockpool.Name) + } + return nil +} + // Create the pool func createPool(context *clusterd.Context, clusterInfo *cephclient.ClusterInfo, clusterSpec *cephv1.ClusterSpec, p *cephv1.NamedPoolSpec) error { // Set the application name to rbd by default, but override later for special pools @@ -419,35 +442,50 @@ func deletePool(context *clusterd.Context, clusterInfo *cephclient.ClusterInfo, return nil } -// remove removes any element from a list -func remove(list []string, s string) []string { - for i, v := range list { - if v == s { - list = append(list[:i], list[i+1:]...) +// generateStatsPoolList combines existingStatsPools and rookStatsPools, removes items in removePools, +// removes duplicates, ensures no empty strings, and returns a comma-separated string in a deterministic order. +func generateStatsPoolList(existingStatsPools []string, rookStatsPools []string, removePools []string) string { + poolList := []string{} + + // Helper function to add a poolList if it's not in the removePools list and not already in poolList + addUniquePool := func(pool string) { + if pool == "" { + return } + // Check if the pool should be removed or already exists in poolList + if contains(removePools, pool) || contains(poolList, pool) { + return + } + poolList = append(poolList, pool) + } + for _, pool := range existingStatsPools { + addUniquePool(pool) } + for _, pool := range rookStatsPools { + addUniquePool(pool) + } + + sort.Strings(poolList) // Sort the list to ensure deterministic output - return list + return strings.Join(poolList, ",") } -// Remove duplicate entries from slice -func removeDuplicates(slice []string) []string { - inResult := make(map[string]bool) - var result []string - for _, str := range slice { - if _, ok := inResult[str]; !ok { - inResult[str] = true - result = append(result, str) +// Helper function to check if a slice contains a string +func contains(slice []string, item string) bool { + for _, s := range slice { + if s == item { + return true } } - return result + return false } func configureRBDStats(clusterContext *clusterd.Context, clusterInfo *cephclient.ClusterInfo, deletedPool string) error { logger.Debug("configuring RBD per-image IO statistics collection") namespaceListOpt := client.InNamespace(clusterInfo.Namespace) cephBlockPoolList := &cephv1.CephBlockPoolList{} - var enableStatsForCephBlockPools []string + var rookStatsPools []string + var removePools []string err := clusterContext.Client.List(clusterInfo.Context, cephBlockPoolList, namespaceListOpt) if err != nil { return errors.Wrap(err, "failed to retrieve list of CephBlockPool") @@ -455,28 +493,29 @@ func configureRBDStats(clusterContext *clusterd.Context, clusterInfo *cephclient for _, cephBlockPool := range cephBlockPoolList.Items { if cephBlockPool.GetDeletionTimestamp() == nil && cephBlockPool.Spec.EnableRBDStats { // add to list of CephBlockPool with enableRBDStats set to true and not marked for deletion - enableStatsForCephBlockPools = append(enableStatsForCephBlockPools, cephBlockPool.ToNamedPoolSpec().Name) + rookStatsPools = append(rookStatsPools, cephBlockPool.ToNamedPoolSpec().Name) + } else { + removePools = append(removePools, cephBlockPool.ToNamedPoolSpec().Name) } } - enableStatsForCephBlockPools = remove(enableStatsForCephBlockPools, deletedPool) + if deletedPool != "" { + removePools = append(removePools, deletedPool) + } monStore := config.GetMonStore(clusterContext, clusterInfo) // Check for existing rbd stats pools - existingRBDStatsPools, e := monStore.Get("mgr", "mgr/prometheus/rbd_stats_pools") + existingStatsPools, e := monStore.Get("mgr", "mgr/prometheus/rbd_stats_pools") if e != nil { return errors.Wrapf(e, "failed to get rbd_stats_pools") } - - existingRBDStatsPoolsList := strings.Split(existingRBDStatsPools, ",") - enableStatsForPools := append(enableStatsForCephBlockPools, existingRBDStatsPoolsList...) - enableStatsForPools = removeDuplicates(enableStatsForPools) - + existingStatsPoolsList := strings.Split(existingStatsPools, ",") + enableStatsForPools := generateStatsPoolList(existingStatsPoolsList, rookStatsPools, removePools) + logger.Infof("enableStatsForPools=%q ", enableStatsForPools) logger.Debugf("RBD per-image IO statistics will be collected for pools: %v", enableStatsForPools) - if len(enableStatsForPools) == 0 { err = monStore.Delete("mgr", "mgr/prometheus/rbd_stats_pools") } else { // appending existing rbd stats pools if any - err = monStore.Set("mgr", "mgr/prometheus/rbd_stats_pools", strings.Trim(strings.Join(enableStatsForPools, ","), ",")) + err = monStore.Set("mgr", "mgr/prometheus/rbd_stats_pools", enableStatsForPools) } if err != nil { return errors.Wrapf(err, "failed to enable rbd_stats_pools") diff --git a/pkg/operator/ceph/pool/controller_test.go b/pkg/operator/ceph/pool/controller_test.go index d444e92e4d7f..7804f277d61b 100644 --- a/pkg/operator/ceph/pool/controller_test.go +++ b/pkg/operator/ceph/pool/controller_test.go @@ -635,12 +635,14 @@ func TestConfigureRBDStats(t *testing.T) { logger.Infof("Command: %s %v", command, args) if args[0] == "config" && args[2] == "mgr" && args[3] == "mgr/prometheus/rbd_stats_pools" { if args[1] == "set" { + mockedPools = args[4] return "", nil } if args[1] == "get" { return mockedPools, nil } if args[1] == "rm" { + mockedPools = "" return "", nil } } @@ -701,7 +703,6 @@ func TestConfigureRBDStats(t *testing.T) { monStore := config.GetMonStore(context, clusterInfo) e := monStore.Set("mgr", "mgr/prometheus/rbd_stats_pools", "pool1,pool2") assert.Nil(t, e) - mockedPools = "my-pool-with-rbd-stats,pool1,pool2" e = configureRBDStats(context, clusterInfo, "") assert.Nil(t, e) @@ -710,7 +711,6 @@ func TestConfigureRBDStats(t *testing.T) { assert.Equal(t, "my-pool-with-rbd-stats,pool1,pool2", rbdStatsPools) // Case 6: Deleted CephBlockPool should be excluded from config - mockedPools = "pool1,pool2" err = configureRBDStats(context, clusterInfo, "my-pool-with-rbd-stats") assert.Nil(t, err) @@ -726,7 +726,7 @@ func TestConfigureRBDStats(t *testing.T) { rbdStatsPools, err = monStore.Get("mgr", "mgr/prometheus/rbd_stats_pools") assert.Nil(t, err) - assert.Equal(t, "pool1,pool2", rbdStatsPools) + assert.Equal(t, "my-pool-with-rbd-stats,pool1,pool2", rbdStatsPools) // Case 8: Two CephBlockPools with EnableRBDStats:false & EnableRBDStats:true. // SetConfig returns an error @@ -738,5 +738,111 @@ func TestConfigureRBDStats(t *testing.T) { } err = configureRBDStats(context, clusterInfo, "") assert.NotNil(t, err) +} + +func TestGenerateStatsPoolList(t *testing.T) { + tests := []struct { + name string + existingStatsPools []string + rookStatsPools []string + removePools []string + expectedOutput string + }{ + // Basic cases + { + name: "Empty lists", + existingStatsPools: []string{}, + rookStatsPools: []string{}, + removePools: []string{}, + expectedOutput: "", + }, + { + name: "Single-item lists, no removal", + existingStatsPools: []string{"p1"}, + rookStatsPools: []string{"p2"}, + removePools: []string{}, + expectedOutput: "p1,p2", + }, + // Overlap and duplicates + { + name: "Overlapping pools, some to remove", + existingStatsPools: []string{"p1", "p2", "p3"}, + rookStatsPools: []string{"p2", "p4", "p5"}, + removePools: []string{"p1", "p5"}, + expectedOutput: "p2,p3,p4", + }, + { + name: "Non-overlapping lists", + existingStatsPools: []string{"p1", "p2"}, + rookStatsPools: []string{"p3", "p4"}, + removePools: []string{}, + expectedOutput: "p1,p2,p3,p4", + }, + // All pools removed + { + name: "All pools removed", + existingStatsPools: []string{"p1", "p2"}, + rookStatsPools: []string{"p2", "p3"}, + removePools: []string{"p1", "p2", "p3"}, + expectedOutput: "", + }, + // Mixed scenarios with edge cases + { + name: "Only removed pools", + existingStatsPools: []string{"p1", "p2"}, + rookStatsPools: []string{"p2", "p3"}, + removePools: []string{"p1", "p2", "p3", "p4"}, + expectedOutput: "", + }, + { + name: "Duplicate pools across lists", + existingStatsPools: []string{"p1", "p2", "p1"}, + rookStatsPools: []string{"p2", "p3", "p3"}, + removePools: []string{}, + expectedOutput: "p1,p2,p3", + }, + { + name: "Empty string in pools", + existingStatsPools: []string{"p1", ""}, + rookStatsPools: []string{"p2", ""}, + removePools: []string{""}, + expectedOutput: "p1,p2", + }, + { + name: "Empty string in remove pools", + existingStatsPools: []string{"p1", "p2"}, + rookStatsPools: []string{"p3", "p4"}, + removePools: []string{""}, + expectedOutput: "p1,p2,p3,p4", + }, + { + name: "All lists empty strings", + existingStatsPools: []string{""}, + rookStatsPools: []string{""}, + removePools: []string{""}, + expectedOutput: "", + }, + // Larger cases + { + name: "Large unique pool list", + existingStatsPools: []string{"p1", "p2", "p3", "p4"}, + rookStatsPools: []string{"p5", "p6", "p7", "p8"}, + removePools: []string{"p1", "p8"}, + expectedOutput: "p2,p3,p4,p5,p6,p7", + }, + { + name: "Large list with many duplicates", + existingStatsPools: []string{"p1", "p2", "p3", "p2", "p1"}, + rookStatsPools: []string{"p2", "p3", "p3", "p4", "p1"}, + removePools: []string{"p4"}, + expectedOutput: "p1,p2,p3", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := generateStatsPoolList(tt.existingStatsPools, tt.rookStatsPools, tt.removePools) + assert.Equal(t, tt.expectedOutput, result) + }) + } } diff --git a/pkg/operator/ceph/pool/health.go b/pkg/operator/ceph/pool/health.go deleted file mode 100644 index 90731bf913e9..000000000000 --- a/pkg/operator/ceph/pool/health.go +++ /dev/null @@ -1,117 +0,0 @@ -/* -Copyright 2020 The Rook Authors. 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. -*/ - -package pool - -import ( - "context" - "time" - - cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1" - "github.com/rook/rook/pkg/clusterd" - cephclient "github.com/rook/rook/pkg/daemon/ceph/client" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -var ( - defaultHealthCheckInterval = 1 * time.Minute -) - -type mirrorChecker struct { - context *clusterd.Context - interval *time.Duration - client client.Client - clusterInfo *cephclient.ClusterInfo - namespacedName types.NamespacedName - poolSpec *cephv1.NamedPoolSpec -} - -// newMirrorChecker creates a new HealthChecker object -func newMirrorChecker(context *clusterd.Context, client client.Client, clusterInfo *cephclient.ClusterInfo, namespacedName types.NamespacedName, poolSpec *cephv1.NamedPoolSpec) *mirrorChecker { - c := &mirrorChecker{ - context: context, - interval: &defaultHealthCheckInterval, - clusterInfo: clusterInfo, - namespacedName: namespacedName, - client: client, - poolSpec: poolSpec, - } - - // allow overriding the check interval - checkInterval := poolSpec.StatusCheck.Mirror.Interval - if checkInterval != nil { - logger.Infof("pool mirroring status check interval for block pool %q is %q", namespacedName.Name, checkInterval.Duration.String()) - c.interval = &checkInterval.Duration - } - - return c -} - -// checkMirroring periodically checks the health of the cluster -func (c *mirrorChecker) checkMirroring(context context.Context) { - // check the mirroring health immediately before starting the loop - err := c.checkMirroringHealth() - if err != nil { - c.updateStatusMirroring(nil, nil, nil, err.Error()) - logger.Debugf("failed to check pool mirroring status for ceph block pool %q. %v", c.namespacedName.Name, err) - } - - for { - select { - case <-context.Done(): - logger.Infof("stopping monitoring pool mirroring status %q", c.namespacedName.Name) - return - - case <-time.After(*c.interval): - logger.Debugf("checking pool mirroring status %q", c.namespacedName.Name) - err := c.checkMirroringHealth() - if err != nil { - c.updateStatusMirroring(nil, nil, nil, err.Error()) - logger.Debugf("failed to check pool mirroring status for ceph block pool %q. %v", c.namespacedName.Name, err) - } - } - } -} - -func (c *mirrorChecker) checkMirroringHealth() error { - // Check mirroring status - mirrorStatus, err := cephclient.GetPoolMirroringStatus(c.context, c.clusterInfo, c.poolSpec.Name) - if err != nil { - c.updateStatusMirroring(nil, nil, nil, err.Error()) - } - - // Check mirroring info - mirrorInfo, err := cephclient.GetPoolMirroringInfo(c.context, c.clusterInfo, c.poolSpec.Name) - if err != nil { - c.updateStatusMirroring(nil, nil, nil, err.Error()) - } - - // If snapshot scheduling is enabled let's add it to the status - // snapSchedStatus := cephclient.SnapshotScheduleStatus{} - snapSchedStatus := []cephv1.SnapshotSchedulesSpec{} - if c.poolSpec.Mirroring.SnapshotSchedulesEnabled() { - snapSchedStatus, err = cephclient.ListSnapshotSchedulesRecursively(c.context, c.clusterInfo, c.poolSpec.Name) - if err != nil { - c.updateStatusMirroring(nil, nil, nil, err.Error()) - } - } - - // On success - c.updateStatusMirroring(mirrorStatus.Summary, mirrorInfo, snapSchedStatus, "") - - return nil -} diff --git a/pkg/operator/ceph/pool/radosnamespace/controller.go b/pkg/operator/ceph/pool/radosnamespace/controller.go index 7bae0b595ba9..f013db3102e7 100644 --- a/pkg/operator/ceph/pool/radosnamespace/controller.go +++ b/pkg/operator/ceph/pool/radosnamespace/controller.go @@ -67,12 +67,19 @@ var controllerTypeMeta = metav1.TypeMeta{ // ReconcileCephBlockPoolRadosNamespace reconciles a CephBlockPoolRadosNamespace object type ReconcileCephBlockPoolRadosNamespace struct { - client client.Client - scheme *runtime.Scheme - context *clusterd.Context - clusterInfo *cephclient.ClusterInfo - opManagerContext context.Context - opConfig opcontroller.OperatorConfig + client client.Client + scheme *runtime.Scheme + context *clusterd.Context + clusterInfo *cephclient.ClusterInfo + radosNamespaceContexts map[string]*mirrorHealth + opManagerContext context.Context + opConfig opcontroller.OperatorConfig +} + +type mirrorHealth struct { + internalCtx context.Context + internalCancel context.CancelFunc + started bool } // Add creates a new CephBlockPoolRadosNamespace Controller and adds it to the @@ -85,11 +92,12 @@ func Add(mgr manager.Manager, context *clusterd.Context, opManagerContext contex // newReconciler returns a new reconcile.Reconciler func newReconciler(mgr manager.Manager, context *clusterd.Context, opManagerContext context.Context, opConfig opcontroller.OperatorConfig) reconcile.Reconciler { return &ReconcileCephBlockPoolRadosNamespace{ - client: mgr.GetClient(), - scheme: mgr.GetScheme(), - context: context, - opManagerContext: opManagerContext, - opConfig: opConfig, + client: mgr.GetClient(), + scheme: mgr.GetScheme(), + context: context, + radosNamespaceContexts: make(map[string]*mirrorHealth), + opManagerContext: opManagerContext, + opConfig: opConfig, } } @@ -155,6 +163,8 @@ func (r *ReconcileCephBlockPoolRadosNamespace) reconcile(request reconcile.Reque r.updateStatus(r.client, request.NamespacedName, cephv1.ConditionProgressing) } + poolAndRadosNamespaceName := fmt.Sprintf("%s/%s", cephBlockPoolRadosNamespace.Spec.BlockPoolName, getRadosNamespaceName(cephBlockPoolRadosNamespace)) + // Make sure a CephCluster is present otherwise do nothing cephCluster, isReadyToReconcile, cephClusterExists, reconcileResponse := opcontroller.IsReadyToReconcile(r.opManagerContext, r.client, request.NamespacedName, controllerName) if !isReadyToReconcile { @@ -165,6 +175,8 @@ func (r *ReconcileCephBlockPoolRadosNamespace) reconcile(request reconcile.Reque // If not, we should wait for it to be ready // This handles the case where the operator is not ready to accept Ceph command but the cluster exists if !cephBlockPoolRadosNamespace.GetDeletionTimestamp().IsZero() && !cephClusterExists { + // don't leak the health checker routine if we are force-deleting + r.cancelMirrorMonitoring(radosNamespaceChannelKeyName(cephBlockPoolRadosNamespace.Namespace, poolAndRadosNamespaceName)) // Remove finalizer err = opcontroller.RemoveFinalizer(r.opManagerContext, r.client, cephBlockPoolRadosNamespace) if err != nil { @@ -219,6 +231,9 @@ func (r *ReconcileCephBlockPoolRadosNamespace) reconcile(request reconcile.Reque } return reconcile.Result{}, errors.Wrapf(err, "failed to delete ceph blockpool rados namespace %q", cephBlockPoolRadosNamespace.Name) } + // If the ceph block pool is still in the map, we must remove it during CR deletion + // We must remove it first otherwise the checker will panic since the status/info will be nil + r.cancelMirrorMonitoring(radosNamespaceChannelKeyName(cephBlockPoolRadosNamespace.Namespace, poolAndRadosNamespaceName)) } err = csi.SaveClusterConfig(r.context.Clientset, buildClusterID(cephBlockPoolRadosNamespace), cephCluster.Namespace, r.clusterInfo, nil) if err != nil { @@ -326,14 +341,7 @@ func (r *ReconcileCephBlockPoolRadosNamespace) updateClusterConfig(cephBlockPool }, } - if cephCluster.Spec.Network.IsMultus() { - // Build the network namespace config to be injected into the csi config - netNamespaceFilePath, err := csi.GenerateNetNamespaceFilePath(r.opManagerContext, r.client, cephCluster.Namespace, r.opConfig.OperatorNamespace, csi.RBDDriverShortName) - if err != nil { - return errors.Wrap(err, "failed to generate rbd net namespace file path") - } - csiClusterConfigEntry.RBD.NetNamespaceFilePath = netNamespaceFilePath - } + csiClusterConfigEntry.RBD.NetNamespaceFilePath = "" // Save cluster config in the csi config map err := csi.SaveClusterConfig(r.context.Clientset, buildClusterID(cephBlockPoolRadosNamespace), cephCluster.Namespace, r.clusterInfo, &csiClusterConfigEntry) @@ -425,6 +433,23 @@ func (r *ReconcileCephBlockPoolRadosNamespace) reconcileMirroring(cephBlockPoolR return errors.Wrapf(err, "failed to get mirroring info for the radosnamespace %q", poolAndRadosNamespaceName) } + // Initialize the channel for radosNamespace + // This allows us to track multiple radosNamespace in the same namespace + radosNamespaceChannelKey := radosNamespaceChannelKeyName(cephBlockPool.Namespace, poolAndRadosNamespaceName) + _, radosNamespaceContextsExists := r.radosNamespaceContexts[radosNamespaceChannelKey] + if !radosNamespaceContextsExists { + internalCtx, internalCancel := context.WithCancel(r.opManagerContext) + r.radosNamespaceContexts[radosNamespaceChannelKey] = &mirrorHealth{ + internalCtx: internalCtx, + internalCancel: internalCancel, + } + } + monitoringSpec := cephv1.NamedPoolSpec{ + Name: poolAndRadosNamespaceName, // use the name of the blockpool/radosNamespace + PoolSpec: cephBlockPool.Spec.PoolSpec, + } + checker := cephclient.NewMirrorChecker(r.context, r.client, r.clusterInfo, types.NamespacedName{Name: cephBlockPoolRadosNamespace.Name, Namespace: cephBlockPoolRadosNamespace.Namespace}, &monitoringSpec, cephBlockPoolRadosNamespace) + if cephBlockPoolRadosNamespace.Spec.Mirroring != nil { mirroringDisabled := checkBlockPoolMirroring(cephBlockPool) if mirroringDisabled { @@ -441,6 +466,19 @@ func (r *ReconcileCephBlockPoolRadosNamespace) reconcileMirroring(cephBlockPoolR if err != nil { return errors.Wrapf(err, "failed to enable snapshot scheduling for rbd rados namespace %q", poolAndRadosNamespaceName) } + + // Run the goroutine to update the mirroring status + // use the monitoring settings from the cephBlockPool CR + if !cephBlockPool.Spec.StatusCheck.Mirror.Disabled { + logger.Debugf("starting mirror monitoring for radosnamespace %q", poolAndRadosNamespaceName) + // Start monitoring of the radosNamespace + if r.radosNamespaceContexts[radosNamespaceChannelKey].started { + logger.Debug("radosnamespace monitoring go routine already running!") + } else { + r.radosNamespaceContexts[radosNamespaceChannelKey].started = true + go checker.CheckMirroring(r.radosNamespaceContexts[radosNamespaceChannelKey].internalCtx) + } + } } if cephBlockPoolRadosNamespace.Spec.Mirroring == nil && mirrorInfo.Mode != "disabled" { @@ -460,5 +498,31 @@ func (r *ReconcileCephBlockPoolRadosNamespace) reconcileMirroring(cephBlockPoolR return errors.Wrap(err, "failed to disable rbd rados namespace mirroring") } } + + if cephBlockPool.Spec.StatusCheck.Mirror.Disabled { + // Stop monitoring the mirroring status of this radosNamespace + if radosNamespaceContextsExists && r.radosNamespaceContexts[radosNamespaceChannelKey].started { + r.cancelMirrorMonitoring(radosNamespaceChannelKey) + // Reset the MirrorHealthCheckSpec + checker.UpdateStatusMirroring(nil, nil, nil, "") + } + } + return nil } + +func radosNamespaceChannelKeyName(poolAndRadosNamespaceName, namespace string) string { + return types.NamespacedName{Namespace: namespace, Name: poolAndRadosNamespaceName}.String() +} + +// cancel mirror monitoring. This is a noop if monitoring is not running. +func (r *ReconcileCephBlockPoolRadosNamespace) cancelMirrorMonitoring(channelKey string) { + _, poolContextExists := r.radosNamespaceContexts[channelKey] + if poolContextExists { + // Cancel the context to stop the go routine + r.radosNamespaceContexts[channelKey].internalCancel() + + // Remove ceph radosNamespace from the map + delete(r.radosNamespaceContexts, channelKey) + } +} diff --git a/pkg/operator/ceph/pool/radosnamespace/controller_test.go b/pkg/operator/ceph/pool/radosnamespace/controller_test.go index 1446c94a56f5..d940c3497ffb 100644 --- a/pkg/operator/ceph/pool/radosnamespace/controller_test.go +++ b/pkg/operator/ceph/pool/radosnamespace/controller_test.go @@ -167,7 +167,7 @@ func TestCephBlockPoolRadosNamespaceController(t *testing.T) { Phase: "", }, } - + cephBlockPool.Spec.StatusCheck.Mirror.Disabled = true t.Run("error - ceph blockpool not ready", func(t *testing.T) { res, err := r.Reconcile(ctx, req) assert.NoError(t, err) @@ -218,11 +218,12 @@ func TestCephBlockPoolRadosNamespaceController(t *testing.T) { s.AddKnownTypes(cephv1.SchemeGroupVersion, &cephv1.CephBlockPoolList{}) // Create a ReconcileCephBlockPoolRadosNamespace object with the scheme and fake client. r = &ReconcileCephBlockPoolRadosNamespace{ - client: cl, - scheme: s, - context: c, - opManagerContext: context.TODO(), - opConfig: opcontroller.OperatorConfig{Image: "ceph/ceph:v14.2.9"}, + client: cl, + scheme: s, + context: c, + opManagerContext: context.TODO(), + opConfig: opcontroller.OperatorConfig{Image: "ceph/ceph:v14.2.9"}, + radosNamespaceContexts: make(map[string]*mirrorHealth), } detectCephVersion = func(ctx context.Context, rookImage, namespace, jobName string, ownerInfo *k8sutil.OwnerInfo, clientset kubernetes.Interface, cephClusterSpec *cephv1.ClusterSpec) (*cephver.CephVersion, error) { return &version.Reef, nil @@ -337,11 +338,12 @@ func TestCephBlockPoolRadosNamespaceController(t *testing.T) { s.AddKnownTypes(cephv1.SchemeGroupVersion, &cephv1.CephBlockPoolList{}) // Create a ReconcileCephBlockPoolRadosNamespace object with the scheme and fake client. r = &ReconcileCephBlockPoolRadosNamespace{ - client: cl, - scheme: s, - context: c, - opManagerContext: context.TODO(), - opConfig: opcontroller.OperatorConfig{Image: "ceph/ceph:v14.2.9"}, + client: cl, + scheme: s, + context: c, + opManagerContext: context.TODO(), + opConfig: opcontroller.OperatorConfig{Image: "ceph/ceph:v14.2.9"}, + radosNamespaceContexts: make(map[string]*mirrorHealth), } detectCephVersion = func(ctx context.Context, rookImage, namespace, jobName string, ownerInfo *k8sutil.OwnerInfo, clientset kubernetes.Interface, cephClusterSpec *cephv1.ClusterSpec) (*cephver.CephVersion, error) { return &version.Reef, nil @@ -385,11 +387,12 @@ func TestCephBlockPoolRadosNamespaceController(t *testing.T) { s.AddKnownTypes(cephv1.SchemeGroupVersion, &cephv1.CephBlockPoolList{}) // Create a ReconcileCephBlockPoolRadosNamespace object with the scheme and fake client. r = &ReconcileCephBlockPoolRadosNamespace{ - client: cl, - scheme: s, - context: c, - opManagerContext: context.TODO(), - opConfig: opcontroller.OperatorConfig{Image: "ceph/ceph:v14.2.9"}, + client: cl, + scheme: s, + context: c, + opManagerContext: context.TODO(), + opConfig: opcontroller.OperatorConfig{Image: "ceph/ceph:v14.2.9"}, + radosNamespaceContexts: make(map[string]*mirrorHealth), } detectCephVersion = func(ctx context.Context, rookImage, namespace, jobName string, ownerInfo *k8sutil.OwnerInfo, clientset kubernetes.Interface, cephClusterSpec *cephv1.ClusterSpec) (*cephver.CephVersion, error) { return &version.Reef, nil @@ -436,11 +439,12 @@ func TestCephBlockPoolRadosNamespaceController(t *testing.T) { s.AddKnownTypes(cephv1.SchemeGroupVersion, &cephv1.CephBlockPoolList{}) // Create a ReconcileCephBlockPoolRadosNamespace object with the scheme and fake client. r = &ReconcileCephBlockPoolRadosNamespace{ - client: cl, - scheme: s, - context: c, - opManagerContext: context.TODO(), - opConfig: opcontroller.OperatorConfig{Image: "ceph/ceph:v14.2.9"}, + client: cl, + scheme: s, + context: c, + opManagerContext: context.TODO(), + opConfig: opcontroller.OperatorConfig{Image: "ceph/ceph:v14.2.9"}, + radosNamespaceContexts: make(map[string]*mirrorHealth), } detectCephVersion = func(ctx context.Context, rookImage, namespace, jobName string, ownerInfo *k8sutil.OwnerInfo, clientset kubernetes.Interface, cephClusterSpec *cephv1.ClusterSpec) (*cephver.CephVersion, error) { return &version.Reef, nil @@ -487,11 +491,12 @@ func TestCephBlockPoolRadosNamespaceController(t *testing.T) { s.AddKnownTypes(cephv1.SchemeGroupVersion, &cephv1.CephBlockPoolList{}) // Create a ReconcileCephBlockPoolRadosNamespace object with the scheme and fake client. r = &ReconcileCephBlockPoolRadosNamespace{ - client: cl, - scheme: s, - context: c, - opManagerContext: context.TODO(), - opConfig: opcontroller.OperatorConfig{Image: "ceph/ceph:v14.2.9"}, + client: cl, + scheme: s, + context: c, + opManagerContext: context.TODO(), + opConfig: opcontroller.OperatorConfig{Image: "ceph/ceph:v14.2.9"}, + radosNamespaceContexts: make(map[string]*mirrorHealth), } detectCephVersion = func(ctx context.Context, rookImage, namespace, jobName string, ownerInfo *k8sutil.OwnerInfo, clientset kubernetes.Interface, cephClusterSpec *cephv1.ClusterSpec) (*cephver.CephVersion, error) { return &cephver.CephVersion{Major: 20, Minor: 0, Extra: 0}, nil @@ -541,11 +546,12 @@ func TestCephBlockPoolRadosNamespaceController(t *testing.T) { s.AddKnownTypes(cephv1.SchemeGroupVersion, &cephv1.CephBlockPoolList{}) // Create a ReconcileCephBlockPoolRadosNamespace object with the scheme and fake client. r = &ReconcileCephBlockPoolRadosNamespace{ - client: cl, - scheme: s, - context: c, - opManagerContext: context.TODO(), - opConfig: opcontroller.OperatorConfig{Image: "ceph/ceph:v14.2.9"}, + client: cl, + scheme: s, + context: c, + opManagerContext: context.TODO(), + opConfig: opcontroller.OperatorConfig{Image: "ceph/ceph:v14.2.9"}, + radosNamespaceContexts: make(map[string]*mirrorHealth), } detectCephVersion = func(ctx context.Context, rookImage, namespace, jobName string, ownerInfo *k8sutil.OwnerInfo, clientset kubernetes.Interface, cephClusterSpec *cephv1.ClusterSpec) (*cephver.CephVersion, error) { return &cephver.CephVersion{Major: 20, Minor: 0, Extra: 0}, nil @@ -599,11 +605,12 @@ func TestCephBlockPoolRadosNamespaceController(t *testing.T) { s.AddKnownTypes(cephv1.SchemeGroupVersion, &cephv1.CephBlockPoolList{}) // Create a ReconcileCephBlockPoolRadosNamespace object with the scheme and fake client. r = &ReconcileCephBlockPoolRadosNamespace{ - client: cl, - scheme: s, - context: c, - opManagerContext: context.TODO(), - opConfig: opcontroller.OperatorConfig{Image: "ceph/ceph:v14.2.9"}, + client: cl, + scheme: s, + context: c, + opManagerContext: context.TODO(), + opConfig: opcontroller.OperatorConfig{Image: "ceph/ceph:v14.2.9"}, + radosNamespaceContexts: make(map[string]*mirrorHealth), } detectCephVersion = func(ctx context.Context, rookImage, namespace, jobName string, ownerInfo *k8sutil.OwnerInfo, clientset kubernetes.Interface, cephClusterSpec *cephv1.ClusterSpec) (*cephver.CephVersion, error) { return &version.Reef, nil diff --git a/pkg/operator/ceph/pool/status.go b/pkg/operator/ceph/pool/status.go index e9de744fd79c..666efd5d11ac 100644 --- a/pkg/operator/ceph/pool/status.go +++ b/pkg/operator/ceph/pool/status.go @@ -19,7 +19,6 @@ package pool import ( "context" - "time" cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1" opcontroller "github.com/rook/rook/pkg/operator/ceph/controller" @@ -59,79 +58,6 @@ func updateStatus(ctx context.Context, client client.Client, poolName types.Name logger.Debugf("pool %q status updated to %q", poolName, status) } -// updateStatusBucket updates an object with a given status -func (c *mirrorChecker) updateStatusMirroring(mirrorStatus *cephv1.PoolMirroringStatusSummarySpec, mirrorInfo *cephv1.PoolMirroringInfo, snapSchedStatus []cephv1.SnapshotSchedulesSpec, details string) { - blockPool := &cephv1.CephBlockPool{} - if err := c.client.Get(c.clusterInfo.Context, c.namespacedName, blockPool); err != nil { - if kerrors.IsNotFound(err) { - logger.Debug("CephBlockPool resource not found. Ignoring since object must be deleted.") - return - } - logger.Warningf("failed to retrieve ceph block pool %q to update mirroring status. %v", c.namespacedName.Name, err) - return - } - if blockPool.Status == nil { - blockPool.Status = &cephv1.CephBlockPoolStatus{} - } - - // Update the CephBlockPool CR status field - blockPool.Status.MirroringStatus, blockPool.Status.MirroringInfo, blockPool.Status.SnapshotScheduleStatus = toCustomResourceStatus(blockPool.Status.MirroringStatus, mirrorStatus, blockPool.Status.MirroringInfo, mirrorInfo, blockPool.Status.SnapshotScheduleStatus, snapSchedStatus, details) - if err := reporting.UpdateStatus(c.client, blockPool); err != nil { - logger.Errorf("failed to set ceph block pool %q mirroring status. %v", c.namespacedName.Name, err) - return - } - - logger.Debugf("ceph block pool %q mirroring status updated", c.namespacedName.Name) -} - -func toCustomResourceStatus(currentStatus *cephv1.MirroringStatusSpec, mirroringStatus *cephv1.PoolMirroringStatusSummarySpec, - currentInfo *cephv1.MirroringInfoSpec, mirroringInfo *cephv1.PoolMirroringInfo, - currentSnapSchedStatus *cephv1.SnapshotScheduleStatusSpec, snapSchedStatus []cephv1.SnapshotSchedulesSpec, - details string) (*cephv1.MirroringStatusSpec, *cephv1.MirroringInfoSpec, *cephv1.SnapshotScheduleStatusSpec) { - mirroringStatusSpec := &cephv1.MirroringStatusSpec{} - mirroringInfoSpec := &cephv1.MirroringInfoSpec{} - snapshotScheduleStatusSpec := &cephv1.SnapshotScheduleStatusSpec{} - - // mirroringStatus will be nil in case of an error to fetch it - if mirroringStatus != nil { - mirroringStatusSpec.LastChecked = time.Now().UTC().Format(time.RFC3339) - mirroringStatusSpec.Summary = mirroringStatus - } - - // Always display the details, typically an error - mirroringStatusSpec.Details = details - - if currentStatus != nil { - mirroringStatusSpec.LastChanged = currentStatus.LastChanged - } - - // mirroringInfo will be nil in case of an error to fetch it - if mirroringInfo != nil { - mirroringInfoSpec.LastChecked = time.Now().UTC().Format(time.RFC3339) - mirroringInfoSpec.PoolMirroringInfo = mirroringInfo - } - // Always display the details, typically an error - mirroringInfoSpec.Details = details - - if currentInfo != nil { - mirroringInfoSpec.LastChanged = currentInfo.LastChecked - } - - // snapSchedStatus will be nil in case of an error to fetch it - if len(snapSchedStatus) != 0 { - snapshotScheduleStatusSpec.LastChecked = time.Now().UTC().Format(time.RFC3339) - snapshotScheduleStatusSpec.SnapshotSchedules = snapSchedStatus - } - // Always display the details, typically an error - snapshotScheduleStatusSpec.Details = details - - if currentSnapSchedStatus != nil { - snapshotScheduleStatusSpec.LastChanged = currentSnapSchedStatus.LastChecked - } - - return mirroringStatusSpec, mirroringInfoSpec, snapshotScheduleStatusSpec -} - func updateStatusInfo(cephBlockPool *cephv1.CephBlockPool) { m := make(map[string]string) if cephBlockPool.Status.Phase == cephv1.ConditionReady && cephBlockPool.Spec.Mirroring.Enabled { diff --git a/pkg/operator/ceph/pool/status_test.go b/pkg/operator/ceph/pool/status_test.go index e34b58282aed..cdcba99e41ab 100644 --- a/pkg/operator/ceph/pool/status_test.go +++ b/pkg/operator/ceph/pool/status_test.go @@ -25,41 +25,6 @@ import ( "github.com/stretchr/testify/assert" ) -func TestToCustomResourceStatus(t *testing.T) { - mirroringStatus := &cephv1.PoolMirroringStatusSummarySpec{} - mirroringStatus.Health = "HEALTH_OK" - mirroringInfo := &cephv1.PoolMirroringInfo{ - Mode: "pool", - SiteName: "rook-ceph-emea", - Peers: []cephv1.PeersSpec{ - {UUID: "82656994-3314-4996-ac4c-263c2c9fd081"}, - }, - } - - // Test 1: Empty so it's disabled - { - newMirroringStatus, newMirroringInfo, _ := toCustomResourceStatus(&cephv1.MirroringStatusSpec{}, mirroringStatus, &cephv1.MirroringInfoSpec{}, mirroringInfo, &cephv1.SnapshotScheduleStatusSpec{}, []cephv1.SnapshotSchedulesSpec{}, "") - assert.NotEmpty(t, newMirroringStatus.Summary) - assert.Equal(t, "HEALTH_OK", newMirroringStatus.Summary.Health) - assert.Equal(t, "pool", newMirroringInfo.Mode) - } - - // Test 2: snap sched - { - snapSchedStatus := []cephv1.SnapshotSchedulesSpec{ - { - Pool: "my-pool", - Image: "pool/image", - }, - } - newMirroringStatus, newMirroringInfo, newSnapshotScheduleStatus := toCustomResourceStatus(&cephv1.MirroringStatusSpec{}, mirroringStatus, &cephv1.MirroringInfoSpec{}, mirroringInfo, &cephv1.SnapshotScheduleStatusSpec{}, snapSchedStatus, "") - assert.NotEmpty(t, newMirroringStatus.Summary) - assert.Equal(t, "HEALTH_OK", newMirroringStatus.Summary.Health) - assert.NotEmpty(t, newMirroringInfo.Mode, "pool") - assert.NotEmpty(t, newSnapshotScheduleStatus) - } -} - func TestUpdateStatusInfo(t *testing.T) { cephBlockPoolReplicated := &cephv1.CephBlockPool{ diff --git a/pkg/operator/k8sutil/cmdreporter/cmdreporter.go b/pkg/operator/k8sutil/cmdreporter/cmdreporter.go index 3de895d3a87a..6a5eea450125 100644 --- a/pkg/operator/k8sutil/cmdreporter/cmdreporter.go +++ b/pkg/operator/k8sutil/cmdreporter/cmdreporter.go @@ -80,6 +80,7 @@ type cmdReporterCfg struct { rookImage string runImage string imagePullPolicy v1.PullPolicy + resources cephv1.ResourceSpec } // New creates a new CmdReporter. @@ -101,6 +102,7 @@ func New( cmd, args []string, rookImage, runImage string, imagePullPolicy v1.PullPolicy, + resources cephv1.ResourceSpec, ) (CmdReporterInterface, error) { cfg := &cmdReporterCfg{ clientset: clientset, @@ -113,6 +115,7 @@ func New( rookImage: rookImage, runImage: runImage, imagePullPolicy: imagePullPolicy, + resources: resources, } // Validate contents of config struct, not inputs to function to catch any developer errors @@ -352,6 +355,7 @@ func (cr *cmdReporterCfg) initContainers() []v1.Container { }, Image: cr.rookImage, ImagePullPolicy: cr.imagePullPolicy, + Resources: cephv1.GetCmdReporterResources(cr.resources), } _, copyBinsMount := copyBinariesVolAndMount() c.VolumeMounts = []v1.VolumeMount{copyBinsMount} @@ -382,6 +386,7 @@ func (cr *cmdReporterCfg) container() (*v1.Container, error) { }, Image: cr.runImage, ImagePullPolicy: cr.imagePullPolicy, + Resources: cephv1.GetCmdReporterResources(cr.resources), } if cr.needToCopyBinaries() { _, copyBinsMount := copyBinariesVolAndMount() @@ -419,6 +424,7 @@ func MockCmdReporterJob( rookImage string, runImage string, imagePullPolicy v1.PullPolicy, + resources cephv1.ResourceSpec, ) (*batch.Job, error) { cfg := &cmdReporterCfg{ clientset: clientset, @@ -431,6 +437,7 @@ func MockCmdReporterJob( rookImage: rookImage, runImage: runImage, imagePullPolicy: imagePullPolicy, + resources: resources, } return cfg.initJobSpec() } diff --git a/pkg/operator/k8sutil/node.go b/pkg/operator/k8sutil/node.go index 0962c26929ad..2dcce962cd90 100644 --- a/pkg/operator/k8sutil/node.go +++ b/pkg/operator/k8sutil/node.go @@ -22,9 +22,10 @@ import ( "encoding/json" "errors" "fmt" - "sigs.k8s.io/yaml" "strings" + "sigs.k8s.io/yaml" + cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -37,7 +38,7 @@ import ( // validNodeNoSched returns true if the node (1) meets Rook's placement terms, // and (2) is ready. Unlike ValidNode, this method will ignore the // Node.Spec.Unschedulable flag. False otherwise. -func validNodeNoSched(node v1.Node, placement cephv1.Placement) error { +func validNodeNoSched(node v1.Node, placement cephv1.Placement, scheduleAlways bool) error { p, err := NodeMeetsPlacementTerms(node, placement, false) if err != nil { return fmt.Errorf("failed to check if node meets Rook placement terms. %+v", err) @@ -47,6 +48,10 @@ func validNodeNoSched(node v1.Node, placement cephv1.Placement) error { } if !NodeIsReady(node) { + if scheduleAlways { + logger.Infof("node %q is not ready but scheduleAlways set", node.Name) + return nil + } return errors.New("node is not ready") } @@ -55,12 +60,12 @@ func validNodeNoSched(node v1.Node, placement cephv1.Placement) error { // ValidNode returns true if the node (1) is schedulable, (2) meets Rook's placement terms, and // (3) is ready. False otherwise. -func ValidNode(node v1.Node, placement cephv1.Placement) error { - if !GetNodeSchedulable(node) { +func ValidNode(node v1.Node, placement cephv1.Placement, scheduleAlways bool) error { + if !GetNodeSchedulable(node, scheduleAlways) { return errors.New("node is unschedulable") } - return validNodeNoSched(node, placement) + return validNodeNoSched(node, placement, scheduleAlways) } // GetValidNodes returns all nodes that (1) are not cordoned, (2) meet Rook's placement terms, and @@ -76,7 +81,7 @@ func GetValidNodes(ctx context.Context, rookStorage cephv1.StorageScopeSpec, cli validK8sNodes := []v1.Node{} reasonsForSkippingNodes := map[string][]string{} for _, n := range matchingK8sNodes { - err := ValidNode(n, placement) + err := ValidNode(n, placement, rookStorage.ScheduleAlways) if err != nil { reason := err.Error() reasonsForSkippingNodes[reason] = append(reasonsForSkippingNodes[reason], n.Name) @@ -144,10 +149,15 @@ func GetNodeHostNames(ctx context.Context, clientset kubernetes.Interface) (map[ // GetNodeSchedulable returns a boolean if the node is tainted as Schedulable or not // true -> Node is schedulable // false -> Node is unschedulable -func GetNodeSchedulable(node v1.Node) bool { +func GetNodeSchedulable(node v1.Node, scheduleAlways bool) bool { // some unit tests set this to quickly emulate an unschedulable node; if this is set to true, // we can shortcut deeper inspection for schedulability. - return !node.Spec.Unschedulable + schedulable := !node.Spec.Unschedulable + if !schedulable && scheduleAlways { + logger.Infof("node %q is unschedulable but scheduling since scheduleAlways is set", node.Name) + return true + } + return schedulable } // NodeMeetsPlacementTerms returns true if the Rook placement allows the node to have resources scheduled diff --git a/pkg/operator/k8sutil/node_test.go b/pkg/operator/k8sutil/node_test.go index b92b3dd8c4f9..c3cff521dfb7 100644 --- a/pkg/operator/k8sutil/node_test.go +++ b/pkg/operator/k8sutil/node_test.go @@ -25,6 +25,7 @@ import ( cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1" optest "github.com/rook/rook/pkg/operator/test" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes/fake" @@ -74,8 +75,17 @@ func TestValidNode(t *testing.T) { t.Run("test valid node", func(t *testing.T) { var placement cephv1.Placement validNodes := GetValidNodes(context.TODO(), storage, clientset, placement) - assert.Equal(t, len(validNodes), 1) + assert.Equal(t, 1, len(validNodes)) + assert.Equal(t, "nodeA", validNodes[0].Name) + }) + + t.Run("test nodes always valid", func(t *testing.T) { + var placement cephv1.Placement + storage.ScheduleAlways = true + validNodes := GetValidNodes(context.TODO(), storage, clientset, placement) + require.Equal(t, 2, len(validNodes)) assert.Equal(t, "nodeA", validNodes[0].Name) + assert.Equal(t, "nodeB", validNodes[1].Name) }) t.Run("test placement", func(t *testing.T) { @@ -438,12 +448,12 @@ func TestGenerateNodeAffinity(t *testing.T) { name: "GenerateNodeAffinityWithYAMLInputUsingDoesNotExistOperator", args: args{ nodeAffinity: ` ---- -requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - - matchExpressions: - - +--- +requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - + matchExpressions: + - key: myKey operator: DoesNotExist`, }, @@ -467,15 +477,15 @@ requiredDuringSchedulingIgnoredDuringExecution: name: "GenerateNodeAffinityWithYAMLInputUsingNotInOperator", args: args{ nodeAffinity: ` ---- -requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - - matchExpressions: - - +--- +requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - + matchExpressions: + - key: myKey operator: NotIn - values: + values: - myValue`, }, want: &v1.NodeAffinity{ diff --git a/tests/framework/installer/ceph_installer.go b/tests/framework/installer/ceph_installer.go index a02757fcd83d..42adcebe7d2d 100644 --- a/tests/framework/installer/ceph_installer.go +++ b/tests/framework/installer/ceph_installer.go @@ -98,7 +98,8 @@ func ReturnCephVersion() cephv1.CephVersionSpec { case "squid-devel": return SquidDevelVersion default: - return SquidDevelVersion + // Default to the latest stable version + return SquidVersion } } @@ -265,7 +266,12 @@ func (h *CephInstaller) CreateCephCluster() error { } func (h *CephInstaller) waitForCluster() error { - if err := h.k8shelper.WaitForPodCount("app=rook-ceph-mon", h.settings.Namespace, h.settings.Mons); err != nil { + monWaitLabel := "app=rook-ceph-mon,mon_daemon=true" + if h.Manifests.Settings().RookVersion == Version1_14 { + // TODO: Remove this when upgrade test is from v1.15 since v1.14 does not have the mon_daemon label + monWaitLabel = "app=rook-ceph-mon" + } + if err := h.k8shelper.WaitForPodCount(monWaitLabel, h.settings.Namespace, h.settings.Mons); err != nil { return err } diff --git a/tests/framework/utils/k8s_helper.go b/tests/framework/utils/k8s_helper.go index efa2dba1a672..d7ebb81f33f1 100644 --- a/tests/framework/utils/k8s_helper.go +++ b/tests/framework/utils/k8s_helper.go @@ -341,6 +341,9 @@ func (k8sh *K8sHelper) WaitForPodCount(label, namespace string, count int) error if len(pods.Items) >= count { logger.Infof("found %d pods with label %s", count, label) + for _, pod := range pods.Items { + logger.Infof("pod found includes %q with status %q", pod.Name, pod.Status.Phase) + } return nil } diff --git a/tests/integration/ceph_base_object_test.go b/tests/integration/ceph_base_object_test.go index 6358935aa212..79521d1ec25c 100644 --- a/tests/integration/ceph_base_object_test.go +++ b/tests/integration/ceph_base_object_test.go @@ -238,8 +238,7 @@ func assertObjectStoreDeletion(t *testing.T, k8sh *utils.K8sHelper, namespace, s func createCephObjectUser( s *suite.Suite, helper *clients.TestClient, k8sh *utils.K8sHelper, - namespace, storeName, userID string, - checkPhase, checkQuotaAndCaps bool) { + namespace, storeName, userID string, checkQuotaAndCaps bool) { maxObjectInt, err := strconv.Atoi(maxObject) assert.Nil(s.T(), err) @@ -254,14 +253,13 @@ func createCephObjectUser( time.Sleep(5 * time.Second) } - checkCephObjectUser(s, helper, k8sh, namespace, storeName, userID, checkPhase, checkQuotaAndCaps) + checkCephObjectUser(s, helper, k8sh, namespace, storeName, userID, checkQuotaAndCaps) } func checkCephObjectUser( s *suite.Suite, helper *clients.TestClient, k8sh *utils.K8sHelper, - namespace, storeName, userID string, - checkPhase, checkQuotaAndCaps bool, -) { + namespace, storeName, userID string, checkQuotaAndCaps bool) { + logger.Infof("checking object store \"%s/%s\" user %q", namespace, storeName, userID) assert.True(s.T(), helper.ObjectUserClient.UserSecretExists(namespace, storeName, userID)) @@ -270,23 +268,9 @@ func checkCephObjectUser( assert.Equal(s.T(), userID, userInfo.UserID) assert.Equal(s.T(), userdisplayname, *userInfo.DisplayName) - if checkPhase { - // status.phase doesn't exist before Rook v1.6 - phase, err := k8sh.GetResource("--namespace", namespace, "cephobjectstoreuser", userID, "--output", "jsonpath={.status.phase}") - assert.NoError(s.T(), err) - assert.Equal(s.T(), k8sutil.ReadyStatus, phase) - } - if checkQuotaAndCaps { - // following fields in CephObjectStoreUser CRD doesn't exist before Rook v1.7.3 - maxObjectInt, err := strconv.Atoi(maxObject) - assert.Nil(s.T(), err) - maxSizeInt, err := strconv.Atoi(maxSize) - assert.Nil(s.T(), err) - assert.Equal(s.T(), maxBucket, userInfo.MaxBuckets) - assert.Equal(s.T(), int64(maxObjectInt), *userInfo.UserQuota.MaxObjects) - assert.Equal(s.T(), int64(maxSizeInt), *userInfo.UserQuota.MaxSize) - assert.Equal(s.T(), userCap, userInfo.Caps[0].Perm) - } + phase, err := k8sh.GetResource("--namespace", namespace, "cephobjectstoreuser", userID, "--output", "jsonpath={.status.phase}") + assert.NoError(s.T(), err) + assert.Equal(s.T(), k8sutil.ReadyStatus, phase) } func objectStoreCleanUp(s *suite.Suite, helper *clients.TestClient, k8sh *utils.K8sHelper, namespace, storeName string) { diff --git a/tests/integration/ceph_object_test.go b/tests/integration/ceph_object_test.go index d51dd59b4be5..3763a3c1e20a 100644 --- a/tests/integration/ceph_object_test.go +++ b/tests/integration/ceph_object_test.go @@ -19,10 +19,11 @@ package integration import ( "context" "encoding/json" - "k8s.io/apimachinery/pkg/api/errors" + "strings" "testing" "time" + "github.com/kube-object-storage/lib-bucket-provisioner/pkg/apis/objectbucket.io/v1alpha1" cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1" "github.com/rook/rook/pkg/daemon/ceph/client" rgw "github.com/rook/rook/pkg/operator/ceph/object" @@ -32,6 +33,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -165,7 +167,7 @@ func testObjectStoreOperations(s *suite.Suite, helper *clients.TestClient, k8sh logger.Infof("Testing Object Operations on %s", storeName) t.Run("create CephObjectStoreUser", func(t *testing.T) { - createCephObjectUser(s, helper, k8sh, namespace, storeName, userid, true, true) + createCephObjectUser(s, helper, k8sh, namespace, storeName, userid, true) i := 0 for i = 0; i < 4; i++ { if helper.ObjectUserClient.UserSecretExists(namespace, storeName, userid) { @@ -236,7 +238,7 @@ func testObjectStoreOperations(s *suite.Suite, helper *clients.TestClient, k8sh assert.Equal(t, ObjBody, read) }) - t.Run("quota enforcement", func(t *testing.T) { + t.Run("user quota enforcement", func(t *testing.T) { _, poErr := s3client.PutObjectInBucket(bucketname, ObjBody, ObjectKey2, contentType) assert.Nil(t, poErr) logger.Infof("Testing the max object limit") @@ -244,7 +246,7 @@ func testObjectStoreOperations(s *suite.Suite, helper *clients.TestClient, k8sh assert.Error(t, poErr) }) - t.Run("update quota limits", func(t *testing.T) { + t.Run("update user quota limits", func(t *testing.T) { poErr := helper.BucketClient.UpdateObc(obcName, bucketStorageClassName, bucketname, newMaxObject, true) assert.Nil(t, poErr) updated := utils.Retry(20, 2*time.Second, "OBC is updated", func() bool { @@ -269,6 +271,161 @@ func testObjectStoreOperations(s *suite.Suite, helper *clients.TestClient, k8sh }) }) + // this test deviates from the others in this package in that it does not + // rely on kubectl and uses the k8s api directly + t.Run("OBC bucket quota enforcement", func(t *testing.T) { + bucketName := "bucket-quota-test" + var obName string + var s3client *rgw.S3Agent + + t.Run("create obc with bucketMaxObjects", func(t *testing.T) { + newObc := v1alpha1.ObjectBucketClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: bucketName, + Namespace: namespace, + }, + Spec: v1alpha1.ObjectBucketClaimSpec{ + BucketName: bucketName, + StorageClassName: bucketStorageClassName, + AdditionalConfig: map[string]string{ + "bucketMaxObjects": "1", + }, + }, + } + _, err := k8sh.BucketClientset.ObjectbucketV1alpha1().ObjectBucketClaims(namespace).Create(ctx, &newObc, metav1.CreateOptions{}) + assert.Nil(t, err) + obcBound := utils.Retry(20, 2*time.Second, "OBC is Bound", func() bool { + liveObc, err := k8sh.BucketClientset.ObjectbucketV1alpha1().ObjectBucketClaims(namespace).Get(ctx, bucketName, metav1.GetOptions{}) + if err != nil { + return false + } + + return liveObc.Status.Phase == v1alpha1.ObjectBucketClaimStatusPhaseBound + }) + assert.True(t, obcBound) + + // wait until obc is Bound to lookup the ob name + obc, err := k8sh.BucketClientset.ObjectbucketV1alpha1().ObjectBucketClaims(namespace).Get(ctx, bucketName, metav1.GetOptions{}) + assert.Nil(t, err) + obName = obc.Spec.ObjectBucketName + + obBound := utils.Retry(20, 2*time.Second, "OB is Bound", func() bool { + liveOb, err := k8sh.BucketClientset.ObjectbucketV1alpha1().ObjectBuckets().Get(ctx, obName, metav1.GetOptions{}) + if err != nil { + return false + } + + return liveOb.Status.Phase == v1alpha1.ObjectBucketStatusPhaseBound + }) + assert.True(t, obBound) + + // verify that bucketMaxObjects is set + assert.True(t, obc.Spec.AdditionalConfig["bucketMaxObjects"] == "1") + + // as the tests are running external to k8s, the internal svc can't be used + labelSelector := "rgw=" + storeName + services, err := k8sh.Clientset.CoreV1().Services(namespace).List(ctx, metav1.ListOptions{LabelSelector: labelSelector}) + assert.Nil(t, err) + assert.Equal(t, 1, len(services.Items)) + s3endpoint := services.Items[0].Spec.ClusterIP + ":80" + + secret, err := k8sh.Clientset.CoreV1().Secrets(namespace).Get(ctx, bucketName, metav1.GetOptions{}) + assert.Nil(t, err) + s3AccessKey := string(secret.Data["AWS_ACCESS_KEY_ID"]) + s3SecretKey := string(secret.Data["AWS_SECRET_ACCESS_KEY"]) + + if objectStore.Spec.IsTLSEnabled() { + s3client, err = rgw.NewInsecureS3Agent(s3AccessKey, s3SecretKey, s3endpoint, true) + } else { + s3client, err = rgw.NewS3Agent(s3AccessKey, s3SecretKey, s3endpoint, true, nil) + } + assert.Nil(t, err) + logger.Infof("endpoint (%s) Accesskey (%s) secret (%s)", s3endpoint, s3AccessKey, s3SecretKey) + }) + + t.Run("bucketMaxObjects quota is enforced", func(t *testing.T) { + // first object should succeed + _, err := s3client.PutObjectInBucket(bucketName, ObjBody, ObjectKey1, contentType) + assert.Nil(t, err) + // second object should fail as bucket quota is 1 + _, err = s3client.PutObjectInBucket(bucketName, ObjBody, ObjectKey2, contentType) + assert.Error(t, err) + // cleanup bucket + _, err = s3client.DeleteObjectInBucket(bucketName, ObjectKey1) + assert.Nil(t, err) + _, err = s3client.DeleteObjectInBucket(bucketName, ObjectKey2) + assert.Nil(t, err) + }) + + t.Run("change quota to bucketMaxSize", func(t *testing.T) { + obc, err := k8sh.BucketClientset.ObjectbucketV1alpha1().ObjectBucketClaims(namespace).Get(ctx, bucketName, metav1.GetOptions{}) + assert.Nil(t, err) + + obc.Spec.AdditionalConfig = map[string]string{"bucketMaxSize": "4Ki"} + + _, err = k8sh.BucketClientset.ObjectbucketV1alpha1().ObjectBucketClaims(namespace).Update(ctx, obc, metav1.UpdateOptions{}) + assert.Nil(t, err) + obcBound := utils.Retry(20, 2*time.Second, "OBC is Bound", func() bool { + liveObc, err := k8sh.BucketClientset.ObjectbucketV1alpha1().ObjectBucketClaims(namespace).Get(ctx, bucketName, metav1.GetOptions{}) + if err != nil { + return false + } + + return liveObc.Status.Phase == v1alpha1.ObjectBucketClaimStatusPhaseBound + }) + assert.True(t, obcBound) + + // wait until obc is Bound to lookup the ob name + obc, err = k8sh.BucketClientset.ObjectbucketV1alpha1().ObjectBucketClaims(namespace).Get(ctx, bucketName, metav1.GetOptions{}) + assert.Nil(t, err) + obName = obc.Spec.ObjectBucketName + + obBound := utils.Retry(20, 2*time.Second, "OB is Bound", func() bool { + liveOb, err := k8sh.BucketClientset.ObjectbucketV1alpha1().ObjectBuckets().Get(ctx, obName, metav1.GetOptions{}) + if err != nil { + return false + } + + return liveOb.Status.Phase == v1alpha1.ObjectBucketStatusPhaseBound + }) + assert.True(t, obBound) + + // verify that bucketMaxSize is set + assert.True(t, obc.Spec.AdditionalConfig["bucketMaxSize"] == "4Ki") + }) + + t.Run("bucketMaxSize quota is enforced", func(t *testing.T) { + // first ~3KiB Object should succeed + _, err := s3client.PutObjectInBucket(bucketName, strings.Repeat("1", 3072), ObjectKey1, contentType) + assert.Nil(t, err) + // second ~2KiB Object should fail as bucket quota is is 4KiB + _, err = s3client.PutObjectInBucket(bucketName, strings.Repeat("2", 2048), ObjectKey2, contentType) + assert.Error(t, err) + // cleanup bucket + _, err = s3client.DeleteObjectInBucket(bucketName, ObjectKey1) + assert.Nil(t, err) + _, err = s3client.DeleteObjectInBucket(bucketName, ObjectKey2) + assert.Nil(t, err) + }) + + t.Run("delete bucket", func(t *testing.T) { + err = k8sh.BucketClientset.ObjectbucketV1alpha1().ObjectBucketClaims(namespace).Delete(ctx, bucketName, metav1.DeleteOptions{}) + assert.Nil(t, err) + + absent := utils.Retry(20, 2*time.Second, "OBC is absent", func() bool { + _, err := k8sh.BucketClientset.ObjectbucketV1alpha1().ObjectBucketClaims(namespace).Get(ctx, bucketName, metav1.GetOptions{}) + return err != nil + }) + assert.True(t, absent) + + absent = utils.Retry(20, 2*time.Second, "OB is absent", func() bool { + _, err := k8sh.BucketClientset.ObjectbucketV1alpha1().ObjectBuckets().Get(ctx, obName, metav1.GetOptions{}) + return err != nil + }) + assert.True(t, absent) + }) + }) + t.Run("Regression check: OBC does not revert to Pending phase", func(t *testing.T) { // A bug exists in older versions of lib-bucket-provisioner that will revert a bucket and claim // back to "Pending" phase after being created and initially "Bound" by looping infinitely in diff --git a/tests/integration/ceph_upgrade_test.go b/tests/integration/ceph_upgrade_test.go index 04ee2b4bb7dc..849ad06eb148 100644 --- a/tests/integration/ceph_upgrade_test.go +++ b/tests/integration/ceph_upgrade_test.go @@ -145,7 +145,7 @@ func (s *UpgradeSuite) testUpgrade(useHelm bool, initialCephVersion v1.CephVersi rbdFilesToRead = append(rbdFilesToRead, newFile) cephfsFilesToRead = append(cephfsFilesToRead, newFile) - checkCephObjectUser(&s.Suite, s.helper, s.k8sh, s.namespace, installer.ObjectStoreName, objectUserID, true, false) + checkCephObjectUser(&s.Suite, s.helper, s.k8sh, s.namespace, installer.ObjectStoreName, objectUserID, false) // should be Bound after upgrade to Rook master // do not need retry b/c the OBC controller runs parallel to Rook-Ceph orchestration @@ -169,7 +169,7 @@ func (s *UpgradeSuite) testUpgrade(useHelm bool, initialCephVersion v1.CephVersi s.verifyFilesAfterUpgrade(newFile, rbdFilesToRead, cephfsFilesToRead) logger.Infof("Verified upgrade from reef to squid") - checkCephObjectUser(&s.Suite, s.helper, s.k8sh, s.namespace, installer.ObjectStoreName, objectUserID, true, false) + checkCephObjectUser(&s.Suite, s.helper, s.k8sh, s.namespace, installer.ObjectStoreName, objectUserID, false) } func (s *UpgradeSuite) TestUpgradeCephToReefDevel() { @@ -203,7 +203,7 @@ func (s *UpgradeSuite) TestUpgradeCephToReefDevel() { s.verifyFilesAfterUpgrade(newFile, rbdFilesToRead, cephfsFilesToRead) logger.Infof("verified upgrade from reef stable to reef devel") - checkCephObjectUser(&s.Suite, s.helper, s.k8sh, s.namespace, installer.ObjectStoreName, objectUserID, true, false) + checkCephObjectUser(&s.Suite, s.helper, s.k8sh, s.namespace, installer.ObjectStoreName, objectUserID, false) } func (s *UpgradeSuite) TestUpgradeCephToSquidDevel() { @@ -237,7 +237,7 @@ func (s *UpgradeSuite) TestUpgradeCephToSquidDevel() { s.verifyFilesAfterUpgrade(newFile, rbdFilesToRead, cephfsFilesToRead) logger.Infof("verified upgrade from squid stable to squid devel") - checkCephObjectUser(&s.Suite, s.helper, s.k8sh, s.namespace, installer.ObjectStoreName, objectUserID, true, false) + checkCephObjectUser(&s.Suite, s.helper, s.k8sh, s.namespace, installer.ObjectStoreName, objectUserID, false) } func (s *UpgradeSuite) deployClusterforUpgrade(baseRookImage, objectUserID, preFilename string) (int, []string, []string) { @@ -274,7 +274,7 @@ func (s *UpgradeSuite) deployClusterforUpgrade(baseRookImage, objectUserID, preF } logger.Infof("Initializing object user before the upgrade") - createCephObjectUser(&s.Suite, s.helper, s.k8sh, s.namespace, installer.ObjectStoreName, objectUserID, false, false) + createCephObjectUser(&s.Suite, s.helper, s.k8sh, s.namespace, installer.ObjectStoreName, objectUserID, false) logger.Info("Initializing object bucket claim before the upgrade") cobErr := s.helper.BucketClient.CreateBucketStorageClass(s.namespace, installer.ObjectStoreName, installer.ObjectStoreName, "Delete") diff --git a/tests/scripts/deploy-validate-vault.sh b/tests/scripts/deploy-validate-vault.sh index df793a07e793..b0003c0e8add 100755 --- a/tests/scripts/deploy-validate-vault.sh +++ b/tests/scripts/deploy-validate-vault.sh @@ -276,6 +276,32 @@ function validate_osd_secret { fi } +function validate_key_rotation() { + local backend_path=$1 + pvc_name=$(kubectl get pvc -n rook-ceph -l ceph.rook.io/setIndex=0 -o jsonpath='{.items[0].metadata.name}') + key_name="rook-ceph-osd-encryption-key-$pvc_name" + cmd="vault kv get -format=json $backend_path/$key_name" + old_key=$(kubectl exec vault-0 -- sh -c "$cmd" | jq -r ".data.\"$key_name\"") + local new_key + runtime=180 + endtime=$((SECONDS + runtime)) + while [ $SECONDS -le $endtime ]; do + echo "Time Now: $(date +%H:%M:%S)" + new_key=$(kubectl exec vault-0 -- sh -c "$cmd" | jq -r ".data.\"$key_name\"") + + if [ "$old_key" != "$new_key" ]; then + echo "encryption passphrase is successfully rotated" + exit 0 + fi + + echo "encryption passphrase is not rotated, sleeping for 10 seconds" + sleep 10 + done + + echo "encryption passphrase is not rotated" + exit 1 +} + ######## # MAIN # ######## @@ -290,6 +316,9 @@ validate_osd) validate_rgw) validate_rgw_deployment ;; +validate_key_rotation) + validate_key_rotation "$2" + ;; *) echo "invalid action $ACTION" >&2 exit 1 diff --git a/tests/scripts/github-action-helper.sh b/tests/scripts/github-action-helper.sh index c2735d260484..558c315a5459 100755 --- a/tests/scripts/github-action-helper.sh +++ b/tests/scripts/github-action-helper.sh @@ -615,58 +615,6 @@ function create_helm_tag() { docker tag "${build_image}" "rook/ceph:${helm_tag}" } -function deploy_multus() { - # download the multus daemonset, and remove mem and cpu limits that cause it to crash on minikube - curl https://raw.githubusercontent.com/k8snetworkplumbingwg/multus-cni/master/deployments/multus-daemonset-thick.yml | - sed -e 's/cpu: /# cpu: /g' -e 's/memory: /# memory: /g' | - kubectl apply -f - - - # install whereabouts - kubectl apply \ - -f https://raw.githubusercontent.com/k8snetworkplumbingwg/whereabouts/master/doc/crds/daemonset-install.yaml \ - -f https://github.com/k8snetworkplumbingwg/whereabouts/raw/master/doc/crds/whereabouts.cni.cncf.io_ippools.yaml \ - -f https://github.com/k8snetworkplumbingwg/whereabouts/raw/master/doc/crds/whereabouts.cni.cncf.io_overlappingrangeipreservations.yaml - - # create the rook-ceph namespace if it doesn't exist, the NAD will go in this namespace - kubectl create namespace rook-ceph || true - - # install network attachment definitions - IFACE="eth0" # the runner has eth0 so we don't need any heuristics to find the interface - kubectl apply -f - <