Skip to content

Commit

Permalink
feat: scheduled autoscale
Browse files Browse the repository at this point in the history
  • Loading branch information
crgisch committed Nov 10, 2023
1 parent a667645 commit 6ac5ab7
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 12 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ require (
github.com/json-iterator/go v1.1.12 // indirect
github.com/kr/pretty v0.3.0 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/lnquy/cron v1.1.1 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
github.com/moby/sys/mount v0.3.0 // indirect
github.com/moby/sys/mountinfo v0.6.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,8 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3/go.mod h1:3r6x7q95whyfWQpmGZTu3gk3v2YkMi05HEzl7Tf7YEo=
github.com/lnquy/cron v1.1.1 h1:iaDX1ublgQ9LBhA8l9BVU+FrTE1PPSPAuvAdhgdnXgA=
github.com/lnquy/cron v1.1.1/go.mod h1:hu2Y7H68/8oKk6T4+K4qdbopbnaP4rGltK3ylWiiDss=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
Expand Down
58 changes: 49 additions & 9 deletions tsuru/client/apps.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"time"

"github.com/ajg/form"
"github.com/lnquy/cron"
"github.com/tsuru/gnuflag"
"github.com/tsuru/go-tsuruclient/pkg/client"
"github.com/tsuru/go-tsuruclient/pkg/tsuru"
Expand Down Expand Up @@ -743,22 +744,49 @@ func (a *app) String(simplified bool) string {
renderServiceInstanceBinds(&buf, a.ServiceInstanceBinds)
}

autoScaleTable := tablecli.NewTable()
autoScaleTable.Headers = tablecli.Row([]string{"Process", "Min", "Max", "Target CPU"})
var autoScaleTables []*tablecli.Table
processes := []string{}

for _, as := range a.AutoScale {
cpu := cpuValue(as.AverageCPU)
autoScaleTable := tablecli.NewTable()
autoScaleTable.LineSeparator = true

processString := fmt.Sprintf(
"Process: %s (v%d), Min Units: %d, Max Units: %d",
as.Process, as.Version, int(as.MinUnits), int(as.MaxUnits),
)
processes = append(processes, processString)

autoScaleTable.Headers = tablecli.Row([]string{
"Triggers",
"Trigger details",
})

autoScaleTable.AddRow(tablecli.Row([]string{
fmt.Sprintf("%s (v%d)", as.Process, as.Version),
strconv.Itoa(int(as.MinUnits)),
strconv.Itoa(int(as.MaxUnits)),
cpu,
"CPU",
"Target: 20%",
}))

for _, schedule := range as.Schedules {
scheduleInfo := buildScheduleInfo(schedule)
autoScaleTable.AddRow(tablecli.Row([]string{
"Schedule",
scheduleInfo,
}))
}

autoScaleTables = append(autoScaleTables, autoScaleTable)
}

if autoScaleTable.Rows() > 0 {
if len(processes) > 0 {
buf.WriteString("\n")
buf.WriteString("Auto Scale:\n")
buf.WriteString(autoScaleTable.String())
for i, asTable := range autoScaleTables {
buf.WriteString("\n")
buf.WriteString(processes[i])
buf.WriteString("\n")
buf.WriteString(asTable.String())
}
}

if !simplified && (a.Plan.Memory != 0 || a.Plan.CPUMilli != 0) {
Expand Down Expand Up @@ -789,6 +817,18 @@ func (a *app) String(simplified bool) string {
return tplBuffer.String() + buf.String()
}

func buildScheduleInfo(schedule tsuru.AutoScaleSchedule) string {
// Init with default EN locale
exprDesc, _ := cron.NewDescriptor()

startTimeHuman, _ := exprDesc.ToDescription(schedule.Start, cron.Locale_en)
endTimeHuman, _ := exprDesc.ToDescription(schedule.End, cron.Locale_en)

return fmt.Sprintf("Start: %s (%s)\nEnd: %s (%s)\nUnits: %d",
startTimeHuman, schedule.Start, endTimeHuman, schedule.End, schedule.MinReplicas,
)
}

func (a *app) SimpleServicesView() string {
sibs := make([]tsuru.AppServiceInstanceBinds, len(a.ServiceInstanceBinds))
copy(sibs, a.ServiceInstanceBinds)
Expand Down
34 changes: 31 additions & 3 deletions tsuru/client/autoscale.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package client

import (
"context"
"encoding/json"
"fmt"
"strconv"

Expand All @@ -29,13 +30,26 @@ type AutoScaleSet struct {
cmd.AppNameMixIn
fs *gnuflag.FlagSet
autoscale tsuru.AutoScaleSpec
schedules cmd.StringSliceFlag
}

func (c *AutoScaleSet) Info() *cmd.Info {
return &cmd.Info{
Name: "unit-autoscale-set",
Usage: "unit autoscale set [-a/--app appname] [-p/--process processname] [--cpu targetCPU] [--min minUnits] [--max maxUnits]",
Desc: `Sets a unit auto scale configuration.`,
Name: "unit-autoscale-set",
Usage: "unit autoscale set [-a/--app appname] [-p/--process processname] [--cpu targetCPU] [--min minUnits] [--max maxUnits] [--schedule scheduleWindow]",
Desc: `
# Sets an autoscale configuration:
# Based on 50% of CPU utilization with min units 1 and max units 3
unit autoscale set -a my-app --cpu 50% --min 1 --max 3
# Based on a schedule window everyday from 6AM to 6PM UTC
unit autoscale set -a my-app --min 1 --max 3 --schedule '{"minReplicas": 2, "start": "0 6 * * *", "end": "0 18 * * *"}'
# Combining both
unit autoscale set -a my-app --cpu 50% --min 1 --max 3 --schedule '{"minReplicas": 2, "start": "0 6 * * *", "end": "0 18 * * *"}'
# When using more than one trigger (CPU + Schedule as an exemple), the number of units will be determined by the highest value
`,
MinArgs: 0,
MaxArgs: 0,
}
Expand All @@ -54,6 +68,8 @@ func (c *AutoScaleSet) Flags() *gnuflag.FlagSet {
c.fs.Var((*int32Value)(&c.autoscale.MinUnits), "min", "Minimum Units")

c.fs.Var((*int32Value)(&c.autoscale.MaxUnits), "max", "Maximum Units")

c.fs.Var(&c.schedules, "schedule", "Schedule window to up/down scale. Example: {\"minReplicas\": 2, \"start\": \"0 6 * * *\", \"end\": \"0 18 * * *\"}")
}
return c.fs
}
Expand All @@ -70,6 +86,18 @@ func (c *AutoScaleSet) Run(ctx *cmd.Context, cli *cmd.Client) error {
return err
}

schedules := []tsuru.AutoScaleSchedule{}
for _, scheduleString := range c.schedules {
var autoScaleSchedule tsuru.AutoScaleSchedule
if err := json.Unmarshal([]byte(scheduleString), &autoScaleSchedule); err != nil {
return err
}

schedules = append(schedules, autoScaleSchedule)
}

c.autoscale.Schedules = schedules

_, err = apiClient.AppApi.AutoScaleAdd(context.TODO(), appName, c.autoscale)
if err != nil {
return err
Expand Down

0 comments on commit 6ac5ab7

Please sign in to comment.