runservice: add runEvents handler
This commit is contained in:
parent
ac893f1c91
commit
81d557d785
|
@ -36,6 +36,9 @@ import (
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
etcdclientv3 "go.etcd.io/etcd/clientv3"
|
||||||
|
etcdclientv3rpc "go.etcd.io/etcd/etcdserver/api/v3rpc/rpctypes"
|
||||||
|
"go.etcd.io/etcd/mvcc/mvccpb"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -117,7 +120,6 @@ func NewLogsHandler(logger *zap.Logger, e *etcd.Store, ost *objectstorage.ObjSto
|
||||||
func (h *LogsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (h *LogsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
|
|
||||||
// TODO(sgotti) Check authorized call from client
|
|
||||||
q := r.URL.Query()
|
q := r.URL.Query()
|
||||||
|
|
||||||
runID := q.Get("runid")
|
runID := q.Get("runid")
|
||||||
|
@ -706,3 +708,79 @@ func (h *RunTaskActionsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type RunEventsHandler struct {
|
||||||
|
log *zap.SugaredLogger
|
||||||
|
e *etcd.Store
|
||||||
|
ost *objectstorage.ObjStorage
|
||||||
|
dm *datamanager.DataManager
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRunEventsHandler(logger *zap.Logger, e *etcd.Store, ost *objectstorage.ObjStorage, dm *datamanager.DataManager) *RunEventsHandler {
|
||||||
|
return &RunEventsHandler{
|
||||||
|
log: logger.Sugar(),
|
||||||
|
e: e,
|
||||||
|
ost: ost,
|
||||||
|
dm: dm,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
func (h *RunEventsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ctx := r.Context()
|
||||||
|
|
||||||
|
q := r.URL.Query()
|
||||||
|
|
||||||
|
// TODO(sgotti) handle additional events filtering (by type, etc...)
|
||||||
|
startRunEventID := q.Get("startruneventid")
|
||||||
|
|
||||||
|
if err := h.sendRunEvents(ctx, startRunEventID, w); err != nil {
|
||||||
|
h.log.Errorf("err: %+v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *RunEventsHandler) sendRunEvents(ctx context.Context, startRunEventID string, w http.ResponseWriter) error {
|
||||||
|
w.Header().Set("Content-Type", "text/event-stream")
|
||||||
|
w.Header().Set("Cache-Control", "no-cache")
|
||||||
|
w.Header().Set("Connection", "keep-alive")
|
||||||
|
|
||||||
|
var flusher http.Flusher
|
||||||
|
if fl, ok := w.(http.Flusher); ok {
|
||||||
|
flusher = fl
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(sgotti) fetch from previous events (handle startRunEventID).
|
||||||
|
// Use the readdb instead of etcd
|
||||||
|
|
||||||
|
wctx, cancel := context.WithCancel(ctx)
|
||||||
|
defer cancel()
|
||||||
|
wctx = etcdclientv3.WithRequireLeader(wctx)
|
||||||
|
wch := h.e.WatchKey(wctx, common.EtcdRunEventKey, 0)
|
||||||
|
for wresp := range wch {
|
||||||
|
if wresp.Canceled {
|
||||||
|
err := wresp.Err()
|
||||||
|
if err == etcdclientv3rpc.ErrCompacted {
|
||||||
|
h.log.Errorf("required events already compacted")
|
||||||
|
}
|
||||||
|
return errors.Wrapf(err, "watch error")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ev := range wresp.Events {
|
||||||
|
switch ev.Type {
|
||||||
|
case mvccpb.PUT:
|
||||||
|
var runEvent *types.RunEvent
|
||||||
|
if err := json.Unmarshal(ev.Kv.Value, &runEvent); err != nil {
|
||||||
|
return errors.Wrap(err, "failed to unmarshal run")
|
||||||
|
}
|
||||||
|
if _, err := w.Write([]byte(fmt.Sprintf("data: %s\n\n", ev.Kv.Value))); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if flusher != nil {
|
||||||
|
flusher.Flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -303,3 +303,10 @@ func (c *Client) GetLogs(ctx context.Context, runID, taskID string, setup bool,
|
||||||
|
|
||||||
return c.getResponse(ctx, "GET", "/logs", q, -1, nil, nil)
|
return c.getResponse(ctx, "GET", "/logs", q, -1, nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetRunEvents(ctx context.Context, startRunEventID string) (*http.Response, error) {
|
||||||
|
q := url.Values{}
|
||||||
|
q.Add("startruneventid", startRunEventID)
|
||||||
|
|
||||||
|
return c.getResponse(ctx, "GET", "/runs/events", q, -1, nil, nil)
|
||||||
|
}
|
||||||
|
|
|
@ -189,6 +189,8 @@ func (s *Runservice) Run(ctx context.Context) error {
|
||||||
runsHandler := api.NewRunsHandler(logger, s.readDB)
|
runsHandler := api.NewRunsHandler(logger, s.readDB)
|
||||||
runActionsHandler := api.NewRunActionsHandler(logger, s.ah)
|
runActionsHandler := api.NewRunActionsHandler(logger, s.ah)
|
||||||
runCreateHandler := api.NewRunCreateHandler(logger, s.ah)
|
runCreateHandler := api.NewRunCreateHandler(logger, s.ah)
|
||||||
|
runEventsHandler := api.NewRunEventsHandler(logger, s.e, s.ost, s.dm)
|
||||||
|
|
||||||
changeGroupsUpdateTokensHandler := api.NewChangeGroupsUpdateTokensHandler(logger, s.readDB)
|
changeGroupsUpdateTokensHandler := api.NewChangeGroupsUpdateTokensHandler(logger, s.readDB)
|
||||||
|
|
||||||
router := mux.NewRouter()
|
router := mux.NewRouter()
|
||||||
|
@ -209,6 +211,7 @@ func (s *Runservice) Run(ctx context.Context) error {
|
||||||
|
|
||||||
apirouter.Handle("/logs", logsHandler).Methods("GET")
|
apirouter.Handle("/logs", logsHandler).Methods("GET")
|
||||||
|
|
||||||
|
apirouter.Handle("/runs/events", runEventsHandler).Methods("GET")
|
||||||
apirouter.Handle("/runs/{runid}", runHandler).Methods("GET")
|
apirouter.Handle("/runs/{runid}", runHandler).Methods("GET")
|
||||||
apirouter.Handle("/runs/{runid}/actions", runActionsHandler).Methods("PUT")
|
apirouter.Handle("/runs/{runid}/actions", runActionsHandler).Methods("PUT")
|
||||||
apirouter.Handle("/runs/{runid}/tasks/{taskid}/actions", runTaskActionsHandler).Methods("PUT")
|
apirouter.Handle("/runs/{runid}/tasks/{taskid}/actions", runTaskActionsHandler).Methods("PUT")
|
||||||
|
|
Loading…
Reference in New Issue