github.com/iqoqo/nomad@v0.11.3-0.20200911112621-d7021c74d101/command/status.go (about) 1 package command 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/hashicorp/nomad/api/contexts" 8 "github.com/mitchellh/cli" 9 "github.com/posener/complete" 10 ) 11 12 type StatusCommand struct { 13 Meta 14 15 // Placeholder bool to allow passing of verbose flags to subcommands. 16 verbose bool 17 } 18 19 func (s *StatusCommand) Help() string { 20 helpText := ` 21 Usage: nomad status [options] <identifier> 22 23 Display the status output for any given resource. The command will 24 detect the type of resource being queried and display the appropriate 25 status output. 26 27 General Options: 28 29 ` + generalOptionsUsage() + ` 30 31 Status Options: 32 33 -verbose 34 Display full information. 35 ` 36 37 return strings.TrimSpace(helpText) 38 } 39 40 func (c *StatusCommand) Synopsis() string { 41 return "Display the status output for a resource" 42 } 43 44 func (c *StatusCommand) AutocompleteFlags() complete.Flags { 45 return mergeAutocompleteFlags(c.Meta.AutocompleteFlags(FlagSetClient), 46 complete.Flags{ 47 "-verbose": complete.PredictNothing, 48 }) 49 } 50 51 func (c *StatusCommand) AutocompleteArgs() complete.Predictor { 52 return complete.PredictFunc(func(a complete.Args) []string { 53 client, err := c.Meta.Client() 54 if err != nil { 55 return nil 56 } 57 58 resp, _, err := client.Search().PrefixSearch(a.Last, contexts.All, nil) 59 if err != nil { 60 return []string{} 61 } 62 63 final := make([]string, 0) 64 65 for _, matches := range resp.Matches { 66 if len(matches) == 0 { 67 continue 68 } 69 70 final = append(final, matches...) 71 } 72 73 return final 74 }) 75 } 76 77 func (c *StatusCommand) Run(args []string) int { 78 flags := c.Meta.FlagSet("status", FlagSetClient) 79 flags.Usage = func() { c.Ui.Output(c.Help()) } 80 flags.BoolVar(&c.verbose, "verbose", false, "") 81 82 if err := flags.Parse(args); err != nil { 83 c.Ui.Error(fmt.Sprintf("Error parsing arguments: %q", err)) 84 return 1 85 } 86 87 // Store the original arguments so we can pass them to the routed command 88 argsCopy := args 89 90 // Check that we got exactly one evaluation ID 91 args = flags.Args() 92 93 // Get the HTTP client 94 client, err := c.Meta.Client() 95 if err != nil { 96 c.Ui.Error(fmt.Sprintf("Error initializing client: %q", err)) 97 return 1 98 } 99 100 // If no identifier is provided, default to listing jobs 101 if len(args) == 0 { 102 cmd := &JobStatusCommand{Meta: c.Meta} 103 return cmd.Run(argsCopy) 104 } 105 106 id := args[len(args)-1] 107 108 // Query for the context associated with the id 109 res, _, err := client.Search().PrefixSearch(id, contexts.All, nil) 110 if err != nil { 111 c.Ui.Error(fmt.Sprintf("Error querying search with id: %q", err)) 112 return 1 113 } 114 115 if res.Matches == nil { 116 c.Ui.Error(fmt.Sprintf("No matches returned for query: %q", err)) 117 return 1 118 } 119 120 var match contexts.Context 121 exactMatches := 0 122 for ctx, vers := range res.Matches { 123 if len(vers) > 0 && vers[0] == id { 124 match = ctx 125 exactMatches++ 126 } 127 } 128 129 if exactMatches > 1 { 130 c.logMultiMatchError(id, res.Matches) 131 return 1 132 } else if exactMatches == 0 { 133 matchCount := 0 134 for ctx, vers := range res.Matches { 135 l := len(vers) 136 if l == 1 { 137 match = ctx 138 matchCount++ 139 } 140 141 // Only a single result should return, as this is a match against a full id 142 if matchCount > 1 || l > 1 { 143 c.logMultiMatchError(id, res.Matches) 144 return 1 145 } 146 } 147 } 148 149 var cmd cli.Command 150 switch match { 151 case contexts.Evals: 152 cmd = &EvalStatusCommand{Meta: c.Meta} 153 case contexts.Nodes: 154 cmd = &NodeStatusCommand{Meta: c.Meta} 155 case contexts.Allocs: 156 cmd = &AllocStatusCommand{Meta: c.Meta} 157 case contexts.Jobs: 158 cmd = &JobStatusCommand{Meta: c.Meta} 159 case contexts.Deployments: 160 cmd = &DeploymentStatusCommand{Meta: c.Meta} 161 case contexts.Namespaces: 162 cmd = &NamespaceStatusCommand{Meta: c.Meta} 163 case contexts.Quotas: 164 cmd = &QuotaStatusCommand{Meta: c.Meta} 165 case contexts.Plugins: 166 cmd = &PluginStatusCommand{Meta: c.Meta} 167 case contexts.Volumes: 168 cmd = &VolumeStatusCommand{Meta: c.Meta} 169 default: 170 c.Ui.Error(fmt.Sprintf("Unable to resolve ID: %q", id)) 171 return 1 172 } 173 174 return cmd.Run(argsCopy) 175 } 176 177 // logMultiMatchError is used to log an error message when multiple matches are 178 // found. The error message logged displays the matched IDs per context. 179 func (c *StatusCommand) logMultiMatchError(id string, matches map[contexts.Context][]string) { 180 c.Ui.Error(fmt.Sprintf("Multiple matches found for id %q", id)) 181 for ctx, vers := range matches { 182 if len(vers) == 0 { 183 continue 184 } 185 186 c.Ui.Error(fmt.Sprintf("\n%s:", strings.Title(string(ctx)))) 187 c.Ui.Error(fmt.Sprintf("%s", strings.Join(vers, ", "))) 188 } 189 }