Merge pull request #258 from zalando-incubator/always-create-replica-service

[WIP] Always create replica service
This commit is contained in:
zerg-junior
2018-03-29 14:42:26 +02:00
committed by GitHub
11 changed files with 202 additions and 60 deletions
+2 -8
View File
@@ -217,9 +217,7 @@ func (c *Cluster) Create() error {
c.setStatus(spec.ClusterStatusCreating)
for _, role := range []PostgresRole{Master, Replica} {
if role == Replica && !c.Spec.ReplicaLoadBalancer {
continue
}
if c.Endpoints[role] != nil {
return fmt.Errorf("%s endpoint already exists in the cluster", role)
}
@@ -480,8 +478,7 @@ func (c *Cluster) Update(oldSpec, newSpec *spec.Postgresql) error {
// Service
if !reflect.DeepEqual(c.generateService(Master, &oldSpec.Spec), c.generateService(Master, &newSpec.Spec)) ||
!reflect.DeepEqual(c.generateService(Replica, &oldSpec.Spec), c.generateService(Replica, &newSpec.Spec)) ||
oldSpec.Spec.ReplicaLoadBalancer != newSpec.Spec.ReplicaLoadBalancer {
!reflect.DeepEqual(c.generateService(Replica, &oldSpec.Spec), c.generateService(Replica, &newSpec.Spec)) {
c.logger.Debugf("syncing services")
if err := c.syncServices(); err != nil {
c.logger.Errorf("could not sync services: %v", err)
@@ -589,9 +586,6 @@ func (c *Cluster) Delete() error {
}
for _, role := range []PostgresRole{Master, Replica} {
if role == Replica && !c.Spec.ReplicaLoadBalancer {
continue
}
if err := c.deleteEndpoint(role); err != nil {
return fmt.Errorf("could not delete %s endpoint: %v", role, err)
+48 -3
View File
@@ -669,6 +669,48 @@ func (c *Cluster) generateSingleUserSecret(namespace string, pgUser spec.PgUser)
return &secret
}
func (c *Cluster) shouldCreateLoadBalancerForService(role PostgresRole, spec *spec.PostgresSpec) bool {
switch role {
case Replica:
// deprecated option takes priority for backward compatibility
if spec.ReplicaLoadBalancer != nil {
c.logger.Debugf("The Postgres manifest for the cluster %v sets the deprecated `replicaLoadBalancer` param. Consider using the `enableReplicaLoadBalancer` instead.", c.Name)
return *spec.ReplicaLoadBalancer
}
// if the value is explicitly set in a Postgresql manifest, follow this setting
if spec.EnableReplicaLoadBalancer != nil {
return *spec.EnableReplicaLoadBalancer
}
// otherwise, follow the operator configuration
return c.OpConfig.EnableReplicaLoadBalancer
case Master:
if spec.UseLoadBalancer != nil {
c.logger.Debugf("The Postgres manifest for the cluster %v sets the deprecated `useLoadBalancer` param. Consider using the `enableMasterLoadBalancer` instead.", c.Name)
return *spec.UseLoadBalancer
}
// `enable_load_balancer`` governs LB for a master service
// there is no equivalent deprecated operator option for the replica LB
if c.OpConfig.EnableLoadBalancer != nil {
c.logger.Debugf("The operator configmap sets the deprecated `enable_load_balancer` param. Consider using the `enable_master_load_balancer` or `enable_replica_load_balancer` instead.", c.Name)
return *c.OpConfig.EnableLoadBalancer
}
return c.OpConfig.EnableMasterLoadBalancer
default:
panic(fmt.Sprintf("Unknown role %v", role))
}
}
func (c *Cluster) generateService(role PostgresRole, spec *spec.PostgresSpec) *v1.Service {
var dnsName string
@@ -689,12 +731,11 @@ func (c *Cluster) generateService(role PostgresRole, spec *spec.PostgresSpec) *v
var annotations map[string]string
// Examine the per-cluster load balancer setting, if it is not defined - check the operator configuration.
if (spec.UseLoadBalancer != nil && *spec.UseLoadBalancer) ||
(spec.UseLoadBalancer == nil && c.OpConfig.EnableLoadBalancer) {
if c.shouldCreateLoadBalancerForService(role, spec) {
// safe default value: lock load balancer to only local address unless overridden explicitly.
sourceRanges := []string{localHost}
allowedSourceRanges := spec.AllowedSourceRanges
if len(allowedSourceRanges) >= 0 {
sourceRanges = allowedSourceRanges
@@ -707,6 +748,10 @@ func (c *Cluster) generateService(role PostgresRole, spec *spec.PostgresSpec) *v
constants.ZalandoDNSNameAnnotation: dnsName,
constants.ElbTimeoutAnnotationName: constants.ElbTimeoutAnnotationValue,
}
} else if role == Replica {
// before PR #258, the replica service was only created if allocated a LB
// now we always create the service but warn if the LB is absent
c.logger.Debugf("No load balancer created for the replica service")
}
service := &v1.Service{
+94
View File
@@ -0,0 +1,94 @@
package cluster
import (
"github.com/zalando-incubator/postgres-operator/pkg/spec"
"github.com/zalando-incubator/postgres-operator/pkg/util/config"
"github.com/zalando-incubator/postgres-operator/pkg/util/k8sutil"
"testing"
)
func True() *bool {
b := true
return &b
}
func False() *bool {
b := false
return &b
}
func TestCreateLoadBalancerLogic(t *testing.T) {
var cluster = New(
Config{
OpConfig: config.Config{
ProtectedRoles: []string{"admin"},
Auth: config.Auth{
SuperUsername: superUserName,
ReplicationUsername: replicationUserName,
},
},
}, k8sutil.KubernetesClient{}, spec.Postgresql{}, logger)
testName := "TestCreateLoadBalancerLogic"
tests := []struct {
subtest string
role PostgresRole
spec *spec.PostgresSpec
opConfig config.Config
result bool
}{
{
subtest: "new format, load balancer is enabled for replica",
role: Replica,
spec: &spec.PostgresSpec{EnableReplicaLoadBalancer: True()},
opConfig: config.Config{},
result: true,
},
{
subtest: "new format, load balancer is disabled for replica",
role: Replica,
spec: &spec.PostgresSpec{EnableReplicaLoadBalancer: False()},
opConfig: config.Config{},
result: false,
},
{
subtest: "new format, load balancer isn't specified for replica",
role: Replica,
spec: &spec.PostgresSpec{EnableReplicaLoadBalancer: nil},
opConfig: config.Config{EnableReplicaLoadBalancer: true},
result: true,
},
{
subtest: "new format, load balancer isn't specified for replica",
role: Replica,
spec: &spec.PostgresSpec{EnableReplicaLoadBalancer: nil},
opConfig: config.Config{EnableReplicaLoadBalancer: false},
result: false,
},
{
subtest: "old format, load balancer is enabled for replica",
role: Replica,
spec: &spec.PostgresSpec{ReplicaLoadBalancer: True()},
opConfig: config.Config{},
result: true,
},
{
subtest: "old format has priority",
role: Replica,
spec: &spec.PostgresSpec{
ReplicaLoadBalancer: True(),
EnableReplicaLoadBalancer: False(),
},
opConfig: config.Config{},
result: true,
},
}
for _, tt := range tests {
cluster.OpConfig = tt.opConfig
result := cluster.shouldCreateLoadBalancerForService(tt.role, tt.spec)
if tt.result != result {
t.Errorf("%s %s: Load balancer is %t, expect %t for role %#v and spec %#v",
testName, tt.subtest, result, tt.result, tt.role, tt.spec)
}
}
}
-19
View File
@@ -108,11 +108,6 @@ func (c *Cluster) syncService(role PostgresRole) error {
svc, err := c.KubeClient.Services(c.Namespace).Get(c.serviceName(role), metav1.GetOptions{})
if err == nil {
if role == Replica && !c.Spec.ReplicaLoadBalancer {
if err := c.deleteService(role); err != nil {
return fmt.Errorf("could not delete %s service", role)
}
}
desiredSvc := c.generateService(role, &c.Spec)
match, reason := k8sutil.SameService(svc, desiredSvc)
@@ -133,11 +128,6 @@ func (c *Cluster) syncService(role PostgresRole) error {
}
c.Services[role] = nil
// Service does not exist
if role == Replica && !c.Spec.ReplicaLoadBalancer {
return nil
}
c.logger.Infof("could not find the cluster's %s service", role)
if svc, err := c.createService(role); err != nil {
@@ -165,11 +155,6 @@ func (c *Cluster) syncEndpoint(role PostgresRole) error {
ep, err := c.KubeClient.Endpoints(c.Namespace).Get(c.endpointName(role), metav1.GetOptions{})
if err == nil {
if role == Replica && !c.Spec.ReplicaLoadBalancer {
if err := c.deleteEndpoint(role); err != nil {
return fmt.Errorf("could not delete %s endpoint", role)
}
}
c.Endpoints[role] = ep
return nil
@@ -178,10 +163,6 @@ func (c *Cluster) syncEndpoint(role PostgresRole) error {
}
c.Endpoints[role] = nil
if role == Replica && !c.Spec.ReplicaLoadBalancer {
return nil
}
c.logger.Infof("could not find the cluster's %s endpoint", role)
if ep, err := c.createEndpoint(role); err != nil {