From 220ffe17e99e563b8cb48baccb8b04ebb6994251 Mon Sep 17 00:00:00 2001 From: Daniel De Vera Date: Thu, 13 Jun 2024 12:48:01 -0300 Subject: [PATCH] Improvements in signadot job get --- go.mod | 2 +- go.sum | 2 + internal/command/jobs/get.go | 39 +++++++-- internal/command/jobs/printers.go | 139 ++++++++++++++++++++++-------- 4 files changed, 138 insertions(+), 44 deletions(-) diff --git a/go.mod b/go.mod index 6171a09c..988479fb 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249 github.com/oklog/run v1.1.0 github.com/panta/machineid v1.0.2 - github.com/signadot/go-sdk v0.3.8-0.20240612174838-f3123693033c + github.com/signadot/go-sdk v0.3.8-0.20240613150121-99844d18e645 github.com/signadot/libconnect v0.1.1-0.20240306100356-4c865b888453 github.com/spf13/cobra v1.6.0 github.com/spf13/viper v1.11.0 diff --git a/go.sum b/go.sum index 9d2831cd..4e14a609 100644 --- a/go.sum +++ b/go.sum @@ -306,6 +306,8 @@ github.com/signadot/go-sdk v0.3.8-0.20240612140005-9c306a9dc373 h1:Lalacny/LWwQh github.com/signadot/go-sdk v0.3.8-0.20240612140005-9c306a9dc373/go.mod h1:LBc3zdVqtLQpXo78HN/DrMhf6PBcfyhlg/tVRrDL+sg= github.com/signadot/go-sdk v0.3.8-0.20240612174838-f3123693033c h1:kpIAGzeq5EwI/9Q0BoW7NVqvUv73aN5zBYmPLQwj6LM= github.com/signadot/go-sdk v0.3.8-0.20240612174838-f3123693033c/go.mod h1:LBc3zdVqtLQpXo78HN/DrMhf6PBcfyhlg/tVRrDL+sg= +github.com/signadot/go-sdk v0.3.8-0.20240613150121-99844d18e645 h1:M913ILxw/gynYIOrcU9qIMh1nJYOKAYan0CYlztWd6o= +github.com/signadot/go-sdk v0.3.8-0.20240613150121-99844d18e645/go.mod h1:LBc3zdVqtLQpXo78HN/DrMhf6PBcfyhlg/tVRrDL+sg= github.com/signadot/libconnect v0.1.1-0.20240306100356-4c865b888453 h1:omG9Iuz5vO0wNvpX/o1sAu+yuHnjHp6okvV9dDRCcd4= github.com/signadot/libconnect v0.1.1-0.20240306100356-4c865b888453/go.mod h1:hS/87oYNXxPg5+sSQuHnQgc8q1xEsBIExnbLEeC46+8= github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= diff --git a/internal/command/jobs/get.go b/internal/command/jobs/get.go index eee44ac4..80048c9c 100644 --- a/internal/command/jobs/get.go +++ b/internal/command/jobs/get.go @@ -6,7 +6,9 @@ import ( "github.com/signadot/cli/internal/config" "github.com/signadot/cli/internal/print" + "github.com/signadot/go-sdk/client/artifacts" "github.com/signadot/go-sdk/client/jobs" + "github.com/signadot/go-sdk/models" "github.com/spf13/cobra" ) @@ -29,20 +31,47 @@ func get(cfg *config.JobGet, out io.Writer, name string) error { if err := cfg.InitAPIConfig(); err != nil { return err } - params := jobs.NewGetJobParams().WithOrgName(cfg.Org).WithJobName(name) - resp, err := cfg.Client.Jobs.GetJob(params, nil) + job, err := getJob(cfg.Job, name) + if err != nil { + return err + } + artifacts, err := getArtifacts(cfg.Job, job) if err != nil { return err } switch cfg.OutputFormat { case config.OutputFormatDefault: - return printJobDetails(cfg.Job, out, resp.Payload) + return printJobDetails(cfg.Job, out, job, artifacts) case config.OutputFormatJSON: - return print.RawJSON(out, resp.Payload) + return printRawJob(out, print.RawJSON, job, artifacts) case config.OutputFormatYAML: - return print.RawYAML(out, resp.Payload) + return printRawJob(out, print.RawK8SYAML, job, artifacts) default: return fmt.Errorf("unsupported output format: %q", cfg.OutputFormat) } } + +func getJob(cfg *config.Job, jobName string) (*models.Job, error) { + params := jobs.NewGetJobParams().WithOrgName(cfg.Org).WithJobName(jobName) + resp, err := cfg.Client.Jobs.GetJob(params, nil) + if err != nil { + return nil, err + } + + return resp.Payload, nil +} + +func getArtifacts(cfg *config.Job, job *models.Job) ([]*models.JobArtifact, error) { + params := artifacts.NewListJobAttemptArtifactsParams(). + WithOrgName(cfg.Org). + WithJobAttempt(job.Status.Attempts[0].ID). + WithJobName(job.Name) + + resp, err := cfg.Client.Artifacts.ListJobAttemptArtifacts(params, nil) + if err != nil { + return []*models.JobArtifact{}, nil + } + + return resp.Payload, nil +} diff --git a/internal/command/jobs/printers.go b/internal/command/jobs/printers.go index 6228226e..2ec4766c 100644 --- a/internal/command/jobs/printers.go +++ b/internal/command/jobs/printers.go @@ -9,7 +9,6 @@ import ( "github.com/signadot/cli/internal/config" "github.com/signadot/cli/internal/sdtab" - "github.com/signadot/go-sdk/client/artifacts" "github.com/signadot/go-sdk/models" "github.com/xeonx/timeago" ) @@ -87,14 +86,31 @@ func isJobPhaseToPrintDefault(ph string) bool { return true } -func printJobDetails(cfg *config.Job, out io.Writer, job *models.Job) error { +func printJobDetails(cfg *config.Job, out io.Writer, job *models.Job, artifacts []*models.JobArtifact) error { tw := tabwriter.NewWriter(out, 0, 0, 3, ' ', 0) createdAt, duration := getAttemptCreatedAtAndDuration(job) fmt.Fprintf(tw, "Job Name:\t%s\n", job.Name) fmt.Fprintf(tw, "Job Runner Group:\t%s\n", job.Spec.RunnerGroup) - fmt.Fprintf(tw, "Status:\t%s\n", job.Status.Attempts[0].Phase) + fmt.Fprintf(tw, "Status:\t%s\n", getJobStatus(job)) + if state := job.Status.Attempts[0].State; state != nil { + switch { + case state.Queued != nil: + fmt.Fprintf(tw, "Message:\t%s\n", state.Queued.Message) + case state.Running != nil: + fmt.Fprintf(tw, "Runner Pod:\t%s/%s\n", state.Running.PodNamespace, state.Running.PodName) + case state.Canceled != nil: + fmt.Fprintf(tw, "Canceled By:\t%s\n", state.Canceled.CanceledBy) + fmt.Fprintf(tw, "Message:\t%s\n", state.Canceled.Message) + case state.Failed != nil: + if state.Failed.ExitCode != nil { + fmt.Fprintf(tw, "Exit Code:\t%d\n", *state.Failed.ExitCode) + } + fmt.Fprintf(tw, "Message:\t%s\n", state.Failed.Message) + } + } + fmt.Fprintf(tw, "Environment:\t%s\n", getJobEnvironment(job)) fmt.Fprintf(tw, "Created At:\t%s\n", getCreatedAt(job)) @@ -108,7 +124,7 @@ func printJobDetails(cfg *config.Job, out io.Writer, job *models.Job) error { fmt.Fprintf(tw, "Dashboard URL:\t%s\n", cfg.JobDashboardUrl(job.Name)) - if err := printArtifacts(cfg, tw, job); err != nil { + if err := printArtifacts(tw, artifacts); err != nil { return err } @@ -119,6 +135,22 @@ func printJobDetails(cfg *config.Job, out io.Writer, job *models.Job) error { return nil } +func getJobStatus(job *models.Job) string { + switch job.Status.Attempts[0].Phase { + case "queued": + return "Queued" + case "running": + return "Running" + case "failed": + return "Failed" + case "succeeded": + return "Succeeded" + case "canceled": + return "Canceled" + } + return "Unknown" +} + func getCreatedAt(job *models.Job) string { createdAt := job.CreatedAt if len(createdAt) == 0 { @@ -185,45 +217,15 @@ func getJobEnvironment(job *models.Job) string { return "baseline" } -func getArtifacts(cfg *config.Job, job *models.Job) ([]*models.JobArtifact, error) { - params := artifacts.NewListJobAttemptArtifactsParams(). - WithOrgName(cfg.Org). - WithJobAttempt(job.Status.Attempts[0].ID). - WithJobName(job.Name) - - resp, err := cfg.Client.Artifacts.ListJobAttemptArtifacts(params, nil) - if err != nil { - return []*models.JobArtifact{}, nil - } - - return resp.Payload, nil -} - type jobArtifactRow struct { Path string `sdtab:"PATH"` Size string `sdtab:"SIZE"` } -func printArtifacts(cfg *config.Job, out io.Writer, job *models.Job) error { - artifactsList, err := getArtifacts(cfg, job) - if err != nil { - return err - } - - fmt.Fprintf(out, "\nArtifacts\n") - - if len(artifactsList) == 0 { - fmt.Fprintln(out, "No artifacts") - return nil - } - - t := sdtab.New[jobArtifactRow](out) - t.AddHeader() - +func rangeArtifacts(artifacts []*models.JobArtifact, fn func(path string, size int64)) { excludeFiles := map[string]bool{"stderr.index": true, "stdout.index": true} - for _, artifact := range artifactsList { + for _, artifact := range artifacts { path := artifact.Path - if _, ok := excludeFiles[path]; ok { continue } @@ -231,12 +233,25 @@ func printArtifacts(cfg *config.Job, out io.Writer, job *models.Job) error { if artifact.Space == "system" { path = "@" + path } + fn(path, artifact.Size) + } +} +func printArtifacts(out io.Writer, artifacts []*models.JobArtifact) error { + fmt.Fprintf(out, "\nArtifacts\n") + if len(artifacts) == 0 { + fmt.Fprintln(out, "No artifacts") + return nil + } + + t := sdtab.New[jobArtifactRow](out) + t.AddHeader() + rangeArtifacts(artifacts, func(path string, size int64) { t.AddRow(jobArtifactRow{ Path: path, - Size: byteCountSI(artifact.Size), + Size: byteCountSI(size), }) - } + }) return t.Flush() } @@ -253,3 +268,51 @@ func byteCountSI(b int64) string { return fmt.Sprintf("%.1f %cB", float64(b)/float64(div), "kMGTPE"[exp]) } + +func printRawJob(out io.Writer, printer func(out io.Writer, v any) error, + job *models.Job, artifacts []*models.JobArtifact) error { + attempt := job.Status.Attempts[0] + + type rawArtifact struct { + Path string `json:"path,omitempty"` + Size int64 `json:"size"` + } + + type rawJobAttemptStatus struct { + CreatedAt string `json:"createdAt,omitempty"` + StartedAt string `json:"startedAt,omitempty"` + FinishedAt string `json:"finishedAt,omitempty"` + ExecutionCount int64 `json:"executionCount,omitempty"` + Phase string `json:"phase,omitempty"` + State *models.JobsState `json:"state,omitempty"` + Artifacts []*rawArtifact `json:"artifacts,omitempty"` + } + + type rawJob struct { + Spec *models.JobSpec `json:"spec,omitempty"` + Status *rawJobAttemptStatus `json:"status,omitempty"` + } + + displayableArtifacts := make([]*rawArtifact, 0, len(artifacts)) + rangeArtifacts(artifacts, func(path string, size int64) { + displayableArtifacts = append(displayableArtifacts, &rawArtifact{ + Path: path, + Size: size, + }) + }) + + displayableJob := &rawJob{ + Spec: job.Spec, + Status: &rawJobAttemptStatus{ + CreatedAt: attempt.CreatedAt, + StartedAt: attempt.StartedAt, + FinishedAt: attempt.FinishedAt, + ExecutionCount: attempt.ExecutionCount, + Phase: attempt.Phase, + State: attempt.State, + Artifacts: displayableArtifacts, + }, + } + + return printer(out, displayableJob) +}