/
service_group_management.go
140 lines (120 loc) · 3.89 KB
/
service_group_management.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package rest
import (
"net/http"
"github.com/evergreen-ci/gimlet"
"github.com/mongodb/amboy"
"github.com/mongodb/grip"
)
// ManagementGroupService provides the reporting service
// impelementation for queue groups.
type ManagementGroupService struct {
group amboy.QueueGroup
}
// NewManagementGroupService returns a service that defines REST routes can
// manage the abortable pools of a QueueGroup.
func NewManagementGroupService(g amboy.QueueGroup) *ManagementGroupService {
return &ManagementGroupService{
group: g,
}
}
// App returns a gimlet app with all of the routes registered.
func (s *ManagementGroupService) App() *gimlet.APIApp {
app := gimlet.NewApp()
app.AddRoute("/jobs/list").Version(1).Get().Handler(s.ListJobs)
app.AddRoute("/jobs/abort").Version(1).Delete().Handler(s.AbortAllJobs)
app.AddRoute("/job/{name}").Version(1).Get().Handler(s.GetJobStatus)
app.AddRoute("/job/{name}").Version(1).Delete().Handler(s.AbortRunningJob)
return app
}
// ListJobs is an http.HandlerFunc that returns a list of all running
// jobs in all pools for the queue group.
func (s *ManagementGroupService) ListJobs(rw http.ResponseWriter, r *http.Request) {
ctx := r.Context()
jobs := []string{}
for _, group := range s.group.Queues(ctx) {
if queue, err := s.group.Get(ctx, group); err == nil {
if pool, ok := queue.Runner().(amboy.AbortableRunner); ok {
jobs = append(jobs, pool.RunningJobs()...)
}
}
}
gimlet.WriteJSON(rw, jobs)
}
// AbortAllJobs is an http.HandlerFunc that sends the signal to abort
// all running jobs in the pools of the group. May return a 408 (timeout) if the
// calling context was canceled before the operation
// returned. Otherwise, this handler returns 200. The body of the
// response is always empty.
func (s *ManagementGroupService) AbortAllJobs(rw http.ResponseWriter, r *http.Request) {
ctx := r.Context()
catcher := grip.NewBasicCatcher()
for _, group := range s.group.Queues(ctx) {
if queue, err := s.group.Get(ctx, group); err == nil {
if pool, ok := queue.Runner().(amboy.AbortableRunner); ok {
if err := pool.AbortAll(ctx); err != nil {
if ctx.Err() != nil {
gimlet.WriteJSONResponse(rw, http.StatusRequestTimeout, struct{}{})
return
}
catcher.Wrapf(err, "queue '%s'", queue.ID())
}
}
}
}
if catcher.HasErrors() {
gimlet.WriteJSONInternalError(rw, catcher.Resolve().Error())
return
}
gimlet.WriteJSON(rw, struct{}{})
}
// GetJobStatus is an http.HandlerFunc reports on the status (running
// or not running) of a specific job.
func (s *ManagementGroupService) GetJobStatus(rw http.ResponseWriter, r *http.Request) {
name := gimlet.GetVars(r)["name"]
ctx := r.Context()
for _, group := range s.group.Queues(ctx) {
if queue, err := s.group.Get(ctx, group); err == nil {
if pool, ok := queue.Runner().(amboy.AbortableRunner); ok {
if pool.IsRunning(name) {
gimlet.WriteJSON(rw, map[string]string{
"name": name,
"status": "running",
"group": group,
})
return
}
}
}
}
gimlet.WriteJSONResponse(rw, http.StatusNotFound,
map[string]string{
"name": name,
"status": "not running",
})
}
// AbortRunningJob is an http.HandlerFunc that terminates the
// execution of a single running job, returning a 400 response when
// the job doesn't exist.
func (s *ManagementGroupService) AbortRunningJob(rw http.ResponseWriter, r *http.Request) {
name := gimlet.GetVars(r)["name"]
ctx := r.Context()
for _, group := range s.group.Queues(ctx) {
if queue, err := s.group.Get(ctx, group); err == nil {
if pool, ok := queue.Runner().(amboy.AbortableRunner); ok {
if err = pool.Abort(ctx, name); err == nil {
gimlet.WriteJSON(rw, map[string]string{
"name": name,
"status": "aborted",
"group": group,
})
return
}
}
}
}
gimlet.WriteJSONResponse(rw, http.StatusNotFound,
map[string]string{
"name": name,
"status": "unknown",
})
}