Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21143,6 +21143,10 @@ spec:
version:
type: string
type: object
patroniVersion:
description: 'Deprecated: Use Patroni instead. This field will be
removed in a future release.'
type: string
pgbackrest:
description: Status information for pgBackRest
properties:
Expand Down
4 changes: 4 additions & 0 deletions config/crd/bases/pgv2.percona.com_perconapgclusters.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21548,6 +21548,10 @@ spec:
version:
type: string
type: object
patroniVersion:
description: 'Deprecated: Use Patroni instead. This field will be
removed in a future release.'
type: string
pgbackrest:
description: Status information for pgBackRest
properties:
Expand Down
4 changes: 4 additions & 0 deletions deploy/bundle.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21845,6 +21845,10 @@ spec:
version:
type: string
type: object
patroniVersion:
description: 'Deprecated: Use Patroni instead. This field will be
removed in a future release.'
type: string
pgbackrest:
description: Status information for pgBackRest
properties:
Expand Down
4 changes: 4 additions & 0 deletions deploy/crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21845,6 +21845,10 @@ spec:
version:
type: string
type: object
patroniVersion:
description: 'Deprecated: Use Patroni instead. This field will be
removed in a future release.'
type: string
pgbackrest:
description: Status information for pgBackRest
properties:
Expand Down
4 changes: 4 additions & 0 deletions deploy/cw-bundle.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21845,6 +21845,10 @@ spec:
version:
type: string
type: object
patroniVersion:
description: 'Deprecated: Use Patroni instead. This field will be
removed in a future release.'
type: string
pgbackrest:
description: Status information for pgBackRest
properties:
Expand Down
105 changes: 73 additions & 32 deletions percona/controller/pgcluster/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -374,8 +374,6 @@ func (r *PGClusterReconciler) reconcilePatroniVersionCheck(ctx context.Context,
}

