From d8c0242c29eb0d8bb7f8ff6c5f36525a830e05b3 Mon Sep 17 00:00:00 2001 From: Praveen M Date: Mon, 23 Sep 2024 11:13:45 +0530 Subject: [PATCH 01/38] security: key rotation support for vault kms Signed-off-by: Praveen M --- pkg/daemon/ceph/osd/kms/kms.go | 19 +++++++++++++++++++ pkg/operator/ceph/cluster/osd/key_rotation.go | 6 ++++++ 2 files changed, 25 insertions(+) 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/osd/key_rotation.go b/pkg/operator/ceph/cluster/osd/key_rotation.go index f9a427100d9d..d13f525684f0 100644 --- a/pkg/operator/ceph/cluster/osd/key_rotation.go +++ b/pkg/operator/ceph/cluster/osd/key_rotation.go @@ -137,6 +137,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") From 01ccb5e20a01fe0ff818ab169deaa2217df418e8 Mon Sep 17 00:00:00 2001 From: Praveen M Date: Tue, 8 Oct 2024 16:44:58 +0530 Subject: [PATCH 02/38] docs: update docs for vault KMS key rotation support Signed-off-by: Praveen M --- .../Storage-Configuration/Advanced/key-management-system.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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: From c9bc3a2685822a342bf390a5f490e0ee35661d60 Mon Sep 17 00:00:00 2001 From: Praveen M Date: Thu, 10 Oct 2024 10:43:06 +0530 Subject: [PATCH 03/38] ci: add test for vault key rotation Signed-off-by: Praveen M --- .github/workflows/canary-integration-test.yml | 8 +++++ tests/scripts/deploy-validate-vault.sh | 29 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/.github/workflows/canary-integration-test.yml b/.github/workflows/canary-integration-test.yml index 0c0dfcfbee0d..29cedc250a2f 100644 --- a/.github/workflows/canary-integration-test.yml +++ b/.github/workflows/canary-integration-test.yml @@ -1073,6 +1073,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 @@ -1093,6 +1094,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 @@ -1158,6 +1162,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 @@ -1174,6 +1179,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 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 From 4e29717317d6e62c57b404282b6c9f155d7b1531 Mon Sep 17 00:00:00 2001 From: Madhu Rajanna Date: Wed, 23 Oct 2024 12:10:53 +0200 Subject: [PATCH 04/38] core: cleanup blockpool with annotation This is similar to #14052 we did for radosnamespace and this is an extension to support cleanup at the blockpool level to cleanup the images and the snapshots in a pool. Signed-off-by: Madhu Rajanna --- .../Storage-Configuration/ceph-teardown.md | 1 + cmd/rook/ceph/cleanup.go | 31 ++++++++++- pkg/daemon/ceph/cleanup/radosnamespace.go | 43 +++++++++++---- .../ceph/cleanup/radosnamespace_test.go | 53 +++++++++++++++++++ pkg/daemon/ceph/client/image.go | 19 +++++-- pkg/operator/ceph/pool/controller.go | 26 ++++++++- 6 files changed, 157 insertions(+), 16 deletions(-) diff --git a/Documentation/Storage-Configuration/ceph-teardown.md b/Documentation/Storage-Configuration/ceph-teardown.md index b207efc47659..6196854ed632 100644 --- a/Documentation/Storage-Configuration/ceph-teardown.md +++ b/Documentation/Storage-Configuration/ceph-teardown.md @@ -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/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/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/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/operator/ceph/pool/controller.go b/pkg/operator/ceph/pool/controller.go index 015d59dea098..33ac9b428da9 100644 --- a/pkg/operator/ceph/pool/controller.go +++ b/pkg/operator/ceph/pool/controller.go @@ -76,6 +76,7 @@ type ReconcileCephBlockPool struct { blockPoolContexts map[string]*blockPoolHealth opManagerContext context.Context recorder record.EventRecorder + opConfig opcontroller.OperatorConfig } type blockPoolHealth struct { @@ -87,11 +88,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 +100,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 +247,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) } @@ -373,6 +381,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 From f51cfbdf6bbffb468560964631c53c3dd3f749f3 Mon Sep 17 00:00:00 2001 From: Joshua Hoblitt Date: Wed, 9 Oct 2024 16:32:34 -0700 Subject: [PATCH 05/38] object: add bucketMaxObjects & bucketMaxSize to obc Two new keys are added to ObjectBucketClaim.spec.additionalConfig to support the configuration of bucket scope quota(s). This differs from the existing maxObjects & maxSize keys, which manage a user scope quota(s) on the automatically generated rgw user. Signed-off-by: Joshua Hoblitt --- .../ceph-object-bucket-claim.md | 8 +- .../ceph/object/bucket/provisioner.go | 73 +++- .../ceph/object/bucket/provisioner_test.go | 360 +++++++++++++----- pkg/operator/ceph/object/bucket/util.go | 14 + 4 files changed, 346 insertions(+), 109 deletions(-) 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/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 } From f64027bf43f718dbadad4a6b081997877504814d Mon Sep 17 00:00:00 2001 From: Joshua Hoblitt Date: Thu, 17 Oct 2024 15:00:03 -0700 Subject: [PATCH 06/38] test: add obc bucketMaxObjects integration test Signed-off-by: Joshua Hoblitt --- tests/integration/ceph_object_test.go | 163 +++++++++++++++++++++++++- 1 file changed, 160 insertions(+), 3 deletions(-) diff --git a/tests/integration/ceph_object_test.go b/tests/integration/ceph_object_test.go index d51dd59b4be5..db55cd39e4bc 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" ) @@ -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 From 5539eedd1b1f209062d734ab653184d230b322c6 Mon Sep 17 00:00:00 2001 From: Blaine Gardner Date: Tue, 8 Oct 2024 11:19:03 -0600 Subject: [PATCH 07/38] multus: finish deprecating holder pods Finish the process of deprecating holder pods by removing Rook's ability to deploy them. The intent of this change is to make the most superficial changes possible to accomplish this. There are still remnants of code in Rook (particularly the CSI controller) that helped configure or deploy holder pods. Due to the risk of breaking some features, cleanup work of hose remnants will be deferred for future work. Signed-off-by: Blaine Gardner --- .github/workflows/canary-integration-test.yml | 103 ++------ .mergify.yml | 2 +- .../CRDs/Cluster/network-providers.md | 179 -------------- Documentation/Helm-Charts/operator-chart.md | 1 - Documentation/Upgrade/rook-upgrade.md | 31 +-- .../charts/rook-ceph/templates/configmap.yaml | 1 - deploy/charts/rook-ceph/values.yaml | 6 +- deploy/examples/operator-openshift.yaml | 5 - deploy/examples/operator.yaml | 5 - design/ceph/multus-network.md | 44 ---- pkg/operator/ceph/cluster/cephstatus.go | 3 - pkg/operator/ceph/cluster/cephstatus_test.go | 5 +- pkg/operator/ceph/csi/controller.go | 66 +---- pkg/operator/ceph/csi/controller_test.go | 8 +- pkg/operator/ceph/csi/operator_config_test.go | 1 - pkg/operator/ceph/csi/operator_driver_test.go | 1 - pkg/operator/ceph/csi/spec.go | 229 +----------------- pkg/operator/ceph/csi/spec_test.go | 104 -------- .../cephfs/csi-cephfsplugin-holder.yaml | 67 ----- .../template/nfs/csi-nfsplugin-holder.yaml | 67 ----- .../template/rbd/csi-rbdplugin-holder.yaml | 67 ----- .../ceph/file/subvolumegroup/controller.go | 10 +- .../ceph/pool/radosnamespace/controller.go | 9 +- tests/scripts/github-action-helper.sh | 52 ---- .../multus/default-public-cluster-nads.yaml | 2 + tests/scripts/multus/host-cfg-ds.yaml | 1 + .../multus/rook-ceph-public-cluster-nads.yaml | 43 ++++ tests/scripts/validate_cluster.sh | 23 +- 28 files changed, 102 insertions(+), 1033 deletions(-) delete mode 100644 pkg/operator/ceph/csi/template/cephfs/csi-cephfsplugin-holder.yaml delete mode 100644 pkg/operator/ceph/csi/template/nfs/csi-nfsplugin-holder.yaml delete mode 100644 pkg/operator/ceph/csi/template/rbd/csi-rbdplugin-holder.yaml create mode 100644 tests/scripts/multus/rook-ceph-public-cluster-nads.yaml diff --git a/.github/workflows/canary-integration-test.yml b/.github/workflows/canary-integration-test.yml index 55dd34b0a3dc..19157c7fcf8f 100644 --- a/.github/workflows/canary-integration-test.yml +++ b/.github/workflows/canary-integration-test.yml @@ -1632,7 +1632,7 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} artifact-name: ${{ github.job }}-${{ 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: @@ -1649,45 +1649,50 @@ jobs: with: use-tmate: ${{ secrets.USE_TMATE }} - - name: setup golang - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 - with: - go-version: "1.22" - - 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 - - name: deploy multus cluster - run: tests/scripts/github-action-helper.sh deploy_multus_cluster + tests/scripts/github-action-helper.sh deploy_toolbox + + 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 +1713,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')" 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/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/Helm-Charts/operator-chart.md b/Documentation/Helm-Charts/operator-chart.md index a78ddc1ad4e7..63ec4f542872 100644 --- a/Documentation/Helm-Charts/operator-chart.md +++ b/Documentation/Helm-Charts/operator-chart.md @@ -84,7 +84,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/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/deploy/charts/rook-ceph/templates/configmap.yaml b/deploy/charts/rook-ceph/templates/configmap.yaml index c29dbcd74fc9..98b99741dbe8 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 }} diff --git a/deploy/charts/rook-ceph/values.yaml b/deploy/charts/rook-ceph/values.yaml index 7e3d47bb3c04..5b48fc868142 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 @@ -640,7 +636,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/operator-openshift.yaml b/deploy/examples/operator-openshift.yaml index 876a029f0df3..239b75b16e50 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" diff --git a/deploy/examples/operator.yaml b/deploy/examples/operator.yaml index 0533051fffcc..1a90a5193039 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. 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/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/csi/controller.go b/pkg/operator/ceph/csi/controller.go index 31c9d7924a0f..e2fc9e39f898 100644 --- a/pkg/operator/ceph/csi/controller.go +++ b/pkg/operator/ceph/csi/controller.go @@ -52,23 +52,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 +70,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, } } @@ -250,22 +241,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,29 +270,14 @@ 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) diff --git a/pkg/operator/ceph/csi/controller_test.go b/pkg/operator/ceph/csi/controller_test.go index 2860c6d673f4..b1998bab4114 100644 --- a/pkg/operator/ceph/csi/controller_test.go +++ b/pkg/operator/ceph/csi/controller_test.go @@ -264,12 +264,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/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..59af7f601dac 100644 --- a/pkg/operator/ceph/csi/spec.go +++ b/pkg/operator/ceph/csi/spec.go @@ -21,7 +21,6 @@ import ( _ "embed" "fmt" "path" - "strconv" "strings" "time" @@ -30,7 +29,6 @@ import ( 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 +36,8 @@ 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 +110,6 @@ type templateParam struct { Namespace string } -type driverDetails struct { - name string - fullName string - holderTemplate string - toleration string - nodeAffinity string - resource string -} - var ( CSIParam Param @@ -164,8 +150,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 +158,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 +168,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 @@ -333,8 +313,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 +369,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 +399,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 +421,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 +431,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 +451,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 +520,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 +590,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 { @@ -865,166 +798,6 @@ func (r *ReconcileCSI) validateCSIVersion(ownerInfo *k8sutil.OwnerInfo) (*CephCS 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 +879,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/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/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/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/pool/radosnamespace/controller.go b/pkg/operator/ceph/pool/radosnamespace/controller.go index 7bae0b595ba9..790fd6f614c6 100644 --- a/pkg/operator/ceph/pool/radosnamespace/controller.go +++ b/pkg/operator/ceph/pool/radosnamespace/controller.go @@ -326,14 +326,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) 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 - < Date: Thu, 24 Oct 2024 10:08:15 +0200 Subject: [PATCH 08/38] osd: mount /run/udev in the init container for ceph-volume activate The /run/udev directory is now mounted in the OSD init container. This change is necessary because `ceph-volume activate` needs access to /run/udev [1] in order to properly handle devices. Without this mount, `ceph-volume activate` could fail to discover devices during OSD initialization. [1] https://github.com/ceph/ceph/commit/c2e8c295dc46f1bd74861feb163d9d82f8bb5509 Signed-off-by: Guillaume Abrioux --- pkg/operator/ceph/cluster/osd/spec.go | 3 +++ pkg/operator/ceph/cluster/osd/spec_test.go | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/pkg/operator/ceph/cluster/osd/spec.go b/pkg/operator/ceph/cluster/osd/spec.go index f1ab7516b710..4506d5249a37 100644 --- a/pkg/operator/ceph/cluster/osd/spec.go +++ b/pkg/operator/ceph/cluster/osd/spec.go @@ -867,10 +867,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, } 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) From b47dff9770e066228ae65bb32c2f8b8a768696d2 Mon Sep 17 00:00:00 2001 From: Artem Torubarov Date: Fri, 25 Oct 2024 12:52:06 +0200 Subject: [PATCH 09/38] rgw: support custom name for default pool placement introduce Default flag to CRD Signed-off-by: Artem Torubarov --- Documentation/CRDs/specification.md | 11 + .../Object-Storage-RGW/object-storage.md | 8 +- .../charts/rook-ceph/templates/resources.yaml | 8 + deploy/examples/crds.yaml | 8 + pkg/apis/ceph.rook.io/v1/types.go | 3 + pkg/operator/ceph/object/objectstore.go | 7 +- pkg/operator/ceph/object/objectstore_test.go | 19 +- pkg/operator/ceph/object/shared_pools.go | 52 ++-- pkg/operator/ceph/object/shared_pools_test.go | 241 ++++++++++++++---- 9 files changed, 273 insertions(+), 84 deletions(-) diff --git a/Documentation/CRDs/specification.md b/Documentation/CRDs/specification.md index dd6949d64ffe..e0b0151097e7 100644 --- a/Documentation/CRDs/specification.md +++ b/Documentation/CRDs/specification.md @@ -10959,6 +10959,17 @@ string +default
+ +bool + + + +

Sets given placement as default. Only one placement in the list can be marked as default.

+ + + + metadataPoolName
string 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/deploy/charts/rook-ceph/templates/resources.yaml b/deploy/charts/rook-ceph/templates/resources.yaml index 12c2d1ffbaa8..77ff73089547 100644 --- a/deploy/charts/rook-ceph/templates/resources.yaml +++ b/deploy/charts/rook-ceph/templates/resources.yaml @@ -12383,6 +12383,9 @@ 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. + type: boolean metadataPoolName: description: The metadata pool used to store ObjectStore bucket index. minLength: 1 @@ -12420,6 +12423,7 @@ spec: type: array required: - dataPoolName + - default - metadataPoolName - name type: object @@ -13305,6 +13309,9 @@ 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. + type: boolean metadataPoolName: description: The metadata pool used to store ObjectStore bucket index. minLength: 1 @@ -13342,6 +13349,7 @@ spec: type: array required: - dataPoolName + - default - metadataPoolName - name type: object diff --git a/deploy/examples/crds.yaml b/deploy/examples/crds.yaml index 1ffc720b8548..b10029784a72 100644 --- a/deploy/examples/crds.yaml +++ b/deploy/examples/crds.yaml @@ -12374,6 +12374,9 @@ 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. + type: boolean metadataPoolName: description: The metadata pool used to store ObjectStore bucket index. minLength: 1 @@ -12411,6 +12414,7 @@ spec: type: array required: - dataPoolName + - default - metadataPoolName - name type: object @@ -13293,6 +13297,9 @@ 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. + type: boolean metadataPoolName: description: The metadata pool used to store ObjectStore bucket index. minLength: 1 @@ -13330,6 +13337,7 @@ spec: type: array required: - dataPoolName + - default - metadataPoolName - name type: object diff --git a/pkg/apis/ceph.rook.io/v1/types.go b/pkg/apis/ceph.rook.io/v1/types.go index 61812212b663..633b9153c6b8 100755 --- a/pkg/apis/ceph.rook.io/v1/types.go +++ b/pkg/apis/ceph.rook.io/v1/types.go @@ -1563,6 +1563,9 @@ 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 bool `json:"default"` + // The metadata pool used to store ObjectStore bucket index. // +kubebuilder:validation:Required // +kubebuilder:validation:MinLength=1 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..ee5aa4c83dd6 100644 --- a/pkg/operator/ceph/object/objectstore_test.go +++ b/pkg/operator/ceph/object/objectstore_test.go @@ -152,7 +152,7 @@ const ( "notif_pool": "%[1]s:store-a.log.notif" }` - objectZonegroupJson = `{ + objectZonegroupJsonTempl = `{ "id": "610c9e3d-19e7-40b0-9f88-03319c4bc65a", "name": "store-a", "api_name": "test", @@ -174,14 +174,14 @@ const ( ], "placement_targets": [ { - "name": "default-placement", + "name": "%[1]s", "tags": [], "storage_classes": [ "STANDARD" ] } ], - "default_placement": "default-placement", + "default_placement": "%[1]s", "realm_id": "29e28253-be54-4581-90dd-206020d2fcdd", "sync_policy": { "groups": [] @@ -229,6 +229,7 @@ func TestReconcileRealm(t *testing.T) { func TestConfigureStoreWithSharedPools(t *testing.T) { sharedMetaPoolAlreadySet, sharedDataPoolAlreadySet := "", "" + defaultPlacement := defaultPlacementCephConfigName zoneGetCalled := false zoneSetCalled := false zoneGroupGetCalled := false @@ -273,7 +274,7 @@ func TestConfigureStoreWithSharedPools(t *testing.T) { } else if args[0] == "zonegroup" { if args[1] == "get" { zoneGroupGetCalled = true - return objectZonegroupJson, nil + return fmt.Sprintf(objectZonegroupJsonTempl, defaultPlacement), nil } else if args[1] == "set" { zoneGroupSetCalled = true for _, arg := range args { @@ -287,7 +288,7 @@ func TestConfigureStoreWithSharedPools(t *testing.T) { } return string(inBytes), nil } - return objectZonegroupJson, nil + return fmt.Sprintf(objectZonegroupJsonTempl, defaultPlacement), nil } } return "", errors.Errorf("unexpected ceph command %q", args) @@ -334,12 +335,14 @@ func TestConfigureStoreWithSharedPools(t *testing.T) { sharedPools := cephv1.ObjectSharedPoolsSpec{ PoolPlacements: []cephv1.PoolPlacementSpec{ { - Name: defaultPlacementName, + Name: "default", + Default: true, MetadataPoolName: "test-meta", DataPoolName: "test-data", }, }, } + defaultPlacement = "default" err := ConfigureSharedPoolsForZone(context, sharedPools) assert.NoError(t, err) assert.True(t, zoneGetCalled) @@ -354,6 +357,7 @@ func TestConfigureStoreWithSharedPools(t *testing.T) { MetadataPoolName: "test-meta", DataPoolName: "test-data", } + defaultPlacement = defaultPlacementCephConfigName sharedMetaPoolAlreadySet, sharedDataPoolAlreadySet = "test-meta", "test-data" zoneGetCalled = false zoneSetCalled = false @@ -370,7 +374,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/shared_pools.go b/pkg/operator/ceph/object/shared_pools.go index 7627a08a8a38..b447cdf46edd 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 @@ -79,6 +89,7 @@ func adjustZonePlacementPools(zone map[string]interface{}, spec cephv1.ObjectSha fromSpec := toZonePlacementPools(spec, name) + defaultPlacementName := getDefaultPlacementName(spec) inConfig := map[string]struct{}{} idxToRemove := map[int]struct{}{} for i, p := range placements { @@ -91,7 +102,7 @@ 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 { + if _, inSpec := fromSpec[placementID]; !inSpec && placementID != defaultPlacementName { // remove placement if it is not in spec, but don't remove default placement idxToRemove[i] = struct{}{} continue @@ -151,9 +162,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 } } @@ -165,12 +185,10 @@ func toZonePlacementPools(spec cephv1.ObjectSharedPoolsSpec, ns string) map[stri hasDefault := false res := make(map[string]ZonePlacementPool, len(spec.PoolPlacements)+1) for _, pp := range spec.PoolPlacements { - name := pp.Name - if pp.Name == defaultPlacementName { + if pp.Default { hasDefault = true - name = defaultPlacementCephConfigName } - res[name] = toZonePlacementPool(pp, ns) + res[pp.Name] = toZonePlacementPool(pp, ns) } if !hasDefault && spec.DataPoolName != "" && spec.MetadataPoolName != "" { // set shared pools as default if no default placement was provided @@ -197,10 +215,7 @@ func toZonePlacementPools(spec cephv1.ObjectSharedPoolsSpec, ns string) map[stri } 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 +233,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 +247,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 +259,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) } diff --git a/pkg/operator/ceph/object/shared_pools_test.go b/pkg/operator/ceph/object/shared_pools_test.go index 4ef29275f258..f40306141d1e 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", @@ -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", @@ -596,14 +655,14 @@ func Test_toZonePlacementPools(t *testing.T) { ns: "rgw-instance", }, want: map[string]ZonePlacementPool{ - defaultPlacementCephConfigName: { - Key: defaultPlacementCephConfigName, + "some_name": { + Key: "some_name", Val: ZonePlacementPoolVal{ - DataExtraPool: "data-non-ec:rgw-instance.data.non-ec", - IndexPool: "meta1:rgw-instance.index", + 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 +1021,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", }, @@ -1418,8 +1478,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 +1492,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 +1554,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 +1616,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 +1681,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 +1762,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 +1835,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 +1935,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) + } + }) + } +} From 36721edae8a853b29b67d8ab48962cc891c1ee7c Mon Sep 17 00:00:00 2001 From: Satoru Takeuchi Date: Fri, 25 Oct 2024 11:48:36 +0000 Subject: [PATCH 10/38] test: specify ceph image correctly `encryption-pvc-kms-ibm-kp` workflow replaces the name of ceph-image. Since the dest value is always empty by mistake, this workflow always fails. Signed-off-by: Satoru Takeuchi --- .github/workflows/canary-integration-test.yml | 1 + .github/workflows/encryption-pvc-kms-ibm-kp/action.yml | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/canary-integration-test.yml b/.github/workflows/canary-integration-test.yml index 8069ab2cde78..033c4ff98fa2 100644 --- a/.github/workflows/canary-integration-test.yml +++ b/.github/workflows/canary-integration-test.yml @@ -1639,6 +1639,7 @@ 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-public-and-cluster: runs-on: ubuntu-22.04 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} From b52ba6baca719477f35a7a0dd73ca350b9961b1e Mon Sep 17 00:00:00 2001 From: Travis Nielsen Date: Thu, 24 Oct 2024 14:23:31 -0600 Subject: [PATCH 11/38] test: wait for mon daemons rather than mon canaries The mon canaries may be created even when the mon daemons are not created thereafter during the integration tests. Therefore, the integration tests need to also query a label specific to the mon daemon so the canaries are not a distraction to the test. Signed-off-by: Travis Nielsen --- pkg/operator/ceph/cluster/mon/spec.go | 3 +++ tests/framework/installer/ceph_installer.go | 7 ++++++- tests/framework/utils/k8s_helper.go | 3 +++ 3 files changed, 12 insertions(+), 1 deletion(-) 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/tests/framework/installer/ceph_installer.go b/tests/framework/installer/ceph_installer.go index a02757fcd83d..0e2287190a74 100644 --- a/tests/framework/installer/ceph_installer.go +++ b/tests/framework/installer/ceph_installer.go @@ -265,7 +265,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 } From 7bb72a0171ad6126f3d38b55df524581e475b4eb Mon Sep 17 00:00:00 2001 From: Blaine Gardner Date: Thu, 10 Oct 2024 16:15:28 -0600 Subject: [PATCH 12/38] object: also use system certs for validating RGW cert When generating the HTTP client used for RGW admin ops, use both system certs as well as the user-given cert. As a real world example, admins may use ACME to rotate Letsencrypt certs every 2 months. For an external CephObjectStore, the cert used by Rook and RGW may not be rotated at the same time. This can cause the Rook operator to fail CephObjectStore reconciliation until both certs agree. When Rook also relies on system certs in the container, Rook's reconciliation will not have reconciliation failures because Letsencrypt's well-known and trusted root certificates can be loaded from the system to validate the RGW's newly-rotated cert. Signed-off-by: Blaine Gardner --- .../CRDs/Cluster/external-cluster/provider-export.md | 2 +- deploy/examples/create-external-cluster-resources.py | 2 +- pkg/operator/ceph/object/s3-handlers.go | 12 +++++++++--- pkg/operator/ceph/object/s3-handlers_test.go | 2 +- 4 files changed, 12 insertions(+), 6 deletions(-) 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/deploy/examples/create-external-cluster-resources.py b/deploy/examples/create-external-cluster-resources.py index 268176c4f607..d059a1456462 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/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) }) From 67885727a2e515c197e0f9bcf4f24fcd8b41b98f Mon Sep 17 00:00:00 2001 From: Ceph Jenkins Date: Mon, 28 Oct 2024 04:06:18 -0400 Subject: [PATCH 13/38] csv: add additional csv changes that other commits bring add generated csv changes Signed-off-by: Ceph Jenkins --- .../ceph/ceph.rook.io_cephobjectstores.yaml | 3 + .../ceph/ceph.rook.io_cephobjectzones.yaml | 3 + ...al-cluster-script-config_v1_configmap.yaml | 2649 +++++++++-------- ...k-ceph-operator.clusterserviceversion.yaml | 2649 +++++++++-------- 4 files changed, 2656 insertions(+), 2648 deletions(-) diff --git a/build/csv/ceph/ceph.rook.io_cephobjectstores.yaml b/build/csv/ceph/ceph.rook.io_cephobjectstores.yaml index 3f86d6ffce5d..2a95fe1cc6d3 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 @@ -1508,6 +1510,7 @@ spec: type: array required: - dataPoolName + - default - metadataPoolName - name type: object diff --git a/build/csv/ceph/ceph.rook.io_cephobjectzones.yaml b/build/csv/ceph/ceph.rook.io_cephobjectzones.yaml index 52a8209f1ef8..9a07c66ecc0b 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 @@ -346,6 +348,7 @@ spec: type: array required: - dataPoolName + - default - metadataPoolName - name type: object 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..489cb625a792 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: From 734da26d89bf0a6abd655e2042480b458d9b7319 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 12:35:26 +0000 Subject: [PATCH 14/38] build(deps): bump actions/checkout from 4.2.1 to 4.2.2 Bumps [actions/checkout](https://github.com/actions/checkout) from 4.2.1 to 4.2.2. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871...11bd71901bbe5b1630ceea73d27597364c9af683) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/build.yml | 4 +- .github/workflows/canary-integration-test.yml | 42 +++++++++---------- .github/workflows/codegen.yml | 2 +- .github/workflows/codespell.yaml | 4 +- .github/workflows/commitlint.yml | 2 +- .github/workflows/crds-gen.yml | 2 +- .github/workflows/daily-nightly-jobs.yml | 14 +++---- .github/workflows/docs-check.yml | 2 +- .github/workflows/golangci-lint.yaml | 2 +- .github/workflows/helm-lint.yaml | 2 +- .../integration-test-helm-suite.yaml | 2 +- .../integration-test-keystone-auth-suite.yaml | 2 +- .../workflows/integration-test-mgr-suite.yaml | 2 +- .../integration-test-multi-cluster-suite.yaml | 2 +- .../integration-test-object-suite.yaml | 2 +- .../integration-test-smoke-suite.yaml | 2 +- .../integration-test-upgrade-suite.yaml | 4 +- .../integration-tests-on-release.yaml | 12 +++--- .github/workflows/linters.yaml | 4 +- .github/workflows/mod-check.yml | 2 +- .github/workflows/multus.yaml | 2 +- .github/workflows/push-build.yaml | 2 +- .github/workflows/rbac-gen.yaml | 2 +- .github/workflows/scorecards.yml | 2 +- .github/workflows/shellcheck.yaml | 2 +- .github/workflows/snyk.yaml | 2 +- .github/workflows/unit-test.yml | 2 +- 27 files changed, 62 insertions(+), 62 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2e9922c5af3f..e3652e4ae00b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,7 +21,7 @@ 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 @@ -74,7 +74,7 @@ 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 diff --git a/.github/workflows/canary-integration-test.yml b/.github/workflows/canary-integration-test.yml index 8069ab2cde78..a0aa586f192f 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 @@ -334,7 +334,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 @@ -412,7 +412,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 - name: consider debugging @@ -463,7 +463,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 @@ -512,7 +512,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 @@ -570,7 +570,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 @@ -622,7 +622,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 @@ -679,7 +679,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 @@ -755,7 +755,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 @@ -807,7 +807,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 @@ -862,7 +862,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 @@ -930,7 +930,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 @@ -984,7 +984,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 @@ -1048,7 +1048,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 @@ -1138,7 +1138,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,7 +1208,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,7 +1265,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,7 +1524,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 @@ -1619,7 +1619,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 @@ -1648,7 +1648,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 @@ -1729,7 +1729,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 diff --git a/.github/workflows/codegen.yml b/.github/workflows/codegen.yml index 74fb05769987..b35a5b00d0e4 100644 --- a/.github/workflows/codegen.yml +++ b/.github/workflows/codegen.yml @@ -30,7 +30,7 @@ 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 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..0482b0e98b76 100644 --- a/.github/workflows/crds-gen.yml +++ b/.github/workflows/crds-gen.yml @@ -29,7 +29,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/daily-nightly-jobs.yml b/.github/workflows/daily-nightly-jobs.yml index a5bf2f89f4ed..50685dca0584 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 @@ -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..197f7555ff60 100644 --- a/.github/workflows/docs-check.yml +++ b/.github/workflows/docs-check.yml @@ -24,7 +24,7 @@ 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 diff --git a/.github/workflows/golangci-lint.yaml b/.github/workflows/golangci-lint.yaml index 89df3980ab52..69d1a574412c 100644 --- a/.github/workflows/golangci-lint.yaml +++ b/.github/workflows/golangci-lint.yaml @@ -24,7 +24,7 @@ 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 diff --git a/.github/workflows/helm-lint.yaml b/.github/workflows/helm-lint.yaml index 8a57bf6349fb..996f837b87dd 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 diff --git a/.github/workflows/integration-test-helm-suite.yaml b/.github/workflows/integration-test-helm-suite.yaml index f00ccdc79bef..962f98f8dff0 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 diff --git a/.github/workflows/integration-test-keystone-auth-suite.yaml b/.github/workflows/integration-test-keystone-auth-suite.yaml index 014652a5cf2c..24da4dd58be0 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 diff --git a/.github/workflows/integration-test-mgr-suite.yaml b/.github/workflows/integration-test-mgr-suite.yaml index 916feff75c32..cf8623cba2d4 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 diff --git a/.github/workflows/integration-test-multi-cluster-suite.yaml b/.github/workflows/integration-test-multi-cluster-suite.yaml index cc1f242522ae..71c73b0180db 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 diff --git a/.github/workflows/integration-test-object-suite.yaml b/.github/workflows/integration-test-object-suite.yaml index d3980eed037a..be07cdb0f233 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 diff --git a/.github/workflows/integration-test-smoke-suite.yaml b/.github/workflows/integration-test-smoke-suite.yaml index d64bcdf01061..0ccf3fe1a723 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 diff --git a/.github/workflows/integration-test-upgrade-suite.yaml b/.github/workflows/integration-test-upgrade-suite.yaml index 99051c6f1b4b..0c88af1a2e9f 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 @@ -75,7 +75,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/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..09c52f745cd5 100644 --- a/.github/workflows/linters.yaml +++ b/.github/workflows/linters.yaml @@ -23,7 +23,7 @@ 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 @@ -41,7 +41,7 @@ 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 diff --git a/.github/workflows/mod-check.yml b/.github/workflows/mod-check.yml index 108eac712b91..cf0cde0d220d 100644 --- a/.github/workflows/mod-check.yml +++ b/.github/workflows/mod-check.yml @@ -29,7 +29,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/multus.yaml b/.github/workflows/multus.yaml index 21c172ebf491..8619e8f0887f 100644 --- a/.github/workflows/multus.yaml +++ b/.github/workflows/multus.yaml @@ -36,7 +36,7 @@ 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 diff --git a/.github/workflows/push-build.yaml b/.github/workflows/push-build.yaml index 8f5c08302461..cf7ee8988611 100644 --- a/.github/workflows/push-build.yaml +++ b/.github/workflows/push-build.yaml @@ -21,7 +21,7 @@ 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 diff --git a/.github/workflows/rbac-gen.yaml b/.github/workflows/rbac-gen.yaml index be342bf72620..72b9f40e3bb7 100644 --- a/.github/workflows/rbac-gen.yaml +++ b/.github/workflows/rbac-gen.yaml @@ -29,7 +29,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/scorecards.yml b/.github/workflows/scorecards.yml index 3cebd2816234..e7c57051f53e 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 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/unit-test.yml b/.github/workflows/unit-test.yml index 3167fd74315a..1d74fca1812e 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -37,7 +37,7 @@ 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 From 56752e5890db741483c9035527d9c8cbd679d7a0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 12:35:31 +0000 Subject: [PATCH 15/38] build(deps): bump actions/setup-python from 5.2.0 to 5.3.0 Bumps [actions/setup-python](https://github.com/actions/setup-python) from 5.2.0 to 5.3.0. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/f677139bbe7f9c59b41e40162b753c062f5d49a3...0b93645e9fea7318ecaed2b359559ac225c90a2b) --- updated-dependencies: - dependency-name: actions/setup-python dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/docs-check.yml | 2 +- .github/workflows/helm-lint.yaml | 2 +- .github/workflows/linters.yaml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/docs-check.yml b/.github/workflows/docs-check.yml index 265ffff830dc..2c180b90b0a4 100644 --- a/.github/workflows/docs-check.yml +++ b/.github/workflows/docs-check.yml @@ -32,7 +32,7 @@ jobs: 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/helm-lint.yaml b/.github/workflows/helm-lint.yaml index 8a57bf6349fb..5339508ef04b 100644 --- a/.github/workflows/helm-lint.yaml +++ b/.github/workflows/helm-lint.yaml @@ -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/linters.yaml b/.github/workflows/linters.yaml index 810eb2417503..0e990e816537 100644 --- a/.github/workflows/linters.yaml +++ b/.github/workflows/linters.yaml @@ -28,7 +28,7 @@ jobs: 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 @@ -46,7 +46,7 @@ jobs: 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 From f1cd919564567d9c4999b43c85f2dab670c66570 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 12:35:43 +0000 Subject: [PATCH 16/38] build(deps): bump github/codeql-action from 3.26.13 to 3.27.0 Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.26.13 to 3.27.0. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/f779452ac5af1c261dce0346a8f964149f49322b...662472033e021d55d94146f66f6058822b0b39fd) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/scorecards.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 3cebd2816234..6c264e9daa29 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -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 From 6f4ad530e0e1f94c2dbd54b0983676c365289846 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 12:35:50 +0000 Subject: [PATCH 17/38] build(deps): bump actions/setup-go from 5.0.2 to 5.1.0 Bumps [actions/setup-go](https://github.com/actions/setup-go) from 5.0.2 to 5.1.0. - [Release notes](https://github.com/actions/setup-go/releases) - [Commits](https://github.com/actions/setup-go/compare/0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32...41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed) --- updated-dependencies: - dependency-name: actions/setup-go dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/build.yml | 4 ++-- .github/workflows/codegen.yml | 2 +- .github/workflows/crds-gen.yml | 2 +- .github/workflows/daily-nightly-jobs.yml | 2 +- .github/workflows/docs-check.yml | 2 +- .github/workflows/golangci-lint.yaml | 4 ++-- .github/workflows/mod-check.yml | 2 +- .github/workflows/multus.yaml | 2 +- .github/workflows/push-build.yaml | 2 +- .github/workflows/rbac-gen.yaml | 2 +- .github/workflows/unit-test.yml | 2 +- 11 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2e9922c5af3f..54eee4bfc400 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -25,7 +25,7 @@ jobs: 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" @@ -79,7 +79,7 @@ jobs: 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/codegen.yml b/.github/workflows/codegen.yml index 74fb05769987..7e71466d2956 100644 --- a/.github/workflows/codegen.yml +++ b/.github/workflows/codegen.yml @@ -34,7 +34,7 @@ jobs: 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/crds-gen.yml b/.github/workflows/crds-gen.yml index 8916627bff23..401a51424553 100644 --- a/.github/workflows/crds-gen.yml +++ b/.github/workflows/crds-gen.yml @@ -33,7 +33,7 @@ jobs: 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..069df7be8ec2 100644 --- a/.github/workflows/daily-nightly-jobs.yml +++ b/.github/workflows/daily-nightly-jobs.yml @@ -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" diff --git a/.github/workflows/docs-check.yml b/.github/workflows/docs-check.yml index 265ffff830dc..60636f83d3fd 100644 --- a/.github/workflows/docs-check.yml +++ b/.github/workflows/docs-check.yml @@ -28,7 +28,7 @@ jobs: 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/golangci-lint.yaml b/.github/workflows/golangci-lint.yaml index 89df3980ab52..4fcf39157f12 100644 --- a/.github/workflows/golangci-lint.yaml +++ b/.github/workflows/golangci-lint.yaml @@ -27,7 +27,7 @@ jobs: - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 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/mod-check.yml b/.github/workflows/mod-check.yml index 108eac712b91..cea61078966c 100644 --- a/.github/workflows/mod-check.yml +++ b/.github/workflows/mod-check.yml @@ -33,7 +33,7 @@ jobs: 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..a362b78165fd 100644 --- a/.github/workflows/multus.yaml +++ b/.github/workflows/multus.yaml @@ -41,7 +41,7 @@ jobs: 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" diff --git a/.github/workflows/push-build.yaml b/.github/workflows/push-build.yaml index 8f5c08302461..5e775d9915d9 100644 --- a/.github/workflows/push-build.yaml +++ b/.github/workflows/push-build.yaml @@ -25,7 +25,7 @@ jobs: 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..b41af151b664 100644 --- a/.github/workflows/rbac-gen.yaml +++ b/.github/workflows/rbac-gen.yaml @@ -33,7 +33,7 @@ jobs: 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/unit-test.yml b/.github/workflows/unit-test.yml index 3167fd74315a..fcd76db978d4 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -41,7 +41,7 @@ jobs: 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" From 280cb922abab90e8b65b7cbef4ae7f5dd3664b56 Mon Sep 17 00:00:00 2001 From: Travis Nielsen Date: Fri, 25 Oct 2024 10:25:33 -0600 Subject: [PATCH 18/38] doc: update the roadmap for the 1.16 release The roadmap doc is now updated for v1.16 with potential features and fixes we hope to include. Signed-off-by: Travis Nielsen --- ROADMAP.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) 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) From 3449890365949fa63a6ddbaec8cc6ca448e1e8aa Mon Sep 17 00:00:00 2001 From: Nikhil-Ladha Date: Tue, 29 Oct 2024 14:48:27 +0530 Subject: [PATCH 19/38] multus: remove csi holder pods key removed CSI_DISABLE_HOLDER_PODS from the operator deployment files. Signed-off-by: Nikhil-Ladha --- deploy/examples/operator-openshift.yaml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/deploy/examples/operator-openshift.yaml b/deploy/examples/operator-openshift.yaml index 3b98f9238c1b..36cf43706fb9 100644 --- a/deploy/examples/operator-openshift.yaml +++ b/deploy/examples/operator-openshift.yaml @@ -691,11 +691,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 From ec8878bea849af63d2302313a0aea21c7a02888e Mon Sep 17 00:00:00 2001 From: Nikhil-Ladha Date: Tue, 29 Oct 2024 14:49:41 +0530 Subject: [PATCH 20/38] csv: add generated csv changes add generated csv changes for mutltus key removal Signed-off-by: Nikhil-Ladha --- build/csv/ceph/rook-ceph-operator.clusterserviceversion.yaml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/build/csv/ceph/rook-ceph-operator.clusterserviceversion.yaml b/build/csv/ceph/rook-ceph-operator.clusterserviceversion.yaml index 489cb625a792..da7ae9780bff 100644 --- a/build/csv/ceph/rook-ceph-operator.clusterserviceversion.yaml +++ b/build/csv/ceph/rook-ceph-operator.clusterserviceversion.yaml @@ -3052,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 From d0613826613ddc35de4565c0bdd5e73e1b82217e Mon Sep 17 00:00:00 2001 From: parth-gr Date: Tue, 29 Oct 2024 17:33:35 +0530 Subject: [PATCH 21/38] docs: fix external doc broken links some of the links have the full path which is not working in the doc server, but works locally Signed-off-by: parth-gr --- .../Cluster/external-cluster/advance-external.md | 2 +- .../Cluster/external-cluster/external-cluster.md | 16 ++++++++-------- .../Cluster/external-cluster/upgrade-external.md | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) 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/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. From 8382c084e45ced77a4eb60e9130d2ae21b8592bc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 12:59:54 +0000 Subject: [PATCH 22/38] build(deps): bump the k8s-dependencies group with 7 updates Bumps the k8s-dependencies group with 7 updates: | Package | From | To | | --- | --- | --- | | [k8s.io/api](https://github.com/kubernetes/api) | `0.31.1` | `0.31.2` | | [k8s.io/apiextensions-apiserver](https://github.com/kubernetes/apiextensions-apiserver) | `0.31.1` | `0.31.2` | | [k8s.io/apimachinery](https://github.com/kubernetes/apimachinery) | `0.31.1` | `0.31.2` | | [k8s.io/cli-runtime](https://github.com/kubernetes/cli-runtime) | `0.31.1` | `0.31.2` | | [k8s.io/client-go](https://github.com/kubernetes/client-go) | `0.31.1` | `0.31.2` | | [k8s.io/cloud-provider](https://github.com/kubernetes/cloud-provider) | `0.31.1` | `0.31.2` | | [sigs.k8s.io/controller-runtime](https://github.com/kubernetes-sigs/controller-runtime) | `0.19.0` | `0.19.1` | Updates `k8s.io/api` from 0.31.1 to 0.31.2 - [Commits](https://github.com/kubernetes/api/compare/v0.31.1...v0.31.2) Updates `k8s.io/apiextensions-apiserver` from 0.31.1 to 0.31.2 - [Release notes](https://github.com/kubernetes/apiextensions-apiserver/releases) - [Commits](https://github.com/kubernetes/apiextensions-apiserver/compare/v0.31.1...v0.31.2) Updates `k8s.io/apimachinery` from 0.31.1 to 0.31.2 - [Commits](https://github.com/kubernetes/apimachinery/compare/v0.31.1...v0.31.2) Updates `k8s.io/cli-runtime` from 0.31.1 to 0.31.2 - [Commits](https://github.com/kubernetes/cli-runtime/compare/v0.31.1...v0.31.2) Updates `k8s.io/client-go` from 0.31.1 to 0.31.2 - [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md) - [Commits](https://github.com/kubernetes/client-go/compare/v0.31.1...v0.31.2) Updates `k8s.io/cloud-provider` from 0.31.1 to 0.31.2 - [Commits](https://github.com/kubernetes/cloud-provider/compare/v0.31.1...v0.31.2) Updates `sigs.k8s.io/controller-runtime` from 0.19.0 to 0.19.1 - [Release notes](https://github.com/kubernetes-sigs/controller-runtime/releases) - [Changelog](https://github.com/kubernetes-sigs/controller-runtime/blob/main/RELEASE.md) - [Commits](https://github.com/kubernetes-sigs/controller-runtime/compare/v0.19.0...v0.19.1) --- updated-dependencies: - dependency-name: k8s.io/api dependency-type: direct:production update-type: version-update:semver-patch dependency-group: k8s-dependencies - dependency-name: k8s.io/apiextensions-apiserver dependency-type: direct:production update-type: version-update:semver-patch dependency-group: k8s-dependencies - dependency-name: k8s.io/apimachinery dependency-type: direct:production update-type: version-update:semver-patch dependency-group: k8s-dependencies - dependency-name: k8s.io/cli-runtime dependency-type: direct:production update-type: version-update:semver-patch dependency-group: k8s-dependencies - dependency-name: k8s.io/client-go dependency-type: direct:production update-type: version-update:semver-patch dependency-group: k8s-dependencies - dependency-name: k8s.io/cloud-provider dependency-type: direct:production update-type: version-update:semver-patch dependency-group: k8s-dependencies - dependency-name: sigs.k8s.io/controller-runtime dependency-type: direct:production update-type: version-update:semver-patch dependency-group: k8s-dependencies ... Signed-off-by: dependabot[bot] --- go.mod | 14 +++++++------- go.sum | 28 ++++++++++++++-------------- pkg/apis/go.mod | 6 +++--- pkg/apis/go.sum | 12 ++++++------ 4 files changed, 30 insertions(+), 30 deletions(-) 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/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= From 448f42ab12f0b5e00729c30dba02c1479fe09100 Mon Sep 17 00:00:00 2001 From: Satoru Takeuchi Date: Wed, 30 Oct 2024 00:08:27 +0000 Subject: [PATCH 23/38] test: make debug-ci label work again cmoposite workflow can't use `github` variable. close: https://github.com/rook/rook/issues/14898 Signed-off-by: Satoru Takeuchi --- .github/workflows/canary-integration-test.yml | 21 +++++++++++++++++++ .../integration-test-helm-suite.yaml | 1 + .../integration-test-keystone-auth-suite.yaml | 1 + .../workflows/integration-test-mgr-suite.yaml | 1 + .../integration-test-multi-cluster-suite.yaml | 1 + .../integration-test-object-suite.yaml | 1 + .../integration-test-smoke-suite.yaml | 1 + .../integration-test-upgrade-suite.yaml | 2 ++ .github/workflows/multus.yaml | 1 + .github/workflows/tmate_debug/action.yml | 5 ++++- 10 files changed, 34 insertions(+), 1 deletion(-) diff --git a/.github/workflows/canary-integration-test.yml b/.github/workflows/canary-integration-test.yml index 8069ab2cde78..3c7160c031a7 100644 --- a/.github/workflows/canary-integration-test.yml +++ b/.github/workflows/canary-integration-test.yml @@ -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 @@ -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 @@ -419,6 +421,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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -1146,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 @@ -1216,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 @@ -1273,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 @@ -1532,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 @@ -1627,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 @@ -1656,6 +1675,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 @@ -1737,6 +1757,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/integration-test-helm-suite.yaml b/.github/workflows/integration-test-helm-suite.yaml index f00ccdc79bef..ef077a7d9fca 100644 --- a/.github/workflows/integration-test-helm-suite.yaml +++ b/.github/workflows/integration-test-helm-suite.yaml @@ -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..b27343406215 100644 --- a/.github/workflows/integration-test-keystone-auth-suite.yaml +++ b/.github/workflows/integration-test-keystone-auth-suite.yaml @@ -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..b04029a464f6 100644 --- a/.github/workflows/integration-test-mgr-suite.yaml +++ b/.github/workflows/integration-test-mgr-suite.yaml @@ -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..87c985ea0b97 100644 --- a/.github/workflows/integration-test-multi-cluster-suite.yaml +++ b/.github/workflows/integration-test-multi-cluster-suite.yaml @@ -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..6a5888265eb2 100644 --- a/.github/workflows/integration-test-object-suite.yaml +++ b/.github/workflows/integration-test-object-suite.yaml @@ -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..c6a4016529ae 100644 --- a/.github/workflows/integration-test-smoke-suite.yaml +++ b/.github/workflows/integration-test-smoke-suite.yaml @@ -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..449fa08cf1af 100644 --- a/.github/workflows/integration-test-upgrade-suite.yaml +++ b/.github/workflows/integration-test-upgrade-suite.yaml @@ -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 @@ -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/multus.yaml b/.github/workflows/multus.yaml index 21c172ebf491..f8245eb80f94 100644 --- a/.github/workflows/multus.yaml +++ b/.github/workflows/multus.yaml @@ -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/tmate_debug/action.yml b/.github/workflows/tmate_debug/action.yml index b6a32e5f570d..59f7e833c045 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 }} 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 From 04741fb8996442366ef89cbf955f3398bd0bc41c Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Mon, 28 Oct 2024 16:14:40 +0100 Subject: [PATCH 24/38] build: make generating make targets more systematic This addresses a suggestion from a review comment in another PR. The goal of this change is to make generating make targets more systematic. Firstly, generating targets are made available under a more systematic naming following the pattern of "gen.foo". more concretely, the following targets are introduced as aliases of the corresponding existing targets: * gen.codegen * gen.rbac * gen.crds * gen.docs * gen.crd-docs additionally, a new "generate" make target is added that invokes all generating targets. Co-authored-by: Blaine Gardner Signed-off-by: Michael Adam --- Makefile | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 6fef6948bb21..413f33f6189b 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 @@ -178,19 +179,21 @@ distclean: clean ## Remove all files that are created by building or configuring prune: ## Prune cached artifacts. @$(MAKE) -C images prune -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 +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 \ @@ -218,11 +221,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 From 2ff429e4790921bc6bd6c4d57a81963bf7c12723 Mon Sep 17 00:00:00 2001 From: Travis Nielsen Date: Wed, 30 Oct 2024 14:03:51 -0600 Subject: [PATCH 25/38] csi: remove version check for k8s and cephcsi The version checks for the csi driver are removed now since they are all obsolete. The K8s version and cephcsi versions are no longer checked. Anyway, the move to the csi operator would take ownership of version checks needed in the future, so for now we simplify rook deployment of the csi driver. Signed-off-by: Travis Nielsen --- Documentation/Helm-Charts/operator-chart.md | 1 - .../charts/rook-ceph/templates/configmap.yaml | 3 - deploy/charts/rook-ceph/values.yaml | 3 - deploy/examples/operator-openshift.yaml | 3 - deploy/examples/operator.yaml | 3 - pkg/operator/ceph/csi/controller.go | 20 +-- pkg/operator/ceph/csi/controller_test.go | 1 - pkg/operator/ceph/csi/csi.go | 31 +---- pkg/operator/ceph/csi/spec.go | 81 +---------- pkg/operator/ceph/csi/version.go | 114 ---------------- pkg/operator/ceph/csi/version_test.go | 129 ------------------ 11 files changed, 19 insertions(+), 370 deletions(-) delete mode 100644 pkg/operator/ceph/csi/version.go delete mode 100644 pkg/operator/ceph/csi/version_test.go diff --git a/Documentation/Helm-Charts/operator-chart.md b/Documentation/Helm-Charts/operator-chart.md index 63ec4f542872..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` | diff --git a/deploy/charts/rook-ceph/templates/configmap.yaml b/deploy/charts/rook-ceph/templates/configmap.yaml index 98b99741dbe8..1acc2c5e871d 100644 --- a/deploy/charts/rook-ceph/templates/configmap.yaml +++ b/deploy/charts/rook-ceph/templates/configmap.yaml @@ -169,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/values.yaml b/deploy/charts/rook-ceph/values.yaml index 5b48fc868142..8b5ceb82f197 100644 --- a/deploy/charts/rook-ceph/values.yaml +++ b/deploy/charts/rook-ceph/values.yaml @@ -179,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: diff --git a/deploy/examples/operator-openshift.yaml b/deploy/examples/operator-openshift.yaml index 239b75b16e50..1186fd1841b9 100644 --- a/deploy/examples/operator-openshift.yaml +++ b/deploy/examples/operator-openshift.yaml @@ -183,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" diff --git a/deploy/examples/operator.yaml b/deploy/examples/operator.yaml index 1a90a5193039..b11549be5d32 100644 --- a/deploy/examples/operator.yaml +++ b/deploy/examples/operator.yaml @@ -113,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/pkg/operator/ceph/csi/controller.go b/pkg/operator/ceph/csi/controller.go index e2fc9e39f898..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 ( @@ -178,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'") @@ -203,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") } @@ -218,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") } @@ -280,11 +274,11 @@ func (r *ReconcileCSI) reconcile(request reconcile.Request) (reconcile.Result, e // 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") } @@ -293,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") } @@ -302,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 b1998bab4114..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", 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/spec.go b/pkg/operator/ceph/csi/spec.go index 59af7f601dac..f3e14a68187c 100644 --- a/pkg/operator/ceph/csi/spec.go +++ b/pkg/operator/ceph/csi/spec.go @@ -24,11 +24,8 @@ import ( "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" "github.com/pkg/errors" apps "k8s.io/api/apps/v1" @@ -36,7 +33,6 @@ 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/version" "k8s.io/client-go/kubernetes" ) @@ -117,7 +113,6 @@ var ( EnableCephFS = false EnableNFS = false enableCSIOperator = false - AllowUnsupported = false CustomCSICephConfigExists = false // driver names @@ -178,9 +173,6 @@ var ( ) const ( - kubeMinMajor = "1" - kubeMinVerForCSIDriverSeLinuxMount = "25" - // common tolerations and node affinity provisionerTolerationsEnv = "CSI_PROVISIONER_TOLERATIONS" provisionerNodeAffinityEnv = "CSI_PROVISIONER_NODE_AFFINITY" @@ -234,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 @@ -304,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 @@ -659,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") } @@ -675,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") } @@ -684,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") } @@ -694,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 { @@ -738,66 +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 validateCSIDriverNamePrefix(ctx context.Context, clientset kubernetes.Interface, namespace, driverNamePrefix string) error { if EnableRBD { rbdDriverNamePrefix, err := getCSIDriverNamePrefixFromDeployment(ctx, clientset, namespace, csiRBDProvisioner, "csi-rbdplugin") 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") -} From f60f4443dfbe098c82006bbc6c5ce809c55691d4 Mon Sep 17 00:00:00 2001 From: Travis Nielsen Date: Wed, 30 Oct 2024 15:03:24 -0600 Subject: [PATCH 26/38] test: remove obsolete object user test flag In Rook v1.6 some new properties were added for ceph object store users, so the CI was skipping validation of that setting in the upgrade test. Now we are far past the need for that flag, and we can assume the latest flags exist for the tests. Signed-off-by: Travis Nielsen --- tests/integration/ceph_base_object_test.go | 30 +++++----------------- tests/integration/ceph_object_test.go | 2 +- tests/integration/ceph_upgrade_test.go | 10 ++++---- 3 files changed, 13 insertions(+), 29 deletions(-) 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 db55cd39e4bc..3763a3c1e20a 100644 --- a/tests/integration/ceph_object_test.go +++ b/tests/integration/ceph_object_test.go @@ -167,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) { 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") From 47ca3fd245131151fb8ebdd154140769a9faf79c Mon Sep 17 00:00:00 2001 From: Satoru Takeuchi Date: Wed, 30 Oct 2024 22:53:58 +0000 Subject: [PATCH 27/38] doc: avoid always enabling tmate session tmate session is always enabled by mistake. This bug is introduced in the following PR. https://github.com/rook/rook/pull/14934 We should enable this if `inputs.debug-ci` is `true`. Signed-off-by: Satoru Takeuchi --- .github/workflows/tmate_debug/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tmate_debug/action.yml b/.github/workflows/tmate_debug/action.yml index 59f7e833c045..93c2d5772513 100644 --- a/.github/workflows/tmate_debug/action.yml +++ b/.github/workflows/tmate_debug/action.yml @@ -12,7 +12,7 @@ runs: steps: - name: consider debugging shell: bash --noprofile --norc -eo pipefail -x {0} - if: runner.debug || ${{ inputs.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 From 7fbe4e7db5f4845e98e444460ff5e835d0f66f3f Mon Sep 17 00:00:00 2001 From: Travis Nielsen Date: Wed, 30 Oct 2024 17:00:22 -0600 Subject: [PATCH 28/38] osd: allow scheduling on unschedulable nodes For nodes that are explicitly requested for deploying OSDs, they will be skipped temporarily if not schedulable or not ready. A future reconcile is expected to schedule them. Allow the OSDs to be scheduled even on these nodes that are temporarily down, even if it blocks the reconcile from completing. Signed-off-by: Travis Nielsen --- .../CRDs/Cluster/ceph-cluster-crd.md | 2 + Documentation/CRDs/specification.md | 12 ++++++ .../charts/rook-ceph/templates/resources.yaml | 3 ++ deploy/examples/cluster.yaml | 3 ++ deploy/examples/crds.yaml | 3 ++ pkg/apis/ceph.rook.io/v1/types.go | 3 ++ pkg/operator/ceph/cluster/watcher.go | 4 +- pkg/operator/k8sutil/node.go | 26 +++++++++---- pkg/operator/k8sutil/node_test.go | 38 ++++++++++++------- 9 files changed, 70 insertions(+), 24 deletions(-) diff --git a/Documentation/CRDs/Cluster/ceph-cluster-crd.md b/Documentation/CRDs/Cluster/ceph-cluster-crd.md index fce6603648a1..e6bba7ff5127 100755 --- a/Documentation/CRDs/Cluster/ceph-cluster-crd.md +++ b/Documentation/CRDs/Cluster/ceph-cluster-crd.md @@ -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. diff --git a/Documentation/CRDs/specification.md b/Documentation/CRDs/specification.md index e0b0151097e7..89f570a271dd 100644 --- a/Documentation/CRDs/specification.md +++ b/Documentation/CRDs/specification.md @@ -12821,6 +12821,18 @@ bool +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/deploy/charts/rook-ceph/templates/resources.yaml b/deploy/charts/rook-ceph/templates/resources.yaml index 77ff73089547..9f0e70332b6b 100644 --- a/deploy/charts/rook-ceph/templates/resources.yaml +++ b/deploy/charts/rook-ceph/templates/resources.yaml @@ -3645,6 +3645,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 diff --git a/deploy/examples/cluster.yaml b/deploy/examples/cluster.yaml index 345897fb58bd..e1ec44c237da 100644 --- a/deploy/examples/cluster.yaml +++ b/deploy/examples/cluster.yaml @@ -285,6 +285,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/crds.yaml b/deploy/examples/crds.yaml index b10029784a72..6cbfc7321144 100644 --- a/deploy/examples/crds.yaml +++ b/deploy/examples/crds.yaml @@ -3643,6 +3643,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 diff --git a/pkg/apis/ceph.rook.io/v1/types.go b/pkg/apis/ceph.rook.io/v1/types.go index 633b9153c6b8..da0ef9b5815d 100755 --- a/pkg/apis/ceph.rook.io/v1/types.go +++ b/pkg/apis/ceph.rook.io/v1/types.go @@ -3035,6 +3035,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 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/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{ From f489f99e13de2b335f2ea007738e35fd948cbf60 Mon Sep 17 00:00:00 2001 From: Travis Nielsen Date: Wed, 30 Oct 2024 13:44:11 -0600 Subject: [PATCH 29/38] core: set resources on the cmd reporter jobs If the cmd-reporter key is set under the resources element in the CephCluster CR, the memory and cpu request and limits will be set on the ceph detect version job and network job accordingly. Signed-off-by: Travis Nielsen --- .../CRDs/Cluster/ceph-cluster-crd.md | 1 + deploy/examples/cluster.yaml | 1 + pkg/apis/ceph.rook.io/v1/resources.go | 25 ++++++++++++------- pkg/operator/ceph/controller/network.go | 1 + pkg/operator/ceph/controller/network_test.go | 7 +++--- pkg/operator/ceph/controller/version.go | 1 + .../k8sutil/cmdreporter/cmdreporter.go | 7 ++++++ 7 files changed, 30 insertions(+), 13 deletions(-) diff --git a/Documentation/CRDs/Cluster/ceph-cluster-crd.md b/Documentation/CRDs/Cluster/ceph-cluster-crd.md index fce6603648a1..d76a649d397f 100755 --- a/Documentation/CRDs/Cluster/ceph-cluster-crd.md +++ b/Documentation/CRDs/Cluster/ceph-cluster-crd.md @@ -485,6 +485,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/deploy/examples/cluster.yaml b/deploy/examples/cluster.yaml index 345897fb58bd..68612419b713 100644 --- a/deploy/examples/cluster.yaml +++ b/deploy/examples/cluster.yaml @@ -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: 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/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/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/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() } From 62d99330d6317a5df1f138d1a9de6804a684691f Mon Sep 17 00:00:00 2001 From: Satoru Takeuchi Date: Wed, 30 Oct 2024 07:44:31 +0000 Subject: [PATCH 30/38] doc: clarify dataDirHostPath must be unique for each cluster If there are multiple clusters, `dataDirHostPath` must be unique for each cluster. However, it's not documented yet. In addition, `ceph-teardown.md` was also updated because the original document assumes that `dataDirHostPath` is `/var/lib/rook` and the files for a cluster `rook-ceph` is under `/var/lib/rook/rook-ceph`. related issue: https://github.com/rook/rook/issues/14790 Signed-off-by: Satoru Takeuchi --- Documentation/CRDs/Cluster/ceph-cluster-crd.md | 2 +- Documentation/Storage-Configuration/ceph-teardown.md | 6 +++--- deploy/charts/rook-ceph-cluster/values.yaml | 2 +- deploy/examples/cluster-external-management.yaml | 1 + deploy/examples/cluster-on-local-pvc.yaml | 1 + deploy/examples/cluster-on-pvc-minikube.yaml | 1 + deploy/examples/cluster-on-pvc.yaml | 1 + deploy/examples/cluster-stretched-aws.yaml | 1 + deploy/examples/cluster-stretched.yaml | 1 + deploy/examples/cluster.yaml | 2 +- 10 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Documentation/CRDs/Cluster/ceph-cluster-crd.md b/Documentation/CRDs/Cluster/ceph-cluster-crd.md index fce6603648a1..9268858b2df8 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). diff --git a/Documentation/Storage-Configuration/ceph-teardown.md b/Documentation/Storage-Configuration/ceph-teardown.md index 6196854ed632..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 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/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..3263448eacac 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 From 99d60c5bbabbca3a03956d9a368093632785da6c Mon Sep 17 00:00:00 2001 From: Travis Nielsen Date: Fri, 1 Nov 2024 13:58:48 -0600 Subject: [PATCH 31/38] mds: wait for mds standby upgrade for same fs The upgrade of the mds daemons pauses to wait for the stopping of standby daemons before the filesystem upgrade is completed. If there are multiple filesystems, there could be standbys for other filesystems that will not be stopped at the time of the upgrade of another filesystem. Thus, the standbys may not upgrade and be stuck on the previous version. Now, the standby upgrade will only wait for standbys for the same filesystem. Signed-off-by: Travis Nielsen --- pkg/daemon/ceph/client/filesystem.go | 20 +++++++++++++-- pkg/daemon/ceph/client/filesystem_test.go | 30 ++++++++++++++++++++--- pkg/operator/ceph/file/mds/mds.go | 2 +- 3 files changed, 46 insertions(+), 6 deletions(-) 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/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") } From b229240faadcd93ddc735752bdd1dec7e2e0219e Mon Sep 17 00:00:00 2001 From: Travis Nielsen Date: Mon, 4 Nov 2024 14:10:36 -0700 Subject: [PATCH 32/38] ci: default to the latest stable squid instead of devel The devel images have been fairly stable for Rook to test against, but on occasion there are regressions from Ceph development that affect the Rook CI. For stability during Rook development, use the latest stable version of ceph for PRs, master, and release tests. The daily CI will still use the devel images from Ceph. Signed-off-by: Travis Nielsen --- tests/framework/installer/ceph_installer.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/framework/installer/ceph_installer.go b/tests/framework/installer/ceph_installer.go index 0e2287190a74..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 } } From 9785ef5c8d93a4a85bf656998079306e80b59585 Mon Sep 17 00:00:00 2001 From: parth-gr Date: Wed, 23 Oct 2024 19:42:41 +0530 Subject: [PATCH 33/38] rbdmirror: enable periodic monitoring for rados namespace enable monitoring for rados namespace Signed-off-by: parth-gr --- .../ceph-block-pool-rados-namespace-crd.md | 3 + Documentation/CRDs/specification.md | 383 ++++++++++-------- PendingReleaseNotes.md | 1 + .../charts/rook-ceph/templates/resources.yaml | 137 ++++++- deploy/examples/crds.yaml | 137 ++++++- pkg/apis/ceph.rook.io/v1/types.go | 30 +- .../ceph.rook.io/v1/zz_generated.deepcopy.go | 141 ++++--- pkg/daemon/ceph/client/mirror.go | 16 +- pkg/daemon/ceph/client/mirror_health.go | 225 ++++++++++ pkg/daemon/ceph/client/mirror_health_test.go | 43 ++ pkg/operator/ceph/cluster/rbd/controller.go | 2 +- pkg/operator/ceph/pool/controller.go | 6 +- pkg/operator/ceph/pool/health.go | 117 ------ .../ceph/pool/radosnamespace/controller.go | 93 ++++- .../pool/radosnamespace/controller_test.go | 79 ++-- pkg/operator/ceph/pool/status.go | 74 ---- pkg/operator/ceph/pool/status_test.go | 35 -- 17 files changed, 987 insertions(+), 535 deletions(-) create mode 100644 pkg/daemon/ceph/client/mirror_health.go create mode 100644 pkg/daemon/ceph/client/mirror_health_test.go delete mode 100644 pkg/operator/ceph/pool/health.go 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/specification.md b/Documentation/CRDs/specification.md index dd6949d64ffe..317219f6384e 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,162 +10970,6 @@ 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 -

-

-(Appears on:PoolMirroringStatus) -

-
-

PoolMirroringStatusSummarySpec 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

-

PoolPlacementSpec

@@ -12317,7 +12356,7 @@ string

SnapshotScheduleStatusSpec

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

SnapshotScheduleStatusSpec is the status of the snapshot schedule

@@ -12453,7 +12492,7 @@ string

StatesSpec

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

StatesSpec are rbd images mirroring state

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/deploy/charts/rook-ceph/templates/resources.yaml b/deploy/charts/rook-ceph/templates/resources.yaml index 12c2d1ffbaa8..d6f2613dd483 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 diff --git a/deploy/examples/crds.yaml b/deploy/examples/crds.yaml index 1ffc720b8548..53550a10be2e 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 diff --git a/pkg/apis/ceph.rook.io/v1/types.go b/pkg/apis/ceph.rook.io/v1/types.go index 61812212b663..7d9ee31fe370 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"` @@ -3386,6 +3386,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/daemon/ceph/client/mirror.go b/pkg/daemon/ceph/client/mirror.go index 30b4f3c2486f..a37a95d87589 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/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/pool/controller.go b/pkg/operator/ceph/pool/controller.go index 015d59dea098..df42c92656a4 100644 --- a/pkg/operator/ceph/pool/controller.go +++ b/pkg/operator/ceph/pool/controller.go @@ -297,7 +297,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 +316,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 +353,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, "") } } 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..d67c39520972 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 { @@ -425,6 +440,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 +473,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 +505,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{ From 8ad2bf88bba0cee91e1ed9934f77da1d32c8aac7 Mon Sep 17 00:00:00 2001 From: Artem Torubarov Date: Fri, 1 Nov 2024 14:41:29 +0100 Subject: [PATCH 34/38] rgw: keep default-placement in zone config Signed-off-by: Artem Torubarov --- Documentation/CRDs/specification.md | 4 +- .../charts/rook-ceph/templates/resources.yaml | 10 +- deploy/examples/crds.yaml | 10 +- pkg/apis/ceph.rook.io/v1/types.go | 2 + pkg/operator/ceph/object/objectstore_test.go | 19 +- pkg/operator/ceph/object/shared_pools.go | 58 ++++-- pkg/operator/ceph/object/shared_pools_test.go | 165 +++++++++++++++++- 7 files changed, 233 insertions(+), 35 deletions(-) diff --git a/Documentation/CRDs/specification.md b/Documentation/CRDs/specification.md index e0b0151097e7..df8166674d67 100644 --- a/Documentation/CRDs/specification.md +++ b/Documentation/CRDs/specification.md @@ -10965,7 +10965,9 @@ bool
-

Sets given placement as default. Only one placement in the list can be marked as default.

+(Optional) +

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

diff --git a/deploy/charts/rook-ceph/templates/resources.yaml b/deploy/charts/rook-ceph/templates/resources.yaml index 77ff73089547..f4d0dc5d8a73 100644 --- a/deploy/charts/rook-ceph/templates/resources.yaml +++ b/deploy/charts/rook-ceph/templates/resources.yaml @@ -12384,7 +12384,9 @@ spec: minLength: 1 type: string default: - description: Sets given placement as default. Only one placement in the list can be marked as 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. @@ -12423,7 +12425,6 @@ spec: type: array required: - dataPoolName - - default - metadataPoolName - name type: object @@ -13310,7 +13311,9 @@ spec: minLength: 1 type: string default: - description: Sets given placement as default. Only one placement in the list can be marked as 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. @@ -13349,7 +13352,6 @@ spec: type: array required: - dataPoolName - - default - metadataPoolName - name type: object diff --git a/deploy/examples/crds.yaml b/deploy/examples/crds.yaml index b10029784a72..db2c73513760 100644 --- a/deploy/examples/crds.yaml +++ b/deploy/examples/crds.yaml @@ -12375,7 +12375,9 @@ spec: minLength: 1 type: string default: - description: Sets given placement as default. Only one placement in the list can be marked as 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. @@ -12414,7 +12416,6 @@ spec: type: array required: - dataPoolName - - default - metadataPoolName - name type: object @@ -13298,7 +13299,9 @@ spec: minLength: 1 type: string default: - description: Sets given placement as default. Only one placement in the list can be marked as 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. @@ -13337,7 +13340,6 @@ spec: type: array required: - dataPoolName - - default - metadataPoolName - name type: object diff --git a/pkg/apis/ceph.rook.io/v1/types.go b/pkg/apis/ceph.rook.io/v1/types.go index 633b9153c6b8..26af881c7d1c 100755 --- a/pkg/apis/ceph.rook.io/v1/types.go +++ b/pkg/apis/ceph.rook.io/v1/types.go @@ -1564,6 +1564,8 @@ type PoolPlacementSpec struct { 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. diff --git a/pkg/operator/ceph/object/objectstore_test.go b/pkg/operator/ceph/object/objectstore_test.go index ee5aa4c83dd6..f384d6c704c2 100644 --- a/pkg/operator/ceph/object/objectstore_test.go +++ b/pkg/operator/ceph/object/objectstore_test.go @@ -152,7 +152,7 @@ const ( "notif_pool": "%[1]s:store-a.log.notif" }` - objectZonegroupJsonTempl = `{ + objectZonegroupJson = `{ "id": "610c9e3d-19e7-40b0-9f88-03319c4bc65a", "name": "store-a", "api_name": "test", @@ -174,14 +174,14 @@ const ( ], "placement_targets": [ { - "name": "%[1]s", + "name": "default-placement", "tags": [], "storage_classes": [ "STANDARD" ] } ], - "default_placement": "%[1]s", + "default_placement": "default-placement", "realm_id": "29e28253-be54-4581-90dd-206020d2fcdd", "sync_policy": { "groups": [] @@ -229,7 +229,6 @@ func TestReconcileRealm(t *testing.T) { func TestConfigureStoreWithSharedPools(t *testing.T) { sharedMetaPoolAlreadySet, sharedDataPoolAlreadySet := "", "" - defaultPlacement := defaultPlacementCephConfigName zoneGetCalled := false zoneSetCalled := false zoneGroupGetCalled := false @@ -274,7 +273,7 @@ func TestConfigureStoreWithSharedPools(t *testing.T) { } else if args[0] == "zonegroup" { if args[1] == "get" { zoneGroupGetCalled = true - return fmt.Sprintf(objectZonegroupJsonTempl, defaultPlacement), nil + return objectZonegroupJson, nil } else if args[1] == "set" { zoneGroupSetCalled = true for _, arg := range args { @@ -288,7 +287,7 @@ func TestConfigureStoreWithSharedPools(t *testing.T) { } return string(inBytes), nil } - return fmt.Sprintf(objectZonegroupJsonTempl, defaultPlacement), nil + return objectZonegroupJson, nil } } return "", errors.Errorf("unexpected ceph command %q", args) @@ -331,7 +330,7 @@ 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{ { @@ -342,22 +341,22 @@ func TestConfigureStoreWithSharedPools(t *testing.T) { }, }, } - defaultPlacement = "default" err := ConfigureSharedPoolsForZone(context, sharedPools) assert.NoError(t, err) assert.True(t, zoneGetCalled) 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", DataPoolName: "test-data", } - defaultPlacement = defaultPlacementCephConfigName sharedMetaPoolAlreadySet, sharedDataPoolAlreadySet = "test-meta", "test-data" zoneGetCalled = false zoneSetCalled = false diff --git a/pkg/operator/ceph/object/shared_pools.go b/pkg/operator/ceph/object/shared_pools.go index b447cdf46edd..95bafb14c8af 100644 --- a/pkg/operator/ceph/object/shared_pools.go +++ b/pkg/operator/ceph/object/shared_pools.go @@ -89,7 +89,6 @@ func adjustZonePlacementPools(zone map[string]interface{}, spec cephv1.ObjectSha fromSpec := toZonePlacementPools(spec, name) - defaultPlacementName := getDefaultPlacementName(spec) inConfig := map[string]struct{}{} idxToRemove := map[int]struct{}{} for i, p := range placements { @@ -102,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 != defaultPlacementName { - // 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 { @@ -155,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) @@ -182,16 +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 { - if pp.Default { - hasDefault = true - } - res[pp.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{ @@ -211,6 +235,10 @@ 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 } @@ -493,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 f40306141d1e..81f26b799887 100644 --- a/pkg/operator/ceph/object/shared_pools_test.go +++ b/pkg/operator/ceph/object/shared_pools_test.go @@ -630,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", @@ -655,6 +655,19 @@ func Test_toZonePlacementPools(t *testing.T) { ns: "rgw-instance", }, want: map[string]ZonePlacementPool{ + defaultPlacementCephConfigName: { + Key: defaultPlacementCephConfigName, + Val: ZonePlacementPoolVal{ + 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{ @@ -1444,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, From 97a13628e5a0262896ec583f069d424511daca55 Mon Sep 17 00:00:00 2001 From: Peter Razumovsky Date: Wed, 9 Oct 2024 16:00:00 +0400 Subject: [PATCH 35/38] core: add capabilities to securityContext to fix CIS 5.2.8 Resolves CIS benchmark 5.2.8 rule by adding capabilities with explicitly defined empty "add" list (where it needed) and with NET_RAW capability in "drop" list. 5.2.8 Minimize the admission of containers with added capabilities Containers must drop the `NET_RAW` capability and are not permitted to add back any capabilities. Signed-off-by: Peter Razumovsky --- pkg/operator/ceph/cluster/osd/key_rotation.go | 6 ++++++ pkg/operator/ceph/cluster/osd/provision_spec.go | 6 ++++++ pkg/operator/ceph/cluster/osd/spec.go | 9 +++++++++ pkg/operator/ceph/controller/spec.go | 12 ++++++++++++ .../cephfs/csi-cephfsplugin-provisioner-dep.yaml | 1 + .../csi/template/cephfs/csi-cephfsplugin.yaml | 2 ++ .../nfs/csi-nfsplugin-provisioner-dep.yaml | 16 ++++++++++++++++ .../ceph/csi/template/nfs/csi-nfsplugin.yaml | 1 + .../rbd/csi-rbdplugin-provisioner-dep.yaml | 2 ++ .../ceph/csi/template/rbd/csi-rbdplugin.yaml | 3 +++ 10 files changed, 58 insertions(+) diff --git a/pkg/operator/ceph/cluster/osd/key_rotation.go b/pkg/operator/ceph/cluster/osd/key_rotation.go index ae10ca7b661f..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, } 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 4506d5249a37..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 @@ -913,6 +919,9 @@ func getBlockDevMapperContext() *v1.SecurityContext { Add: []v1.Capability{ "MKNOD", }, + Drop: []v1.Capability{ + "NET_RAW", + }, }, Privileged: &privileged, } 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/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-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-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: From 8dea77255b21897a5c4060cb13ebdee73d481ec5 Mon Sep 17 00:00:00 2001 From: Oded Viner Date: Wed, 23 Oct 2024 20:51:49 +0300 Subject: [PATCH 36/38] pool: fix CephBlockPool enableRBDStats not clearing rbd_stats_pools This PR fixes an issue where disabling enableRBDStats in CephBlockPool did not remove the pool from rbd_stats_pools, leading to unnecessary monitoring. The update ensures that when enableRBDStats is set to false, the pool is properly removed from rbd_stats_pools, optimizing resource tracking. Signed-off-by: Oded Viner --- pkg/operator/ceph/pool/controller.go | 69 ++++++++----- pkg/operator/ceph/pool/controller_test.go | 112 +++++++++++++++++++++- 2 files changed, 152 insertions(+), 29 deletions(-) diff --git a/pkg/operator/ceph/pool/controller.go b/pkg/operator/ceph/pool/controller.go index 015d59dea098..25f583136fb7 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" @@ -419,35 +420,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 +471,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) + }) + } } From 501e0ea0a4d3c59995afcd677954be0b7b169e86 Mon Sep 17 00:00:00 2001 From: Madhu Rajanna Date: Wed, 6 Nov 2024 08:24:01 +0100 Subject: [PATCH 37/38] csi: add new RBAC required for csiaddons csiaddons required new RBAC in the next release to create/update the csiaddonsnode object based on the owner deployment/daemonset names of the pods its running with. Signed-off-by: Madhu Rajanna --- deploy/charts/rook-ceph/templates/role.yaml | 24 ++++++++++++++++++--- deploy/examples/common.yaml | 24 ++++++++++++++++++--- 2 files changed, 42 insertions(+), 6 deletions(-) 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/examples/common.yaml b/deploy/examples/common.yaml index fae242f78d76..e16a78f0dc97 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 From b6113ae7f6059ab90d612d45b35914bef5b1f87e Mon Sep 17 00:00:00 2001 From: Nikhil-Ladha Date: Thu, 7 Nov 2024 18:48:56 +0530 Subject: [PATCH 38/38] csv: add generated changes add generated csv, crds changes Signed-off-by: Nikhil-Ladha --- ....rook.io_cephblockpoolradosnamespaces.yaml | 94 +++++++++++++++++++ build/csv/ceph/ceph.rook.io_cephclusters.yaml | 2 + .../ceph/ceph.rook.io_cephobjectstores.yaml | 1 - .../ceph/ceph.rook.io_cephobjectzones.yaml | 1 - ...k-ceph-operator.clusterserviceversion.yaml | 42 +++++++++ 5 files changed, 138 insertions(+), 2 deletions(-) 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 2a95fe1cc6d3..d56100724710 100644 --- a/build/csv/ceph/ceph.rook.io_cephobjectstores.yaml +++ b/build/csv/ceph/ceph.rook.io_cephobjectstores.yaml @@ -1510,7 +1510,6 @@ spec: type: array required: - dataPoolName - - default - metadataPoolName - name type: object diff --git a/build/csv/ceph/ceph.rook.io_cephobjectzones.yaml b/build/csv/ceph/ceph.rook.io_cephobjectzones.yaml index 9a07c66ecc0b..11bffeb18c99 100644 --- a/build/csv/ceph/ceph.rook.io_cephobjectzones.yaml +++ b/build/csv/ceph/ceph.rook.io_cephobjectzones.yaml @@ -348,7 +348,6 @@ spec: type: array required: - dataPoolName - - default - metadataPoolName - name type: object diff --git a/build/csv/ceph/rook-ceph-operator.clusterserviceversion.yaml b/build/csv/ceph/rook-ceph-operator.clusterserviceversion.yaml index da7ae9780bff..e4f97d1b1b5c 100644 --- a/build/csv/ceph/rook-ceph-operator.clusterserviceversion.yaml +++ b/build/csv/ceph/rook-ceph-operator.clusterserviceversion.yaml @@ -3448,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: @@ -3456,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: @@ -3475,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: