From 5db63d8a18a7054d1a4ff53b5b4f5dbf47feeb03 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Utku=20=C3=96zdemir?= <uoz@protonmail.com>
Date: Fri, 4 Feb 2022 19:56:08 +0100
Subject: [PATCH] fix: do not fail on pvc names longer than 63 characters
 (#150)

Signed-off-by: Utku Ozdemir <uoz@protonmail.com>
---
 helm/pv-migrate/Chart.yaml                    |   4 +-
 helm/pv-migrate/templates/rsync/job.yaml      |  16 ++---
 .../pv-migrate/templates/sshd/deployment.yaml |  16 ++---
 internal/integrationtest/app_test.go          |  65 ++++++++++++++++++
 internal/migrator/migrator.go                 |   2 +-
 internal/migrator/pv-migrate-0.2.0.tgz        | Bin 4264 -> 0 bytes
 internal/migrator/pv-migrate-0.2.1.tgz        | Bin 0 -> 4286 bytes
 7 files changed, 84 insertions(+), 19 deletions(-)
 delete mode 100644 internal/migrator/pv-migrate-0.2.0.tgz
 create mode 100644 internal/migrator/pv-migrate-0.2.1.tgz

diff --git a/helm/pv-migrate/Chart.yaml b/helm/pv-migrate/Chart.yaml
index fb749294..0686ce66 100644
--- a/helm/pv-migrate/Chart.yaml
+++ b/helm/pv-migrate/Chart.yaml
@@ -2,8 +2,8 @@ apiVersion: v2
 name: pv-migrate
 description: The helm chart of pv-migrate
 type: application
-version: 0.2.0
-appVersion: 0.2.0
+version: 0.2.1
+appVersion: 0.2.1
 home: https://github.com/utkuozdemir/pv-migrate
 keywords:
   - pv-migrate
diff --git a/helm/pv-migrate/templates/rsync/job.yaml b/helm/pv-migrate/templates/rsync/job.yaml
index b9999e51..0118a480 100644
--- a/helm/pv-migrate/templates/rsync/job.yaml
+++ b/helm/pv-migrate/templates/rsync/job.yaml
@@ -55,10 +55,10 @@ spec:
           resources:
             {{- toYaml .Values.rsync.resources | nindent 12 }}
           volumeMounts:
-            {{- range .Values.rsync.pvcMounts }}
-            - mountPath: {{ .mountPath }}
-              name: {{ .name }}
-              readOnly: {{ default false .readOnly }}
+            {{- range $index, $mount := .Values.rsync.pvcMounts }}
+            - mountPath: {{ $mount.mountPath }}
+              name: vol-{{ $index }}
+              readOnly: {{ default false $mount.readOnly }}
             {{- end }}
             {{- if .Values.rsync.privateKeyMount }}
             - mountPath: {{ .Values.rsync.privateKeyMountPath }}
@@ -79,11 +79,11 @@ spec:
         {{- toYaml . | nindent 8 }}
       {{- end }}
       volumes:
-        {{- range .Values.rsync.pvcMounts }}
-        - name: {{ .name }}
+        {{- range $index, $mount := .Values.rsync.pvcMounts }}
+        - name: vol-{{ $index }}
           persistentVolumeClaim:
-            claimName: {{ required ".Values.rsync.pvcMounts[*].pvcName is required!" .name }}
-            readOnly: {{ default false .readOnly }}
+            claimName: {{ required ".Values.rsync.pvcMounts[*].pvcName is required!" $mount.name }}
+            readOnly: {{ default false $mount.readOnly }}
         {{- end }}
         {{- if .Values.rsync.privateKeyMount }}
         - name: private-key
diff --git a/helm/pv-migrate/templates/sshd/deployment.yaml b/helm/pv-migrate/templates/sshd/deployment.yaml
index 6d85f5d4..0d47c620 100644
--- a/helm/pv-migrate/templates/sshd/deployment.yaml
+++ b/helm/pv-migrate/templates/sshd/deployment.yaml
@@ -40,10 +40,10 @@ spec:
           resources:
             {{- toYaml .Values.sshd.resources | nindent 12 }}
           volumeMounts:
-            {{- range .Values.sshd.pvcMounts }}
-            - mountPath: {{ .mountPath }}
-              name: {{ .name }}
-              readOnly: {{ default false .readOnly }}
+            {{- range $index, $mount := .Values.sshd.pvcMounts }}
+            - mountPath: {{ $mount.mountPath }}
+              name: vol-{{ $index }}
+              readOnly: {{ default false $mount.readOnly }}
             {{- end }}
             {{- if .Values.sshd.publicKeyMount }}
             - mountPath: {{ .Values.sshd.publicKeyMountPath }}
@@ -69,11 +69,11 @@ spec:
         {{- toYaml . | nindent 8 }}
       {{- end }}
       volumes:
-      {{- range .Values.sshd.pvcMounts }}
-      - name: {{ .name }}
+      {{- range $index, $mount := .Values.sshd.pvcMounts }}
+      - name: vol-{{ $index }}
         persistentVolumeClaim:
-          claimName: {{ required ".Values.sshd.pvcMounts[*].pvcName is required!" .name }}
-          readOnly: {{ default false .readOnly }}
+          claimName: {{ required ".Values.sshd.pvcMounts[*].pvcName is required!" $mount.name }}
+          readOnly: {{ default false $mount.readOnly }}
       {{- end }}
       {{- if or .Values.sshd.publicKeyMount .Values.sshd.privateKeyMount }}
       - name: keys
diff --git a/internal/integrationtest/app_test.go b/internal/integrationtest/app_test.go
index 81e00937..f277a0a4 100644
--- a/internal/integrationtest/app_test.go
+++ b/internal/integrationtest/app_test.go
@@ -37,6 +37,9 @@ const (
 	dataFilePath        = "/volume/file.txt"
 	extraDataFilePath   = "/volume/extra_file.txt"
 	generateDataContent = "DATA"
+
+	longSourcePvcName = "source-source-source-source-source-source-source-source-source-source-source-source-source-source-source-source-source-source-source-source-source-source-source-source-source-source-source"
+	longDestPvcName   = "dest-dest-dest-dest-dest-dest-dest-dest-dest-dest-dest-dest-dest-dest-dest-dest-dest-dest-dest-dest-dest-dest-dest-dest-dest-dest-dest-dest-dest-dest-dest-dest-dest-dest-dest-dest-dest-dest"
 )
 
 var (
@@ -299,6 +302,28 @@ func TestLocal(t *testing.T) {
 	assert.NoError(t, err)
 }
 
+func TestLongPVCNames(t *testing.T) {
+	_, err := execInPod(mainClusterCli, ns1, "long-dest", clearDataShellCommand)
+	assert.NoError(t, err)
+
+	cmd := fmt.Sprintf("--log-level debug m -i -n %s -N %s %s %s",
+		ns1, ns1, longSourcePvcName, longDestPvcName)
+	assert.NoError(t, runCliApp(cmd))
+
+	stdout, err := execInPod(mainClusterCli, ns1, "long-dest", printDataUidGidContentShellCommand)
+	assert.NoError(t, err)
+
+	parts := strings.Split(stdout, "\n")
+	assert.Equal(t, len(parts), 3)
+	if len(parts) < 3 {
+		return
+	}
+
+	assert.Equal(t, dataFileUid, parts[0])
+	assert.Equal(t, dataFileGid, parts[1])
+	assert.Equal(t, generateDataContent, parts[2])
+}
+
 func setup() error {
 	homeDir, err := userHomeDir()
 	if err != nil {
@@ -342,6 +367,11 @@ func setup() error {
 		return err
 	}
 
+	err = setupPVCsWithLongName()
+	if err != nil {
+		return err
+	}
+
 	_, err = createPVC(mainClusterCli, ns1, "source")
 	if err != nil {
 		return err
@@ -426,6 +456,41 @@ func setup() error {
 	return err
 }
 
+func setupPVCsWithLongName() error {
+	_, err := createPVC(mainClusterCli, ns1, longSourcePvcName)
+	if err != nil {
+		return err
+	}
+
+	_, err = createPVC(mainClusterCli, ns1, longDestPvcName)
+	if err != nil {
+		return err
+	}
+
+	_, err = createPod(mainClusterCli, ns1, "long-source", longSourcePvcName)
+	if err != nil {
+		return err
+	}
+
+	_, err = createPod(mainClusterCli, ns1, "long-dest", longDestPvcName)
+	if err != nil {
+		return err
+	}
+
+	err = waitUntilPodIsRunning(mainClusterCli, ns1, "long-source")
+	if err != nil {
+		return err
+	}
+
+	err = waitUntilPodIsRunning(mainClusterCli, ns1, "long-dest")
+	if err != nil {
+		return err
+	}
+
+	_, err = execInPod(mainClusterCli, ns1, "long-source", generateDataShellCommand)
+	return err
+}
+
 func teardown() error {
 	var result *multierror.Error
 	err := deleteNs(mainClusterCli, ns1)
diff --git a/internal/migrator/migrator.go b/internal/migrator/migrator.go
index 0e138883..09f49572 100644
--- a/internal/migrator/migrator.go
+++ b/internal/migrator/migrator.go
@@ -16,7 +16,7 @@ import (
 	"helm.sh/helm/v3/pkg/chart/loader"
 )
 
-//go:embed pv-migrate-0.2.0.tgz
+//go:embed pv-migrate-0.2.1.tgz
 var chartBytes []byte
 
 type (
diff --git a/internal/migrator/pv-migrate-0.2.0.tgz b/internal/migrator/pv-migrate-0.2.0.tgz
deleted file mode 100644
index 19a9a293ec80800ace2dca9f4eecafe881aeba03..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 4264
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

diff --git a/internal/migrator/pv-migrate-0.2.1.tgz b/internal/migrator/pv-migrate-0.2.1.tgz
new file mode 100644
index 0000000000000000000000000000000000000000..58f45d35b2fc9636ed2bd7977e1f1a8a0e8961b7
GIT binary patch
literal 4286
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
IP{zOj0B)CnBme*a

literal 0
HcmV?d00001

-- 
GitLab