mirror of
https://github.com/zalando/postgres-operator.git
synced 2026-09-30 18:06:37 +02:00
feature toggle for using maintenance windows (#3074)
* feature toggle for using maintenance windows
This commit is contained in:
@@ -105,6 +105,9 @@ var OperatorConfigCRDResourceValidation = apiextv1.CustomResourceValidation{
|
||||
"enable_lazy_spilo_upgrade": {
|
||||
Type: "boolean",
|
||||
},
|
||||
"enable_maintenance_windows": {
|
||||
Type: "boolean",
|
||||
},
|
||||
"enable_shm_volume": {
|
||||
Type: "boolean",
|
||||
},
|
||||
|
||||
@@ -266,6 +266,7 @@ type OperatorConfigurationData struct {
|
||||
Workers uint32 `json:"workers,omitempty"`
|
||||
ResyncPeriod Duration `json:"resync_period,omitempty"`
|
||||
RepairPeriod Duration `json:"repair_period,omitempty"`
|
||||
EnableMaintenanceWindows *bool `json:"enable_maintenance_windows,omitempty"`
|
||||
MaintenanceWindows []MaintenanceWindow `json:"maintenance_windows,omitempty"`
|
||||
SetMemoryRequestToLimit bool `json:"set_memory_request_to_limit,omitempty"`
|
||||
ShmVolume *bool `json:"enable_shm_volume,omitempty"`
|
||||
|
||||
@@ -433,6 +433,11 @@ func (in *OperatorConfigurationData) DeepCopyInto(out *OperatorConfigurationData
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.EnableMaintenanceWindows != nil {
|
||||
in, out := &in.EnableMaintenanceWindows, &out.EnableMaintenanceWindows
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
if in.MaintenanceWindows != nil {
|
||||
in, out := &in.MaintenanceWindows, &out.MaintenanceWindows
|
||||
*out = make([]MaintenanceWindow, len(*in))
|
||||
|
||||
+3
-1
@@ -675,7 +675,9 @@ func isStandbyCluster(spec *acidv1.PostgresSpec) bool {
|
||||
}
|
||||
|
||||
func (c *Cluster) isInMaintenanceWindow(specMaintenanceWindows []acidv1.MaintenanceWindow) bool {
|
||||
if len(specMaintenanceWindows) == 0 && len(c.OpConfig.MaintenanceWindows) == 0 {
|
||||
ignoreMaintenanceWindows := c.OpConfig.EnableMaintenanceWindows != nil && !*c.OpConfig.EnableMaintenanceWindows
|
||||
noWindowsDefined := len(specMaintenanceWindows) == 0 && len(c.OpConfig.MaintenanceWindows) == 0
|
||||
if noWindowsDefined || ignoreMaintenanceWindows {
|
||||
return true
|
||||
}
|
||||
now := time.Now()
|
||||
|
||||
@@ -660,6 +660,7 @@ func TestIsInMaintenanceWindow(t *testing.T) {
|
||||
cluster := New(
|
||||
Config{
|
||||
OpConfig: config.Config{
|
||||
EnableMaintenanceWindows: util.True(),
|
||||
Resources: config.Resources{
|
||||
ClusterLabels: map[string]string{"application": "spilo"},
|
||||
ClusterNameLabel: "cluster-name",
|
||||
@@ -683,12 +684,27 @@ func TestIsInMaintenanceWindow(t *testing.T) {
|
||||
name string
|
||||
windows []acidv1.MaintenanceWindow
|
||||
configWindows []string
|
||||
windowsFlag bool
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "no maintenance windows",
|
||||
windows: nil,
|
||||
configWindows: nil,
|
||||
windowsFlag: true,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "maintenance windows diabled",
|
||||
windows: []acidv1.MaintenanceWindow{
|
||||
{
|
||||
Everyday: true,
|
||||
StartTime: mustParseTime("00:00"),
|
||||
EndTime: mustParseTime("23:59"),
|
||||
},
|
||||
},
|
||||
configWindows: nil,
|
||||
windowsFlag: false,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
@@ -701,6 +717,7 @@ func TestIsInMaintenanceWindow(t *testing.T) {
|
||||
},
|
||||
},
|
||||
configWindows: nil,
|
||||
windowsFlag: true,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
@@ -713,6 +730,7 @@ func TestIsInMaintenanceWindow(t *testing.T) {
|
||||
},
|
||||
},
|
||||
configWindows: nil,
|
||||
windowsFlag: true,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
@@ -724,24 +742,35 @@ func TestIsInMaintenanceWindow(t *testing.T) {
|
||||
EndTime: mustParseTime(futureTimeEndFormatted),
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
windowsFlag: true,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "global maintenance windows with future interval time",
|
||||
windows: nil,
|
||||
configWindows: []string{fmt.Sprintf("%s-%s", futureTimeStartFormatted, futureTimeEndFormatted)},
|
||||
windowsFlag: true,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "global maintenance windows all day",
|
||||
windows: nil,
|
||||
configWindows: []string{"00:00-02:00", "02:00-23:59"},
|
||||
windowsFlag: true,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "global maintenance windows ignored",
|
||||
windows: nil,
|
||||
configWindows: []string{"00:00-02:00", "02:00-23:59"},
|
||||
windowsFlag: false,
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cluster.OpConfig.EnableMaintenanceWindows = &tt.windowsFlag
|
||||
cluster.OpConfig.MaintenanceWindows = tt.configWindows
|
||||
cluster.Spec.MaintenanceWindows = tt.windows
|
||||
if cluster.isInMaintenanceWindow(cluster.Spec.MaintenanceWindows) != tt.expected {
|
||||
|
||||
@@ -51,6 +51,7 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur
|
||||
result.ShmVolume = util.CoalesceBool(fromCRD.ShmVolume, util.True())
|
||||
result.SidecarImages = fromCRD.SidecarImages
|
||||
result.SidecarContainers = fromCRD.SidecarContainers
|
||||
result.EnableMaintenanceWindows = util.CoalesceBool(fromCRD.EnableMaintenanceWindows, util.True())
|
||||
if len(fromCRD.MaintenanceWindows) > 0 {
|
||||
result.MaintenanceWindows = make([]string, 0, len(fromCRD.MaintenanceWindows))
|
||||
for _, window := range fromCRD.MaintenanceWindows {
|
||||
|
||||
@@ -173,14 +173,15 @@ type Config struct {
|
||||
LogicalBackup
|
||||
ConnectionPooler
|
||||
|
||||
WatchedNamespace string `name:"watched_namespace"` // special values: "*" means 'watch all namespaces', the empty string "" means 'watch a namespace where operator is deployed to'
|
||||
KubernetesUseConfigMaps bool `name:"kubernetes_use_configmaps" default:"false"`
|
||||
EtcdHost string `name:"etcd_host" default:""` // special values: the empty string "" means Patroni will use K8s as a DCS
|
||||
MaintenanceWindows []string `name:"maintenance_windows"`
|
||||
DockerImage string `name:"docker_image" default:"ghcr.io/zalando/spilo-18:4.1-p1"`
|
||||
SidecarImages map[string]string `name:"sidecar_docker_images"` // deprecated in favour of SidecarContainers
|
||||
SidecarContainers []v1.Container `name:"sidecars"`
|
||||
PodServiceAccountName string `name:"pod_service_account_name" default:"postgres-pod"`
|
||||
WatchedNamespace string `name:"watched_namespace"` // special values: "*" means 'watch all namespaces', the empty string "" means 'watch a namespace where operator is deployed to'
|
||||
KubernetesUseConfigMaps bool `name:"kubernetes_use_configmaps" default:"false"`
|
||||
EtcdHost string `name:"etcd_host" default:""` // special values: the empty string "" means Patroni will use K8s as a DCS
|
||||
EnableMaintenanceWindows *bool `name:"enable_maintenance_windows" default:"true"`
|
||||
MaintenanceWindows []string `name:"maintenance_windows"`
|
||||
DockerImage string `name:"docker_image" default:"ghcr.io/zalando/spilo-18:4.1-p1"`
|
||||
SidecarImages map[string]string `name:"sidecar_docker_images"` // deprecated in favour of SidecarContainers
|
||||
SidecarContainers []v1.Container `name:"sidecars"`
|
||||
PodServiceAccountName string `name:"pod_service_account_name" default:"postgres-pod"`
|
||||
// value of this string must be valid JSON or YAML; see initPodServiceAccount
|
||||
PodServiceAccountDefinition string `name:"pod_service_account_definition" default:""`
|
||||
PodServiceAccountRoleBindingDefinition string `name:"pod_service_account_role_binding_definition" default:""`
|
||||
|
||||
Reference in New Issue
Block a user