Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 28 additions & 4 deletions apis/vshn/v1/common_types.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package v1

import (
"strings"
"time"

xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
Expand Down Expand Up @@ -311,8 +312,31 @@ func (a *TimeOfDay) SetTime(t time.Time) {
*a = TimeOfDay(t.Format(time.TimeOnly))
}

// AddTime adds duration to current time
func (a *TimeOfDay) AddTime(d time.Duration) TimeOfDay {
a.SetTime(a.GetTime().Add(d))
return *a
// AddDuration adds duration to current time and returns the new time plus day offset.
func (a TimeOfDay) AddDuration(d time.Duration) (TimeOfDay, int) {
startTime := a.GetTime()
newTime := startTime.Add(d)

dayOffset := int(d.Hours() / 24)

// Adjust for additional day rollover from the time component
if d > 0 && newTime.Hour() < startTime.Hour() {
dayOffset++
}
if d < 0 && newTime.Hour() > startTime.Hour() {
dayOffset--
}

return TimeOfDay(newTime.Format(time.TimeOnly)), dayOffset
}

// AddDaysToWeekday adds days to a weekday and returns the new weekday.
func AddDaysToWeekday(weekday string, days int) string {
for wd := time.Sunday; wd <= time.Saturday; wd++ {
if strings.ToLower(wd.String()) == weekday {
newWd := (int(wd) + days%7 + 7) % 7
return strings.ToLower(time.Weekday(newWd).String())
}
}
return weekday
}
187 changes: 164 additions & 23 deletions apis/vshn/v1/common_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,40 +42,36 @@ func Test_GetTime(t *testing.T) {
}
}

func Test_AddTime(t *testing.T) {
func Test_AddDuration_BasicCases(t *testing.T) {
tests := []struct {
name string
scheduleSpec VSHNDBaaSMaintenanceScheduleSpec
d time.Duration
want string
name string
timeOfDay TimeOfDay
d time.Duration
want string
}{
{
name: "GivenNormalSchedule_ThenExpectAddedTimeOfDay",
scheduleSpec: VSHNDBaaSMaintenanceScheduleSpec{
TimeOfDay: TimeOfDay("00:30:00"),
},
d: 60 * time.Minute,
want: "01:30:00",
name: "GivenNormalSchedule_ThenExpectAddedTimeOfDay",
timeOfDay: TimeOfDay("00:30:00"),
d: 60 * time.Minute,
want: "01:30:00",
},
{
name: "GivenEmptyTimeOfDay_ThenExpectAddedTimeOfDay",
scheduleSpec: VSHNDBaaSMaintenanceScheduleSpec{
TimeOfDay: TimeOfDay(""),
},
d: 10 * time.Minute,
want: "00:10:00",
name: "GivenEmptyTimeOfDay_ThenExpectAddedTimeOfDay",
timeOfDay: TimeOfDay(""),
d: 10 * time.Minute,
want: "00:10:00",
},
{
name: "GivenNoTimeOfDay_ThenExpectAddedTimeOfDay",
scheduleSpec: VSHNDBaaSMaintenanceScheduleSpec{},
d: 5 * time.Minute,
want: "00:05:00",
name: "GivenNoTimeOfDay_ThenExpectAddedTimeOfDay",
timeOfDay: TimeOfDay(""),
d: 5 * time.Minute,
want: "00:05:00",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
actualTime := tt.scheduleSpec.TimeOfDay.AddTime(tt.d)
assert.Equal(t, tt.want, string(actualTime))
resultTime, _ := tt.timeOfDay.AddDuration(tt.d)
assert.Equal(t, tt.want, string(resultTime))
})
}
}
Expand Down Expand Up @@ -164,3 +160,148 @@ func Test_IsAppcatReleaseDisabled(t *testing.T) {
})
}
}

