Skip to content
Open
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
7 changes: 4 additions & 3 deletions docs/reference/operator_parameters.md
Original file line number Diff line number Diff line change
Expand Up @@ -556,9 +556,10 @@ configuration they are grouped under the `kubernetes` key.
* **master_pod_move_timeout**
The period of time to wait for the success of migration of master pods from
an unschedulable node. The migration includes Patroni switchovers to
respective replicas on healthy nodes. The situation where master pods still
exist on the old node after this timeout expires has to be fixed manually.
The default is 20 minutes.
respective replicas on healthy nodes. A failed migration attempt is retried
every minute until this timeout expires. The situation where master pods
still exist on the old node after this timeout expires has to be fixed
manually. The default is 20 minutes.

* **enable_pod_antiaffinity**
toggles [pod anti affinity](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/)
Expand Down
3 changes: 2 additions & 1 deletion pkg/controller/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,8 @@ func (c *Controller) moveMasterPodsOffNode(node *v1.Node) {
func() (bool, error) {
err := c.attemptToMoveMasterPodsOffNode(node)
if err != nil {
return false, err
c.logger.Warningf("attempt to move master pods off node %q failed, will retry: %v", node.Name, err)
return false, nil
}
return true, nil
},
Expand Down
36 changes: 36 additions & 0 deletions pkg/controller/node_test.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
package controller

import (
"fmt"
"strings"
"testing"
"time"

logrustest "github.com/sirupsen/logrus/hooks/test"
"github.com/zalando/postgres-operator/v2/pkg/spec"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes/fake"
k8stesting "k8s.io/client-go/testing"
)

const (
Expand Down Expand Up @@ -93,3 +100,32 @@ func TestNodeIsReady(t *testing.T) {
}
}
}

// TestMoveMasterPodsOffNodeRetriesOnError ensures a failed attempt to move
// master pods off a node is retried rather than aborting the whole retry
// loop on the first error.
func TestMoveMasterPodsOffNodeRetriesOnError(t *testing.T) {
clientSet := fake.NewSimpleClientset()
clientSet.PrependReactor("list", "pods", func(action k8stesting.Action) (bool, runtime.Object, error) {
return true, nil, fmt.Errorf("could not list pods")
})

controller := newNodeTestController()
controller.KubeClient.PodsGetter = clientSet.CoreV1()
// timeout == the retry interval hardcoded in moveMasterPodsOffNode, so
// the single retry attempt resolves synchronously without a real sleep.
controller.opConfig.MasterPodMoveTimeout = &metav1.Duration{Duration: 1 * time.Minute}

logger, hook := logrustest.NewNullLogger()
controller.logger = logger.WithField("pkg", "controller")

controller.moveMasterPodsOffNode(makeNode(map[string]string{}, false))

lastEntry := hook.LastEntry()
if lastEntry == nil {
t.Fatal("expected moveMasterPodsOffNode to log a warning")
}
if !strings.Contains(lastEntry.Message, "still failing after") {
t.Errorf("expected the retry loop to run out of attempts instead of aborting on the first error, got log message: %q", lastEntry.Message)
}
}