fix condition to decide on syncing pooler

This commit is contained in:
Felix Kunde 2021-08-26 12:16:13 +02:00
parent 8a3b414cec
commit f32e186d66
3 changed files with 39 additions and 67 deletions

View File

@ -1006,9 +1006,9 @@ func (c *Cluster) initSystemUsers() {
// Connection pooler user is an exception, if requested it's going to be // Connection pooler user is an exception, if requested it's going to be
// created by operator as a normal pgUser // created by operator as a normal pgUser
if needConnectionPooler(&c.Spec) { if needConnectionPooler(&c.Spec) {
// initialize empty connection pooler if not done yet connectionPoolerSpec := c.Spec.ConnectionPooler
if c.Spec.ConnectionPooler == nil { if connectionPoolerSpec == nil {
c.Spec.ConnectionPooler = &acidv1.ConnectionPooler{} connectionPoolerSpec = &acidv1.ConnectionPooler{}
} }
// Using superuser as pooler user is not a good idea. First of all it's // Using superuser as pooler user is not a good idea. First of all it's
@ -1016,13 +1016,13 @@ func (c *Cluster) initSystemUsers() {
// and second it's a bad practice. // and second it's a bad practice.
username := c.OpConfig.ConnectionPooler.User username := c.OpConfig.ConnectionPooler.User
isSuperUser := c.Spec.ConnectionPooler.User == c.OpConfig.SuperUsername isSuperUser := connectionPoolerSpec.User == c.OpConfig.SuperUsername
isProtectedUser := c.shouldAvoidProtectedOrSystemRole( isProtectedUser := c.shouldAvoidProtectedOrSystemRole(
c.Spec.ConnectionPooler.User, "connection pool role") connectionPoolerSpec.User, "connection pool role")
if !isSuperUser && !isProtectedUser { if !isSuperUser && !isProtectedUser {
username = util.Coalesce( username = util.Coalesce(
c.Spec.ConnectionPooler.User, connectionPoolerSpec.User,
c.OpConfig.ConnectionPooler.User) c.OpConfig.ConnectionPooler.User)
} }

View File

@ -3,6 +3,7 @@ package cluster
import ( import (
"context" "context"
"fmt" "fmt"
"reflect"
"strings" "strings"
"github.com/r3labs/diff" "github.com/r3labs/diff"
@ -114,7 +115,7 @@ func (c *Cluster) createConnectionPooler(LookupFunction InstallFunction) (SyncRe
c.setProcessName("creating connection pooler") c.setProcessName("creating connection pooler")
//this is essentially sync with nil as oldSpec //this is essentially sync with nil as oldSpec
if reason, err := c.syncConnectionPooler(nil, &c.Postgresql, LookupFunction); err != nil { if reason, err := c.syncConnectionPooler(&acidv1.Postgresql{}, &c.Postgresql, LookupFunction); err != nil {
return reason, err return reason, err
} }
return reason, nil return reason, nil
@ -321,12 +322,13 @@ func (c *Cluster) generateConnectionPoolerDeployment(connectionPooler *Connectio
// default values, initialize it to an empty structure. It could be done // default values, initialize it to an empty structure. It could be done
// anywhere, but here is the earliest common entry point between sync and // anywhere, but here is the earliest common entry point between sync and
// create code, so init here. // create code, so init here.
if spec.ConnectionPooler == nil { connectionPoolerSpec := spec.ConnectionPooler
spec.ConnectionPooler = &acidv1.ConnectionPooler{} if connectionPoolerSpec == nil {
connectionPoolerSpec = &acidv1.ConnectionPooler{}
} }
podTemplate, err := c.generateConnectionPoolerPodTemplate(connectionPooler.Role) podTemplate, err := c.generateConnectionPoolerPodTemplate(connectionPooler.Role)
numberOfInstances := spec.ConnectionPooler.NumberOfInstances numberOfInstances := connectionPoolerSpec.NumberOfInstances
if numberOfInstances == nil { if numberOfInstances == nil {
numberOfInstances = util.CoalesceInt32( numberOfInstances = util.CoalesceInt32(
c.OpConfig.ConnectionPooler.NumberOfInstances, c.OpConfig.ConnectionPooler.NumberOfInstances,
@ -371,16 +373,6 @@ func (c *Cluster) generateConnectionPoolerDeployment(connectionPooler *Connectio
func (c *Cluster) generateConnectionPoolerService(connectionPooler *ConnectionPoolerObjects) *v1.Service { func (c *Cluster) generateConnectionPoolerService(connectionPooler *ConnectionPoolerObjects) *v1.Service {
spec := &c.Spec spec := &c.Spec
// there are two ways to enable connection pooler, either to specify a
// connectionPooler section or enableConnectionPooler. In the second case
// spec.connectionPooler will be nil, so to make it easier to calculate
// default values, initialize it to an empty structure. It could be done
// anywhere, but here is the earliest common entry point between sync and
// create code, so init here.
if spec.ConnectionPooler == nil {
spec.ConnectionPooler = &acidv1.ConnectionPooler{}
}
serviceSpec := v1.ServiceSpec{ serviceSpec := v1.ServiceSpec{
Ports: []v1.ServicePort{ Ports: []v1.ServicePort{
{ {
@ -693,15 +685,7 @@ func (c *Cluster) syncConnectionPooler(oldSpec, newSpec *acidv1.Postgresql, Look
var err error var err error
var connectionPoolerNeeded bool var connectionPoolerNeeded bool
if oldSpec == nil { needSync := !reflect.DeepEqual(oldSpec.Spec.ConnectionPooler, newSpec.Spec.ConnectionPooler)
oldSpec = &acidv1.Postgresql{
Spec: acidv1.PostgresSpec{
ConnectionPooler: &acidv1.ConnectionPooler{},
},
}
}
needSync, _ := needSyncConnectionPoolerSpecs(oldSpec.Spec.ConnectionPooler, newSpec.Spec.ConnectionPooler, c.logger)
masterChanges, err := diff.Diff(oldSpec.Spec.EnableConnectionPooler, newSpec.Spec.EnableConnectionPooler) masterChanges, err := diff.Diff(oldSpec.Spec.EnableConnectionPooler, newSpec.Spec.EnableConnectionPooler)
if err != nil { if err != nil {
c.logger.Error("Error in getting diff of master connection pooler changes") c.logger.Error("Error in getting diff of master connection pooler changes")
@ -711,15 +695,14 @@ func (c *Cluster) syncConnectionPooler(oldSpec, newSpec *acidv1.Postgresql, Look
c.logger.Error("Error in getting diff of replica connection pooler changes") c.logger.Error("Error in getting diff of replica connection pooler changes")
} }
// skip pooler sync only // skip pooler sync when theres no diff or it's deactivated
// 1. if there is no diff in spec, AND // but, handling the case when connectionPooler is not there but it is required
// 2. if connection pooler is already there and is also required as per newSpec
//
// Handling the case when connectionPooler is not there but it is required
// as per spec, hence do not skip syncing in that case, even though there // as per spec, hence do not skip syncing in that case, even though there
// is no diff in specs // is no diff in specs
if (!needSync && len(masterChanges) <= 0 && len(replicaChanges) <= 0) && if (!needSync && len(masterChanges) <= 0 && len(replicaChanges) <= 0) &&
(c.ConnectionPooler != nil && (needConnectionPooler(&newSpec.Spec))) { ((c.ConnectionPooler == nil && !needConnectionPooler(&newSpec.Spec)) ||
(c.ConnectionPooler != nil && needConnectionPooler(&newSpec.Spec) &&
c.ConnectionPooler[Master].LookupFunction && c.ConnectionPooler[Replica].LookupFunction)) {
c.logger.Debugln("syncing pooler is not required") c.logger.Debugln("syncing pooler is not required")
return nil, nil return nil, nil
} }
@ -761,7 +744,24 @@ func (c *Cluster) syncConnectionPooler(oldSpec, newSpec *acidv1.Postgresql, Look
// in this case also do not forget to install lookup function // in this case also do not forget to install lookup function
if !c.ConnectionPooler[role].LookupFunction { if !c.ConnectionPooler[role].LookupFunction {
if err = c.syncConnectionPoolerSchema(LookupFunction); err != nil { connectionPooler := c.Spec.ConnectionPooler
specSchema := ""
specUser := ""
if connectionPooler != nil {
specSchema = connectionPooler.Schema
specUser = connectionPooler.User
}
schema := util.Coalesce(
specSchema,
c.OpConfig.ConnectionPooler.Schema)
user := util.Coalesce(
specUser,
c.OpConfig.ConnectionPooler.User)
if err = LookupFunction(schema, user); err != nil {
return NoSync, err return NoSync, err
} }
c.ConnectionPooler[role].LookupFunction = true c.ConnectionPooler[role].LookupFunction = true
@ -849,8 +849,6 @@ func (c *Cluster) syncConnectionPoolerWorker(oldSpec, newSpec *acidv1.Postgresql
newConnectionPooler = &acidv1.ConnectionPooler{} newConnectionPooler = &acidv1.ConnectionPooler{}
} }
c.logger.Infof("old: %+v, new %+v", oldConnectionPooler, newConnectionPooler)
var specSync bool var specSync bool
var specReason []string var specReason []string
@ -917,29 +915,3 @@ func (c *Cluster) syncConnectionPoolerWorker(oldSpec, newSpec *acidv1.Postgresql
return NoSync, nil return NoSync, nil
} }
func (c *Cluster) syncConnectionPoolerSchema(LookupFunction InstallFunction) error {
connectionPooler := c.Spec.ConnectionPooler
specSchema := ""
specUser := ""
if connectionPooler != nil {
specSchema = connectionPooler.Schema
specUser = connectionPooler.User
}
schema := util.Coalesce(
specSchema,
c.OpConfig.ConnectionPooler.Schema)
user := util.Coalesce(
specUser,
c.OpConfig.ConnectionPooler.User)
if err := LookupFunction(schema, user); err != nil {
return err
}
return nil
}

View File

@ -759,9 +759,9 @@ func (c *Cluster) syncDatabases() error {
} }
if len(createDatabases) > 0 { if len(createDatabases) > 0 {
// create the pooler objects in new database if needed // trigger creation of pooler objects in new database in syncConnectionPooler
if c.ConnectionPooler != nil && needConnectionPooler(&c.Spec) { for _, role := range [2]PostgresRole{Master, Replica} {
c.syncConnectionPoolerSchema(c.installLookupFunction) c.ConnectionPooler[role].LookupFunction = false
} }
} }