Skip to content

Commit c3849cd

Browse files
jianxiaoguoduanhongyi
authored andcommitted
feat(pts): add pts support
* feat(controller-sdk-go): add fetch ptypes and events interface * feat(ps): support delete pods
1 parent 81d290b commit c3849cd

12 files changed

Lines changed: 609 additions & 109 deletions

File tree

api/events.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package api
2+
3+
import "github.com/drycc/controller-sdk-go/pkg/time"
4+
5+
// Event defines the structure of event.
6+
type AppEvent struct {
7+
Reason string `json:"reason"`
8+
Message string `json:"message"`
9+
Created time.Time `json:"created"`
10+
}
11+
12+
type AppEvents []AppEvent

api/ps.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,7 @@ type ContainerState struct {
7272

7373
// PodState defines a collection of container state.
7474
type PodState []ContainerState
75+
76+
type PodIDs struct {
77+
PodIDs string `json:"pod_ids"`
78+
}

api/pts.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package api
2+
3+
import "github.com/drycc/controller-sdk-go/pkg/time"
4+
5+
// Ptype defines the structure of ptype deployment.
6+
type Ptype struct {
7+
Name string `json:"name"`
8+
Release string `json:"release"`
9+
Ready string `json:"ready"`
10+
UpToDate int `json:"up_to_date"`
11+
AvailableReplicas int `json:"available_replicas"`
12+
Started time.Time `json:"started"`
13+
}
14+
15+
// Ptypes defines a collection of app Ptypes.
16+
type Ptypes []Ptype
17+
18+
func (d Ptypes) Len() int { return len(d) }
19+
func (d Ptypes) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
20+
func (d Ptypes) Less(i, j int) bool { return d[i].Name < d[j].Name }
21+
22+
// PtypeState defines a ptype deployment state.
23+
type PtypeState struct {
24+
Container string `json:"container"`
25+
Image string `json:"image"`
26+
Command []string `json:"command,omitempty"`
27+
Args []string `json:"args,omitempty"`
28+
LivenessProbe Healthcheck `json:"liveness_probe,omitempty"`
29+
ReadinessProbe Healthcheck `json:"readiness_probe,omitempty"`
30+
Limits map[string]string `json:"limits,omitempty"`
31+
VolumeMounts []VolumeMount `json:"volume_mounts,omitempty"`
32+
}
33+
34+
type VolumeMount struct {
35+
Name string `json:"name"`
36+
MountPath string `json:"mountPath"`
37+
}
38+
39+
// PtypesState defines a collection of container state.
40+
type PtypeStates []PtypeState

api/pts_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package api
2+
3+
import (
4+
"sort"
5+
"testing"
6+
7+
"github.com/drycc/controller-sdk-go/pkg/time"
8+
)
9+
10+
func TestPtypesSorted(t *testing.T) {
11+
ptypes := Ptypes{
12+
{"web", "v1", "1/1", 1, 1, time.Time{}},
13+
{"cronjob", "v1", "1/1", 1, 1, time.Time{}},
14+
{"sleep", "v1", "1/1", 1, 1, time.Time{}},
15+
}
16+
17+
sort.Sort(ptypes)
18+
19+
expectedPtypeNames := []string{"cronjob", "sleep", "web"}
20+
21+
for i, ptype := range ptypes {
22+
if expectedPtypeNames[i] != ptype.Name {
23+
t.Errorf("Expected ptypes to be sorted %v, Got %v", expectedPtypeNames[i], ptype.Name)
24+
}
25+
}
26+
}

events/events.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Package ps provides methods for managing app processes.
2+
package events
3+
4+
import (
5+
"encoding/json"
6+
"fmt"
7+
8+
drycc "github.com/drycc/controller-sdk-go"
9+
"github.com/drycc/controller-sdk-go/api"
10+
)
11+
12+
// List events of an app process.
13+
func ListPodEvents(c *drycc.Client, appID string, podName string, results int) (api.AppEvents, int, error) {
14+
u := fmt.Sprintf("/v2/apps/%s/events/?pod_name=%s", appID, podName)
15+
body, count, reqErr := c.LimitedRequest(u, results)
16+
if reqErr != nil && !drycc.IsErrAPIMismatch(reqErr) {
17+
return []api.AppEvent{}, -1, reqErr
18+
}
19+
20+
var events []api.AppEvent
21+
if err := json.Unmarshal([]byte(body), &events); err != nil {
22+
return []api.AppEvent{}, -1, err
23+
}
24+
25+
return events, count, reqErr
26+
}
27+
28+
// List events of an app ptype.
29+
func ListPtypeEvents(c *drycc.Client, appID string, ptype string, results int) (api.AppEvents, int, error) {
30+
u := fmt.Sprintf("/v2/apps/%s/events/?ptype_name=%s-%s", appID, appID, ptype)
31+
body, count, reqErr := c.LimitedRequest(u, results)
32+
if reqErr != nil && !drycc.IsErrAPIMismatch(reqErr) {
33+
return []api.AppEvent{}, -1, reqErr
34+
}
35+
36+
var events []api.AppEvent
37+
if err := json.Unmarshal([]byte(body), &events); err != nil {
38+
return []api.AppEvent{}, -1, err
39+
}
40+
41+
return events, count, reqErr
42+
}

events/events_test.go

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package events
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
"net/http/httptest"
7+
"reflect"
8+
"testing"
9+
10+
drycc "github.com/drycc/controller-sdk-go"
11+
"github.com/drycc/controller-sdk-go/api"
12+
"github.com/drycc/controller-sdk-go/pkg/time"
13+
)
14+
15+
const podEventsFixture string = `
16+
{
17+
"count": 1,
18+
"next": null,
19+
"previous": null,
20+
"results": [
21+
{
22+
"reason": "Scheduled",
23+
"message": "Successfully assigned example-go/example-go-web-6b44dbd6c8-h89cg to node1",
24+
"created": "2024-07-03T16:28:00"
25+
}
26+
]
27+
}`
28+
29+
const ptypeEventsFixture string = `
30+
{
31+
"count": 1,
32+
"next": null,
33+
"previous": null,
34+
"results": [
35+
{
36+
"reason": "ScalingReplicaSet",
37+
"message": "Scaled up replica set example-go-web-6b44dbd6c8 to 2 from 1",
38+
"created": "2024-07-03T16:28:00"
39+
}
40+
]
41+
}`
42+
43+
type fakeHTTPServer struct{}
44+
45+
func (fakeHTTPServer) ServeHTTP(res http.ResponseWriter, req *http.Request) {
46+
res.Header().Add("DRYCC_API_VERSION", drycc.APIVersion)
47+
if req.URL.Path == "/v2/apps/example-go/events/" && req.Method == "GET" && req.URL.RawQuery == "ptype_name=example-go-web" {
48+
res.Write([]byte(ptypeEventsFixture))
49+
return
50+
}
51+
if req.URL.Path == "/v2/apps/example-go/events/" && req.Method == "GET" && req.URL.RawQuery == "pod_name=example-go-web-6b44dbd6c8-h89cg" {
52+
res.Write([]byte(podEventsFixture))
53+
return
54+
}
55+
56+
fmt.Printf("Unrecognized URL %s\n", req.URL)
57+
res.WriteHeader(http.StatusNotFound)
58+
res.Write(nil)
59+
}
60+
61+
func TestEvents(t *testing.T) {
62+
t.Parallel()
63+
64+
created := time.Time{}
65+
created.UnmarshalText([]byte("2024-07-03T16:28:00"))
66+
podExpected := api.AppEvents{
67+
{
68+
Reason: "Scheduled",
69+
Message: "Successfully assigned example-go/example-go-web-6b44dbd6c8-h89cg to node1",
70+
Created: created,
71+
},
72+
}
73+
ptypeExpected := api.AppEvents{
74+
{
75+
Reason: "ScalingReplicaSet",
76+
Message: "Scaled up replica set example-go-web-6b44dbd6c8 to 2 from 1",
77+
Created: created,
78+
},
79+
}
80+
81+
handler := fakeHTTPServer{}
82+
server := httptest.NewServer(handler)
83+
defer server.Close()
84+
85+
drycc, err := drycc.New(false, server.URL, "abc")
86+
if err != nil {
87+
t.Fatal(err)
88+
}
89+
90+
actual, _, err := ListPodEvents(drycc, "example-go", "example-go-web-6b44dbd6c8-h89cg", 100)
91+
92+
if err != nil {
93+
t.Fatal(err)
94+
}
95+
96+
if !reflect.DeepEqual(podExpected, actual) {
97+
t.Error(fmt.Errorf("Expected %v, Got %v", podExpected, actual))
98+
}
99+
100+
actual, _, err = ListPtypeEvents(drycc, "example-go", "web", 100)
101+
102+
if err != nil {
103+
t.Fatal(err)
104+
}
105+
106+
if !reflect.DeepEqual(ptypeExpected, actual) {
107+
t.Error(fmt.Errorf("Expected %v, Got %v", ptypeExpected, actual))
108+
}
109+
}

