patch Pg config on spec.Patroni changes
This commit is contained in:
parent
fb1dc2265c
commit
b3f58f2f16
|
|
@ -81,7 +81,7 @@ func (ps *PostgresStatus) UnmarshalJSON(data []byte) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
metaErr := json.Unmarshal(data, &status)
|
metaErr := json.Unmarshal(data, &status)
|
||||||
if metaErr != nil {
|
if metaErr != nil {
|
||||||
return fmt.Errorf("Could not parse status: %v; err %v", string(data), metaErr)
|
return fmt.Errorf("could not parse status: %v; err %v", string(data), metaErr)
|
||||||
}
|
}
|
||||||
tmp.PostgresClusterStatus = status
|
tmp.PostgresClusterStatus = status
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@ package cluster
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -409,7 +411,7 @@ func (c *Cluster) syncStatefulSet() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if instanceRestartRequired {
|
if instanceRestartRequired {
|
||||||
c.logger.Debugln("restarting Postgres server within pods")
|
c.logger.Debugf("restarting Postgres server within pod %s", podName)
|
||||||
ttl, ok := config["ttl"].(int32)
|
ttl, ok := config["ttl"].(int32)
|
||||||
if !ok {
|
if !ok {
|
||||||
ttl = 30
|
ttl = 30
|
||||||
|
|
@ -494,29 +496,71 @@ func (c *Cluster) checkAndSetGlobalPostgreSQLConfiguration(pod *v1.Pod, patroniC
|
||||||
restartRequired bool
|
restartRequired bool
|
||||||
)
|
)
|
||||||
|
|
||||||
// we need to extract those options from the cluster manifest.
|
configToSet := make(map[string]interface{})
|
||||||
optionsToSet := make(map[string]string)
|
parametersToSet := make(map[string]string)
|
||||||
desiredConfig := c.Spec.Parameters
|
effectivePgParameters := make(map[string]interface{})
|
||||||
effectiveConfig := patroniConfig["postgresql"].(map[string]interface{})
|
|
||||||
effectiveParameters := effectiveConfig["parameters"].(map[string]interface{})
|
|
||||||
|
|
||||||
for desiredOption, desiredValue := range desiredConfig {
|
// read effective Patroni config if set
|
||||||
effectiveValue, exists := effectiveParameters[desiredOption]
|
if patroniConfig != nil {
|
||||||
if isBootstrapOnlyParameter(desiredOption) && (effectiveValue != desiredValue || !exists) {
|
effectivePostgresql := patroniConfig["postgresql"].(map[string]interface{})
|
||||||
optionsToSet[desiredOption] = desiredValue
|
effectivePgParameters = effectivePostgresql[patroniPGParametersParameterName].(map[string]interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// compare parameters under postgresql section with c.Spec.Postgresql.Parameters from manifest
|
||||||
|
desiredPgParameters := c.Spec.Parameters
|
||||||
|
for desiredOption, desiredValue := range desiredPgParameters {
|
||||||
|
effectiveValue := effectivePgParameters[desiredOption]
|
||||||
|
if isBootstrapOnlyParameter(desiredOption) && (effectiveValue != desiredValue) {
|
||||||
|
parametersToSet[desiredOption] = desiredValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(optionsToSet) == 0 {
|
if len(parametersToSet) > 0 {
|
||||||
|
configToSet["postgresql"] = map[string]interface{}{patroniPGParametersParameterName: parametersToSet}
|
||||||
|
}
|
||||||
|
|
||||||
|
// compare other options from config with c.Spec.Patroni from manifest
|
||||||
|
desiredPatroniConfig := c.Spec.Patroni
|
||||||
|
if desiredPatroniConfig.LoopWait > 0 && desiredPatroniConfig.LoopWait != uint32(patroniConfig["loop_wait"].(float64)) {
|
||||||
|
configToSet["loop_wait"] = desiredPatroniConfig.LoopWait
|
||||||
|
}
|
||||||
|
if desiredPatroniConfig.MaximumLagOnFailover > 0 && desiredPatroniConfig.MaximumLagOnFailover != float32(patroniConfig["maximum_lag_on_failover"].(float64)) {
|
||||||
|
configToSet["maximum_lag_on_failover"] = desiredPatroniConfig.MaximumLagOnFailover
|
||||||
|
}
|
||||||
|
if desiredPatroniConfig.PgHba != nil && !reflect.DeepEqual(desiredPatroniConfig.PgHba, (patroniConfig["pg_hba"])) {
|
||||||
|
configToSet["pg_hba"] = desiredPatroniConfig.PgHba
|
||||||
|
}
|
||||||
|
if desiredPatroniConfig.RetryTimeout > 0 && desiredPatroniConfig.RetryTimeout != uint32(patroniConfig["retry_timeout"].(float64)) {
|
||||||
|
configToSet["retry_timeout"] = desiredPatroniConfig.RetryTimeout
|
||||||
|
}
|
||||||
|
if desiredPatroniConfig.Slots != nil && !reflect.DeepEqual(desiredPatroniConfig.Slots, patroniConfig["slots"]) {
|
||||||
|
configToSet["slots"] = desiredPatroniConfig.Slots
|
||||||
|
}
|
||||||
|
if desiredPatroniConfig.SynchronousMode != patroniConfig["synchronous_mode"] {
|
||||||
|
configToSet["synchronous_mode"] = desiredPatroniConfig.SynchronousMode
|
||||||
|
}
|
||||||
|
if desiredPatroniConfig.SynchronousModeStrict != patroniConfig["synchronous_mode_strict"] {
|
||||||
|
configToSet["synchronous_mode_strict"] = desiredPatroniConfig.SynchronousModeStrict
|
||||||
|
}
|
||||||
|
if desiredPatroniConfig.TTL > 0 && desiredPatroniConfig.TTL != uint32(patroniConfig["ttl"].(float64)) {
|
||||||
|
configToSet["ttl"] = desiredPatroniConfig.TTL
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(configToSet) == 0 {
|
||||||
return restartRequired, nil
|
return restartRequired, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
configToSetJson, err := json.Marshal(configToSet)
|
||||||
|
if err != nil {
|
||||||
|
c.logger.Debugf("could not convert config patch to JSON: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
// try all pods until the first one that is successful, as it doesn't matter which pod
|
// try all pods until the first one that is successful, as it doesn't matter which pod
|
||||||
// carries the request to change configuration through
|
// carries the request to change configuration through
|
||||||
podName := util.NameFromMeta(pod.ObjectMeta)
|
podName := util.NameFromMeta(pod.ObjectMeta)
|
||||||
c.logger.Debugf("calling Patroni API on a pod %s to set the following Postgres options: %v",
|
c.logger.Debugf("calling Patroni API on a pod %s to set the following Postgres options: %s",
|
||||||
podName, optionsToSet)
|
podName, configToSetJson)
|
||||||
if err = c.patroni.SetPostgresParameters(pod, optionsToSet); err == nil {
|
if err = c.patroni.SetConfig(pod, configToSet); err == nil {
|
||||||
restartRequired = true
|
restartRequired = true
|
||||||
return restartRequired, nil
|
return restartRequired, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ type Interface interface {
|
||||||
GetMemberData(server *v1.Pod) (MemberData, error)
|
GetMemberData(server *v1.Pod) (MemberData, error)
|
||||||
Restart(server *v1.Pod) error
|
Restart(server *v1.Pod) error
|
||||||
GetConfig(server *v1.Pod) (map[string]interface{}, error)
|
GetConfig(server *v1.Pod) (map[string]interface{}, error)
|
||||||
|
SetConfig(server *v1.Pod, config map[string]interface{}) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Patroni API client
|
// Patroni API client
|
||||||
|
|
@ -163,6 +164,20 @@ func (p *Patroni) SetPostgresParameters(server *v1.Pod, parameters map[string]st
|
||||||
return p.httpPostOrPatch(http.MethodPatch, apiURLString+configPath, buf)
|
return p.httpPostOrPatch(http.MethodPatch, apiURLString+configPath, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//SetConfig sets Patroni options via Patroni patch API call.
|
||||||
|
func (p *Patroni) SetConfig(server *v1.Pod, config map[string]interface{}) error {
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
err := json.NewEncoder(buf).Encode(config)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not encode json: %v", err)
|
||||||
|
}
|
||||||
|
apiURLString, err := apiURL(server)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return p.httpPostOrPatch(http.MethodPatch, apiURLString+configPath, buf)
|
||||||
|
}
|
||||||
|
|
||||||
// MemberDataPatroni child element
|
// MemberDataPatroni child element
|
||||||
type MemberDataPatroni struct {
|
type MemberDataPatroni struct {
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue