Skip to content

Commit db590b2

Browse files
author
Joshua Anderson
committed
feat(client-go): added ps endpoint
1 parent 3b5bb9c commit db590b2

7 files changed

Lines changed: 675 additions & 0 deletions

File tree

client-go/cmd/ps.go

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"regexp"
6+
"strconv"
7+
"strings"
8+
"time"
9+
10+
"github.com/deis/deis/client-go/controller/api"
11+
"github.com/deis/deis/client-go/controller/models/ps"
12+
)
13+
14+
// PsList lists an app's processes.
15+
func PsList(appID string) error {
16+
c, appID, err := load(appID)
17+
18+
if err != nil {
19+
return err
20+
}
21+
22+
processes, err := ps.List(c, appID)
23+
24+
if err != nil {
25+
return err
26+
}
27+
28+
printProcesses(appID, processes)
29+
30+
return nil
31+
}
32+
33+
// PsScale scales an app's processes.
34+
func PsScale(appID string, targets []string) error {
35+
c, appID, err := load(appID)
36+
37+
if err != nil {
38+
return err
39+
}
40+
41+
targetMap := make(map[string]int)
42+
regex := regexp.MustCompile("^([A-z]+)=([0-9]+)$")
43+
44+
for _, target := range targets {
45+
if regex.MatchString(target) {
46+
captures := regex.FindStringSubmatch(target)
47+
targetMap[captures[1]], err = strconv.Atoi(captures[2])
48+
49+
if err != nil {
50+
return err
51+
}
52+
} else {
53+
fmt.Printf("'%s' does not match the pattern 'type=num', ex: web=2\n", target)
54+
}
55+
}
56+
57+
fmt.Printf("Scaling processes... but first, %s!\n", drinkOfChoice())
58+
startTime := time.Now()
59+
quit := progress()
60+
61+
err = ps.Scale(c, appID, targetMap)
62+
63+
quit <- true
64+
<-quit
65+
66+
if err != nil {
67+
return err
68+
}
69+
70+
fmt.Printf("done in %ds\n", int(time.Since(startTime).Seconds()))
71+
72+
processes, err := ps.List(c, appID)
73+
74+
if err != nil {
75+
return err
76+
}
77+
78+
printProcesses(appID, processes)
79+
return nil
80+
}
81+
82+
// PsRestart restarts an app's processes.
83+
func PsRestart(appID, target string) error {
84+
c, appID, err := load(appID)
85+
86+
if err != nil {
87+
return err
88+
}
89+
90+
psType := ""
91+
psNum := -1
92+
93+
if target != "" {
94+
if strings.Contains(target, ".") {
95+
parts := strings.Split(target, ".")
96+
psType = parts[0]
97+
psNum, err = strconv.Atoi(parts[1])
98+
99+
if err != nil {
100+
return err
101+
}
102+
} else {
103+
psType = target
104+
}
105+
}
106+
107+
fmt.Printf("Restarting processes... but first, %s!\n", drinkOfChoice())
108+
startTime := time.Now()
109+
quit := progress()
110+
111+
_, err = ps.Restart(c, appID, psType, psNum)
112+
113+
quit <- true
114+
<-quit
115+
116+
if err != nil {
117+
return err
118+
}
119+
120+
fmt.Printf("done in %ds\n", int(time.Since(startTime).Seconds()))
121+
122+
processes, err := ps.List(c, appID)
123+
124+
if err != nil {
125+
return err
126+
}
127+
128+
printProcesses(appID, processes)
129+
return nil
130+
}
131+
132+
func printProcesses(appID string, processes []api.Process) {
133+
psMap := ps.ByType(processes)
134+
135+
fmt.Printf("=== %s Processes\n", appID)
136+
137+
for psType, procs := range psMap {
138+
fmt.Printf("--- %s:\n", psType)
139+
140+
for _, proc := range procs {
141+
fmt.Printf("%s.%d %s (%s)\n", proc.Type, proc.Num, proc.State, proc.Release)
142+
}
143+
}
144+
}

client-go/cmd/utils.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package cmd
22