if patroniVersion, ok := cr.Annotations[pNaming.AnnotationCustomPatroniVersion]; ok {
cr.Annotations[pNaming.AnnotationPatroniVersion] = patroniVersion

patroniVersionUpdateFunc := func() error {
cluster := &v2.PerconaPGCluster{}
if err := r.Client.Get(ctx, types.NamespacedName{
Expand All @@ -388,10 +386,17 @@ func (r *PGClusterReconciler) reconcilePatroniVersionCheck(ctx context.Context,
orig := cluster.DeepCopy()

cluster.Status.Patroni.Version = patroniVersion
cluster.Status.PatroniVersion = patroniVersion

if err := r.Client.Status().Patch(ctx, cluster.DeepCopy(), client.MergeFrom(orig)); err != nil {
return errors.Wrap(err, "failed to patch patroni version")
}

err := r.patchPatroniVersionAnnotation(ctx, cr, patroniVersion)
if err != nil {
return errors.Wrap(err, "failed to patch patroni version annotation")
}

return nil
}

Expand All @@ -403,40 +408,29 @@ func (r *PGClusterReconciler) reconcilePatroniVersionCheck(ctx context.Context,
return nil
}

getImageIDFromPod := func(pod *corev1.Pod, containerName string) string {
idx := slices.IndexFunc(pod.Status.ContainerStatuses, func(s corev1.ContainerStatus) bool {
return s.Name == containerName
})
if idx == -1 {
return ""
}
return pod.Status.ContainerStatuses[idx].ImageID
}

pods := new(corev1.PodList)
instances, err := naming.AsSelector(naming.ClusterInstances(cr.Name))
imageIDs, err := r.instanceImageIDs(ctx, cr)
if err != nil {
return err
}
if err = r.Client.List(ctx, pods, client.InNamespace(cr.Namespace), client.MatchingLabelsSelector{Selector: instances}); err != nil {
return err
}

// Collecting all image IDs from instance pods. Under normal conditions, this slice will contain a single image ID, as all pods typically use the same image.
// During an image update, it may contain multiple different image IDs as the update progresses.
imageIDs := []string{}
for _, pod := range pods.Items {
imageID := getImageIDFromPod(&pod, naming.ContainerDatabase)
if imageID != "" && !slices.Contains(imageIDs, imageID) {
imageIDs = append(imageIDs, imageID)
}
return errors.Wrap(err, "get image IDs")
}

// If the imageIDs slice contains the imageID from the status, we skip checking the Patroni version.
// This ensures that the Patroni version is only checked after all pods have been updated.
if (len(imageIDs) == 0 || slices.Contains(imageIDs, cr.Status.Postgres.ImageID)) && cr.Status.Patroni.Version != "" {
cr.Annotations[pNaming.AnnotationPatroniVersion] = cr.Status.Patroni.Version
return nil
if cr.CompareVersion("2.8.0") >= 0 {
if (len(imageIDs) == 0 || slices.Contains(imageIDs, cr.Status.Postgres.ImageID)) && cr.Status.Patroni.Version != "" {
err = r.patchPatroniVersionAnnotation(ctx, cr, cr.Status.Patroni.Version)
if err != nil {
return errors.Wrap(err, "failed to patch patroni version annotation")
}
return nil
}
} else {
if (len(imageIDs) == 0 || slices.Contains(imageIDs, cr.Status.Postgres.ImageID)) && cr.Status.PatroniVersion != "" {
err = r.patchPatroniVersionAnnotation(ctx, cr, cr.Status.PatroniVersion)
if err != nil {
return errors.Wrap(err, "failed to patch patroni version annotation")
}
return nil
}
}

meta := metav1.ObjectMeta{
Expand Down Expand Up @@ -535,21 +529,68 @@ func (r *PGClusterReconciler) reconcilePatroniVersionCheck(ctx context.Context,
orig := cr.DeepCopy()

cr.Status.Patroni.Version = patroniVersion
cr.Status.PatroniVersion = patroniVersion
cr.Status.Postgres.Version = cr.Spec.PostgresVersion
cr.Status.Postgres.ImageID = getImageIDFromPod(p, pNaming.ContainerPatroniVersionCheck)

if err := r.Client.Status().Patch(ctx, cr.DeepCopy(), client.MergeFrom(orig)); err != nil {
return errors.Wrap(err, "failed to patch patroni version")
}

err = r.patchPatroniVersionAnnotation(ctx, cr, patroniVersion)
if err != nil {
return errors.Wrap(err, "failed to patch patroni version annotation")
}

if err := r.Client.Delete(ctx, p); err != nil {
return errors.Wrap(err, "failed to delete patroni version check pod")
}
cr.Annotations[pNaming.AnnotationPatroniVersion] = patroniVersion

return nil
}

func (r *PGClusterReconciler) patchPatroniVersionAnnotation(ctx context.Context, cr *v2.PerconaPGCluster, patroniVersion string) error {
orig := cr.DeepCopy()
cr.Annotations[pNaming.AnnotationPatroniVersion] = patroniVersion
if err := r.Client.Patch(ctx, cr.DeepCopy(), client.MergeFrom(orig)); err != nil {
return errors.Wrap(err, "failed to patch the pg cluster")
}
return nil
}

func (r *PGClusterReconciler) instanceImageIDs(ctx context.Context, cr *v2.PerconaPGCluster) ([]string, error) {
pods := new(corev1.PodList)
instances, err := naming.AsSelector(naming.ClusterInstances(cr.Name))
if err != nil {
return nil, errors.Wrap(err, "failed to create a selector for instance pods")
}
if err = r.Client.List(ctx, pods, client.InNamespace(cr.Namespace), client.MatchingLabelsSelector{Selector: instances}); err != nil {
return nil, errors.Wrap(err, "failed to list instances")
}

// Collecting all image IDs from instance pods. Under normal conditions, this slice will contain a single image ID, as all pods typically use the same image.
// During an image update, it may contain multiple different image IDs as the update progresses.
var imageIDs []string
for _, pod := range pods.Items {
imageID := getImageIDFromPod(&pod, naming.ContainerDatabase)
if imageID != "" && !slices.Contains(imageIDs, imageID) {
imageIDs = append(imageIDs, imageID)
}
}

return imageIDs, nil
}

func getImageIDFromPod(pod *corev1.Pod, containerName string) string {
idx := slices.IndexFunc(pod.Status.ContainerStatuses, func(s corev1.ContainerStatus) bool {
return s.Name == containerName
})
if idx == -1 {
return ""
}
return pod.Status.ContainerStatuses[idx].ImageID
}

func (r *PGClusterReconciler) reconcileTLS(ctx context.Context, cr *v2.PerconaPGCluster) error {
if err := r.validateTLS(ctx, cr); err != nil {
return errors.Wrap(err, "validate TLS")
Expand Down
6 changes: 6 additions & 0 deletions percona/controller/pgcluster/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2079,6 +2079,8 @@ var _ = Describe("patroni version check", Ordered, func() {
Expect(k8sClient.Get(ctx, crNamespacedName, updatedCR)).Should(Succeed())

Expect(updatedCR.Status.Patroni.Version).To(Equal("3.2.1"))
Expect(updatedCR.Status.PatroniVersion).To(Equal("3.2.1"))
Expect(updatedCR.Annotations[pNaming.AnnotationPatroniVersion]).To(Equal("3.2.1"))
})
})

Expand Down Expand Up @@ -2134,7 +2136,9 @@ var _ = Describe("patroni version check", Ordered, func() {
}

cr2.Status.Patroni.Version = "3.1.0"
cr2.Status.PatroniVersion = "3.1.0"
cr2.Status.Postgres.ImageID = "some-image-id"
cr2.Annotations[pNaming.AnnotationPatroniVersion] = "3.1.0"

status := cr2.Status
Expect(k8sClient.Create(ctx, cr2)).Should(Succeed())
Expand Down Expand Up @@ -2240,6 +2244,8 @@ var _ = Describe("patroni version check", Ordered, func() {
Expect(k8sClient.Get(ctx, crNamespacedName2, updatedCR)).Should(Succeed())

Expect(updatedCR.Status.Patroni.Version).To(Equal("3.1.0"))
Expect(updatedCR.Status.PatroniVersion).To(Equal("3.1.0"))
Expect(updatedCR.Annotations[pNaming.AnnotationPatroniVersion]).To(Equal("3.1.0"))
})
})
})
Expand Down
8 changes: 7 additions & 1 deletion percona/postgres/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,13 @@ func GetPrimaryPod(ctx context.Context, cli client.Client, cr *v2.PerconaPGClust
// K8SPG-648: patroni v4.0.0 deprecated "master" role.
// We should use "primary" instead
role := "primary"
patroniVer, err := gover.NewVersion(cr.Status.Patroni.Version)

patroniVersion := cr.Status.PatroniVersion
if cr.CompareVersion("2.8.0") >= 0 {
patroniVersion = cr.Status.Patroni.Version
}

patroniVer, err := gover.NewVersion(patroniVersion)
if err != nil {
return nil, errors.Wrap(err, "failed to get patroni version")
}
Expand Down
4 changes: 4 additions & 0 deletions percona/watcher/wal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"testing"
"time"

"github.com/percona/percona-postgresql-operator/v2/percona/version"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[goimports-reviser] reported by reviewdog 🐶

Suggested change
"github.com/percona/percona-postgresql-operator/v2/percona/version"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand Down Expand Up @@ -343,6 +344,9 @@ func TestGetLatestCommitTimestamp(t *testing.T) {
Version: "error",
},
},
Spec: pgv2.PerconaPGClusterSpec{
CRVersion: version.Version(),
},
},
expectedErr: errors.New("failed to get patroni version: Malformed version: error: primary pod not found"),
},
Expand Down
5 changes: 5 additions & 0 deletions pkg/apis/pgv2.percona.com/v2/perconapgcluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,11 @@ type PerconaPGClusterStatus struct {
// +operator-sdk:csv:customresourcedefinitions:type=status
State AppState `json:"state"`

// +optional
// +operator-sdk:csv:customresourcedefinitions:type=status
// Deprecated: Use Patroni instead. This field will be removed in a future release.
PatroniVersion string `json:"patroniVersion"`

// +optional
// +operator-sdk:csv:customresourcedefinitions:type=status
Patroni Patroni `json:"patroni,omitempty"`
Expand Down
Loading