diff --git a/manifests/postgresql.crd.yaml b/manifests/postgresql.crd.yaml index 0f7524bcc..d855b1812 100644 --- a/manifests/postgresql.crd.yaml +++ b/manifests/postgresql.crd.yaml @@ -462,11 +462,11 @@ spec: type: integer standby: type: object - required: - - s3_wal_path properties: s3_wal_path: type: string + gs_wal_path: + type: string teamId: type: string tls: diff --git a/pkg/cluster/k8sres_test.go b/pkg/cluster/k8sres_test.go index 0f99d5f31..c3c4a56bd 100644 --- a/pkg/cluster/k8sres_test.go +++ b/pkg/cluster/k8sres_test.go @@ -24,7 +24,6 @@ import ( "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/client-go/kubernetes/fake" v1core "k8s.io/client-go/kubernetes/typed/core/v1" ) @@ -47,11 +46,6 @@ type ExpectedValue struct { envVarValue string } -func toIntStr(val int) *intstr.IntOrString { - b := intstr.FromInt(val) - return &b -} - func TestGenerateSpiloJSONConfiguration(t *testing.T) { var cluster = New( Config{ @@ -311,7 +305,7 @@ func TestGeneratePodDisruptionBudget(t *testing.T) { Labels: map[string]string{"team": "myapp", "cluster-name": "myapp-database"}, }, Spec: policyv1beta1.PodDisruptionBudgetSpec{ - MinAvailable: toIntStr(1), + MinAvailable: util.ToIntStr(1), Selector: &metav1.LabelSelector{ MatchLabels: map[string]string{"spilo-role": "master", "cluster-name": "myapp-database"}, }, @@ -335,7 +329,7 @@ func TestGeneratePodDisruptionBudget(t *testing.T) { Labels: map[string]string{"team": "myapp", "cluster-name": "myapp-database"}, }, Spec: policyv1beta1.PodDisruptionBudgetSpec{ - MinAvailable: toIntStr(0), + MinAvailable: util.ToIntStr(0), Selector: &metav1.LabelSelector{ MatchLabels: map[string]string{"spilo-role": "master", "cluster-name": "myapp-database"}, }, @@ -359,7 +353,7 @@ func TestGeneratePodDisruptionBudget(t *testing.T) { Labels: map[string]string{"team": "myapp", "cluster-name": "myapp-database"}, }, Spec: policyv1beta1.PodDisruptionBudgetSpec{ - MinAvailable: toIntStr(0), + MinAvailable: util.ToIntStr(0), Selector: &metav1.LabelSelector{ MatchLabels: map[string]string{"spilo-role": "master", "cluster-name": "myapp-database"}, }, @@ -383,7 +377,7 @@ func TestGeneratePodDisruptionBudget(t *testing.T) { Labels: map[string]string{"team": "myapp", "cluster-name": "myapp-database"}, }, Spec: policyv1beta1.PodDisruptionBudgetSpec{ - MinAvailable: toIntStr(1), + MinAvailable: util.ToIntStr(1), Selector: &metav1.LabelSelector{ MatchLabels: map[string]string{"spilo-role": "master", "cluster-name": "myapp-database"}, }, diff --git a/pkg/cluster/pod.go b/pkg/cluster/pod.go index b5415dc4e..805112e29 100644 --- a/pkg/cluster/pod.go +++ b/pkg/cluster/pod.go @@ -514,11 +514,15 @@ func (c *Cluster) getSwitchoverCandidate(master *v1.Pod) (spec.NamespacedName, e // pick candidate with lowest lag // if sync_standby replicas were found assume synchronous_mode is enabled and ignore other candidates list if len(syncCandidates) > 0 { - sort.Slice(syncCandidates, func(i, j int) bool { return syncCandidates[i].LagInMb < syncCandidates[j].LagInMb }) + sort.Slice(syncCandidates, func(i, j int) bool { + return util.IntFromIntStr(syncCandidates[i].Lag) < util.IntFromIntStr(syncCandidates[j].Lag) + }) return spec.NamespacedName{Namespace: master.Namespace, Name: syncCandidates[0].Name}, nil } if len(candidates) > 0 { - sort.Slice(candidates, func(i, j int) bool { return candidates[i].LagInMb < candidates[j].LagInMb }) + sort.Slice(candidates, func(i, j int) bool { + return util.IntFromIntStr(candidates[i].Lag) < util.IntFromIntStr(candidates[j].Lag) + }) return spec.NamespacedName{Namespace: master.Namespace, Name: candidates[0].Name}, nil } diff --git a/pkg/util/patroni/patroni.go b/pkg/util/patroni/patroni.go index f030659ca..d3b2f28f0 100644 --- a/pkg/util/patroni/patroni.go +++ b/pkg/util/patroni/patroni.go @@ -16,6 +16,7 @@ import ( "github.com/sirupsen/logrus" acidv1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1" v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/util/intstr" ) const ( @@ -184,11 +185,11 @@ type ClusterMembers struct { // ClusterMember cluster member data from Patroni API type ClusterMember struct { - Name string `json:"name"` - Role string `json:"role"` - State string `json:"state"` - Timeline int `json:"timeline"` - LagInMb int `json:"lag"` + Name string `json:"name"` + Role string `json:"role"` + State string `json:"state"` + Timeline int `json:"timeline"` + Lag intstr.IntOrString `json:"lag,omitempty"` } // MemberDataPatroni child element diff --git a/pkg/util/patroni/patroni_test.go b/pkg/util/patroni/patroni_test.go index 48d27c8dc..2db721360 100644 --- a/pkg/util/patroni/patroni_test.go +++ b/pkg/util/patroni/patroni_test.go @@ -15,6 +15,7 @@ import ( acidv1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1" v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/util/intstr" ) var logger = logrus.New().WithField("test", "patroni") @@ -95,22 +96,22 @@ func TestGetClusterMembers(t *testing.T) { Role: "leader", State: "running", Timeline: 1, - LagInMb: 0, + Lag: intstr.IntOrString{IntVal: 0}, }, { Name: "acid-test-cluster-1", Role: "sync_standby", State: "running", Timeline: 1, - LagInMb: 0, + Lag: intstr.IntOrString{IntVal: 0}, }, { Name: "acid-test-cluster-2", Role: "replica", State: "running", Timeline: 1, - LagInMb: 0, + Lag: intstr.IntOrString{Type: 1, StrVal: "unknown"}, }} - 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}]}` + 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"}]}` r := ioutil.NopCloser(bytes.NewReader([]byte(json))) response := http.Response{ diff --git a/pkg/util/util.go b/pkg/util/util.go index a52925583..7efcccc18 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -19,6 +19,7 @@ import ( "github.com/motomux/pretty" resource "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" "github.com/zalando/postgres-operator/pkg/spec" "golang.org/x/crypto/pbkdf2" @@ -322,6 +323,20 @@ func testNil(values ...*int32) bool { return false } +// Convert int to IntOrString type +func ToIntStr(val int) *intstr.IntOrString { + b := intstr.FromInt(val) + return &b +} + +// Get int from IntOrString and return max int if string +func IntFromIntStr(intOrStr intstr.IntOrString) int { + if intOrStr.Type == 1 { + return 32 << (^int(0) >> 32 & 1) // return max int + } + return intOrStr.IntValue() +} + // MaxInt32 : Return maximum of two integers provided via pointers. If one value // is not defined, return the other one. If both are not defined, result is also // undefined, caller needs to check for that.