Skip to content

Commit ec466d7

Browse files
authored
feat(autoscale): add the ability to define autoscale rules per process type on an app (#208)
1 parent 0da35d8 commit ec466d7

7 files changed

Lines changed: 338 additions & 15 deletions

File tree

cmd/autoscale.go

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package cmd
2+
3+
import (
4+
"github.com/deis/controller-sdk-go/api"
5+
"github.com/deis/controller-sdk-go/appsettings"
6+
)
7+
8+
// AutoscaleList tells the informations about app's autoscale status
9+
func (d DeisCmd) AutoscaleList(appID string) error {
10+
s, appID, err := load(d.ConfigFile, appID)
11+
12+
if err != nil {
13+
return err
14+
}
15+
16+
appSettings, err := appsettings.List(s.Client, appID)
17+
if checkAPICompatibility(s.Client, err, d.WErr) != nil {
18+
return err
19+
}
20+
21+
d.Printf("=== %s Autoscale\n\n", appID)
22+
23+
if appSettings.Autoscale == nil {
24+
d.Println("No autoscale rules found.")
25+
} else {
26+
for process, kv := range appSettings.Autoscale {
27+
d.Println("--- " + process + ":")
28+
d.Println(*kv)
29+
}
30+
}
31+
32+
return nil
33+
}
34+
35+
// AutoscaleSet sets autoscale options for the app.
36+
func (d DeisCmd) AutoscaleSet(appID string, processType string, min int, max int, CPUPercent int) error {
37+
s, appID, err := load(d.ConfigFile, appID)
38+
39+
if err != nil {
40+
return err
41+
}
42+
43+
d.Printf("Applying autoscale settings for process type %s on %s... ", processType, appID)
44+
45+
quit := progress(d.WOut)
46+
data := map[string]*api.Autoscale{
47+
processType: {
48+
Min: min,
49+
Max: max,
50+
CPUPercent: CPUPercent,
51+
},
52+
}
53+
_, err = appsettings.Set(s.Client, appID, api.AppSettings{Autoscale: data})
54+
55+
quit <- true
56+
<-quit
57+
58+
if err != nil {
59+
return err
60+
}
61+
62+
d.Println("done")
63+
return nil
64+
}
65+
66+
// AutoscaleUnset removes autoscale for the app.
67+
func (d DeisCmd) AutoscaleUnset(appID string, processType string) error {
68+
s, appID, err := load(d.ConfigFile, appID)
69+
70+
if err != nil {
71+
return err
72+
}
73+
74+
d.Printf("Removing autoscale for process type %s on %s... ", processType, appID)
75+
76+
quit := progress(d.WOut)
77+
data := map[string]*api.Autoscale{
78+
processType: nil,
79+
}
80+
_, err = appsettings.Set(s.Client, appID, api.AppSettings{Autoscale: data})
81+
82+
quit <- true
83+
<-quit
84+
85+
if err != nil {
86+
return err
87+
}
88+
89+
d.Println("done")
90+
return nil
91+
}

cmd/autoscale_test.go

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package cmd
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
"net/http"
7+
"testing"
8+
9+
"github.com/arschles/assert"
10+
"github.com/deis/controller-sdk-go/api"
11+
"github.com/deis/workflow-cli/pkg/testutil"
12+
)
13+
14+
func TestAutoscaleList(t *testing.T) {
15+
t.Parallel()
16+
cf, server, err := testutil.NewTestServerAndClient()
17+
if err != nil {
18+
t.Fatal(err)
19+
}
20+
defer server.Close()
21+
var b bytes.Buffer
22+
cmdr := DeisCmd{WOut: &b, ConfigFile: cf}
23+
24+
server.Mux.HandleFunc("/v2/apps/rivendell/settings/", func(w http.ResponseWriter, r *http.Request) {
25+
testutil.SetHeaders(w)
26+
fmt.Fprintf(w, `{
27+
"owner": "elrond",
28+
"app": "rivendell",
29+
"autoscale": {"cmd": {"min": 3, "max": 8, "cpu_percent": 40}},
30+
"created": "2014-01-01T00:00:00UTC",
31+
"updated": "2014-01-01T00:00:00UTC",
32+
"uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
33+
}`)
34+
})
35+
36+
err = cmdr.AutoscaleList("rivendell")
37+
assert.NoErr(t, err)
38+
assert.Equal(t, b.String(), "=== rivendell Autoscale\n\n--- cmd:\nMin Replicas: 3\nMax Replicas: 8\nCPU: 40%\n", "output")
39+
40+
server.Mux.HandleFunc("/v2/apps/mordor/settings/", func(w http.ResponseWriter, r *http.Request) {
41+
testutil.SetHeaders(w)
42+
fmt.Fprintf(w, `{
43+
"owner": "sauron",
44+
"app": "mordor",
45+
"created": "2014-01-01T00:00:00UTC",
46+
"updated": "2014-01-01T00:00:00UTC",
47+
"uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75"
48+
}`)
49+
})
50+
b.Reset()
51+
52+
err = cmdr.AutoscaleList("mordor")
53+
assert.NoErr(t, err)
54+
assert.Equal(t, b.String(), "=== mordor Autoscale\n\nNo autoscale rules found.\n", "output")
55+
}
56+
57+
func TestAutoscaleSet(t *testing.T) {
58+
t.Parallel()
59+
cf, server, err := testutil.NewTestServerAndClient()
60+
if err != nil {
61+
t.Fatal(err)
62+
}
63+
defer server.Close()
64+
var b bytes.Buffer
65+
cmdr := DeisCmd{WOut: &b, ConfigFile: cf}
66+
67+
server.Mux.HandleFunc("/v2/apps/lothlorien/settings/", func(w http.ResponseWriter, r *http.Request) {
68+
testutil.SetHeaders(w)
69+
data := map[string]*api.Autoscale{
70+
"cmd": {
71+
Min: 3,
72+
Max: 8,
73+
CPUPercent: 40,
74+
},
75+
}
76+
testutil.AssertBody(t, api.AppSettings{Autoscale: data}, r)
77+
fmt.Fprintf(w, `{}`)
78+
})
79+
80+
err = cmdr.AutoscaleSet("lothlorien", "cmd", 3, 8, 40)
81+
assert.NoErr(t, err)
82+
assert.Equal(t, testutil.StripProgress(b.String()), "Applying autoscale settings for process type cmd on lothlorien... done\n", "output")
83+
}
84+
85+
func TestAutoscaleUnset(t *testing.T) {
86+
t.Parallel()
87+
cf, server, err := testutil.NewTestServerAndClient()
88+
if err != nil {
89+
t.Fatal(err)
90+
}
91+
defer server.Close()
92+
var b bytes.Buffer
93+
cmdr := DeisCmd{WOut: &b, ConfigFile: cf}
94+
95+
server.Mux.HandleFunc("/v2/apps/bree/settings/", func(w http.ResponseWriter, r *http.Request) {
96+
testutil.SetHeaders(w)
97+
testutil.AssertBody(t, api.AppSettings{Autoscale: map[string]*api.Autoscale{"cmd": nil}}, r)
98+
fmt.Fprintf(w, `{"autoscale":{"cmd":null}}`)
99+
})
100+
101+
err = cmdr.AutoscaleUnset("bree", "cmd")
102+
assert.NoErr(t, err)
103+
assert.Equal(t, testutil.StripProgress(b.String()), "Removing autoscale for process type cmd on bree... done\n", "output")
104+
}

