Skip to content

Improvements in signadot job get #130

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down
39 changes: 34 additions & 5 deletions internal/command/jobs/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand All @@ -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
}
139 changes: 101 additions & 38 deletions internal/command/jobs/printers.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand Down Expand Up @@ -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))

Expand All @@ -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
}

Expand All @@ -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 {
Expand Down Expand Up @@ -185,58 +217,41 @@ 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
}

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()
}

Expand All @@ -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)
}