From ee2ac89b881f93b23d42a4e8bf60b4828770171d Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Thu, 3 Mar 2022 14:19:20 -0800 Subject: [PATCH 01/10] CLI: Add `waypoint job` command for job management This commit adds a job command for managing and inspecting jobs in Waypoint server. --- internal/cli/job_cancel.go | 84 +++++++++++++++ internal/cli/job_get_stream.go | 74 +++++++++++++ internal/cli/job_inspect.go | 191 +++++++++++++++++++++++++++++++++ internal/cli/job_list.go | 170 +++++++++++++++++++++++++++++ internal/cli/main.go | 34 ++++++ 5 files changed, 553 insertions(+) create mode 100644 internal/cli/job_cancel.go create mode 100644 internal/cli/job_get_stream.go create mode 100644 internal/cli/job_inspect.go create mode 100644 internal/cli/job_list.go diff --git a/internal/cli/job_cancel.go b/internal/cli/job_cancel.go new file mode 100644 index 00000000000..ae866eef342 --- /dev/null +++ b/internal/cli/job_cancel.go @@ -0,0 +1,84 @@ +package cli + +import ( + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/hashicorp/waypoint-plugin-sdk/terminal" + "github.com/hashicorp/waypoint/internal/clierrors" + "github.com/hashicorp/waypoint/internal/pkg/flag" + pb "github.com/hashicorp/waypoint/pkg/server/gen" +) + +type JobCancelCommand struct { + *baseCommand + + flagJson bool +} + +func (c *JobCancelCommand) Run(args []string) int { + // Initialize. If we fail, we just exit since Init handles the UI. + if err := c.Init( + WithArgs(args), + WithFlags(c.Flags()), + ); err != nil { + return 1 + } + + ctx := c.Ctx + + var jobId string + if len(c.args) == 0 { + c.ui.Output("Job ID required.\n\n%s", c.Help(), terminal.WithErrorStyle()) + return 1 + } else { + jobId = c.args[0] + } + + sg := c.ui.StepGroup() + defer sg.Wait() + + s := sg.Add("Cancelling job %q", jobId) + defer func() { s.Abort() }() + + _, err := c.project.Client().CancelJob(ctx, &pb.CancelJobRequest{ + JobId: jobId, + }) + if err != nil { + s.Update("Failed to marked job %q for cancellation", jobId) + s.Status(terminal.StatusError) + s.Done() + + if status.Code(err) == codes.NotFound { + c.ui.Output("Job id not found: %s", clierrors.Humanize(err), + terminal.WithErrorStyle()) + return 1 + } + + c.ui.Output(clierrors.Humanize(err), terminal.WithErrorStyle()) + return 1 + } + + s.Update("Marked job %q for cancellation", jobId) + s.Done() + + return 0 +} + +func (c *JobCancelCommand) Flags() *flag.Sets { + return c.flagSet(flagSetOperation, func(set *flag.Sets) { + }) +} + +func (c *JobCancelCommand) Synopsis() string { + return "Cancel a running a job by id" +} + +func (c *JobCancelCommand) Help() string { + return formatHelp(` +Usage: waypoint job cancel [options] + + Cancel a running job by id from Waypoint server. + +` + c.Flags().Help()) +} diff --git a/internal/cli/job_get_stream.go b/internal/cli/job_get_stream.go new file mode 100644 index 00000000000..bd699069815 --- /dev/null +++ b/internal/cli/job_get_stream.go @@ -0,0 +1,74 @@ +package cli + +import ( + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/hashicorp/waypoint-plugin-sdk/terminal" + "github.com/hashicorp/waypoint/internal/clierrors" + "github.com/hashicorp/waypoint/internal/pkg/flag" + pb "github.com/hashicorp/waypoint/pkg/server/gen" +) + +type JobGetStreamCommand struct { + *baseCommand + + flagJson bool +} + +func (c *JobGetStreamCommand) Run(args []string) int { + // Initialize. If we fail, we just exit since Init handles the UI. + if err := c.Init( + WithArgs(args), + WithFlags(c.Flags()), + ); err != nil { + return 1 + } + ctx := c.Ctx + + var jobId string + if len(c.args) == 0 { + c.ui.Output("Job ID required.\n\n%s", c.Help(), terminal.WithErrorStyle()) + return 1 + } else { + jobId = c.args[0] + } + + _, err := c.project.Client().GetJobStream(ctx, &pb.GetJobStreamRequest{ + JobId: jobId, + }) + if err != nil { + if status.Code(err) == codes.NotFound { + c.ui.Output("Job id not found: %s", clierrors.Humanize(err), + terminal.WithErrorStyle()) + return 1 + } + + c.ui.Output(clierrors.Humanize(err), terminal.WithErrorStyle()) + return 1 + } + + // TODO(briancain): process and print terminal events like `internal/client/job.go` + c.ui.Output("Job stream is not implemented yet!", terminal.WithWarningStyle()) + + return 0 +} + +func (c *JobGetStreamCommand) Flags() *flag.Sets { + return c.flagSet(flagSetOperation, func(set *flag.Sets) { + //f := set.NewSet("Command Options") + }) +} + +func (c *JobGetStreamCommand) Synopsis() string { + return "Attach a local CLI to a job stream by id" +} + +func (c *JobGetStreamCommand) Help() string { + return formatHelp(` +Usage: waypoint job get-stream [options] + + Connects the local CLI to an active job stream. + +` + c.Flags().Help()) +} diff --git a/internal/cli/job_inspect.go b/internal/cli/job_inspect.go new file mode 100644 index 00000000000..f942b3a8ea5 --- /dev/null +++ b/internal/cli/job_inspect.go @@ -0,0 +1,191 @@ +package cli + +import ( + "fmt" + + "github.com/golang/protobuf/jsonpb" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/hashicorp/waypoint-plugin-sdk/terminal" + "github.com/hashicorp/waypoint/internal/clierrors" + "github.com/hashicorp/waypoint/internal/pkg/flag" + pb "github.com/hashicorp/waypoint/pkg/server/gen" +) + +type JobInspectCommand struct { + *baseCommand + + flagJson bool +} + +func (c *JobInspectCommand) Run(args []string) int { + // Initialize. If we fail, we just exit since Init handles the UI. + if err := c.Init( + WithArgs(args), + WithFlags(c.Flags()), + ); err != nil { + return 1 + } + ctx := c.Ctx + + var jobId string + if len(c.args) == 0 { + c.ui.Output("Job ID required.\n\n%s", c.Help(), terminal.WithErrorStyle()) + return 1 + } else { + jobId = c.args[0] + } + + resp, err := c.project.Client().GetJob(ctx, &pb.GetJobRequest{ + JobId: jobId, + }) + if err != nil { + if status.Code(err) == codes.NotFound { + c.ui.Output("Job id not found: %s", clierrors.Humanize(err), + terminal.WithErrorStyle()) + return 1 + } + + c.ui.Output(clierrors.Humanize(err), terminal.WithErrorStyle()) + return 1 + } + if resp == nil { + c.ui.Output("The requested job id %q was empty", jobId, terminal.WithWarningStyle()) + return 0 + } + + if c.flagJson { + var m jsonpb.Marshaler + m.Indent = "\t" + str, err := m.MarshalToString(resp) + if err != nil { + c.ui.Output(clierrors.Humanize(err), terminal.WithErrorStyle()) + return 1 + } + + fmt.Println(str) + return 0 + } + + var op string + // Job_Noop seems to be missing the isJob_operation method + switch resp.Operation.(type) { + case *pb.Job_Build: + op = "Build" + case *pb.Job_Push: + op = "Push" + case *pb.Job_Deploy: + op = "Deploy" + case *pb.Job_Destroy: + op = "Destroy" + case *pb.Job_Release: + op = "Release" + case *pb.Job_Validate: + op = "Validate" + case *pb.Job_Auth: + op = "Auth" + case *pb.Job_Docs: + op = "Docs" + case *pb.Job_ConfigSync: + op = "ConfigSync" + case *pb.Job_Exec: + op = "Exec" + case *pb.Job_Up: + op = "Up" + case *pb.Job_Logs: + op = "Logs" + case *pb.Job_QueueProject: + op = "QueueProject" + case *pb.Job_Poll: + op = "Poll" + case *pb.Job_StatusReport: + op = "StatusReport" + case *pb.Job_StartTask: + op = "StartTask" + case *pb.Job_StopTask: + op = "StopTask" + case *pb.Job_Init: + op = "Init" + default: + op = "Unknown" + } + + var jobState string + switch resp.State { + case pb.Job_UNKNOWN: + jobState = "Unknown" + case pb.Job_QUEUED: + jobState = "Queued" + case pb.Job_WAITING: + jobState = "Waiting" + case pb.Job_RUNNING: + jobState = "Running" + case pb.Job_ERROR: + jobState = "Error" + case pb.Job_SUCCESS: + jobState = "Sucecss" + default: + jobState = "Unknown" + } + + var targetRunner string + switch target := resp.TargetRunner.Target.(type) { + case *pb.Ref_Runner_Any: + targetRunner = "*" + case *pb.Ref_Runner_Id: + targetRunner = target.Id.Id + } + + c.ui.Output("Job Configuration", terminal.WithHeaderStyle()) + c.ui.NamedValues([]terminal.NamedValue{ + { + Name: "ID", Value: resp.Id, + }, + { + Name: "Operation", Value: op, + }, + { + Name: "State", Value: jobState, + }, + { + Name: "Target Runner", Value: targetRunner, + }, + { + Name: "Workspace", Value: resp.Workspace.Workspace, + }, + { + Name: "Project", Value: resp.Application.Project, + }, + { + Name: "Application", Value: resp.Application.Application, + }, + }, terminal.WithInfoStyle()) + + return 0 +} + +func (c *JobInspectCommand) Flags() *flag.Sets { + return c.flagSet(flagSetOperation, func(set *flag.Sets) { + f := set.NewSet("Command Options") + f.BoolVar(&flag.BoolVar{ + Name: "json", + Target: &c.flagJson, + Default: false, + Usage: "Output the list of jobs as json.", + }) + }) +} + +func (c *JobInspectCommand) Synopsis() string { + return "Inspect the details of a job by id in Waypoint" +} + +func (c *JobInspectCommand) Help() string { + return formatHelp(` +Usage: waypoint job list [options] + + Inspect the details of a job by id in Waypoint server. + +` + c.Flags().Help()) +} diff --git a/internal/cli/job_list.go b/internal/cli/job_list.go new file mode 100644 index 00000000000..63d43db5a64 --- /dev/null +++ b/internal/cli/job_list.go @@ -0,0 +1,170 @@ +package cli + +import ( + "fmt" + + "github.com/golang/protobuf/jsonpb" + + "github.com/hashicorp/waypoint-plugin-sdk/terminal" + "github.com/hashicorp/waypoint/internal/clierrors" + "github.com/hashicorp/waypoint/internal/pkg/flag" + pb "github.com/hashicorp/waypoint/pkg/server/gen" +) + +type JobListCommand struct { + *baseCommand + + flagJson bool +} + +func (c *JobListCommand) Run(args []string) int { + // Initialize. If we fail, we just exit since Init handles the UI. + if err := c.Init( + WithArgs(args), + WithFlags(c.Flags()), + ); err != nil { + return 1 + } + ctx := c.Ctx + + req := &pb.ListJobsRequest{} + + // NOTE(briancain): This is technically not a "public API" function + resp, err := c.project.Client().XListJobs(ctx, req) + if err != nil { + c.ui.Output(clierrors.Humanize(err), terminal.WithErrorStyle()) + return 1 + } + + if c.flagJson { + var m jsonpb.Marshaler + m.Indent = "\t" + for _, t := range resp.Jobs { + str, err := m.MarshalToString(t) + if err != nil { + c.ui.Output(clierrors.Humanize(err), terminal.WithErrorStyle()) + return 1 + } + + fmt.Println(str) + } + return 0 + } + + c.ui.Output("Waypoint Jobs", terminal.WithHeaderStyle()) + + tblHeaders := []string{"ID", "Operation", "State", "Target Runner", "Workspace", "Project", "Application"} + tbl := terminal.NewTable(tblHeaders...) + + for _, j := range resp.Jobs { + var op string + // Job_Noop seems to be missing the isJob_operation method + switch j.Operation.(type) { + case *pb.Job_Build: + op = "Build" + case *pb.Job_Push: + op = "Push" + case *pb.Job_Deploy: + op = "Deploy" + case *pb.Job_Destroy: + op = "Destroy" + case *pb.Job_Release: + op = "Release" + case *pb.Job_Validate: + op = "Validate" + case *pb.Job_Auth: + op = "Auth" + case *pb.Job_Docs: + op = "Docs" + case *pb.Job_ConfigSync: + op = "ConfigSync" + case *pb.Job_Exec: + op = "Exec" + case *pb.Job_Up: + op = "Up" + case *pb.Job_Logs: + op = "Logs" + case *pb.Job_QueueProject: + op = "QueueProject" + case *pb.Job_Poll: + op = "Poll" + case *pb.Job_StatusReport: + op = "StatusReport" + case *pb.Job_StartTask: + op = "StartTask" + case *pb.Job_StopTask: + op = "StopTask" + case *pb.Job_Init: + op = "Init" + default: + op = "Unknown" + } + + var jobState string + switch j.State { + case pb.Job_UNKNOWN: + jobState = "Unknown" + case pb.Job_QUEUED: + jobState = "Queued" + case pb.Job_WAITING: + jobState = "Waiting" + case pb.Job_RUNNING: + jobState = "Running" + case pb.Job_ERROR: + jobState = "Error" + case pb.Job_SUCCESS: + jobState = "Sucecss" + default: + jobState = "Unknown" + } + + var targetRunner string + switch target := j.TargetRunner.Target.(type) { + case *pb.Ref_Runner_Any: + targetRunner = "*" + case *pb.Ref_Runner_Id: + targetRunner = target.Id.Id + } + + tblColumn := []string{ + j.Id, + op, + jobState, + targetRunner, + j.Workspace.Workspace, + j.Application.Project, + j.Application.Application, + } + + tbl.Rich(tblColumn, nil) + } + + c.ui.Table(tbl) + + return 0 +} + +func (c *JobListCommand) Flags() *flag.Sets { + return c.flagSet(flagSetOperation, func(set *flag.Sets) { + f := set.NewSet("Command Options") + f.BoolVar(&flag.BoolVar{ + Name: "json", + Target: &c.flagJson, + Default: false, + Usage: "Output the list of jobs as json.", + }) + }) +} + +func (c *JobListCommand) Synopsis() string { + return "List all jobs in Waypoint" +} + +func (c *JobListCommand) Help() string { + return formatHelp(` +Usage: waypoint job list [options] + + List all known jobs from Waypoint server. + +` + c.Flags().Help()) +} diff --git a/internal/cli/main.go b/internal/cli/main.go index ff6cf6c9b7f..4a7db73b6e2 100644 --- a/internal/cli/main.go +++ b/internal/cli/main.go @@ -390,6 +390,33 @@ func Commands( }, nil }, + "job": func() (cli.Command, error) { + return &helpCommand{ + SynopsisText: helpText["job"][0], + HelpText: helpText["job"][1], + }, nil + }, + "job list": func() (cli.Command, error) { + return &JobListCommand{ + baseCommand: baseCommand, + }, nil + }, + "job inspect": func() (cli.Command, error) { + return &JobInspectCommand{ + baseCommand: baseCommand, + }, nil + }, + "job cancel": func() (cli.Command, error) { + return &JobCancelCommand{ + baseCommand: baseCommand, + }, nil + }, + "job get-stream": func() (cli.Command, error) { + return &JobGetStreamCommand{ + baseCommand: baseCommand, + }, nil + }, + "token": func() (cli.Command, error) { return &helpCommand{ SynopsisText: helpText["token"][0], @@ -977,6 +1004,13 @@ For more information see: https://waypointproject.io/docs/url `, }, + "job": { + "Job introspection and management", + ` +Manage and check the status of jobs in Waypoint. +`, + }, + "project": { "Project management", ` From 792bb0256238085a1249a117674089a1ff7401ef Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Thu, 3 Mar 2022 14:39:30 -0800 Subject: [PATCH 02/10] Generate CLI website docs --- website/content/commands/job-cancel.mdx | 39 +++++++++++++++++ website/content/commands/job-get-stream.mdx | 39 +++++++++++++++++ website/content/commands/job-inspect.mdx | 43 +++++++++++++++++++ website/content/commands/job-list.mdx | 43 +++++++++++++++++++ .../partials/commands/job-cancel_desc.mdx | 0 .../partials/commands/job-cancel_more.mdx | 0 .../partials/commands/job-get-stream_desc.mdx | 0 .../partials/commands/job-get-stream_more.mdx | 0 .../partials/commands/job-inspect_desc.mdx | 0 .../partials/commands/job-inspect_more.mdx | 0 .../partials/commands/job-list_desc.mdx | 0 .../partials/commands/job-list_more.mdx | 0 12 files changed, 164 insertions(+) create mode 100644 website/content/commands/job-cancel.mdx create mode 100644 website/content/commands/job-get-stream.mdx create mode 100644 website/content/commands/job-inspect.mdx create mode 100644 website/content/commands/job-list.mdx create mode 100644 website/content/partials/commands/job-cancel_desc.mdx create mode 100644 website/content/partials/commands/job-cancel_more.mdx create mode 100644 website/content/partials/commands/job-get-stream_desc.mdx create mode 100644 website/content/partials/commands/job-get-stream_more.mdx create mode 100644 website/content/partials/commands/job-inspect_desc.mdx create mode 100644 website/content/partials/commands/job-inspect_more.mdx create mode 100644 website/content/partials/commands/job-list_desc.mdx create mode 100644 website/content/partials/commands/job-list_more.mdx diff --git a/website/content/commands/job-cancel.mdx b/website/content/commands/job-cancel.mdx new file mode 100644 index 00000000000..f40d6356140 --- /dev/null +++ b/website/content/commands/job-cancel.mdx @@ -0,0 +1,39 @@ +--- +layout: commands +page_title: 'Commands: Job cancel' +sidebar_title: 'job cancel' +description: 'Cancel a running a job by id' +--- + +# Waypoint Job cancel + +Command: `waypoint job cancel` + +Cancel a running a job by id + +@include "commands/job-cancel_desc.mdx" + +## Usage + +Usage: `waypoint job cancel [options] ` + +Cancel a running job by id from Waypoint server. + +#### Global Options + +- `-plain` - Plain output: no colors, no animation. +- `-app=` (`-a`) - App to target. Certain commands require a single app target for Waypoint configurations with multiple apps. If you have a single app, then this can be ignored. +- `-project=` (`-p`) - Project to target. +- `-workspace=` (`-w`) - Workspace to operate in. + +#### Operation Options + +- `-label=` - Labels to set for this operation. Can be specified multiple times. +- `-local` - True to use a local runner to execute the operation, false to use a remote runner. + If unset, Waypoint will automatically determine where the operation will occur, + defaulting to remote if possible. +- `-remote-source=` - Override configurations for how remote runners source data. This is specified to the data source type being used in your configuration. This is used for example to set a specific Git ref to run against. +- `-var=` - Variable value to set for this operation. Can be specified multiple times. +- `-var-file=` - HCL or JSON file containing variable values to set for this operation. If any "_.auto.wpvars" or "_.auto.wpvars.json" files are present, they will be automatically loaded. + +@include "commands/job-cancel_more.mdx" diff --git a/website/content/commands/job-get-stream.mdx b/website/content/commands/job-get-stream.mdx new file mode 100644 index 00000000000..d63f77c71e5 --- /dev/null +++ b/website/content/commands/job-get-stream.mdx @@ -0,0 +1,39 @@ +--- +layout: commands +page_title: 'Commands: Job get-stream' +sidebar_title: 'job get-stream' +description: 'Attach a local CLI to a job stream by id' +--- + +# Waypoint Job get-stream + +Command: `waypoint job get-stream` + +Attach a local CLI to a job stream by id + +@include "commands/job-get-stream_desc.mdx" + +## Usage + +Usage: `waypoint job get-stream [options] ` + +Connects the local CLI to an active job stream. + +#### Global Options + +- `-plain` - Plain output: no colors, no animation. +- `-app=` (`-a`) - App to target. Certain commands require a single app target for Waypoint configurations with multiple apps. If you have a single app, then this can be ignored. +- `-project=` (`-p`) - Project to target. +- `-workspace=` (`-w`) - Workspace to operate in. + +#### Operation Options + +- `-label=` - Labels to set for this operation. Can be specified multiple times. +- `-local` - True to use a local runner to execute the operation, false to use a remote runner. + If unset, Waypoint will automatically determine where the operation will occur, + defaulting to remote if possible. +- `-remote-source=` - Override configurations for how remote runners source data. This is specified to the data source type being used in your configuration. This is used for example to set a specific Git ref to run against. +- `-var=` - Variable value to set for this operation. Can be specified multiple times. +- `-var-file=` - HCL or JSON file containing variable values to set for this operation. If any "_.auto.wpvars" or "_.auto.wpvars.json" files are present, they will be automatically loaded. + +@include "commands/job-get-stream_more.mdx" diff --git a/website/content/commands/job-inspect.mdx b/website/content/commands/job-inspect.mdx new file mode 100644 index 00000000000..ff823f7b521 --- /dev/null +++ b/website/content/commands/job-inspect.mdx @@ -0,0 +1,43 @@ +--- +layout: commands +page_title: 'Commands: Job inspect' +sidebar_title: 'job inspect' +description: 'Inspect the details of a job by id in Waypoint' +--- + +# Waypoint Job inspect + +Command: `waypoint job inspect` + +Inspect the details of a job by id in Waypoint + +@include "commands/job-inspect_desc.mdx" + +## Usage + +Usage: `waypoint job list [options]` + +Inspect the details of a job by id in Waypoint server. + +#### Global Options + +- `-plain` - Plain output: no colors, no animation. +- `-app=` (`-a`) - App to target. Certain commands require a single app target for Waypoint configurations with multiple apps. If you have a single app, then this can be ignored. +- `-project=` (`-p`) - Project to target. +- `-workspace=` (`-w`) - Workspace to operate in. + +#### Operation Options + +- `-label=` - Labels to set for this operation. Can be specified multiple times. +- `-local` - True to use a local runner to execute the operation, false to use a remote runner. + If unset, Waypoint will automatically determine where the operation will occur, + defaulting to remote if possible. +- `-remote-source=` - Override configurations for how remote runners source data. This is specified to the data source type being used in your configuration. This is used for example to set a specific Git ref to run against. +- `-var=` - Variable value to set for this operation. Can be specified multiple times. +- `-var-file=` - HCL or JSON file containing variable values to set for this operation. If any "_.auto.wpvars" or "_.auto.wpvars.json" files are present, they will be automatically loaded. + +#### Command Options + +- `-json` - Output the list of jobs as json. + +@include "commands/job-inspect_more.mdx" diff --git a/website/content/commands/job-list.mdx b/website/content/commands/job-list.mdx new file mode 100644 index 00000000000..981bece523c --- /dev/null +++ b/website/content/commands/job-list.mdx @@ -0,0 +1,43 @@ +--- +layout: commands +page_title: 'Commands: Job list' +sidebar_title: 'job list' +description: 'List all jobs in Waypoint' +--- + +# Waypoint Job list + +Command: `waypoint job list` + +List all jobs in Waypoint + +@include "commands/job-list_desc.mdx" + +## Usage + +Usage: `waypoint job list [options]` + +List all known jobs from Waypoint server. + +#### Global Options + +- `-plain` - Plain output: no colors, no animation. +- `-app=` (`-a`) - App to target. Certain commands require a single app target for Waypoint configurations with multiple apps. If you have a single app, then this can be ignored. +- `-project=` (`-p`) - Project to target. +- `-workspace=` (`-w`) - Workspace to operate in. + +#### Operation Options + +- `-label=` - Labels to set for this operation. Can be specified multiple times. +- `-local` - True to use a local runner to execute the operation, false to use a remote runner. + If unset, Waypoint will automatically determine where the operation will occur, + defaulting to remote if possible. +- `-remote-source=` - Override configurations for how remote runners source data. This is specified to the data source type being used in your configuration. This is used for example to set a specific Git ref to run against. +- `-var=` - Variable value to set for this operation. Can be specified multiple times. +- `-var-file=` - HCL or JSON file containing variable values to set for this operation. If any "_.auto.wpvars" or "_.auto.wpvars.json" files are present, they will be automatically loaded. + +#### Command Options + +- `-json` - Output the list of jobs as json. + +@include "commands/job-list_more.mdx" diff --git a/website/content/partials/commands/job-cancel_desc.mdx b/website/content/partials/commands/job-cancel_desc.mdx new file mode 100644 index 00000000000..e69de29bb2d diff --git a/website/content/partials/commands/job-cancel_more.mdx b/website/content/partials/commands/job-cancel_more.mdx new file mode 100644 index 00000000000..e69de29bb2d diff --git a/website/content/partials/commands/job-get-stream_desc.mdx b/website/content/partials/commands/job-get-stream_desc.mdx new file mode 100644 index 00000000000..e69de29bb2d diff --git a/website/content/partials/commands/job-get-stream_more.mdx b/website/content/partials/commands/job-get-stream_more.mdx new file mode 100644 index 00000000000..e69de29bb2d diff --git a/website/content/partials/commands/job-inspect_desc.mdx b/website/content/partials/commands/job-inspect_desc.mdx new file mode 100644 index 00000000000..e69de29bb2d diff --git a/website/content/partials/commands/job-inspect_more.mdx b/website/content/partials/commands/job-inspect_more.mdx new file mode 100644 index 00000000000..e69de29bb2d diff --git a/website/content/partials/commands/job-list_desc.mdx b/website/content/partials/commands/job-list_desc.mdx new file mode 100644 index 00000000000..e69de29bb2d diff --git a/website/content/partials/commands/job-list_more.mdx b/website/content/partials/commands/job-list_more.mdx new file mode 100644 index 00000000000..e69de29bb2d From a79f605400edcd93607615b00c89c3d029b1ad12 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Thu, 3 Mar 2022 14:41:15 -0800 Subject: [PATCH 03/10] internal: Show job id that's being waited on This commit updates the operation queue message to include the job id that waypoint is currently waiting on. This will enable users to inspect the job id that's being waited on to check the status of the job and potentially cancel it if it is stuck --- internal/client/job.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/client/job.go b/internal/client/job.go index 42829b91e8b..0682474c8d0 100644 --- a/internal/client/job.go +++ b/internal/client/job.go @@ -540,7 +540,8 @@ func (c *Project) queueAndStreamJob( switch event.State.Current { case pb.Job_QUEUED: stateEventTimer = time.AfterFunc(stateEventPause, func() { - ui.Output("Operation is queued. Waiting for runner assignment...", + ui.Output("Operation is queued waiting for job %q. Waiting for runner assignment...", + queueResp.JobId, terminal.WithHeaderStyle()) ui.Output("If you interrupt this command, the job will still run in the background.", terminal.WithInfoStyle()) From f0333c9384543d79623759da87baadf7d2ae2d82 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Thu, 3 Mar 2022 14:44:56 -0800 Subject: [PATCH 04/10] Add Changelog --- .changelog/3067.txt | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .changelog/3067.txt diff --git a/.changelog/3067.txt b/.changelog/3067.txt new file mode 100644 index 00000000000..ec1c61b1805 --- /dev/null +++ b/.changelog/3067.txt @@ -0,0 +1,4 @@ +```release-note:feature +**cli:** Introduce a new CLI command for job management and inspection +`waypoint job`. +``` From 0bdfce4f4a16759aa5059bb5629b13fa6a60396f Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Thu, 3 Mar 2022 15:13:04 -0800 Subject: [PATCH 05/10] cli: Allow for limits, descending by job id, and show completion time --- internal/cli/job_list.go | 46 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/internal/cli/job_list.go b/internal/cli/job_list.go index 63d43db5a64..3c299b763ef 100644 --- a/internal/cli/job_list.go +++ b/internal/cli/job_list.go @@ -3,7 +3,9 @@ package cli import ( "fmt" + "github.com/dustin/go-humanize" "github.com/golang/protobuf/jsonpb" + "github.com/golang/protobuf/ptypes" "github.com/hashicorp/waypoint-plugin-sdk/terminal" "github.com/hashicorp/waypoint/internal/clierrors" @@ -14,7 +16,9 @@ import ( type JobListCommand struct { *baseCommand - flagJson bool + flagJson bool + flagLimit int + flagDesc bool } func (c *JobListCommand) Run(args []string) int { @@ -36,10 +40,24 @@ func (c *JobListCommand) Run(args []string) int { return 1 } + jobs := resp.Jobs + + if c.flagDesc { + var reverse []*pb.Job + for i := len(jobs) - 1; i >= 0; i-- { + reverse = append(reverse, jobs[i]) + } + jobs = reverse + } + + if c.flagLimit > 0 && c.flagLimit <= len(jobs) { + jobs = jobs[len(jobs)-c.flagLimit:] + } + if c.flagJson { var m jsonpb.Marshaler m.Indent = "\t" - for _, t := range resp.Jobs { + for _, t := range jobs { str, err := m.MarshalToString(t) if err != nil { c.ui.Output(clierrors.Humanize(err), terminal.WithErrorStyle()) @@ -53,10 +71,10 @@ func (c *JobListCommand) Run(args []string) int { c.ui.Output("Waypoint Jobs", terminal.WithHeaderStyle()) - tblHeaders := []string{"ID", "Operation", "State", "Target Runner", "Workspace", "Project", "Application"} + tblHeaders := []string{"ID", "Operation", "State", "Time Completed", "Target Runner", "Workspace", "Project", "Application"} tbl := terminal.NewTable(tblHeaders...) - for _, j := range resp.Jobs { + for _, j := range jobs { var op string // Job_Noop seems to be missing the isJob_operation method switch j.Operation.(type) { @@ -126,10 +144,16 @@ func (c *JobListCommand) Run(args []string) int { targetRunner = target.Id.Id } + var completeTime string + if time, err := ptypes.Timestamp(j.CompleteTime); err == nil { + completeTime = humanize.Time(time) + } + tblColumn := []string{ j.Id, op, jobState, + completeTime, targetRunner, j.Workspace.Workspace, j.Application.Project, @@ -147,12 +171,26 @@ func (c *JobListCommand) Run(args []string) int { func (c *JobListCommand) Flags() *flag.Sets { return c.flagSet(flagSetOperation, func(set *flag.Sets) { f := set.NewSet("Command Options") + f.BoolVar(&flag.BoolVar{ + Name: "desc", + Target: &c.flagDesc, + Default: false, + Usage: "Output the list of jobs from newest to oldest.", + }) + f.BoolVar(&flag.BoolVar{ Name: "json", Target: &c.flagJson, Default: false, Usage: "Output the list of jobs as json.", }) + + f.IntVar(&flag.IntVar{ + Name: "limit", + Target: &c.flagLimit, + Default: 0, + Usage: "If set, will limit the number of jobs to list.", + }) }) } From d7223e98802985f4de156aa107154a05854608bb Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Thu, 3 Mar 2022 15:14:36 -0800 Subject: [PATCH 06/10] Website autogen --- website/content/commands/job-list.mdx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/content/commands/job-list.mdx b/website/content/commands/job-list.mdx index 981bece523c..d1ae5433746 100644 --- a/website/content/commands/job-list.mdx +++ b/website/content/commands/job-list.mdx @@ -38,6 +38,8 @@ List all known jobs from Waypoint server. #### Command Options +- `-desc` - Output the list of jobs from newest to oldest. - `-json` - Output the list of jobs as json. +- `-limit=` - If set, will limit the number of jobs to list. @include "commands/job-list_more.mdx" From 43708c9ff5950396c8dd426e43419478052d49c4 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Thu, 3 Mar 2022 15:19:14 -0800 Subject: [PATCH 07/10] website: Add CLI to nav data json for website --- website/data/commands-nav-data.json | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/website/data/commands-nav-data.json b/website/data/commands-nav-data.json index 07289bff462..2a259b058e1 100644 --- a/website/data/commands-nav-data.json +++ b/website/data/commands-nav-data.json @@ -170,6 +170,26 @@ "title": "hostname register", "path": "hostname-register" }, + { + "title": "job list", + "path": "job-list" + }, + { + "title": "job inspect", + "path": "job-inspect" + }, + { + "title": "job cancel", + "path": "job-cancel" + }, + { + "title": "job inspect", + "path": "job-inspect" + }, + { + "title": "job get-stream", + "path": "job-get-stream" + }, { "title": "plugin", "path": "plugin" From 4545d5aa8889b0e8b9e97dd25f522147ce10e910 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Thu, 3 Mar 2022 15:23:19 -0800 Subject: [PATCH 08/10] Remove extra route typo --- website/data/commands-nav-data.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/website/data/commands-nav-data.json b/website/data/commands-nav-data.json index 2a259b058e1..d5a147c1142 100644 --- a/website/data/commands-nav-data.json +++ b/website/data/commands-nav-data.json @@ -182,10 +182,6 @@ "title": "job cancel", "path": "job-cancel" }, - { - "title": "job inspect", - "path": "job-inspect" - }, { "title": "job get-stream", "path": "job-get-stream" From ebd3cc15ddac9423ea7f29f474c922eddea5124c Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Fri, 4 Mar 2022 08:21:32 -0800 Subject: [PATCH 09/10] Add more fields to job inspect --- internal/cli/job_inspect.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/internal/cli/job_inspect.go b/internal/cli/job_inspect.go index f942b3a8ea5..9491afa25bf 100644 --- a/internal/cli/job_inspect.go +++ b/internal/cli/job_inspect.go @@ -3,7 +3,9 @@ package cli import ( "fmt" + "github.com/dustin/go-humanize" "github.com/golang/protobuf/jsonpb" + "github.com/golang/protobuf/ptypes" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -137,17 +139,35 @@ func (c *JobInspectCommand) Run(args []string) int { targetRunner = target.Id.Id } + var completeTime string + if time, err := ptypes.Timestamp(resp.CompleteTime); err == nil { + completeTime = humanize.Time(time) + } + var cancelTime string + if time, err := ptypes.Timestamp(resp.CancelTime); err == nil { + cancelTime = humanize.Time(time) + } + c.ui.Output("Job Configuration", terminal.WithHeaderStyle()) c.ui.NamedValues([]terminal.NamedValue{ { Name: "ID", Value: resp.Id, }, + { + Name: "Singleton ID", Value: resp.SingletonId, + }, { Name: "Operation", Value: op, }, { Name: "State", Value: jobState, }, + { + Name: "Complete Time", Value: completeTime, + }, + { + Name: "Cancel Time", Value: cancelTime, + }, { Name: "Target Runner", Value: targetRunner, }, From 8e871c4adaf362528b57a31a5ca644ba6cf8ceeb Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Fri, 4 Mar 2022 08:26:07 -0800 Subject: [PATCH 10/10] Fix docstring in job inspect --- internal/cli/job_inspect.go | 2 +- website/content/commands/job-inspect.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/cli/job_inspect.go b/internal/cli/job_inspect.go index 9491afa25bf..f1599521966 100644 --- a/internal/cli/job_inspect.go +++ b/internal/cli/job_inspect.go @@ -203,7 +203,7 @@ func (c *JobInspectCommand) Synopsis() string { func (c *JobInspectCommand) Help() string { return formatHelp(` -Usage: waypoint job list [options] +Usage: waypoint job inspect [options] Inspect the details of a job by id in Waypoint server. diff --git a/website/content/commands/job-inspect.mdx b/website/content/commands/job-inspect.mdx index ff823f7b521..adee2e3e8f3 100644 --- a/website/content/commands/job-inspect.mdx +++ b/website/content/commands/job-inspect.mdx @@ -15,7 +15,7 @@ Inspect the details of a job by id in Waypoint ## Usage -Usage: `waypoint job list [options]` +Usage: `waypoint job inspect [options] ` Inspect the details of a job by id in Waypoint server.