diff --git a/api/operator/v1beta1/vmcluster_types.go b/api/operator/v1beta1/vmcluster_types.go index 749f78d64..f6ebb4921 100644 --- a/api/operator/v1beta1/vmcluster_types.go +++ b/api/operator/v1beta1/vmcluster_types.go @@ -468,13 +468,6 @@ type VMStorage struct { } type VMBackup struct { - // AcceptEULA accepts enterprise feature usage, must be set to true. - // otherwise backupmanager cannot be added to single/cluster version. - // https://victoriametrics.com/legal/esa/ - // Deprecated: use license.key or license.keyRef instead - // +deprecated - // +optional - AcceptEULA bool `json:"acceptEULA"` // SnapshotCreateURL overwrites url for snapshot create // +optional SnapshotCreateURL string `json:"snapshotCreateURL,omitempty"` @@ -552,7 +545,7 @@ type VMBackup struct { } func (cr *VMBackup) validate(l *License) error { - if !l.IsProvided() && !cr.AcceptEULA { + if !l.IsProvided() { return fmt.Errorf("it is required to provide license key. See [here](https://docs.victoriametrics.com/victoriametrics/enterprise/)") } diff --git a/config/crd/overlay/crd.yaml b/config/crd/overlay/crd.yaml index d8ba7e876..0177929f9 100644 --- a/config/crd/overlay/crd.yaml +++ b/config/crd/overlay/crd.yaml @@ -27737,13 +27737,6 @@ spec: vmBackup: description: VMBackup configuration for backup properties: - acceptEULA: - description: |- - AcceptEULA accepts enterprise feature usage, must be set to true. - otherwise backupmanager cannot be added to single/cluster version. - https://victoriametrics.com/legal/esa/ - Deprecated: use license.key or license.keyRef instead - type: boolean concurrency: description: Defines number of concurrent workers. Higher concurrency may reduce backup duration (default 10) @@ -37261,13 +37254,6 @@ spec: vmBackup: description: VMBackup configuration for backup properties: - acceptEULA: - description: |- - AcceptEULA accepts enterprise feature usage, must be set to true. - otherwise backupmanager cannot be added to single/cluster version. - https://victoriametrics.com/legal/esa/ - Deprecated: use license.key or license.keyRef instead - type: boolean concurrency: description: Defines number of concurrent workers. Higher concurrency may reduce backup duration (default 10) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 73e3e1278..196a72883 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -13,6 +13,8 @@ aliases: ## tip +* FEATURE: [vmoperator](https://docs.victoriametrics.com/operator/): remove deprecated acceptEULA. Replaced it with license in tests. See [#1319](https://github.com/VictoriaMetrics/operator/issues/1319). + ## [v0.61.0](https://github.com/VictoriaMetrics/operator/releases/tag/v0.61.0) **Release date:** 15 July 2025 diff --git a/docs/api.md b/docs/api.md index 84421bb12..95ea6fd44 100644 --- a/docs/api.md +++ b/docs/api.md @@ -3668,7 +3668,6 @@ Appears in: [VMSingleSpec](#vmsinglespec), [VMStorage](#vmstorage) | Field | Description | | --- | --- | -| acceptEULA#
_boolean_ | _(Optional)_
AcceptEULA accepts enterprise feature usage, must be set to true.
otherwise backupmanager cannot be added to single/cluster version.
https://victoriametrics.com/legal/esa/
Deprecated: use license.key or license.keyRef instead | | concurrency#
_integer_ | _(Optional)_
Defines number of concurrent workers. Higher concurrency may reduce backup duration (default 10) | | credentialsSecret#
_[SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#secretkeyselector-v1-core)_ | _(Optional)_
CredentialsSecret is secret in the same namespace for access to remote storage
The secret is mounted into /etc/vm/creds. | | customS3Endpoint#
_string_ | _(Optional)_
Custom S3 endpoint for use with S3-compatible storages (e.g. MinIO). S3 is used if not set | diff --git a/internal/controller/operator/factory/build/backup.go b/internal/controller/operator/factory/build/backup.go index 0d5d3f60d..210a5d505 100644 --- a/internal/controller/operator/factory/build/backup.go +++ b/internal/controller/operator/factory/build/backup.go @@ -26,9 +26,9 @@ func VMBackupManager( isCluster bool, license *vmv1beta1.License, ) (*corev1.Container, error) { - if !cr.AcceptEULA && !license.IsProvided() { - logger.WithContext(ctx).Info("EULA or license wasn't defined, update your backup settings." + - " Follow https://docs.victoriametrics.com/enterprise.html for further instructions.") + if !license.IsProvided() { + logger.WithContext(ctx).Info("license wasn't defined, update your backup settings." + + " Follow https://docs.victoriametrics.com/victoriametrics/enterprise/ for further instructions.") return nil, nil } snapshotCreateURL := cr.SnapshotCreateURL diff --git a/internal/controller/operator/factory/vmcluster/vmcluster_test.go b/internal/controller/operator/factory/vmcluster/vmcluster_test.go index 42d63583f..2dc0c5e32 100644 --- a/internal/controller/operator/factory/vmcluster/vmcluster_test.go +++ b/internal/controller/operator/factory/vmcluster/vmcluster_test.go @@ -550,6 +550,9 @@ spec: f("storage", &vmv1beta1.VMCluster{ ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: "default-1"}, Spec: vmv1beta1.VMClusterSpec{ + License: &vmv1beta1.License{ + Key: ptr.To("test-key"), + }, VMStorage: &vmv1beta1.VMStorage{ ServiceSpec: &vmv1beta1.AdditionalServiceSpec{ UseAsDefault: true, @@ -564,9 +567,7 @@ spec: }, }, }, - VMBackup: &vmv1beta1.VMBackup{ - AcceptEULA: true, - }, + VMBackup: &vmv1beta1.VMBackup{}, }, }, }, ` diff --git a/internal/webhook/operator/v1beta1/vmcluster_webhook.go b/internal/webhook/operator/v1beta1/vmcluster_webhook.go index ff97a6c45..40296d50d 100644 --- a/internal/webhook/operator/v1beta1/vmcluster_webhook.go +++ b/internal/webhook/operator/v1beta1/vmcluster_webhook.go @@ -56,10 +56,6 @@ func (*VMClusterCustomValidator) ValidateCreate(ctx context.Context, obj runtime if err = r.Validate(); err != nil { return } - if r.Spec.VMStorage != nil && r.Spec.VMStorage.VMBackup != nil && r.Spec.VMStorage.VMBackup.AcceptEULA { - warnings = append(warnings, "deprecated property is defined `spec.vmstorage.vmbackup.acceptEula`, use `spec.license.key` or `spec.license.keyRef` instead.") - logger.WithContext(ctx).Info("deprecated property is defined `spec.vmstorage.vmbackup.acceptEula`, use `spec.license.key` or `spec.license.keyRef` instead.") - } if r.Spec.VMSelect != nil && r.Spec.VMSelect.StorageSpec != nil { warnings = append(warnings, "deprecated property is defined `spec.vmselect.persistentVolume`, use `storage` instead.") logger.WithContext(ctx).Info("deprecated property is defined `spec.vmselect.persistentVolume`, use `storage` instead.") @@ -81,10 +77,6 @@ func (*VMClusterCustomValidator) ValidateUpdate(ctx context.Context, _, newObj r if err = r.Validate(); err != nil { return } - if r.Spec.VMStorage != nil && r.Spec.VMStorage.VMBackup != nil && r.Spec.VMStorage.VMBackup.AcceptEULA { - warnings = append(warnings, "deprecated property is defined `spec.vmbackup.acceptEula`, use `spec.license.key` or `spec.license.keyRef` instead.") - logger.WithContext(ctx).Info("deprecated property is defined `spec.vmbackup.acceptEula`, use `spec.license.key` or `spec.license.keyRef` instead.") - } if r.Spec.VMSelect != nil && r.Spec.VMSelect.StorageSpec != nil { warnings = append(warnings, "deprecated property is defined `vmcluster.spec.vmselect.persistentVolume`, use `storage` instead.") logger.WithContext(ctx).Info("deprecated property is defined `vmcluster.spec.vmselect.persistentVolume`, use `storage` instead.") diff --git a/internal/webhook/operator/v1beta1/vmsingle_webhook.go b/internal/webhook/operator/v1beta1/vmsingle_webhook.go index 428a8522c..b1abdb72f 100644 --- a/internal/webhook/operator/v1beta1/vmsingle_webhook.go +++ b/internal/webhook/operator/v1beta1/vmsingle_webhook.go @@ -26,7 +26,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/webhook/admission" vmv1beta1 "github.com/VictoriaMetrics/operator/api/operator/v1beta1" - "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/logger" ) // SetupVMSingleWebhookWithManager will setup the manager to manage the webhooks @@ -56,10 +55,6 @@ func (*VMSingleCustomValidator) ValidateCreate(ctx context.Context, obj runtime. if err = r.Validate(); err != nil { return } - if r.Spec.VMBackup != nil && r.Spec.VMBackup.AcceptEULA { - warnings = append(warnings, "deprecated property is defined `spec.vmbackup.acceptEula`, use `spec.license.key` or `spec.license.keyRef` instead.") - logger.WithContext(ctx).Info("deprecated property is defined `spec.vmbackup.acceptEula`, use `spec.license.key` or `spec.license.keyRef` instead.") - } return } @@ -77,10 +72,6 @@ func (*VMSingleCustomValidator) ValidateUpdate(ctx context.Context, _, newObj ru if err = r.Validate(); err != nil { return } - if r.Spec.VMBackup != nil && r.Spec.VMBackup.AcceptEULA { - warnings = append(warnings, "deprecated property is defined `spec.vmbackup.acceptEula`, use `spec.license.key` or `spec.license.keyRef` instead.") - logger.WithContext(ctx).Info("deprecated property is defined `spec.vmbackup.acceptEula`, use `spec.license.key` or `spec.license.keyRef` instead.") - } return } diff --git a/test/e2e/prometheus_converter_test.go b/test/e2e/prometheus_converter_test.go index f2ea2d731..fc3af9529 100644 --- a/test/e2e/prometheus_converter_test.go +++ b/test/e2e/prometheus_converter_test.go @@ -39,7 +39,6 @@ var ( Scheme: ptr.To("HTTPS"), StaticConfigs: []promv1alpha1.StaticConfig{ { - Targets: []promv1alpha1.Target{ "localhost:9100", }, @@ -61,7 +60,6 @@ var ( return nil }, }, - { name: "PrometheusScrapeConfig", source: &promv1alpha1.ScrapeConfig{ @@ -297,106 +295,98 @@ func getObject(ctx context.Context, obj client.Object) (client.Object, error) { return obj, err } -var _ = Describe("test prometheusConverter Controller", func() { - Context("e2e prome converter", func() { - for _, testCaseIt := range testCases { - testCase := testCaseIt +var _ = Describe("prometheus converter", Label("vm", "prom"), func() { + for _, tc := range testCases { + Context(fmt.Sprintf("crud %s", tc.name), func() { // adapt test for parallel execution // https://onsi.github.io/ginkgo/#patterns-for-parallel-integration-specs procSuffix := fmt.Sprintf("-%d", GinkgoParallelProcess()) - testCase.source.SetName(testCase.source.GetName() + procSuffix) - testCase.targetTpl.SetName(testCase.targetTpl.GetName() + procSuffix) + tc.source.SetName(tc.source.GetName() + procSuffix) + tc.targetTpl.SetName(tc.targetTpl.GetName() + procSuffix) ctx := context.Background() - Context(fmt.Sprintf("crud %s", testCase.name), func() { - AfterEach(func() { - k8sClient.Delete(ctx, testCase.source) // nolint:errcheck - Eventually(func() error { - _, err := getObject(ctx, testCase.source) + AfterEach(func() { + k8sClient.Delete(ctx, tc.source) // nolint:errcheck + Eventually(func() error { + _, err := getObject(ctx, tc.source) + return err + }, eventualDeletionTimeout, 1).Should(MatchError(k8serrors.IsNotFound, "IsNotFound")) + k8sClient.Delete(ctx, tc.targetTpl) // nolint:errcheck + Eventually(func() error { + _, err := getObject(ctx, tc.targetTpl) + if err == nil { + return fmt.Errorf("Should be deleted") + } + return nil + }, 60, 1).Should(Succeed()) + }) + It("Should convert the object", func() { + source := tc.source.DeepCopyObject().(client.Object) + Expect(k8sClient.Create(ctx, source)).To(Succeed()) + Eventually(func() error { + target, err := getObject(ctx, tc.targetTpl) + if err != nil { return err - }, eventualDeletionTimeout, 1).Should(MatchError(k8serrors.IsNotFound, "IsNotFound")) - - k8sClient.Delete(ctx, testCase.targetTpl) // nolint:errcheck - Eventually(func() error { - _, err := getObject(ctx, testCase.targetTpl) - if err == nil { - return fmt.Errorf("Should be deleted") - } - return nil - }, 60, 1).Should(Succeed()) - }) - - It("Should convert the object", func() { - source := testCase.source.DeepCopyObject().(client.Object) + } + return tc.targetValidator(target) + }, 60, 1).Should(Succeed()) + }) - Expect(k8sClient.Create(ctx, source)).To(Succeed()) - Eventually(func() error { - target, err := getObject(ctx, testCase.targetTpl) - if err != nil { - return err - } - return testCase.targetValidator(target) - }, 60, 1).Should(Succeed()) - }) + It("Should update the converted object", func() { + source := tc.source.DeepCopyObject().(client.Object) + Expect(k8sClient.Create(ctx, source)).To(Succeed()) + Eventually(func() error { + _, err := getObject(ctx, tc.targetTpl) + return err + }, 60, 1).Should(Succeed()) - It("Should update the converted object", func() { - source := testCase.source.DeepCopyObject().(client.Object) + labels := source.GetLabels() + if labels == nil { + labels = make(map[string]string) + } + // Use this hack to trigger update manually for GenerationChange predicate + // It's not a problem for production workloads + // Since operator performs period syncs for parent objects + source.SetGeneration(source.GetGeneration() + 1) + labels["testKey"] = "testValue" + source.SetLabels(labels) - Expect(k8sClient.Create(ctx, source)).To(Succeed()) - Eventually(func() error { - _, err := getObject(ctx, testCase.targetTpl) + Expect(k8sClient.Update(ctx, source)).To(Succeed()) + Eventually(func() error { + target, err := getObject(ctx, tc.targetTpl) + if err != nil { return err - }, 60, 1).Should(Succeed()) - - labels := source.GetLabels() - if labels == nil { - labels = make(map[string]string) } - // Use this hack to trigger update manually for GenerationChange predicate - // It's not a problem for production workloads - // Since operator performs period syncs for parent objects - source.SetGeneration(source.GetGeneration() + 1) - labels["testKey"] = "testValue" - source.SetLabels(labels) - - Expect(k8sClient.Update(ctx, source)).To(Succeed()) - Eventually(func() error { - target, err := getObject(ctx, testCase.targetTpl) - if err != nil { - return err - } - if target.GetLabels() == nil || target.GetLabels()["testKey"] != "testValue" { - return fmt.Errorf("unexpected labels, want testKey=testValue, got: %v", target.GetLabels()) - } - return nil - }, 60, 1).Should(Succeed()) - }) + if target.GetLabels() == nil || target.GetLabels()["testKey"] != "testValue" { + return fmt.Errorf("unexpected labels, want testKey=testValue, got: %v", target.GetLabels()) + } + return nil + }, 60, 1).Should(Succeed()) + }) - It("Should delete the converted object", func() { - source := testCase.source.DeepCopyObject().(client.Object) + It("Should delete the converted object", func() { + source := tc.source.DeepCopyObject().(client.Object) + Expect(k8sClient.Create(ctx, source)).To(Succeed()) + Eventually(func() error { + _, err := getObject(ctx, tc.targetTpl) + return err + }, 60, 1).Should(Succeed()) - Expect(k8sClient.Create(ctx, source)).To(Succeed()) - Eventually(func() error { - _, err := getObject(ctx, testCase.targetTpl) + Expect(func() error { + target, err := getObject(ctx, tc.targetTpl) + if err != nil { return err - }, 60, 1).Should(Succeed()) - - Expect(func() error { - target, err := getObject(ctx, testCase.targetTpl) - if err != nil { - return err - } - if target.GetOwnerReferences() == nil { - return fmt.Errorf("expected owner reference to be non nil, object :%s", target.GetName()) - } - return nil - }()).To(Succeed()) - Expect(k8sClient.Delete(ctx, source)).To(Succeed()) - Eventually(func() error { - _, err := getObject(ctx, testCase.targetTpl) - return err - }, eventualDeletionTimeout, 1).Should(MatchError(k8serrors.IsNotFound, "IsNotFound")) - }) + } + if target.GetOwnerReferences() == nil { + return fmt.Errorf("expected owner reference to be non nil, object: %s", target.GetName()) + } + return nil + }()).To(Succeed()) + Expect(k8sClient.Delete(ctx, source)).To(Succeed()) + Eventually(func() error { + _, err := getObject(ctx, tc.targetTpl) + return err + }, eventualDeletionTimeout, 1).Should(MatchError(k8serrors.IsNotFound, "IsNotFound")) }) - } - }) + }) + } }) diff --git a/test/e2e/suite/suite.go b/test/e2e/suite/suite.go index 0b5c1aa33..27432e1f9 100644 --- a/test/e2e/suite/suite.go +++ b/test/e2e/suite/suite.go @@ -29,7 +29,6 @@ import ( "github.com/VictoriaMetrics/operator/internal/manager" ) -// var cfg *rest.Config var testEnv *envtest.Environment var cancelManager context.CancelFunc var stopped = make(chan struct{}) diff --git a/test/e2e/vlcluster_test.go b/test/e2e/vlcluster_test.go index 0c6b2d6fc..6317022d5 100644 --- a/test/e2e/vlcluster_test.go +++ b/test/e2e/vlcluster_test.go @@ -20,9 +20,8 @@ import ( ) //nolint:dupl,lll -var _ = Describe("test vlcluster Controller", Label("vl", "cluster", "vlcluster"), func() { - - Context("e2e vlcluster", func() { +var _ = Describe("vlsingle", Label("vl", "cluster"), func() { + Context("crud", func() { var ctx context.Context namespace := fmt.Sprintf("default-%d", GinkgoParallelProcess()) namespacedName := types.NamespacedName{ diff --git a/test/e2e/vlsingle_test.go b/test/e2e/vlsingle_test.go index c3eda1379..0b0f49b8a 100644 --- a/test/e2e/vlsingle_test.go +++ b/test/e2e/vlsingle_test.go @@ -21,9 +21,8 @@ import ( ) //nolint:dupl,lll -var _ = Describe("test vlsingle Controller", Label("vl", "single", "vlsingle"), func() { - - Context("e2e vlsingle", func() { +var _ = Describe("vlsingle", Label("vl", "single"), func() { + Context("crud", func() { var ctx context.Context namespace := fmt.Sprintf("default-%d", GinkgoParallelProcess()) namespacedName := types.NamespacedName{ @@ -43,279 +42,276 @@ var _ = Describe("test vlsingle Controller", Label("vl", "single", "vlsingle"), return k8sClient.Get(ctx, namespacedName, &vmv1.VLSingle{}) }, eventualDeletionTimeout).Should(MatchError(k8serrors.IsNotFound, "IsNotFound")) }) - Context("crud", func() { - DescribeTable("should create", - func(name string, cr *vmv1.VLSingle, verify func(*vmv1.VLSingle)) { - cr.Name = name - namespacedName.Name = name - Expect(k8sClient.Create(ctx, cr)).To(Succeed()) - Eventually(func() error { - return expectObjectStatusOperational(ctx, k8sClient, &vmv1.VLSingle{}, namespacedName) - }, eventualDeploymentAppReadyTimeout, - ).Should(Succeed()) + DescribeTable("should create", + func(name string, cr *vmv1.VLSingle, verify func(*vmv1.VLSingle)) { + cr.Name = name + namespacedName.Name = name + Expect(k8sClient.Create(ctx, cr)).To(Succeed()) + Eventually(func() error { + return expectObjectStatusOperational(ctx, k8sClient, &vmv1.VLSingle{}, namespacedName) + }, eventualDeploymentAppReadyTimeout, + ).Should(Succeed()) - var created vmv1.VLSingle - Expect(k8sClient.Get(ctx, namespacedName, &created)).To(Succeed()) - verify(&created) - }, - Entry("with strict security", "strict-security", - &vmv1.VLSingle{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace, + var created vmv1.VLSingle + Expect(k8sClient.Get(ctx, namespacedName, &created)).To(Succeed()) + verify(&created) + }, + Entry("with strict security", "strict-security", + &vmv1.VLSingle{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace, + }, + Spec: vmv1.VLSingleSpec{ + CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), }, - Spec: vmv1.VLSingleSpec{ - CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ - ReplicaCount: ptr.To[int32](1), - }, - CommonDefaultableParams: vmv1beta1.CommonDefaultableParams{ - UseStrictSecurity: ptr.To(true), - }, - RetentionPeriod: "1", - Storage: &corev1.PersistentVolumeClaimSpec{ - Resources: corev1.VolumeResourceRequirements{ - Requests: corev1.ResourceList{ - corev1.ResourceStorage: resource.MustParse("1Gi"), - }, + CommonDefaultableParams: vmv1beta1.CommonDefaultableParams{ + UseStrictSecurity: ptr.To(true), + }, + RetentionPeriod: "1", + Storage: &corev1.PersistentVolumeClaimSpec{ + Resources: corev1.VolumeResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceStorage: resource.MustParse("1Gi"), }, }, }, }, - func(cr *vmv1.VLSingle) { - createdChildObjects := types.NamespacedName{Namespace: namespace, Name: cr.PrefixedName()} - var createdDeploy appsv1.Deployment - Expect(k8sClient.Get(ctx, createdChildObjects, &createdDeploy)).To(Succeed()) - Expect(createdDeploy.Spec.Template.Spec.Containers).To(HaveLen(1)) - Expect(createdDeploy.Spec.Template.Spec.Containers[0].SecurityContext).NotTo(BeNil()) - Expect(createdDeploy.Spec.Template.Spec.Containers[0].SecurityContext.RunAsNonRoot).NotTo(BeNil()) - Expect(*createdDeploy.Spec.Template.Spec.Containers[0].SecurityContext.RunAsNonRoot).To(BeTrue()) + }, + func(cr *vmv1.VLSingle) { + createdChildObjects := types.NamespacedName{Namespace: namespace, Name: cr.PrefixedName()} + var createdDeploy appsv1.Deployment + Expect(k8sClient.Get(ctx, createdChildObjects, &createdDeploy)).To(Succeed()) + Expect(createdDeploy.Spec.Template.Spec.Containers).To(HaveLen(1)) + Expect(createdDeploy.Spec.Template.Spec.Containers[0].SecurityContext).NotTo(BeNil()) + Expect(createdDeploy.Spec.Template.Spec.Containers[0].SecurityContext.RunAsNonRoot).NotTo(BeNil()) + Expect(*createdDeploy.Spec.Template.Spec.Containers[0].SecurityContext.RunAsNonRoot).To(BeTrue()) - }), - Entry("with data emptyDir", "emptydir", - &vmv1.VLSingle{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace, + }), + Entry("with data emptyDir", "emptydir", + &vmv1.VLSingle{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace, + }, + Spec: vmv1.VLSingleSpec{ + CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), }, - Spec: vmv1.VLSingleSpec{ - CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ - ReplicaCount: ptr.To[int32](1), - }, - CommonDefaultableParams: vmv1beta1.CommonDefaultableParams{ - UseStrictSecurity: ptr.To(false), - }, - RetentionPeriod: "1", + CommonDefaultableParams: vmv1beta1.CommonDefaultableParams{ + UseStrictSecurity: ptr.To(false), }, + RetentionPeriod: "1", }, - func(cr *vmv1.VLSingle) { - createdChildObjects := types.NamespacedName{Namespace: namespace, Name: cr.PrefixedName()} - var createdDeploy appsv1.Deployment - Expect(k8sClient.Get(ctx, createdChildObjects, &createdDeploy)).To(Succeed()) - ts := createdDeploy.Spec.Template.Spec - Expect(ts.Containers).To(HaveLen(1)) - Expect(ts.Volumes).To(HaveLen(1)) - Expect(ts.Containers[0].VolumeMounts).To(HaveLen(1)) - }), - Entry("with external volume", "externalvolume", - &vmv1.VLSingle{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace, - }, - Spec: vmv1.VLSingleSpec{ - CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ - ReplicaCount: ptr.To[int32](1), - Volumes: []corev1.Volume{ - { - Name: "data", - VolumeSource: corev1.VolumeSource{ - EmptyDir: &corev1.EmptyDirVolumeSource{}, - }, - }, - { - Name: "unused", - VolumeSource: corev1.VolumeSource{ - EmptyDir: &corev1.EmptyDirVolumeSource{}, - }, + }, + func(cr *vmv1.VLSingle) { + createdChildObjects := types.NamespacedName{Namespace: namespace, Name: cr.PrefixedName()} + var createdDeploy appsv1.Deployment + Expect(k8sClient.Get(ctx, createdChildObjects, &createdDeploy)).To(Succeed()) + ts := createdDeploy.Spec.Template.Spec + Expect(ts.Containers).To(HaveLen(1)) + Expect(ts.Volumes).To(HaveLen(1)) + Expect(ts.Containers[0].VolumeMounts).To(HaveLen(1)) + }), + Entry("with external volume", "externalvolume", + &vmv1.VLSingle{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace, + }, + Spec: vmv1.VLSingleSpec{ + CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + Volumes: []corev1.Volume{ + { + Name: "data", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, }, }, - VolumeMounts: []corev1.VolumeMount{ - { - Name: "unused", - MountPath: "/opt/unused/mountpoint", + { + Name: "unused", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, }, }, }, - CommonDefaultableParams: vmv1beta1.CommonDefaultableParams{ - UseStrictSecurity: ptr.To(false), + VolumeMounts: []corev1.VolumeMount{ + { + Name: "unused", + MountPath: "/opt/unused/mountpoint", + }, }, - RetentionPeriod: "1", - StorageDataPath: "/custom-path/internal/dir", - Storage: &corev1.PersistentVolumeClaimSpec{}, }, + CommonDefaultableParams: vmv1beta1.CommonDefaultableParams{ + UseStrictSecurity: ptr.To(false), + }, + RetentionPeriod: "1", + StorageDataPath: "/custom-path/internal/dir", + Storage: &corev1.PersistentVolumeClaimSpec{}, }, - func(cr *vmv1.VLSingle) { - createdChildObjects := types.NamespacedName{Namespace: namespace, Name: cr.PrefixedName()} - var createdDeploy appsv1.Deployment - Expect(k8sClient.Get(ctx, createdChildObjects, &createdDeploy)).To(Succeed()) - ts := createdDeploy.Spec.Template.Spec - Expect(ts.Containers).To(HaveLen(1)) - Expect(ts.Volumes).To(HaveLen(2)) - Expect(ts.Containers[0].VolumeMounts).To(HaveLen(2)) - Expect(ts.Containers[0].VolumeMounts[0].Name).To(Equal("data")) - Expect(ts.Containers[0].VolumeMounts[1].Name).To(Equal("unused")) + }, + func(cr *vmv1.VLSingle) { + createdChildObjects := types.NamespacedName{Namespace: namespace, Name: cr.PrefixedName()} + var createdDeploy appsv1.Deployment + Expect(k8sClient.Get(ctx, createdChildObjects, &createdDeploy)).To(Succeed()) + ts := createdDeploy.Spec.Template.Spec + Expect(ts.Containers).To(HaveLen(1)) + Expect(ts.Volumes).To(HaveLen(2)) + Expect(ts.Containers[0].VolumeMounts).To(HaveLen(2)) + Expect(ts.Containers[0].VolumeMounts[0].Name).To(Equal("data")) + Expect(ts.Containers[0].VolumeMounts[1].Name).To(Equal("unused")) - }), - ) + }), + ) - baseVLSingle := &vmv1.VLSingle{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace, - }, - Spec: vmv1.VLSingleSpec{ - RetentionPeriod: "10", - CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ - ReplicaCount: ptr.To[int32](1), - }, + baseVLSingle := &vmv1.VLSingle{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace, + }, + Spec: vmv1.VLSingleSpec{ + RetentionPeriod: "10", + CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), }, - } - type testStep struct { - setup func(*vmv1.VLSingle) - modify func(*vmv1.VLSingle) - verify func(*vmv1.VLSingle) - } + }, + } + type testStep struct { + setup func(*vmv1.VLSingle) + modify func(*vmv1.VLSingle) + verify func(*vmv1.VLSingle) + } + + DescribeTable("should update exist", + func(name string, initCR *vmv1.VLSingle, steps ...testStep) { + initCR.Name = name + initCR.Namespace = namespace + namespacedName.Name = name + // setup test + Expect(k8sClient.Create(ctx, initCR)).To(Succeed()) + Eventually(func() error { + return expectObjectStatusOperational(ctx, k8sClient, &vmv1.VLSingle{}, namespacedName) + }, eventualDeploymentAppReadyTimeout).Should(Succeed()) - DescribeTable("should update exist", - func(name string, initCR *vmv1.VLSingle, steps ...testStep) { - initCR.Name = name - initCR.Namespace = namespace - namespacedName.Name = name - // setup test - Expect(k8sClient.Create(ctx, initCR)).To(Succeed()) + for _, step := range steps { + if step.setup != nil { + step.setup(initCR) + } + // perform update + Eventually(func() error { + var toUpdate vmv1.VLSingle + Expect(k8sClient.Get(ctx, namespacedName, &toUpdate)).To(Succeed()) + step.modify(&toUpdate) + return k8sClient.Update(ctx, &toUpdate) + }, eventualExpandingTimeout).Should(Succeed()) Eventually(func() error { return expectObjectStatusOperational(ctx, k8sClient, &vmv1.VLSingle{}, namespacedName) }, eventualDeploymentAppReadyTimeout).Should(Succeed()) - for _, step := range steps { - if step.setup != nil { - step.setup(initCR) - } - // perform update - Eventually(func() error { - var toUpdate vmv1.VLSingle - Expect(k8sClient.Get(ctx, namespacedName, &toUpdate)).To(Succeed()) - step.modify(&toUpdate) - return k8sClient.Update(ctx, &toUpdate) - }, eventualExpandingTimeout).Should(Succeed()) - Eventually(func() error { - return expectObjectStatusOperational(ctx, k8sClient, &vmv1.VLSingle{}, namespacedName) - }, eventualDeploymentAppReadyTimeout).Should(Succeed()) + var updated vmv1.VLSingle + Expect(k8sClient.Get(ctx, namespacedName, &updated)).To(Succeed()) - var updated vmv1.VLSingle - Expect(k8sClient.Get(ctx, namespacedName, &updated)).To(Succeed()) + // verify results + step.verify(&updated) + } + }, + Entry("add and remove annotations", "manage-annotations", + baseVLSingle.DeepCopy(), + testStep{ + modify: func(cr *vmv1.VLSingle) { + cr.Spec.ManagedMetadata = &vmv1beta1.ManagedObjectsMetadata{ + Annotations: map[string]string{ + "added-annotation": "some-value", + }, + } + }, + verify: func(cr *vmv1.VLSingle) { + nss := types.NamespacedName{Namespace: namespace, Name: cr.PrefixedName()} - // verify results - step.verify(&updated) - } + expectedAnnotations := map[string]string{"added-annotation": "some-value"} + assertAnnotationsOnObjects(ctx, nss, []client.Object{&appsv1.Deployment{}, &corev1.ServiceAccount{}, &corev1.Service{}}, expectedAnnotations) + var createdDeploy appsv1.Deployment + Expect(k8sClient.Get(ctx, nss, &createdDeploy)). + To(Succeed()) + }, }, - Entry("add and remove annotations", "manage-annotations", - baseVLSingle.DeepCopy(), - testStep{ - modify: func(cr *vmv1.VLSingle) { - cr.Spec.ManagedMetadata = &vmv1beta1.ManagedObjectsMetadata{ - Annotations: map[string]string{ - "added-annotation": "some-value", - }, - } - }, - verify: func(cr *vmv1.VLSingle) { - nss := types.NamespacedName{Namespace: namespace, Name: cr.PrefixedName()} - - expectedAnnotations := map[string]string{"added-annotation": "some-value"} - assertAnnotationsOnObjects(ctx, nss, []client.Object{&appsv1.Deployment{}, &corev1.ServiceAccount{}, &corev1.Service{}}, expectedAnnotations) - var createdDeploy appsv1.Deployment - Expect(k8sClient.Get(ctx, nss, &createdDeploy)). - To(Succeed()) - }, + testStep{ + modify: func(cr *vmv1.VLSingle) { + delete(cr.Spec.ManagedMetadata.Annotations, "added-annotation") }, - testStep{ - modify: func(cr *vmv1.VLSingle) { - delete(cr.Spec.ManagedMetadata.Annotations, "added-annotation") - }, - verify: func(cr *vmv1.VLSingle) { - nss := types.NamespacedName{Namespace: namespace, Name: cr.PrefixedName()} - expectedAnnotations := map[string]string{"added-annotation": ""} + verify: func(cr *vmv1.VLSingle) { + nss := types.NamespacedName{Namespace: namespace, Name: cr.PrefixedName()} + expectedAnnotations := map[string]string{"added-annotation": ""} - assertAnnotationsOnObjects(ctx, nss, []client.Object{&appsv1.Deployment{}, &corev1.ServiceAccount{}, &corev1.Service{}}, expectedAnnotations) + assertAnnotationsOnObjects(ctx, nss, []client.Object{&appsv1.Deployment{}, &corev1.ServiceAccount{}, &corev1.Service{}}, expectedAnnotations) - }, }, - ), - Entry("with syslog tls", "syslog-tls", - baseVLSingle.DeepCopy(), - testStep{ - modify: func(cr *vmv1.VLSingle) { - tlsSecret := corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "syslog-tls", - Namespace: namespace, - }, - StringData: map[string]string{ - "TLS_CERT": tlsCert, - "TLS_KEY": tlsKey, + }, + ), + Entry("with syslog tls", "syslog-tls", + baseVLSingle.DeepCopy(), + testStep{ + modify: func(cr *vmv1.VLSingle) { + tlsSecret := corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "syslog-tls", + Namespace: namespace, + }, + StringData: map[string]string{ + "TLS_CERT": tlsCert, + "TLS_KEY": tlsKey, + }, + } + Expect(k8sClient.Create(ctx, &tlsSecret)).To(Succeed()) + DeferCleanup(func(ctx SpecContext) { + Expect(k8sClient.Delete(ctx, &tlsSecret)).To(Succeed()) + }) + cr.Spec.SyslogSpec = &vmv1.SyslogServerSpec{ + TCPListeners: []*vmv1.SyslogTCPListener{ + { + ListenPort: 9505, + IgnoreFields: vmv1.FieldsListString(`["ip","id"]`), }, - } - Expect(k8sClient.Create(ctx, &tlsSecret)).To(Succeed()) - DeferCleanup(func(ctx SpecContext) { - Expect(k8sClient.Delete(ctx, &tlsSecret)).To(Succeed()) - }) - cr.Spec.SyslogSpec = &vmv1.SyslogServerSpec{ - TCPListeners: []*vmv1.SyslogTCPListener{ - { - ListenPort: 9505, - IgnoreFields: vmv1.FieldsListString(`["ip","id"]`), - }, - { - ListenPort: 9500, - StreamFields: vmv1.FieldsListString(`["stream", "log.message"]`), - IgnoreFields: vmv1.FieldsListString(`["_id","_container_id"]`), - TLSConfig: &vmv1.TLSServerConfig{ - CertSecret: &corev1.SecretKeySelector{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: tlsSecret.Name, - }, - Key: "TLS_CERT", + { + ListenPort: 9500, + StreamFields: vmv1.FieldsListString(`["stream", "log.message"]`), + IgnoreFields: vmv1.FieldsListString(`["_id","_container_id"]`), + TLSConfig: &vmv1.TLSServerConfig{ + CertSecret: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: tlsSecret.Name, }, - KeySecret: &corev1.SecretKeySelector{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: tlsSecret.Name, - }, - Key: "TLS_KEY", + Key: "TLS_CERT", + }, + KeySecret: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: tlsSecret.Name, }, + Key: "TLS_KEY", }, }, }, - UDPListeners: []*vmv1.SyslogUDPListener{ - { - ListenPort: 9500, - StreamFields: vmv1.FieldsListString(`["stream", "log.message"]`), - CompressMethod: "zstd", - DecolorizeFields: vmv1.FieldsListString(`["severity"]`), - }, + }, + UDPListeners: []*vmv1.SyslogUDPListener{ + { + ListenPort: 9500, + StreamFields: vmv1.FieldsListString(`["stream", "log.message"]`), + CompressMethod: "zstd", + DecolorizeFields: vmv1.FieldsListString(`["severity"]`), }, - } - }, - verify: func(cr *vmv1.VLSingle) { - var svc corev1.Service - Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: cr.PrefixedName()}, &svc)).To(Succeed()) - Expect(svc.Spec.Ports).To(HaveLen(4)) - - var dep appsv1.Deployment - Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: cr.PrefixedName()}, &dep)).To(Succeed()) - Expect(dep.Spec.Template.Spec.Volumes).To(HaveLen(2)) - Expect(dep.Spec.Template.Spec.Containers[0].VolumeMounts).To(HaveLen(2)) - }, + }, + } + }, + verify: func(cr *vmv1.VLSingle) { + var svc corev1.Service + Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: cr.PrefixedName()}, &svc)).To(Succeed()) + Expect(svc.Spec.Ports).To(HaveLen(4)) + var dep appsv1.Deployment + Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: cr.PrefixedName()}, &dep)).To(Succeed()) + Expect(dep.Spec.Template.Spec.Volumes).To(HaveLen(2)) + Expect(dep.Spec.Template.Spec.Containers[0].VolumeMounts).To(HaveLen(2)) }, - ), - ) - }, + }, + ), ) - }) + }, + ) }) diff --git a/test/e2e/vmagent_test.go b/test/e2e/vmagent_test.go index 76fa227d6..0a6a02098 100644 --- a/test/e2e/vmagent_test.go +++ b/test/e2e/vmagent_test.go @@ -21,15 +21,17 @@ import ( ) //nolint:dupl,lll -var _ = Describe("test vmagent Controller", Label("vm", "agent", "vmagent"), func() { - ctx := context.Background() - Context("e2e vmagent", func() { +var _ = Describe("vmagent", Label("vm", "agent"), func() { + tlsSecretName := "vmagent-remote-tls-certs" + Context("crud", func() { + var ctx context.Context namespace := fmt.Sprintf("default-%d", GinkgoParallelProcess()) namespacedName := types.NamespacedName{ Namespace: namespace, } - tlsSecretName := "vmagent-remote-tls-certs" - + BeforeEach(func() { + ctx = context.Background() + }) AfterEach(func() { Expect(k8sClient.Delete(ctx, &vmv1beta1.VMAgent{ ObjectMeta: metav1.ObjectMeta{ diff --git a/test/e2e/vmalert_test.go b/test/e2e/vmalert_test.go index 1ed271b56..88f169232 100644 --- a/test/e2e/vmalert_test.go +++ b/test/e2e/vmalert_test.go @@ -18,14 +18,17 @@ import ( ) //nolint:dupl -var _ = Describe("test vmalert Controller", Label("vm", "alert"), func() { - ctx := context.Background() - - Context("e2e vmalert", func() { +var _ = Describe("vmalert", Label("vm", "alert"), func() { + tlsSecretName := "vmalert-remote-tls" + Context("crud", func() { + var ctx context.Context namespace := fmt.Sprintf("default-%d", GinkgoParallelProcess()) namespacedName := types.NamespacedName{ Namespace: namespace, } + BeforeEach(func() { + ctx = context.Background() + }) AfterEach(func() { Expect(k8sClient.Delete(ctx, &vmv1beta1.VMAlert{ ObjectMeta: metav1.ObjectMeta{ @@ -41,7 +44,6 @@ var _ = Describe("test vmalert Controller", Label("vm", "alert"), func() { }, &vmv1beta1.VMAlert{}) }, eventualDeletionTimeout, 1).Should(MatchError(k8serrors.IsNotFound, "IsNotFound")) }) - tlsSecretName := "vmalert-remote-tls" DescribeTable("should create vmalert", func(name string, cr *vmv1beta1.VMAlert, setup func(), verify func(*vmv1beta1.VMAlert)) { diff --git a/test/e2e/vmalertmanager_test.go b/test/e2e/vmalertmanager_test.go index 7cac74119..aef44e3e1 100644 --- a/test/e2e/vmalertmanager_test.go +++ b/test/e2e/vmalertmanager_test.go @@ -37,15 +37,16 @@ receivers: ) //nolint:dupl -var _ = Describe("test vmalertmanager Controller", Label("vm", "alertmanager"), func() { - - Context("e2e vmalertmanager", func() { - ctx := context.Background() +var _ = Describe("vmalertmanager", Label("vm", "alertmanager"), func() { + Context("crud", func() { + var ctx context.Context namespace := fmt.Sprintf("default-%d", GinkgoParallelProcess()) namespacedName := types.NamespacedName{ Namespace: namespace, } - + BeforeEach(func() { + ctx = context.Background() + }) // delete test results AfterEach(func() { Expect(finalize.SafeDelete(ctx, k8sClient, &vmv1beta1.VMAlertmanager{ diff --git a/test/e2e/vmanomaly_test.go b/test/e2e/vmanomaly_test.go index 06d8e7e1f..de87d70ca 100644 --- a/test/e2e/vmanomaly_test.go +++ b/test/e2e/vmanomaly_test.go @@ -60,61 +60,46 @@ var ( ) //nolint:dupl,lll -var _ = Describe("test vmanomaly Controller", Label("vm", "anomaly", "enterprise"), func() { - ctx := context.Background() - namespace := fmt.Sprintf("default-%d", GinkgoParallelProcess()) - anomalyDatasourceURL := fmt.Sprintf("http://vmsingle-anomaly.%s.svc:8428", namespace) - anomalySingle := vmv1beta1.VMSingle{ - ObjectMeta: metav1.ObjectMeta{ - Name: "anomaly", - Namespace: namespace, - }, - } +var _ = Describe("vmanomaly", Label("vm", "anomaly", "enterprise"), func() { + tlsSecretName := "vmanomaly-remote-tls-certs" licenseKey := os.Getenv("LICENSE_KEY") - BeforeEach(func() { - if licenseKey == "" { - Skip("ignoring VMAnomaly tests, license was not found") - } - Expect(k8sClient.Create(ctx, - &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "license", - Namespace: namespace, - }, - StringData: map[string]string{ - "key": licenseKey, - }, - }, - )).To(Succeed()) - - Expect(k8sClient.Create(ctx, &anomalySingle)).To(Succeed()) - Eventually(func() error { - return expectObjectStatusOperational(ctx, k8sClient, &vmv1beta1.VMSingle{}, types.NamespacedName{Name: anomalySingle.Name, Namespace: namespace}) - }, eventualDeploymentAppReadyTimeout, - ).Should(Succeed()) - - }) - AfterEach(func() { - Expect(k8sClient.Delete(ctx, - &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "license", - Namespace: namespace, - }, - }, - )).To(Succeed()) - Expect(k8sClient.Delete(ctx, &anomalySingle)).To(Succeed()) - Eventually(func() error { - return k8sClient.Get(context.Background(), types.NamespacedName{Name: anomalySingle.Name, Namespace: namespace}, &vmv1beta1.VMSingle{}) - }, eventualDeletionTimeout, 1).Should(MatchError(k8serrors.IsNotFound, "IsNotFound")) - - }) - Context("e2e vmanomaly", func() { + Context("crud", func() { + var ctx context.Context namespace := fmt.Sprintf("default-%d", GinkgoParallelProcess()) namespacedName := types.NamespacedName{ Namespace: namespace, } - tlsSecretName := "vmanomaly-remote-tls-certs" + anomalyDatasourceURL := fmt.Sprintf("http://vmsingle-anomaly.%s.svc:8428", namespace) + anomalySingle := vmv1beta1.VMSingle{ + ObjectMeta: metav1.ObjectMeta{ + Name: "anomaly", + Namespace: namespace, + }, + } + BeforeEach(func() { + ctx = context.Background() + if licenseKey == "" { + Skip("ignoring VMAnomaly tests, license was not found") + } + Expect(k8sClient.Create(ctx, + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "license", + Namespace: namespace, + }, + StringData: map[string]string{ + "key": licenseKey, + }, + }, + )).To(Succeed()) + + Expect(k8sClient.Create(ctx, &anomalySingle)).To(Succeed()) + Eventually(func() error { + return expectObjectStatusOperational(ctx, k8sClient, &vmv1beta1.VMSingle{}, types.NamespacedName{Name: anomalySingle.Name, Namespace: namespace}) + }, eventualDeploymentAppReadyTimeout, + ).Should(Succeed()) + + }) AfterEach(func() { Expect(k8sClient.Delete(ctx, &vmv1.VMAnomaly{ @@ -130,6 +115,21 @@ var _ = Describe("test vmanomaly Controller", Label("vm", "anomaly", "enterprise Namespace: namespacedName.Namespace, }, &vmv1.VMAnomaly{}) }, anomalyDeleteTimeout, 1).Should(MatchError(k8serrors.IsNotFound, "IsNotFound")) + Expect(k8sClient.Delete(ctx, + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "license", + Namespace: namespace, + }, + }, + )).To(Succeed()) + Expect(k8sClient.Delete(ctx, &anomalySingle)).To(Succeed()) + Eventually(func() error { + return k8sClient.Get(ctx, types.NamespacedName{ + Name: anomalySingle.Name, + Namespace: namespace, + }, &vmv1beta1.VMSingle{}) + }, eventualDeletionTimeout, 1).Should(MatchError(k8serrors.IsNotFound, "IsNotFound")) }) DescribeTable("should create vmanomaly", func(name string, cr *vmv1.VMAnomaly, setup func(), verify func(*vmv1.VMAnomaly)) { diff --git a/test/e2e/vmauth_test.go b/test/e2e/vmauth_test.go index feb7efe2c..83845cd6d 100644 --- a/test/e2e/vmauth_test.go +++ b/test/e2e/vmauth_test.go @@ -22,43 +22,151 @@ import ( ) //nolint:dupl -var _ = Describe("test vmauth Controller", Label("vm", "auth"), func() { - Context("e2e ", func() { +var _ = Describe("vmauth", Label("vm", "auth"), func() { + Context("crud", func() { var ctx context.Context namespace := fmt.Sprintf("default-%d", GinkgoParallelProcess()) namespacedName := types.NamespacedName{ Namespace: namespace, } + BeforeEach(func() { + ctx = context.Background() + }) + AfterEach(func() { + Expect(finalize.SafeDelete(ctx, k8sClient, &vmv1beta1.VMAuth{ + ObjectMeta: metav1.ObjectMeta{ + Name: namespacedName.Name, + Namespace: namespacedName.Namespace, + }, + })).To(Succeed()) + Eventually(func() error { + return k8sClient.Get(ctx, namespacedName, &vmv1beta1.VMAuth{}) + }, eventualDeletionTimeout).Should(MatchError(k8serrors.IsNotFound, "IsNotFound")) + }) + DescribeTable("should create vmauth", func(name string, cr *vmv1beta1.VMAuth, verify func(cr *vmv1beta1.VMAuth)) { + namespacedName.Name = name + cr.Name = name + Expect(k8sClient.Create(ctx, cr)).To(Succeed()) + Eventually(func() error { + return expectObjectStatusOperational(ctx, k8sClient, &vmv1beta1.VMAuth{}, namespacedName) + }, eventualDeploymentAppReadyTimeout).Should(Succeed()) + verify(cr) + }, + Entry("with 1 replica", "replica-1", &vmv1beta1.VMAuth{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespacedName.Namespace, + }, + Spec: vmv1beta1.VMAuthSpec{ + CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + }, + UnauthorizedAccessConfig: []vmv1beta1.UnauthorizedAccessConfigURLMap{ + { + URLPrefix: []string{"http://localhost:8490"}, + SrcPaths: []string{"/.*"}, + }, + }, + }, + }, func(cr *vmv1beta1.VMAuth) { + Expect(expectPodCount(k8sClient, 1, cr.Namespace, cr.SelectorLabels())).To(BeEmpty()) + var dep appsv1.Deployment + Expect(k8sClient.Get(ctx, types.NamespacedName{Name: cr.PrefixedName(), Namespace: namespace}, &dep)).To(Succeed()) + ps := dep.Spec.Template.Spec + reloaderContainer := ps.Containers[1] + Expect(reloaderContainer.Name).To(Equal("config-reloader")) + Expect(reloaderContainer.Resources.Limits.Cpu().CmpInt64(0)).To(Equal(0)) + Expect(reloaderContainer.Resources.Limits.Memory().CmpInt64(0)).To(Equal(0)) + Expect(reloaderContainer.Resources.Requests.Cpu()).To(Equal(ptr.To(resource.MustParse("10m")))) + Expect(reloaderContainer.Resources.Requests.Memory()).To(Equal(ptr.To(resource.MustParse("25Mi")))) + }), + Entry("with strict security and vm config-reloader", "strict-with-reloader", &vmv1beta1.VMAuth{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespacedName.Namespace, + }, + Spec: vmv1beta1.VMAuthSpec{ + CommonDefaultableParams: vmv1beta1.CommonDefaultableParams{ + UseStrictSecurity: ptr.To(true), + UseDefaultResources: ptr.To(false), + }, + CommonConfigReloaderParams: vmv1beta1.CommonConfigReloaderParams{ + UseVMConfigReloader: ptr.To(true), + }, + CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + DisableAutomountServiceAccountToken: true, + }, + UnauthorizedAccessConfig: []vmv1beta1.UnauthorizedAccessConfigURLMap{ + { + URLPrefix: []string{"http://localhost:8490"}, + SrcPaths: []string{"/.*"}, + }, + }, + }, + }, func(cr *vmv1beta1.VMAuth) { + Expect(expectPodCount(k8sClient, 1, cr.Namespace, cr.SelectorLabels())).To(BeEmpty()) + var dep appsv1.Deployment + Expect(k8sClient.Get(ctx, types.NamespacedName{Name: cr.PrefixedName(), Namespace: namespace}, &dep)).To(Succeed()) + ps := dep.Spec.Template.Spec + Expect(ps.SecurityContext).NotTo(BeNil()) + Expect(ps.SecurityContext.RunAsNonRoot).NotTo(BeNil()) + Expect(ps.Containers).To(HaveLen(2)) + Expect(ps.InitContainers).To(HaveLen(1)) + Expect(ps.Containers[0].SecurityContext).NotTo(BeNil()) + Expect(ps.Containers[1].SecurityContext).NotTo(BeNil()) + Expect(ps.InitContainers[0].SecurityContext).NotTo(BeNil()) + Expect(ps.Containers[0].SecurityContext.AllowPrivilegeEscalation).NotTo(BeNil()) + Expect(ps.Containers[1].SecurityContext.AllowPrivilegeEscalation).NotTo(BeNil()) + Expect(ps.InitContainers[0].SecurityContext.AllowPrivilegeEscalation).NotTo(BeNil()) - Context("crud", func() { + // assert k8s api access + saTokenMount := "/var/run/secrets/kubernetes.io/serviceaccount" + vmauthPod := mustGetFirstPod(k8sClient, namespace, cr.SelectorLabels()) + Expect(hasVolumeMount(vmauthPod.Spec.Containers[0].VolumeMounts, saTokenMount)).NotTo(Succeed()) + Expect(hasVolume(dep.Spec.Template.Spec.Volumes, "kube-api-access")).To(Succeed()) + Expect(hasVolumeMount(ps.Containers[1].VolumeMounts, saTokenMount)).To(Succeed()) + Expect(hasVolumeMount(ps.InitContainers[0].VolumeMounts, saTokenMount)).To(Succeed()) + }), + ) - JustBeforeEach(func() { - ctx = context.Background() - }) - AfterEach(func() { - Expect(finalize.SafeDelete(ctx, k8sClient, &vmv1beta1.VMAuth{ - ObjectMeta: metav1.ObjectMeta{ - Name: namespacedName.Name, - Namespace: namespacedName.Namespace, - }, - })).To(Succeed()) - Eventually(func() error { - return k8sClient.Get(ctx, namespacedName, &vmv1beta1.VMAuth{}) - }, eventualDeletionTimeout).Should(MatchError(k8serrors.IsNotFound, "IsNotFound")) - }) - DescribeTable("should create vmauth", func(name string, cr *vmv1beta1.VMAuth, verify func(cr *vmv1beta1.VMAuth)) { + type testStep struct { + setup func(*vmv1beta1.VMAuth) + modify func(*vmv1beta1.VMAuth) + verify func(*vmv1beta1.VMAuth) + } + DescribeTable("should update exist vmauth", + func(name string, initCR *vmv1beta1.VMAuth, steps ...testStep) { + + initCR.Name = name + initCR.Namespace = namespace namespacedName.Name = name - cr.Name = name - Expect(k8sClient.Create(ctx, cr)).To(Succeed()) + // setup test + Expect(k8sClient.Create(ctx, initCR)).To(Succeed()) Eventually(func() error { return expectObjectStatusOperational(ctx, k8sClient, &vmv1beta1.VMAuth{}, namespacedName) }, eventualDeploymentAppReadyTimeout).Should(Succeed()) - verify(cr) + for _, step := range steps { + if step.setup != nil { + step.setup(initCR) + } + // perform update + Eventually(func() error { + var toUpdate vmv1beta1.VMAuth + Expect(k8sClient.Get(ctx, namespacedName, &toUpdate)).To(Succeed()) + step.modify(&toUpdate) + return k8sClient.Update(ctx, &toUpdate) + }, eventualExpandingTimeout).Should(Succeed()) + Eventually(func() error { + return expectObjectStatusOperational(ctx, k8sClient, &vmv1beta1.VMAuth{}, namespacedName) + }, eventualDeploymentAppReadyTimeout).Should(Succeed()) + var updated vmv1beta1.VMAuth + Expect(k8sClient.Get(ctx, namespacedName, &updated)).To(Succeed()) + // verify results + step.verify(&updated) + } + }, - Entry("with 1 replica", "replica-1", &vmv1beta1.VMAuth{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespacedName.Namespace, - }, + Entry("by changing replicas to 2", "update-replicas-2", + &vmv1beta1.VMAuth{ Spec: vmv1beta1.VMAuthSpec{ CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ ReplicaCount: ptr.To[int32](1), @@ -70,33 +178,24 @@ var _ = Describe("test vmauth Controller", Label("vm", "auth"), func() { }, }, }, - }, func(cr *vmv1beta1.VMAuth) { - Expect(expectPodCount(k8sClient, 1, cr.Namespace, cr.SelectorLabels())).To(BeEmpty()) - var dep appsv1.Deployment - Expect(k8sClient.Get(ctx, types.NamespacedName{Name: cr.PrefixedName(), Namespace: namespace}, &dep)).To(Succeed()) - ps := dep.Spec.Template.Spec - reloaderContainer := ps.Containers[1] - Expect(reloaderContainer.Name).To(Equal("config-reloader")) - Expect(reloaderContainer.Resources.Limits.Cpu().CmpInt64(0)).To(Equal(0)) - Expect(reloaderContainer.Resources.Limits.Memory().CmpInt64(0)).To(Equal(0)) - Expect(reloaderContainer.Resources.Requests.Cpu()).To(Equal(ptr.To(resource.MustParse("10m")))) - Expect(reloaderContainer.Resources.Requests.Memory()).To(Equal(ptr.To(resource.MustParse("25Mi")))) - }), - Entry("with strict security and vm config-reloader", "strict-with-reloader", &vmv1beta1.VMAuth{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespacedName.Namespace, + }, + testStep{ + modify: func(cr *vmv1beta1.VMAuth) { + cr.Spec.ReplicaCount = ptr.To[int32](2) + }, + verify: func(cr *vmv1beta1.VMAuth) { + Eventually(func() string { + return expectPodCount(k8sClient, 2, namespace, cr.SelectorLabels()) + }, eventualDeploymentPodTimeout).Should(BeEmpty()) }, + }, + ), + Entry("by switching to vm config reloader", "vm-reloader", + &vmv1beta1.VMAuth{ Spec: vmv1beta1.VMAuthSpec{ - CommonDefaultableParams: vmv1beta1.CommonDefaultableParams{ - UseStrictSecurity: ptr.To(true), - UseDefaultResources: ptr.To(false), - }, - CommonConfigReloaderParams: vmv1beta1.CommonConfigReloaderParams{ - UseVMConfigReloader: ptr.To(true), - }, + SelectAllByDefault: true, CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ - ReplicaCount: ptr.To[int32](1), - DisableAutomountServiceAccountToken: true, + ReplicaCount: ptr.To[int32](1), }, UnauthorizedAccessConfig: []vmv1beta1.UnauthorizedAccessConfigURLMap{ { @@ -105,452 +204,349 @@ var _ = Describe("test vmauth Controller", Label("vm", "auth"), func() { }, }, }, - }, func(cr *vmv1beta1.VMAuth) { - Expect(expectPodCount(k8sClient, 1, cr.Namespace, cr.SelectorLabels())).To(BeEmpty()) - var dep appsv1.Deployment - Expect(k8sClient.Get(ctx, types.NamespacedName{Name: cr.PrefixedName(), Namespace: namespace}, &dep)).To(Succeed()) - ps := dep.Spec.Template.Spec - Expect(ps.SecurityContext).NotTo(BeNil()) - Expect(ps.SecurityContext.RunAsNonRoot).NotTo(BeNil()) - Expect(ps.Containers).To(HaveLen(2)) - Expect(ps.InitContainers).To(HaveLen(1)) - Expect(ps.Containers[0].SecurityContext).NotTo(BeNil()) - Expect(ps.Containers[1].SecurityContext).NotTo(BeNil()) - Expect(ps.InitContainers[0].SecurityContext).NotTo(BeNil()) - Expect(ps.Containers[0].SecurityContext.AllowPrivilegeEscalation).NotTo(BeNil()) - Expect(ps.Containers[1].SecurityContext.AllowPrivilegeEscalation).NotTo(BeNil()) - Expect(ps.InitContainers[0].SecurityContext.AllowPrivilegeEscalation).NotTo(BeNil()) - - // assert k8s api access - saTokenMount := "/var/run/secrets/kubernetes.io/serviceaccount" - vmauthPod := mustGetFirstPod(k8sClient, namespace, cr.SelectorLabels()) - Expect(hasVolumeMount(vmauthPod.Spec.Containers[0].VolumeMounts, saTokenMount)).NotTo(Succeed()) - Expect(hasVolume(dep.Spec.Template.Spec.Volumes, "kube-api-access")).To(Succeed()) - Expect(hasVolumeMount(ps.Containers[1].VolumeMounts, saTokenMount)).To(Succeed()) - Expect(hasVolumeMount(ps.InitContainers[0].VolumeMounts, saTokenMount)).To(Succeed()) - }), - ) - - type testStep struct { - setup func(*vmv1beta1.VMAuth) - modify func(*vmv1beta1.VMAuth) - verify func(*vmv1beta1.VMAuth) - } - DescribeTable("should update exist vmauth", - func(name string, initCR *vmv1beta1.VMAuth, steps ...testStep) { - - initCR.Name = name - initCR.Namespace = namespace - namespacedName.Name = name - // setup test - Expect(k8sClient.Create(ctx, initCR)).To(Succeed()) - Eventually(func() error { - return expectObjectStatusOperational(ctx, k8sClient, &vmv1beta1.VMAuth{}, namespacedName) - }, eventualDeploymentAppReadyTimeout).Should(Succeed()) - for _, step := range steps { - if step.setup != nil { - step.setup(initCR) - } - // perform update - Eventually(func() error { - var toUpdate vmv1beta1.VMAuth - Expect(k8sClient.Get(ctx, namespacedName, &toUpdate)).To(Succeed()) - step.modify(&toUpdate) - return k8sClient.Update(ctx, &toUpdate) - }, eventualExpandingTimeout).Should(Succeed()) - Eventually(func() error { - return expectObjectStatusOperational(ctx, k8sClient, &vmv1beta1.VMAuth{}, namespacedName) - }, eventualDeploymentAppReadyTimeout).Should(Succeed()) - var updated vmv1beta1.VMAuth - Expect(k8sClient.Get(ctx, namespacedName, &updated)).To(Succeed()) - // verify results - step.verify(&updated) - } - }, - Entry("by changing replicas to 2", "update-replicas-2", - &vmv1beta1.VMAuth{ - Spec: vmv1beta1.VMAuthSpec{ - CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ - ReplicaCount: ptr.To[int32](1), - }, - UnauthorizedAccessConfig: []vmv1beta1.UnauthorizedAccessConfigURLMap{ - { - URLPrefix: []string{"http://localhost:8490"}, - SrcPaths: []string{"/.*"}, - }, - }, - }, + testStep{ + modify: func(cr *vmv1beta1.VMAuth) { + cr.Spec.UseVMConfigReloader = ptr.To(true) + cr.Spec.UseDefaultResources = ptr.To(false) }, - testStep{ - modify: func(cr *vmv1beta1.VMAuth) { - cr.Spec.ReplicaCount = ptr.To[int32](2) - }, - verify: func(cr *vmv1beta1.VMAuth) { - Eventually(func() string { - return expectPodCount(k8sClient, 2, namespace, cr.SelectorLabels()) - }, eventualDeploymentPodTimeout).Should(BeEmpty()) - }, + verify: func(cr *vmv1beta1.VMAuth) { + Eventually(func() string { + return expectPodCount(k8sClient, 1, namespace, cr.SelectorLabels()) + }, eventualDeploymentPodTimeout).Should(BeEmpty()) }, - ), - Entry("by switching to vm config reloader", "vm-reloader", - &vmv1beta1.VMAuth{ - Spec: vmv1beta1.VMAuthSpec{ - SelectAllByDefault: true, - CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ - ReplicaCount: ptr.To[int32](1), + }, + testStep{ + modify: func(cr *vmv1beta1.VMAuth) { + authSecret := corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "reload-auth-key", + Namespace: namespace, }, - UnauthorizedAccessConfig: []vmv1beta1.UnauthorizedAccessConfigURLMap{ - { - URLPrefix: []string{"http://localhost:8490"}, - SrcPaths: []string{"/.*"}, - }, + StringData: map[string]string{ + "SECRET_VALUE": "some-auth-value", }, - }, + } + Expect(k8sClient.Create(ctx, &authSecret)).To(Succeed()) + DeferCleanup(func(ctx SpecContext) { + Expect(k8sClient.Delete(ctx, &authSecret)).To(Succeed()) + }) + cr.Spec.ConfigReloadAuthKeySecret = &corev1.SecretKeySelector{ + Key: "SECRET_VALUE", + LocalObjectReference: corev1.LocalObjectReference{ + Name: authSecret.Name, + }, + } }, - testStep{ - modify: func(cr *vmv1beta1.VMAuth) { - cr.Spec.UseVMConfigReloader = ptr.To(true) - cr.Spec.UseDefaultResources = ptr.To(false) - }, - verify: func(cr *vmv1beta1.VMAuth) { - Eventually(func() string { - return expectPodCount(k8sClient, 1, namespace, cr.SelectorLabels()) - }, eventualDeploymentPodTimeout).Should(BeEmpty()) - }, + verify: func(cr *vmv1beta1.VMAuth) { + Eventually(func() string { + return expectPodCount(k8sClient, 1, namespace, cr.SelectorLabels()) + }, eventualDeploymentPodTimeout).Should(BeEmpty()) }, - testStep{ - modify: func(cr *vmv1beta1.VMAuth) { - authSecret := corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "reload-auth-key", - Namespace: namespace, - }, - StringData: map[string]string{ - "SECRET_VALUE": "some-auth-value", - }, - } - Expect(k8sClient.Create(ctx, &authSecret)).To(Succeed()) - DeferCleanup(func(ctx SpecContext) { - Expect(k8sClient.Delete(ctx, &authSecret)).To(Succeed()) - }) - cr.Spec.ConfigReloadAuthKeySecret = &corev1.SecretKeySelector{ - Key: "SECRET_VALUE", - LocalObjectReference: corev1.LocalObjectReference{ - Name: authSecret.Name, - }, - } + }, + ), + Entry("by switching to internal listen port", "vm-internal-listen", + &vmv1beta1.VMAuth{ + Spec: vmv1beta1.VMAuthSpec{ + SelectAllByDefault: true, + CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), }, - verify: func(cr *vmv1beta1.VMAuth) { - Eventually(func() string { - return expectPodCount(k8sClient, 1, namespace, cr.SelectorLabels()) - }, eventualDeploymentPodTimeout).Should(BeEmpty()) + CommonDefaultableParams: vmv1beta1.CommonDefaultableParams{ + UseDefaultResources: ptr.To(false), + }, + CommonConfigReloaderParams: vmv1beta1.CommonConfigReloaderParams{ + UseVMConfigReloader: ptr.To(true), }, - }, - ), - Entry("by switching to internal listen port", "vm-internal-listen", - &vmv1beta1.VMAuth{ - Spec: vmv1beta1.VMAuthSpec{ - SelectAllByDefault: true, - CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ - ReplicaCount: ptr.To[int32](1), - }, - CommonDefaultableParams: vmv1beta1.CommonDefaultableParams{ - UseDefaultResources: ptr.To(false), - }, - CommonConfigReloaderParams: vmv1beta1.CommonConfigReloaderParams{ - UseVMConfigReloader: ptr.To(true), - }, - UnauthorizedAccessConfig: []vmv1beta1.UnauthorizedAccessConfigURLMap{ - { - URLPrefix: []string{"http://localhost:8490"}, - SrcPaths: []string{"/.*"}, - }, + UnauthorizedAccessConfig: []vmv1beta1.UnauthorizedAccessConfigURLMap{ + { + URLPrefix: []string{"http://localhost:8490"}, + SrcPaths: []string{"/.*"}, }, }, }, - testStep{ - modify: func(cr *vmv1beta1.VMAuth) { - cr.Spec.InternalListenPort = "8426" + }, + testStep{ + modify: func(cr *vmv1beta1.VMAuth) { + cr.Spec.InternalListenPort = "8426" + }, + verify: func(cr *vmv1beta1.VMAuth) { + Eventually(func() string { + return expectPodCount(k8sClient, 1, namespace, cr.SelectorLabels()) + }, eventualDeploymentPodTimeout).Should(BeEmpty()) + pod := mustGetFirstPod(k8sClient, cr.Namespace, cr.SelectorLabels()) + Expect(pod.Spec.Containers).To(HaveLen(2)) + ac := pod.Spec.Containers[0] + Expect(ac.Ports).To(HaveLen(2)) + Expect(ac.Ports[1].ContainerPort).To(Equal(int32(8426))) + nsn := types.NamespacedName{ + Namespace: cr.Namespace, + Name: cr.PrefixedName(), + } + var svc corev1.Service + Expect(k8sClient.Get(ctx, nsn, &svc)).To(Succeed()) + Expect(svc.Spec.Ports).To(HaveLen(2)) + var vmss vmv1beta1.VMServiceScrape + Expect(k8sClient.Get(ctx, nsn, &vmss)).To(Succeed()) + Expect(vmss.Spec.Endpoints).To(HaveLen(1)) + ep := vmss.Spec.Endpoints[0] + Expect(ep.Port).To(Equal("internal")) + }, + }, + ), + Entry("by removing podDisruptionBudget and keeping exist ingress", "vm-keep-ingress-change-pdb", + &vmv1beta1.VMAuth{ + Spec: vmv1beta1.VMAuthSpec{ + SelectAllByDefault: true, + CommonDefaultableParams: vmv1beta1.CommonDefaultableParams{ + UseDefaultResources: ptr.To(false), }, - verify: func(cr *vmv1beta1.VMAuth) { - Eventually(func() string { - return expectPodCount(k8sClient, 1, namespace, cr.SelectorLabels()) - }, eventualDeploymentPodTimeout).Should(BeEmpty()) - pod := mustGetFirstPod(k8sClient, cr.Namespace, cr.SelectorLabels()) - Expect(pod.Spec.Containers).To(HaveLen(2)) - ac := pod.Spec.Containers[0] - Expect(ac.Ports).To(HaveLen(2)) - Expect(ac.Ports[1].ContainerPort).To(Equal(int32(8426))) - nsn := types.NamespacedName{ - Namespace: cr.Namespace, - Name: cr.PrefixedName(), - } - var svc corev1.Service - Expect(k8sClient.Get(ctx, nsn, &svc)).To(Succeed()) - Expect(svc.Spec.Ports).To(HaveLen(2)) - var vmss vmv1beta1.VMServiceScrape - Expect(k8sClient.Get(ctx, nsn, &vmss)).To(Succeed()) - Expect(vmss.Spec.Endpoints).To(HaveLen(1)) - ep := vmss.Spec.Endpoints[0] - Expect(ep.Port).To(Equal("internal")) + CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](2), }, - }, - ), - Entry("by removing podDisruptionBudget and keeping exist ingress", "vm-keep-ingress-change-pdb", - &vmv1beta1.VMAuth{ - Spec: vmv1beta1.VMAuthSpec{ - SelectAllByDefault: true, - CommonDefaultableParams: vmv1beta1.CommonDefaultableParams{ - UseDefaultResources: ptr.To(false), - }, - CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ - ReplicaCount: ptr.To[int32](2), - }, - PodDisruptionBudget: &vmv1beta1.EmbeddedPodDisruptionBudgetSpec{ - MaxUnavailable: &intstr.IntOrString{IntVal: 1}, - }, - UnauthorizedAccessConfig: []vmv1beta1.UnauthorizedAccessConfigURLMap{ - { - URLPrefix: []string{"http://localhost:8490"}, - SrcPaths: []string{"/.*"}, - }, + PodDisruptionBudget: &vmv1beta1.EmbeddedPodDisruptionBudgetSpec{ + MaxUnavailable: &intstr.IntOrString{IntVal: 1}, + }, + UnauthorizedAccessConfig: []vmv1beta1.UnauthorizedAccessConfigURLMap{ + { + URLPrefix: []string{"http://localhost:8490"}, + SrcPaths: []string{"/.*"}, }, }, }, - testStep{ - setup: func(cr *vmv1beta1.VMAuth) { - ing := &networkingv1.Ingress{ - // intentionally use the same prefixed name - ObjectMeta: metav1.ObjectMeta{ - Name: cr.PrefixedName(), - Namespace: cr.Namespace, - }, - Spec: networkingv1.IngressSpec{ - Rules: []networkingv1.IngressRule{ - { - Host: "vmauth.example.com", - IngressRuleValue: networkingv1.IngressRuleValue{ - HTTP: &networkingv1.HTTPIngressRuleValue{ - Paths: []networkingv1.HTTPIngressPath{ - {Path: "/", PathType: ptr.To(networkingv1.PathTypePrefix), Backend: networkingv1.IngressBackend{ - Service: &networkingv1.IngressServiceBackend{ - Name: cr.PrefixedName(), - Port: networkingv1.ServiceBackendPort{Number: 8427}, - }, - }}, - }, + }, + testStep{ + setup: func(cr *vmv1beta1.VMAuth) { + ing := &networkingv1.Ingress{ + // intentionally use the same prefixed name + ObjectMeta: metav1.ObjectMeta{ + Name: cr.PrefixedName(), + Namespace: cr.Namespace, + }, + Spec: networkingv1.IngressSpec{ + Rules: []networkingv1.IngressRule{ + { + Host: "vmauth.example.com", + IngressRuleValue: networkingv1.IngressRuleValue{ + HTTP: &networkingv1.HTTPIngressRuleValue{ + Paths: []networkingv1.HTTPIngressPath{ + {Path: "/", PathType: ptr.To(networkingv1.PathTypePrefix), Backend: networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: cr.PrefixedName(), + Port: networkingv1.ServiceBackendPort{Number: 8427}, + }, + }}, }, }, }, }, }, - } - Expect(k8sClient.Create(ctx, ing)).To(Succeed()) - Expect(k8sClient.Get(ctx, - types.NamespacedName{Name: cr.PrefixedName(), Namespace: namespace}, - &policyv1.PodDisruptionBudget{})).To(Succeed()) - }, - modify: func(cr *vmv1beta1.VMAuth) { - cr.Spec.PodDisruptionBudget = nil - }, - verify: func(cr *vmv1beta1.VMAuth) { - Eventually(func() string { - return expectPodCount(k8sClient, 2, namespace, cr.SelectorLabels()) - }, eventualDeploymentPodTimeout).Should(BeEmpty()) - nsn := types.NamespacedName{Namespace: cr.Namespace, Name: cr.PrefixedName()} - Expect(k8sClient.Get(ctx, nsn, &networkingv1.Ingress{})).To(Succeed()) - Eventually(func() error { - return k8sClient.Get(ctx, nsn, &policyv1.PodDisruptionBudget{}) - }, eventualDeletionTimeout).Should(MatchError(k8serrors.IsNotFound, "IsNotFound")) - }, + }, + } + Expect(k8sClient.Create(ctx, ing)).To(Succeed()) + Expect(k8sClient.Get(ctx, + types.NamespacedName{Name: cr.PrefixedName(), Namespace: namespace}, + &policyv1.PodDisruptionBudget{})).To(Succeed()) }, - testStep{ - modify: func(cr *vmv1beta1.VMAuth) { - cr.Spec.PodDisruptionBudget = &vmv1beta1.EmbeddedPodDisruptionBudgetSpec{ - MaxUnavailable: &intstr.IntOrString{IntVal: 1}, - } - }, - verify: func(cr *vmv1beta1.VMAuth) { - nsn := types.NamespacedName{Namespace: cr.Namespace, Name: cr.PrefixedName()} - Expect(k8sClient.Get(ctx, nsn, &networkingv1.Ingress{})).To(Succeed()) - Expect(k8sClient.Get(ctx, nsn, &policyv1.PodDisruptionBudget{})).To(Succeed()) - Expect(k8sClient.Delete(ctx, &networkingv1.Ingress{ObjectMeta: metav1.ObjectMeta{ - Name: nsn.Name, - Namespace: nsn.Namespace, - }})).To(Succeed()) - }, + modify: func(cr *vmv1beta1.VMAuth) { + cr.Spec.PodDisruptionBudget = nil }, - ), - Entry("by migrating from configSecret to externalConfig.secretRef", "ext-config", - &vmv1beta1.VMAuth{ - Spec: vmv1beta1.VMAuthSpec{ - SelectAllByDefault: true, - CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ - ReplicaCount: ptr.To[int32](1), - }, - UnauthorizedAccessConfig: []vmv1beta1.UnauthorizedAccessConfigURLMap{ - { - URLPrefix: []string{"http://localhost:8490"}, - SrcPaths: []string{"/.*"}, - }, + verify: func(cr *vmv1beta1.VMAuth) { + Eventually(func() string { + return expectPodCount(k8sClient, 2, namespace, cr.SelectorLabels()) + }, eventualDeploymentPodTimeout).Should(BeEmpty()) + nsn := types.NamespacedName{Namespace: cr.Namespace, Name: cr.PrefixedName()} + Expect(k8sClient.Get(ctx, nsn, &networkingv1.Ingress{})).To(Succeed()) + Eventually(func() error { + return k8sClient.Get(ctx, nsn, &policyv1.PodDisruptionBudget{}) + }, eventualDeletionTimeout).Should(MatchError(k8serrors.IsNotFound, "IsNotFound")) + }, + }, + testStep{ + modify: func(cr *vmv1beta1.VMAuth) { + cr.Spec.PodDisruptionBudget = &vmv1beta1.EmbeddedPodDisruptionBudgetSpec{ + MaxUnavailable: &intstr.IntOrString{IntVal: 1}, + } + }, + verify: func(cr *vmv1beta1.VMAuth) { + nsn := types.NamespacedName{Namespace: cr.Namespace, Name: cr.PrefixedName()} + Expect(k8sClient.Get(ctx, nsn, &networkingv1.Ingress{})).To(Succeed()) + Expect(k8sClient.Get(ctx, nsn, &policyv1.PodDisruptionBudget{})).To(Succeed()) + Expect(k8sClient.Delete(ctx, &networkingv1.Ingress{ObjectMeta: metav1.ObjectMeta{ + Name: nsn.Name, + Namespace: nsn.Namespace, + }})).To(Succeed()) + }, + }, + ), + Entry("by migrating from configSecret to externalConfig.secretRef", "ext-config", + &vmv1beta1.VMAuth{ + Spec: vmv1beta1.VMAuthSpec{ + SelectAllByDefault: true, + CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + }, + UnauthorizedAccessConfig: []vmv1beta1.UnauthorizedAccessConfigURLMap{ + { + URLPrefix: []string{"http://localhost:8490"}, + SrcPaths: []string{"/.*"}, }, }, }, - testStep{ - setup: func(v *vmv1beta1.VMAuth) { - extSecret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "auth-ext-config", - Namespace: namespace, - }, - StringData: map[string]string{ - "config.yaml": ` + }, + testStep{ + setup: func(v *vmv1beta1.VMAuth) { + extSecret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "auth-ext-config", + Namespace: namespace, + }, + StringData: map[string]string{ + "config.yaml": ` unauthorized_user: url_map: - src_paths: - "/.*" url_prefix: "http://vmsingle-some-url:8429"`, - }, - } - Expect(k8sClient.Create(ctx, extSecret)).To(Succeed()) - DeferCleanup(func(specCtx SpecContext) { - Expect(k8sClient.Delete(ctx, extSecret)).To(Succeed()) - }) - }, - modify: func(cr *vmv1beta1.VMAuth) { - cr.Spec.ConfigSecret = "auth-ext-config" - }, - verify: func(cr *vmv1beta1.VMAuth) { - var dep appsv1.Deployment - Expect(k8sClient.Get(ctx, types.NamespacedName{Name: cr.PrefixedName(), Namespace: namespace}, &dep)). - To(Succeed()) - Expect(dep.Spec.Template.Spec.Containers).To(HaveLen(1)) - Eventually(func() string { - return expectPodCount(k8sClient, 1, namespace, cr.SelectorLabels()) - }, eventualDeploymentPodTimeout).Should(BeEmpty()) - - }, + }, + } + Expect(k8sClient.Create(ctx, extSecret)).To(Succeed()) + DeferCleanup(func(specCtx SpecContext) { + Expect(k8sClient.Delete(ctx, extSecret)).To(Succeed()) + }) }, - testStep{ - modify: func(cr *vmv1beta1.VMAuth) { - cr.Spec.ConfigSecret = "" - cr.Spec.SecretRef = &corev1.SecretKeySelector{ - Key: "config.yaml", - LocalObjectReference: corev1.LocalObjectReference{ - Name: "auth-ext-config", - }, - } - }, - verify: func(cr *vmv1beta1.VMAuth) { - var dep appsv1.Deployment - Expect(k8sClient.Get(ctx, types.NamespacedName{Name: cr.PrefixedName(), Namespace: namespace}, &dep)). - To(Succeed()) - Expect(dep.Spec.Template.Spec.Containers).To(HaveLen(1)) - Expect(dep.Spec.Template.Spec.Containers[0].VolumeMounts).To(HaveLen(1)) - Eventually(func() string { - return expectPodCount(k8sClient, 1, namespace, cr.SelectorLabels()) - }, eventualDeploymentPodTimeout).Should(BeEmpty()) + modify: func(cr *vmv1beta1.VMAuth) { + cr.Spec.ConfigSecret = "auth-ext-config" + }, + verify: func(cr *vmv1beta1.VMAuth) { + var dep appsv1.Deployment + Expect(k8sClient.Get(ctx, types.NamespacedName{Name: cr.PrefixedName(), Namespace: namespace}, &dep)). + To(Succeed()) + Expect(dep.Spec.Template.Spec.Containers).To(HaveLen(1)) + Eventually(func() string { + return expectPodCount(k8sClient, 1, namespace, cr.SelectorLabels()) + }, eventualDeploymentPodTimeout).Should(BeEmpty()) - }, }, - ), - Entry("by switching to local config", "local-config", - &vmv1beta1.VMAuth{ - Spec: vmv1beta1.VMAuthSpec{ - SelectAllByDefault: true, - CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ - ReplicaCount: ptr.To[int32](1), + }, + testStep{ + modify: func(cr *vmv1beta1.VMAuth) { + cr.Spec.ConfigSecret = "" + cr.Spec.SecretRef = &corev1.SecretKeySelector{ + Key: "config.yaml", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "auth-ext-config", }, - UnauthorizedAccessConfig: []vmv1beta1.UnauthorizedAccessConfigURLMap{ - { - URLPrefix: []string{"http://localhost:8490"}, - SrcPaths: []string{"/.*"}, - }, + } + }, + verify: func(cr *vmv1beta1.VMAuth) { + var dep appsv1.Deployment + Expect(k8sClient.Get(ctx, types.NamespacedName{Name: cr.PrefixedName(), Namespace: namespace}, &dep)). + To(Succeed()) + Expect(dep.Spec.Template.Spec.Containers).To(HaveLen(1)) + Expect(dep.Spec.Template.Spec.Containers[0].VolumeMounts).To(HaveLen(1)) + Eventually(func() string { + return expectPodCount(k8sClient, 1, namespace, cr.SelectorLabels()) + }, eventualDeploymentPodTimeout).Should(BeEmpty()) + + }, + }, + ), + Entry("by switching to local config", "local-config", + &vmv1beta1.VMAuth{ + Spec: vmv1beta1.VMAuthSpec{ + SelectAllByDefault: true, + CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + }, + UnauthorizedAccessConfig: []vmv1beta1.UnauthorizedAccessConfigURLMap{ + { + URLPrefix: []string{"http://localhost:8490"}, + SrcPaths: []string{"/.*"}, }, }, }, - testStep{ - setup: func(v *vmv1beta1.VMAuth) { - extSecret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "local-ext-config", - Namespace: namespace, - }, - StringData: map[string]string{ - "vmauth.yaml": ` + }, + testStep{ + setup: func(v *vmv1beta1.VMAuth) { + extSecret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "local-ext-config", + Namespace: namespace, + }, + StringData: map[string]string{ + "vmauth.yaml": ` unauthorized_user: url_map: - src_paths: - "/.*" url_prefix: "http://vmsingle-some-url:8429"`, + }, + } + Expect(k8sClient.Create(ctx, extSecret)).To(Succeed()) + DeferCleanup(func(specCtx SpecContext) { + Expect(k8sClient.Delete(ctx, extSecret)).To(Succeed()) + }) + }, + modify: func(cr *vmv1beta1.VMAuth) { + cr.Spec.LocalPath = "/etc/local-config/vmauth.yaml" + cr.Spec.Volumes = append(cr.Spec.Volumes, corev1.Volume{ + Name: "local-cfg", + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: "local-ext-config", }, - } - Expect(k8sClient.Create(ctx, extSecret)).To(Succeed()) - DeferCleanup(func(specCtx SpecContext) { - Expect(k8sClient.Delete(ctx, extSecret)).To(Succeed()) - }) - }, - modify: func(cr *vmv1beta1.VMAuth) { - cr.Spec.LocalPath = "/etc/local-config/vmauth.yaml" - cr.Spec.Volumes = append(cr.Spec.Volumes, corev1.Volume{ - Name: "local-cfg", - VolumeSource: corev1.VolumeSource{ - Secret: &corev1.SecretVolumeSource{ - SecretName: "local-ext-config", - }, - }, - }) - cr.Spec.VolumeMounts = append(cr.Spec.VolumeMounts, corev1.VolumeMount{ - Name: "local-cfg", - MountPath: "/etc/local-config", - }) - }, - verify: func(cr *vmv1beta1.VMAuth) { - var dep appsv1.Deployment - Expect(k8sClient.Get(ctx, types.NamespacedName{Name: cr.PrefixedName(), Namespace: namespace}, &dep)). - To(Succeed()) - Expect(dep.Spec.Template.Spec.Containers).To(HaveLen(1)) - Eventually(func() string { - return expectPodCount(k8sClient, 1, namespace, cr.SelectorLabels()) - }, eventualDeploymentPodTimeout).Should(BeEmpty()) + }, + }) + cr.Spec.VolumeMounts = append(cr.Spec.VolumeMounts, corev1.VolumeMount{ + Name: "local-cfg", + MountPath: "/etc/local-config", + }) + }, + verify: func(cr *vmv1beta1.VMAuth) { + var dep appsv1.Deployment + Expect(k8sClient.Get(ctx, types.NamespacedName{Name: cr.PrefixedName(), Namespace: namespace}, &dep)). + To(Succeed()) + Expect(dep.Spec.Template.Spec.Containers).To(HaveLen(1)) + Eventually(func() string { + return expectPodCount(k8sClient, 1, namespace, cr.SelectorLabels()) + }, eventualDeploymentPodTimeout).Should(BeEmpty()) - }, }, - ), - Entry("by switching to proxy-protocol", "proxy-protocol", - &vmv1beta1.VMAuth{ - Spec: vmv1beta1.VMAuthSpec{ - SelectAllByDefault: true, - CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ - ReplicaCount: ptr.To[int32](1), - }, - CommonConfigReloaderParams: vmv1beta1.CommonConfigReloaderParams{ - UseVMConfigReloader: ptr.To(true), - }, - UnauthorizedAccessConfig: []vmv1beta1.UnauthorizedAccessConfigURLMap{ - { - URLPrefix: []string{"http://localhost:8490"}, - SrcPaths: []string{"/.*"}, - }, + }, + ), + Entry("by switching to proxy-protocol", "proxy-protocol", + &vmv1beta1.VMAuth{ + Spec: vmv1beta1.VMAuthSpec{ + SelectAllByDefault: true, + CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + }, + CommonConfigReloaderParams: vmv1beta1.CommonConfigReloaderParams{ + UseVMConfigReloader: ptr.To(true), + }, + UnauthorizedAccessConfig: []vmv1beta1.UnauthorizedAccessConfigURLMap{ + { + URLPrefix: []string{"http://localhost:8490"}, + SrcPaths: []string{"/.*"}, }, }, }, - testStep{ - modify: func(cr *vmv1beta1.VMAuth) { - cr.Spec.UseProxyProtocol = true - }, - verify: func(cr *vmv1beta1.VMAuth) {}, + }, + testStep{ + modify: func(cr *vmv1beta1.VMAuth) { + cr.Spec.UseProxyProtocol = true }, - testStep{ - modify: func(cr *vmv1beta1.VMAuth) { - cr.Spec.UseVMConfigReloader = ptr.To(false) - }, - verify: func(cr *vmv1beta1.VMAuth) {}, + verify: func(cr *vmv1beta1.VMAuth) {}, + }, + testStep{ + modify: func(cr *vmv1beta1.VMAuth) { + cr.Spec.UseVMConfigReloader = ptr.To(false) }, - ), - ) - }) + verify: func(cr *vmv1beta1.VMAuth) {}, + }, + ), + ) }) }) diff --git a/test/e2e/vmcluster_test.go b/test/e2e/vmcluster_test.go index 5a1507f55..0c8ebcfc5 100644 --- a/test/e2e/vmcluster_test.go +++ b/test/e2e/vmcluster_test.go @@ -3,6 +3,7 @@ package e2e import ( "context" "fmt" + "os" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -18,17 +19,19 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" vmv1beta1 "github.com/VictoriaMetrics/operator/api/operator/v1beta1" + "github.com/VictoriaMetrics/operator/internal/config" ) //nolint:dupl,lll -var _ = Describe("e2e vmcluster", Label("vm", "cluster"), func() { - namespace := fmt.Sprintf("default-%d", GinkgoParallelProcess()) - var ctx context.Context - namespacedName := types.NamespacedName{ - Namespace: namespace, - } +var _ = Describe("vmcluster", Label("vm", "cluster"), func() { + licenseKey := os.Getenv("LICENSE_KEY") Context("create", func() { - JustBeforeEach(func() { + var ctx context.Context + namespace := fmt.Sprintf("default-%d", GinkgoParallelProcess()) + namespacedName := types.NamespacedName{ + Namespace: namespace, + } + BeforeEach(func() { ctx = context.Background() }) AfterEach(func() { @@ -284,6 +287,27 @@ var _ = Describe("e2e vmcluster", Label("vm", "cluster"), func() { ) }) Context("update", func() { + var ctx context.Context + namespace := fmt.Sprintf("default-%d", GinkgoParallelProcess()) + namespacedName := types.NamespacedName{ + Namespace: namespace, + } + BeforeEach(func() { + ctx = context.Background() + if licenseKey != "" { + Expect(k8sClient.Create(ctx, + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "license", + Namespace: namespace, + }, + StringData: map[string]string{ + "key": licenseKey, + }, + }, + )).To(Succeed()) + } + }) AfterEach(func() { Expect(k8sClient.Delete(ctx, &vmv1beta1.VMCluster{ ObjectMeta: metav1.ObjectMeta{ @@ -296,8 +320,17 @@ var _ = Describe("e2e vmcluster", Label("vm", "cluster"), func() { Name: namespacedName.Name, Namespace: namespace, }, &vmv1beta1.VMCluster{}) - }, eventualDeletionTimeout).WithContext(ctx).Should(MatchError(k8serrors.IsNotFound, "want not found error")) + if licenseKey != "" { + Expect(k8sClient.Delete(ctx, + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "license", + Namespace: namespace, + }, + }, + )).To(Succeed()) + } }) type testStep struct { @@ -307,11 +340,28 @@ var _ = Describe("e2e vmcluster", Label("vm", "cluster"), func() { } DescribeTable("should update exist cluster", - func(name string, initCR *vmv1beta1.VMCluster, steps ...testStep) { + func(name string, isEnterprise bool, initCR *vmv1beta1.VMCluster, steps ...testStep) { + if isEnterprise { + if licenseKey == "" { + Skip("ignoring VMCluster test, license was not found") + } + cfg := config.MustGetBaseConfig() + tag := cfg.MetricsVersion + "-enterprise-cluster" + initCR.Spec.VMStorage.Image.Tag = tag + initCR.Spec.VMSelect.Image.Tag = tag + initCR.Spec.VMInsert.Image.Tag = tag + initCR.Spec.License = &vmv1beta1.License{ + KeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "license", + }, + Key: "key", + }, + } + } namespacedName.Name = name initCR.Namespace = namespace initCR.Name = name - ctx = context.Background() Expect(k8sClient.Create(ctx, initCR)).To(Succeed()) Eventually(func() error { return expectObjectStatusOperational(ctx, k8sClient, initCR, namespacedName) @@ -340,7 +390,7 @@ var _ = Describe("e2e vmcluster", Label("vm", "cluster"), func() { step.verify(&updated) } }, - Entry("by scaling select and storage replicas to 2", "storage-select-r-2", + Entry("by scaling select and storage replicas to 2", "storage-select-r-2", false, &vmv1beta1.VMCluster{ Spec: vmv1beta1.VMClusterSpec{ RetentionPeriod: "1", @@ -371,7 +421,7 @@ var _ = Describe("e2e vmcluster", Label("vm", "cluster"), func() { }, }, ), - Entry("by adding vmbackupmanager to vmstorage ", "with-backup", + Entry("by adding vmbackupmanager to vmstorage ", "with-backup", true, &vmv1beta1.VMCluster{ Spec: vmv1beta1.VMClusterSpec{ RetentionPeriod: "1", @@ -385,9 +435,10 @@ var _ = Describe("e2e vmcluster", Label("vm", "cluster"), func() { ReplicaCount: ptr.To[int32](1), }, }, - VMInsert: &vmv1beta1.VMInsert{CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ - ReplicaCount: ptr.To[int32](1), - }, + VMInsert: &vmv1beta1.VMInsert{ + CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + }, }, }, }, @@ -422,7 +473,6 @@ var _ = Describe("e2e vmcluster", Label("vm", "cluster"), func() { {Name: "backup", VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}}}, } cr.Spec.VMStorage.VMBackup = &vmv1beta1.VMBackup{ - AcceptEULA: true, Destination: "fs:///opt/backup-dir", VolumeMounts: []corev1.VolumeMount{ {Name: "backup", MountPath: "/opt/backup-dir"}, @@ -444,7 +494,7 @@ var _ = Describe("e2e vmcluster", Label("vm", "cluster"), func() { }, }, ), - Entry("by scaling storage and insert replicas to 2", "storage-insert-r-2", + Entry("by scaling storage and insert replicas to 2", "storage-insert-r-2", false, &vmv1beta1.VMCluster{ Spec: vmv1beta1.VMClusterSpec{ RetentionPeriod: "1", @@ -478,7 +528,7 @@ var _ = Describe("e2e vmcluster", Label("vm", "cluster"), func() { }, }, ), - Entry("by changing storage revisionHistoryLimit to 2", "storage-revision-2", + Entry("by changing storage revisionHistoryLimit to 2", "storage-revision-2", false, &vmv1beta1.VMCluster{ Spec: vmv1beta1.VMClusterSpec{ RetentionPeriod: "1", @@ -509,7 +559,7 @@ var _ = Describe("e2e vmcluster", Label("vm", "cluster"), func() { }, }, ), - Entry("by adding clusterNative ports", "storage-native-r-2", + Entry("by adding clusterNative ports", "storage-native-r-2", false, &vmv1beta1.VMCluster{ Spec: vmv1beta1.VMClusterSpec{ RetentionPeriod: "1", @@ -551,7 +601,7 @@ var _ = Describe("e2e vmcluster", Label("vm", "cluster"), func() { }, }, ), - Entry("by deleting select component", "select-delete", + Entry("by deleting select component", "select-delete", false, &vmv1beta1.VMCluster{ Spec: vmv1beta1.VMClusterSpec{ RetentionPeriod: "1", @@ -611,7 +661,7 @@ var _ = Describe("e2e vmcluster", Label("vm", "cluster"), func() { }, }, ), - Entry("by deleting storage and insert components", "storage-insert-delete", + Entry("by deleting storage and insert components", "storage-insert-delete", false, &vmv1beta1.VMCluster{ Spec: vmv1beta1.VMClusterSpec{ RetentionPeriod: "1", @@ -692,7 +742,7 @@ var _ = Describe("e2e vmcluster", Label("vm", "cluster"), func() { }, }, ), - Entry("by deleting deleting and renaming additional services", "select-additional-svc", + Entry("by deleting deleting and renaming additional services", "select-additional-svc", false, &vmv1beta1.VMCluster{ Spec: vmv1beta1.VMClusterSpec{ RetentionPeriod: "1", @@ -782,7 +832,7 @@ var _ = Describe("e2e vmcluster", Label("vm", "cluster"), func() { }, }, ), - Entry("by adding imagePullSecret", "storage-image-pull-secret", + Entry("by adding imagePullSecret", "storage-image-pull-secret", false, &vmv1beta1.VMCluster{ Spec: vmv1beta1.VMClusterSpec{ RetentionPeriod: "1", @@ -830,7 +880,7 @@ var _ = Describe("e2e vmcluster", Label("vm", "cluster"), func() { }, }, ), - Entry("by switching to vmauth loadbalancer", "with-load-balancing", + Entry("by switching to vmauth loadbalancer", "with-load-balancing", false, &vmv1beta1.VMCluster{ Spec: vmv1beta1.VMClusterSpec{ RetentionPeriod: "1", @@ -934,7 +984,7 @@ up{baz="bar"} 123 }, }, ), - Entry("by switching partially to vmauth loadbalanacer", "with-partial-load-balancing", + Entry("by switching partially to vmauth loadbalanacer", "with-partial-load-balancing", false, &vmv1beta1.VMCluster{ Spec: vmv1beta1.VMClusterSpec{ RetentionPeriod: "1", @@ -1064,7 +1114,7 @@ up{baz="bar"} 123 }, }, ), - Entry("by running with load-balancer and modify vmauth", "with-load-balancing-modify-auth", + Entry("by running with load-balancer and modify vmauth", "with-load-balancing-modify-auth", false, &vmv1beta1.VMCluster{ Spec: vmv1beta1.VMClusterSpec{ RetentionPeriod: "1", @@ -1174,7 +1224,7 @@ up{baz="bar"} 123 }, }, ), - Entry("by changing annotations for created objects", "manage-annotations", + Entry("by changing annotations for created objects", "manage-annotations", false, &vmv1beta1.VMCluster{ Spec: vmv1beta1.VMClusterSpec{ RequestsLoadBalancer: vmv1beta1.VMAuthLoadBalancer{Enabled: true}, @@ -1249,30 +1299,6 @@ up{baz="bar"} 123 }, ), ) - }) - Context("update", func() { - AfterEach(func() { - Expect(k8sClient.Delete(ctx, &vmv1beta1.VMCluster{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace, - Name: namespacedName.Name, - }, - })).To(Succeed()) - Eventually(func() error { - return k8sClient.Get(context.Background(), types.NamespacedName{ - Name: namespacedName.Name, - Namespace: namespace, - }, &vmv1beta1.VMCluster{}) - - }, eventualDeletionTimeout).WithContext(ctx).Should(MatchError(k8serrors.IsNotFound, "want not found error")) - }) - - type testStep struct { - setup func(*vmv1beta1.VMCluster) - modify func(*vmv1beta1.VMCluster) - verify func(*vmv1beta1.VMCluster) - } - DescribeTable("should respect customized behavior", func(name string, initCR *vmv1beta1.VMCluster, steps ...testStep) { namespacedName.Name = name diff --git a/test/e2e/vmsingle_test.go b/test/e2e/vmsingle_test.go index d0e81404d..508284f1c 100644 --- a/test/e2e/vmsingle_test.go +++ b/test/e2e/vmsingle_test.go @@ -3,6 +3,7 @@ package e2e import ( "context" "fmt" + "os" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -16,13 +17,14 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" vmv1beta1 "github.com/VictoriaMetrics/operator/api/operator/v1beta1" + "github.com/VictoriaMetrics/operator/internal/config" "github.com/VictoriaMetrics/operator/internal/controller/operator/factory/finalize" ) //nolint:dupl,lll -var _ = Describe("test vmsingle Controller", Label("vm", "single"), func() { - - Context("e2e vmsingle", func() { +var _ = Describe("vmsingle", Label("vm", "single"), func() { + licenseKey := os.Getenv("LICENSE_KEY") + Context("crud", func() { var ctx context.Context namespace := fmt.Sprintf("default-%d", GinkgoParallelProcess()) namespacedName := types.NamespacedName{ @@ -30,7 +32,19 @@ var _ = Describe("test vmsingle Controller", Label("vm", "single"), func() { } BeforeEach(func() { ctx = context.Background() - + if licenseKey != "" { + Expect(k8sClient.Create(ctx, + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "license", + Namespace: namespace, + }, + StringData: map[string]string{ + "key": licenseKey, + }, + }, + )).To(Succeed()) + } }) AfterEach(func() { Expect(finalize.SafeDelete(ctx, k8sClient, &vmv1beta1.VMSingle{ @@ -42,349 +56,378 @@ var _ = Describe("test vmsingle Controller", Label("vm", "single"), func() { Eventually(func() error { return k8sClient.Get(ctx, namespacedName, &vmv1beta1.VMSingle{}) }, eventualDeletionTimeout).Should(MatchError(k8serrors.IsNotFound, "IsNotFound")) - }) - Context("crud", func() { - DescribeTable("should create vmsingle", - func(name string, cr *vmv1beta1.VMSingle, verify func(*vmv1beta1.VMSingle)) { - cr.Name = name - namespacedName.Name = name - Expect(k8sClient.Create(ctx, cr)).To(Succeed()) - Eventually(func() error { - return expectObjectStatusOperational(ctx, k8sClient, &vmv1beta1.VMSingle{}, namespacedName) - }, eventualDeploymentAppReadyTimeout, - ).Should(Succeed()) - - var created vmv1beta1.VMSingle - Expect(k8sClient.Get(ctx, namespacedName, &created)).To(Succeed()) - verify(&created) - }, - Entry("with built-in pvc and insert ports", "create-with-pvc-ports", - &vmv1beta1.VMSingle{ + if licenseKey != "" { + Expect(k8sClient.Delete(ctx, + &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ + Name: "license", Namespace: namespace, }, - Spec: vmv1beta1.VMSingleSpec{ - CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ - ReplicaCount: ptr.To[int32](1), - }, - RetentionPeriod: "1", - RemovePvcAfterDelete: true, - Storage: &corev1.PersistentVolumeClaimSpec{ - Resources: corev1.VolumeResourceRequirements{ - Requests: corev1.ResourceList{ - corev1.ResourceStorage: resource.MustParse("1Gi"), - }, - }, - }, - InsertPorts: &vmv1beta1.InsertPorts{ - OpenTSDBPort: "8081", - OpenTSDBHTTPPort: "8082", - GraphitePort: "8083", - InfluxPort: "8084", + }, + )).To(Succeed()) + } + }) + DescribeTable("should create vmsingle", + func(name string, isEnterprise bool, cr *vmv1beta1.VMSingle, verify func(*vmv1beta1.VMSingle)) { + if isEnterprise { + if licenseKey == "" { + Skip("ignoring VMSingle test, license was not found") + } + cfg := config.MustGetBaseConfig() + cr.Spec.Image.Tag = cfg.MetricsVersion + "-enterprise" + cr.Spec.License = &vmv1beta1.License{ + KeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "license", }, + Key: "key", }, + } + } + cr.Name = name + namespacedName.Name = name + Expect(k8sClient.Create(ctx, cr)).To(Succeed()) + Eventually(func() error { + return expectObjectStatusOperational(ctx, k8sClient, &vmv1beta1.VMSingle{}, namespacedName) + }, eventualDeploymentAppReadyTimeout, + ).Should(Succeed()) + + var created vmv1beta1.VMSingle + Expect(k8sClient.Get(ctx, namespacedName, &created)).To(Succeed()) + verify(&created) + }, + Entry("with built-in pvc and insert ports", "create-with-pvc-ports", false, + &vmv1beta1.VMSingle{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace, }, - func(cr *vmv1beta1.VMSingle) { - var createdSvc corev1.Service - createdChildObjects := types.NamespacedName{Namespace: namespace, Name: cr.PrefixedName()} - Expect( - k8sClient.Get(ctx, createdChildObjects, &createdSvc)). - To(Succeed()) - Expect(createdSvc.Spec.Ports).To(HaveLen(9)) - var createdDeploy appsv1.Deployment - Expect(k8sClient.Get(ctx, createdChildObjects, &createdDeploy)).To(Succeed()) - Expect(createdDeploy.Spec.Template.Spec.Containers).To(HaveLen(1)) - Expect(createdDeploy.Spec.Template.Spec.Containers[0].Ports).To(HaveLen(8)) - }), - Entry("with empty resources and vmbackup ", "create-wo-resource-w-backup", - &vmv1beta1.VMSingle{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace, + Spec: vmv1beta1.VMSingleSpec{ + CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), }, - Spec: vmv1beta1.VMSingleSpec{ - CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ - ReplicaCount: ptr.To[int32](1), - Volumes: []corev1.Volume{ - {Name: "backup", VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}}}, + RetentionPeriod: "1", + RemovePvcAfterDelete: true, + Storage: &corev1.PersistentVolumeClaimSpec{ + Resources: corev1.VolumeResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceStorage: resource.MustParse("1Gi"), }, }, - CommonDefaultableParams: vmv1beta1.CommonDefaultableParams{ - UseDefaultResources: ptr.To(false), + }, + InsertPorts: &vmv1beta1.InsertPorts{ + OpenTSDBPort: "8081", + OpenTSDBHTTPPort: "8082", + GraphitePort: "8083", + InfluxPort: "8084", + }, + }, + }, + func(cr *vmv1beta1.VMSingle) { + var createdSvc corev1.Service + createdChildObjects := types.NamespacedName{Namespace: namespace, Name: cr.PrefixedName()} + Expect( + k8sClient.Get(ctx, createdChildObjects, &createdSvc)). + To(Succeed()) + Expect(createdSvc.Spec.Ports).To(HaveLen(9)) + var createdDeploy appsv1.Deployment + Expect(k8sClient.Get(ctx, createdChildObjects, &createdDeploy)).To(Succeed()) + Expect(createdDeploy.Spec.Template.Spec.Containers).To(HaveLen(1)) + Expect(createdDeploy.Spec.Template.Spec.Containers[0].Ports).To(HaveLen(8)) + }), + Entry("with empty resources and vmbackup ", "create-wo-resource-w-backup", true, + &vmv1beta1.VMSingle{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace, + }, + Spec: vmv1beta1.VMSingleSpec{ + CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + Volumes: []corev1.Volume{ + {Name: "backup", VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}}}, }, - VMBackup: &vmv1beta1.VMBackup{ - AcceptEULA: true, - Destination: "fs:///opt/backup-dir", - VolumeMounts: []corev1.VolumeMount{ - {Name: "backup", MountPath: "/opt/backup-dir"}, - }, + }, + CommonDefaultableParams: vmv1beta1.CommonDefaultableParams{ + UseDefaultResources: ptr.To(false), + }, + VMBackup: &vmv1beta1.VMBackup{ + Destination: "fs:///opt/backup-dir", + VolumeMounts: []corev1.VolumeMount{ + {Name: "backup", MountPath: "/opt/backup-dir"}, }, - RetentionPeriod: "1", - RemovePvcAfterDelete: true, - Storage: &corev1.PersistentVolumeClaimSpec{ - Resources: corev1.VolumeResourceRequirements{ - Requests: corev1.ResourceList{ - corev1.ResourceStorage: resource.MustParse("1Gi"), - }, + }, + RetentionPeriod: "1", + RemovePvcAfterDelete: true, + Storage: &corev1.PersistentVolumeClaimSpec{ + Resources: corev1.VolumeResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceStorage: resource.MustParse("1Gi"), }, }, }, }, - func(cr *vmv1beta1.VMSingle) { - var createdSvc corev1.Service - createdChildObjects := types.NamespacedName{Namespace: namespace, Name: cr.PrefixedName()} - Expect( - k8sClient.Get(ctx, createdChildObjects, &createdSvc)). - To(Succeed()) - Expect(createdSvc.Spec.Ports).To(HaveLen(3)) - var createdDeploy appsv1.Deployment - Expect(k8sClient.Get(ctx, createdChildObjects, &createdDeploy)).To(Succeed()) - Expect(createdDeploy.Spec.Template.Spec.Containers).To(HaveLen(2)) - Expect(createdDeploy.Spec.Template.Spec.Containers[1].VolumeMounts).To(HaveLen(2)) - Expect(createdDeploy.Spec.Template.Spec.Containers[0].Resources).To(Equal(corev1.ResourceRequirements{})) - Expect(createdDeploy.Spec.Template.Spec.Containers[1].Resources).To(Equal(corev1.ResourceRequirements{})) - var vss vmv1beta1.VMServiceScrape - Expect(k8sClient.Get(ctx, createdChildObjects, &vss)).To(Succeed()) - Expect(vss.Spec.Endpoints).To(HaveLen(2)) - }), - Entry("with strict security", "strict-security", - &vmv1beta1.VMSingle{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace, + }, + func(cr *vmv1beta1.VMSingle) { + var createdSvc corev1.Service + createdChildObjects := types.NamespacedName{Namespace: namespace, Name: cr.PrefixedName()} + Expect( + k8sClient.Get(ctx, createdChildObjects, &createdSvc)). + To(Succeed()) + Expect(createdSvc.Spec.Ports).To(HaveLen(3)) + var createdDeploy appsv1.Deployment + Expect(k8sClient.Get(ctx, createdChildObjects, &createdDeploy)).To(Succeed()) + Expect(createdDeploy.Spec.Template.Spec.Containers).To(HaveLen(2)) + Expect(createdDeploy.Spec.Template.Spec.Containers[1].VolumeMounts).To(HaveLen(3)) + Expect(createdDeploy.Spec.Template.Spec.Containers[0].Resources).To(Equal(corev1.ResourceRequirements{})) + Expect(createdDeploy.Spec.Template.Spec.Containers[1].Resources).To(Equal(corev1.ResourceRequirements{})) + var vss vmv1beta1.VMServiceScrape + Expect(k8sClient.Get(ctx, createdChildObjects, &vss)).To(Succeed()) + Expect(vss.Spec.Endpoints).To(HaveLen(2)) + }), + Entry("with strict security", "strict-security", false, + &vmv1beta1.VMSingle{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace, + }, + Spec: vmv1beta1.VMSingleSpec{ + CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), }, - Spec: vmv1beta1.VMSingleSpec{ - CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ - ReplicaCount: ptr.To[int32](1), - }, - CommonDefaultableParams: vmv1beta1.CommonDefaultableParams{ - UseStrictSecurity: ptr.To(true), - }, - RetentionPeriod: "1", - RemovePvcAfterDelete: true, - Storage: &corev1.PersistentVolumeClaimSpec{ - Resources: corev1.VolumeResourceRequirements{ - Requests: corev1.ResourceList{ - corev1.ResourceStorage: resource.MustParse("1Gi"), - }, + CommonDefaultableParams: vmv1beta1.CommonDefaultableParams{ + UseStrictSecurity: ptr.To(true), + }, + RetentionPeriod: "1", + RemovePvcAfterDelete: true, + Storage: &corev1.PersistentVolumeClaimSpec{ + Resources: corev1.VolumeResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceStorage: resource.MustParse("1Gi"), }, }, }, }, - func(cr *vmv1beta1.VMSingle) { - createdChildObjects := types.NamespacedName{Namespace: namespace, Name: cr.PrefixedName()} - var createdDeploy appsv1.Deployment - Expect(k8sClient.Get(ctx, createdChildObjects, &createdDeploy)).To(Succeed()) - Expect(createdDeploy.Spec.Template.Spec.Containers).To(HaveLen(1)) - Expect(createdDeploy.Spec.Template.Spec.Containers[0].SecurityContext).NotTo(BeNil()) - Expect(createdDeploy.Spec.Template.Spec.Containers[0].SecurityContext.RunAsNonRoot).NotTo(BeNil()) - Expect(*createdDeploy.Spec.Template.Spec.Containers[0].SecurityContext.RunAsNonRoot).To(BeTrue()) - - }), - Entry("with data emptyDir", "emptydir", - &vmv1beta1.VMSingle{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace, + }, + func(cr *vmv1beta1.VMSingle) { + createdChildObjects := types.NamespacedName{Namespace: namespace, Name: cr.PrefixedName()} + var createdDeploy appsv1.Deployment + Expect(k8sClient.Get(ctx, createdChildObjects, &createdDeploy)).To(Succeed()) + Expect(createdDeploy.Spec.Template.Spec.Containers).To(HaveLen(1)) + Expect(createdDeploy.Spec.Template.Spec.Containers[0].SecurityContext).NotTo(BeNil()) + Expect(createdDeploy.Spec.Template.Spec.Containers[0].SecurityContext.RunAsNonRoot).NotTo(BeNil()) + Expect(*createdDeploy.Spec.Template.Spec.Containers[0].SecurityContext.RunAsNonRoot).To(BeTrue()) + }), + Entry("with data emptyDir", "emptydir", false, + &vmv1beta1.VMSingle{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace, + }, + Spec: vmv1beta1.VMSingleSpec{ + CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), }, - Spec: vmv1beta1.VMSingleSpec{ - CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ - ReplicaCount: ptr.To[int32](1), - }, - CommonDefaultableParams: vmv1beta1.CommonDefaultableParams{ - UseStrictSecurity: ptr.To(false), - }, - RetentionPeriod: "1", - RemovePvcAfterDelete: true, - StorageDataPath: "/tmp/", - Storage: &corev1.PersistentVolumeClaimSpec{ - Resources: corev1.VolumeResourceRequirements{ - Requests: corev1.ResourceList{ - corev1.ResourceStorage: resource.MustParse("1Gi"), - }, + CommonDefaultableParams: vmv1beta1.CommonDefaultableParams{ + UseStrictSecurity: ptr.To(false), + }, + RetentionPeriod: "1", + RemovePvcAfterDelete: true, + StorageDataPath: "/tmp/", + Storage: &corev1.PersistentVolumeClaimSpec{ + Resources: corev1.VolumeResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceStorage: resource.MustParse("1Gi"), }, }, }, }, - func(cr *vmv1beta1.VMSingle) { - createdChildObjects := types.NamespacedName{Namespace: namespace, Name: cr.PrefixedName()} - var createdDeploy appsv1.Deployment - Expect(k8sClient.Get(ctx, createdChildObjects, &createdDeploy)).To(Succeed()) - ts := createdDeploy.Spec.Template.Spec - Expect(ts.Containers).To(HaveLen(1)) - Expect(ts.Volumes).To(BeEmpty()) - Expect(ts.Containers[0].VolumeMounts).To(BeEmpty()) - }), - Entry("with external volume", "externalvolume", - &vmv1beta1.VMSingle{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace, - }, - Spec: vmv1beta1.VMSingleSpec{ - CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ - ReplicaCount: ptr.To[int32](1), - Volumes: []corev1.Volume{ - { - Name: "data", - VolumeSource: corev1.VolumeSource{ - EmptyDir: &corev1.EmptyDirVolumeSource{}, - }, - }, - { - Name: "backup", - VolumeSource: corev1.VolumeSource{ - EmptyDir: &corev1.EmptyDirVolumeSource{}, - }, + }, + func(cr *vmv1beta1.VMSingle) { + createdChildObjects := types.NamespacedName{Namespace: namespace, Name: cr.PrefixedName()} + var createdDeploy appsv1.Deployment + Expect(k8sClient.Get(ctx, createdChildObjects, &createdDeploy)).To(Succeed()) + ts := createdDeploy.Spec.Template.Spec + Expect(ts.Containers).To(HaveLen(1)) + Expect(ts.Volumes).To(BeEmpty()) + Expect(ts.Containers[0].VolumeMounts).To(BeEmpty()) + }), + Entry("with external volume", "externalvolume", true, + &vmv1beta1.VMSingle{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace, + }, + Spec: vmv1beta1.VMSingleSpec{ + CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + Volumes: []corev1.Volume{ + { + Name: "data", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, }, - { - Name: "unused", - VolumeSource: corev1.VolumeSource{ - EmptyDir: &corev1.EmptyDirVolumeSource{}, - }, + }, + { + Name: "backup", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, }, }, - VolumeMounts: []corev1.VolumeMount{ - { - Name: "unused", - MountPath: "/opt/unused/mountpoint", + { + Name: "unused", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, }, }, }, - CommonDefaultableParams: vmv1beta1.CommonDefaultableParams{ - UseStrictSecurity: ptr.To(false), - }, - RetentionPeriod: "1", - RemovePvcAfterDelete: true, - StorageDataPath: "/custom-path/internal/dir", - Storage: &corev1.PersistentVolumeClaimSpec{}, - VMBackup: &vmv1beta1.VMBackup{ - AcceptEULA: true, - Destination: "fs:///opt/backup", - VolumeMounts: []corev1.VolumeMount{{Name: "backup", MountPath: "/opt/backup"}}, + VolumeMounts: []corev1.VolumeMount{ + { + Name: "unused", + MountPath: "/opt/unused/mountpoint", + }, }, }, + CommonDefaultableParams: vmv1beta1.CommonDefaultableParams{ + UseStrictSecurity: ptr.To(false), + }, + RetentionPeriod: "1", + RemovePvcAfterDelete: true, + StorageDataPath: "/custom-path/internal/dir", + Storage: &corev1.PersistentVolumeClaimSpec{}, + VMBackup: &vmv1beta1.VMBackup{ + Destination: "fs:///opt/backup", + VolumeMounts: []corev1.VolumeMount{{Name: "backup", MountPath: "/opt/backup"}}, + }, }, - func(cr *vmv1beta1.VMSingle) { - createdChildObjects := types.NamespacedName{Namespace: namespace, Name: cr.PrefixedName()} - var createdDeploy appsv1.Deployment - Expect(k8sClient.Get(ctx, createdChildObjects, &createdDeploy)).To(Succeed()) - ts := createdDeploy.Spec.Template.Spec - Expect(ts.Containers).To(HaveLen(2)) - Expect(ts.Volumes).To(HaveLen(3)) - Expect(ts.Containers[0].VolumeMounts).To(HaveLen(2)) - Expect(ts.Containers[0].VolumeMounts[0].Name).To(Equal("data")) - Expect(ts.Containers[1].VolumeMounts).To(HaveLen(2)) - Expect(ts.Containers[1].VolumeMounts[0].Name).To(Equal("data")) - Expect(ts.Containers[1].VolumeMounts[1].Name).To(Equal("backup")) - }), - ) - - baseSingle := &vmv1beta1.VMSingle{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace, }, - Spec: vmv1beta1.VMSingleSpec{ - RemovePvcAfterDelete: true, - RetentionPeriod: "10", - CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ - ReplicaCount: ptr.To[int32](1), - }, + func(cr *vmv1beta1.VMSingle) { + createdChildObjects := types.NamespacedName{Namespace: namespace, Name: cr.PrefixedName()} + var createdDeploy appsv1.Deployment + Expect(k8sClient.Get(ctx, createdChildObjects, &createdDeploy)).To(Succeed()) + ts := createdDeploy.Spec.Template.Spec + Expect(ts.Containers).To(HaveLen(2)) + Expect(ts.Volumes).To(HaveLen(4)) + Expect(ts.Containers[0].VolumeMounts).To(HaveLen(3)) + Expect(ts.Containers[0].VolumeMounts[0].Name).To(Equal("data")) + Expect(ts.Containers[1].VolumeMounts).To(HaveLen(3)) + Expect(ts.Containers[1].VolumeMounts[0].Name).To(Equal("data")) + Expect(ts.Containers[1].VolumeMounts[1].Name).To(Equal("backup")) + }), + ) + + baseSingle := &vmv1beta1.VMSingle{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace, + }, + Spec: vmv1beta1.VMSingleSpec{ + RemovePvcAfterDelete: true, + RetentionPeriod: "10", + CommonApplicationDeploymentParams: vmv1beta1.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), }, - } - type testStep struct { - setup func(*vmv1beta1.VMSingle) - modify func(*vmv1beta1.VMSingle) - verify func(*vmv1beta1.VMSingle) - } + }, + } + type testStep struct { + setup func(*vmv1beta1.VMSingle) + modify func(*vmv1beta1.VMSingle) + verify func(*vmv1beta1.VMSingle) + } - DescribeTable("should update exist vmsingle", - func(name string, initCR *vmv1beta1.VMSingle, steps ...testStep) { - initCR.Name = name - initCR.Namespace = namespace - namespacedName.Name = name - // setup test - Expect(k8sClient.Create(ctx, initCR)).To(Succeed()) + DescribeTable("should update exist vmsingle", + func(name string, isEnterprise bool, initCR *vmv1beta1.VMSingle, steps ...testStep) { + if isEnterprise { + if licenseKey == "" { + Skip("ignoring VMSingle test, license was not found") + } + cfg := config.MustGetBaseConfig() + initCR.Spec.Image.Tag = cfg.MetricsVersion + "-enterprise" + initCR.Spec.License = &vmv1beta1.License{ + KeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "license", + }, + Key: "key", + }, + } + } + initCR.Name = name + initCR.Namespace = namespace + namespacedName.Name = name + // setup test + Expect(k8sClient.Create(ctx, initCR)).To(Succeed()) + Eventually(func() error { + return expectObjectStatusOperational(ctx, k8sClient, &vmv1beta1.VMSingle{}, namespacedName) + }, eventualDeploymentAppReadyTimeout).Should(Succeed()) + + for _, step := range steps { + if step.setup != nil { + step.setup(initCR) + } + // perform update + Eventually(func() error { + var toUpdate vmv1beta1.VMSingle + Expect(k8sClient.Get(ctx, namespacedName, &toUpdate)).To(Succeed()) + step.modify(&toUpdate) + return k8sClient.Update(ctx, &toUpdate) + }, eventualExpandingTimeout).Should(Succeed()) Eventually(func() error { return expectObjectStatusOperational(ctx, k8sClient, &vmv1beta1.VMSingle{}, namespacedName) }, eventualDeploymentAppReadyTimeout).Should(Succeed()) - for _, step := range steps { - if step.setup != nil { - step.setup(initCR) - } - // perform update - Eventually(func() error { - var toUpdate vmv1beta1.VMSingle - Expect(k8sClient.Get(ctx, namespacedName, &toUpdate)).To(Succeed()) - step.modify(&toUpdate) - return k8sClient.Update(ctx, &toUpdate) - }, eventualExpandingTimeout).Should(Succeed()) - Eventually(func() error { - return expectObjectStatusOperational(ctx, k8sClient, &vmv1beta1.VMSingle{}, namespacedName) - }, eventualDeploymentAppReadyTimeout).Should(Succeed()) - - var updated vmv1beta1.VMSingle - Expect(k8sClient.Get(ctx, namespacedName, &updated)).To(Succeed()) + var updated vmv1beta1.VMSingle + Expect(k8sClient.Get(ctx, namespacedName, &updated)).To(Succeed()) - // verify results - step.verify(&updated) - } + // verify results + step.verify(&updated) + } + }, + Entry("add backup app", "add-backup", true, + baseSingle.DeepCopy(), + testStep{ + modify: func(cr *vmv1beta1.VMSingle) { + cr.Spec.Volumes = []corev1.Volume{ + {Name: "backup", VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}}}, + } + cr.Spec.VMBackup = &vmv1beta1.VMBackup{ + Destination: "fs:///opt/backup", + VolumeMounts: []corev1.VolumeMount{{Name: "backup", MountPath: "/opt/backup"}}, + } + }, + verify: func(cr *vmv1beta1.VMSingle) { + var createdDeploy appsv1.Deployment + Expect(k8sClient.Get(ctx, + types.NamespacedName{Namespace: namespace, Name: cr.PrefixedName()}, &createdDeploy)). + To(Succeed()) + Expect(createdDeploy.Spec.Template.Spec.Containers).To(HaveLen(2)) + Expect(createdDeploy.Spec.Template.Spec.Containers[1].VolumeMounts).To(HaveLen(3)) + }, + }), + Entry("add and remove annotations", "manage-annotations", false, + baseSingle.DeepCopy(), + testStep{ + modify: func(cr *vmv1beta1.VMSingle) { + cr.Spec.ManagedMetadata = &vmv1beta1.ManagedObjectsMetadata{ + Annotations: map[string]string{ + "added-annotation": "some-value", + }, + } + }, + verify: func(cr *vmv1beta1.VMSingle) { + nss := types.NamespacedName{Namespace: namespace, Name: cr.PrefixedName()} + expectedAnnotations := map[string]string{"added-annotation": "some-value"} + assertAnnotationsOnObjects(ctx, nss, []client.Object{&appsv1.Deployment{}, &corev1.ServiceAccount{}, &corev1.Service{}}, expectedAnnotations) + var createdDeploy appsv1.Deployment + Expect(k8sClient.Get(ctx, nss, &createdDeploy)). + To(Succeed()) + }, }, - Entry("add backup app", "add-backup", - baseSingle.DeepCopy(), - testStep{ - modify: func(cr *vmv1beta1.VMSingle) { - cr.Spec.Volumes = []corev1.Volume{ - {Name: "backup", VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}}}, - } - cr.Spec.VMBackup = &vmv1beta1.VMBackup{ - AcceptEULA: true, - Destination: "fs:///opt/backup", - VolumeMounts: []corev1.VolumeMount{{Name: "backup", MountPath: "/opt/backup"}}, - } - }, - verify: func(cr *vmv1beta1.VMSingle) { - var createdDeploy appsv1.Deployment - Expect(k8sClient.Get(ctx, - types.NamespacedName{Namespace: namespace, Name: cr.PrefixedName()}, &createdDeploy)). - To(Succeed()) - Expect(createdDeploy.Spec.Template.Spec.Containers).To(HaveLen(2)) - Expect(createdDeploy.Spec.Template.Spec.Containers[1].VolumeMounts).To(HaveLen(2)) - - }, - }), - Entry("add and remove annotations", "manage-annotations", - baseSingle.DeepCopy(), - testStep{ - modify: func(cr *vmv1beta1.VMSingle) { - cr.Spec.ManagedMetadata = &vmv1beta1.ManagedObjectsMetadata{ - Annotations: map[string]string{ - "added-annotation": "some-value", - }, - } - }, - verify: func(cr *vmv1beta1.VMSingle) { - nss := types.NamespacedName{Namespace: namespace, Name: cr.PrefixedName()} - - expectedAnnotations := map[string]string{"added-annotation": "some-value"} - assertAnnotationsOnObjects(ctx, nss, []client.Object{&appsv1.Deployment{}, &corev1.ServiceAccount{}, &corev1.Service{}}, expectedAnnotations) - var createdDeploy appsv1.Deployment - Expect(k8sClient.Get(ctx, nss, &createdDeploy)). - To(Succeed()) - }, + testStep{ + modify: func(cr *vmv1beta1.VMSingle) { + delete(cr.Spec.ManagedMetadata.Annotations, "added-annotation") }, - testStep{ - modify: func(cr *vmv1beta1.VMSingle) { - delete(cr.Spec.ManagedMetadata.Annotations, "added-annotation") - }, - verify: func(cr *vmv1beta1.VMSingle) { - nss := types.NamespacedName{Namespace: namespace, Name: cr.PrefixedName()} - expectedAnnotations := map[string]string{"added-annotation": ""} - - assertAnnotationsOnObjects(ctx, nss, []client.Object{&appsv1.Deployment{}, &corev1.ServiceAccount{}, &corev1.Service{}}, expectedAnnotations) - - }, + verify: func(cr *vmv1beta1.VMSingle) { + nss := types.NamespacedName{Namespace: namespace, Name: cr.PrefixedName()} + expectedAnnotations := map[string]string{"added-annotation": ""} + assertAnnotationsOnObjects(ctx, nss, []client.Object{&appsv1.Deployment{}, &corev1.ServiceAccount{}, &corev1.Service{}}, expectedAnnotations) }, - ), - ) - }, + }, + ), ) }) })