diff --git a/test/e2e/vmagent_test.go b/test/e2e/vmagent_test.go index 81214dd4..a0d48a57 100644 --- a/test/e2e/vmagent_test.go +++ b/test/e2e/vmagent_test.go @@ -11,14 +11,16 @@ import ( "golang.org/x/net/context" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" + policyv1 "k8s.io/api/policy/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/client" ) -//nolint:dupl +//nolint:dupl,lll var _ = Describe("test vmagent Controller", func() { ctx := context.Background() It("must clean up previous test resutls", func() { @@ -236,83 +238,200 @@ var _ = Describe("test vmagent Controller", func() { }), ) - existObject := &v1beta1vm.VMAgent{ - ObjectMeta: metav1.ObjectMeta{ - Name: namespacedName.Name, - Namespace: namespace, - }, - Spec: v1beta1vm.VMAgentSpec{ - CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ - ReplicaCount: ptr.To[int32](1), - }, - RemoteWrite: []v1beta1vm.VMAgentRemoteWriteSpec{ - {URL: "http://some-vm-single:8428"}, - }, - }, + type testStep struct { + setup func(*v1beta1vm.VMAgent) + modify func(*v1beta1vm.VMAgent) + verify func(*v1beta1vm.VMAgent) } DescribeTable("should update exist vmagent", - func(name string, modify func(*v1beta1vm.VMAgent), verify func(*v1beta1vm.VMAgent)) { + func(name string, initCR *v1beta1vm.VMAgent, steps ...testStep) { // create and wait ready - existObject := existObject.DeepCopy() - existObject.Name = name + initCR.Name = name + initCR.Namespace = namespace namespacedName.Name = name - Expect(k8sClient.Create(ctx, existObject)).To(Succeed()) - Eventually(func() error { - return expectObjectStatusOperational(ctx, k8sClient, &v1beta1vm.VMAgent{}, namespacedName) - }, eventualStatefulsetAppReadyTimeout).Should(Succeed()) - // update and wait ready - Eventually(func() error { - var toUpdate v1beta1vm.VMAgent - Expect(k8sClient.Get(ctx, namespacedName, &toUpdate)).To(Succeed()) - modify(&toUpdate) - return k8sClient.Update(ctx, &toUpdate) - }, eventualExpandingTimeout).Should(Succeed()) - Eventually(func() error { - return expectObjectStatusExpanding(ctx, k8sClient, &v1beta1vm.VMAgent{}, namespacedName) - }, eventualExpandingTimeout).Should(Succeed()) + Expect(k8sClient.Create(ctx, initCR)).To(Succeed()) Eventually(func() error { return expectObjectStatusOperational(ctx, k8sClient, &v1beta1vm.VMAgent{}, namespacedName) }, eventualStatefulsetAppReadyTimeout).Should(Succeed()) - // verify - var updated v1beta1vm.VMAgent - Expect(k8sClient.Get(ctx, namespacedName, &updated)).To(Succeed()) - verify(&updated) + for _, step := range steps { + if step.setup != nil { + step.setup(initCR) + } + // update and wait ready + Eventually(func() error { + var toUpdate v1beta1vm.VMAgent + Expect(k8sClient.Get(ctx, namespacedName, &toUpdate)).To(Succeed()) + step.modify(&toUpdate) + return k8sClient.Update(ctx, &toUpdate) + }, eventualExpandingTimeout).Should(Succeed()) + Eventually(func() error { + return expectObjectStatusExpanding(ctx, k8sClient, &v1beta1vm.VMAgent{}, namespacedName) + }, eventualExpandingTimeout).Should(Succeed()) + Eventually(func() error { + return expectObjectStatusOperational(ctx, k8sClient, &v1beta1vm.VMAgent{}, namespacedName) + }, eventualStatefulsetAppReadyTimeout).Should(Succeed()) + // verify + var updated v1beta1vm.VMAgent + Expect(k8sClient.Get(ctx, namespacedName, &updated)).To(Succeed()) + step.verify(&updated) + } }, Entry("by scaling replicas to to 3", "update-replicas-3", - func(cr *v1beta1vm.VMAgent) { cr.Spec.ReplicaCount = ptr.To[int32](3) }, - func(cr *v1beta1vm.VMAgent) { - Eventually(func() string { - return expectPodCount(k8sClient, 3, namespace, cr.SelectorLabels()) - }, eventualDeploymentAppReadyTimeout, 1).Should(BeEmpty()) - }), + &v1beta1vm.VMAgent{ + Spec: v1beta1vm.VMAgentSpec{ + CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + }, + RemoteWrite: []v1beta1vm.VMAgentRemoteWriteSpec{ + {URL: "http://some-vm-single:8428"}, + }, + }, + }, + testStep{ + modify: func(cr *v1beta1vm.VMAgent) { cr.Spec.ReplicaCount = ptr.To[int32](3) }, + verify: func(cr *v1beta1vm.VMAgent) { + Eventually(func() string { + return expectPodCount(k8sClient, 3, namespace, cr.SelectorLabels()) + }, eventualDeploymentAppReadyTimeout, 1).Should(BeEmpty()) + }, + }, + ), Entry("by chaning revisionHistoryLimit to 3", "update-revision", - func(cr *v1beta1vm.VMAgent) { cr.Spec.RevisionHistoryLimitCount = ptr.To[int32](3) }, - func(cr *v1beta1vm.VMAgent) { - namespacedNameDeployment := types.NamespacedName{ - Name: cr.PrefixedName(), - Namespace: namespace, - } - Expect(getRevisionHistoryLimit(k8sClient, namespacedNameDeployment)).To(Equal(int32(3))) - }), + &v1beta1vm.VMAgent{ + Spec: v1beta1vm.VMAgentSpec{ + CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + RevisionHistoryLimitCount: ptr.To[int32](11), + }, + RemoteWrite: []v1beta1vm.VMAgentRemoteWriteSpec{ + {URL: "http://some-vm-single:8428"}, + }, + }, + }, + testStep{ + setup: func(cr *v1beta1vm.VMAgent) { + Expect(getRevisionHistoryLimit(k8sClient, types.NamespacedName{ + Namespace: cr.Namespace, + Name: cr.PrefixedName(), + })).To(Equal(int32(11))) + }, + modify: func(cr *v1beta1vm.VMAgent) { cr.Spec.RevisionHistoryLimitCount = ptr.To[int32](3) }, + verify: func(cr *v1beta1vm.VMAgent) { + namespacedNameDeployment := types.NamespacedName{ + Name: cr.PrefixedName(), + Namespace: namespace, + } + Expect(getRevisionHistoryLimit(k8sClient, namespacedNameDeployment)).To(Equal(int32(3))) + }, + }, + ), Entry("by switching to statefulMode with shard", "stateful-shard", - func(cr *v1beta1vm.VMAgent) { - cr.Spec.ReplicaCount = ptr.To[int32](1) - cr.Spec.ShardCount = ptr.To(2) - cr.Spec.StatefulMode = true - cr.Spec.IngestOnlyMode = true + &v1beta1vm.VMAgent{ + Spec: v1beta1vm.VMAgentSpec{ + CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + }, + RemoteWrite: []v1beta1vm.VMAgentRemoteWriteSpec{ + {URL: "http://some-vm-single:8428"}, + }, + }, }, - func(cr *v1beta1vm.VMAgent) { - var createdSts appsv1.StatefulSet - Expect(k8sClient.Get(ctx, types.NamespacedName{ - Namespace: namespace, - Name: fmt.Sprintf("%s-%d", cr.PrefixedName(), 0), - }, &createdSts)).To(Succeed()) - Expect(k8sClient.Get(ctx, types.NamespacedName{ - Namespace: namespace, - Name: fmt.Sprintf("%s-%d", cr.PrefixedName(), 1), - }, &createdSts)).To(Succeed()) + testStep{ + modify: func(cr *v1beta1vm.VMAgent) { + cr.Spec.ReplicaCount = ptr.To[int32](1) + cr.Spec.ShardCount = ptr.To(2) + cr.Spec.StatefulMode = true + cr.Spec.IngestOnlyMode = true + }, + verify: func(cr *v1beta1vm.VMAgent) { + var createdSts appsv1.StatefulSet + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Namespace: namespace, + Name: fmt.Sprintf("%s-%d", cr.PrefixedName(), 0), + }, &createdSts)).To(Succeed()) + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Namespace: namespace, + Name: fmt.Sprintf("%s-%d", cr.PrefixedName(), 1), + }, &createdSts)).To(Succeed()) - }), + }, + }, + ), + + Entry("by transition into statefulMode and back", "stateful-transition", + &v1beta1vm.VMAgent{Spec: v1beta1vm.VMAgentSpec{ + CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + }, + RemoteWrite: []v1beta1vm.VMAgentRemoteWriteSpec{ + {URL: "http://some-vm-single:8428"}, + }, + }, + }, + testStep{ + modify: func(cr *v1beta1vm.VMAgent) { cr.Spec.StatefulMode = true }, + verify: func(cr *v1beta1vm.VMAgent) { + nsn := types.NamespacedName{Namespace: namespace, Name: cr.PrefixedName()} + Expect(k8sClient.Get(ctx, nsn, &appsv1.StatefulSet{})).To(Succeed()) + Expect(k8sClient.Get(ctx, nsn, &appsv1.Deployment{})).To(MatchError(errors.IsNotFound, "IsNotFound")) + }, + }, + testStep{ + modify: func(cr *v1beta1vm.VMAgent) { cr.Spec.StatefulMode = false }, + verify: func(cr *v1beta1vm.VMAgent) { + nsn := types.NamespacedName{Namespace: namespace, Name: cr.PrefixedName()} + Expect(k8sClient.Get(ctx, nsn, &appsv1.Deployment{})).To(Succeed()) + Expect(k8sClient.Get(ctx, nsn, &appsv1.StatefulSet{})).To(MatchError(errors.IsNotFound, "IsNotFound")) + }, + }, + ), + Entry("by deleting and restoring PodDisruptionBudget and serviceScrape", "pdb-mutations-scrape", + &v1beta1vm.VMAgent{Spec: v1beta1vm.VMAgentSpec{ + CommonDefaultableParams: v1beta1vm.CommonDefaultableParams{UseDefaultResources: ptr.To(false)}, + CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](2), + }, + SelectAllByDefault: true, + PodDisruptionBudget: &v1beta1vm.EmbeddedPodDisruptionBudgetSpec{MaxUnavailable: &intstr.IntOrString{IntVal: 1}}, + RemoteWrite: []v1beta1vm.VMAgentRemoteWriteSpec{ + {URL: "http://some-vm-single:8428"}, + }, + }, + }, + testStep{ + setup: func(cr *v1beta1vm.VMAgent) { + nsn := types.NamespacedName{Namespace: namespace, Name: cr.PrefixedName()} + Expect(k8sClient.Get(ctx, nsn, &policyv1.PodDisruptionBudget{})).To(Succeed()) + Expect(k8sClient.Get(ctx, nsn, &v1beta1vm.VMServiceScrape{})).To(Succeed()) + }, + modify: func(cr *v1beta1vm.VMAgent) { + cr.Spec.PodDisruptionBudget = nil + cr.Spec.DisableSelfServiceScrape = ptr.To(true) + }, + verify: func(cr *v1beta1vm.VMAgent) { + nsn := types.NamespacedName{Namespace: namespace, Name: cr.PrefixedName()} + Eventually(func() error { + return k8sClient.Get(ctx, nsn, &policyv1.PodDisruptionBudget{}) + }, eventualDeletionTimeout).Should(MatchError(errors.IsNotFound, "IsNotFound")) + Eventually(func() error { + return k8sClient.Get(ctx, nsn, &v1beta1vm.VMServiceScrape{}) + }, eventualDeletionTimeout).Should(MatchError(errors.IsNotFound, "IsNotFound")) + }, + }, + testStep{ + modify: func(cr *v1beta1vm.VMAgent) { + cr.Spec.PodDisruptionBudget = &v1beta1vm.EmbeddedPodDisruptionBudgetSpec{MaxUnavailable: &intstr.IntOrString{IntVal: 1}} + cr.Spec.DisableSelfServiceScrape = nil + + }, + verify: func(cr *v1beta1vm.VMAgent) { + nsn := types.NamespacedName{Namespace: namespace, Name: cr.PrefixedName()} + Expect(k8sClient.Get(ctx, nsn, &policyv1.PodDisruptionBudget{})).To(Succeed()) + Expect(k8sClient.Get(ctx, nsn, &v1beta1vm.VMServiceScrape{})).To(Succeed()) + + }, + }, + ), ) }) }) diff --git a/test/e2e/vmauth_test.go b/test/e2e/vmauth_test.go index 80b413e0..9c395a6c 100644 --- a/test/e2e/vmauth_test.go +++ b/test/e2e/vmauth_test.go @@ -7,9 +7,12 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "golang.org/x/net/context" + networkingv1 "k8s.io/api/networking/v1" + policyv1 "k8s.io/api/policy/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -110,72 +113,183 @@ var _ = Describe("test vmauth Controller", func() { }), ) - existVMAuth := &v1beta1vm.VMAuth{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace, - }, - Spec: v1beta1vm.VMAuthSpec{ - CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ - ReplicaCount: ptr.To[int32](1), - }, - UnauthorizedAccessConfig: []v1beta1vm.UnauthorizedAccessConfigURLMap{ - { - URLPrefix: []string{"http://localhost:8490"}, - SrcPaths: []string{"/.*"}, - }, - }, - }, + type testStep struct { + setup func(*v1beta1vm.VMAuth) + modify func(*v1beta1vm.VMAuth) + verify func(*v1beta1vm.VMAuth) } DescribeTable("should update exist vmauth", - func(name string, modify func(*v1beta1vm.VMAuth), verify func(*v1beta1vm.VMAuth)) { - existVMAuth := existVMAuth.DeepCopy() - existVMAuth.Name = name + func(name string, initCR *v1beta1vm.VMAuth, steps ...testStep) { + initCR.Name = name + initCR.Namespace = namespace namespacedName.Name = name // setup test - Expect(k8sClient.Create(ctx, existVMAuth)).To(Succeed()) + Expect(k8sClient.Create(ctx, initCR)).To(Succeed()) Eventually(func() error { return expectObjectStatusOperational(ctx, k8sClient, &v1beta1vm.VMAuth{}, namespacedName) }, eventualDeploymentAppReadyTimeout).Should(Succeed()) + for _, step := range steps { + if step.setup != nil { + step.setup(initCR) + } + // perform update + Eventually(func() error { + var toUpdate v1beta1vm.VMAuth + Expect(k8sClient.Get(ctx, namespacedName, &toUpdate)).To(Succeed()) + step.modify(&toUpdate) + return k8sClient.Update(ctx, &toUpdate) + }, eventualExpandingTimeout).Should(Succeed()) + Eventually(func() error { + return expectObjectStatusExpanding(ctx, k8sClient, &v1beta1vm.VMAuth{}, namespacedName) + }, eventualExpandingTimeout).Should(Succeed()) + Eventually(func() error { + return expectObjectStatusOperational(ctx, k8sClient, &v1beta1vm.VMAuth{}, namespacedName) + }, eventualDeploymentAppReadyTimeout).Should(Succeed()) + var updated v1beta1vm.VMAuth + Expect(k8sClient.Get(ctx, namespacedName, &updated)).To(Succeed()) + // verify results + step.verify(&updated) + } - // perform update - Eventually(func() error { - var toUpdate v1beta1vm.VMAuth - Expect(k8sClient.Get(ctx, namespacedName, &toUpdate)).To(Succeed()) - modify(&toUpdate) - return k8sClient.Update(ctx, &toUpdate) - }, eventualExpandingTimeout).Should(Succeed()) - Eventually(func() error { - return expectObjectStatusExpanding(ctx, k8sClient, &v1beta1vm.VMAuth{}, namespacedName) - }, eventualExpandingTimeout).Should(Succeed()) - Eventually(func() error { - return expectObjectStatusOperational(ctx, k8sClient, &v1beta1vm.VMAuth{}, namespacedName) - }, eventualDeploymentAppReadyTimeout).Should(Succeed()) - var updated v1beta1vm.VMAuth - Expect(k8sClient.Get(ctx, namespacedName, &updated)).To(Succeed()) - // verify results - verify(&updated) }, - Entry("extend replicas to 2", "update-replicas-2", - func(cr *v1beta1vm.VMAuth) { - cr.Spec.ReplicaCount = ptr.To[int32](2) + Entry("by chaning replicas to 2", "update-replicas-2", + &v1beta1vm.VMAuth{ + Spec: v1beta1vm.VMAuthSpec{ + CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + }, + UnauthorizedAccessConfig: []v1beta1vm.UnauthorizedAccessConfigURLMap{ + { + URLPrefix: []string{"http://localhost:8490"}, + SrcPaths: []string{"/.*"}, + }, + }, + }, }, - func(cr *v1beta1vm.VMAuth) { - Eventually(func() string { - return expectPodCount(k8sClient, 2, namespace, cr.SelectorLabels()) - }, eventualDeploymentPodTimeout).Should(BeEmpty()) - }), - Entry("switch to vm config reloader", "vm-reloader", - func(cr *v1beta1vm.VMAuth) { - cr.Spec.UseVMConfigReloader = ptr.To(true) - cr.Spec.UseDefaultResources = ptr.To(false) + testStep{ + modify: func(cr *v1beta1vm.VMAuth) { + cr.Spec.ReplicaCount = ptr.To[int32](2) + }, + verify: func(cr *v1beta1vm.VMAuth) { + Eventually(func() string { + return expectPodCount(k8sClient, 2, namespace, cr.SelectorLabels()) + }, eventualDeploymentPodTimeout).Should(BeEmpty()) + }, }, - func(cr *v1beta1vm.VMAuth) { - Eventually(func() string { - return expectPodCount(k8sClient, 1, namespace, cr.SelectorLabels()) - }, eventualDeploymentPodTimeout).Should(BeEmpty()) - }), + ), + Entry("by switching to vm config reloader", "vm-reloader", + &v1beta1vm.VMAuth{ + Spec: v1beta1vm.VMAuthSpec{ + SelectAllByDefault: true, + CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + }, + UnauthorizedAccessConfig: []v1beta1vm.UnauthorizedAccessConfigURLMap{ + { + URLPrefix: []string{"http://localhost:8490"}, + SrcPaths: []string{"/.*"}, + }, + }, + }, + }, + testStep{ + modify: func(cr *v1beta1vm.VMAuth) { + cr.Spec.UseVMConfigReloader = ptr.To(true) + cr.Spec.UseDefaultResources = ptr.To(false) + }, + verify: func(cr *v1beta1vm.VMAuth) { + Eventually(func() string { + return expectPodCount(k8sClient, 1, namespace, cr.SelectorLabels()) + }, eventualDeploymentPodTimeout).Should(BeEmpty()) + }, + }, + ), + Entry("by removing podDistruptionBudget and keeping exist ingress", "vm-keep-ingress-change-pdb", + &v1beta1vm.VMAuth{ + Spec: v1beta1vm.VMAuthSpec{ + SelectAllByDefault: true, + CommonDefaultableParams: v1beta1vm.CommonDefaultableParams{ + UseDefaultResources: ptr.To(false), + }, + CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](2), + }, + PodDisruptionBudget: &v1beta1vm.EmbeddedPodDisruptionBudgetSpec{ + MaxUnavailable: &intstr.IntOrString{IntVal: 1}, + }, + UnauthorizedAccessConfig: []v1beta1vm.UnauthorizedAccessConfigURLMap{ + { + URLPrefix: []string{"http://localhost:8490"}, + SrcPaths: []string{"/.*"}, + }, + }, + }, + }, + testStep{ + setup: func(cr *v1beta1vm.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 *v1beta1vm.VMAuth) { + cr.Spec.PodDisruptionBudget = nil + }, + verify: func(cr *v1beta1vm.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(errors.IsNotFound, "IsNotFound")) + }, + }, + testStep{ + modify: func(cr *v1beta1vm.VMAuth) { + cr.Spec.PodDisruptionBudget = &v1beta1vm.EmbeddedPodDisruptionBudgetSpec{ + MaxUnavailable: &intstr.IntOrString{IntVal: 1}, + } + }, + verify: func(cr *v1beta1vm.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()) + }, + }, + ), ) - }) }) }) diff --git a/test/e2e/vmcluster_test.go b/test/e2e/vmcluster_test.go index 2be4b1ce..838882e1 100644 --- a/test/e2e/vmcluster_test.go +++ b/test/e2e/vmcluster_test.go @@ -10,107 +10,276 @@ import ( v1beta1vm "github.com/VictoriaMetrics/operator/api/operator/v1beta1" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/utils/ptr" ) +//nolint:dupl,lll var _ = Describe("e2e vmcluster", func() { - Context("crud", func() { - namespace := "default" - var ctx context.Context - namespacedName := types.NamespacedName{ - Namespace: namespace, - } - It("must clean up previous test resutls", func() { + namespace := "default" + var ctx context.Context + namespacedName := types.NamespacedName{ + Namespace: namespace, + } + It("must clean up previous test resutls", func() { + ctx = context.Background() + // clean up before tests + Expect(k8sClient.DeleteAllOf(ctx, &v1beta1vm.VMCluster{}, &client.DeleteAllOfOptions{ + ListOptions: client.ListOptions{ + Namespace: namespace, + }, + })).To(Succeed()) + Eventually(func() bool { + var unDeletedObjects v1beta1vm.VMClusterList + Expect(k8sClient.List(ctx, &unDeletedObjects, &client.ListOptions{ + Namespace: namespace, + })).To(Succeed()) + return len(unDeletedObjects.Items) == 0 + }, eventualDeletionTimeout).Should(BeTrue()) + + }) + + Context("create", func() { + JustBeforeEach(func() { ctx = context.Background() - // clean up before tests - Expect(k8sClient.DeleteAllOf(ctx, &v1beta1vm.VMCluster{}, &client.DeleteAllOfOptions{ - ListOptions: client.ListOptions{ + }) + AfterEach(func() { + Expect(k8sClient.Delete(ctx, &v1beta1vm.VMCluster{ + ObjectMeta: metav1.ObjectMeta{ Namespace: namespace, + Name: namespacedName.Name, }, - })).To(Succeed()) - Eventually(func() bool { - var unDeletedObjects v1beta1vm.VMClusterList - Expect(k8sClient.List(ctx, &unDeletedObjects, &client.ListOptions{ + })).To(Succeed(), "must delete vmcluster after test") + Eventually(func() error { + err := k8sClient.Get(ctx, types.NamespacedName{ + Name: namespacedName.Name, Namespace: namespace, - })).To(Succeed()) - return len(unDeletedObjects.Items) == 0 - }, eventualDeletionTimeout).Should(BeTrue()) - + }, &v1beta1vm.VMCluster{}) + if errors.IsNotFound(err) { + return nil + } + return fmt.Errorf("want NotFound error, got: %w", err) + }, eventualDeletionTimeout, 1).Should(BeNil()) }) - Context("create", func() { - JustBeforeEach(func() { - ctx = context.Background() - }) - AfterEach(func() { - Expect(k8sClient.Delete(ctx, &v1beta1vm.VMCluster{ + DescribeTable("should create vmcluster", func(name string, cr *v1beta1vm.VMCluster) { + namespacedName.Name = name + cr.Name = name + Expect(k8sClient.Create(ctx, cr)).To(Succeed()) + Eventually(func() error { + return expectObjectStatusOperational(ctx, k8sClient, &v1beta1vm.VMCluster{}, namespacedName) + }, eventualStatefulsetAppReadyTimeout).Should(Succeed()) + + }, + Entry("without any componets", "empty", &v1beta1vm.VMCluster{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace, + Name: namespacedName.Name, + }, + Spec: v1beta1vm.VMClusterSpec{RetentionPeriod: "1"}, + }), + Entry("with all components", "all-services", + &v1beta1vm.VMCluster{ ObjectMeta: metav1.ObjectMeta{ Namespace: namespace, Name: namespacedName.Name, }, - })).To(Succeed(), "must delete vmcluster after test") - Eventually(func() error { - err := k8sClient.Get(ctx, types.NamespacedName{ - Name: namespacedName.Name, - Namespace: namespace, - }, &v1beta1vm.VMCluster{}) - if errors.IsNotFound(err) { - return nil - } - return fmt.Errorf("want NotFound error, got: %w", err) - }, eventualDeletionTimeout, 1).Should(BeNil()) - }) - - DescribeTable("should create vmcluster", func(name string, cr *v1beta1vm.VMCluster) { - namespacedName.Name = name - cr.Name = name - Expect(k8sClient.Create(ctx, cr)).To(Succeed()) - Eventually(func() error { - return expectObjectStatusOperational(ctx, k8sClient, &v1beta1vm.VMCluster{}, namespacedName) - }, eventualStatefulsetAppReadyTimeout).Should(Succeed()) - - }, - Entry("without any componets", "empty", &v1beta1vm.VMCluster{ + Spec: v1beta1vm.VMClusterSpec{ + RetentionPeriod: "1", + VMStorage: &v1beta1vm.VMStorage{ + CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + }, + }, + VMSelect: &v1beta1vm.VMSelect{ + CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + }, + }, + VMInsert: &v1beta1vm.VMInsert{CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + }, + }, + }, + }, + ), + Entry("with vmstorage and vmselect", "with-select", &v1beta1vm.VMCluster{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace, + Name: namespacedName.Name, + }, + Spec: v1beta1vm.VMClusterSpec{ + RetentionPeriod: "1", + VMStorage: &v1beta1vm.VMStorage{ + CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + }, + }, + VMSelect: &v1beta1vm.VMSelect{ + CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + }, + }, + }, + }), + Entry("with vmstorage and vminsert", "with-insert", &v1beta1vm.VMCluster{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace, + Name: namespacedName.Name, + }, + Spec: v1beta1vm.VMClusterSpec{ + RetentionPeriod: "1", + VMStorage: &v1beta1vm.VMStorage{ + CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + }, + }, + VMInsert: &v1beta1vm.VMInsert{CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + }, + }, + }, + }), + Entry("with security enable and without default resources", "all-secure", + &v1beta1vm.VMCluster{ ObjectMeta: metav1.ObjectMeta{ Namespace: namespace, Name: namespacedName.Name, }, - Spec: v1beta1vm.VMClusterSpec{RetentionPeriod: "1"}, - }), - Entry("with all components", "all-services", - &v1beta1vm.VMCluster{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace, - Name: namespacedName.Name, - }, - Spec: v1beta1vm.VMClusterSpec{ - RetentionPeriod: "1", - VMStorage: &v1beta1vm.VMStorage{ - CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ - ReplicaCount: ptr.To[int32](1), - }, + Spec: v1beta1vm.VMClusterSpec{ + RetentionPeriod: "1", + VMStorage: &v1beta1vm.VMStorage{ + CommonDefaultableParams: v1beta1vm.CommonDefaultableParams{ + // UseStrictSecurity: ptr.To(true), + UseDefaultResources: ptr.To(false), }, - VMSelect: &v1beta1vm.VMSelect{ - CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ - ReplicaCount: ptr.To[int32](1), - }, + CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + }, + }, + VMSelect: &v1beta1vm.VMSelect{ + CommonDefaultableParams: v1beta1vm.CommonDefaultableParams{ + // UseStrictSecurity: ptr.To(true), + UseDefaultResources: ptr.To(false), }, - VMInsert: &v1beta1vm.VMInsert{CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + + CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ ReplicaCount: ptr.To[int32](1), }, + }, + VMInsert: &v1beta1vm.VMInsert{ + CommonDefaultableParams: v1beta1vm.CommonDefaultableParams{ + // UseStrictSecurity: ptr.To(true), + UseDefaultResources: ptr.To(false), + }, + CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), }, }, }, - ), - Entry("with vmstorage and vmselect", "with-select", &v1beta1vm.VMCluster{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace, - Name: namespacedName.Name, + }, + ), + ) + }) + Context("update", func() { + AfterEach(func() { + Expect(k8sClient.Delete(ctx, &v1beta1vm.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, + }, &v1beta1vm.VMCluster{}) + + }, eventualDeletionTimeout).Should(MatchError(errors.IsNotFound, "want not found error")) + }) + + type testStep struct { + setup func(*v1beta1vm.VMCluster) + modify func(*v1beta1vm.VMCluster) + verify func(*v1beta1vm.VMCluster) + } + + DescribeTable("should update exist cluster", + func(name string, initCR *v1beta1vm.VMCluster, steps ...testStep) { + 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) + }, eventualStatefulsetAppReadyTimeout). + Should(Succeed()) + for _, step := range steps { + if step.setup != nil { + step.setup(initCR) + } + // update and wait ready + Eventually(func() error { + var toUpdate v1beta1.VMCluster + if err := k8sClient.Get(ctx, namespacedName, &toUpdate); err != nil { + return err + } + step.modify(&toUpdate) + return k8sClient.Update(ctx, &toUpdate) + }, eventualExpandingTimeout).Should(Succeed()) + Eventually(func() error { + return expectObjectStatusExpanding(ctx, k8sClient, initCR, namespacedName) + }, eventualStatefulsetAppReadyTimeout). + Should(Succeed()) + Eventually(func() error { + return expectObjectStatusOperational(ctx, k8sClient, initCR, namespacedName) + }, eventualStatefulsetAppReadyTimeout). + Should(Succeed()) + var updated v1beta1vm.VMCluster + Expect(k8sClient.Get(ctx, namespacedName, &updated)).To(Succeed()) + // verify results + step.verify(&updated) + } + }, + Entry("by scaling select and storage replicas to 2", "storage-select-r-2", + &v1beta1vm.VMCluster{ + Spec: v1beta1vm.VMClusterSpec{ + RetentionPeriod: "1", + VMStorage: &v1beta1vm.VMStorage{ + CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + }, + }, + VMSelect: &v1beta1vm.VMSelect{ + CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + }, + }, + VMInsert: &v1beta1vm.VMInsert{CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + }, + }, + }, + }, + testStep{ + modify: func(cr *v1beta1vm.VMCluster) { + cr.Spec.VMStorage.ReplicaCount = ptr.To[int32](2) + cr.Spec.VMSelect.ReplicaCount = ptr.To[int32](2) + }, + verify: func(cr *v1beta1vm.VMCluster) { + Expect(expectPodCount(k8sClient, 2, namespace, cr.VMStorageSelectorLabels())).To(BeEmpty()) + Expect(expectPodCount(k8sClient, 2, namespace, cr.VMSelectSelectorLabels())).To(BeEmpty()) }, + }, + ), + Entry("by scaling storage and insert replicas to 2", "storage-insert-r-2", + &v1beta1vm.VMCluster{ Spec: v1beta1vm.VMClusterSpec{ RetentionPeriod: "1", VMStorage: &v1beta1vm.VMStorage{ @@ -123,13 +292,27 @@ var _ = Describe("e2e vmcluster", func() { ReplicaCount: ptr.To[int32](1), }, }, + VMInsert: &v1beta1vm.VMInsert{CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + }, + }, }, - }), - Entry("with vmstorage and vminsert", "with-insert", &v1beta1vm.VMCluster{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace, - Name: namespacedName.Name, + }, + testStep{ + modify: func(cr *v1beta1vm.VMCluster) { + cr.Spec.VMStorage.ReplicaCount = ptr.To[int32](2) + cr.Spec.VMInsert.ReplicaCount = ptr.To[int32](2) + }, + verify: func(cr *v1beta1vm.VMCluster) { + Expect(expectPodCount(k8sClient, 2, namespace, cr.VMStorageSelectorLabels())).To(BeEmpty()) + Eventually(func() string { + return expectPodCount(k8sClient, 2, namespace, cr.VMInsertSelectorLabels()) + }, eventualDeploymentPodTimeout).Should(BeEmpty()) }, + }, + ), + Entry("by changing storage revisionHistoryLimit to 2", "storage-revision-2", + &v1beta1vm.VMCluster{ Spec: v1beta1vm.VMClusterSpec{ RetentionPeriod: "1", VMStorage: &v1beta1vm.VMStorage{ @@ -137,170 +320,301 @@ var _ = Describe("e2e vmcluster", func() { ReplicaCount: ptr.To[int32](1), }, }, + VMSelect: &v1beta1vm.VMSelect{ + CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + }, + }, VMInsert: &v1beta1vm.VMInsert{CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ ReplicaCount: ptr.To[int32](1), }, }, }, - }), - Entry("with security enable and without default resources", "all-secure", - &v1beta1vm.VMCluster{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace, - Name: namespacedName.Name, + }, + testStep{ + modify: func(cr *v1beta1vm.VMCluster) { + cr.Spec.VMStorage.RevisionHistoryLimitCount = ptr.To[int32](2) + }, + verify: func(cr *v1beta1vm.VMCluster) { + var updatedCluster v1beta1vm.VMCluster + Expect(k8sClient.Get(ctx, namespacedName, &updatedCluster)).To(Succeed()) + Expect(*updatedCluster.Spec.VMStorage.RevisionHistoryLimitCount).To(Equal(int32(2))) + }, + }, + ), + Entry("by adding clusterNative ports", "storage-native-r-2", + &v1beta1vm.VMCluster{ + Spec: v1beta1vm.VMClusterSpec{ + RetentionPeriod: "1", + VMStorage: &v1beta1vm.VMStorage{ + CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + }, }, - Spec: v1beta1vm.VMClusterSpec{ - RetentionPeriod: "1", - VMStorage: &v1beta1vm.VMStorage{ - CommonDefaultableParams: v1beta1vm.CommonDefaultableParams{ - // UseStrictSecurity: ptr.To(true), - UseDefaultResources: ptr.To(false), - }, - CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ - ReplicaCount: ptr.To[int32](1), - }, + VMSelect: &v1beta1vm.VMSelect{ + CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), }, - VMSelect: &v1beta1vm.VMSelect{ - CommonDefaultableParams: v1beta1vm.CommonDefaultableParams{ - // UseStrictSecurity: ptr.To(true), - UseDefaultResources: ptr.To(false), - }, - - CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ - ReplicaCount: ptr.To[int32](1), - }, + }, + VMInsert: &v1beta1vm.VMInsert{CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + }, + }, + }, + }, + testStep{ + modify: func(cr *v1beta1vm.VMCluster) { + cr.Spec.VMInsert.ClusterNativePort = "8035" + cr.Spec.VMSelect.ClusterNativePort = "8036" + }, + verify: func(cr *v1beta1vm.VMCluster) { + var updatedSvc corev1.Service + Expect(k8sClient.Get(ctx, + types.NamespacedName{Namespace: namespace, Name: "vmselect-" + cr.Name}, + &updatedSvc)). + To(Succeed()) + Expect(updatedSvc.Spec.Ports).To(HaveLen(2)) + Expect(updatedSvc.Spec.Ports[1].Port).To(Equal(int32(8036))) + Expect(k8sClient.Get(ctx, + types.NamespacedName{Namespace: namespace, Name: "vminsert-" + cr.Name}, + &updatedSvc)). + To(Succeed()) + Expect(updatedSvc.Spec.Ports).To(HaveLen(2)) + Expect(updatedSvc.Spec.Ports[1].Port).To(Equal(int32(8035))) + }, + }, + ), + Entry("by deleting select component", "select-delete", + &v1beta1vm.VMCluster{ + Spec: v1beta1vm.VMClusterSpec{ + RetentionPeriod: "1", + VMStorage: &v1beta1vm.VMStorage{ + CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), }, - VMInsert: &v1beta1vm.VMInsert{ - CommonDefaultableParams: v1beta1vm.CommonDefaultableParams{ - // UseStrictSecurity: ptr.To(true), - UseDefaultResources: ptr.To(false), - }, - CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ - ReplicaCount: ptr.To[int32](1), - }, + }, + VMSelect: &v1beta1vm.VMSelect{ + CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), }, }, + VMInsert: &v1beta1vm.VMInsert{CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + }, + }, }, - ), - ) - }) - Context("update", func() { - AfterEach(func() { - Expect(k8sClient.Delete(ctx, &v1beta1vm.VMCluster{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace, - Name: namespacedName.Name, + }, + testStep{ + setup: func(cr *v1beta1vm.VMCluster) { + Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "vmselect-" + cr.Name}, &appsv1.StatefulSet{})).To(Succeed()) + Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "vmselect-" + cr.Name}, &corev1.Service{})).To(Succeed()) + Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "vmselect-" + cr.Name}, &v1beta1vm.VMServiceScrape{})).To(Succeed()) }, - })).To(Succeed()) - Eventually(func() error { - return k8sClient.Get(context.Background(), types.NamespacedName{ - Name: namespacedName.Name, - Namespace: namespace, - }, &v1beta1vm.VMCluster{}) + modify: func(cr *v1beta1vm.VMCluster) { + cr.Spec.VMSelect = nil + }, + verify: func(cr *v1beta1vm.VMCluster) { + Eventually(func() error { + return k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "vmselect-" + cr.Name}, &appsv1.StatefulSet{}) + }, eventualDeletionTimeout).Should(MatchError(errors.IsNotFound, "IsNotFound")) + Eventually(func() error { + return k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "vmselect-" + cr.Name}, &corev1.Service{}) + }, eventualDeletionTimeout).Should(MatchError(errors.IsNotFound, "IsNotFound")) + Eventually(func() error { + return k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "vmselect-" + cr.Name}, &v1beta1vm.VMServiceScrape{}) + }, eventualDeletionTimeout).Should(MatchError(errors.IsNotFound, "IsNotFound")) - }, eventualDeletionTimeout).Should(MatchError(errors.IsNotFound, "want not found error")) - }) - clusterForUpdate := &v1beta1vm.VMCluster{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace, + }, }, - Spec: v1beta1vm.VMClusterSpec{ - RetentionPeriod: "1", - VMStorage: &v1beta1vm.VMStorage{ - CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + testStep{ + modify: func(cr *v1beta1vm.VMCluster) { + cr.Spec.VMSelect = &v1beta1vm.VMSelect{ + CommonDefaultableParams: v1beta1vm.CommonDefaultableParams{ + UseDefaultResources: ptr.To(false), + }, + CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + }, + } + }, + verify: func(cr *v1beta1vm.VMCluster) { + Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "vmselect-" + cr.Name}, &appsv1.StatefulSet{})).To(Succeed()) + Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "vmselect-" + cr.Name}, &corev1.Service{})).To(Succeed()) + Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "vmselect-" + cr.Name}, &v1beta1vm.VMServiceScrape{})).To(Succeed()) + }, + }, + ), + Entry("by deleting storage and insert components", "storage-insert-delete", + &v1beta1vm.VMCluster{ + Spec: v1beta1vm.VMClusterSpec{ + RetentionPeriod: "1", + VMStorage: &v1beta1vm.VMStorage{ + CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + }, + }, + VMSelect: &v1beta1vm.VMSelect{ + CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + }, + }, + VMInsert: &v1beta1vm.VMInsert{CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ ReplicaCount: ptr.To[int32](1), }, + }, }, - VMSelect: &v1beta1vm.VMSelect{ - CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ - ReplicaCount: ptr.To[int32](1), + }, + testStep{ + setup: func(cr *v1beta1vm.VMCluster) { + Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "vmstorage-" + cr.Name}, &appsv1.StatefulSet{})).To(Succeed()) + Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "vmstorage-" + cr.Name}, &corev1.Service{})).To(Succeed()) + Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "vmstorage-" + cr.Name}, &v1beta1vm.VMServiceScrape{})).To(Succeed()) + Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "vminsert-" + cr.Name}, &appsv1.Deployment{})).To(Succeed()) + Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "vminsert-" + cr.Name}, &corev1.Service{})).To(Succeed()) + Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "vminsert-" + cr.Name}, &v1beta1vm.VMServiceScrape{})).To(Succeed()) + }, + modify: func(cr *v1beta1vm.VMCluster) { + cr.Spec.VMStorage = nil + cr.Spec.VMInsert = nil + cr.Spec.VMSelect.ExtraArgs = map[string]string{ + "storageNode": "http://non-exist-vmstorage:8402", + } + }, + verify: func(cr *v1beta1vm.VMCluster) { + Eventually(func() error { + return k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "vmstorage-" + cr.Name}, &appsv1.StatefulSet{}) + }, eventualDeletionTimeout).Should(MatchError(errors.IsNotFound, "IsNotFound")) + Eventually(func() error { + return k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "vmstorage-" + cr.Name}, &corev1.Service{}) + }, eventualDeletionTimeout).Should(MatchError(errors.IsNotFound, "IsNotFound")) + Eventually(func() error { + return k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "vmstorage-" + cr.Name}, &v1beta1vm.VMServiceScrape{}) + }, eventualDeletionTimeout).Should(MatchError(errors.IsNotFound, "IsNotFound")) + Eventually(func() error { + return k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "vminsert-" + cr.Name}, &appsv1.Deployment{}) + }, eventualDeletionTimeout).Should(MatchError(errors.IsNotFound, "IsNotFound")) + + }, + }, + testStep{ + modify: func(cr *v1beta1vm.VMCluster) { + cr.Spec.VMStorage = &v1beta1vm.VMStorage{ + CommonDefaultableParams: v1beta1vm.CommonDefaultableParams{ + UseDefaultResources: ptr.To(false), + }, + CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + }, + } + cr.Spec.VMInsert = &v1beta1vm.VMInsert{ + CommonDefaultableParams: v1beta1vm.CommonDefaultableParams{ + UseDefaultResources: ptr.To(false), + }, + CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + }, + } + }, + verify: func(cr *v1beta1vm.VMCluster) { + Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "vmstorage-" + cr.Name}, &appsv1.StatefulSet{})).To(Succeed()) + Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "vmstorage-" + cr.Name}, &corev1.Service{})).To(Succeed()) + Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "vmstorage-" + cr.Name}, &v1beta1vm.VMServiceScrape{})).To(Succeed()) + Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "vminsert-" + cr.Name}, &appsv1.Deployment{})).To(Succeed()) + Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "vminsert-" + cr.Name}, &corev1.Service{})).To(Succeed()) + Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "vminsert-" + cr.Name}, &v1beta1vm.VMServiceScrape{})).To(Succeed()) + }, + }, + ), + Entry("by deleting deleting and renaming additional services", "select-additional-svc", + &v1beta1vm.VMCluster{ + Spec: v1beta1vm.VMClusterSpec{ + RetentionPeriod: "1", + VMStorage: &v1beta1vm.VMStorage{ + CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + }, + ServiceSpec: &v1beta1vm.AdditionalServiceSpec{ + EmbeddedObjectMetadata: v1beta1vm.EmbeddedObjectMetadata{ + Name: "my-service-name", + }, + Spec: corev1.ServiceSpec{ + Type: corev1.ServiceTypeClusterIP, + Ports: []corev1.ServicePort{ + { + TargetPort: intstr.FromInt(8431), + Name: "web-port", + Port: 8435, + }, + }, + }, + }, + }, + VMSelect: &v1beta1vm.VMSelect{ + CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ + ReplicaCount: ptr.To[int32](1), + }, + ServiceSpec: &v1beta1vm.AdditionalServiceSpec{ + Spec: corev1.ServiceSpec{ + Type: corev1.ServiceTypeClusterIP, + Ports: []corev1.ServicePort{ + { + TargetPort: intstr.FromInt(8431), + Name: "web-port", + Port: 8435, + }, + }, + }, + }, }, }, - VMInsert: &v1beta1vm.VMInsert{CommonApplicationDeploymentParams: v1beta1vm.CommonApplicationDeploymentParams{ - ReplicaCount: ptr.To[int32](1), + }, + testStep{ + setup: func(cr *v1beta1vm.VMCluster) { + Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "vmselect-" + cr.Name + "-additional-service"}, &corev1.Service{})).To(Succeed()) + Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "my-service-name"}, &corev1.Service{})).To(Succeed()) + }, + modify: func(cr *v1beta1vm.VMCluster) { + cr.Spec.VMSelect.ServiceSpec = nil + cr.Spec.VMStorage.ServiceSpec.Name = "" }, + verify: func(cr *v1beta1vm.VMCluster) { + Eventually(func() error { + return k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "vmselect-" + cr.Name + "-additional-service"}, &corev1.Service{}) + }, eventualDeletionTimeout).Should(MatchError(errors.IsNotFound, "IsNotFound")) + Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "vmstorage-" + cr.Name + "-additional-service"}, &corev1.Service{})).To(Succeed()) + Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "my-service-name"}, &corev1.Service{})).To(MatchError(errors.IsNotFound, "IsNotFound")) }, }, - } - DescribeTable("should update exist cluster", - func(name string, modify func(*v1beta1vm.VMCluster), verify func(*v1beta1vm.VMCluster)) { - namespacedName.Name = name - existCluster := clusterForUpdate.DeepCopy() - existCluster.Name = name - ctx = context.Background() - Expect(k8sClient.Create(ctx, existCluster)).To(Succeed()) - Eventually(func() error { - return expectObjectStatusOperational(ctx, k8sClient, existCluster, namespacedName) - }, eventualStatefulsetAppReadyTimeout). - Should(Succeed()) - Expect(expectPodCount(k8sClient, 1, namespace, existCluster.VMStorageSelectorLabels())).To(BeEmpty()) - Expect(expectPodCount(k8sClient, 1, namespace, existCluster.VMSelectSelectorLabels())).To(BeEmpty()) - Expect(expectPodCount(k8sClient, 1, namespace, existCluster.VMInsertSelectorLabels())).To(BeEmpty()) - - // update and wait ready - Eventually(func() error { - var toUpdate v1beta1.VMCluster - if err := k8sClient.Get(ctx, namespacedName, &toUpdate); err != nil { - return err + testStep{ + modify: func(cr *v1beta1vm.VMCluster) { + cr.Spec.VMStorage.ServiceSpec.UseAsDefault = true + cr.Spec.VMSelect.ServiceSpec = &v1beta1vm.AdditionalServiceSpec{ + EmbeddedObjectMetadata: v1beta1vm.EmbeddedObjectMetadata{ + Name: "my-service-name-v2", + }, + Spec: corev1.ServiceSpec{ + Type: corev1.ServiceTypeClusterIP, + Ports: []corev1.ServicePort{ + { + TargetPort: intstr.FromInt(8431), + Name: "web-port", + Port: 8436, + }, + }, + }, } - modify(&toUpdate) - return k8sClient.Update(ctx, &toUpdate) - }, eventualExpandingTimeout).Should(Succeed()) - Eventually(func() error { - return expectObjectStatusExpanding(ctx, k8sClient, existCluster, namespacedName) - }, eventualStatefulsetAppReadyTimeout). - Should(Succeed()) - Eventually(func() error { - return expectObjectStatusOperational(ctx, k8sClient, existCluster, namespacedName) - }, eventualStatefulsetAppReadyTimeout). - Should(Succeed()) - // verify results - verify(existCluster) + }, + verify: func(cr *v1beta1vm.VMCluster) { + Eventually(func() error { + return k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "vmstorage-" + cr.Name + "-additional-service"}, &corev1.Service{}) + }, eventualDeletionTimeout).Should(MatchError(errors.IsNotFound, "IsNotFound")) + Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "my-service-name-v2"}, &corev1.Service{})).To(Succeed()) + var stSvc corev1.Service + Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "vmstorage-" + cr.Name}, &stSvc)).To(Succeed()) + Expect(stSvc.Spec.Ports).To(HaveLen(4)) + }, }, - Entry("update storage and select replicas to 2", "storage-select-r-2", func(cr *v1beta1vm.VMCluster) { - cr.Spec.VMStorage.ReplicaCount = ptr.To[int32](2) - cr.Spec.VMSelect.ReplicaCount = ptr.To[int32](2) - }, func(cr *v1beta1vm.VMCluster) { - Expect(expectPodCount(k8sClient, 2, namespace, cr.VMStorageSelectorLabels())).To(BeEmpty()) - Expect(expectPodCount(k8sClient, 2, namespace, cr.VMSelectSelectorLabels())).To(BeEmpty()) - - }), - Entry("update storage and insert replicas to 2", "storage-insert-r-2", func(cr *v1beta1vm.VMCluster) { - cr.Spec.VMStorage.ReplicaCount = ptr.To[int32](2) - cr.Spec.VMInsert.ReplicaCount = ptr.To[int32](2) - }, func(cr *v1beta1vm.VMCluster) { - Expect(expectPodCount(k8sClient, 2, namespace, cr.VMStorageSelectorLabels())).To(BeEmpty()) - Eventually(func() string { - return expectPodCount(k8sClient, 2, namespace, cr.VMInsertSelectorLabels()) - }, eventualDeploymentPodTimeout).Should(BeEmpty()) - }), - Entry("update storage revisionHistoryLimit to 2", "storage-revision-2", func(cr *v1beta1vm.VMCluster) { - cr.Spec.VMStorage.RevisionHistoryLimitCount = ptr.To[int32](2) - }, func(cr *v1beta1vm.VMCluster) { - var updatedCluster v1beta1vm.VMCluster - Expect(k8sClient.Get(ctx, namespacedName, &updatedCluster)).To(Succeed()) - Expect(*updatedCluster.Spec.VMStorage.RevisionHistoryLimitCount).To(Equal(int32(2))) - }), - Entry("add clusterNative ports", "storage-native-r-2", func(cr *v1beta1vm.VMCluster) { - cr.Spec.VMInsert.ClusterNativePort = "8035" - cr.Spec.VMSelect.ClusterNativePort = "8036" - }, func(cr *v1beta1vm.VMCluster) { - var updatedSvc corev1.Service - Expect(k8sClient.Get(ctx, - types.NamespacedName{Namespace: namespace, Name: "vmselect-" + cr.Name}, - &updatedSvc)). - To(Succeed()) - Expect(updatedSvc.Spec.Ports).To(HaveLen(2)) - Expect(updatedSvc.Spec.Ports[1].Port).To(Equal(int32(8036))) - Expect(k8sClient.Get(ctx, - types.NamespacedName{Namespace: namespace, Name: "vminsert-" + cr.Name}, - &updatedSvc)). - To(Succeed()) - Expect(updatedSvc.Spec.Ports).To(HaveLen(2)) - Expect(updatedSvc.Spec.Ports[1].Port).To(Equal(int32(8035))) - - }), - ) - }) + ), + ) }) })