mirror of
https://github.com/zalando/postgres-operator.git
synced 2026-09-30 06:25:20 +02:00
Implement per-cluster maintenance window for Postgres automatic upgrade (#2710)
* implement maintenance window for major version upgrade * e2e test: fix major version upgrade test and extend with the time window * unit test: add iteration to test isInMaintenanceWindow * UI: show the window and enable edit via UI
This commit is contained in:
@@ -74,6 +74,11 @@ func (c *Cluster) majorVersionUpgrade() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !c.isInMainternanceWindow() {
|
||||
c.logger.Infof("skipping major version upgrade, not in maintenance window")
|
||||
return nil
|
||||
}
|
||||
|
||||
pods, err := c.listPods()
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -662,3 +662,24 @@ func parseResourceRequirements(resourcesRequirement v1.ResourceRequirements) (ac
|
||||
}
|
||||
return resources, nil
|
||||
}
|
||||
|
||||
func (c *Cluster) isInMainternanceWindow() bool {
|
||||
if c.Spec.MaintenanceWindows == nil {
|
||||
return true
|
||||
}
|
||||
now := time.Now()
|
||||
currentDay := now.Weekday()
|
||||
currentTime := now.Format("15:04")
|
||||
|
||||
for _, window := range c.Spec.MaintenanceWindows {
|
||||
startTime := window.StartTime.Format("15:04")
|
||||
endTime := window.EndTime.Format("15:04")
|
||||
|
||||
if window.Everyday || window.Weekday == currentDay {
|
||||
if currentTime >= startTime && currentTime <= endTime {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -27,6 +27,15 @@ import (
|
||||
|
||||
var externalAnnotations = map[string]string{"existing": "annotation"}
|
||||
|
||||
func mustParseTime(s string) metav1.Time {
|
||||
v, err := time.Parse("15:04", s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return metav1.Time{Time: v.UTC()}
|
||||
}
|
||||
|
||||
func newFakeK8sAnnotationsClient() (k8sutil.KubernetesClient, *k8sFake.Clientset) {
|
||||
clientSet := k8sFake.NewSimpleClientset()
|
||||
acidClientSet := fakeacidv1.NewSimpleClientset()
|
||||
@@ -521,3 +530,83 @@ func Test_trimCronjobName(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsInMaintenanceWindow(t *testing.T) {
|
||||
client, _ := newFakeK8sStreamClient()
|
||||
|
||||
var cluster = New(
|
||||
Config{
|
||||
OpConfig: config.Config{
|
||||
PodManagementPolicy: "ordered_ready",
|
||||
Resources: config.Resources{
|
||||
ClusterLabels: map[string]string{"application": "spilo"},
|
||||
ClusterNameLabel: "cluster-name",
|
||||
DefaultCPURequest: "300m",
|
||||
DefaultCPULimit: "300m",
|
||||
DefaultMemoryRequest: "300Mi",
|
||||
DefaultMemoryLimit: "300Mi",
|
||||
PodRoleLabel: "spilo-role",
|
||||
},
|
||||
},
|
||||
}, client, pg, logger, eventRecorder)
|
||||
|
||||
now := time.Now()
|
||||
futureTimeStart := now.Add(1 * time.Hour)
|
||||
futureTimeStartFormatted := futureTimeStart.Format("15:04")
|
||||
futureTimeEnd := now.Add(2 * time.Hour)
|
||||
futureTimeEndFormatted := futureTimeEnd.Format("15:04")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
windows []acidv1.MaintenanceWindow
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "no maintenance windows",
|
||||
windows: nil,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "maintenance windows with everyday",
|
||||
windows: []acidv1.MaintenanceWindow{
|
||||
{
|
||||
Everyday: true,
|
||||
StartTime: mustParseTime("00:00"),
|
||||
EndTime: mustParseTime("23:59"),
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "maintenance windows with weekday",
|
||||
windows: []acidv1.MaintenanceWindow{
|
||||
{
|
||||
Weekday: now.Weekday(),
|
||||
StartTime: mustParseTime("00:00"),
|
||||
EndTime: mustParseTime("23:59"),
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "maintenance windows with future interval time",
|
||||
windows: []acidv1.MaintenanceWindow{
|
||||
{
|
||||
Weekday: now.Weekday(),
|
||||
StartTime: mustParseTime(futureTimeStartFormatted),
|
||||
EndTime: mustParseTime(futureTimeEndFormatted),
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cluster.Spec.MaintenanceWindows = tt.windows
|
||||
if cluster.isInMainternanceWindow() != tt.expected {
|
||||
t.Errorf("Expected isInMainternanceWindow to return %t", tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user