func Test_AddDuration(t *testing.T) {
tests := []struct {
name string
timeOfDay TimeOfDay
duration time.Duration
wantTime string
wantDayOffset int
}{
{
name: "GivenMidnightRollover_ThenExpectNextDay",
timeOfDay: TimeOfDay("23:50:00"),
duration: 20 * time.Minute,
wantTime: "00:10:00",
wantDayOffset: 1,
},
{
name: "GivenSameDay_ThenExpectNoDayOffset",
timeOfDay: TimeOfDay("10:00:00"),
duration: 30 * time.Minute,
wantTime: "10:30:00",
wantDayOffset: 0,
},
{
name: "GivenRolloverToMidnight_ThenExpectNextDay",
timeOfDay: TimeOfDay("23:00:00"),
duration: 1 * time.Hour,
wantTime: "00:00:00",
wantDayOffset: 1,
},
{
name: "GivenNegativeDuration_ThenExpectPreviousDay",
timeOfDay: TimeOfDay("00:10:00"),
duration: -20 * time.Minute,
wantTime: "23:50:00",
wantDayOffset: -1,
},
{
name: "GivenLargePositiveDuration_ThenExpectPositiveDayOffset",
timeOfDay: TimeOfDay("10:00:00"),
duration: 15 * time.Hour,
wantTime: "01:00:00",
wantDayOffset: 1,
},
{
name: "GivenExactly24Hours_ThenExpectOneDayOffset",
timeOfDay: TimeOfDay("10:00:00"),
duration: 24 * time.Hour,
wantTime: "10:00:00",
wantDayOffset: 1,
},
{
name: "Given25HoursWithRollover_ThenExpectTwoDayOffset",
timeOfDay: TimeOfDay("23:00:00"),
duration: 25 * time.Hour,
wantTime: "00:00:00",
wantDayOffset: 2,
},
{
name: "Given36HoursWithRollover_ThenExpectTwoDayOffset",
timeOfDay: TimeOfDay("12:00:00"),
duration: 36 * time.Hour,
wantTime: "00:00:00",
wantDayOffset: 2,
},
{
name: "Given50HoursWithRollover_ThenExpectThreeDayOffset",
timeOfDay: TimeOfDay("22:00:00"),
duration: 50 * time.Hour,
wantTime: "00:00:00",
wantDayOffset: 3,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
resultTime, dayOffset := tt.timeOfDay.AddDuration(tt.duration)
assert.Equal(t, tt.wantTime, string(resultTime), "Result time should match expected")
assert.Equal(t, tt.wantDayOffset, dayOffset, "Day offset should match expected")
})
}
}

func Test_AddDaysToWeekday(t *testing.T) {
tests := []struct {
name string
weekday string
days int
want string
}{
{
name: "GivenMondayPlus1_ThenExpectTuesday",
weekday: "monday",
days: 1,
want: "tuesday",
},
{
name: "GivenMondayPlus0_ThenExpectMonday",
weekday: "monday",
days: 0,
want: "monday",
},
{
name: "GivenSundayPlus1_ThenExpectMonday",
weekday: "sunday",
days: 1,
want: "monday",
},
{
name: "GivenMondayPlus7_ThenExpectMonday",
weekday: "monday",
days: 7,
want: "monday",
},
{
name: "GivenMondayMinus1_ThenExpectSunday",
weekday: "monday",
days: -1,
want: "sunday",
},
{
name: "GivenSaturdayPlus2_ThenExpectMonday",
weekday: "saturday",
days: 2,
want: "monday",
},
{
name: "GivenInvalidWeekday_ThenExpectUnchanged",
weekday: "invalid",
days: 1,
want: "invalid",
},
{
name: "GivenWednesdayPlus10_ThenExpectSaturday",
weekday: "wednesday",
days: 10,
want: "saturday",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := AddDaysToWeekday(tt.weekday, tt.days)
assert.Equal(t, tt.want, result)
})
}
}
17 changes: 15 additions & 2 deletions pkg/comp-functions/functions/common/postgresql.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package common
import (
"encoding/json"
"fmt"
"time"

"dario.cat/mergo"
xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
Expand All @@ -27,6 +28,7 @@ type PostgreSQLDependencyBuilder struct {
pgBouncerConfig map[string]string
pgSettings map[string]string
timeOfDayMaintenance vshnv1.TimeOfDay
dayOfWeekOverride string
restore *vshnv1.VSHNPostgreSQLRestore
}

Expand Down Expand Up @@ -60,8 +62,16 @@ func (a *PostgreSQLDependencyBuilder) AddPGSettings(pgSettings map[string]string
return a
}

func (a *PostgreSQLDependencyBuilder) SetCustomMaintenanceSchedule(timeOfDayMaintenance vshnv1.TimeOfDay) *PostgreSQLDependencyBuilder {
a.timeOfDayMaintenance = timeOfDayMaintenance
// SetCustomMaintenanceSchedule offsets the maintenance schedule by the given duration.
func (a *PostgreSQLDependencyBuilder) SetCustomMaintenanceSchedule(duration time.Duration) *PostgreSQLDependencyBuilder {
parentSchedule := a.comp.GetFullMaintenanceSchedule()
newTime, dayOffset := parentSchedule.TimeOfDay.AddDuration(duration)
a.timeOfDayMaintenance = newTime

if dayOffset != 0 {
a.dayOfWeekOverride = vshnv1.AddDaysToWeekday(parentSchedule.DayOfWeek, dayOffset)
}

return a
}

Expand Down Expand Up @@ -145,6 +155,9 @@ func (a *PostgreSQLDependencyBuilder) CreateDependency() (string, error) {
if a.timeOfDayMaintenance != "" {
params.Maintenance.TimeOfDay = a.timeOfDayMaintenance
}
if a.dayOfWeekOverride != "" {
params.Maintenance.DayOfWeek = a.dayOfWeekOverride
}
// We need to set this after the merge, as the default instance count for PostgreSQL is always 1
// and would therefore override any value we set before the merge.
params.Instances = a.comp.GetInstances()
Expand Down
2 changes: 1 addition & 1 deletion pkg/comp-functions/functions/vshnkeycloak/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ func DeployKeycloak(ctx context.Context, comp *vshnv1.VSHNKeycloak, svc *runtime
AddParameters(comp.Spec.Parameters.Service.PostgreSQLParameters).
AddPGBouncerConfig(pgBuncerConfig).
AddRestore(comp.Spec.Parameters.Restore, comp.Kind).
SetCustomMaintenanceSchedule(comp.Spec.Parameters.Maintenance.TimeOfDay.AddTime(20 * time.Minute)).
SetCustomMaintenanceSchedule(20 * time.Minute).
CreateDependency()
if err != nil {
return runtime.NewWarningResult(fmt.Sprintf("cannot create postgresql instance: %s", err))
Expand Down
5 changes: 1 addition & 4 deletions pkg/comp-functions/functions/vshnnextcloud/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,6 @@ func configureDatabase(ctx context.Context, comp *vshnv1.VSHNNextcloud, svc *run
}

func createNewPGService(comp *vshnv1.VSHNNextcloud, svc *runtime.ServiceRuntime) (pgSecret string, err error) {
var pgTime vshnv1.TimeOfDay
pgTime.SetTime(comp.GetMaintenanceTimeOfDay().GetTime().Add(20 * time.Minute))

pgBouncerConfig, pgSettings, pgDiskSize, err := getObservedPostgresSettings(svc, comp)
if err != nil {
return "", fmt.Errorf("cannot get observed postgres settings: %s", err)
Expand All @@ -151,7 +148,7 @@ func createNewPGService(comp *vshnv1.VSHNNextcloud, svc *runtime.ServiceRuntime)
AddParameters(comp.Spec.Parameters.Service.PostgreSQLParameters).
AddPGBouncerConfig(pgBouncerConfig).
AddPGSettings(pgSettings).
SetCustomMaintenanceSchedule(pgTime)
SetCustomMaintenanceSchedule(20 * time.Minute)

if pgDiskSize != "" {
pgBuilder.SetDiskSize(pgDiskSize)
Expand Down
Loading