mirror of
https://github.com/zalando-incubator/kube-metrics-adapter.git
synced 2025-07-04 09:03:46 +00:00
Add end date support for OneTime schedule
This commit is contained in:
@ -58,6 +58,11 @@ spec:
|
|||||||
description: The duration in minutes that the configured value
|
description: The duration in minutes that the configured value
|
||||||
will be returned for the defined schedule.
|
will be returned for the defined schedule.
|
||||||
type: integer
|
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:
|
period:
|
||||||
description: Defines the details of a Repeating schedule.
|
description: Defines the details of a Repeating schedule.
|
||||||
properties:
|
properties:
|
||||||
@ -76,6 +81,10 @@ spec:
|
|||||||
- Sat
|
- Sat
|
||||||
type: string
|
type: string
|
||||||
type: array
|
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:
|
startTime:
|
||||||
description: The startTime has the format HH:MM
|
description: The startTime has the format HH:MM
|
||||||
pattern: (([0-1][0-9])|([2][0-3])):([0-5][0-9])
|
pattern: (([0-1][0-9])|([2][0-3])):([0-5][0-9])
|
||||||
@ -86,6 +95,7 @@ spec:
|
|||||||
type: string
|
type: string
|
||||||
required:
|
required:
|
||||||
- days
|
- days
|
||||||
|
- endTime
|
||||||
- startTime
|
- startTime
|
||||||
- timezone
|
- timezone
|
||||||
type: object
|
type: object
|
||||||
|
@ -58,6 +58,11 @@ spec:
|
|||||||
description: The duration in minutes that the configured value
|
description: The duration in minutes that the configured value
|
||||||
will be returned for the defined schedule.
|
will be returned for the defined schedule.
|
||||||
type: integer
|
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:
|
period:
|
||||||
description: Defines the details of a Repeating schedule.
|
description: Defines the details of a Repeating schedule.
|
||||||
properties:
|
properties:
|
||||||
@ -76,6 +81,10 @@ spec:
|
|||||||
- Sat
|
- Sat
|
||||||
type: string
|
type: string
|
||||||
type: array
|
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:
|
startTime:
|
||||||
description: The startTime has the format HH:MM
|
description: The startTime has the format HH:MM
|
||||||
pattern: (([0-1][0-9])|([2][0-3])):([0-5][0-9])
|
pattern: (([0-1][0-9])|([2][0-3])):([0-5][0-9])
|
||||||
@ -86,6 +95,7 @@ spec:
|
|||||||
type: string
|
type: string
|
||||||
required:
|
required:
|
||||||
- days
|
- days
|
||||||
|
- endTime
|
||||||
- startTime
|
- startTime
|
||||||
- timezone
|
- timezone
|
||||||
type: object
|
type: object
|
||||||
|
@ -61,6 +61,10 @@ type Schedule struct {
|
|||||||
// be a RFC3339 formated date.
|
// be a RFC3339 formated date.
|
||||||
// +optional
|
// +optional
|
||||||
Date *ScheduleDate `json:"date,omitempty"`
|
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
|
// The duration in minutes that the configured value will be
|
||||||
// returned for the defined schedule.
|
// returned for the defined schedule.
|
||||||
DurationMinutes int `json:"durationMinutes"`
|
DurationMinutes int `json:"durationMinutes"`
|
||||||
@ -90,6 +94,9 @@ type SchedulePeriod struct {
|
|||||||
// The startTime has the format HH:MM
|
// The startTime has the format HH:MM
|
||||||
// +kubebuilder:validation:Pattern="(([0-1][0-9])|([2][0-3])):([0-5][0-9])"
|
// +kubebuilder:validation:Pattern="(([0-1][0-9])|([2][0-3])):([0-5][0-9])"
|
||||||
StartTime string `json:"startTime"`
|
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.
|
// The days that this schedule will be active.
|
||||||
Days []ScheduleDay `json:"days"`
|
Days []ScheduleDay `json:"days"`
|
||||||
// The location name corresponding to a file in the IANA
|
// The location name corresponding to a file in the IANA
|
||||||
|
@ -186,6 +186,11 @@ func (in *Schedule) DeepCopyInto(out *Schedule) {
|
|||||||
*out = new(ScheduleDate)
|
*out = new(ScheduleDate)
|
||||||
**out = **in
|
**out = **in
|
||||||
}
|
}
|
||||||
|
if in.EndDate != nil {
|
||||||
|
in, out := &in.EndDate, &out.EndDate
|
||||||
|
*out = new(ScheduleDate)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,6 +259,7 @@ func calculateMetrics(spec v1.ScalingScheduleSpec, defaultScalingWindow time.Dur
|
|||||||
}
|
}
|
||||||
|
|
||||||
value := int64(0)
|
value := int64(0)
|
||||||
|
var scheduledEndTime time.Time
|
||||||
for _, schedule := range spec.Schedules {
|
for _, schedule := range spec.Schedules {
|
||||||
switch schedule.Type {
|
switch schedule.Type {
|
||||||
case v1.RepeatingSchedule:
|
case v1.RepeatingSchedule:
|
||||||
@ -292,7 +293,32 @@ func calculateMetrics(spec v1.ScalingScheduleSpec, defaultScalingWindow time.Dur
|
|||||||
parsedStartTime.Nanosecond(),
|
parsedStartTime.Nanosecond(),
|
||||||
location,
|
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
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -302,7 +328,17 @@ func calculateMetrics(spec v1.ScalingScheduleSpec, defaultScalingWindow time.Dur
|
|||||||
return nil, ErrInvalidScheduleDate
|
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
|
}, 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)
|
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)
|
scaleUpEnd := endTime.Add(scalingWindowDuration)
|
||||||
|
|
||||||
if between(timestamp, startTime, endTime) {
|
if between(timestamp, startTime, endTime) {
|
||||||
|
@ -21,6 +21,7 @@ const (
|
|||||||
type schedule struct {
|
type schedule struct {
|
||||||
kind string
|
kind string
|
||||||
date string
|
date string
|
||||||
|
endDate string
|
||||||
startTime string
|
startTime string
|
||||||
days []v1.ScheduleDay
|
days []v1.ScheduleDay
|
||||||
timezone string
|
timezone string
|
||||||
@ -75,6 +76,19 @@ func TestScalingScheduleCollector(t *testing.T) {
|
|||||||
},
|
},
|
||||||
expectedValue: 100,
|
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",
|
msg: "Return the right value for one time config - 30 seconds before ending",
|
||||||
schedules: []schedule{
|
schedules: []schedule{
|
||||||
@ -745,15 +759,18 @@ func newClusterMockStoreFirstRun(name string, scalingWindowDurationMinutes *int6
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// comment DEBUG
|
||||||
func getSchedules(schedules []schedule) (result []v1.Schedule) {
|
func getSchedules(schedules []schedule) (result []v1.Schedule) {
|
||||||
for _, schedule := range schedules {
|
for _, schedule := range schedules {
|
||||||
switch schedule.kind {
|
switch schedule.kind {
|
||||||
case string(v1.OneTimeSchedule):
|
case string(v1.OneTimeSchedule):
|
||||||
date := v1.ScheduleDate(schedule.date)
|
date := v1.ScheduleDate(schedule.date)
|
||||||
|
endDate := v1.ScheduleDate(schedule.endDate)
|
||||||
result = append(result,
|
result = append(result,
|
||||||
v1.Schedule{
|
v1.Schedule{
|
||||||
Type: v1.OneTimeSchedule,
|
Type: v1.OneTimeSchedule,
|
||||||
Date: &date,
|
Date: &date,
|
||||||
|
EndDate: &endDate,
|
||||||
DurationMinutes: schedule.duration,
|
DurationMinutes: schedule.duration,
|
||||||
Value: schedule.value,
|
Value: schedule.value,
|
||||||
},
|
},
|
||||||
|
Reference in New Issue
Block a user