go.mod

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ module github.com/drycc/controller-sdk-go
33
go 1.22
44

55
require (
6-
github.com/google/uuid v1.6.0
76
github.com/stretchr/testify v1.9.0
87
golang.org/x/net v0.23.0
98
)

go.sum

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
22
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3-
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
4-
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
53
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
64
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
75
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=

ps/ps.go

Lines changed: 17 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -83,42 +83,6 @@ func Logs(c *drycc.Client, appID, podID string, request api.PodLogsRequest) (*we
8383
return conn, nil
8484
}
8585

86-
// Scale increases or decreases an app's processes. The processes are specified in the target argument,
87-
// a key-value map, where the key is the process name and the value is the number of replicas
88-
func Scale(c *drycc.Client, appID string, targets map[string]int) error {
89-
u := fmt.Sprintf("/v2/apps/%s/scale/", appID)
90-
91-
body, err := json.Marshal(targets)
92-
93-
if err != nil {
94-
return err
95-
}
96-
97-
res, err := c.Request("POST", u, body)
98-
if err != nil && !drycc.IsErrAPIMismatch(err) {
99-
return err
100-
}
101-
defer res.Body.Close()
102-
return err
103-
}
104-
105-
// Restart restarts an app's processes. To restart all app processes, pass empty strings for
106-
// procType and name. To restart an specific process, pass an procType by leave name empty.
107-
// To restart a specific instance, pass a procType and a name.
108-
func Restart(c *drycc.Client, appID string, targets map[string]string) error {
109-
u := fmt.Sprintf("/v2/apps/%s/pods/restart/", appID)
110-
body, err := json.Marshal(targets)
111-
if err != nil {
112-
return err
113-
}
114-
res, err := c.Request("POST", u, body)
115-
if err != nil && !drycc.IsErrAPIMismatch(err) {
116-
return err
117-
}
118-
defer res.Body.Close()
119-
return err
120-
}
121-
12286
// Describe pod state
12387
func Describe(c *drycc.Client, appID string, podID string, results int) (api.PodState, int, error) {
12488
u := fmt.Sprintf("/v2/apps/%s/pods/%s/describe/", appID, podID)
@@ -135,6 +99,23 @@ func Describe(c *drycc.Client, appID string, podID string, results int) (api.Pod
13599
return podState, count, reqErr
136100
}
137101

102+
// delete a pod
103+
func Delete(c *drycc.Client, appID string, podIDs string) error {
104+
u := fmt.Sprintf("/v2/apps/%s/pods/", appID)
105+
106+
req := api.PodIDs{PodIDs: podIDs}
107+
108+
body, err := json.Marshal(req)
109+
if err != nil {
110+
return err
111+
}
112+
res, err := c.Request("DELETE", u, body)
113+
if err == nil {
114+
res.Body.Close()
115+
}
116+
return err
117+
}
118+
138119
// ByType organizes processes of an app by process type.
139120
func ByType(processes api.PodsList) api.PodTypes {
140121
var pts api.PodTypes

0 commit comments

Comments
 (0)