From dd24cf94ee30910e150ded0b9949141b04877545 Mon Sep 17 00:00:00 2001 From: Tim Gross Date: Mon, 24 May 2021 09:39:38 -0400 Subject: [PATCH 1/2] cli: improve wildcard namespace prefix matches When a wildcard namespace is used for `nomad job` commands that support prefix matching, avoid asking the user for input if a prefix is an unambiguous exact match so that the behavior is similar to the commands using a specific or unset namespace. --- CHANGELOG.md | 4 ++++ command/job_deployments.go | 13 ++++++++++--- command/job_history.go | 12 +++++++++--- command/job_inspect.go | 12 +++++++++--- command/job_promote.go | 12 +++++++++--- command/job_revert.go | 12 +++++++++--- command/job_status.go | 13 ++++++++++--- command/job_stop.go | 13 ++++++++++--- 8 files changed, 70 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 737116c7d711..1215ebd9c3c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,13 @@ ## 1.1.1 (Unreleased) +IMPROVEMENTS: +* cli: Cross-namespace `nomad job` commands will now select exact matches if the selection is unambiguous. [[GH-10648](https://github.com/hashicorp/nomad/issues/10648)] + BUG FIXES: * api: Fixed event stream connection initialization when there are no events to send [[GH-10637](https://github.com/hashicorp/nomad/issues/10637)] * cli: Fixed a bug where `quota status` and `namespace status` commands may panic if the CLI targets a pre-1.1.0 cluster + ## 1.1.0 (May 18, 2021) FEATURES: diff --git a/command/job_deployments.go b/command/job_deployments.go index 053e44d81c03..0ec82efb84c6 100644 --- a/command/job_deployments.go +++ b/command/job_deployments.go @@ -122,10 +122,17 @@ func (c *JobDeploymentsCommand) Run(args []string) int { c.Ui.Error(fmt.Sprintf("No job(s) with prefix or id %q found", jobID)) return 1 } - if len(jobs) > 1 && (c.allNamespaces() || strings.TrimSpace(jobID) != jobs[0].ID) { - c.Ui.Error(fmt.Sprintf("Prefix matched multiple jobs\n\n%s", createStatusListOutput(jobs, c.allNamespaces()))) - return 1 + if len(jobs) > 1 { + if strings.TrimSpace(jobID) != jobs[0].ID { + c.Ui.Error(fmt.Sprintf("Prefix matched multiple jobs\n\n%s", createStatusListOutput(jobs, c.allNamespaces()))) + return 1 + } + if c.allNamespaces() && jobs[0].ID == jobs[1].ID { + c.Ui.Error(fmt.Sprintf("Prefix matched multiple jobs\n\n%s", createStatusListOutput(jobs, c.allNamespaces()))) + return 1 + } } + jobID = jobs[0].ID q := &api.QueryOptions{Namespace: jobs[0].JobSummary.Namespace} diff --git a/command/job_history.go b/command/job_history.go index f926d182282b..2f922636e080 100644 --- a/command/job_history.go +++ b/command/job_history.go @@ -133,9 +133,15 @@ func (c *JobHistoryCommand) Run(args []string) int { c.Ui.Error(fmt.Sprintf("No job(s) with prefix or id %q found", jobID)) return 1 } - if len(jobs) > 1 && (c.allNamespaces() || strings.TrimSpace(jobID) != jobs[0].ID) { - c.Ui.Error(fmt.Sprintf("Prefix matched multiple jobs\n\n%s", createStatusListOutput(jobs, c.allNamespaces()))) - return 1 + if len(jobs) > 1 { + if strings.TrimSpace(jobID) != jobs[0].ID { + c.Ui.Error(fmt.Sprintf("Prefix matched multiple jobs\n\n%s", createStatusListOutput(jobs, c.allNamespaces()))) + return 1 + } + if c.allNamespaces() && jobs[0].ID == jobs[1].ID { + c.Ui.Error(fmt.Sprintf("Prefix matched multiple jobs\n\n%s", createStatusListOutput(jobs, c.allNamespaces()))) + return 1 + } } q := &api.QueryOptions{Namespace: jobs[0].JobSummary.Namespace} diff --git a/command/job_inspect.go b/command/job_inspect.go index 6966f04e8856..ee4214a56188 100644 --- a/command/job_inspect.go +++ b/command/job_inspect.go @@ -129,9 +129,15 @@ func (c *JobInspectCommand) Run(args []string) int { c.Ui.Error(fmt.Sprintf("No job(s) with prefix or id %q found", jobID)) return 1 } - if len(jobs) > 1 && (c.allNamespaces() || strings.TrimSpace(jobID) != jobs[0].ID) { - c.Ui.Error(fmt.Sprintf("Prefix matched multiple jobs\n\n%s", createStatusListOutput(jobs, c.allNamespaces()))) - return 1 + if len(jobs) > 1 { + if strings.TrimSpace(jobID) != jobs[0].ID { + c.Ui.Error(fmt.Sprintf("Prefix matched multiple jobs\n\n%s", createStatusListOutput(jobs, c.allNamespaces()))) + return 1 + } + if c.allNamespaces() && jobs[0].ID == jobs[1].ID { + c.Ui.Error(fmt.Sprintf("Prefix matched multiple jobs\n\n%s", createStatusListOutput(jobs, c.allNamespaces()))) + return 1 + } } var version *uint64 diff --git a/command/job_promote.go b/command/job_promote.go index 35ce1bd5555b..0d6d5fcd8b6c 100644 --- a/command/job_promote.go +++ b/command/job_promote.go @@ -127,9 +127,15 @@ func (c *JobPromoteCommand) Run(args []string) int { c.Ui.Error(fmt.Sprintf("No job(s) with prefix or id %q found", jobID)) return 1 } - if len(jobs) > 1 && (c.allNamespaces() || strings.TrimSpace(jobID) != jobs[0].ID) { - c.Ui.Error(fmt.Sprintf("Prefix matched multiple jobs\n\n%s", createStatusListOutput(jobs, c.allNamespaces()))) - return 1 + if len(jobs) > 1 { + if strings.TrimSpace(jobID) != jobs[0].ID { + c.Ui.Error(fmt.Sprintf("Prefix matched multiple jobs\n\n%s", createStatusListOutput(jobs, c.allNamespaces()))) + return 1 + } + if c.allNamespaces() && jobs[0].ID == jobs[1].ID { + c.Ui.Error(fmt.Sprintf("Prefix matched multiple jobs\n\n%s", createStatusListOutput(jobs, c.allNamespaces()))) + return 1 + } } jobID = jobs[0].ID q := &api.QueryOptions{Namespace: jobs[0].JobSummary.Namespace} diff --git a/command/job_revert.go b/command/job_revert.go index fecdd22ddd87..e2214e70860a 100644 --- a/command/job_revert.go +++ b/command/job_revert.go @@ -147,9 +147,15 @@ func (c *JobRevertCommand) Run(args []string) int { c.Ui.Error(fmt.Sprintf("No job(s) with prefix or id %q found", jobID)) return 1 } - if len(jobs) > 1 && (c.allNamespaces() || strings.TrimSpace(jobID) != jobs[0].ID) { - c.Ui.Error(fmt.Sprintf("Prefix matched multiple jobs\n\n%s", createStatusListOutput(jobs, c.allNamespaces()))) - return 1 + if len(jobs) > 1 { + if strings.TrimSpace(jobID) != jobs[0].ID { + c.Ui.Error(fmt.Sprintf("Prefix matched multiple jobs\n\n%s", createStatusListOutput(jobs, c.allNamespaces()))) + return 1 + } + if c.allNamespaces() && jobs[0].ID == jobs[1].ID { + c.Ui.Error(fmt.Sprintf("Prefix matched multiple jobs\n\n%s", createStatusListOutput(jobs, c.allNamespaces()))) + return 1 + } } // Prefix lookup matched a single job diff --git a/command/job_status.go b/command/job_status.go index fbaf21cae33c..c838ec43a263 100644 --- a/command/job_status.go +++ b/command/job_status.go @@ -157,10 +157,17 @@ func (c *JobStatusCommand) Run(args []string) int { c.Ui.Error(fmt.Sprintf("No job(s) with prefix or id %q found", jobID)) return 1 } - if len(jobs) > 1 && (allNamespaces || strings.TrimSpace(jobID) != jobs[0].ID) { - c.Ui.Error(fmt.Sprintf("Prefix matched multiple jobs\n\n%s", createStatusListOutput(jobs, allNamespaces))) - return 1 + if len(jobs) > 1 { + if strings.TrimSpace(jobID) != jobs[0].ID { + c.Ui.Error(fmt.Sprintf("Prefix matched multiple jobs\n\n%s", createStatusListOutput(jobs, allNamespaces))) + return 1 + } + if allNamespaces && jobs[0].ID == jobs[1].ID { + c.Ui.Error(fmt.Sprintf("Prefix matched multiple jobs\n\n%s", createStatusListOutput(jobs, allNamespaces))) + return 1 + } } + // Prefix lookup matched a single job q := &api.QueryOptions{Namespace: jobs[0].JobSummary.Namespace} job, _, err := client.Jobs().Info(jobs[0].ID, q) diff --git a/command/job_stop.go b/command/job_stop.go index bea83e884b19..dd20e707d0c4 100644 --- a/command/job_stop.go +++ b/command/job_stop.go @@ -135,10 +135,17 @@ func (c *JobStopCommand) Run(args []string) int { c.Ui.Error(fmt.Sprintf("No job(s) with prefix or id %q found", jobID)) return 1 } - if len(jobs) > 1 && (c.allNamespaces() || strings.TrimSpace(jobID) != jobs[0].ID) { - c.Ui.Error(fmt.Sprintf("Prefix matched multiple jobs\n\n%s", createStatusListOutput(jobs, c.allNamespaces()))) - return 1 + if len(jobs) > 1 { + if strings.TrimSpace(jobID) != jobs[0].ID { + c.Ui.Error(fmt.Sprintf("Prefix matched multiple jobs\n\n%s", createStatusListOutput(jobs, c.allNamespaces()))) + return 1 + } + if c.allNamespaces() && jobs[0].ID == jobs[1].ID { + c.Ui.Error(fmt.Sprintf("Prefix matched multiple jobs\n\n%s", createStatusListOutput(jobs, c.allNamespaces()))) + return 1 + } } + // Prefix lookup matched a single job q := &api.QueryOptions{Namespace: jobs[0].JobSummary.Namespace} job, _, err := client.Jobs().Info(jobs[0].ID, q) From b2caec378ae710508287a9b24b9cfaebbf250d00 Mon Sep 17 00:00:00 2001 From: Tim Gross Date: Mon, 24 May 2021 11:13:17 -0400 Subject: [PATCH 2/2] move trimspace --- command/job_deployments.go | 4 ++-- command/job_history.go | 4 ++-- command/job_inspect.go | 4 ++-- command/job_promote.go | 4 ++-- command/job_revert.go | 4 ++-- command/job_status.go | 4 ++-- command/job_stop.go | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/command/job_deployments.go b/command/job_deployments.go index 0ec82efb84c6..12a5204c68ff 100644 --- a/command/job_deployments.go +++ b/command/job_deployments.go @@ -110,7 +110,7 @@ func (c *JobDeploymentsCommand) Run(args []string) int { return 1 } - jobID := args[0] + jobID := strings.TrimSpace(args[0]) // Check if the job exists jobs, _, err := client.Jobs().PrefixList(jobID) @@ -123,7 +123,7 @@ func (c *JobDeploymentsCommand) Run(args []string) int { return 1 } if len(jobs) > 1 { - if strings.TrimSpace(jobID) != jobs[0].ID { + if jobID != jobs[0].ID { c.Ui.Error(fmt.Sprintf("Prefix matched multiple jobs\n\n%s", createStatusListOutput(jobs, c.allNamespaces()))) return 1 } diff --git a/command/job_history.go b/command/job_history.go index 2f922636e080..ebe87d1d728e 100644 --- a/command/job_history.go +++ b/command/job_history.go @@ -121,7 +121,7 @@ func (c *JobHistoryCommand) Run(args []string) int { return 1 } - jobID := args[0] + jobID := strings.TrimSpace(args[0]) // Check if the job exists jobs, _, err := client.Jobs().PrefixList(jobID) @@ -134,7 +134,7 @@ func (c *JobHistoryCommand) Run(args []string) int { return 1 } if len(jobs) > 1 { - if strings.TrimSpace(jobID) != jobs[0].ID { + if jobID != jobs[0].ID { c.Ui.Error(fmt.Sprintf("Prefix matched multiple jobs\n\n%s", createStatusListOutput(jobs, c.allNamespaces()))) return 1 } diff --git a/command/job_inspect.go b/command/job_inspect.go index ee4214a56188..fe6aca6c7946 100644 --- a/command/job_inspect.go +++ b/command/job_inspect.go @@ -117,7 +117,7 @@ func (c *JobInspectCommand) Run(args []string) int { c.Ui.Error(commandErrorText(c)) return 1 } - jobID := args[0] + jobID := strings.TrimSpace(args[0]) // Check if the job exists jobs, _, err := client.Jobs().PrefixList(jobID) @@ -130,7 +130,7 @@ func (c *JobInspectCommand) Run(args []string) int { return 1 } if len(jobs) > 1 { - if strings.TrimSpace(jobID) != jobs[0].ID { + if jobID != jobs[0].ID { c.Ui.Error(fmt.Sprintf("Prefix matched multiple jobs\n\n%s", createStatusListOutput(jobs, c.allNamespaces()))) return 1 } diff --git a/command/job_promote.go b/command/job_promote.go index 0d6d5fcd8b6c..4fcbcabf7619 100644 --- a/command/job_promote.go +++ b/command/job_promote.go @@ -117,7 +117,7 @@ func (c *JobPromoteCommand) Run(args []string) int { } // Check if the job exists - jobID := args[0] + jobID := strings.TrimSpace(args[0]) jobs, _, err := client.Jobs().PrefixList(jobID) if err != nil { c.Ui.Error(fmt.Sprintf("Error promoting job: %s", err)) @@ -128,7 +128,7 @@ func (c *JobPromoteCommand) Run(args []string) int { return 1 } if len(jobs) > 1 { - if strings.TrimSpace(jobID) != jobs[0].ID { + if jobID != jobs[0].ID { c.Ui.Error(fmt.Sprintf("Prefix matched multiple jobs\n\n%s", createStatusListOutput(jobs, c.allNamespaces()))) return 1 } diff --git a/command/job_revert.go b/command/job_revert.go index e2214e70860a..ac9ffeb3bc7a 100644 --- a/command/job_revert.go +++ b/command/job_revert.go @@ -126,7 +126,7 @@ func (c *JobRevertCommand) Run(args []string) int { vaultToken = os.Getenv("VAULT_TOKEN") } - jobID := args[0] + jobID := strings.TrimSpace(args[0]) revertVersion, ok, err := parseVersion(args[1]) if !ok { c.Ui.Error("The job version to revert to must be specified using the -job-version flag") @@ -148,7 +148,7 @@ func (c *JobRevertCommand) Run(args []string) int { return 1 } if len(jobs) > 1 { - if strings.TrimSpace(jobID) != jobs[0].ID { + if jobID != jobs[0].ID { c.Ui.Error(fmt.Sprintf("Prefix matched multiple jobs\n\n%s", createStatusListOutput(jobs, c.allNamespaces()))) return 1 } diff --git a/command/job_status.go b/command/job_status.go index c838ec43a263..c6266ae9bf8c 100644 --- a/command/job_status.go +++ b/command/job_status.go @@ -146,7 +146,7 @@ func (c *JobStatusCommand) Run(args []string) int { } // Try querying the job - jobID := args[0] + jobID := strings.TrimSpace(args[0]) jobs, _, err := client.Jobs().PrefixList(jobID) if err != nil { @@ -158,7 +158,7 @@ func (c *JobStatusCommand) Run(args []string) int { return 1 } if len(jobs) > 1 { - if strings.TrimSpace(jobID) != jobs[0].ID { + if jobID != jobs[0].ID { c.Ui.Error(fmt.Sprintf("Prefix matched multiple jobs\n\n%s", createStatusListOutput(jobs, allNamespaces))) return 1 } diff --git a/command/job_stop.go b/command/job_stop.go index dd20e707d0c4..cbfed763873b 100644 --- a/command/job_stop.go +++ b/command/job_stop.go @@ -116,7 +116,7 @@ func (c *JobStopCommand) Run(args []string) int { c.Ui.Error(commandErrorText(c)) return 1 } - jobID := args[0] + jobID := strings.TrimSpace(args[0]) // Get the HTTP client client, err := c.Meta.Client() @@ -136,7 +136,7 @@ func (c *JobStopCommand) Run(args []string) int { return 1 } if len(jobs) > 1 { - if strings.TrimSpace(jobID) != jobs[0].ID { + if jobID != jobs[0].ID { c.Ui.Error(fmt.Sprintf("Prefix matched multiple jobs\n\n%s", createStatusListOutput(jobs, c.allNamespaces()))) return 1 }