From 031aea7d5eddeefba7acae07aa4e07b796aec39a Mon Sep 17 00:00:00 2001 From: Natalia Marukovich Date: Fri, 4 Jul 2025 16:04:39 +0200 Subject: [PATCH 1/5] K8SPG-777 set crVersion --- .../pgv2.percona.com_perconapgclusters.yaml | 3 +++ .../pgv2.percona.com_perconapgclusters.yaml | 3 +++ deploy/bundle.yaml | 3 +++ deploy/crd.yaml | 3 +++ deploy/cw-bundle.yaml | 3 +++ percona/controller/pgcluster/controller.go | 22 +++++++++++++++++++ .../v2/perconapgcluster_types.go | 4 ++++ 7 files changed, 41 insertions(+) diff --git a/build/crd/percona/generated/pgv2.percona.com_perconapgclusters.yaml b/build/crd/percona/generated/pgv2.percona.com_perconapgclusters.yaml index 050e83ca4..ba6fc863d 100644 --- a/build/crd/percona/generated/pgv2.percona.com_perconapgclusters.yaml +++ b/build/crd/percona/generated/pgv2.percona.com_perconapgclusters.yaml @@ -5237,6 +5237,9 @@ spec: Version of the operator. Update this to new version after operator upgrade to apply changes to Kubernetes objects. Default is the latest version. + enum: + - 2.7.0 + pattern: ^$|^\d+\.\d+\.\d+$ type: string dataSource: description: Specifies a data source for bootstrapping the PostgreSQL diff --git a/config/crd/bases/pgv2.percona.com_perconapgclusters.yaml b/config/crd/bases/pgv2.percona.com_perconapgclusters.yaml index 871e89b05..d2295a6a5 100644 --- a/config/crd/bases/pgv2.percona.com_perconapgclusters.yaml +++ b/config/crd/bases/pgv2.percona.com_perconapgclusters.yaml @@ -5644,6 +5644,9 @@ spec: Version of the operator. Update this to new version after operator upgrade to apply changes to Kubernetes objects. Default is the latest version. + enum: + - 2.7.0 + pattern: ^$|^\d+\.\d+\.\d+$ type: string dataSource: description: Specifies a data source for bootstrapping the PostgreSQL diff --git a/deploy/bundle.yaml b/deploy/bundle.yaml index f2531bfc3..e9c1292e7 100644 --- a/deploy/bundle.yaml +++ b/deploy/bundle.yaml @@ -5941,6 +5941,9 @@ spec: Version of the operator. Update this to new version after operator upgrade to apply changes to Kubernetes objects. Default is the latest version. + enum: + - 2.7.0 + pattern: ^$|^\d+\.\d+\.\d+$ type: string dataSource: description: Specifies a data source for bootstrapping the PostgreSQL diff --git a/deploy/crd.yaml b/deploy/crd.yaml index ed6416046..196be4b30 100644 --- a/deploy/crd.yaml +++ b/deploy/crd.yaml @@ -5941,6 +5941,9 @@ spec: Version of the operator. Update this to new version after operator upgrade to apply changes to Kubernetes objects. Default is the latest version. + enum: + - 2.7.0 + pattern: ^$|^\d+\.\d+\.\d+$ type: string dataSource: description: Specifies a data source for bootstrapping the PostgreSQL diff --git a/deploy/cw-bundle.yaml b/deploy/cw-bundle.yaml index be92efa6b..336e64868 100644 --- a/deploy/cw-bundle.yaml +++ b/deploy/cw-bundle.yaml @@ -5941,6 +5941,9 @@ spec: Version of the operator. Update this to new version after operator upgrade to apply changes to Kubernetes objects. Default is the latest version. + enum: + - 2.7.0 + pattern: ^$|^\d+\.\d+\.\d+$ type: string dataSource: description: Specifies a data source for bootstrapping the PostgreSQL diff --git a/percona/controller/pgcluster/controller.go b/percona/controller/pgcluster/controller.go index f3e0d0392..4c6637ba0 100644 --- a/percona/controller/pgcluster/controller.go +++ b/percona/controller/pgcluster/controller.go @@ -7,6 +7,7 @@ import ( "fmt" "io" "reflect" + logf "sigs.k8s.io/controller-runtime/pkg/log" "slices" "strings" "time" @@ -49,6 +50,7 @@ import ( "github.com/percona/percona-postgresql-operator/percona/pmm" perconaPG "github.com/percona/percona-postgresql-operator/percona/postgres" "github.com/percona/percona-postgresql-operator/percona/utils/registry" + "github.com/percona/percona-postgresql-operator/percona/version" "github.com/percona/percona-postgresql-operator/percona/watcher" v2 "github.com/percona/percona-postgresql-operator/pkg/apis/pgv2.percona.com/v2" "github.com/percona/percona-postgresql-operator/pkg/apis/postgres-operator.crunchydata.com/v1beta1" @@ -201,6 +203,9 @@ func (r *PGClusterReconciler) Reconcile(ctx context.Context, request reconcile.R return ctrl.Result{}, errors.Wrap(err, "get PerconaPGCluster") } + if err := r.setCRVersion(ctx, cr); err != nil { + return reconcile.Result{}, errors.Wrap(err, "set CR version") + } cr.Default() if cr.Spec.OpenShift == nil { @@ -964,3 +969,20 @@ func (r *PGClusterReconciler) ensureFinalizers(ctx context.Context, cr *v2.Perco return nil } + +func (r *PGClusterReconciler) setCRVersion(ctx context.Context, cr *v2.PerconaPGCluster) error { + if len(cr.Spec.CRVersion) > 0 { + return nil + } + + orig := cr.DeepCopy() + cr.Spec.CRVersion = version.Version() + + if err := r.Client.Patch(ctx, cr, client.MergeFrom(orig)); err != nil { + return errors.Wrap(err, "patch CR") + } + + logf.FromContext(ctx).Info("Set CR version", "version", cr.Spec.CRVersion) + + return nil +} diff --git a/pkg/apis/pgv2.percona.com/v2/perconapgcluster_types.go b/pkg/apis/pgv2.percona.com/v2/perconapgcluster_types.go index a63503c4f..5cea5936d 100644 --- a/pkg/apis/pgv2.percona.com/v2/perconapgcluster_types.go +++ b/pkg/apis/pgv2.percona.com/v2/perconapgcluster_types.go @@ -2,6 +2,7 @@ package v2 import ( "context" + "fmt" gover "github.com/hashicorp/go-version" corev1 "k8s.io/api/core/v1" @@ -52,6 +53,8 @@ type PerconaPGClusterSpec struct { // upgrade to apply changes to Kubernetes objects. Default is the latest // version. // +optional + // +kubebuilder:validation:Pattern=`^$|^\d+\.\d+\.\d+$` + // +kubebuilder:validation:Enum="2.7.0" CRVersion string `json:"crVersion,omitempty"` InitContainer *crunchyv1beta1.InitContainerSpec `json:"initContainer,omitempty"` @@ -177,6 +180,7 @@ type PerconaPGClusterSpec struct { func (cr *PerconaPGCluster) Default() { if len(cr.Spec.CRVersion) == 0 { cr.Spec.CRVersion = version.Version() + fmt.Printf("Default CRVersion set to: %s\n", cr.Spec.CRVersion) } for i := range cr.Spec.InstanceSets { From 299de12320d7293932869c0b560187e9024472cb Mon Sep 17 00:00:00 2001 From: Natalia Marukovich Date: Fri, 4 Jul 2025 16:06:36 +0200 Subject: [PATCH 2/5] delete log --- pkg/apis/pgv2.percona.com/v2/perconapgcluster_types.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/pkg/apis/pgv2.percona.com/v2/perconapgcluster_types.go b/pkg/apis/pgv2.percona.com/v2/perconapgcluster_types.go index 5cea5936d..0bd72d4fe 100644 --- a/pkg/apis/pgv2.percona.com/v2/perconapgcluster_types.go +++ b/pkg/apis/pgv2.percona.com/v2/perconapgcluster_types.go @@ -2,8 +2,6 @@ package v2 import ( "context" - "fmt" - gover "github.com/hashicorp/go-version" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -180,7 +178,6 @@ type PerconaPGClusterSpec struct { func (cr *PerconaPGCluster) Default() { if len(cr.Spec.CRVersion) == 0 { cr.Spec.CRVersion = version.Version() - fmt.Printf("Default CRVersion set to: %s\n", cr.Spec.CRVersion) } for i := range cr.Spec.InstanceSets { From 0e53193caa63e47dc958d7fa9b206e76625e495f Mon Sep 17 00:00:00 2001 From: Natalia Marukovich Date: Fri, 4 Jul 2025 16:56:06 +0200 Subject: [PATCH 3/5] fix import --- pkg/apis/pgv2.percona.com/v2/perconapgcluster_types.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/apis/pgv2.percona.com/v2/perconapgcluster_types.go b/pkg/apis/pgv2.percona.com/v2/perconapgcluster_types.go index 0bd72d4fe..f9b6b651d 100644 --- a/pkg/apis/pgv2.percona.com/v2/perconapgcluster_types.go +++ b/pkg/apis/pgv2.percona.com/v2/perconapgcluster_types.go @@ -2,6 +2,7 @@ package v2 import ( "context" + gover "github.com/hashicorp/go-version" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" From f770dbfea985b5aa1603a474b185d98927e974d6 Mon Sep 17 00:00:00 2001 From: Natalia Marukovich Date: Mon, 7 Jul 2025 13:42:43 +0200 Subject: [PATCH 4/5] add test --- .../controller/pgcluster/controller_test.go | 77 ++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/percona/controller/pgcluster/controller_test.go b/percona/controller/pgcluster/controller_test.go index 8ba1ee9ef..86b8a35ab 100644 --- a/percona/controller/pgcluster/controller_test.go +++ b/percona/controller/pgcluster/controller_test.go @@ -27,6 +27,7 @@ import ( "github.com/percona/percona-postgresql-operator/internal/feature" "github.com/percona/percona-postgresql-operator/internal/naming" pNaming "github.com/percona/percona-postgresql-operator/percona/naming" + "github.com/percona/percona-postgresql-operator/percona/version" v2 "github.com/percona/percona-postgresql-operator/pkg/apis/pgv2.percona.com/v2" "github.com/percona/percona-postgresql-operator/pkg/apis/postgres-operator.crunchydata.com/v1beta1" ) @@ -686,7 +687,7 @@ var _ = Describe("Version labels", Ordered, func() { }) cr, err := readDefaultCR(crName, ns) - It("should read defautl cr.yaml", func() { + It("should read default cr.yaml", func() { Expect(err).NotTo(HaveOccurred()) }) @@ -2265,3 +2266,77 @@ var _ = Describe("Init Container", Ordered, func() { }) }) }) + +var _ = Describe("CR Version Management", Ordered, func() { + ctx := context.Background() + const crName = "cr-version" + const ns = crName + + namespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: crName, + Namespace: ns, + }, + } + + BeforeAll(func() { + By("Creating the Namespace for CR version tests") + err := k8sClient.Create(ctx, namespace) + Expect(err).To(Not(HaveOccurred())) + }) + + AfterAll(func() { + By("Deleting the Namespace after CR version tests") + _ = k8sClient.Delete(ctx, namespace) + }) + + Context("setCRVersion logic", Ordered, func() { + When("the CRVersion is already set", func() { + It("should not change the CRVersion", func() { + cr, err := readDefaultCR("cr-version-1", ns) + Expect(err).NotTo(HaveOccurred()) + + cr.Spec.CRVersion = "2.7.0" + Expect(k8sClient.Create(ctx, cr)).Should(Succeed()) + + reconciler := &PGClusterReconciler{Client: k8sClient} + err = reconciler.setCRVersion(ctx, cr) + Expect(err).NotTo(HaveOccurred()) + Expect(cr.Spec.CRVersion).To(Equal("2.7.0")) + }) + }) + + When("the CRVersion is empty", func() { + It("should set CRVersion and patch the resource", func() { + cr, err := readDefaultCR("cr-version-2", ns) + Expect(err).NotTo(HaveOccurred()) + + cr.Spec.CRVersion = "" + Expect(k8sClient.Create(ctx, cr)).Should(Succeed()) + + reconciler := &PGClusterReconciler{Client: k8sClient} + err = reconciler.setCRVersion(ctx, cr) + Expect(err).NotTo(HaveOccurred()) + + // Fetch the CR again to verify the patch was applied in the cluster + updated := &v2.PerconaPGCluster{} + Expect(k8sClient.Get(ctx, types.NamespacedName{Name: cr.Name, Namespace: cr.Namespace}, updated)).Should(Succeed()) + Expect(updated.Spec.CRVersion).To(Equal(version.Version())) + }) + }) + + When("the patch operation fails", func() { + It("should return an error", func() { + cr, err := readDefaultCR("cr-version-3", ns) + Expect(err).NotTo(HaveOccurred()) + cr.Spec.CRVersion = "" + + // Do NOT create the CR in k8s, so Patch will fail (object does not exist) + reconciler := &PGClusterReconciler{Client: k8sClient} + err = reconciler.setCRVersion(ctx, cr) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("patch CR")) + }) + }) + }) +}) From dc3710cc27f3d4637af4a5275c5208d79ebf6577 Mon Sep 17 00:00:00 2001 From: Natalia Marukovich Date: Wed, 9 Jul 2025 14:35:57 +0200 Subject: [PATCH 5/5] PR fix --- .../percona/generated/pgv2.percona.com_perconapgclusters.yaml | 4 ++-- config/crd/bases/pgv2.percona.com_perconapgclusters.yaml | 4 ++-- deploy/bundle.yaml | 4 ++-- deploy/cr.yaml | 2 +- deploy/crd.yaml | 4 ++-- deploy/cw-bundle.yaml | 4 ++-- pkg/apis/pgv2.percona.com/v2/perconapgcluster_types.go | 3 ++- 7 files changed, 13 insertions(+), 12 deletions(-) diff --git a/build/crd/percona/generated/pgv2.percona.com_perconapgclusters.yaml b/build/crd/percona/generated/pgv2.percona.com_perconapgclusters.yaml index ba6fc863d..dd8e73ee6 100644 --- a/build/crd/percona/generated/pgv2.percona.com_perconapgclusters.yaml +++ b/build/crd/percona/generated/pgv2.percona.com_perconapgclusters.yaml @@ -5237,8 +5237,8 @@ spec: Version of the operator. Update this to new version after operator upgrade to apply changes to Kubernetes objects. Default is the latest version. - enum: - - 2.7.0 + Version is the application version in the format X.Y.Z (e.g., "2.7.0"). + example: 2.7.0 pattern: ^$|^\d+\.\d+\.\d+$ type: string dataSource: diff --git a/config/crd/bases/pgv2.percona.com_perconapgclusters.yaml b/config/crd/bases/pgv2.percona.com_perconapgclusters.yaml index d2295a6a5..7203733a1 100644 --- a/config/crd/bases/pgv2.percona.com_perconapgclusters.yaml +++ b/config/crd/bases/pgv2.percona.com_perconapgclusters.yaml @@ -5644,8 +5644,8 @@ spec: Version of the operator. Update this to new version after operator upgrade to apply changes to Kubernetes objects. Default is the latest version. - enum: - - 2.7.0 + Version is the application version in the format X.Y.Z (e.g., "2.7.0"). + example: 2.7.0 pattern: ^$|^\d+\.\d+\.\d+$ type: string dataSource: diff --git a/deploy/bundle.yaml b/deploy/bundle.yaml index e9c1292e7..c911f270b 100644 --- a/deploy/bundle.yaml +++ b/deploy/bundle.yaml @@ -5941,8 +5941,8 @@ spec: Version of the operator. Update this to new version after operator upgrade to apply changes to Kubernetes objects. Default is the latest version. - enum: - - 2.7.0 + Version is the application version in the format X.Y.Z (e.g., "2.7.0"). + example: 2.7.0 pattern: ^$|^\d+\.\d+\.\d+$ type: string dataSource: diff --git a/deploy/cr.yaml b/deploy/cr.yaml index a229d0d68..09bcb6a2a 100644 --- a/deploy/cr.yaml +++ b/deploy/cr.yaml @@ -9,7 +9,7 @@ metadata: # - percona.com/delete-ssl # - percona.com/delete-backups spec: - crVersion: 2.7.0 + crVersion: "2.7.0" # initContainer: # image: perconalab/percona-postgresql-operator:main # resources: diff --git a/deploy/crd.yaml b/deploy/crd.yaml index 196be4b30..fc0b87263 100644 --- a/deploy/crd.yaml +++ b/deploy/crd.yaml @@ -5941,8 +5941,8 @@ spec: Version of the operator. Update this to new version after operator upgrade to apply changes to Kubernetes objects. Default is the latest version. - enum: - - 2.7.0 + Version is the application version in the format X.Y.Z (e.g., "2.7.0"). + example: 2.7.0 pattern: ^$|^\d+\.\d+\.\d+$ type: string dataSource: diff --git a/deploy/cw-bundle.yaml b/deploy/cw-bundle.yaml index 336e64868..126453ee5 100644 --- a/deploy/cw-bundle.yaml +++ b/deploy/cw-bundle.yaml @@ -5941,8 +5941,8 @@ spec: Version of the operator. Update this to new version after operator upgrade to apply changes to Kubernetes objects. Default is the latest version. - enum: - - 2.7.0 + Version is the application version in the format X.Y.Z (e.g., "2.7.0"). + example: 2.7.0 pattern: ^$|^\d+\.\d+\.\d+$ type: string dataSource: diff --git a/pkg/apis/pgv2.percona.com/v2/perconapgcluster_types.go b/pkg/apis/pgv2.percona.com/v2/perconapgcluster_types.go index f9b6b651d..48a474573 100644 --- a/pkg/apis/pgv2.percona.com/v2/perconapgcluster_types.go +++ b/pkg/apis/pgv2.percona.com/v2/perconapgcluster_types.go @@ -52,8 +52,9 @@ type PerconaPGClusterSpec struct { // upgrade to apply changes to Kubernetes objects. Default is the latest // version. // +optional + // Version is the application version in the format X.Y.Z (e.g., "2.7.0"). // +kubebuilder:validation:Pattern=`^$|^\d+\.\d+\.\d+$` - // +kubebuilder:validation:Enum="2.7.0" + // +kubebuilder:example="2.7.0" CRVersion string `json:"crVersion,omitempty"` InitContainer *crunchyv1beta1.InitContainerSpec `json:"initContainer,omitempty"`