Skip to content

Commit 421bd6d

Browse files
authored
fix: invalid switchover scheduling with default maintenance windows (zalando#3058)
1 parent d495825 commit 421bd6d

File tree

3 files changed

+63
-7
lines changed

3 files changed

+63
-7
lines changed

e2e/run.sh

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ readonly e2e_test_runner_image="ghcr.io/zalando/postgres-operator-e2e-tests-runn
1414
export GOPATH=${GOPATH-~/go}
1515
export PATH=${GOPATH}/bin:$PATH
1616

17+
# detect system architecture for pulling the correct Spilo image
18+
case "$(uname -m)" in
19+
x86_64) readonly PLATFORM="linux/amd64" ;;
20+
aarch64|arm64) readonly PLATFORM="linux/arm64" ;;
21+
*) echo "Unsupported architecture: $(uname -m)"; exit 1 ;;
22+
esac
23+
1724
echo "Clustername: ${cluster_name}"
1825
echo "Kubeconfig path: ${kubeconfig_path}"
1926

@@ -43,9 +50,8 @@ function start_kind(){
4350
export KUBECONFIG="${kubeconfig_path}"
4451
kind create cluster --name ${cluster_name} --config kind-cluster-postgres-operator-e2e-tests.yaml
4552

46-
# Pull all platforms to satisfy Kind's --all-platforms requirement
47-
docker pull --platform linux/amd64 "${spilo_image}"
48-
docker pull --platform linux/arm64 "${spilo_image}"
53+
echo "Pulling Spilo image for platform ${PLATFORM}"
54+
docker pull --platform ${PLATFORM} "${spilo_image}"
4955
kind load docker-image "${spilo_image}" --name ${cluster_name}
5056
}
5157

pkg/cluster/cluster.go

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1784,7 +1784,20 @@ func (c *Cluster) GetSwitchoverSchedule() string {
17841784
func (c *Cluster) getSwitchoverScheduleAtTime(now time.Time) string {
17851785
var possibleSwitchover, schedule time.Time
17861786

1787-
for _, window := range c.Spec.MaintenanceWindows {
1787+
maintenanceWindows := c.Spec.MaintenanceWindows
1788+
if len(maintenanceWindows) == 0 {
1789+
maintenanceWindows = make([]acidv1.MaintenanceWindow, 0, len(c.OpConfig.MaintenanceWindows))
1790+
for _, windowStr := range c.OpConfig.MaintenanceWindows {
1791+
var window acidv1.MaintenanceWindow
1792+
if err := window.UnmarshalJSON([]byte(windowStr)); err != nil {
1793+
c.logger.Errorf("could not parse default maintenance window %q: %v", windowStr, err)
1794+
continue
1795+
}
1796+
maintenanceWindows = append(maintenanceWindows, window)
1797+
}
1798+
}
1799+
1800+
for _, window := range maintenanceWindows {
17881801
// in the best case it is possible today
17891802
possibleSwitchover = time.Date(now.Year(), now.Month(), now.Day(), window.StartTime.Hour(), window.StartTime.Minute(), 0, 0, time.UTC)
17901803
if window.Everyday {
@@ -1806,6 +1819,11 @@ func (c *Cluster) getSwitchoverScheduleAtTime(now time.Time) string {
18061819
schedule = possibleSwitchover
18071820
}
18081821
}
1822+
1823+
if schedule.IsZero() {
1824+
return ""
1825+
}
1826+
18091827
return schedule.Format("2006-01-02T15:04+00")
18101828
}
18111829

pkg/cluster/cluster_test.go

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2125,10 +2125,13 @@ func TestGetSwitchoverSchedule(t *testing.T) {
21252125
pastWindowTimeStart := pastTimeStart.Format("15:04")
21262126
pastWindowTimeEnd := now.Add(-1 * time.Hour).Format("15:04")
21272127

2128+
defaultWindowStr := fmt.Sprintf("%s-%s", futureWindowTimeStart, futureWindowTimeEnd)
2129+
21282130
tests := []struct {
2129-
name string
2130-
windows []acidv1.MaintenanceWindow
2131-
expected string
2131+
name string
2132+
windows []acidv1.MaintenanceWindow
2133+
defaultWindows []string
2134+
expected string
21322135
}{
21332136
{
21342137
name: "everyday maintenance windows is later today",
@@ -2190,11 +2193,40 @@ func TestGetSwitchoverSchedule(t *testing.T) {
21902193
},
21912194
expected: pastTimeStart.AddDate(0, 0, 1).Format("2006-01-02T15:04+00"),
21922195
},
2196+
{
2197+
name: "fallback to operator default window when spec is empty",
2198+
windows: []acidv1.MaintenanceWindow{},
2199+
defaultWindows: []string{defaultWindowStr},
2200+
expected: futureTimeStart.Format("2006-01-02T15:04+00"),
2201+
},
2202+
{
2203+
name: "no windows defined returns empty string",
2204+
windows: []acidv1.MaintenanceWindow{},
2205+
defaultWindows: nil,
2206+
expected: "",
2207+
},
2208+
{
2209+
name: "choose the earliest window from multiple in spec",
2210+
windows: []acidv1.MaintenanceWindow{
2211+
{
2212+
Weekday: now.AddDate(0, 0, 2).Weekday(),
2213+
StartTime: mustParseTime(futureWindowTimeStart),
2214+
EndTime: mustParseTime(futureWindowTimeEnd),
2215+
},
2216+
{
2217+
Weekday: now.AddDate(0, 0, 1).Weekday(),
2218+
StartTime: mustParseTime(pastWindowTimeStart),
2219+
EndTime: mustParseTime(pastWindowTimeEnd),
2220+
},
2221+
},
2222+
expected: pastTimeStart.AddDate(0, 0, 1).Format("2006-01-02T15:04+00"),
2223+
},
21932224
}
21942225

21952226
for _, tt := range tests {
21962227
t.Run(tt.name, func(t *testing.T) {
21972228
cluster.Spec.MaintenanceWindows = tt.windows
2229+
cluster.OpConfig.MaintenanceWindows = tt.defaultWindows
21982230
schedule := cluster.getSwitchoverScheduleAtTime(now)
21992231
if schedule != tt.expected {
22002232
t.Errorf("Expected GetSwitchoverSchedule to return %s, returned: %s", tt.expected, schedule)

0 commit comments

Comments
 (0)