From 3a21b29af548a691cd8ad2a66039b3d5b289da4a Mon Sep 17 00:00:00 2001 From: Philipp Eberle Date: Wed, 31 Aug 2022 16:05:04 +0200 Subject: [PATCH 01/23] Check patronic config and only update if neccessary --- controllers/postgres_controller.go | 170 +++++++++++++++++++++++------ 1 file changed, 135 insertions(+), 35 deletions(-) diff --git a/controllers/postgres_controller.go b/controllers/postgres_controller.go index b6df1fce..2ddaf38e 100644 --- a/controllers/postgres_controller.go +++ b/controllers/postgres_controller.go @@ -12,6 +12,7 @@ import ( "encoding/json" "errors" "fmt" + "io/ioutil" "net" "net/http" "net/url" @@ -38,6 +39,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/predicate" + "sigs.k8s.io/controller-runtime/pkg/reconcile" pg "github.com/fi-ts/postgreslet/api/v1" "github.com/fi-ts/postgreslet/pkg/lbmanager" @@ -77,8 +79,18 @@ type PostgresReconciler struct { PatroniRetryTimeout uint32 } +type PatroniStandbyCluster struct { + CreateReplicaMethods []string `json:"create_replica_methods"` + Host string `json:"host"` + Port int `json:"port"` + ApplicationName string `json:"application_name"` +} +type PatroniConfigRequest struct { + StandbyCluster *PatroniStandbyCluster `json:"standby_cluster"` + SynchronousNodesAdditional *string `json:"synchronous_nodes_additional"` +} + // Reconcile is the entry point for postgres reconciliation. -// +kubebuilder:rbac:groups=database.fits.cloud,resources=postgres,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=database.fits.cloud,resources=postgres/status,verbs=get;update;patch // +kubebuilder:rbac:groups=acid.zalan.do,resources=postgresqls,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=acid.zalan.do,resources=postgresqls/status,verbs=get;list;watch @@ -210,18 +222,22 @@ func (r *PostgresReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c return ctrl.Result{}, fmt.Errorf("error while creating standby secrets: %w", err) } - if instance.IsReplicationPrimary() { - // the field is not empty, which means we were either a regular, standalone database that was promoted to leader - // (meaning we are already running) or we are a standby which was promoted to leader (also meaning we are - // already running) - // That means we should be able to call the patroni api already. this is required, as updating the custom - // ressource of a standby db seems to fail (maybe because of the users/databases?)... - // anyway, let's get on with it - if err := r.updatePatroniConfig(ctx, instance); err != nil { - // TODO what to do here? reschedule or ignore? - log.Error(err, "failed to update patroni config via REST call") + // if instance.IsReplicationPrimary() { + // the field is not empty, which means we were either a regular, standalone database that was promoted to leader + // (meaning we are already running) or we are a standby which was promoted to leader (also meaning we are + // already running) + // That means we should be able to call the patroni api already. this is required, as updating the custom + // ressource of a standby db seems to fail (maybe because of the users/databases?)... + // anyway, let's get on with it + if result, err := r.checkAndUpdatePatroniConfig(ctx, instance); err != nil { + // TODO what to do here? reschedule or ignore? + log.Error(err, "failed to update patroni config via REST call") + } else { + if result.Requeue { + return *result, nil } } + // } // create standby egress rule first, so the standby can actually connect to the primary if err := r.createOrUpdateEgressCWNP(ctx, instance); err != nil { @@ -275,11 +291,6 @@ func (r *PostgresReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c return ctrl.Result{}, fmt.Errorf("unable to create or update ingress ClusterwideNetworkPolicy: %w", err) } - // this is the call for standbys - if err := r.updatePatroniConfig(ctx, instance); err != nil { - return requeue, fmt.Errorf("unable to update patroni config: %w", err) - } - r.recorder.Event(instance, "Normal", "Reconciled", "postgres up to date") return ctrl.Result{}, nil } @@ -695,10 +706,21 @@ func (r *PostgresReconciler) ensureStandbySecrets(ctx context.Context, instance } -func (r *PostgresReconciler) updatePatroniConfig(ctx context.Context, instance *pg.Postgres) error { - // Finally, send a POST to to the database with the correct config +func (r *PostgresReconciler) checkAndUpdatePatroniConfig(ctx context.Context, instance *pg.Postgres) (*reconcile.Result, error) { + + // requeue defines in how many seconds a requeue should happen + var requeue = ctrl.Result{ + Requeue: true, + } + + // noRequeue defines in how many seconds a requeue should happen + var noRequeue = ctrl.Result{ + Requeue: false, + } + + // Nothing to do, skip all of it if instance.Spec.PostgresConnection == nil { - return nil + return &noRequeue, nil } r.Log.Info("Sending REST call to Patroni API") @@ -707,7 +729,7 @@ func (r *PostgresReconciler) updatePatroniConfig(ctx context.Context, instance * roleReq, err := labels.NewRequirement(pg.SpiloRoleLabelName, selection.In, []string{pg.SpiloRoleLabelValueMaster, pg.SpiloRoleLabelValueStandbyLeader}) if err != nil { r.Log.Info("could not create requirements for label selector to query pods, requeuing") - return err + return &requeue, err } leaderSelector := labels.NewSelector() leaderSelector = leaderSelector.Add(*roleReq) @@ -718,7 +740,7 @@ func (r *PostgresReconciler) updatePatroniConfig(ctx context.Context, instance * } if err := r.SvcClient.List(ctx, pods, opts...); err != nil { r.Log.Info("could not query pods, requeuing") - return err + return &requeue, err } if len(pods.Items) == 0 { r.Log.Info("no leader pod found, selecting all spilo pods as a last resort (might be ok if it is still creating)") @@ -726,13 +748,61 @@ func (r *PostgresReconciler) updatePatroniConfig(ctx context.Context, instance * err = r.updatePatroniConfigOnAllPods(ctx, instance) if err != nil { r.Log.Info("updating patroni config failed, got one or more errors") - return err + // TODO requeue or continue here? + return &requeue, err } - return nil + // To make sure any updates to the Zalando postgresql manifest are written, we do not requeue in this case + return &noRequeue, nil } podIP := pods.Items[0].Status.PodIP - return r.httpPatchPatroni(ctx, instance, podIP) + // TODO check config. If in wrong state, make the call and return *reconcile.Result + // TODO what happens, when the call fails consistently? We will not be able to change any settings via Postgreslet then, as the createOrUpdateZalandoPostgrseql will not be called... + var resp *PatroniConfigRequest + if resp, err = r.httpGetPatroniConfig(ctx, instance, podIP); err != nil { + // TODO could not fetch config, what to do now? + } + + if resp == nil { + return &requeue, r.httpPatchPatroni(ctx, instance, podIP) + } + + // TODO check config + if instance.IsReplicationPrimary() { + if resp.StandbyCluster != nil { + return &requeue, r.httpPatchPatroni(ctx, instance, podIP) + } + + if resp.SynchronousNodesAdditional != nil { + return &requeue, r.httpPatchPatroni(ctx, instance, podIP) + } + } else { + if resp.StandbyCluster == nil { + return &requeue, r.httpPatchPatroni(ctx, instance, podIP) + } + if resp.StandbyCluster.CreateReplicaMethods == nil { + // TODO check for actual content instead of nil + return &requeue, r.httpPatchPatroni(ctx, instance, podIP) + } + if resp.StandbyCluster.Host != instance.Spec.PostgresConnection.ConnectionIP { + return &requeue, r.httpPatchPatroni(ctx, instance, podIP) + } + if resp.StandbyCluster.Port != int(instance.Spec.PostgresConnection.ConnectionPort) { + return &requeue, r.httpPatchPatroni(ctx, instance, podIP) + } + if resp.StandbyCluster.ApplicationName != instance.ObjectMeta.Name { + return &requeue, r.httpPatchPatroni(ctx, instance, podIP) + } + + if resp.SynchronousNodesAdditional == nil { + return &requeue, r.httpPatchPatroni(ctx, instance, podIP) + } + if resp.SynchronousNodesAdditional != pointer.String(instance.Spec.PostgresConnection.ConnectedPostgresID) { + return &requeue, r.httpPatchPatroni(ctx, instance, podIP) + } + } + + return &noRequeue, nil } func (r *PostgresReconciler) updatePatroniConfigOnAllPods(ctx context.Context, instance *pg.Postgres) error { @@ -777,17 +847,6 @@ func (r *PostgresReconciler) httpPatchPatroni(ctx context.Context, instance *pg. podPort := "8008" path := "config" - type PatroniStandbyCluster struct { - CreateReplicaMethods []string `json:"create_replica_methods"` - Host string `json:"host"` - Port int `json:"port"` - ApplicationName string `json:"application_name"` - } - type PatroniConfigRequest struct { - StandbyCluster *PatroniStandbyCluster `json:"standby_cluster"` - SynchronousNodesAdditional *string `json:"synchronous_nodes_additional"` - } - r.Log.Info("Preparing request") var request PatroniConfigRequest if instance.IsReplicationPrimary() { @@ -840,6 +899,47 @@ func (r *PostgresReconciler) httpPatchPatroni(ctx context.Context, instance *pg. return nil } +func (r *PostgresReconciler) httpGetPatroniConfig(ctx context.Context, instance *pg.Postgres, podIP string) (*PatroniConfigRequest, error) { + if podIP == "" { + return nil, errors.New("podIP must not be empty") + } + + podPort := "8008" + path := "config" + + httpClient := &http.Client{} + url := "http://" + podIP + ":" + podPort + "/" + path + + req, err := http.NewRequest("GET", url, nil) + if err != nil { + r.Log.Error(err, "could not create request") + return nil, err + } + req.Header.Set("Content-Type", "application/json") + + resp, err := httpClient.Do(req) + if err != nil { + r.Log.Error(err, "could not perform request") + return nil, err + } + + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + r.Log.Info("could not read body") + return nil, err + } + var jsonResp PatroniConfigRequest + err = json.Unmarshal(body, &jsonResp) + if err != nil { + r.Log.Info("could not parse config") + return nil, err + } + + return &jsonResp, err +} + func (r *PostgresReconciler) getBackupConfig(ctx context.Context, ns, name string) (*pg.BackupConfig, error) { // fetch secret backupSecret := &corev1.Secret{} From 4e7a9997b9f0ff2063d0c5527e565ba7586ebd55 Mon Sep 17 00:00:00 2001 From: Philipp Eberle Date: Wed, 31 Aug 2022 17:20:25 +0200 Subject: [PATCH 02/23] Refactoring --- controllers/postgres_controller.go | 146 ++++++++++++++--------------- 1 file changed, 69 insertions(+), 77 deletions(-) diff --git a/controllers/postgres_controller.go b/controllers/postgres_controller.go index 2ddaf38e..ae394288 100644 --- a/controllers/postgres_controller.go +++ b/controllers/postgres_controller.go @@ -39,7 +39,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/predicate" - "sigs.k8s.io/controller-runtime/pkg/reconcile" pg "github.com/fi-ts/postgreslet/api/v1" "github.com/fi-ts/postgreslet/pkg/lbmanager" @@ -222,22 +221,10 @@ func (r *PostgresReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c return ctrl.Result{}, fmt.Errorf("error while creating standby secrets: %w", err) } - // if instance.IsReplicationPrimary() { - // the field is not empty, which means we were either a regular, standalone database that was promoted to leader - // (meaning we are already running) or we are a standby which was promoted to leader (also meaning we are - // already running) - // That means we should be able to call the patroni api already. this is required, as updating the custom - // ressource of a standby db seems to fail (maybe because of the users/databases?)... - // anyway, let's get on with it - if result, err := r.checkAndUpdatePatroniConfig(ctx, instance); err != nil { - // TODO what to do here? reschedule or ignore? - log.Error(err, "failed to update patroni config via REST call") - } else { - if result.Requeue { - return *result, nil - } + immediateRequeue, patroniErr := r.checkAndUpdatePatroniConfig(ctx, instance) + if immediateRequeue { + return requeue, patroniErr } - // } // create standby egress rule first, so the standby can actually connect to the primary if err := r.createOrUpdateEgressCWNP(ctx, instance); err != nil { @@ -291,6 +278,12 @@ func (r *PostgresReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c return ctrl.Result{}, fmt.Errorf("unable to create or update ingress ClusterwideNetworkPolicy: %w", err) } + // this is done down here to make sure the rest of the resource updates are performed anyway + if patroniErr != nil { + // when an error occurred while updating the patroni config, requeue here + return requeue, patroniErr + } + r.recorder.Event(instance, "Normal", "Reconciled", "postgres up to date") return ctrl.Result{}, nil } @@ -706,103 +699,102 @@ func (r *PostgresReconciler) ensureStandbySecrets(ctx context.Context, instance } -func (r *PostgresReconciler) checkAndUpdatePatroniConfig(ctx context.Context, instance *pg.Postgres) (*reconcile.Result, error) { +func (r *PostgresReconciler) checkAndUpdatePatroniConfig(ctx context.Context, instance *pg.Postgres) (bool, error) { - // requeue defines in how many seconds a requeue should happen - var requeue = ctrl.Result{ - Requeue: true, - } + var requeueImmediately = true + var continueWithReconciliation = false - // noRequeue defines in how many seconds a requeue should happen - var noRequeue = ctrl.Result{ - Requeue: false, + // If there is no connected postgres, no need to tinker with patroni directly + if instance.Spec.PostgresConnection == nil { + return continueWithReconciliation, nil } - // Nothing to do, skip all of it - if instance.Spec.PostgresConnection == nil { - return &noRequeue, nil + // If we are a standby, we can safely patch the Patronic config directly. + // Also, there should only be one instance running anyway, and that instance might have the role master or standby_leader, so we just patch them all. + if !instance.IsReplicationPrimary() { + // send PATCH immediately + return continueWithReconciliation, r.updatePatroniConfigOnAllPods(ctx, instance) } - r.Log.Info("Sending REST call to Patroni API") - pods := &corev1.PodList{} + // r.Log.Info("Reading config from Patroni API") + // Get the leader pod + leaderPods := &corev1.PodList{} roleReq, err := labels.NewRequirement(pg.SpiloRoleLabelName, selection.In, []string{pg.SpiloRoleLabelValueMaster, pg.SpiloRoleLabelValueStandbyLeader}) if err != nil { r.Log.Info("could not create requirements for label selector to query pods, requeuing") - return &requeue, err + return requeueImmediately, err } - leaderSelector := labels.NewSelector() - leaderSelector = leaderSelector.Add(*roleReq) - + leaderSelector := labels.NewSelector().Add(*roleReq) opts := []client.ListOption{ client.InNamespace(instance.ToPeripheralResourceNamespace()), client.MatchingLabelsSelector{Selector: leaderSelector}, } - if err := r.SvcClient.List(ctx, pods, opts...); err != nil { + if err := r.SvcClient.List(ctx, leaderPods, opts...); err != nil { r.Log.Info("could not query pods, requeuing") - return &requeue, err + return requeueImmediately, err } - if len(pods.Items) == 0 { + + if len(leaderPods.Items) == 0 { r.Log.Info("no leader pod found, selecting all spilo pods as a last resort (might be ok if it is still creating)") err = r.updatePatroniConfigOnAllPods(ctx, instance) if err != nil { r.Log.Info("updating patroni config failed, got one or more errors") // TODO requeue or continue here? - return &requeue, err + return continueWithReconciliation, err } // To make sure any updates to the Zalando postgresql manifest are written, we do not requeue in this case - return &noRequeue, nil + return continueWithReconciliation, nil } - podIP := pods.Items[0].Status.PodIP + leaderIP := leaderPods.Items[0].Status.PodIP // TODO check config. If in wrong state, make the call and return *reconcile.Result // TODO what happens, when the call fails consistently? We will not be able to change any settings via Postgreslet then, as the createOrUpdateZalandoPostgrseql will not be called... var resp *PatroniConfigRequest - if resp, err = r.httpGetPatroniConfig(ctx, instance, podIP); err != nil { - // TODO could not fetch config, what to do now? + if resp, err = r.httpGetPatroniConfig(ctx, instance, leaderIP); err != nil { + return continueWithReconciliation, err } if resp == nil { - return &requeue, r.httpPatchPatroni(ctx, instance, podIP) + return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) } - // TODO check config - if instance.IsReplicationPrimary() { - if resp.StandbyCluster != nil { - return &requeue, r.httpPatchPatroni(ctx, instance, podIP) - } - - if resp.SynchronousNodesAdditional != nil { - return &requeue, r.httpPatchPatroni(ctx, instance, podIP) - } - } else { - if resp.StandbyCluster == nil { - return &requeue, r.httpPatchPatroni(ctx, instance, podIP) - } - if resp.StandbyCluster.CreateReplicaMethods == nil { - // TODO check for actual content instead of nil - return &requeue, r.httpPatchPatroni(ctx, instance, podIP) - } - if resp.StandbyCluster.Host != instance.Spec.PostgresConnection.ConnectionIP { - return &requeue, r.httpPatchPatroni(ctx, instance, podIP) - } - if resp.StandbyCluster.Port != int(instance.Spec.PostgresConnection.ConnectionPort) { - return &requeue, r.httpPatchPatroni(ctx, instance, podIP) - } - if resp.StandbyCluster.ApplicationName != instance.ObjectMeta.Name { - return &requeue, r.httpPatchPatroni(ctx, instance, podIP) - } - - if resp.SynchronousNodesAdditional == nil { - return &requeue, r.httpPatchPatroni(ctx, instance, podIP) - } - if resp.SynchronousNodesAdditional != pointer.String(instance.Spec.PostgresConnection.ConnectedPostgresID) { - return &requeue, r.httpPatchPatroni(ctx, instance, podIP) - } - } + // if instance.IsReplicationPrimary() { + if resp.StandbyCluster != nil { + return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) + } + + if resp.SynchronousNodesAdditional != nil { + return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) + } + // } else { + // if resp.StandbyCluster == nil { + // return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) + // } + // if resp.StandbyCluster.CreateReplicaMethods == nil { + // // TODO check for actual content instead of nil + // return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) + // } + // if resp.StandbyCluster.Host != instance.Spec.PostgresConnection.ConnectionIP { + // return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) + // } + // if resp.StandbyCluster.Port != int(instance.Spec.PostgresConnection.ConnectionPort) { + // return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) + // } + // if resp.StandbyCluster.ApplicationName != instance.ObjectMeta.Name { + // return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) + // } + + // if resp.SynchronousNodesAdditional == nil { + // return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) + // } + // if resp.SynchronousNodesAdditional != pointer.String(instance.Spec.PostgresConnection.ConnectedPostgresID) { + // return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) + // } + // } - return &noRequeue, nil + return continueWithReconciliation, nil } func (r *PostgresReconciler) updatePatroniConfigOnAllPods(ctx context.Context, instance *pg.Postgres) error { From 6c599cc98825de6e414a057737102c262695191e Mon Sep 17 00:00:00 2001 From: Philipp Eberle Date: Wed, 31 Aug 2022 17:24:11 +0200 Subject: [PATCH 03/23] ... --- controllers/postgres_controller.go | 1 + 1 file changed, 1 insertion(+) diff --git a/controllers/postgres_controller.go b/controllers/postgres_controller.go index ae394288..ba56f5ce 100644 --- a/controllers/postgres_controller.go +++ b/controllers/postgres_controller.go @@ -90,6 +90,7 @@ type PatroniConfigRequest struct { } // Reconcile is the entry point for postgres reconciliation. +// +kubebuilder:rbac:groups=database.fits.cloud,resources=postgres,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=database.fits.cloud,resources=postgres/status,verbs=get;update;patch // +kubebuilder:rbac:groups=acid.zalan.do,resources=postgresqls,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=acid.zalan.do,resources=postgresqls/status,verbs=get;list;watch From f5b3adc2972b2ad2544842e5b91727c111529ac0 Mon Sep 17 00:00:00 2001 From: Philipp Eberle Date: Wed, 31 Aug 2022 17:57:34 +0200 Subject: [PATCH 04/23] Refactoring --- controllers/postgres_controller.go | 93 +++++++++++------------------- 1 file changed, 33 insertions(+), 60 deletions(-) diff --git a/controllers/postgres_controller.go b/controllers/postgres_controller.go index ba56f5ce..320ecb68 100644 --- a/controllers/postgres_controller.go +++ b/controllers/postgres_controller.go @@ -222,8 +222,11 @@ func (r *PostgresReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c return ctrl.Result{}, fmt.Errorf("error while creating standby secrets: %w", err) } - immediateRequeue, patroniErr := r.checkAndUpdatePatroniConfig(ctx, instance) + // check (and update if neccessary) the current patroni replication config. + immediateRequeue, patroniErr := r.checkAndUpdatePatroniReplicationConfig(ctx, instance) if immediateRequeue { + // if a config change was performed that requires a while to settle in, we simply requeue + // on the next reconciliation loop, the config should be correct already so we can continue with the rest return requeue, patroniErr } @@ -279,9 +282,9 @@ func (r *PostgresReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c return ctrl.Result{}, fmt.Errorf("unable to create or update ingress ClusterwideNetworkPolicy: %w", err) } - // this is done down here to make sure the rest of the resource updates are performed anyway + // when an error occurred while updating the patroni config, requeue here + // this is done down here to make sure the rest of the resource updates were performed if patroniErr != nil { - // when an error occurred while updating the patroni config, requeue here return requeue, patroniErr } @@ -700,10 +703,10 @@ func (r *PostgresReconciler) ensureStandbySecrets(ctx context.Context, instance } -func (r *PostgresReconciler) checkAndUpdatePatroniConfig(ctx context.Context, instance *pg.Postgres) (bool, error) { +func (r *PostgresReconciler) checkAndUpdatePatroniReplicationConfig(ctx context.Context, instance *pg.Postgres) (bool, error) { - var requeueImmediately = true - var continueWithReconciliation = false + const requeueImmediately = true + const continueWithReconciliation = false // If there is no connected postgres, no need to tinker with patroni directly if instance.Spec.PostgresConnection == nil { @@ -714,54 +717,34 @@ func (r *PostgresReconciler) checkAndUpdatePatroniConfig(ctx context.Context, in // Also, there should only be one instance running anyway, and that instance might have the role master or standby_leader, so we just patch them all. if !instance.IsReplicationPrimary() { // send PATCH immediately - return continueWithReconciliation, r.updatePatroniConfigOnAllPods(ctx, instance) + return continueWithReconciliation, r.updatePatroniReplicationConfigOnAllPods(ctx, instance) } // r.Log.Info("Reading config from Patroni API") // Get the leader pod - leaderPods := &corev1.PodList{} - roleReq, err := labels.NewRequirement(pg.SpiloRoleLabelName, selection.In, []string{pg.SpiloRoleLabelValueMaster, pg.SpiloRoleLabelValueStandbyLeader}) + leaderPods, err := r.findLeaderPods(ctx, instance) if err != nil { - r.Log.Info("could not create requirements for label selector to query pods, requeuing") - return requeueImmediately, err - } - leaderSelector := labels.NewSelector().Add(*roleReq) - opts := []client.ListOption{ - client.InNamespace(instance.ToPeripheralResourceNamespace()), - client.MatchingLabelsSelector{Selector: leaderSelector}, - } - if err := r.SvcClient.List(ctx, leaderPods, opts...); err != nil { r.Log.Info("could not query pods, requeuing") return requeueImmediately, err } - if len(leaderPods.Items) == 0 { - r.Log.Info("no leader pod found, selecting all spilo pods as a last resort (might be ok if it is still creating)") - - err = r.updatePatroniConfigOnAllPods(ctx, instance) - if err != nil { - r.Log.Info("updating patroni config failed, got one or more errors") - // TODO requeue or continue here? - return continueWithReconciliation, err - } + if len(leaderPods.Items) != 1 { + r.Log.Info("expected exactly one leader pod, selecting all spilo pods as a last resort (might be ok if it is still creating)") // To make sure any updates to the Zalando postgresql manifest are written, we do not requeue in this case - return continueWithReconciliation, nil + return continueWithReconciliation, r.updatePatroniReplicationConfigOnAllPods(ctx, instance) } leaderIP := leaderPods.Items[0].Status.PodIP - // TODO check config. If in wrong state, make the call and return *reconcile.Result - // TODO what happens, when the call fails consistently? We will not be able to change any settings via Postgreslet then, as the createOrUpdateZalandoPostgrseql will not be called... var resp *PatroniConfigRequest - if resp, err = r.httpGetPatroniConfig(ctx, instance, leaderIP); err != nil { + resp, err = r.httpGetPatroniConfig(ctx, instance, leaderIP) + if err != nil { return continueWithReconciliation, err } - if resp == nil { - return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) + return continueWithReconciliation, r.httpPatchPatroni(ctx, instance, leaderIP) } - // if instance.IsReplicationPrimary() { if resp.StandbyCluster != nil { return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) } @@ -769,36 +752,26 @@ func (r *PostgresReconciler) checkAndUpdatePatroniConfig(ctx context.Context, in if resp.SynchronousNodesAdditional != nil { return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) } - // } else { - // if resp.StandbyCluster == nil { - // return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) - // } - // if resp.StandbyCluster.CreateReplicaMethods == nil { - // // TODO check for actual content instead of nil - // return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) - // } - // if resp.StandbyCluster.Host != instance.Spec.PostgresConnection.ConnectionIP { - // return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) - // } - // if resp.StandbyCluster.Port != int(instance.Spec.PostgresConnection.ConnectionPort) { - // return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) - // } - // if resp.StandbyCluster.ApplicationName != instance.ObjectMeta.Name { - // return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) - // } - - // if resp.SynchronousNodesAdditional == nil { - // return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) - // } - // if resp.SynchronousNodesAdditional != pointer.String(instance.Spec.PostgresConnection.ConnectedPostgresID) { - // return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) - // } - // } return continueWithReconciliation, nil } -func (r *PostgresReconciler) updatePatroniConfigOnAllPods(ctx context.Context, instance *pg.Postgres) error { +func (r *PostgresReconciler) findLeaderPods(ctx context.Context, instance *pg.Postgres) (*corev1.PodList, error) { + leaderPods := &corev1.PodList{} + roleReq, err := labels.NewRequirement(pg.SpiloRoleLabelName, selection.In, []string{pg.SpiloRoleLabelValueMaster, pg.SpiloRoleLabelValueStandbyLeader}) + if err != nil { + r.Log.Info("could not create requirements for label selector to query pods, requeuing") + return leaderPods, err + } + leaderSelector := labels.NewSelector().Add(*roleReq) + opts := []client.ListOption{ + client.InNamespace(instance.ToPeripheralResourceNamespace()), + client.MatchingLabelsSelector{Selector: leaderSelector}, + } + return leaderPods, r.SvcClient.List(ctx, leaderPods, opts...) +} + +func (r *PostgresReconciler) updatePatroniReplicationConfigOnAllPods(ctx context.Context, instance *pg.Postgres) error { pods := &corev1.PodList{} opts := []client.ListOption{ client.InNamespace(instance.ToPeripheralResourceNamespace()), From 395937e7ce88a53e65cbdf443998cb74fbd3f676 Mon Sep 17 00:00:00 2001 From: Philipp Eberle Date: Wed, 31 Aug 2022 18:07:28 +0200 Subject: [PATCH 05/23] Fix linter warnings --- controllers/postgres_controller.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controllers/postgres_controller.go b/controllers/postgres_controller.go index 320ecb68..ad10eb79 100644 --- a/controllers/postgres_controller.go +++ b/controllers/postgres_controller.go @@ -876,7 +876,7 @@ func (r *PostgresReconciler) httpGetPatroniConfig(ctx context.Context, instance httpClient := &http.Client{} url := "http://" + podIP + ":" + podPort + "/" + path - req, err := http.NewRequest("GET", url, nil) + req, err := http.NewRequestWithContext(ctx, "GET", url, nil) if err != nil { r.Log.Error(err, "could not create request") return nil, err From 759147b96922afd83e39b7c6397d41a676709896 Mon Sep 17 00:00:00 2001 From: Philipp Eberle Date: Wed, 31 Aug 2022 18:12:13 +0200 Subject: [PATCH 06/23] Fix linter warning --- controllers/postgres_controller.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/controllers/postgres_controller.go b/controllers/postgres_controller.go index ad10eb79..2fa81f88 100644 --- a/controllers/postgres_controller.go +++ b/controllers/postgres_controller.go @@ -737,7 +737,7 @@ func (r *PostgresReconciler) checkAndUpdatePatroniReplicationConfig(ctx context. leaderIP := leaderPods.Items[0].Status.PodIP var resp *PatroniConfigRequest - resp, err = r.httpGetPatroniConfig(ctx, instance, leaderIP) + resp, err = r.httpGetPatroniConfig(ctx, leaderIP) if err != nil { return continueWithReconciliation, err } @@ -865,7 +865,7 @@ func (r *PostgresReconciler) httpPatchPatroni(ctx context.Context, instance *pg. return nil } -func (r *PostgresReconciler) httpGetPatroniConfig(ctx context.Context, instance *pg.Postgres, podIP string) (*PatroniConfigRequest, error) { +func (r *PostgresReconciler) httpGetPatroniConfig(ctx context.Context, podIP string) (*PatroniConfigRequest, error) { if podIP == "" { return nil, errors.New("podIP must not be empty") } From a3408fd3bc78dad0e9792ca857a8f2464a23b180 Mon Sep 17 00:00:00 2001 From: Philipp Eberle Date: Wed, 31 Aug 2022 19:17:21 +0200 Subject: [PATCH 07/23] Delay requeue by 10 secs --- controllers/postgres_controller.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/controllers/postgres_controller.go b/controllers/postgres_controller.go index 2fa81f88..1cfbc559 100644 --- a/controllers/postgres_controller.go +++ b/controllers/postgres_controller.go @@ -18,6 +18,7 @@ import ( "net/url" "strconv" "strings" + "time" "github.com/go-logr/logr" zalando "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1" @@ -227,7 +228,7 @@ func (r *PostgresReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c if immediateRequeue { // if a config change was performed that requires a while to settle in, we simply requeue // on the next reconciliation loop, the config should be correct already so we can continue with the rest - return requeue, patroniErr + return ctrl.Result{Requeue: true, RequeueAfter: 10 * time.Second}, patroniErr } // create standby egress rule first, so the standby can actually connect to the primary From bef00f174790ce24cb73f0013115575fdf14ddbf Mon Sep 17 00:00:00 2001 From: Philipp Eberle Date: Wed, 31 Aug 2022 19:41:37 +0200 Subject: [PATCH 08/23] Check before updating standby configs as well --- controllers/postgres_controller.go | 49 +++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/controllers/postgres_controller.go b/controllers/postgres_controller.go index 1cfbc559..4fa31430 100644 --- a/controllers/postgres_controller.go +++ b/controllers/postgres_controller.go @@ -228,6 +228,7 @@ func (r *PostgresReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c if immediateRequeue { // if a config change was performed that requires a while to settle in, we simply requeue // on the next reconciliation loop, the config should be correct already so we can continue with the rest + log.Info("Requeueing after patroni replication config change") return ctrl.Result{Requeue: true, RequeueAfter: 10 * time.Second}, patroniErr } @@ -286,7 +287,8 @@ func (r *PostgresReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c // when an error occurred while updating the patroni config, requeue here // this is done down here to make sure the rest of the resource updates were performed if patroniErr != nil { - return requeue, patroniErr + log.Info("Requeueing after modifying patroni replication config failed") + return ctrl.Result{Requeue: true, RequeueAfter: 10 * time.Second}, patroniErr } r.recorder.Event(instance, "Normal", "Reconciled", "postgres up to date") @@ -714,14 +716,7 @@ func (r *PostgresReconciler) checkAndUpdatePatroniReplicationConfig(ctx context. return continueWithReconciliation, nil } - // If we are a standby, we can safely patch the Patronic config directly. - // Also, there should only be one instance running anyway, and that instance might have the role master or standby_leader, so we just patch them all. - if !instance.IsReplicationPrimary() { - // send PATCH immediately - return continueWithReconciliation, r.updatePatroniReplicationConfigOnAllPods(ctx, instance) - } - - // r.Log.Info("Reading config from Patroni API") + r.Log.Info("Checking config from Patroni API") // Get the leader pod leaderPods, err := r.findLeaderPods(ctx, instance) @@ -746,12 +741,38 @@ func (r *PostgresReconciler) checkAndUpdatePatroniReplicationConfig(ctx context. return continueWithReconciliation, r.httpPatchPatroni(ctx, instance, leaderIP) } - if resp.StandbyCluster != nil { - return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) - } + if instance.IsReplicationPrimary() { + if resp.StandbyCluster != nil { + return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) + } - if resp.SynchronousNodesAdditional != nil { - return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) + if resp.SynchronousNodesAdditional != nil { + return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) + } + } else { + if resp.StandbyCluster == nil { + return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) + } + if resp.StandbyCluster.CreateReplicaMethods == nil { + // TODO check for actual content instead of nil + return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) + } + if resp.StandbyCluster.Host != instance.Spec.PostgresConnection.ConnectionIP { + return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) + } + if resp.StandbyCluster.Port != int(instance.Spec.PostgresConnection.ConnectionPort) { + return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) + } + if resp.StandbyCluster.ApplicationName != instance.ObjectMeta.Name { + return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) + } + + if resp.SynchronousNodesAdditional == nil { + return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) + } + if resp.SynchronousNodesAdditional != pointer.String(instance.Spec.PostgresConnection.ConnectedPostgresID) { + return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) + } } return continueWithReconciliation, nil From 293ae9c8459ad38aadb9b438bfb1ecc82518ac3e Mon Sep 17 00:00:00 2001 From: Philipp Eberle Date: Wed, 31 Aug 2022 19:59:19 +0200 Subject: [PATCH 09/23] Improve logging --- controllers/postgres_controller.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/controllers/postgres_controller.go b/controllers/postgres_controller.go index 4fa31430..93abfcad 100644 --- a/controllers/postgres_controller.go +++ b/controllers/postgres_controller.go @@ -751,26 +751,33 @@ func (r *PostgresReconciler) checkAndUpdatePatroniReplicationConfig(ctx context. } } else { if resp.StandbyCluster == nil { + r.Log.Info("updating and requeing, got %v", resp) return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) } if resp.StandbyCluster.CreateReplicaMethods == nil { // TODO check for actual content instead of nil + r.Log.Info("updating and requeing, got %v", resp) return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) } if resp.StandbyCluster.Host != instance.Spec.PostgresConnection.ConnectionIP { + r.Log.Info("updating and requeing, got %v", resp) return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) } if resp.StandbyCluster.Port != int(instance.Spec.PostgresConnection.ConnectionPort) { + r.Log.Info("updating and requeing, got %v", resp) return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) } if resp.StandbyCluster.ApplicationName != instance.ObjectMeta.Name { + r.Log.Info("updating and requeing, got %v", resp) return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) } if resp.SynchronousNodesAdditional == nil { + r.Log.Info("updating and requeing, got %v", resp) return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) } if resp.SynchronousNodesAdditional != pointer.String(instance.Spec.PostgresConnection.ConnectedPostgresID) { + r.Log.Info("updating and requeing, got %v", resp) return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) } } From 64354f5b2a8b14a3789b6d2886a7720e3d7ecbfe Mon Sep 17 00:00:00 2001 From: Philipp Eberle Date: Wed, 31 Aug 2022 20:05:27 +0200 Subject: [PATCH 10/23] Improve logging --- controllers/postgres_controller.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/controllers/postgres_controller.go b/controllers/postgres_controller.go index 93abfcad..f3ee438b 100644 --- a/controllers/postgres_controller.go +++ b/controllers/postgres_controller.go @@ -932,6 +932,8 @@ func (r *PostgresReconciler) httpGetPatroniConfig(ctx context.Context, podIP str return nil, err } + r.Log.Info("Got config", "response", jsonResp) + return &jsonResp, err } From 7ac265c33bbff6f07b23777281267c9177cb28c8 Mon Sep 17 00:00:00 2001 From: Philipp Eberle Date: Wed, 31 Aug 2022 20:06:48 +0200 Subject: [PATCH 11/23] Improve logging --- controllers/postgres_controller.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/controllers/postgres_controller.go b/controllers/postgres_controller.go index f3ee438b..0c2022a4 100644 --- a/controllers/postgres_controller.go +++ b/controllers/postgres_controller.go @@ -751,33 +751,33 @@ func (r *PostgresReconciler) checkAndUpdatePatroniReplicationConfig(ctx context. } } else { if resp.StandbyCluster == nil { - r.Log.Info("updating and requeing, got %v", resp) + r.Log.Info("updating and requeing", "response", resp) return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) } if resp.StandbyCluster.CreateReplicaMethods == nil { // TODO check for actual content instead of nil - r.Log.Info("updating and requeing, got %v", resp) + r.Log.Info("updating and requeing", "response", resp) return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) } if resp.StandbyCluster.Host != instance.Spec.PostgresConnection.ConnectionIP { - r.Log.Info("updating and requeing, got %v", resp) + r.Log.Info("updating and requeing", "response", resp) return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) } if resp.StandbyCluster.Port != int(instance.Spec.PostgresConnection.ConnectionPort) { - r.Log.Info("updating and requeing, got %v", resp) + r.Log.Info("updating and requeing", "response", resp) return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) } if resp.StandbyCluster.ApplicationName != instance.ObjectMeta.Name { - r.Log.Info("updating and requeing, got %v", resp) + r.Log.Info("updating and requeing", "response", resp) return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) } if resp.SynchronousNodesAdditional == nil { - r.Log.Info("updating and requeing, got %v", resp) + r.Log.Info("updating and requeing", "response", resp) return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) } if resp.SynchronousNodesAdditional != pointer.String(instance.Spec.PostgresConnection.ConnectedPostgresID) { - r.Log.Info("updating and requeing, got %v", resp) + r.Log.Info("updating and requeing", "response", resp) return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) } } From 3f289f26839be69479746da55a644122082783c3 Mon Sep 17 00:00:00 2001 From: Philipp Eberle Date: Wed, 31 Aug 2022 20:20:48 +0200 Subject: [PATCH 12/23] Fix check for SynchronousNodesAdditional --- controllers/postgres_controller.go | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/controllers/postgres_controller.go b/controllers/postgres_controller.go index 0c2022a4..41c6eb46 100644 --- a/controllers/postgres_controller.go +++ b/controllers/postgres_controller.go @@ -745,10 +745,18 @@ func (r *PostgresReconciler) checkAndUpdatePatroniReplicationConfig(ctx context. if resp.StandbyCluster != nil { return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) } - - if resp.SynchronousNodesAdditional != nil { - return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) + if instance.Spec.PostgresConnection.SynchronousReplication { + // enable sync replication + if resp.SynchronousNodesAdditional != pointer.String(instance.Spec.PostgresConnection.ConnectedPostgresID) { + return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) + } + } else { + // disable sync replication + if resp.SynchronousNodesAdditional != nil { + return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) + } } + } else { if resp.StandbyCluster == nil { r.Log.Info("updating and requeing", "response", resp) @@ -772,11 +780,7 @@ func (r *PostgresReconciler) checkAndUpdatePatroniReplicationConfig(ctx context. return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) } - if resp.SynchronousNodesAdditional == nil { - r.Log.Info("updating and requeing", "response", resp) - return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) - } - if resp.SynchronousNodesAdditional != pointer.String(instance.Spec.PostgresConnection.ConnectedPostgresID) { + if resp.SynchronousNodesAdditional != nil { r.Log.Info("updating and requeing", "response", resp) return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) } From 898bdf2a3763c74a710f70cec79f2d0a7fd88979 Mon Sep 17 00:00:00 2001 From: Philipp Eberle Date: Wed, 31 Aug 2022 20:57:09 +0200 Subject: [PATCH 13/23] Fix comparison, improve logging --- controllers/postgres_controller.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/controllers/postgres_controller.go b/controllers/postgres_controller.go index 41c6eb46..c3682298 100644 --- a/controllers/postgres_controller.go +++ b/controllers/postgres_controller.go @@ -743,45 +743,45 @@ func (r *PostgresReconciler) checkAndUpdatePatroniReplicationConfig(ctx context. if instance.IsReplicationPrimary() { if resp.StandbyCluster != nil { + r.Log.Info("standby_cluster mistmatch, updating and requeing", "response", resp) return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) } if instance.Spec.PostgresConnection.SynchronousReplication { - // enable sync replication - if resp.SynchronousNodesAdditional != pointer.String(instance.Spec.PostgresConnection.ConnectedPostgresID) { + if *resp.SynchronousNodesAdditional != instance.Spec.PostgresConnection.ConnectedPostgresID { + r.Log.Info("synchronous_nodes_additional mistmatch, updating and requeing", "response", resp) return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) } } else { - // disable sync replication if resp.SynchronousNodesAdditional != nil { + r.Log.Info("synchronous_nodes_additional mistmatch, updating and requeing", "response", resp) return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) } } } else { if resp.StandbyCluster == nil { - r.Log.Info("updating and requeing", "response", resp) + r.Log.Info("standby_cluster mismatch, updating and requeing", "response", resp) return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) } if resp.StandbyCluster.CreateReplicaMethods == nil { - // TODO check for actual content instead of nil - r.Log.Info("updating and requeing", "response", resp) + r.Log.Info("create_replica_methods mismatch, updating and requeing", "response", resp) return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) } if resp.StandbyCluster.Host != instance.Spec.PostgresConnection.ConnectionIP { - r.Log.Info("updating and requeing", "response", resp) + r.Log.Info("host mismatch, updating and requeing", "response", resp) return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) } if resp.StandbyCluster.Port != int(instance.Spec.PostgresConnection.ConnectionPort) { - r.Log.Info("updating and requeing", "response", resp) + r.Log.Info("port mismatch, updating and requeing", "response", resp) return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) } if resp.StandbyCluster.ApplicationName != instance.ObjectMeta.Name { - r.Log.Info("updating and requeing", "response", resp) + r.Log.Info("application_name mismatch, updating and requeing", "response", resp) return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) } if resp.SynchronousNodesAdditional != nil { - r.Log.Info("updating and requeing", "response", resp) + r.Log.Info("synchronous_nodes_additional mistmatch, updating and requeing", "response", resp) return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) } } From a17cf1165feeb70d0b2fe6f905aec2c7ca3c4b20 Mon Sep 17 00:00:00 2001 From: Philipp Eberle Date: Wed, 31 Aug 2022 21:10:55 +0200 Subject: [PATCH 14/23] Additional nil check... --- controllers/postgres_controller.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controllers/postgres_controller.go b/controllers/postgres_controller.go index c3682298..9dccbcd9 100644 --- a/controllers/postgres_controller.go +++ b/controllers/postgres_controller.go @@ -747,7 +747,7 @@ func (r *PostgresReconciler) checkAndUpdatePatroniReplicationConfig(ctx context. return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) } if instance.Spec.PostgresConnection.SynchronousReplication { - if *resp.SynchronousNodesAdditional != instance.Spec.PostgresConnection.ConnectedPostgresID { + if resp.SynchronousNodesAdditional == nil || *resp.SynchronousNodesAdditional != instance.Spec.PostgresConnection.ConnectedPostgresID { r.Log.Info("synchronous_nodes_additional mistmatch, updating and requeing", "response", resp) return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) } From 3f57b1cf0ff024f7c9ba68020de5b8cbda671202 Mon Sep 17 00:00:00 2001 From: Philipp Eberle Date: Wed, 31 Aug 2022 21:38:37 +0200 Subject: [PATCH 15/23] Test different execution order for primaries and standbies --- controllers/postgres_controller.go | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/controllers/postgres_controller.go b/controllers/postgres_controller.go index 9dccbcd9..1f7afb66 100644 --- a/controllers/postgres_controller.go +++ b/controllers/postgres_controller.go @@ -224,12 +224,16 @@ func (r *PostgresReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c } // check (and update if neccessary) the current patroni replication config. - immediateRequeue, patroniErr := r.checkAndUpdatePatroniReplicationConfig(ctx, instance) - if immediateRequeue { - // if a config change was performed that requires a while to settle in, we simply requeue - // on the next reconciliation loop, the config should be correct already so we can continue with the rest - log.Info("Requeueing after patroni replication config change") - return ctrl.Result{Requeue: true, RequeueAfter: 10 * time.Second}, patroniErr + var patroniErr error + // for primary databases, do that call before updating the custom ressource + if instance.IsReplicationPrimary() { + immediateRequeue, patroniErr := r.checkAndUpdatePatroniReplicationConfig(ctx, instance) + if immediateRequeue { + // if a config change was performed that requires a while to settle in, we simply requeue + // on the next reconciliation loop, the config should be correct already so we can continue with the rest + log.Info("Requeueing after patroni replication config change") + return ctrl.Result{Requeue: true, RequeueAfter: 10 * time.Second}, patroniErr + } } // create standby egress rule first, so the standby can actually connect to the primary @@ -284,6 +288,17 @@ func (r *PostgresReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c return ctrl.Result{}, fmt.Errorf("unable to create or update ingress ClusterwideNetworkPolicy: %w", err) } + // for standby databases, do that call after updating the custom ressource + if !instance.IsReplicationPrimary() { + immediateRequeue, patroniErr := r.checkAndUpdatePatroniReplicationConfig(ctx, instance) + if immediateRequeue { + // if a config change was performed that requires a while to settle in, we simply requeue + // on the next reconciliation loop, the config should be correct already so we can continue with the rest + log.Info("Requeueing after patroni replication config change") + return ctrl.Result{Requeue: true, RequeueAfter: 10 * time.Second}, patroniErr + } + } + // when an error occurred while updating the patroni config, requeue here // this is done down here to make sure the rest of the resource updates were performed if patroniErr != nil { @@ -786,6 +801,7 @@ func (r *PostgresReconciler) checkAndUpdatePatroniReplicationConfig(ctx context. } } + r.Log.Info("replication config from Patroni API up to date") return continueWithReconciliation, nil } From 298bf0588de59abb7046dbbd2d42634f59c0fa10 Mon Sep 17 00:00:00 2001 From: Philipp Eberle Date: Wed, 31 Aug 2022 21:51:33 +0200 Subject: [PATCH 16/23] Revert "Test different execution order for primaries and standbies" This reverts commit 3f57b1cf0ff024f7c9ba68020de5b8cbda671202. --- controllers/postgres_controller.go | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/controllers/postgres_controller.go b/controllers/postgres_controller.go index 1f7afb66..9dccbcd9 100644 --- a/controllers/postgres_controller.go +++ b/controllers/postgres_controller.go @@ -224,16 +224,12 @@ func (r *PostgresReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c } // check (and update if neccessary) the current patroni replication config. - var patroniErr error - // for primary databases, do that call before updating the custom ressource - if instance.IsReplicationPrimary() { - immediateRequeue, patroniErr := r.checkAndUpdatePatroniReplicationConfig(ctx, instance) - if immediateRequeue { - // if a config change was performed that requires a while to settle in, we simply requeue - // on the next reconciliation loop, the config should be correct already so we can continue with the rest - log.Info("Requeueing after patroni replication config change") - return ctrl.Result{Requeue: true, RequeueAfter: 10 * time.Second}, patroniErr - } + immediateRequeue, patroniErr := r.checkAndUpdatePatroniReplicationConfig(ctx, instance) + if immediateRequeue { + // if a config change was performed that requires a while to settle in, we simply requeue + // on the next reconciliation loop, the config should be correct already so we can continue with the rest + log.Info("Requeueing after patroni replication config change") + return ctrl.Result{Requeue: true, RequeueAfter: 10 * time.Second}, patroniErr } // create standby egress rule first, so the standby can actually connect to the primary @@ -288,17 +284,6 @@ func (r *PostgresReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c return ctrl.Result{}, fmt.Errorf("unable to create or update ingress ClusterwideNetworkPolicy: %w", err) } - // for standby databases, do that call after updating the custom ressource - if !instance.IsReplicationPrimary() { - immediateRequeue, patroniErr := r.checkAndUpdatePatroniReplicationConfig(ctx, instance) - if immediateRequeue { - // if a config change was performed that requires a while to settle in, we simply requeue - // on the next reconciliation loop, the config should be correct already so we can continue with the rest - log.Info("Requeueing after patroni replication config change") - return ctrl.Result{Requeue: true, RequeueAfter: 10 * time.Second}, patroniErr - } - } - // when an error occurred while updating the patroni config, requeue here // this is done down here to make sure the rest of the resource updates were performed if patroniErr != nil { @@ -801,7 +786,6 @@ func (r *PostgresReconciler) checkAndUpdatePatroniReplicationConfig(ctx context. } } - r.Log.Info("replication config from Patroni API up to date") return continueWithReconciliation, nil } From 15680d4f3381be0388d974d5c9a76c0c435bb38d Mon Sep 17 00:00:00 2001 From: Philipp Eberle Date: Wed, 31 Aug 2022 21:52:07 +0200 Subject: [PATCH 17/23] Logging --- controllers/postgres_controller.go | 1 + 1 file changed, 1 insertion(+) diff --git a/controllers/postgres_controller.go b/controllers/postgres_controller.go index 9dccbcd9..764bff5b 100644 --- a/controllers/postgres_controller.go +++ b/controllers/postgres_controller.go @@ -786,6 +786,7 @@ func (r *PostgresReconciler) checkAndUpdatePatroniReplicationConfig(ctx context. } } + r.Log.Info("replication config from Patroni API up to date") return continueWithReconciliation, nil } From f03bb68178ff5401743935ee80e6af66969e6960 Mon Sep 17 00:00:00 2001 From: Philipp Eberle Date: Thu, 1 Sep 2022 11:53:46 +0200 Subject: [PATCH 18/23] Refactoring --- controllers/postgres_controller.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/controllers/postgres_controller.go b/controllers/postgres_controller.go index 764bff5b..18fab605 100644 --- a/controllers/postgres_controller.go +++ b/controllers/postgres_controller.go @@ -85,7 +85,7 @@ type PatroniStandbyCluster struct { Port int `json:"port"` ApplicationName string `json:"application_name"` } -type PatroniConfigRequest struct { +type PatroniConfig struct { StandbyCluster *PatroniStandbyCluster `json:"standby_cluster"` SynchronousNodesAdditional *string `json:"synchronous_nodes_additional"` } @@ -716,7 +716,7 @@ func (r *PostgresReconciler) checkAndUpdatePatroniReplicationConfig(ctx context. return continueWithReconciliation, nil } - r.Log.Info("Checking config from Patroni API") + r.Log.Info("Checking replication config from Patroni API") // Get the leader pod leaderPods, err := r.findLeaderPods(ctx, instance) @@ -732,7 +732,7 @@ func (r *PostgresReconciler) checkAndUpdatePatroniReplicationConfig(ctx context. } leaderIP := leaderPods.Items[0].Status.PodIP - var resp *PatroniConfigRequest + var resp *PatroniConfig resp, err = r.httpGetPatroniConfig(ctx, leaderIP) if err != nil { return continueWithReconciliation, err @@ -848,9 +848,9 @@ func (r *PostgresReconciler) httpPatchPatroni(ctx context.Context, instance *pg. path := "config" r.Log.Info("Preparing request") - var request PatroniConfigRequest + var request PatroniConfig if instance.IsReplicationPrimary() { - request = PatroniConfigRequest{ + request = PatroniConfig{ StandbyCluster: nil, } if instance.Spec.PostgresConnection.SynchronousReplication { @@ -862,7 +862,7 @@ func (r *PostgresReconciler) httpPatchPatroni(ctx context.Context, instance *pg. } } else { // TODO check values first - request = PatroniConfigRequest{ + request = PatroniConfig{ StandbyCluster: &PatroniStandbyCluster{ CreateReplicaMethods: []string{"basebackup_fast_xlog"}, Host: instance.Spec.PostgresConnection.ConnectionIP, @@ -899,7 +899,7 @@ func (r *PostgresReconciler) httpPatchPatroni(ctx context.Context, instance *pg. return nil } -func (r *PostgresReconciler) httpGetPatroniConfig(ctx context.Context, podIP string) (*PatroniConfigRequest, error) { +func (r *PostgresReconciler) httpGetPatroniConfig(ctx context.Context, podIP string) (*PatroniConfig, error) { if podIP == "" { return nil, errors.New("podIP must not be empty") } @@ -930,7 +930,7 @@ func (r *PostgresReconciler) httpGetPatroniConfig(ctx context.Context, podIP str r.Log.Info("could not read body") return nil, err } - var jsonResp PatroniConfigRequest + var jsonResp PatroniConfig err = json.Unmarshal(body, &jsonResp) if err != nil { r.Log.Info("could not parse config") From 41a85edc7e473d6b5c2c32dc5b6a1bfbcffd5f8b Mon Sep 17 00:00:00 2001 From: Philipp Eberle Date: Thu, 1 Sep 2022 19:16:28 +0200 Subject: [PATCH 19/23] Make requeue duration configurable --- controllers/postgres_controller.go | 23 +++---- main.go | 99 ++++++++++++++++-------------- 2 files changed, 66 insertions(+), 56 deletions(-) diff --git a/controllers/postgres_controller.go b/controllers/postgres_controller.go index 18fab605..771940ae 100644 --- a/controllers/postgres_controller.go +++ b/controllers/postgres_controller.go @@ -67,16 +67,17 @@ type PostgresReconciler struct { PartitionID, Tenant, StorageClass string *operatormanager.OperatorManager *lbmanager.LBManager - recorder record.EventRecorder - PgParamBlockList map[string]bool - StandbyClustersSourceRanges []string - PostgresletNamespace string - SidecarsConfigMapName string - EnableNetPol bool - EtcdHost string - PatroniTTL uint32 - PatroniLoopWait uint32 - PatroniRetryTimeout uint32 + recorder record.EventRecorder + PgParamBlockList map[string]bool + StandbyClustersSourceRanges []string + PostgresletNamespace string + SidecarsConfigMapName string + EnableNetPol bool + EtcdHost string + PatroniTTL uint32 + PatroniLoopWait uint32 + PatroniRetryTimeout uint32 + ReplicationChangeRequeueDuration time.Duration } type PatroniStandbyCluster struct { @@ -229,7 +230,7 @@ func (r *PostgresReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c // if a config change was performed that requires a while to settle in, we simply requeue // on the next reconciliation loop, the config should be correct already so we can continue with the rest log.Info("Requeueing after patroni replication config change") - return ctrl.Result{Requeue: true, RequeueAfter: 10 * time.Second}, patroniErr + return ctrl.Result{Requeue: true, RequeueAfter: r.ReplicationChangeRequeueDuration}, patroniErr } // create standby egress rule first, so the standby can actually connect to the primary diff --git a/main.go b/main.go index a58d6ebb..4140aa5a 100644 --- a/main.go +++ b/main.go @@ -12,6 +12,7 @@ import ( "net" "os" "strings" + "time" "github.com/metal-stack/v" coreosv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" @@ -35,31 +36,32 @@ import ( const ( // envPrefix = "pg" - metricsAddrSvcMgrFlg = "metrics-addr-svc-mgr" - metricsAddrCtrlMgrFlg = "metrics-addr-ctrl-mgr" - enableLeaderElectionFlg = "enable-leader-election" - partitionIDFlg = "partition-id" - tenantFlg = "tenant" - ctrlPlaneKubeConfifgFlg = "controlplane-kubeconfig" - loadBalancerIPFlg = "load-balancer-ip" - portRangeStartFlg = "port-range-start" - portRangeSizeFlg = "port-range-size" - customPSPNameFlg = "custom-psp-name" - storageClassFlg = "storage-class" - postgresImageFlg = "postgres-image" - etcdHostFlg = "etcd-host" - crdValidationFlg = "enable-crd-validation" - operatorImageFlg = "operator-image" - pgParamBlockListFlg = "postgres-param-blocklist" - majorVersionUpgradeModeFlg = "major-version-upgrade-mode" - standbyClustersSourceRangesFlg = "standby-clusters-source-ranges" - postgresletNamespaceFlg = "postgreslet-namespace" - sidecarsCMNameFlg = "sidecars-configmap-name" - enableNetPolFlg = "enable-netpol" - enablePodAntiaffinityFlg = "enable-pod-antiaffinity" - patroniRetryTimeoutFlg = "patroni-retry-timeout" - enableStandbyLeaderSelectorFlg = "enable-standby-leader-selector" - ControlPlaneNamespaceFlg = "control-plane-namespace" + metricsAddrSvcMgrFlg = "metrics-addr-svc-mgr" + metricsAddrCtrlMgrFlg = "metrics-addr-ctrl-mgr" + enableLeaderElectionFlg = "enable-leader-election" + partitionIDFlg = "partition-id" + tenantFlg = "tenant" + ctrlPlaneKubeConfifgFlg = "controlplane-kubeconfig" + loadBalancerIPFlg = "load-balancer-ip" + portRangeStartFlg = "port-range-start" + portRangeSizeFlg = "port-range-size" + customPSPNameFlg = "custom-psp-name" + storageClassFlg = "storage-class" + postgresImageFlg = "postgres-image" + etcdHostFlg = "etcd-host" + crdValidationFlg = "enable-crd-validation" + operatorImageFlg = "operator-image" + pgParamBlockListFlg = "postgres-param-blocklist" + majorVersionUpgradeModeFlg = "major-version-upgrade-mode" + standbyClustersSourceRangesFlg = "standby-clusters-source-ranges" + postgresletNamespaceFlg = "postgreslet-namespace" + sidecarsCMNameFlg = "sidecars-configmap-name" + enableNetPolFlg = "enable-netpol" + enablePodAntiaffinityFlg = "enable-pod-antiaffinity" + patroniRetryTimeoutFlg = "patroni-retry-timeout" + enableStandbyLeaderSelectorFlg = "enable-standby-leader-selector" + ControlPlaneNamespaceFlg = "control-plane-namespace" + replicationChangeRequeueTimeFlg = "replication-change-requeue-time-in-seconds" ) var ( @@ -101,8 +103,9 @@ func main() { enablePodAntiaffinity bool enableStandbyLeaderSelector bool - portRangeStart int - portRangeSize int + portRangeStart int + portRangeSize int + replicationChangeRequeueTimeInSeconds int patroniTTL uint32 patroniLoopWait uint32 @@ -207,6 +210,10 @@ func main() { viper.SetDefault(ControlPlaneNamespaceFlg, "metal-extension-postgres") controlPlaneNamespace = viper.GetString(ControlPlaneNamespaceFlg) + viper.SetDefault(replicationChangeRequeueTimeFlg, 10) + replicationChangeRequeueTimeInSeconds = viper.GetInt(replicationChangeRequeueTimeFlg) + replicationChangeRequeueDuration := time.Duration(replicationChangeRequeueTimeInSeconds) * time.Second + ctrl.SetLogger(zap.New(zap.UseDevMode(true))) ctrl.Log.Info("flag", @@ -235,6 +242,7 @@ func main() { patroniRetryTimeoutFlg, patroniRetryTimeout, enableStandbyLeaderSelectorFlg, enableStandbyLeaderSelector, ControlPlaneNamespaceFlg, controlPlaneNamespace, + replicationChangeRequeueTimeFlg, replicationChangeRequeueTimeInSeconds, ) svcClusterConf := ctrl.GetConfigOrDie() @@ -292,24 +300,25 @@ func main() { EnableStandbyLeaderSelector: enableStandbyLeaderSelector, } if err = (&controllers.PostgresReconciler{ - CtrlClient: ctrlPlaneClusterMgr.GetClient(), - SvcClient: svcClusterMgr.GetClient(), - Log: ctrl.Log.WithName("controllers").WithName("Postgres"), - Scheme: ctrlPlaneClusterMgr.GetScheme(), - PartitionID: partitionID, - Tenant: tenant, - StorageClass: storageClass, - OperatorManager: opMgr, - LBManager: lbmanager.New(svcClusterMgr.GetClient(), lbMgrOpts), - PgParamBlockList: pgParamBlockList, - StandbyClustersSourceRanges: standbyClusterSourceRanges, - PostgresletNamespace: postgresletNamespace, - SidecarsConfigMapName: sidecarsCMName, - EnableNetPol: enableNetPol, - EtcdHost: etcdHost, - PatroniTTL: patroniTTL, - PatroniLoopWait: patroniLoopWait, - PatroniRetryTimeout: patroniRetryTimeout, + CtrlClient: ctrlPlaneClusterMgr.GetClient(), + SvcClient: svcClusterMgr.GetClient(), + Log: ctrl.Log.WithName("controllers").WithName("Postgres"), + Scheme: ctrlPlaneClusterMgr.GetScheme(), + PartitionID: partitionID, + Tenant: tenant, + StorageClass: storageClass, + OperatorManager: opMgr, + LBManager: lbmanager.New(svcClusterMgr.GetClient(), lbMgrOpts), + PgParamBlockList: pgParamBlockList, + StandbyClustersSourceRanges: standbyClusterSourceRanges, + PostgresletNamespace: postgresletNamespace, + SidecarsConfigMapName: sidecarsCMName, + EnableNetPol: enableNetPol, + EtcdHost: etcdHost, + PatroniTTL: patroniTTL, + PatroniLoopWait: patroniLoopWait, + PatroniRetryTimeout: patroniRetryTimeout, + ReplicationChangeRequeueDuration: replicationChangeRequeueDuration, }).SetupWithManager(ctrlPlaneClusterMgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "Postgres") os.Exit(1) From 06cc9bbfc67318aa721533ffa060bbdf6d122e36 Mon Sep 17 00:00:00 2001 From: Philipp Eberle Date: Thu, 1 Sep 2022 19:17:58 +0200 Subject: [PATCH 20/23] Rename variable --- controllers/postgres_controller.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/controllers/postgres_controller.go b/controllers/postgres_controller.go index 771940ae..26730269 100644 --- a/controllers/postgres_controller.go +++ b/controllers/postgres_controller.go @@ -225,12 +225,12 @@ func (r *PostgresReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c } // check (and update if neccessary) the current patroni replication config. - immediateRequeue, patroniErr := r.checkAndUpdatePatroniReplicationConfig(ctx, instance) + immediateRequeue, patroniConfigChangeErr := r.checkAndUpdatePatroniReplicationConfig(ctx, instance) if immediateRequeue { // if a config change was performed that requires a while to settle in, we simply requeue // on the next reconciliation loop, the config should be correct already so we can continue with the rest log.Info("Requeueing after patroni replication config change") - return ctrl.Result{Requeue: true, RequeueAfter: r.ReplicationChangeRequeueDuration}, patroniErr + return ctrl.Result{Requeue: true, RequeueAfter: r.ReplicationChangeRequeueDuration}, patroniConfigChangeErr } // create standby egress rule first, so the standby can actually connect to the primary @@ -287,9 +287,9 @@ func (r *PostgresReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c // when an error occurred while updating the patroni config, requeue here // this is done down here to make sure the rest of the resource updates were performed - if patroniErr != nil { + if patroniConfigChangeErr != nil { log.Info("Requeueing after modifying patroni replication config failed") - return ctrl.Result{Requeue: true, RequeueAfter: 10 * time.Second}, patroniErr + return ctrl.Result{Requeue: true, RequeueAfter: 10 * time.Second}, patroniConfigChangeErr } r.recorder.Event(instance, "Normal", "Reconciled", "postgres up to date") From febb2a9435a7b334656d3480fab347732ba72f54 Mon Sep 17 00:00:00 2001 From: Philipp Eberle Date: Thu, 1 Sep 2022 21:51:00 +0200 Subject: [PATCH 21/23] Add additional check (but only log the result for now) --- controllers/postgres_controller.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/controllers/postgres_controller.go b/controllers/postgres_controller.go index 26730269..1bd3ae20 100644 --- a/controllers/postgres_controller.go +++ b/controllers/postgres_controller.go @@ -820,6 +820,8 @@ func (r *PostgresReconciler) updatePatroniReplicationConfigOnAllPods(ctx context if len(pods.Items) == 0 { r.Log.Info("no spilo pods found at all, requeueing") return errors.New("no spilo pods found at all") + } else if len(pods.Items) < int(instance.Spec.NumberOfInstances) { + r.Log.Info("expected %d pods, but only found %d (might be ok if it is still creating)", instance.Spec.NumberOfInstances, len(pods.Items)) } // iterate all spilo pods From 4e8042e81e1600426e5d9af02411dc4e8710ed6f Mon Sep 17 00:00:00 2001 From: Philipp Eberle Date: Thu, 24 Nov 2022 11:20:48 +0100 Subject: [PATCH 22/23] Only requeue when REST call was successful --- controllers/postgres_controller.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/controllers/postgres_controller.go b/controllers/postgres_controller.go index 39109b9e..813ac616 100644 --- a/controllers/postgres_controller.go +++ b/controllers/postgres_controller.go @@ -226,9 +226,9 @@ func (r *PostgresReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c // check (and update if neccessary) the current patroni replication config. immediateRequeue, patroniConfigChangeErr := r.checkAndUpdatePatroniReplicationConfig(ctx, instance) - if immediateRequeue { - // if a config change was performed that requires a while to settle in, we simply requeue - // on the next reconciliation loop, the config should be correct already so we can continue with the rest + if immediateRequeue && patroniConfigChangeErr == nil { + // if a (successful) config change was performed that requires a while to settle in, we simply requeue. + // on the next reconciliation loop, the config should be correct already so we can continue with the rest. log.Info("Requeueing after patroni replication config change") return ctrl.Result{Requeue: true, RequeueAfter: r.ReplicationChangeRequeueDuration}, patroniConfigChangeErr } @@ -753,6 +753,7 @@ func (r *PostgresReconciler) checkAndUpdatePatroniReplicationConfig(ctx context. if instance.IsReplicationPrimary() { if resp.StandbyCluster != nil { r.Log.Info("standby_cluster mistmatch, updating and requeing", "response", resp) + // what happens, if patroni does not do what it is asked to do? what if it returns an error here? return requeueImmediately, r.httpPatchPatroni(ctx, instance, leaderIP) } if instance.Spec.PostgresConnection.SynchronousReplication { From 2b99dbfe60ce91d0ff02513a6dbff36af45c7f0e Mon Sep 17 00:00:00 2001 From: Philipp Eberle Date: Thu, 24 Nov 2022 11:32:11 +0100 Subject: [PATCH 23/23] Fix linter errors --- controllers/postgres_controller.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/controllers/postgres_controller.go b/controllers/postgres_controller.go index 813ac616..8d53faa5 100644 --- a/controllers/postgres_controller.go +++ b/controllers/postgres_controller.go @@ -12,7 +12,7 @@ import ( "encoding/json" "errors" "fmt" - "io/ioutil" + "io" "net" "net/http" "net/url" @@ -230,7 +230,7 @@ func (r *PostgresReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c // if a (successful) config change was performed that requires a while to settle in, we simply requeue. // on the next reconciliation loop, the config should be correct already so we can continue with the rest. log.Info("Requeueing after patroni replication config change") - return ctrl.Result{Requeue: true, RequeueAfter: r.ReplicationChangeRequeueDuration}, patroniConfigChangeErr + return ctrl.Result{Requeue: true, RequeueAfter: r.ReplicationChangeRequeueDuration}, nil } // create standby egress rule first, so the standby can actually connect to the primary @@ -937,7 +937,7 @@ func (r *PostgresReconciler) httpGetPatroniConfig(ctx context.Context, podIP str defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) if err != nil { r.Log.Info("could not read body") return nil, err