cmd/cmd.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ type Commander interface {
1717
AppRun(string, string) error
1818
AppDestroy(string, string) error
1919
AppTransfer(string, string) error
20+
AutoscaleList(string) error
21+
AutoscaleSet(string, string, int, int, int) error
22+
AutoscaleUnset(string, string) error
2023
Register(string, string, string, string, bool) error
2124
Login(string, string, string, bool) error
2225
Logout() error

deis.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ Auth commands, use 'deis help auth' to learn more::
4646
Subcommands, use 'deis help [subcommand]' to learn more::
4747
4848
apps manage applications used to provide services
49+
autoscale manage autoscale for applications
4950
builds manage builds created using 'git push'
5051
certs manage SSL endpoints for an app
5152
config manage environment variables that define app config
@@ -105,6 +106,8 @@ Use 'git push deis master' to deploy to an application.
105106
err = parser.Apps(argv, &cmdr)
106107
case "auth":
107108
err = parser.Auth(argv, &cmdr)
109+
case "autoscale":
110+
err = parser.Autoscale(argv, &cmdr)
108111
case "builds":
109112
err = parser.Builds(argv, &cmdr)
110113
case "certs":

glide.lock

Lines changed: 13 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

glide.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@ import:
1616
- package: github.com/olekukonko/tablewriter
1717
- package: github.com/arschles/assert
1818
- package: github.com/deis/controller-sdk-go
19-
version: c7317175524ed7546731e3b1dd1296b533596c03
19+
version: 72235ec0aa14429beb569bf0b20984fc983d8aaa

0 commit comments

Comments
 (0)