Skip to content

Commit 411abbe

Browse files
authored
handle case when Patroni returns that lag is unknown (zalando#1724)
* handle case when Patroni returns that lag is unknown * remove some prints from e2e test
1 parent 087c379 commit 411abbe

File tree

7 files changed

+38
-32
lines changed

7 files changed

+38
-32
lines changed

e2e/tests/test_e2e.py

-9
Original file line numberDiff line numberDiff line change
@@ -899,7 +899,6 @@ def test_node_affinity(self):
899899

900900
try:
901901
# patch current master node with the label
902-
print('patching master node: {}'.format(master_node))
903902
k8s.api.core_v1.patch_node(master_node, node_label_body)
904903

905904
# add node affinity to cluster
@@ -1636,12 +1635,8 @@ def list_databases(self, pod_name):
16361635
try:
16371636
q = exec_query.format(db_list_query, "postgres")
16381637
q = "su postgres -c \"{}\"".format(q)
1639-
print('Get databases: {}'.format(q))
16401638
result = k8s.exec_with_kubectl(pod_name, q)
16411639
db_list = clean_list(result.stdout.split(b'\n'))
1642-
print('db_list: {}, stdout: {}, stderr {}'.format(
1643-
db_list, result.stdout, result.stderr
1644-
))
16451640
except Exception as ex:
16461641
print('Could not get databases: {}'.format(ex))
16471642
print('Stdout: {}'.format(result.stdout))
@@ -1665,12 +1660,8 @@ def query_database(self, pod_name, db_name, query):
16651660
try:
16661661
q = exec_query.format(query, db_name)
16671662
q = "su postgres -c \"{}\"".format(q)
1668-
print('Send query: {}'.format(q))
16691663
result = k8s.exec_with_kubectl(pod_name, q)
16701664
result_set = clean_list(result.stdout.split(b'\n'))
1671-
print('result: {}, stdout: {}, stderr {}'.format(
1672-
result_set, result.stdout, result.stderr
1673-
))
16741665
except Exception as ex:
16751666
print('Error on query execution: {}'.format(ex))
16761667
print('Stdout: {}'.format(result.stdout))

manifests/postgresql.crd.yaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -462,11 +462,11 @@ spec:
462462
type: integer
463463
standby:
464464
type: object
465-
required:
466-
- s3_wal_path
467465
properties:
468466
s3_wal_path:
469467
type: string
468+
gs_wal_path:
469+
type: string
470470
teamId:
471471
type: string
472472
tls:

pkg/cluster/k8sres_test.go

+4-10
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import (
2424
"k8s.io/apimachinery/pkg/api/resource"
2525
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2626
"k8s.io/apimachinery/pkg/types"
27-
"k8s.io/apimachinery/pkg/util/intstr"
2827
"k8s.io/client-go/kubernetes/fake"
2928
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
3029
)
@@ -47,11 +46,6 @@ type ExpectedValue struct {
4746
envVarValue string
4847
}
4948

50-
func toIntStr(val int) *intstr.IntOrString {
51-
b := intstr.FromInt(val)
52-
return &b
53-
}
54-
5549
func TestGenerateSpiloJSONConfiguration(t *testing.T) {
5650
var cluster = New(
5751
Config{
@@ -311,7 +305,7 @@ func TestGeneratePodDisruptionBudget(t *testing.T) {
311305
Labels: map[string]string{"team": "myapp", "cluster-name": "myapp-database"},
312306
},
313307
Spec: policyv1beta1.PodDisruptionBudgetSpec{
314-
MinAvailable: toIntStr(1),
308+
MinAvailable: util.ToIntStr(1),
315309
Selector: &metav1.LabelSelector{
316310
MatchLabels: map[string]string{"spilo-role": "master", "cluster-name": "myapp-database"},
317311
},
@@ -335,7 +329,7 @@ func TestGeneratePodDisruptionBudget(t *testing.T) {
335329
Labels: map[string]string{"team": "myapp", "cluster-name": "myapp-database"},
336330
},
337331
Spec: policyv1beta1.PodDisruptionBudgetSpec{
338-
MinAvailable: toIntStr(0),
332+
MinAvailable: util.ToIntStr(0),
339333
Selector: &metav1.LabelSelector{
340334
MatchLabels: map[string]string{"spilo-role": "master", "cluster-name": "myapp-database"},
341335
},
@@ -359,7 +353,7 @@ func TestGeneratePodDisruptionBudget(t *testing.T) {
359353
Labels: map[string]string{"team": "myapp", "cluster-name": "myapp-database"},
360354
},
361355
Spec: policyv1beta1.PodDisruptionBudgetSpec{
362-
MinAvailable: toIntStr(0),
356+
MinAvailable: util.ToIntStr(0),
363357
Selector: &metav1.LabelSelector{
364358
MatchLabels: map[string]string{"spilo-role": "master", "cluster-name": "myapp-database"},
365359
},
@@ -383,7 +377,7 @@ func TestGeneratePodDisruptionBudget(t *testing.T) {
383377
Labels: map[string]string{"team": "myapp", "cluster-name": "myapp-database"},
384378
},
385379
Spec: policyv1beta1.PodDisruptionBudgetSpec{
386-
MinAvailable: toIntStr(1),
380+
MinAvailable: util.ToIntStr(1),
387381
Selector: &metav1.LabelSelector{
388382
MatchLabels: map[string]string{"spilo-role": "master", "cluster-name": "myapp-database"},
389383
},

pkg/cluster/pod.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -514,11 +514,15 @@ func (c *Cluster) getSwitchoverCandidate(master *v1.Pod) (spec.NamespacedName, e
514514
// pick candidate with lowest lag
515515
// if sync_standby replicas were found assume synchronous_mode is enabled and ignore other candidates list
516516
if len(syncCandidates) > 0 {
517-
sort.Slice(syncCandidates, func(i, j int) bool { return syncCandidates[i].LagInMb < syncCandidates[j].LagInMb })
517+
sort.Slice(syncCandidates, func(i, j int) bool {
518+
return util.IntFromIntStr(syncCandidates[i].Lag) < util.IntFromIntStr(syncCandidates[j].Lag)
519+
})
518520
return spec.NamespacedName{Namespace: master.Namespace, Name: syncCandidates[0].Name}, nil
519521
}
520522
if len(candidates) > 0 {
521-
sort.Slice(candidates, func(i, j int) bool { return candidates[i].LagInMb < candidates[j].LagInMb })
523+
sort.Slice(candidates, func(i, j int) bool {
524+
return util.IntFromIntStr(candidates[i].Lag) < util.IntFromIntStr(candidates[j].Lag)
525+
})
522526
return spec.NamespacedName{Namespace: master.Namespace, Name: candidates[0].Name}, nil
523527
}
524528

pkg/util/patroni/patroni.go

+6-5
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/sirupsen/logrus"
1717
acidv1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1"
1818
v1 "k8s.io/api/core/v1"
19+
"k8s.io/apimachinery/pkg/util/intstr"
1920
)
2021

2122
const (
@@ -184,11 +185,11 @@ type ClusterMembers struct {
184185

185186
// ClusterMember cluster member data from Patroni API
186187
type ClusterMember struct {
187-
Name string `json:"name"`
188-
Role string `json:"role"`
189-
State string `json:"state"`
190-
Timeline int `json:"timeline"`
191-
LagInMb int `json:"lag"`
188+
Name string `json:"name"`
189+
Role string `json:"role"`
190+
State string `json:"state"`
191+
Timeline int `json:"timeline"`
192+
Lag intstr.IntOrString `json:"lag,omitempty"`
192193
}
193194

194195
// MemberDataPatroni child element

pkg/util/patroni/patroni_test.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515

1616
acidv1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1"
1717
v1 "k8s.io/api/core/v1"
18+
"k8s.io/apimachinery/pkg/util/intstr"
1819
)
1920

2021
var logger = logrus.New().WithField("test", "patroni")
@@ -95,22 +96,21 @@ func TestGetClusterMembers(t *testing.T) {
9596
Role: "leader",
9697
State: "running",
9798
Timeline: 1,
98-
LagInMb: 0,
9999
}, {
100100
Name: "acid-test-cluster-1",
101101
Role: "sync_standby",
102102
State: "running",
103103
Timeline: 1,
104-
LagInMb: 0,
104+
Lag: intstr.IntOrString{IntVal: 0},
105105
}, {
106106
Name: "acid-test-cluster-2",
107107
Role: "replica",
108108
State: "running",
109109
Timeline: 1,
110-
LagInMb: 0,
110+
Lag: intstr.IntOrString{Type: 1, StrVal: "unknown"},
111111
}}
112112

113-
json := `{"members": [{"name": "acid-test-cluster-0", "role": "leader", "state": "running", "api_url": "http://192.168.100.1:8008/patroni", "host": "192.168.100.1", "port": 5432, "timeline": 1}, {"name": "acid-test-cluster-1", "role": "sync_standby", "state": "running", "api_url": "http://192.168.100.2:8008/patroni", "host": "192.168.100.2", "port": 5432, "timeline": 1, "lag": 0}, {"name": "acid-test-cluster-2", "role": "replica", "state": "running", "api_url": "http://192.168.100.3:8008/patroni", "host": "192.168.100.3", "port": 5432, "timeline": 1, "lag": 0}]}`
113+
json := `{"members": [{"name": "acid-test-cluster-0", "role": "leader", "state": "running", "api_url": "http://192.168.100.1:8008/patroni", "host": "192.168.100.1", "port": 5432, "timeline": 1}, {"name": "acid-test-cluster-1", "role": "sync_standby", "state": "running", "api_url": "http://192.168.100.2:8008/patroni", "host": "192.168.100.2", "port": 5432, "timeline": 1, "lag": 0}, {"name": "acid-test-cluster-2", "role": "replica", "state": "running", "api_url": "http://192.168.100.3:8008/patroni", "host": "192.168.100.3", "port": 5432, "timeline": 1, "lag": "unknown"}]}`
114114
r := ioutil.NopCloser(bytes.NewReader([]byte(json)))
115115

116116
response := http.Response{

pkg/util/util.go

+16
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"encoding/base64"
99
"encoding/hex"
1010
"fmt"
11+
"math"
1112
"math/big"
1213
"math/rand"
1314
"reflect"
@@ -19,6 +20,7 @@ import (
1920
"github.com/motomux/pretty"
2021
resource "k8s.io/apimachinery/pkg/api/resource"
2122
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
23+
"k8s.io/apimachinery/pkg/util/intstr"
2224

2325
"github.com/zalando/postgres-operator/pkg/spec"
2426
"golang.org/x/crypto/pbkdf2"
@@ -322,6 +324,20 @@ func testNil(values ...*int32) bool {
322324
return false
323325
}
324326

327+
// Convert int to IntOrString type
328+
func ToIntStr(val int) *intstr.IntOrString {
329+
b := intstr.FromInt(val)
330+
return &b
331+
}
332+
333+
// Get int from IntOrString and return max int if string
334+
func IntFromIntStr(intOrStr intstr.IntOrString) int {
335+
if intOrStr.Type == 1 {
336+
return math.MaxInt
337+
}
338+
return intOrStr.IntValue()
339+
}
340+
325341
// MaxInt32 : Return maximum of two integers provided via pointers. If one value
326342
// is not defined, return the other one. If both are not defined, result is also
327343
// undefined, caller needs to check for that.

0 commit comments

Comments
 (0)