33
import (
44
"fmt"
5+
"os"
56
"strings"
67
"time"
78

@@ -66,3 +67,13 @@ func load(appID string) (*client.Client, string, error) {
6667

6768
return c, appID, nil
6869
}
70+
71+
func drinkOfChoice() string {
72+
drink := os.Getenv("DEIS_DRINK_OF_CHOICE")
73+
74+
if drink == "" {
75+
drink = "coffee"
76+
}
77+
78+
return drink
79+
}

client-go/controller/api/ps.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package api
2+
3+
// Process defines the structure of a process.
4+
type Process struct {
5+
Owner string `json:"owner"`
6+
App string `json:"app"`
7+
Release string `json:"release"`
8+
Created string `json:"created"`
9+
Updated string `json:"updated"`
10+
UUID string `json:"uuid"`
11+
Type string `json:"type"`
12+
Num int `json:"num"`
13+
State string `json:"state"`
14+
}
15+
16+
// Processes defines the structure of processes.
17+
type Processes struct {
18+
Count int `json:"count"`
19+
Next int `json:"next"`
20+
Previous int `json:"previous"`
21+
Processes []Process `json:"results"`
22+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package ps
2+
3+
import (
4+
"encoding/json"
5+
"errors"
6+
"fmt"
7+
"strconv"
8+
9+
"github.com/deis/deis/client-go/controller/api"
10+
"github.com/deis/deis/client-go/controller/client"
11+
)
12+
13+
// List an app's processes.
14+
func List(c *client.Client, appID string) ([]api.Process, error) {
15+
u := fmt.Sprintf("/v1/apps/%s/containers/", appID)
16+
body, status, err := c.BasicRequest("GET", u, nil)
17+
18+
if err != nil {
19+
return []api.Process{}, err
20+
}
21+
22+
if status != 200 {
23+
return []api.Process{}, errors.New(body)
24+
}
25+
26+
procs := api.Processes{}
27+
if err = json.Unmarshal([]byte(body), &procs); err != nil {
28+
return []api.Process{}, err
29+
}
30+
31+
return procs.Processes, nil
32+
}
33+
34+
// Scale an app's processes.
35+
func Scale(c *client.Client, appID string, targets map[string]int) error {
36+
u := fmt.Sprintf("/v1/apps/%s/scale/", appID)
37+
38+
body, err := json.Marshal(targets)
39+
40+
if err != nil {
41+
return err
42+
}
43+
44+
resBody, status, err := c.BasicRequest("POST", u, body)
45+
46+
if err != nil {
47+
return err
48+
}
49+
50+
if status != 204 {
51+
return errors.New(resBody)
52+
}
53+
54+
return nil
55+
}
56+
57+
// Restart an app's processes.
58+
func Restart(c *client.Client, appID string, procType string, num int) ([]api.Process, error) {
59+
u := fmt.Sprintf("/v1/apps/%s/containers/", appID)
60+
61+
if procType == "" {
62+
u += "restart/"
63+
} else {
64+
if num == -1 {
65+
u += procType + "/restart/"
66+
} else {
67+
u += procType + "/" + strconv.Itoa(num) + "/restart/"
68+
}
69+
}
70+
71+
body, status, err := c.BasicRequest("POST", u, nil)
72+
73+
if err != nil {
74+
return []api.Process{}, err
75+
}
76+
77+
if status != 200 {
78+
return []api.Process{}, errors.New(body)
79+
}
80+
81+
procs := []api.Process{}
82+
if err = json.Unmarshal([]byte(body), &procs); err != nil {
83+
return []api.Process{}, err
84+
}
85+
86+
return procs, nil
87+
}
88+
89+
// ByType organizes processes of an app by process type.
90+
func ByType(processes []api.Process) map[string][]api.Process {
91+
psMap := make(map[string][]api.Process)
92+
93+
for _, ps := range processes {
94+
psMap[ps.Type] = append(psMap[ps.Type], ps)
95+
}
96+
97+
return psMap
98+
}

0 commit comments

Comments
 (0)