diff --git a/internal/weldr/api.go b/internal/weldr/api.go index 67f696ad6..fe9a0b797 100644 --- a/internal/weldr/api.go +++ b/internal/weldr/api.go @@ -76,6 +76,7 @@ func New(repo rpmmd.RepoConfig, packages rpmmd.PackageList, logger *log.Logger, api.router.POST("/api/v0/compose", api.composeHandler) api.router.GET("/api/v0/compose/types", api.composeTypesHandler) api.router.GET("/api/v0/compose/queue", api.composeQueueHandler) + api.router.GET("/api/v0/compose/status/:uuids", api.composeStatusHandler) api.router.GET("/api/v0/compose/finished", api.composeFinishedHandler) api.router.GET("/api/v0/compose/failed", api.composeFailedHandler) @@ -658,12 +659,41 @@ func (api *API) composeTypesHandler(writer http.ResponseWriter, request *http.Re func (api *API) composeQueueHandler(writer http.ResponseWriter, request *http.Request, _ httprouter.Params) { var reply struct { - New []interface{} `json:"new"` - Run []interface{} `json:"run"` + New []*composeEntry `json:"new"` + Run []*composeEntry `json:"run"` } - reply.New = make([]interface{}, 0) - reply.Run = make([]interface{}, 0) + reply.New = make([]*composeEntry, 0) + reply.Run = make([]*composeEntry, 0) + + for _, entry := range api.store.listQueue(nil) { + switch entry.QueueStatus { + case "WAITING": + reply.New = append(reply.New, entry) + case "RUNNING": + reply.Run = append(reply.Run, entry) + } + } + + json.NewEncoder(writer).Encode(reply) +} + +func (api *API) composeStatusHandler(writer http.ResponseWriter, request *http.Request, params httprouter.Params) { + var reply struct { + UUIDs []*composeEntry `json:"uuids"` + } + + uuidStrings := strings.Split(params.ByName("uuids"), ",") + uuids := make([]uuid.UUID, len(uuidStrings)) + for _, uuidString := range uuidStrings { + id, err := uuid.Parse(uuidString) + if err != nil { + statusResponseError(writer, http.StatusBadRequest, "invalid UUID") + return + } + uuids = append(uuids, id) + } + reply.UUIDs = api.store.listQueue(uuids) json.NewEncoder(writer).Encode(reply) } diff --git a/internal/weldr/store.go b/internal/weldr/store.go index c37cdcf7f..8f940c3e8 100644 --- a/internal/weldr/store.go +++ b/internal/weldr/store.go @@ -114,6 +114,68 @@ func (s *store) listBlueprints() []string { return names } +type composeEntry struct { + ID uuid.UUID `json:"id"` + Blueprint string `json:"blueprint"` + QueueStatus string `json:"queue_status"` + JobCreated float64 `json:"job_created"` + JobStarted float64 `json:"job_started,omitempty"` + JobFinished float64 `json:"job_finished,omitempty"` +} + +func (s *store) listQueue(uuids []uuid.UUID) []*composeEntry { + s.mu.RLock() + defer s.mu.RUnlock() + + newCompose := func(id uuid.UUID, compose compose) *composeEntry { + switch compose.QueueStatus { + case "WAITING": + return &composeEntry{ + ID: id, + Blueprint: compose.Blueprint.Name, + QueueStatus: compose.QueueStatus, + JobCreated: float64(compose.JobCreated.UnixNano()) / 1000000000, + } + case "RUNNING": + return &composeEntry{ + ID: id, + Blueprint: compose.Blueprint.Name, + QueueStatus: compose.QueueStatus, + JobCreated: float64(compose.JobCreated.UnixNano()) / 1000000000, + JobStarted: float64(compose.JobStarted.UnixNano()) / 1000000000, + } + case "FAILED", "FINISHED": + return &composeEntry{ + ID: id, + Blueprint: compose.Blueprint.Name, + QueueStatus: compose.QueueStatus, + JobCreated: float64(compose.JobCreated.UnixNano()) / 1000000000, + JobStarted: float64(compose.JobStarted.UnixNano()) / 1000000000, + JobFinished: float64(compose.JobFinished.UnixNano()) / 1000000000, + } + default: + panic("invalid compose state") + } + } + + var composes []*composeEntry + if uuids == nil { + composes = make([]*composeEntry, 0, len(s.Composes)) + for id, compose := range s.Composes { + composes = append(composes, newCompose(id, compose)) + } + } else { + composes = make([]*composeEntry, 0, len(uuids)) + for _, id := range uuids { + if compose, exists := s.Composes[id]; exists { + composes = append(composes, newCompose(id, compose)) + } + } + } + + return composes +} + func (s *store) getBlueprint(name string, bp *blueprint.Blueprint, changed *bool) bool { s.mu.RLock() defer s.mu.RUnlock()