Add job list to API and CLI
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
This commit is contained in:
parent
b6a02db446
commit
1287a93cf2
8 changed files with 148 additions and 2 deletions
|
|
@ -306,3 +306,17 @@ func (a *APIController) ListProviders(w http.ResponseWriter, r *http.Request) {
|
|||
log.Printf("failed to encode response: %q", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *APIController) ListAllJobs(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
jobs, err := a.r.ListAllJobs(ctx)
|
||||
if err != nil {
|
||||
handleError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if err := json.NewEncoder(w).Encode(jobs); err != nil {
|
||||
log.Printf("failed to encode response: %q", err)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,6 +94,13 @@ func NewAPIRouter(han *controllers.APIController, logWriter io.Writer, authMiddl
|
|||
apiRouter.Handle("/metrics-token/", http.HandlerFunc(han.MetricsTokenHandler)).Methods("GET", "OPTIONS")
|
||||
apiRouter.Handle("/metrics-token", http.HandlerFunc(han.MetricsTokenHandler)).Methods("GET", "OPTIONS")
|
||||
|
||||
//////////
|
||||
// Jobs //
|
||||
//////////
|
||||
// List all jobs
|
||||
apiRouter.Handle("/jobs/", http.HandlerFunc(han.ListAllJobs)).Methods("GET", "OPTIONS")
|
||||
apiRouter.Handle("/jobs", http.HandlerFunc(han.ListAllJobs)).Methods("GET", "OPTIONS")
|
||||
|
||||
///////////
|
||||
// Pools //
|
||||
///////////
|
||||
|
|
|
|||
|
|
@ -183,6 +183,19 @@ func (c *Client) DeleteRunner(instanceName string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) ListAllJobs() ([]params.Job, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/jobs", c.Config.BaseURL)
|
||||
|
||||
var response []params.Job
|
||||
resp, err := c.client.R().
|
||||
SetResult(&response).
|
||||
Get(url)
|
||||
if err != nil || resp.IsError() {
|
||||
return response, c.handleError(err, resp)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Client) ListPoolInstances(poolID string) ([]params.Instance, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/pools/%s/instances", c.Config.BaseURL, poolID)
|
||||
|
||||
|
|
|
|||
77
cmd/garm-cli/cmd/jobs.go
Normal file
77
cmd/garm-cli/cmd/jobs.go
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
// Copyright 2023 Cloudbase Solutions SRL
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/cloudbase/garm/params"
|
||||
"github.com/google/uuid"
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// runnerCmd represents the runner command
|
||||
var jobsCmd = &cobra.Command{
|
||||
Use: "job",
|
||||
SilenceUsage: true,
|
||||
Short: "Information about jobs",
|
||||
Long: `Query information about jobs.`,
|
||||
Run: nil,
|
||||
}
|
||||
|
||||
var jobsListCmd = &cobra.Command{
|
||||
Use: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Short: "List jobs",
|
||||
Long: `List all jobs currently recorded in the system.`,
|
||||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return errNeedsInitError
|
||||
}
|
||||
|
||||
jobs, err := cli.ListAllJobs()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
formatJobs(jobs)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func formatJobs(jobs []params.Job) {
|
||||
t := table.NewWriter()
|
||||
header := table.Row{"ID", "Name", "Status", "Conclusion", "Runner Name", "Locked by"}
|
||||
t.AppendHeader(header)
|
||||
|
||||
for _, job := range jobs {
|
||||
lockedBy := ""
|
||||
if job.LockedBy != uuid.Nil {
|
||||
lockedBy = job.LockedBy.String()
|
||||
}
|
||||
t.AppendRow(table.Row{job.ID, job.Name, job.Status, job.Conclusion, job.RunnerName, lockedBy})
|
||||
t.AppendSeparator()
|
||||
}
|
||||
fmt.Println(t.Render())
|
||||
}
|
||||
|
||||
func init() {
|
||||
jobsCmd.AddCommand(
|
||||
jobsListCmd,
|
||||
)
|
||||
|
||||
rootCmd.AddCommand(jobsCmd)
|
||||
}
|
||||
|
|
@ -116,6 +116,7 @@ type JobsStore interface {
|
|||
CreateOrUpdateJob(ctx context.Context, job params.Job) (params.Job, error)
|
||||
ListEntityJobsByStatus(ctx context.Context, entityType params.PoolType, entityID string, status params.JobStatus) ([]params.Job, error)
|
||||
ListJobsByStatus(ctx context.Context, status params.JobStatus) ([]params.Job, error)
|
||||
ListAllJobs(ctx context.Context) ([]params.Job, error)
|
||||
|
||||
GetJobByID(ctx context.Context, jobID int64) (params.Job, error)
|
||||
DeleteJob(ctx context.Context, jobID int64) error
|
||||
|
|
|
|||
|
|
@ -261,6 +261,28 @@ func (s *sqlDatabase) ListEntityJobsByStatus(ctx context.Context, entityType par
|
|||
return ret, nil
|
||||
}
|
||||
|
||||
func (s *sqlDatabase) ListAllJobs(ctx context.Context) ([]params.Job, error) {
|
||||
var jobs []WorkflowJob
|
||||
query := s.conn.Model(&WorkflowJob{})
|
||||
|
||||
if err := query.Find(&jobs); err.Error != nil {
|
||||
if errors.Is(err.Error, gorm.ErrRecordNotFound) {
|
||||
return []params.Job{}, nil
|
||||
}
|
||||
return nil, err.Error
|
||||
}
|
||||
|
||||
ret := make([]params.Job, len(jobs))
|
||||
for idx, job := range jobs {
|
||||
jobParam, err := sqlWorkflowJobToParamsJob(job)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "converting job")
|
||||
}
|
||||
ret[idx] = jobParam
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// GetJobByID gets a job by id.
|
||||
func (s *sqlDatabase) GetJobByID(ctx context.Context, jobID int64) (params.Job, error) {
|
||||
var job WorkflowJob
|
||||
|
|
|
|||
|
|
@ -429,9 +429,9 @@ type Job struct {
|
|||
// ID is the ID of the job.
|
||||
ID int64 `json:"id"`
|
||||
// RunID is the ID of the workflow run. A run may have multiple jobs.
|
||||
RunID int64
|
||||
RunID int64 `json:"run_id"`
|
||||
// Action is the specific activity that triggered the event.
|
||||
Action string `json:"run_id"`
|
||||
Action string `json:"action"`
|
||||
// Conclusion is the outcome of the job.
|
||||
// Possible values: "success", "failure", "neutral", "cancelled", "skipped",
|
||||
// "timed_out", "action_required"
|
||||
|
|
|
|||
|
|
@ -125,3 +125,15 @@ func (r *Runner) UpdatePoolByID(ctx context.Context, poolID string, param params
|
|||
}
|
||||
return newPool, nil
|
||||
}
|
||||
|
||||
func (r *Runner) ListAllJobs(ctx context.Context) ([]params.Job, error) {
|
||||
if !auth.IsAdmin(ctx) {
|
||||
return []params.Job{}, runnerErrors.ErrUnauthorized
|
||||
}
|
||||
|
||||
jobs, err := r.store.ListAllJobs(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetching jobs")
|
||||
}
|
||||
return jobs, nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue