Add end date support for OneTime schedule

This commit is contained in:
zlawrence 2022-12-12 19:04:22 +01:00
parent d01a3f6347
commit 37bf73c7fe
No known key found for this signature in database
GPG Key ID: 35E54C19196DDE3E
6 changed files with 101 additions and 4 deletions

View File

@ -58,6 +58,11 @@ spec:
description: The duration in minutes that the configured value
will be returned for the defined schedule.
type: integer
endDate:
description: Defines the ending date of a OneTime schedule.
It must be a RFC3339 formated date.
format: date-time
type: string
period:
description: Defines the details of a Repeating schedule.
properties:
@ -76,6 +81,10 @@ spec:
- Sat
type: string
type: array
endTime:
description: The endTime has the format HH:MM
pattern: (([0-1][0-9])|([2][0-3])):([0-5][0-9])
type: string
startTime:
description: The startTime has the format HH:MM
pattern: (([0-1][0-9])|([2][0-3])):([0-5][0-9])
@ -86,6 +95,7 @@ spec:
type: string
required:
- days
- endTime
- startTime
- timezone
type: object

View File

@ -58,6 +58,11 @@ spec:
description: The duration in minutes that the configured value
will be returned for the defined schedule.
type: integer
endDate:
description: Defines the ending date of a OneTime schedule.
It must be a RFC3339 formated date.
format: date-time
type: string
period:
description: Defines the details of a Repeating schedule.
properties:
@ -76,6 +81,10 @@ spec:
- Sat
type: string
type: array
endTime:
description: The endTime has the format HH:MM
pattern: (([0-1][0-9])|([2][0-3])):([0-5][0-9])
type: string
startTime:
description: The startTime has the format HH:MM
pattern: (([0-1][0-9])|([2][0-3])):([0-5][0-9])
@ -86,6 +95,7 @@ spec:
type: string
required:
- days
- endTime
- startTime
- timezone
type: object

View File

