Skip to content

Commit 0352ebb

Browse files
committed
chore(ps): add pod logs support
1 parent c385680 commit 0352ebb

8 files changed

Lines changed: 115 additions & 51 deletions

File tree

api/apps.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,8 @@ type AppUpdateRequest struct {
3030
type AppRunRequest struct {
3131
Command string `json:"command"`
3232
Volumes map[string]interface{} `json:"volumes,omitempty"`
33-
}
34-
35-
// AppRunResponse is the definition of /v2/apps/<app id>/run.
36-
type AppRunResponse struct {
37-
Output string `json:"output"`
38-
ReturnCode int `json:"exit_code"`
33+
Timeout uint32 `json:"timeout,omitempty"`
34+
Expires uint32 `json:"expires,omitempty"`
3935
}
4036

4137
// AppLogsRequest is the definition of websocket /v2/apps/<app id>/logs

api/ps.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@ type PodType struct {
4040
// PodTypes holds groups of pods organized by type.
4141
type PodTypes []PodType
4242

43+
// AppLogsRequest is the definition of websocket /v2/apps/<app id>/logs
44+
type PodLogsRequest struct {
45+
Lines int `json:"lines"`
46+
Follow bool `json:"follow"`
47+
Container string `json:"container"`
48+
}
49+
4350
// Start is the definition of POST /v2/apps/<app_id>/stop or POST /v2/apps/<app_id>/start.
4451
type Types struct {
4552
Types []string `json:"types,omitempty"`

apps/apps.go

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -119,31 +119,28 @@ func Logs(c *drycc.Client, appID string, request api.AppLogsRequest) (*websocket
119119

120120
// Run a one-time command in your app. This will start a kubernetes job with the
121121
// same container image and environment as the rest of the app.
122-
func Run(c *drycc.Client, appID string, command string, volumes map[string]interface{}) (api.AppRunResponse, error) {
122+
func Run(c *drycc.Client, appID string, command string, volumes map[string]interface{}, timeout, expires uint32) error {
123123
req := api.AppRunRequest{
124124
Command: command,
125125
Volumes: volumes,
126+
Timeout: timeout,
127+
Expires: expires,
126128
}
127129
body, err := json.Marshal(req)
128130

129131
if err != nil {
130-
return api.AppRunResponse{}, err
132+
return err
131133
}
132134

133135
u := fmt.Sprintf("/v2/apps/%s/run", appID)
134136

135137
res, reqErr := c.Request("POST", u, body)
136-
if reqErr != nil && !drycc.IsErrAPIMismatch(reqErr) {
137-
return api.AppRunResponse{}, reqErr
138-
}
139-
140-
arr := api.AppRunResponse{}
141138

142-
if err = json.NewDecoder(res.Body).Decode(&arr); err != nil {
143-
return api.AppRunResponse{}, err
139+
if reqErr != nil && !drycc.IsErrAPIMismatch(reqErr) {
140+
return reqErr
144141
}
145-
146-
return arr, reqErr
142+
defer res.Body.Close()
143+
return reqErr
147144
}
148145

149146
// Delete an app.

apps/apps_test.go

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ const appsFixture string = `
4343
}`
4444

4545
const appCreateExpected string = `{"id":"example-go"}`
46-
const appRunExpected string = `{"command":"echo hi"}`
46+
const appRunExpected string = `{"command":"echo hi","timeout":3600,"expires":3600}`
4747
const appTransferExpected string = `{"owner":"test"}`
4848

4949
type fakeHTTPServer struct {
@@ -227,11 +227,6 @@ func TestAppsDestroy(t *testing.T) {
227227
func TestAppsRun(t *testing.T) {
228228
t.Parallel()
229229

230-
expected := api.AppRunResponse{
231-
Output: "hi\n",
232-
ReturnCode: 0,
233-
}
234-
235230
handler := fakeHTTPServer{}
236231
server := httptest.NewServer(&handler)
237232
defer server.Close()
@@ -241,15 +236,9 @@ func TestAppsRun(t *testing.T) {
241236
t.Fatal(err)
242237
}
243238

244-
actual, err := Run(drycc, "example-go", "echo hi", nil)
245-
246-
if err != nil {
239+
if err := Run(drycc, "example-go", "echo hi", nil, 3600, 3600); err != nil {
247240
t.Fatal(err)
248241
}
249-
250-
if !reflect.DeepEqual(expected, actual) {
251-
t.Errorf("Expected %v, Got %v", expected, actual)
252-
}
253242
}
254243

255244
func TestAppsList(t *testing.T) {

auth/auth.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@ package auth
44
import (
55
"encoding/json"
66
"fmt"
7+
"net/http"
8+
79
drycc "github.com/drycc/controller-sdk-go"
810
"github.com/drycc/controller-sdk-go/api"
9-
"net/http"
1011
)
1112

1213
// Login to the controller and get a oauth url
1314
func Login(c *drycc.Client) (string, error) {
14-
c.HTTPClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {
15+
c.HTTPClient.CheckRedirect = func(*http.Request, []*http.Request) error {
1516
return http.ErrUseLastResponse
1617
}
1718
res, reqErr := c.Request("POST", "/v2/auth/login/", nil)

ps/ps.go

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,12 @@ func List(c *drycc.Client, appID string, results int) (api.PodsList, int, error)
3030
}
3131

3232
// Exec a command in a container.
33-
func Exec(c *drycc.Client, app, pod string, command api.Command) (*websocket.Conn, error) {
33+
func Exec(c *drycc.Client, appID, podID string, command api.Command) (*websocket.Conn, error) {
3434
scheme := "ws"
3535
if c.ControllerURL.Scheme == "https" {
3636
scheme = "wss"
3737
}
38-
path := fmt.Sprintf("v2/apps/%s/pods/%s/exec/", app, pod)
38+
path := fmt.Sprintf("v2/apps/%s/pods/%s/exec/", appID, podID)
3939
u := url.URL{Scheme: scheme, Host: c.ControllerURL.Host, Path: path}
4040
config, err := websocket.NewConfig(u.String(), c.ControllerURL.String())
4141
if err != nil {
@@ -54,6 +54,35 @@ func Exec(c *drycc.Client, app, pod string, command api.Command) (*websocket.Con
5454
return conn, nil
5555
}
5656

57+
// Logs retrieves logs from an pod. The number of log lines fetched can be set by the lines
58+
func Logs(c *drycc.Client, appID, podID string, request api.PodLogsRequest) (*websocket.Conn, error) {
59+
scheme := "ws"
60+
if c.ControllerURL.Scheme == "https" {
61+
scheme = "wss"
62+
}
63+
path := fmt.Sprintf("v2/apps/%s/pods/%s/logs/", appID, podID)
64+
endpoint := url.URL{Scheme: scheme, Host: c.ControllerURL.Host, Path: path}
65+
66+
config, err := websocket.NewConfig(endpoint.String(), c.ControllerURL.String())
67+
if err != nil {
68+
return nil, err
69+
}
70+
config.Header = http.Header{
71+
"User-Agent": {c.UserAgent},
72+
"Authorization": {"token " + c.Token},
73+
"X-Drycc-Builder-Auth": {c.HooksToken},
74+
}
75+
conn, err := websocket.DialConfig(config)
76+
if err != nil {
77+
return nil, err
78+
}
79+
err = websocket.JSON.Send(conn, request)
80+
if err != nil {
81+
return nil, err
82+
}
83+
return conn, nil
84+
}
85+
5786
// Scale increases or decreases an app's processes. The processes are specified in the target argument,
5887
// a key-value map, where the key is the process name and the value is the number of replicas
5988
func Scale(c *drycc.Client, appID string, targets map[string]int) error {
@@ -66,6 +95,9 @@ func Scale(c *drycc.Client, appID string, targets map[string]int) error {
6695
}
6796

6897
res, err := c.Request("POST", u, body)
98+
if err != nil && !drycc.IsErrAPIMismatch(err) {
99+
return err
100+
}
69101
defer res.Body.Close()
70102
return err
71103
}
@@ -83,6 +115,9 @@ func Restart(c *drycc.Client, appID string, procType string) error {
83115
}
84116

85117
res, err := c.Request("POST", u, nil)
118+
if err != nil && !drycc.IsErrAPIMismatch(err) {
119+
return err
120+
}
86121
defer res.Body.Close()
87122
return err
88123
}

ps/ps_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,47 @@ func TestExec(t *testing.T) {
156156
}
157157
}
158158

159+
func TestPodLogs(t *testing.T) {
160+
var once sync.Once
161+
var addr string
162+
163+
once.Do(func() {
164+
http.Handle(
165+
"/v2/apps/example-go/pods/example-go-web-111/logs/",
166+
websocket.Handler(func(conn *websocket.Conn) {
167+
io.Copy(conn, conn)
168+
}),
169+
)
170+
server := httptest.NewServer(nil)
171+
addr = server.Listener.Addr().String()
172+
log.Print("Test WebSocket server listening on ", addr)
173+
})
174+
175+
drycc, err := drycc.New(false, addr, "abc")
176+
if err != nil {
177+
t.Fatal(err)
178+
}
179+
180+
expected := api.PodLogsRequest{
181+
Lines: 100,
182+
Follow: true,
183+
Container: "runner",
184+
}
185+
186+
conn, err := Logs(drycc, "example-go", "example-go-web-111", expected)
187+
if err != nil {
188+
t.Fatal(err)
189+
}
190+
var actual api.PodLogsRequest
191+
err = websocket.JSON.Receive(conn, &actual)
192+
if err != nil {
193+
t.Fatal(err)
194+
}
195+
if !reflect.DeepEqual(actual, expected) {
196+
t.Errorf("Expected: %v, Got %v", expected, actual)
197+
}
198+
}
199+
159200
type testExpected struct {
160201
Name string
161202
Type string

tls/tls_test.go

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -84,16 +84,15 @@ func (fakeHTTPServer) ServeHTTP(res http.ResponseWriter, req *http.Request) {
8484
res.WriteHeader(http.StatusCreated)
8585
res.Write([]byte(issuerFixture))
8686
return
87-
} else {
88-
fmt.Printf("Expected '%s', %s or '%s', Got '%s'\n",
89-
tlsEnableExpected,
90-
tlsDisableExpected,
91-
issuerExpected,
92-
body)
93-
res.WriteHeader(http.StatusInternalServerError)
94-
res.Write(nil)
95-
return
9687
}
88+
fmt.Printf("Expected '%s', %s or '%s', Got '%s'\n",
89+
tlsEnableExpected,
90+
tlsDisableExpected,
91+
issuerExpected,
92+
body)
93+
res.WriteHeader(http.StatusInternalServerError)
94+
res.Write(nil)
95+
return
9796
}
9897

9998
fmt.Printf("Unrecongized URL %s\n", req.URL)
@@ -132,15 +131,14 @@ func (badJSONFakeHTTPServer) ServeHTTP(res http.ResponseWriter, req *http.Reques
132131
res.WriteHeader(http.StatusCreated)
133132
res.Write([]byte(issuerFixture + "blarg"))
134133
return
135-
} else {
136-
fmt.Printf("Expected '%s' or '%s', Got '%s'\n",
137-
tlsEnableExpected,
138-
tlsDisableExpected,
139-
body)
140-
res.WriteHeader(http.StatusInternalServerError)
141-
res.Write(nil)
142-
return
143134
}
135+
fmt.Printf("Expected '%s' or '%s', Got '%s'\n",
136+
tlsEnableExpected,
137+
tlsDisableExpected,
138+
body)
139+
res.WriteHeader(http.StatusInternalServerError)
140+
res.Write(nil)
141+
return
144142
}
145143

146144
fmt.Printf("Unrecongized URL %s\n", req.URL)

0 commit comments

Comments
 (0)