resolve conflict

This commit is contained in:
Felix Kunde
2022-01-24 17:51:24 +01:00
36 changed files with 804 additions and 208 deletions
+6 -5
View File
@@ -14,11 +14,12 @@ import (
// CRD describes CustomResourceDefinition specific configuration parameters
type CRD struct {
ReadyWaitInterval time.Duration `name:"ready_wait_interval" default:"4s"`
ReadyWaitTimeout time.Duration `name:"ready_wait_timeout" default:"30s"`
ResyncPeriod time.Duration `name:"resync_period" default:"30m"`
RepairPeriod time.Duration `name:"repair_period" default:"5m"`
EnableCRDValidation *bool `name:"enable_crd_validation" default:"true"`
ReadyWaitInterval time.Duration `name:"ready_wait_interval" default:"4s"`
ReadyWaitTimeout time.Duration `name:"ready_wait_timeout" default:"30s"`
ResyncPeriod time.Duration `name:"resync_period" default:"30m"`
RepairPeriod time.Duration `name:"repair_period" default:"5m"`
EnableCRDRegistration *bool `name:"enable_crd_registration" default:"true"`
EnableCRDValidation *bool `name:"enable_crd_validation" default:"true"`
}
// Resources describes kubernetes resource specific configuration parameters
+38
View File
@@ -16,11 +16,13 @@ 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 (
failoverPath = "/failover"
configPath = "/config"
clusterPath = "/cluster"
statusPath = "/patroni"
restartPath = "/restart"
apiPort = 8008
@@ -29,6 +31,7 @@ const (
// Interface describe patroni methods
type Interface interface {
GetClusterMembers(master *v1.Pod) ([]ClusterMember, error)
Switchover(master *v1.Pod, candidate string) error
SetPostgresParameters(server *v1.Pod, options map[string]string) error
GetMemberData(server *v1.Pod) (MemberData, error)
@@ -175,6 +178,20 @@ func (p *Patroni) SetConfig(server *v1.Pod, config map[string]interface{}) error
return p.httpPostOrPatch(http.MethodPatch, apiURLString+configPath, buf)
}
// ClusterMembers array of cluster members from Patroni API
type ClusterMembers struct {
Members []ClusterMember `json:"members"`
}
// 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"`
Lag intstr.IntOrString `json:"lag,omitempty"`
}
// MemberDataPatroni child element
type MemberDataPatroni struct {
Version string `json:"version"`
@@ -246,6 +263,27 @@ func (p *Patroni) Restart(server *v1.Pod) error {
return nil
}
// GetClusterMembers read cluster data from patroni API
func (p *Patroni) GetClusterMembers(server *v1.Pod) ([]ClusterMember, error) {
apiURLString, err := apiURL(server)
if err != nil {
return []ClusterMember{}, err
}
body, err := p.httpGet(apiURLString + clusterPath)
if err != nil {
return []ClusterMember{}, err
}
data := ClusterMembers{}
err = json.Unmarshal([]byte(body), &data)
if err != nil {
return []ClusterMember{}, err
}
return data.Members, nil
}
// GetMemberData read member data from patroni API
func (p *Patroni) GetMemberData(server *v1.Pod) (MemberData, error) {
+49
View File
@@ -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")
@@ -85,6 +86,54 @@ func TestApiURL(t *testing.T) {
}
}
func TestGetClusterMembers(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
expectedClusterMemberData := []ClusterMember{
{
Name: "acid-test-cluster-0",
Role: "leader",
State: "running",
Timeline: 1,
}, {
Name: "acid-test-cluster-1",
Role: "sync_standby",
State: "running",
Timeline: 1,
Lag: intstr.IntOrString{IntVal: 0},
}, {
Name: "acid-test-cluster-2",
Role: "replica",
State: "running",
Timeline: 1,
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": "unknown"}]}`
r := ioutil.NopCloser(bytes.NewReader([]byte(json)))
response := http.Response{
StatusCode: 200,
Body: r,
}
mockClient := mocks.NewMockHTTPClient(ctrl)
mockClient.EXPECT().Get(gomock.Any()).Return(&response, nil)
p := New(logger, mockClient)
clusterMemberData, err := p.GetClusterMembers(newMockPod("192.168.100.1"))
if !reflect.DeepEqual(expectedClusterMemberData, clusterMemberData) {
t.Errorf("Patroni cluster members differ: expected: %#v, got: %#v", expectedClusterMemberData, clusterMemberData)
}
if err != nil {
t.Errorf("Could not read Patroni data: %v", err)
}
}
func TestGetMemberData(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
+16
View File
@@ -8,6 +8,7 @@ import (
"encoding/base64"
"encoding/hex"
"fmt"
"math"
"math/big"
"math/rand"
"reflect"
@@ -19,6 +20,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 +324,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 math.MaxInt
}
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.