@ -61,6 +61,10 @@ type Schedule struct {
// be a RFC3339 formated date.
// +optional
Date *ScheduleDate `json:"date,omitempty"`
// Defines the ending date of a OneTime schedule. It must be
// a RFC3339 formated date.
// +optional
EndDate *ScheduleDate `json:"endDate,omitempty"`
// The duration in minutes that the configured value will be
// returned for the defined schedule.
DurationMinutes int `json:"durationMinutes"`
@ -90,6 +94,9 @@ type SchedulePeriod struct {
// The startTime has the format HH:MM
// +kubebuilder:validation:Pattern="(([0-1][0-9])|([2][0-3])):([0-5][0-9])"
StartTime string `json:"startTime"`
// The endTime has the format HH:MM
// +kubebuilder:validation:Pattern="(([0-1][0-9])|([2][0-3])):([0-5][0-9])"
EndTime string `json:"endTime"`
// The days that this schedule will be active.
Days []ScheduleDay `json:"days"`
// The location name corresponding to a file in the IANA

View File

@ -186,6 +186,11 @@ func (in *Schedule) DeepCopyInto(out *Schedule) {
*out = new(ScheduleDate)
**out = **in
}
if in.EndDate != nil {
in, out := &in.EndDate, &out.EndDate
*out = new(ScheduleDate)
**out = **in
}
return
}

View File

@ -259,6 +259,7 @@ func calculateMetrics(spec v1.ScalingScheduleSpec, defaultScalingWindow time.Dur
}
value := int64(0)
var scheduledEndTime time.Time
for _, schedule := range spec.Schedules {
switch schedule.Type {
case v1.RepeatingSchedule:
@ -292,7 +293,32 @@ func calculateMetrics(spec v1.ScalingScheduleSpec, defaultScalingWindow time.Dur
parsedStartTime.Nanosecond(),
location,
)
value = maxInt64(value, valueForEntry(now, scheduledTime, schedule.Duration(), scalingWindowDuration, rampSteps, schedule.Value))
// first check if an end time is provided
if schedule.Period.EndTime != "" {
parsedEndTime, err := time.Parse(hourColonMinuteLayout, schedule.Period.EndTime)
if err != nil {
return nil, ErrInvalidScheduleDate
}
scheduledEndTime = time.Date(
// v1.SchedulePeriod.StartTime can't define the
// year, month or day, so we compute it as the
// current date in the configured location.
nowInLocation.Year(),
nowInLocation.Month(),
nowInLocation.Day(),
// Hours and minute are configured in the
// v1.SchedulePeriod.StartTime.
parsedEndTime.Hour(),
parsedEndTime.Minute(),
parsedEndTime.Second(),
parsedEndTime.Nanosecond(),
location,
)
}
value = maxInt64(value, valueForEntry(now, scheduledTime, schedule.Duration(), scheduledEndTime, scalingWindowDuration, rampSteps, schedule.Value))
break
}
}
@ -302,7 +328,17 @@ func calculateMetrics(spec v1.ScalingScheduleSpec, defaultScalingWindow time.Dur
return nil, ErrInvalidScheduleDate
}
value = maxInt64(value, valueForEntry(now, scheduledTime, schedule.Duration(), scalingWindowDuration, rampSteps, schedule.Value))
// If no end time was provided, set it to equal the start time
if (string(*schedule.EndDate)) == "" {
scheduledEndTime = scheduledTime
} else {
scheduledEndTime, err = time.Parse(time.RFC3339, string(*schedule.EndDate))
if err != nil {
return nil, ErrInvalidScheduleDate
}
}
value = maxInt64(value, valueForEntry(now, scheduledTime, schedule.Duration(), scheduledEndTime, scalingWindowDuration, rampSteps, schedule.Value))
}
}
@ -320,9 +356,21 @@ func calculateMetrics(spec v1.ScalingScheduleSpec, defaultScalingWindow time.Dur
}, nil
}
func valueForEntry(timestamp time.Time, startTime time.Time, entryDuration time.Duration, scalingWindowDuration time.Duration, rampSteps int, value int64) int64 {
func valueForEntry(timestamp time.Time, startTime time.Time, entryDuration time.Duration, scheduledEndTime time.Time, scalingWindowDuration time.Duration, rampSteps int, value int64) int64 {
scaleUpStart := startTime.Add(-scalingWindowDuration)
endTime := startTime.Add(entryDuration)
var endTime time.Time
// Use either the defined end time/date or the start time/date + the
// duration, whichever is longer.
fmt.Println("-----")
fmt.Printf("starttime: %v\n", startTime)
fmt.Printf("end time: %v\n", scheduledEndTime)
if startTime.Add(entryDuration).Before(scheduledEndTime) {
endTime = scheduledEndTime
} else {
endTime = startTime.Add(entryDuration)
}
scaleUpEnd := endTime.Add(scalingWindowDuration)
if between(timestamp, startTime, endTime) {

View File

@ -21,6 +21,7 @@ const (
type schedule struct {
kind string
date string
endDate string
startTime string
days []v1.ScheduleDay
timezone string
@ -75,6 +76,19 @@ func TestScalingScheduleCollector(t *testing.T) {
},
expectedValue: 100,
},
{
msg: "Return 100 - utilise end date instead of start date + duration for one time config",
schedules: []schedule{
{
date: nowTime.Add(-2 * time.Hour).Format(time.RFC3339),
kind: "OneTime",
duration: 60,
endDate: nowTime.Add(1 * time.Hour).Format(time.RFC3339),
value: 100,
},
},
expectedValue: 100,
},
{
msg: "Return the right value for one time config - 30 seconds before ending",
schedules: []schedule{
@ -745,15 +759,18 @@ func newClusterMockStoreFirstRun(name string, scalingWindowDurationMinutes *int6
}
}
// comment DEBUG
func getSchedules(schedules []schedule) (result []v1.Schedule) {
for _, schedule := range schedules {
switch schedule.kind {
case string(v1.OneTimeSchedule):
date := v1.ScheduleDate(schedule.date)
endDate := v1.ScheduleDate(schedule.endDate)
result = append(result,
v1.Schedule{
Type: v1.OneTimeSchedule,
Date: &date,
EndDate: &endDate,
DurationMinutes: schedule.duration,
Value: schedule.value,
},