mirror of
https://github.com/zalando/postgres-operator.git
synced 2026-10-18 18:39:41 +02:00
Merge branch 'master' into default-db-roles
This commit is contained in:
+18
-18
@@ -16,8 +16,8 @@ import (
|
||||
apiextbeta1 "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1beta1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/kubernetes/typed/apps/v1beta1"
|
||||
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
appsv1 "k8s.io/client-go/kubernetes/typed/apps/v1"
|
||||
corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
policyv1beta1 "k8s.io/client-go/kubernetes/typed/policy/v1beta1"
|
||||
rbacv1beta1 "k8s.io/client-go/kubernetes/typed/rbac/v1beta1"
|
||||
"k8s.io/client-go/rest"
|
||||
@@ -29,17 +29,17 @@ import (
|
||||
|
||||
// KubernetesClient describes getters for Kubernetes objects
|
||||
type KubernetesClient struct {
|
||||
v1core.SecretsGetter
|
||||
v1core.ServicesGetter
|
||||
v1core.EndpointsGetter
|
||||
v1core.PodsGetter
|
||||
v1core.PersistentVolumesGetter
|
||||
v1core.PersistentVolumeClaimsGetter
|
||||
v1core.ConfigMapsGetter
|
||||
v1core.NodesGetter
|
||||
v1core.NamespacesGetter
|
||||
v1core.ServiceAccountsGetter
|
||||
v1beta1.StatefulSetsGetter
|
||||
corev1.SecretsGetter
|
||||
corev1.ServicesGetter
|
||||
corev1.EndpointsGetter
|
||||
corev1.PodsGetter
|
||||
corev1.PersistentVolumesGetter
|
||||
corev1.PersistentVolumeClaimsGetter
|
||||
corev1.ConfigMapsGetter
|
||||
corev1.NodesGetter
|
||||
corev1.NamespacesGetter
|
||||
corev1.ServiceAccountsGetter
|
||||
appsv1.StatefulSetsGetter
|
||||
rbacv1beta1.RoleBindingsGetter
|
||||
policyv1beta1.PodDisruptionBudgetsGetter
|
||||
apiextbeta1.CustomResourceDefinitionsGetter
|
||||
@@ -50,14 +50,14 @@ type KubernetesClient struct {
|
||||
}
|
||||
|
||||
type mockSecret struct {
|
||||
v1core.SecretInterface
|
||||
corev1.SecretInterface
|
||||
}
|
||||
|
||||
type MockSecretGetter struct {
|
||||
}
|
||||
|
||||
type mockConfigMap struct {
|
||||
v1core.ConfigMapInterface
|
||||
corev1.ConfigMapInterface
|
||||
}
|
||||
|
||||
type MockConfigMapsGetter struct {
|
||||
@@ -101,7 +101,7 @@ func NewFromConfig(cfg *rest.Config) (KubernetesClient, error) {
|
||||
kubeClient.PersistentVolumesGetter = client.CoreV1()
|
||||
kubeClient.NodesGetter = client.CoreV1()
|
||||
kubeClient.NamespacesGetter = client.CoreV1()
|
||||
kubeClient.StatefulSetsGetter = client.AppsV1beta1()
|
||||
kubeClient.StatefulSetsGetter = client.AppsV1()
|
||||
kubeClient.PodDisruptionBudgetsGetter = client.PolicyV1beta1()
|
||||
kubeClient.RESTClient = client.CoreV1().RESTClient()
|
||||
kubeClient.RoleBindingsGetter = client.RbacV1beta1()
|
||||
@@ -215,12 +215,12 @@ func (c *mockConfigMap) Get(name string, options metav1.GetOptions) (*v1.ConfigM
|
||||
}
|
||||
|
||||
// Secrets to be mocked
|
||||
func (c *MockSecretGetter) Secrets(namespace string) v1core.SecretInterface {
|
||||
func (c *MockSecretGetter) Secrets(namespace string) corev1.SecretInterface {
|
||||
return &mockSecret{}
|
||||
}
|
||||
|
||||
// ConfigMaps to be mocked
|
||||
func (c *MockConfigMapsGetter) ConfigMaps(namespace string) v1core.ConfigMapInterface {
|
||||
func (c *MockConfigMapsGetter) ConfigMaps(namespace string) corev1.ConfigMapInterface {
|
||||
return &mockConfigMap{}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,9 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -43,8 +45,19 @@ func New(logger *logrus.Entry) *Patroni {
|
||||
}
|
||||
}
|
||||
|
||||
func apiURL(masterPod *v1.Pod) string {
|
||||
return fmt.Sprintf("http://%s:%d", masterPod.Status.PodIP, apiPort)
|
||||
func apiURL(masterPod *v1.Pod) (string, error) {
|
||||
ip := net.ParseIP(masterPod.Status.PodIP)
|
||||
if ip == nil {
|
||||
return "", fmt.Errorf("%s is not a valid IP", masterPod.Status.PodIP)
|
||||
}
|
||||
// Sanity check PodIP
|
||||
if ip.To4() == nil {
|
||||
if ip.To16() == nil {
|
||||
// Shouldn't ever get here, but library states it's possible.
|
||||
return "", fmt.Errorf("%s is not a valid IPv4/IPv6 address", masterPod.Status.PodIP)
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("http://%s", net.JoinHostPort(ip.String(), strconv.Itoa(apiPort))), nil
|
||||
}
|
||||
|
||||
func (p *Patroni) httpPostOrPatch(method string, url string, body *bytes.Buffer) (err error) {
|
||||
@@ -88,7 +101,11 @@ func (p *Patroni) Switchover(master *v1.Pod, candidate string) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not encode json: %v", err)
|
||||
}
|
||||
return p.httpPostOrPatch(http.MethodPost, apiURL(master)+failoverPath, buf)
|
||||
apiURLString, err := apiURL(master)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return p.httpPostOrPatch(http.MethodPost, apiURLString+failoverPath, buf)
|
||||
}
|
||||
|
||||
//TODO: add an option call /patroni to check if it is necessary to restart the server
|
||||
@@ -100,5 +117,9 @@ func (p *Patroni) SetPostgresParameters(server *v1.Pod, parameters map[string]st
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not encode json: %v", err)
|
||||
}
|
||||
return p.httpPostOrPatch(http.MethodPatch, apiURL(server)+configPath, buf)
|
||||
apiURLString, err := apiURL(server)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return p.httpPostOrPatch(http.MethodPatch, apiURLString+configPath, buf)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
package patroni
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"k8s.io/api/core/v1"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func newMockPod(ip string) *v1.Pod {
|
||||
return &v1.Pod{
|
||||
Status: v1.PodStatus{
|
||||
PodIP: ip,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestApiURL(t *testing.T) {
|
||||
var testTable = []struct {
|
||||
podIP string
|
||||
expectedResponse string
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
"127.0.0.1",
|
||||
fmt.Sprintf("http://127.0.0.1:%d", apiPort),
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"0000:0000:0000:0000:0000:0000:0000:0001",
|
||||
fmt.Sprintf("http://[::1]:%d", apiPort),
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"::1",
|
||||
fmt.Sprintf("http://[::1]:%d", apiPort),
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"",
|
||||
"",
|
||||
errors.New(" is not a valid IP"),
|
||||
},
|
||||
{
|
||||
"foobar",
|
||||
"",
|
||||
errors.New("foobar is not a valid IP"),
|
||||
},
|
||||
{
|
||||
"127.0.1",
|
||||
"",
|
||||
errors.New("127.0.1 is not a valid IP"),
|
||||
},
|
||||
{
|
||||
":::",
|
||||
"",
|
||||
errors.New("::: is not a valid IP"),
|
||||
},
|
||||
}
|
||||
for _, test := range testTable {
|
||||
resp, err := apiURL(newMockPod(test.podIP))
|
||||
if resp != test.expectedResponse {
|
||||
t.Errorf("expected response %v does not match the actual %v", test.expectedResponse, resp)
|
||||
}
|
||||
if err != test.expectedError {
|
||||
if err == nil || test.expectedError == nil {
|
||||
t.Errorf("expected error '%v' does not match the actual error '%v'", test.expectedError, err)
|
||||
}
|
||||
if err != nil && test.expectedError != nil && err.Error() != test.expectedError.Error() {
|
||||
t.Errorf("expected error '%v' does not match the actual error '%v'", test.expectedError, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user