2017-08-14 17:35:13 +00:00
|
|
|
package command
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2017-08-18 20:27:53 +00:00
|
|
|
"strings"
|
2017-08-14 17:35:13 +00:00
|
|
|
|
|
|
|
"github.com/hashicorp/nomad/api/contexts"
|
|
|
|
"github.com/mitchellh/cli"
|
|
|
|
"github.com/posener/complete"
|
|
|
|
)
|
|
|
|
|
|
|
|
type StatusCommand struct {
|
|
|
|
Meta
|
2019-04-04 17:35:20 +00:00
|
|
|
|
|
|
|
// Placeholder bool to allow passing of verbose flags to subcommands.
|
|
|
|
verbose bool
|
2017-08-14 17:35:13 +00:00
|
|
|
}
|
|
|
|
|
2017-08-25 14:24:36 +00:00
|
|
|
func (s *StatusCommand) Help() string {
|
|
|
|
helpText := `
|
|
|
|
Usage: nomad status [options] <identifier>
|
|
|
|
|
|
|
|
Display the status output for any given resource. The command will
|
|
|
|
detect the type of resource being queried and display the appropriate
|
|
|
|
status output.
|
|
|
|
|
|
|
|
General Options:
|
|
|
|
|
2020-11-19 16:15:23 +00:00
|
|
|
` + generalOptionsUsage(usageOptsDefault) + `
|
2019-04-04 17:35:20 +00:00
|
|
|
|
|
|
|
Status Options:
|
|
|
|
|
|
|
|
-verbose
|
|
|
|
Display full information.
|
|
|
|
`
|
2017-08-25 14:24:36 +00:00
|
|
|
|
|
|
|
return strings.TrimSpace(helpText)
|
|
|
|
}
|
|
|
|
|
2017-08-25 19:42:22 +00:00
|
|
|
func (c *StatusCommand) Synopsis() string {
|
|
|
|
return "Display the status output for a resource"
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *StatusCommand) AutocompleteFlags() complete.Flags {
|
2019-04-04 17:35:20 +00:00
|
|
|
return mergeAutocompleteFlags(c.Meta.AutocompleteFlags(FlagSetClient),
|
|
|
|
complete.Flags{
|
|
|
|
"-verbose": complete.PredictNothing,
|
|
|
|
})
|
2017-08-25 19:42:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *StatusCommand) AutocompleteArgs() complete.Predictor {
|
|
|
|
return complete.PredictFunc(func(a complete.Args) []string {
|
2017-08-29 21:29:32 +00:00
|
|
|
client, err := c.Meta.Client()
|
|
|
|
if err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-08-28 05:17:51 +00:00
|
|
|
resp, _, err := client.Search().PrefixSearch(a.Last, contexts.All, nil)
|
2017-08-25 19:42:22 +00:00
|
|
|
if err != nil {
|
|
|
|
return []string{}
|
|
|
|
}
|
|
|
|
|
|
|
|
final := make([]string, 0)
|
|
|
|
|
|
|
|
for _, matches := range resp.Matches {
|
|
|
|
if len(matches) == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
final = append(final, matches...)
|
|
|
|
}
|
|
|
|
|
|
|
|
return final
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2017-08-14 17:35:13 +00:00
|
|
|
func (c *StatusCommand) Run(args []string) int {
|
2017-08-18 13:49:20 +00:00
|
|
|
flags := c.Meta.FlagSet("status", FlagSetClient)
|
2017-08-18 20:27:53 +00:00
|
|
|
flags.Usage = func() { c.Ui.Output(c.Help()) }
|
2019-04-04 17:35:20 +00:00
|
|
|
flags.BoolVar(&c.verbose, "verbose", false, "")
|
2017-08-18 13:49:20 +00:00
|
|
|
|
|
|
|
if err := flags.Parse(args); err != nil {
|
2017-08-18 20:27:53 +00:00
|
|
|
c.Ui.Error(fmt.Sprintf("Error parsing arguments: %q", err))
|
2017-08-18 13:49:20 +00:00
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
2017-08-18 20:27:53 +00:00
|
|
|
// Store the original arguments so we can pass them to the routed command
|
|
|
|
argsCopy := args
|
|
|
|
|
2017-08-18 13:49:20 +00:00
|
|
|
// Check that we got exactly one evaluation ID
|
|
|
|
args = flags.Args()
|
|
|
|
|
2017-08-18 20:27:53 +00:00
|
|
|
// Get the HTTP client
|
|
|
|
client, err := c.Meta.Client()
|
|
|
|
if err != nil {
|
|
|
|
c.Ui.Error(fmt.Sprintf("Error initializing client: %q", err))
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
2017-08-17 21:37:38 +00:00
|
|
|
// If no identifier is provided, default to listing jobs
|
2017-08-18 13:49:20 +00:00
|
|
|
if len(args) == 0 {
|
2017-08-17 17:40:41 +00:00
|
|
|
cmd := &JobStatusCommand{Meta: c.Meta}
|
2017-08-18 13:49:20 +00:00
|
|
|
return cmd.Run(argsCopy)
|
2017-08-14 17:35:13 +00:00
|
|
|
}
|
|
|
|
|
2017-08-17 17:40:41 +00:00
|
|
|
id := args[len(args)-1]
|
2017-08-14 17:35:13 +00:00
|
|
|
|
2017-08-17 21:37:38 +00:00
|
|
|
// Query for the context associated with the id
|
2017-08-28 05:17:51 +00:00
|
|
|
res, _, err := client.Search().PrefixSearch(id, contexts.All, nil)
|
2017-08-14 17:35:13 +00:00
|
|
|
if err != nil {
|
2017-08-18 20:27:53 +00:00
|
|
|
c.Ui.Error(fmt.Sprintf("Error querying search with id: %q", err))
|
2017-08-14 17:35:13 +00:00
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
if res.Matches == nil {
|
2017-08-18 20:27:53 +00:00
|
|
|
c.Ui.Error(fmt.Sprintf("No matches returned for query: %q", err))
|
2017-08-14 17:35:13 +00:00
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
var match contexts.Context
|
2017-10-13 21:36:02 +00:00
|
|
|
exactMatches := 0
|
2017-08-14 17:35:13 +00:00
|
|
|
for ctx, vers := range res.Matches {
|
2017-10-13 21:36:02 +00:00
|
|
|
if len(vers) > 0 && vers[0] == id {
|
2017-08-14 17:35:13 +00:00
|
|
|
match = ctx
|
2017-10-13 21:36:02 +00:00
|
|
|
exactMatches++
|
2017-08-14 17:35:13 +00:00
|
|
|
}
|
2017-10-13 21:36:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if exactMatches > 1 {
|
|
|
|
c.logMultiMatchError(id, res.Matches)
|
|
|
|
return 1
|
|
|
|
} else if exactMatches == 0 {
|
|
|
|
matchCount := 0
|
|
|
|
for ctx, vers := range res.Matches {
|
|
|
|
l := len(vers)
|
|
|
|
if l == 1 {
|
|
|
|
match = ctx
|
|
|
|
matchCount++
|
|
|
|
}
|
2017-08-14 17:35:13 +00:00
|
|
|
|
2017-10-13 21:36:02 +00:00
|
|
|
// Only a single result should return, as this is a match against a full id
|
|
|
|
if matchCount > 1 || l > 1 {
|
|
|
|
c.logMultiMatchError(id, res.Matches)
|
|
|
|
return 1
|
|
|
|
}
|
2017-08-14 17:35:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var cmd cli.Command
|
|
|
|
switch match {
|
|
|
|
case contexts.Evals:
|
|
|
|
cmd = &EvalStatusCommand{Meta: c.Meta}
|
|
|
|
case contexts.Nodes:
|
|
|
|
cmd = &NodeStatusCommand{Meta: c.Meta}
|
|
|
|
case contexts.Allocs:
|
|
|
|
cmd = &AllocStatusCommand{Meta: c.Meta}
|
|
|
|
case contexts.Jobs:
|
|
|
|
cmd = &JobStatusCommand{Meta: c.Meta}
|
2017-08-25 21:06:33 +00:00
|
|
|
case contexts.Deployments:
|
|
|
|
cmd = &DeploymentStatusCommand{Meta: c.Meta}
|
2017-10-13 21:36:02 +00:00
|
|
|
case contexts.Namespaces:
|
|
|
|
cmd = &NamespaceStatusCommand{Meta: c.Meta}
|
|
|
|
case contexts.Quotas:
|
|
|
|
cmd = &QuotaStatusCommand{Meta: c.Meta}
|
2020-03-06 15:09:10 +00:00
|
|
|
case contexts.Plugins:
|
|
|
|
cmd = &PluginStatusCommand{Meta: c.Meta}
|
|
|
|
case contexts.Volumes:
|
|
|
|
cmd = &VolumeStatusCommand{Meta: c.Meta}
|
2017-08-14 17:35:13 +00:00
|
|
|
default:
|
2017-08-21 23:12:35 +00:00
|
|
|
c.Ui.Error(fmt.Sprintf("Unable to resolve ID: %q", id))
|
2017-08-14 17:35:13 +00:00
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
2017-08-18 13:49:20 +00:00
|
|
|
return cmd.Run(argsCopy)
|
2017-08-14 17:35:13 +00:00
|
|
|
}
|
2017-08-29 15:42:09 +00:00
|
|
|
|
2017-08-29 16:46:14 +00:00
|
|
|
// logMultiMatchError is used to log an error message when multiple matches are
|
|
|
|
// found. The error message logged displays the matched IDs per context.
|
|
|
|
func (c *StatusCommand) logMultiMatchError(id string, matches map[contexts.Context][]string) {
|
2017-08-29 15:42:09 +00:00
|
|
|
c.Ui.Error(fmt.Sprintf("Multiple matches found for id %q", id))
|
|
|
|
for ctx, vers := range matches {
|
|
|
|
if len(vers) == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
c.Ui.Error(fmt.Sprintf("\n%s:", strings.Title(string(ctx))))
|
2020-12-09 19:05:18 +00:00
|
|
|
c.Ui.Error(strings.Join(vers, ", "))
|
2017-08-29 15:42:09 +00:00
|
|
|
}
|
|
|
|
}
|