From e928a68b32604f0676964e3363439476c6f8f1d8 Mon Sep 17 00:00:00 2001 From: "openshift-merge-bot[bot]" <148852131+openshift-merge-bot[bot]@users.noreply.github.com> Date: Thu, 30 Jan 2025 23:30:05 +0000 Subject: [PATCH] Merge pull request #1519 from tesshuflower/resourcenamelimit_63chars Resourcenamelimit 63chars (cherry picked from commit 9dc08b29d5b63fdb0843302303ac90552faafd5f) Signed-off-by: Tesshu Flower --- CHANGELOG.md | 2 + controllers/mover/rclone/mover.go | 2 +- controllers/mover/rclone/rclone_test.go | 24 ++ controllers/mover/restic/mover.go | 2 +- controllers/mover/restic/restic_test.go | 25 ++ controllers/mover/rsync/mover.go | 6 +- controllers/mover/rsync/rsync_test.go | 55 ++++ controllers/mover/rsynctls/mover.go | 6 +- controllers/mover/rsynctls/rsync_test.go | 55 ++++ controllers/mover/syncthing/mover.go | 19 +- controllers/mover/syncthing/syncthing_test.go | 39 +++ controllers/utils/utils.go | 39 +++ controllers/utils/utils_test.go | 81 ++++++ custom-scorecard-tests/config-downstream.yaml | 124 ++++++--- custom-scorecard-tests/config.yaml | 124 ++++++--- .../generateE2ETestsConfig.sh | 4 +- .../bases/patches/e2e-tests-stage1.yaml | 122 ++------- .../bases/patches/e2e-tests-stage2.yaml | 130 +++++++++ helm/volsync/Chart.yaml | 2 + .../tasks/main.yml | 6 +- .../test_restic_manual_normal_longname.yml | 237 ++++++++++++++++ test-e2e/test_rsync_tls_normal_longname.yml | 256 ++++++++++++++++++ test-e2e/test_simple_rsync_longname.yml | 202 ++++++++++++++ ...syncthing_cluster_sync_normal_longname.yml | 35 +++ 24 files changed, 1393 insertions(+), 204 deletions(-) create mode 100644 test-e2e/test_restic_manual_normal_longname.yml create mode 100644 test-e2e/test_rsync_tls_normal_longname.yml create mode 100644 test-e2e/test_simple_rsync_longname.yml create mode 100644 test-e2e/test_syncthing_cluster_sync_normal_longname.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ae2d1eb5..15a72268b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - All movers should return error if not able to EnsurePVCFromSrc +- Fix for mover job/service name length too long (>63 chars) if the + replicationsource or replicationdestination CR name is too long ### Security diff --git a/controllers/mover/rclone/mover.go b/controllers/mover/rclone/mover.go index b4cf316c4..b245b8243 100644 --- a/controllers/mover/rclone/mover.go +++ b/controllers/mover/rclone/mover.go @@ -226,7 +226,7 @@ func (m *Mover) ensureJob(ctx context.Context, dataPVC *corev1.PersistentVolumeC job := &batchv1.Job{ ObjectMeta: metav1.ObjectMeta{ - Name: mover.VolSyncPrefix + "rclone-" + dir + "-" + m.owner.GetName(), + Name: utils.GetJobName(mover.VolSyncPrefix+"rclone-"+dir+"-", m.owner), Namespace: m.owner.GetNamespace(), }, } diff --git a/controllers/mover/rclone/rclone_test.go b/controllers/mover/rclone/rclone_test.go index 2503858ca..38e2aa706 100644 --- a/controllers/mover/rclone/rclone_test.go +++ b/controllers/mover/rclone/rclone_test.go @@ -1157,6 +1157,30 @@ var _ = Describe("Rclone as a source", func() { Expect(job.Spec.Template.Spec.Containers[0].Resources).To(Equal(corev1.ResourceRequirements{})) }) + When("The ReplicationSource CR name is very long", func() { + BeforeEach(func() { + rs.Name = "very-long-name-will-cause-job-name-to-be-evenlongerthan63chars" + }) + + It("The job name should be shortened appropriately (should handle long CR names)", func() { + j, e := mover.ensureJob(ctx, sPVC, sa, rcloneConfigSecret, nil) // Using sPVC as dataPVC (i.e. direct) + Expect(e).NotTo(HaveOccurred()) + Expect(j).To(BeNil()) // hasn't completed + + jobs := &batchv1.JobList{} + Expect(k8sClient.List(ctx, jobs, client.InNamespace(rs.Namespace))).To(Succeed()) + Expect(len(jobs.Items)).To(Equal(1)) + moverJob := jobs.Items[0] + + // Reload the replicationsource to see that it got updated + Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(rs), rs)).To(Succeed()) + + Expect(moverJob.GetName()).To(ContainSubstring(utils.GetHashedName(rs.GetName()))) + // Make sure our shortened name is actually short enough + Expect(len(moverJob.GetName()) > 63).To(BeFalse()) + }) + }) + When("moverResources (resource requirements) are provided", func() { BeforeEach(func() { rs.Spec.Rclone.MoverResources = &corev1.ResourceRequirements{ diff --git a/controllers/mover/restic/mover.go b/controllers/mover/restic/mover.go index a54483dc6..2d99b4e4d 100644 --- a/controllers/mover/restic/mover.go +++ b/controllers/mover/restic/mover.go @@ -290,7 +290,7 @@ func (m *Mover) ensureJob(ctx context.Context, cachePVC *corev1.PersistentVolume job := &batchv1.Job{ ObjectMeta: metav1.ObjectMeta{ - Name: mover.VolSyncPrefix + dir + "-" + m.owner.GetName(), + Name: utils.GetJobName(mover.VolSyncPrefix+dir+"-", m.owner), Namespace: m.owner.GetNamespace(), }, } diff --git a/controllers/mover/restic/restic_test.go b/controllers/mover/restic/restic_test.go index 9301ba31a..745f3e536 100644 --- a/controllers/mover/restic/restic_test.go +++ b/controllers/mover/restic/restic_test.go @@ -1335,6 +1335,31 @@ var _ = Describe("Restic as a source", func() { Expect(psc.RunAsUser).To(BeNil()) Expect(psc.FSGroup).To(BeNil()) }) + + When("The ReplicationSource CR name is very long", func() { + BeforeEach(func() { + rs.Name = "very-long-name-will-cause-job-name-to-be-evenlongerthan63chars" + }) + + It("The job name should be shortened appropriately (should handle long CR names)", func() { + j, e := mover.ensureJob(ctx, cache, sPVC, sa, repo, nil) + Expect(e).NotTo(HaveOccurred()) + Expect(j).To(BeNil()) // hasn't completed + + jobs := &batchv1.JobList{} + Expect(k8sClient.List(ctx, jobs, client.InNamespace(rs.Namespace))).To(Succeed()) + Expect(len(jobs.Items)).To(Equal(1)) + moverJob := jobs.Items[0] + + // Reload the replicationsource to see that it got updated + Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(rs), rs)).To(Succeed()) + + Expect(moverJob.GetName()).To(ContainSubstring(utils.GetHashedName(rs.GetName()))) + // Make sure our shortened name is actually short enough + Expect(len(moverJob.GetName()) > 63).To(BeFalse()) + }) + }) + When("A moverSecurityContext is provided", func() { BeforeEach(func() { rs.Spec.Restic.MoverSecurityContext = &corev1.PodSecurityContext{ diff --git a/controllers/mover/rsync/mover.go b/controllers/mover/rsync/mover.go index 8df931788..05db56f71 100644 --- a/controllers/mover/rsync/mover.go +++ b/controllers/mover/rsync/mover.go @@ -149,7 +149,7 @@ func (m *Mover) ensureServiceAndPublishAddress(ctx context.Context) (bool, error service := &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ - Name: volSyncRsyncPrefix + m.direction() + "-" + m.owner.GetName(), + Name: utils.GetServiceName(volSyncRsyncPrefix+m.direction()+"-", m.owner), Namespace: m.owner.GetNamespace(), }, } @@ -279,7 +279,7 @@ func (m *Mover) direction() string { func (m *Mover) serviceSelector() map[string]string { return map[string]string{ - "app.kubernetes.io/name": m.direction() + "-" + m.owner.GetName(), + "app.kubernetes.io/name": utils.GetOwnerNameLabelValue(m.direction()+"-", m.owner), "app.kubernetes.io/component": "rsync-mover", "app.kubernetes.io/part-of": "volsync", } @@ -355,7 +355,7 @@ func (m *Mover) ensureJob(ctx context.Context, dataPVC *corev1.PersistentVolumeC sa *corev1.ServiceAccount, rsyncSecretName string) (*batchv1.Job, error) { job := &batchv1.Job{ ObjectMeta: metav1.ObjectMeta{ - Name: volSyncRsyncPrefix + m.direction() + "-" + m.owner.GetName(), + Name: utils.GetJobName(volSyncRsyncPrefix+m.direction()+"-", m.owner), Namespace: m.owner.GetNamespace(), }, } diff --git a/controllers/mover/rsync/rsync_test.go b/controllers/mover/rsync/rsync_test.go index 4bd3ee115..0110959e1 100644 --- a/controllers/mover/rsync/rsync_test.go +++ b/controllers/mover/rsync/rsync_test.go @@ -726,6 +726,30 @@ var _ = Describe("Rsync as a source", func() { Expect(job.Spec.Template.Spec.ServiceAccountName).To(Equal(sa.Name)) }) + When("The ReplicationSource CR name is very long", func() { + BeforeEach(func() { + rs.Name = "very-long-name-will-cause-job-name-to-be-evenlongerthan63chars" + }) + + It("The job name should be shortened appropriately (should handle long CR names)", func() { + j, e := mover.ensureJob(ctx, sPVC, sa, sshKeysSecret.GetName()) // Using sPVC as dataPVC (i.e. direct) + Expect(e).NotTo(HaveOccurred()) + Expect(j).To(BeNil()) // hasn't completed + + jobs := &batchv1.JobList{} + Expect(k8sClient.List(ctx, jobs, client.InNamespace(rs.Namespace))).To(Succeed()) + Expect(len(jobs.Items)).To(Equal(1)) + moverJob := jobs.Items[0] + + // Reload the replicationsource to see that it got updated + Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(rs), rs)).To(Succeed()) + + Expect(moverJob.GetName()).To(ContainSubstring(utils.GetHashedName(rs.GetName()))) + // Make sure our shortened name is actually short enough + Expect(len(moverJob.GetName()) > 63).To(BeFalse()) + }) + }) + It("Should not have container resourceRequirements set by default", func() { j, e := mover.ensureJob(ctx, sPVC, sa, sshKeysSecret.GetName()) // Using sPVC as dataPVC (i.e. direct) Expect(e).NotTo(HaveOccurred()) @@ -1283,6 +1307,37 @@ var _ = Describe("Rsync as a destination", func() { }) }) + Context("Service handled properly when replicationdestination name is very long", func() { + BeforeEach(func() { + rd.Name = "very-long-name-will-cause-job-name-to-be-evenlongerthan63chars" + }) + + It("The service name should be shortened appropriately (should handle long CR names)", func() { + // create the svc + result, err := mover.ensureServiceAndPublishAddress(ctx) + Expect(err).To(BeNil()) + + if !result { + // This means the svc address wasn't populated immediately + // Keep reconciling - when service has address populated it should get updated in the rs status) + Eventually(func() bool { + gotAddr, err := mover.ensureServiceAndPublishAddress(ctx) + return err != nil && gotAddr + }, maxWait, interval).Should(BeTrue()) + } + + // Find the service + svcs := &corev1.ServiceList{} + Expect(k8sClient.List(ctx, svcs, client.InNamespace(rd.Namespace))).To(Succeed()) + Expect(len(svcs.Items)).To(Equal(1)) + rdSvc := svcs.Items[0] + + Expect(rdSvc.GetName()).To(ContainSubstring(utils.GetHashedName(rd.GetName()))) + // Make sure our shortened name is actually short enough + Expect(len(rdSvc.GetName()) > 63).To(BeFalse()) + }) + }) + //nolint:dupl Context("Service and address are handled properly", func() { When("when no remote address is specified", func() { diff --git a/controllers/mover/rsynctls/mover.go b/controllers/mover/rsynctls/mover.go index b11d56d12..e967c79cf 100644 --- a/controllers/mover/rsynctls/mover.go +++ b/controllers/mover/rsynctls/mover.go @@ -153,7 +153,7 @@ func (m *Mover) ensureServiceAndPublishAddress(ctx context.Context) (bool, error service := &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ - Name: volSyncRsyncTLSPrefix + m.direction() + "-" + m.owner.GetName(), + Name: utils.GetServiceName(volSyncRsyncTLSPrefix+m.direction()+"-", m.owner), Namespace: m.owner.GetNamespace(), }, } @@ -285,7 +285,7 @@ func (m *Mover) direction() string { func (m *Mover) serviceSelector() map[string]string { return map[string]string{ - "app.kubernetes.io/name": m.direction() + "-" + m.owner.GetName(), + "app.kubernetes.io/name": utils.GetOwnerNameLabelValue(m.direction()+"-", m.owner), "app.kubernetes.io/component": "rsync-tls-mover", "app.kubernetes.io/part-of": "volsync", } @@ -361,7 +361,7 @@ func (m *Mover) ensureJob(ctx context.Context, dataPVC *corev1.PersistentVolumeC sa *corev1.ServiceAccount, rsyncSecretName string) (*batchv1.Job, error) { job := &batchv1.Job{ ObjectMeta: metav1.ObjectMeta{ - Name: volSyncRsyncTLSPrefix + m.direction() + "-" + m.owner.GetName(), + Name: utils.GetJobName(volSyncRsyncTLSPrefix+m.direction()+"-", m.owner), Namespace: m.owner.GetNamespace(), }, } diff --git a/controllers/mover/rsynctls/rsync_test.go b/controllers/mover/rsynctls/rsync_test.go index 8fda50fd1..97220be11 100644 --- a/controllers/mover/rsynctls/rsync_test.go +++ b/controllers/mover/rsynctls/rsync_test.go @@ -1163,6 +1163,30 @@ var _ = Describe("RsyncTLS as a source", func() { Expect(job.Spec.Template.Spec.ServiceAccountName).To(Equal(sa.Name)) }) + When("The ReplicationSource CR name is very long", func() { + BeforeEach(func() { + rs.Name = "very-long-name-will-cause-job-name-to-be-evenlongerthan63chars" + }) + + It("The job name should be shortened appropriately (should handle long CR names)", func() { + j, e := mover.ensureJob(ctx, sPVC, sa, tlsKeySecret.GetName()) // Using sPVC as dataPVC (i.e. direct) + Expect(e).NotTo(HaveOccurred()) + Expect(j).To(BeNil()) // hasn't completed + + jobs := &batchv1.JobList{} + Expect(k8sClient.List(ctx, jobs, client.InNamespace(rs.Namespace))).To(Succeed()) + Expect(len(jobs.Items)).To(Equal(1)) + moverJob := jobs.Items[0] + + // Reload the replicationsource to see that it got updated + Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(rs), rs)).To(Succeed()) + + Expect(moverJob.GetName()).To(ContainSubstring(utils.GetHashedName(rs.GetName()))) + // Make sure our shortened name is actually short enough + Expect(len(moverJob.GetName()) > 63).To(BeFalse()) + }) + }) + getSPVC := func() *corev1.PersistentVolumeClaim { return sPVC } @@ -1690,6 +1714,37 @@ var _ = Describe("Rsync as a destination", func() { }) }) + Context("Service handled properly when replicationdestination name is very long", func() { + BeforeEach(func() { + rd.Name = "very-long-name-will-cause-job-name-to-be-evenlongerthan63chars" + }) + + It("The service name should be shortened appropriately (should handle long CR names)", func() { + // create the svc + result, err := mover.ensureServiceAndPublishAddress(ctx) + Expect(err).To(BeNil()) + + if !result { + // This means the svc address wasn't populated immediately + // Keep reconciling - when service has address populated it should get updated in the rs status) + Eventually(func() bool { + gotAddr, err := mover.ensureServiceAndPublishAddress(ctx) + return err != nil && gotAddr + }, maxWait, interval).Should(BeTrue()) + } + + // Find the service + svcs := &corev1.ServiceList{} + Expect(k8sClient.List(ctx, svcs, client.InNamespace(rd.Namespace))).To(Succeed()) + Expect(len(svcs.Items)).To(Equal(1)) + rdSvc := svcs.Items[0] + + Expect(rdSvc.GetName()).To(ContainSubstring(utils.GetHashedName(rd.GetName()))) + // Make sure our shortened name is actually short enough + Expect(len(rdSvc.GetName()) > 63).To(BeFalse()) + }) + }) + //nolint:dupl Context("Service and address are handled properly", func() { var svc *corev1.Service diff --git a/controllers/mover/syncthing/mover.go b/controllers/mover/syncthing/mover.go index 33a273577..73f518add 100644 --- a/controllers/mover/syncthing/mover.go +++ b/controllers/mover/syncthing/mover.go @@ -304,7 +304,7 @@ func (m *Mover) ensureDataPVC(ctx context.Context) (*corev1.PersistentVolumeClai // serviceSelector Returns a mapping of standardized Kubernetes labels. func (m *Mover) serviceSelector() map[string]string { return map[string]string{ - "app.kubernetes.io/name": m.owner.GetName(), + "app.kubernetes.io/name": utils.GetOwnerNameLabelValue("", m.owner), "app.kubernetes.io/component": "syncthing-mover", "app.kubernetes.io/part-of": "volsync", } @@ -386,7 +386,7 @@ func (m *Mover) ensureDeployment(ctx context.Context, dataPVC *corev1.Persistent Name: deploymentName, Namespace: m.owner.GetNamespace(), Labels: map[string]string{ - "app": m.owner.GetName(), + "app": utils.GetOwnerNameLabelValue("", m.owner), }, }, } @@ -603,7 +603,7 @@ func (m *Mover) ensureAPIService(ctx context.Context, deployment *appsv1.Deploym // ensureDataService Ensures that a service exposing the Syncthing data is present, else it will be created. // This service allows Syncthing to share data with the rest of the world. func (m *Mover) ensureDataService(ctx context.Context, deployment *appsv1.Deployment) (*corev1.Service, error) { - serviceName := mover.VolSyncPrefix + m.owner.GetName() + "-data" //nolint:goconst // goconst thinks -data is used 3x + serviceName := m.getDataServiceName() service := &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ Name: serviceName, @@ -832,6 +832,19 @@ func (m *Mover) getConnectedPeers(syncthing *api.Syncthing) []volsyncv1alpha1.Sy // getAPIServiceName Returns the name of the API service exposing the Syncthing API. func (m *Mover) getAPIServiceName() string { serviceName := mover.VolSyncPrefix + m.owner.GetName() + "-api" + + if len(serviceName) > 63 { + serviceName = mover.VolSyncPrefix + "api-" + utils.GetHashedName(m.owner.GetName()) + } + return serviceName +} + +func (m *Mover) getDataServiceName() string { + serviceName := mover.VolSyncPrefix + m.owner.GetName() + "-data" //nolint:goconst // goconst thinks -data is used 3x + + if len(serviceName) > 63 { + serviceName = mover.VolSyncPrefix + "data-" + utils.GetHashedName(m.owner.GetName()) + } return serviceName } diff --git a/controllers/mover/syncthing/syncthing_test.go b/controllers/mover/syncthing/syncthing_test.go index efd8ec6ac..818e04ce0 100644 --- a/controllers/mover/syncthing/syncthing_test.go +++ b/controllers/mover/syncthing/syncthing_test.go @@ -30,6 +30,7 @@ import ( volsyncv1alpha1 "github.com/backube/volsync/api/v1alpha1" cMover "github.com/backube/volsync/controllers/mover" "github.com/backube/volsync/controllers/mover/syncthing/api" + "github.com/backube/volsync/controllers/utils" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/syncthing/syncthing/lib/config" @@ -287,6 +288,10 @@ var _ = Describe("When an RS specifies Syncthing", func() { Expect(err).NotTo(HaveOccurred()) Expect(deployment).NotTo(BeNil()) + appLabel, ok := deployment.GetLabels()["app"] + Expect(ok).To(BeTrue()) + Expect(appLabel).To(Equal(rs.GetName())) + // make sure the service is created svc, err := mover.ensureDataService(ctx, deployment) Expect(err).NotTo(HaveOccurred()) @@ -294,6 +299,40 @@ var _ = Describe("When an RS specifies Syncthing", func() { Expect(svc.Spec.Type).To(Equal(corev1.ServiceTypeClusterIP)) }) + When("replicationsource CR name is very long", func() { + JustBeforeEach(func() { + rs.Name = "super-very-extra-long-name-that-will-definitely-need-to-be-truncated" + }) + + It("Should be able to create a deployment and api and data service", func() { + // get a deployment + deployment, err := mover.ensureDeployment(ctx, srcPVC, configPVC, sa, apiSecret) + Expect(err).NotTo(HaveOccurred()) + Expect(deployment).NotTo(BeNil()) + + appLabel, ok := deployment.GetLabels()["app"] + Expect(ok).To(BeTrue()) + Expect(appLabel).To(ContainSubstring(utils.GetHashedName(rs.GetName()))) + Expect(len(appLabel) > 63).To(BeFalse()) + + // make sure the api service is created + apiSvc, err := mover.ensureAPIService(ctx, deployment) + Expect(err).NotTo(HaveOccurred()) + Expect(apiSvc).NotTo(BeNil()) + Expect(apiSvc.GetName()).To(ContainSubstring(utils.GetHashedName(rs.GetName()))) + // Make sure our shortened name is actually short enough + Expect(len(apiSvc.GetName()) > 63).To(BeFalse()) + + // make sure the data service is created + dataSvc, err := mover.ensureDataService(ctx, deployment) + Expect(err).NotTo(HaveOccurred()) + Expect(dataSvc).NotTo(BeNil()) + Expect(dataSvc.GetName()).To(ContainSubstring(utils.GetHashedName(rs.GetName()))) + // Make sure our shortened name is actually short enough + Expect(len(dataSvc.GetName()) > 63).To(BeFalse()) + }) + }) + It("Can get DataServiceAddress", func() { // test data const staticIP string = "1.2.3.4" diff --git a/controllers/utils/utils.go b/controllers/utils/utils.go index 1bad88b39..18c8a58a1 100644 --- a/controllers/utils/utils.go +++ b/controllers/utils/utils.go @@ -20,6 +20,7 @@ package utils import ( "context" "fmt" + "hash/crc32" "os" "sort" "strings" @@ -42,6 +43,10 @@ import ( // Define the error messages to be returned by VolSync. const ( ErrUnableToSetControllerRef = "unable to set controller reference" + + JobNameMaxLength = 63 + ServiceNameMaxLength = 63 + LabelValueMaxLength = 63 ) // Check if error is due to the CRD not being present (API kind/group not available) @@ -255,3 +260,37 @@ func UpdatePodTemplateSpecFromMoverConfig(podTemplateSpec *corev1.PodTemplateSpe podTemplateSpec.Labels[label] = value } } + +// Will return a name with prefix + owner.Name unless it's too long, in which +// case we will return prefix + owner.UID +// (This assumes namePrefix + UID is shorter than 63 chars) +func GetJobName(namePrefix string, owner client.Object) string { + return getShortenedResourceName(namePrefix, owner, JobNameMaxLength) +} + +// Will return a name with prefix + owner.Name unless it's too long, in which +// case we will return prefix + owner.UID +// (This assumes namePrefix + UID is shorter than 63 chars) +func GetServiceName(namePrefix string, owner client.Object) string { + return getShortenedResourceName(namePrefix, owner, ServiceNameMaxLength) +} + +func GetOwnerNameLabelValue(namePrefix string, owner client.Object) string { + return getShortenedResourceName(namePrefix, owner, LabelValueMaxLength) +} + +func getShortenedResourceName(namePrefix string, owner client.Object, maxLength int) string { + name := namePrefix + owner.GetName() + + if len(name) > maxLength { + // Use crc32 to hash the owner CR name + return namePrefix + GetHashedName(owner.GetName()) + } + + // No need to shorten, use original name + return name +} + +func GetHashedName(name string) string { + return fmt.Sprintf("%08x", crc32.ChecksumIEEE([]byte(name))) +} diff --git a/controllers/utils/utils_test.go b/controllers/utils/utils_test.go index 65980ee5c..828a13965 100644 --- a/controllers/utils/utils_test.go +++ b/controllers/utils/utils_test.go @@ -583,4 +583,85 @@ var _ = Describe("utils tests", func() { }) }) + + Describe("Name length limit tests", func() { + var ns *corev1.Namespace + var rd *volsyncv1alpha1.ReplicationDestination + var rdlongname *volsyncv1alpha1.ReplicationDestination + + BeforeEach(func() { + ns = &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "utils-test-", + }, + } + + Expect(k8sClient.Create(ctx, ns)).To(Succeed()) + Expect(ns.Name).NotTo(BeEmpty()) + }) + + JustBeforeEach(func() { + // Create namespace for test + rd = &volsyncv1alpha1.ReplicationDestination{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "test-rd-owner-obj-", + Namespace: ns.Name, + }, + Spec: volsyncv1alpha1.ReplicationDestinationSpec{}, + } + + rdlongname = &volsyncv1alpha1.ReplicationDestination{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "test-rd-owner-obj-aaa-bbb-ccc-this-name-is-greater-than-63chars-", + Namespace: ns.Name, + }, + Spec: volsyncv1alpha1.ReplicationDestinationSpec{}, + } + + Expect(k8sClient.Create(ctx, rd)).To(Succeed()) + Expect(k8sClient.Create(ctx, rdlongname)).To(Succeed()) + }) + + AfterEach(func() { + Expect(k8sClient.Delete(ctx, ns)).To(Succeed()) + }) + + Describe("Job name test", func() { + It("Should use the prefix + owner CR name when <= 63 chars", func() { + jobName := utils.GetJobName("myprefix-", rd) + Expect(jobName).To(Equal("myprefix-" + rd.GetName())) + }) + + It("Should use prefix + hashed owner name when > 63 chars", func() { + jobName := utils.GetJobName("myprefix-", rdlongname) + hashedName := utils.GetHashedName(rdlongname.GetName()) + Expect(len(hashedName)).To(Equal(8)) + Expect(jobName).To(Equal("myprefix-" + hashedName)) + }) + }) + + Describe("Service name test", func() { + It("Should use the prefix + owner CR name when <= 63 chars", func() { + jobName := utils.GetServiceName("myprefix-", rd) + Expect(jobName).To(Equal("myprefix-" + rd.GetName())) + }) + + It("Should use prefix + hashed owner name when > 63 chars", func() { + jobName := utils.GetServiceName("myprefix-", rdlongname) + Expect(jobName).To(Equal("myprefix-" + utils.GetHashedName(rdlongname.GetName()))) + }) + }) + + Describe("Label value test", func() { + It("Should use the prefix + owner CR name when <= 63 chars", func() { + jobName := utils.GetOwnerNameLabelValue("myprefix-", rd) + Expect(jobName).To(Equal("myprefix-" + rd.GetName())) + }) + + It("Should use prefix + hashed owner name when > 63 chars", func() { + jobName := utils.GetOwnerNameLabelValue("myprefix-", rdlongname) + Expect(jobName).To(Equal("myprefix-" + utils.GetHashedName(rdlongname.GetName()))) + }) + }) + }) }) diff --git a/custom-scorecard-tests/config-downstream.yaml b/custom-scorecard-tests/config-downstream.yaml index 79390bed3..c62336fdb 100644 --- a/custom-scorecard-tests/config-downstream.yaml +++ b/custom-scorecard-tests/config-downstream.yaml @@ -97,203 +97,233 @@ stages: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_restic_manual_normal.yml + - test_rsync_tls_normal.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_restic_manual_normal.yml + test: test_rsync_tls_normal.yml storage: spec: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_restic_manual_normal_cleanup_pvcs.yml + - test_rsync_tls_normal_diskrsync.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_restic_manual_normal_cleanup_pvcs.yml + test: test_rsync_tls_normal_diskrsync.yml storage: spec: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_restic_manual_normal_copy_trigger.yml + - test_rsync_tls_normal_longname.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_restic_manual_normal_copy_trigger.yml + test: test_rsync_tls_normal_longname.yml storage: spec: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_restic_manual_normal_restore_emptyrepo.yml + - test_rsync_tls_normal_manyfiles.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_restic_manual_normal_restore_emptyrepo.yml + test: test_rsync_tls_normal_manyfiles.yml storage: spec: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_restic_manual_priv.yml + - test_rsync_tls_priv.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_restic_manual_priv.yml + test: test_rsync_tls_priv.yml storage: spec: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_restic_with_customca_configmap.yml + - test_rsync_tls_priv_diskrsync.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_restic_with_customca_configmap.yml + test: test_rsync_tls_priv_diskrsync.yml storage: spec: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_restic_with_customca_secret.yml + - test_simple_rsync.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_restic_with_customca_secret.yml + test: test_simple_rsync.yml storage: spec: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_restic_with_previous.yml + - test_simple_rsync_diskrsync.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_restic_with_previous.yml + test: test_simple_rsync_diskrsync.yml storage: spec: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_restic_with_restoreasof.yml + - test_simple_rsync_longname.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_restic_with_restoreasof.yml + test: test_simple_rsync_longname.yml storage: spec: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_restic_with_restoreoptions.yml + - test_volumepopulator.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_restic_with_restoreoptions.yml + test: test_volumepopulator.yml storage: spec: mountPath: {} +- parallel: true + tests: - entrypoint: - volsync-custom-scorecard-tests - - test_restic_without_trigger.yml + - test_namespace_role.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_restic_without_trigger.yml + test: test_namespace_role.yml storage: spec: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_rsync_tls_normal.yml + - test_restic_manual_normal.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_rsync_tls_normal.yml + test: test_restic_manual_normal.yml storage: spec: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_rsync_tls_normal_diskrsync.yml + - test_restic_manual_normal_cleanup_pvcs.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_rsync_tls_normal_diskrsync.yml + test: test_restic_manual_normal_cleanup_pvcs.yml storage: spec: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_rsync_tls_normal_manyfiles.yml + - test_restic_manual_normal_copy_trigger.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_rsync_tls_normal_manyfiles.yml + test: test_restic_manual_normal_copy_trigger.yml storage: spec: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_rsync_tls_priv.yml + - test_restic_manual_normal_longname.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_rsync_tls_priv.yml + test: test_restic_manual_normal_longname.yml storage: spec: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_rsync_tls_priv_diskrsync.yml + - test_restic_manual_normal_restore_emptyrepo.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_rsync_tls_priv_diskrsync.yml + test: test_restic_manual_normal_restore_emptyrepo.yml storage: spec: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_simple_rsync.yml + - test_restic_manual_priv.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_simple_rsync.yml + test: test_restic_manual_priv.yml storage: spec: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_simple_rsync_diskrsync.yml + - test_restic_with_customca_configmap.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_simple_rsync_diskrsync.yml + test: test_restic_with_customca_configmap.yml storage: spec: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_volumepopulator.yml + - test_restic_with_customca_secret.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_volumepopulator.yml + test: test_restic_with_customca_secret.yml storage: spec: mountPath: {} -- parallel: true - tests: - entrypoint: - volsync-custom-scorecard-tests - - test_namespace_role.yml + - test_restic_with_previous.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_namespace_role.yml + test: test_restic_with_previous.yml + storage: + spec: + mountPath: {} + - entrypoint: + - volsync-custom-scorecard-tests + - test_restic_with_restoreasof.yml + image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 + labels: + suite: volsync-e2e + test: test_restic_with_restoreasof.yml + storage: + spec: + mountPath: {} + - entrypoint: + - volsync-custom-scorecard-tests + - test_restic_with_restoreoptions.yml + image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 + labels: + suite: volsync-e2e + test: test_restic_with_restoreoptions.yml + storage: + spec: + mountPath: {} + - entrypoint: + - volsync-custom-scorecard-tests + - test_restic_without_trigger.yml + image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 + labels: + suite: volsync-e2e + test: test_restic_without_trigger.yml storage: spec: mountPath: {} @@ -327,6 +357,16 @@ stages: storage: spec: mountPath: {} + - entrypoint: + - volsync-custom-scorecard-tests + - test_syncthing_cluster_sync_normal_longname.yml + image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 + labels: + suite: volsync-e2e + test: test_syncthing_cluster_sync_normal_longname.yml + storage: + spec: + mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - test_syncthing_cluster_sync_priv.yml diff --git a/custom-scorecard-tests/config.yaml b/custom-scorecard-tests/config.yaml index 79390bed3..c62336fdb 100644 --- a/custom-scorecard-tests/config.yaml +++ b/custom-scorecard-tests/config.yaml @@ -97,203 +97,233 @@ stages: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_restic_manual_normal.yml + - test_rsync_tls_normal.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_restic_manual_normal.yml + test: test_rsync_tls_normal.yml storage: spec: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_restic_manual_normal_cleanup_pvcs.yml + - test_rsync_tls_normal_diskrsync.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_restic_manual_normal_cleanup_pvcs.yml + test: test_rsync_tls_normal_diskrsync.yml storage: spec: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_restic_manual_normal_copy_trigger.yml + - test_rsync_tls_normal_longname.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_restic_manual_normal_copy_trigger.yml + test: test_rsync_tls_normal_longname.yml storage: spec: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_restic_manual_normal_restore_emptyrepo.yml + - test_rsync_tls_normal_manyfiles.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_restic_manual_normal_restore_emptyrepo.yml + test: test_rsync_tls_normal_manyfiles.yml storage: spec: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_restic_manual_priv.yml + - test_rsync_tls_priv.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_restic_manual_priv.yml + test: test_rsync_tls_priv.yml storage: spec: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_restic_with_customca_configmap.yml + - test_rsync_tls_priv_diskrsync.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_restic_with_customca_configmap.yml + test: test_rsync_tls_priv_diskrsync.yml storage: spec: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_restic_with_customca_secret.yml + - test_simple_rsync.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_restic_with_customca_secret.yml + test: test_simple_rsync.yml storage: spec: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_restic_with_previous.yml + - test_simple_rsync_diskrsync.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_restic_with_previous.yml + test: test_simple_rsync_diskrsync.yml storage: spec: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_restic_with_restoreasof.yml + - test_simple_rsync_longname.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_restic_with_restoreasof.yml + test: test_simple_rsync_longname.yml storage: spec: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_restic_with_restoreoptions.yml + - test_volumepopulator.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_restic_with_restoreoptions.yml + test: test_volumepopulator.yml storage: spec: mountPath: {} +- parallel: true + tests: - entrypoint: - volsync-custom-scorecard-tests - - test_restic_without_trigger.yml + - test_namespace_role.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_restic_without_trigger.yml + test: test_namespace_role.yml storage: spec: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_rsync_tls_normal.yml + - test_restic_manual_normal.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_rsync_tls_normal.yml + test: test_restic_manual_normal.yml storage: spec: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_rsync_tls_normal_diskrsync.yml + - test_restic_manual_normal_cleanup_pvcs.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_rsync_tls_normal_diskrsync.yml + test: test_restic_manual_normal_cleanup_pvcs.yml storage: spec: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_rsync_tls_normal_manyfiles.yml + - test_restic_manual_normal_copy_trigger.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_rsync_tls_normal_manyfiles.yml + test: test_restic_manual_normal_copy_trigger.yml storage: spec: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_rsync_tls_priv.yml + - test_restic_manual_normal_longname.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_rsync_tls_priv.yml + test: test_restic_manual_normal_longname.yml storage: spec: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_rsync_tls_priv_diskrsync.yml + - test_restic_manual_normal_restore_emptyrepo.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_rsync_tls_priv_diskrsync.yml + test: test_restic_manual_normal_restore_emptyrepo.yml storage: spec: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_simple_rsync.yml + - test_restic_manual_priv.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_simple_rsync.yml + test: test_restic_manual_priv.yml storage: spec: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_simple_rsync_diskrsync.yml + - test_restic_with_customca_configmap.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_simple_rsync_diskrsync.yml + test: test_restic_with_customca_configmap.yml storage: spec: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_volumepopulator.yml + - test_restic_with_customca_secret.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_volumepopulator.yml + test: test_restic_with_customca_secret.yml storage: spec: mountPath: {} -- parallel: true - tests: - entrypoint: - volsync-custom-scorecard-tests - - test_namespace_role.yml + - test_restic_with_previous.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_namespace_role.yml + test: test_restic_with_previous.yml + storage: + spec: + mountPath: {} + - entrypoint: + - volsync-custom-scorecard-tests + - test_restic_with_restoreasof.yml + image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 + labels: + suite: volsync-e2e + test: test_restic_with_restoreasof.yml + storage: + spec: + mountPath: {} + - entrypoint: + - volsync-custom-scorecard-tests + - test_restic_with_restoreoptions.yml + image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 + labels: + suite: volsync-e2e + test: test_restic_with_restoreoptions.yml + storage: + spec: + mountPath: {} + - entrypoint: + - volsync-custom-scorecard-tests + - test_restic_without_trigger.yml + image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 + labels: + suite: volsync-e2e + test: test_restic_without_trigger.yml storage: spec: mountPath: {} @@ -327,6 +357,16 @@ stages: storage: spec: mountPath: {} + - entrypoint: + - volsync-custom-scorecard-tests + - test_syncthing_cluster_sync_normal_longname.yml + image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 + labels: + suite: volsync-e2e + test: test_syncthing_cluster_sync_normal_longname.yml + storage: + spec: + mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - test_syncthing_cluster_sync_priv.yml diff --git a/custom-scorecard-tests/generateE2ETestsConfig.sh b/custom-scorecard-tests/generateE2ETestsConfig.sh index 424eec2d2..88da80fc1 100755 --- a/custom-scorecard-tests/generateE2ETestsConfig.sh +++ b/custom-scorecard-tests/generateE2ETestsConfig.sh @@ -18,8 +18,8 @@ TESTS_COUNT=$(echo "${TESTS}" | wc -w) # Group tests into 2 stages (each stage gets run sequentially but # all tests in a stage can run in parallel) -E2E_TESTS_GROUP1=$(echo "${TESTS}" | grep -v -e role -e syncthing) -E2E_TESTS_GROUP2=$(echo "${TESTS}" | grep -e role -e syncthing) +E2E_TESTS_GROUP1=$(echo "${TESTS}" | grep -v -e role -e syncthing -e restic) +E2E_TESTS_GROUP2=$(echo "${TESTS}" | grep -e role -e syncthing -e restic) E2E_TESTS_GROUP3="" # If we want to exclude specific tests downstream - put them in this group E2E_TESTS_GROUP1_COUNT=$(echo "${E2E_TESTS_GROUP1}" | wc -w) diff --git a/custom-scorecard-tests/scorecard/bases/patches/e2e-tests-stage1.yaml b/custom-scorecard-tests/scorecard/bases/patches/e2e-tests-stage1.yaml index 54d263fb5..4f0d11c84 100644 --- a/custom-scorecard-tests/scorecard/bases/patches/e2e-tests-stage1.yaml +++ b/custom-scorecard-tests/scorecard/bases/patches/e2e-tests-stage1.yaml @@ -83,131 +83,31 @@ mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_restic_manual_normal.yml - image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 - labels: - suite: volsync-e2e - test: test_restic_manual_normal.yml - storage: - spec: - mountPath: {} - - entrypoint: - - volsync-custom-scorecard-tests - - test_restic_manual_normal_cleanup_pvcs.yml - image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 - labels: - suite: volsync-e2e - test: test_restic_manual_normal_cleanup_pvcs.yml - storage: - spec: - mountPath: {} - - entrypoint: - - volsync-custom-scorecard-tests - - test_restic_manual_normal_copy_trigger.yml - image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 - labels: - suite: volsync-e2e - test: test_restic_manual_normal_copy_trigger.yml - storage: - spec: - mountPath: {} - - entrypoint: - - volsync-custom-scorecard-tests - - test_restic_manual_normal_restore_emptyrepo.yml - image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 - labels: - suite: volsync-e2e - test: test_restic_manual_normal_restore_emptyrepo.yml - storage: - spec: - mountPath: {} - - entrypoint: - - volsync-custom-scorecard-tests - - test_restic_manual_priv.yml - image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 - labels: - suite: volsync-e2e - test: test_restic_manual_priv.yml - storage: - spec: - mountPath: {} - - entrypoint: - - volsync-custom-scorecard-tests - - test_restic_with_customca_configmap.yml - image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 - labels: - suite: volsync-e2e - test: test_restic_with_customca_configmap.yml - storage: - spec: - mountPath: {} - - entrypoint: - - volsync-custom-scorecard-tests - - test_restic_with_customca_secret.yml - image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 - labels: - suite: volsync-e2e - test: test_restic_with_customca_secret.yml - storage: - spec: - mountPath: {} - - entrypoint: - - volsync-custom-scorecard-tests - - test_restic_with_previous.yml - image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 - labels: - suite: volsync-e2e - test: test_restic_with_previous.yml - storage: - spec: - mountPath: {} - - entrypoint: - - volsync-custom-scorecard-tests - - test_restic_with_restoreasof.yml - image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 - labels: - suite: volsync-e2e - test: test_restic_with_restoreasof.yml - storage: - spec: - mountPath: {} - - entrypoint: - - volsync-custom-scorecard-tests - - test_restic_with_restoreoptions.yml - image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 - labels: - suite: volsync-e2e - test: test_restic_with_restoreoptions.yml - storage: - spec: - mountPath: {} - - entrypoint: - - volsync-custom-scorecard-tests - - test_restic_without_trigger.yml + - test_rsync_tls_normal.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_restic_without_trigger.yml + test: test_rsync_tls_normal.yml storage: spec: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_rsync_tls_normal.yml + - test_rsync_tls_normal_diskrsync.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_rsync_tls_normal.yml + test: test_rsync_tls_normal_diskrsync.yml storage: spec: mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - - test_rsync_tls_normal_diskrsync.yml + - test_rsync_tls_normal_longname.yml image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 labels: suite: volsync-e2e - test: test_rsync_tls_normal_diskrsync.yml + test: test_rsync_tls_normal_longname.yml storage: spec: mountPath: {} @@ -261,6 +161,16 @@ storage: spec: mountPath: {} + - entrypoint: + - volsync-custom-scorecard-tests + - test_simple_rsync_longname.yml + image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 + labels: + suite: volsync-e2e + test: test_simple_rsync_longname.yml + storage: + spec: + mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - test_volumepopulator.yml diff --git a/custom-scorecard-tests/scorecard/bases/patches/e2e-tests-stage2.yaml b/custom-scorecard-tests/scorecard/bases/patches/e2e-tests-stage2.yaml index ce125f1ca..9e902469e 100644 --- a/custom-scorecard-tests/scorecard/bases/patches/e2e-tests-stage2.yaml +++ b/custom-scorecard-tests/scorecard/bases/patches/e2e-tests-stage2.yaml @@ -11,6 +11,126 @@ storage: spec: mountPath: {} + - entrypoint: + - volsync-custom-scorecard-tests + - test_restic_manual_normal.yml + image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 + labels: + suite: volsync-e2e + test: test_restic_manual_normal.yml + storage: + spec: + mountPath: {} + - entrypoint: + - volsync-custom-scorecard-tests + - test_restic_manual_normal_cleanup_pvcs.yml + image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 + labels: + suite: volsync-e2e + test: test_restic_manual_normal_cleanup_pvcs.yml + storage: + spec: + mountPath: {} + - entrypoint: + - volsync-custom-scorecard-tests + - test_restic_manual_normal_copy_trigger.yml + image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 + labels: + suite: volsync-e2e + test: test_restic_manual_normal_copy_trigger.yml + storage: + spec: + mountPath: {} + - entrypoint: + - volsync-custom-scorecard-tests + - test_restic_manual_normal_longname.yml + image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 + labels: + suite: volsync-e2e + test: test_restic_manual_normal_longname.yml + storage: + spec: + mountPath: {} + - entrypoint: + - volsync-custom-scorecard-tests + - test_restic_manual_normal_restore_emptyrepo.yml + image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 + labels: + suite: volsync-e2e + test: test_restic_manual_normal_restore_emptyrepo.yml + storage: + spec: + mountPath: {} + - entrypoint: + - volsync-custom-scorecard-tests + - test_restic_manual_priv.yml + image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 + labels: + suite: volsync-e2e + test: test_restic_manual_priv.yml + storage: + spec: + mountPath: {} + - entrypoint: + - volsync-custom-scorecard-tests + - test_restic_with_customca_configmap.yml + image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 + labels: + suite: volsync-e2e + test: test_restic_with_customca_configmap.yml + storage: + spec: + mountPath: {} + - entrypoint: + - volsync-custom-scorecard-tests + - test_restic_with_customca_secret.yml + image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 + labels: + suite: volsync-e2e + test: test_restic_with_customca_secret.yml + storage: + spec: + mountPath: {} + - entrypoint: + - volsync-custom-scorecard-tests + - test_restic_with_previous.yml + image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 + labels: + suite: volsync-e2e + test: test_restic_with_previous.yml + storage: + spec: + mountPath: {} + - entrypoint: + - volsync-custom-scorecard-tests + - test_restic_with_restoreasof.yml + image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 + labels: + suite: volsync-e2e + test: test_restic_with_restoreasof.yml + storage: + spec: + mountPath: {} + - entrypoint: + - volsync-custom-scorecard-tests + - test_restic_with_restoreoptions.yml + image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 + labels: + suite: volsync-e2e + test: test_restic_with_restoreoptions.yml + storage: + spec: + mountPath: {} + - entrypoint: + - volsync-custom-scorecard-tests + - test_restic_without_trigger.yml + image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 + labels: + suite: volsync-e2e + test: test_restic_without_trigger.yml + storage: + spec: + mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - test_roles.yml @@ -41,6 +161,16 @@ storage: spec: mountPath: {} + - entrypoint: + - volsync-custom-scorecard-tests + - test_syncthing_cluster_sync_normal_longname.yml + image: quay.io/backube/volsync-custom-scorecard-tests:release-0.12 + labels: + suite: volsync-e2e + test: test_syncthing_cluster_sync_normal_longname.yml + storage: + spec: + mountPath: {} - entrypoint: - volsync-custom-scorecard-tests - test_syncthing_cluster_sync_priv.yml diff --git a/helm/volsync/Chart.yaml b/helm/volsync/Chart.yaml index d302adec6..59bf72780 100644 --- a/helm/volsync/Chart.yaml +++ b/helm/volsync/Chart.yaml @@ -34,6 +34,8 @@ annotations: # https://artifacthub.io/docs/topics/annotations/helm/ description: Updates the ensure_initialized function in the restic mover script to follow restic recommendations - kind: fixed description: All movers should return error if not able to EnsurePVCFromSrc + - kind: fixed + description: Fix for mover job/service name length too long (>63 chars) if the replicationsource or replicationdestination CR name is too long - kind: security description: kube-rbac-proxy upgraded to 0.18.1 artifacthub.io/crds: | diff --git a/test-e2e/roles/test_syncthing_cluster_sync/tasks/main.yml b/test-e2e/roles/test_syncthing_cluster_sync/tasks/main.yml index c08f5906a..39a70fa6e 100644 --- a/test-e2e/roles/test_syncthing_cluster_sync/tasks/main.yml +++ b/test-e2e/roles/test_syncthing_cluster_sync/tasks/main.yml @@ -20,13 +20,17 @@ loop_control: loop_var: namespace +- name: Determine name prefix for syncthing CRs + ansible.builtin.set_fact: + local_cr_name_prefix: "{{ cr_name_prefix | default('test-') }}" + - name: Clear list of syncthings set_fact: syncthings: [] - name: Build list of syncthings set_fact: - syncthings: "{{ syncthings + [{ 'Name': 'test-%s' | format(item), 'Namespace': namespaces[item] }] }}" + syncthings: "{{ syncthings + [{ 'Name': '{{ local_cr_name_prefix }}%s' | format(item), 'Namespace': namespaces[item] }] }}" loop: "{{ range(0, num_syncthings) | list }}" - name: Create data PVCs diff --git a/test-e2e/test_restic_manual_normal_longname.yml b/test-e2e/test_restic_manual_normal_longname.yml new file mode 100644 index 000000000..ba2cd91c6 --- /dev/null +++ b/test-e2e/test_restic_manual_normal_longname.yml @@ -0,0 +1,237 @@ +--- +- hosts: localhost + tags: + - e2e + - restic + - unprivileged + - long cr name + vars: + restic_secret_name: restic-secret + tasks: + - include_role: + name: create_namespace + + - include_role: + name: gather_cluster_info + + # We're running everything as a normal user + - name: Define podSecurityContext + ansible.builtin.set_fact: + podSecurityContext: + fsGroup: 5678 + runAsGroup: 5678 + runAsNonRoot: true + runAsUser: 1234 + seccompProfile: + type: RuntimeDefault + when: not cluster_info.is_openshift + + - include_role: + name: create_restic_secret + vars: + minio_namespace: minio + + - name: Create source PVC + kubernetes.core.k8s: + state: present + definition: + kind: PersistentVolumeClaim + apiVersion: v1 + metadata: + name: data-source + namespace: "{{ namespace }}" + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + + - name: Write data into the source PVC + include_role: + name: write_to_pvc + vars: + data: 'data' + path: '/datafile' + pvc_name: 'data-source' + + - name: Backup data from source volume with manual trigger (w/ mSC) + kubernetes.core.k8s: + state: present + definition: + apiVersion: volsync.backube/v1alpha1 + kind: ReplicationSource + metadata: + name: source-thisisavery-very-very-very-longnameevenlongerthan63chars2 + namespace: "{{ namespace }}" + spec: + sourcePVC: data-source + trigger: + manual: once + restic: + pruneIntervalDays: 1 + repository: "{{ restic_secret_name }}" + retain: + hourly: 3 + daily: 2 + monthly: 1 + copyMethod: Snapshot + cacheCapacity: 1Gi + moverSecurityContext: "{{ podSecurityContext }}" + when: podSecurityContext is defined + + - name: Backup data from source volume with manual trigger (w/o mSC) + kubernetes.core.k8s: + state: present + definition: + apiVersion: volsync.backube/v1alpha1 + kind: ReplicationSource + metadata: + name: source-thisisavery-very-very-very-longnameevenlongerthan63chars2 + namespace: "{{ namespace }}" + spec: + sourcePVC: data-source + trigger: + manual: once + restic: + pruneIntervalDays: 1 + repository: "{{ restic_secret_name }}" + retain: + hourly: 3 + daily: 2 + monthly: 1 + copyMethod: Snapshot + cacheCapacity: 1Gi + when: podSecurityContext is not defined + + - name: Wait for sync to MinIO to complete + kubernetes.core.k8s_info: + api_version: volsync.backube/v1alpha1 + kind: ReplicationSource + name: source-thisisavery-very-very-very-longnameevenlongerthan63chars2 + namespace: "{{ namespace }}" + register: res + until: > + res.resources | length > 0 and + res.resources[0].status.lastManualSync is defined and + res.resources[0].status.lastManualSync=="once" and + res.resources[0].status.latestMoverStatus is defined and + res.resources[0].status.latestMoverStatus.result == "Successful" and + res.resources[0].status.latestMoverStatus.logs is search("processed.*files") and + res.resources[0].status.latestMoverStatus.logs is search("snapshot.*saved") and + res.resources[0].status.latestMoverStatus.logs is search("Restic completed in.*") + delay: 1 + retries: 900 + + - name: Create dest PVC (restore volume) + kubernetes.core.k8s: + state: present + definition: + kind: PersistentVolumeClaim + apiVersion: v1 + metadata: + name: data-dest + namespace: "{{ namespace }}" + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + + # Run affinity pod attached to both pvcs to make sure they end up in the + # same availability zone so they can be mounted by a single pod later + # when running compare-pvcs + - name: Run pvc affinity pod + include_role: + name: pvc_affinity_pod + vars: + pvc_names: + - data-source + - data-dest + + - name: Restore data to destination (w/ mSC) + kubernetes.core.k8s: + state: present + definition: + apiVersion: volsync.backube/v1alpha1 + kind: ReplicationDestination + metadata: + name: restore-thisisavery-very-very-very-longnameevenlongerthan63chars2 + namespace: "{{ namespace }}" + spec: + trigger: + manual: restore-once + restic: + repository: "{{ restic_secret_name }}" + destinationPVC: data-dest + copyMethod: Direct + cacheCapacity: 1Gi + moverSecurityContext: "{{ podSecurityContext }}" + when: podSecurityContext is defined + + - name: Restore data to destination (w/o mSC) + kubernetes.core.k8s: + state: present + definition: + apiVersion: volsync.backube/v1alpha1 + kind: ReplicationDestination + metadata: + name: restore-thisisavery-very-very-very-longnameevenlongerthan63chars2 + namespace: "{{ namespace }}" + spec: + trigger: + manual: restore-once + restic: + repository: "{{ restic_secret_name }}" + destinationPVC: data-dest + copyMethod: Direct + cacheCapacity: 1Gi + when: podSecurityContext is not defined + + - name: Wait for restore to complete + kubernetes.core.k8s_info: + api_version: volsync.backube/v1alpha1 + kind: ReplicationDestination + name: restore-thisisavery-very-very-very-longnameevenlongerthan63chars2 + namespace: "{{ namespace }}" + register: res + until: > + res.resources | length > 0 and + res.resources[0].status.lastManualSync is defined and + res.resources[0].status.lastManualSync=="restore-once" and + res.resources[0].status.latestMoverStatus is defined and + res.resources[0].status.latestMoverStatus.result == "Successful" and + res.resources[0].status.latestMoverStatus.logs is search("restoring.*") and + res.resources[0].status.latestMoverStatus.logs is search("Restic completed in.*") + delay: 1 + retries: 300 + + - name: Shutdown pvc affinity pod + include_role: + name: pvc_affinity_pod + tasks_from: "delete" + + - name: Verify contents of PVC + include_role: + name: compare_pvc_data + vars: + pvc1_name: data-source + pvc2_name: data-dest + + # Check that the cache PVC is preserved + # since we're using cleanupCachePVC: false + - name: Confirm cache PVC is preserved + kubernetes.core.k8s_info: + api_version: v1 + kind: PersistentVolumeClaim + name: volsync-restore-thisisavery-very-very-very-longnameevenlongerthan63chars2-cache + namespace: "{{ namespace }}" + register: cachepvcreloaded + + - name: Check cache pvc preserved (cleanupCachePVC is false by default) + ansible.builtin.fail: + msg: cache pvc should be preserved, but has been deleted + when: + cachepvcreloaded.resources | length == 0 or + cachepvcreloaded.resources[0].metadata.deletionTimestamp is defined diff --git a/test-e2e/test_rsync_tls_normal_longname.yml b/test-e2e/test_rsync_tls_normal_longname.yml new file mode 100644 index 000000000..4cf0bb6f5 --- /dev/null +++ b/test-e2e/test_rsync_tls_normal_longname.yml @@ -0,0 +1,256 @@ +--- +- hosts: localhost + tags: + - e2e + - rsync_tls + - unprivileged + - volumepopulator + - long cr name + tasks: + - name: Create namespace + include_role: + name: create_namespace + + - name: Probe cluster information + include_role: + name: gather_cluster_info + + - name: Define podSecurityContext + ansible.builtin.set_fact: + podSecurityContext: + fsGroup: 5678 + runAsGroup: 5678 + runAsNonRoot: true + runAsUser: 1234 + seccompProfile: + type: RuntimeDefault + when: not cluster_info.is_openshift + + - name: Create ReplicationDestination (w/ mSC) + kubernetes.core.k8s: + state: present + definition: + apiVersion: volsync.backube/v1alpha1 + kind: ReplicationDestination + metadata: + name: thisisavery-very-very-very-longnameevenlongerthan63chars2 + namespace: "{{ namespace }}" + spec: + rsyncTLS: + copyMethod: Snapshot + capacity: 1Gi + accessModes: + - ReadWriteOnce + moverSecurityContext: "{{ podSecurityContext }}" + when: podSecurityContext is defined + + - name: Create ReplicationDestination (w/o mSC) + kubernetes.core.k8s: + state: present + definition: + apiVersion: volsync.backube/v1alpha1 + kind: ReplicationDestination + metadata: + name: thisisavery-very-very-very-longnameevenlongerthan63chars2 + namespace: "{{ namespace }}" + spec: + rsyncTLS: + copyMethod: Snapshot + capacity: 1Gi + accessModes: + - ReadWriteOnce + when: podSecurityContext is not defined + + - name: Create source PVC + kubernetes.core.k8s: + state: present + definition: + kind: PersistentVolumeClaim + apiVersion: v1 + metadata: + name: data-source + namespace: "{{ namespace }}" + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + + - name: Write data into the source PVC + include_role: + name: write_to_pvc + vars: + data: 'data' + path: '/datafile' + pvc_name: 'data-source' + + - name: Wait for key and address to be ready + kubernetes.core.k8s_info: + api_version: volsync.backube/v1alpha1 + kind: ReplicationDestination + name: thisisavery-very-very-very-longnameevenlongerthan63chars2 + namespace: "{{ namespace }}" + register: res + until: > + res.resources | length > 0 and + res.resources[0].status.rsyncTLS is defined and + res.resources[0].status.rsyncTLS.keySecret is defined and + res.resources[0].status.rsyncTLS.address is defined + delay: 1 + retries: 300 + + - name: Check on dynamically provisioned destination PVC + kubernetes.core.k8s_info: + api_version: v1 + kind: PersistentVolumeClaim + name: volsync-thisisavery-very-very-very-longnameevenlongerthan63chars2-dst + namespace: "{{ namespace }}" + register: destpvc + + - name: Create ReplicationSource (w/ mSC) + kubernetes.core.k8s: + state: present + definition: + apiVersion: volsync.backube/v1alpha1 + kind: ReplicationSource + metadata: + name: source + namespace: "{{ namespace }}" + spec: + sourcePVC: data-source + trigger: + schedule: "0 0 1 1 *" + rsyncTLS: + keySecret: "{{ res.resources[0].status.rsyncTLS.keySecret }}" + address: "{{ res.resources[0].status.rsyncTLS.address }}" + copyMethod: Snapshot + moverSecurityContext: "{{ podSecurityContext }}" + when: podSecurityContext is defined + + - name: Create ReplicationSource (w/o mSC) + kubernetes.core.k8s: + state: present + definition: + apiVersion: volsync.backube/v1alpha1 + kind: ReplicationSource + metadata: + name: source + namespace: "{{ namespace }}" + spec: + sourcePVC: data-source + trigger: + schedule: "0 0 1 1 *" + rsyncTLS: + keySecret: "{{ res.resources[0].status.rsyncTLS.keySecret }}" + address: "{{ res.resources[0].status.rsyncTLS.address }}" + copyMethod: Snapshot + when: podSecurityContext is not defined + + - name: Check status of replicationsource + kubernetes.core.k8s_info: + api_version: volsync.backube/v1alpha1 + kind: ReplicationSource + name: source + namespace: "{{ namespace }}" + register: res + until: > + res.resources | length > 0 and + res.resources[0].status.lastSyncDuration is defined and + res.resources[0].status.lastSyncTime is defined and + res.resources[0].status.latestMoverStatus is defined and + res.resources[0].status.latestMoverStatus.result == "Successful" and + res.resources[0].status.latestMoverStatus.logs is search("sent.*bytes.*received.*bytes.*") and + res.resources[0].status.latestMoverStatus.logs is search("rsync completed in.*") + delay: 1 + retries: 900 + + - name: Wait for sync to complete + kubernetes.core.k8s_info: + api_version: volsync.backube/v1alpha1 + kind: ReplicationDestination + name: thisisavery-very-very-very-longnameevenlongerthan63chars2 + namespace: "{{ namespace }}" + register: res + until: > + res.resources | length > 0 and + res.resources[0].status.latestImage is defined and + res.resources[0].status.latestImage.kind == "VolumeSnapshot" and + res.resources[0].status.latestMoverStatus is defined and + res.resources[0].status.latestMoverStatus.result == "Successful" + delay: 1 + retries: 900 + + # Check that the dynamically provisioned destination PVC is still there + # and that it has NOT been cleaned up + # + # rsync is a special case where we immediately start the destination mover again (no trigger or schedule) + # so even if the dest pvc was deleted, it would be re-created as soon as the last replicationdestionation completed + # To check we have not deleted the original destination pvc, reload it and check against the destpvc variable + # we loaded earlier + - name: Confirm dynamically provisioned destination PVC is preserved (no cleanup by default) + kubernetes.core.k8s_info: + api_version: v1 + kind: PersistentVolumeClaim + name: volsync-thisisavery-very-very-very-longnameevenlongerthan63chars2-dst + namespace: "{{ namespace }}" + register: destpvcreloaded + + - name: Check dest pvc was not deleted (should be same pvc from our original sync to preserve data) + ansible.builtin.fail: + msg: destination pvc (dynamically provisioned by volsync) should be preserved, but has been deleted + when: + destpvc.resources | length == 0 or + destpvcreloaded.resources | length == 0 or + destpvcreloaded.resources[0].metadata.deletionTimestamp is defined or + destpvcreloaded.resources[0].metadata.uid != destpvc.resources[0].metadata.uid + + - name: Convert latestImage to PVC using VolumePopulator + kubernetes.core.k8s: + state: present + definition: + apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: data-dest + namespace: "{{ namespace }}" + spec: + accessModes: + - ReadWriteOnce + dataSourceRef: + kind: ReplicationDestination + apiGroup: volsync.backube + name: thisisavery-very-very-very-longnameevenlongerthan63chars2 + resources: + requests: + storage: 1Gi + when: cluster_info.volumepopulator_supported + + - name: Convert latestImage to PVC + kubernetes.core.k8s: + state: present + definition: + apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: data-dest + namespace: "{{ namespace }}" + spec: + accessModes: + - ReadWriteOnce + dataSource: + kind: VolumeSnapshot + apiGroup: snapshot.storage.k8s.io + name: "{{ res.resources[0].status.latestImage.name }}" + resources: + requests: + storage: 1Gi + when: not cluster_info.volumepopulator_supported + + - name: Verify contents of PVC + include_role: + name: compare_pvc_data + vars: + pvc1_name: data-source + pvc2_name: data-dest + timeout: 900 diff --git a/test-e2e/test_simple_rsync_longname.yml b/test-e2e/test_simple_rsync_longname.yml new file mode 100644 index 000000000..1487ab5f3 --- /dev/null +++ b/test-e2e/test_simple_rsync_longname.yml @@ -0,0 +1,202 @@ +--- +- hosts: localhost + tags: + - e2e + - rsync + - volumepopulator + - long cr name + tasks: + - include_role: + name: create_namespace + + - include_role: + name: gather_cluster_info + + - name: Create ReplicationDestination + kubernetes.core.k8s: + state: present + definition: + apiVersion: volsync.backube/v1alpha1 + kind: ReplicationDestination + metadata: + name: thisisavery-very-very-very-longnameevenlongerthan63chars2 + namespace: "{{ namespace }}" + spec: + rsync: + copyMethod: Snapshot + capacity: 1Gi + accessModes: + - ReadWriteOnce + + - name: Create source PVC + kubernetes.core.k8s: + state: present + definition: + kind: PersistentVolumeClaim + apiVersion: v1 + metadata: + name: data-source + namespace: "{{ namespace }}" + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + + - name: Write data into the source PVC + include_role: + name: write_to_pvc + vars: + data: 'data' + path: '/datafile' + pvc_name: 'data-source' + + - name: Wait for ssh keys and address to be ready + kubernetes.core.k8s_info: + api_version: volsync.backube/v1alpha1 + kind: ReplicationDestination + name: thisisavery-very-very-very-longnameevenlongerthan63chars2 + namespace: "{{ namespace }}" + register: res + until: > + res.resources | length > 0 and + res.resources[0].status.rsync is defined and + res.resources[0].status.rsync.sshKeys is defined and + res.resources[0].status.rsync.address is defined + delay: 1 + retries: 300 + + - name: Check on dynamically provisioned destination PVC + kubernetes.core.k8s_info: + api_version: v1 + kind: PersistentVolumeClaim + name: volsync-thisisavery-very-very-very-longnameevenlongerthan63chars2-dst + namespace: "{{ namespace }}" + register: destpvc + + - name: Create ReplicationSource + kubernetes.core.k8s: + state: present + definition: + apiVersion: volsync.backube/v1alpha1 + kind: ReplicationSource + metadata: + name: source + namespace: "{{ namespace }}" + spec: + sourcePVC: data-source + trigger: + schedule: "0 0 1 1 *" + rsync: + sshKeys: "{{ res.resources[0].status.rsync.sshKeys }}" + address: "{{ res.resources[0].status.rsync.address }}" + copyMethod: Snapshot + + - name: Check status of replicationsource + kubernetes.core.k8s_info: + api_version: volsync.backube/v1alpha1 + kind: ReplicationSource + name: source + namespace: "{{ namespace }}" + register: res + until: > + res.resources | length > 0 and + res.resources[0].status.lastSyncDuration is defined and + res.resources[0].status.lastSyncTime is defined and + res.resources[0].status.latestMoverStatus is defined and + res.resources[0].status.latestMoverStatus.result == "Successful" and + res.resources[0].status.latestMoverStatus.logs is search("sent.*bytes.*received.*bytes.*") and + res.resources[0].status.latestMoverStatus.logs is search("Rsync completed in.*") + delay: 1 + retries: 900 + + - name: Wait for sync to complete + kubernetes.core.k8s_info: + api_version: volsync.backube/v1alpha1 + kind: ReplicationDestination + name: thisisavery-very-very-very-longnameevenlongerthan63chars2 + namespace: "{{ namespace }}" + register: res + until: > + res.resources | length > 0 and + res.resources[0].status.latestImage is defined and + res.resources[0].status.latestImage.kind == "VolumeSnapshot" and + res.resources[0].status.latestMoverStatus is defined and + res.resources[0].status.latestMoverStatus.result == "Successful" + delay: 1 + retries: 900 + + # Check that the dynamically provisioned destination PVC is still there + # and that it has NOT been cleaned up + # + # rsync is a special case where we immediately start the destination mover again (no trigger or schedule) + # so even if the dest pvc was deleted, it would be re-created as soon as the last replicationdestionation completed + # To check we have not deleted the original destination pvc, reload it and check against the destpvc variable + # we loaded earlier + - name: Confirm dynamically provisioned destination PVC is preserved (no cleanup by default) + kubernetes.core.k8s_info: + api_version: v1 + kind: PersistentVolumeClaim + name: volsync-thisisavery-very-very-very-longnameevenlongerthan63chars2-dst + namespace: "{{ namespace }}" + register: destpvcreloaded + + - name: Check dest pvc was not deleted (should be same pvc from our original sync to preserve data) + ansible.builtin.fail: + msg: destination pvc (dynamically provisioned by volsync) should be preserved, but has been deleted + when: + destpvc.resources | length == 0 or + destpvcreloaded.resources | length == 0 or + destpvcreloaded.resources[0].metadata.deletionTimestamp is defined or + destpvcreloaded.resources[0].metadata.uid != destpvc.resources[0].metadata.uid + + - name: Convert latestImage to PVC using VolumePopulator + kubernetes.core.k8s: + state: present + definition: + apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: data-dest + namespace: "{{ namespace }}" + spec: + accessModes: + - ReadWriteOnce + dataSourceRef: + kind: ReplicationDestination + apiGroup: volsync.backube + name: thisisavery-very-very-very-longnameevenlongerthan63chars2 + resources: + requests: + storage: 1Gi + when: cluster_info.volumepopulator_supported + + - name: Convert latestImage to PVC + kubernetes.core.k8s: + state: present + definition: + apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: data-dest + namespace: "{{ namespace }}" + spec: + accessModes: + - ReadWriteOnce + dataSource: + kind: VolumeSnapshot + apiGroup: snapshot.storage.k8s.io + name: "{{ res.resources[0].status.latestImage.name }}" + resources: + requests: + storage: 1Gi + when: not cluster_info.volumepopulator_supported + + - name: Verify contents of PVC + include_role: + name: compare_pvc_data + vars: + pvc1_name: data-source + pvc2_name: data-dest + timeout: 900 diff --git a/test-e2e/test_syncthing_cluster_sync_normal_longname.yml b/test-e2e/test_syncthing_cluster_sync_normal_longname.yml new file mode 100644 index 000000000..7a7d0a82a --- /dev/null +++ b/test-e2e/test_syncthing_cluster_sync_normal_longname.yml @@ -0,0 +1,35 @@ +--- +- hosts: localhost + tags: + - e2e + - syncthing + - unprivileged + - long cr name + tasks: + - include_role: + name: create_namespace + vars: + num_namespaces: 3 + pss_enforce: restricted + + - include_role: + name: gather_cluster_info + + # We're running everything as a normal user + - name: Define podSecurityContext + ansible.builtin.set_fact: + podSecurityContext: + fsGroup: 5678 + runAsGroup: 5678 + runAsNonRoot: true + runAsUser: 1234 + seccompProfile: + type: RuntimeDefault + when: not cluster_info.is_openshift + + - include_role: + name: test_syncthing_cluster_sync + vars: + cr_name_prefix: source-thisisavery-very-very-very-longnameevenlongerthan63chars2- + num_syncthings: 3 + privileged: false