github.com/ranjib/nomad@v0.1.1-0.20160225204057-97751b02f70b/command/node_status.go (about) 1 package command 2 3 import ( 4 "fmt" 5 "sort" 6 "strings" 7 ) 8 9 type NodeStatusCommand struct { 10 Meta 11 } 12 13 func (c *NodeStatusCommand) Help() string { 14 helpText := ` 15 Usage: nomad node-status [options] <node> 16 17 Display status information about a given node. The list of nodes 18 returned includes only nodes which jobs may be scheduled to, and 19 includes status and other high-level information. 20 21 If a node ID is passed, information for that specific node will 22 be displayed. If no node ID's are passed, then a short-hand 23 list of all nodes will be displayed. 24 25 General Options: 26 27 ` + generalOptionsUsage() + ` 28 29 Node Status Options: 30 31 -short 32 Display short output. Used only when a single node is being 33 queried, and drops verbose output about node allocations. 34 35 -verbose 36 Display full information. 37 ` 38 return strings.TrimSpace(helpText) 39 } 40 41 func (c *NodeStatusCommand) Synopsis() string { 42 return "Display status information about nodes" 43 } 44 45 func (c *NodeStatusCommand) Run(args []string) int { 46 var short, verbose bool 47 48 flags := c.Meta.FlagSet("node-status", FlagSetClient) 49 flags.Usage = func() { c.Ui.Output(c.Help()) } 50 flags.BoolVar(&short, "short", false, "") 51 flags.BoolVar(&verbose, "verbose", false, "") 52 53 if err := flags.Parse(args); err != nil { 54 return 1 55 } 56 57 // Check that we got either a single node or none 58 args = flags.Args() 59 if len(args) > 1 { 60 c.Ui.Error(c.Help()) 61 return 1 62 } 63 64 // Truncate the id unless full length is requested 65 length := shortId 66 if verbose { 67 length = fullId 68 } 69 70 // Get the HTTP client 71 client, err := c.Meta.Client() 72 if err != nil { 73 c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err)) 74 return 1 75 } 76 77 // Use list mode if no node name was provided 78 if len(args) == 0 { 79 // Query the node info 80 nodes, _, err := client.Nodes().List(nil) 81 if err != nil { 82 c.Ui.Error(fmt.Sprintf("Error querying node status: %s", err)) 83 return 1 84 } 85 86 // Return nothing if no nodes found 87 if len(nodes) == 0 { 88 return 0 89 } 90 91 // Format the nodes list 92 out := make([]string, len(nodes)+1) 93 out[0] = "ID|Datacenter|Name|Class|Drain|Status" 94 for i, node := range nodes { 95 out[i+1] = fmt.Sprintf("%s|%s|%s|%s|%v|%s", 96 limit(node.ID, length), 97 node.Datacenter, 98 node.Name, 99 node.NodeClass, 100 node.Drain, 101 node.Status) 102 } 103 104 // Dump the output 105 c.Ui.Output(formatList(out)) 106 return 0 107 } 108 109 // Query the specific node 110 nodeID := args[0] 111 node, _, err := client.Nodes().Info(nodeID, nil) 112 if err != nil { 113 if len(nodeID) == 1 { 114 c.Ui.Error(fmt.Sprintf("Identifier must contain at least two characters.")) 115 return 1 116 } 117 if len(nodeID)%2 == 1 { 118 // Identifiers must be of even length, so we strip off the last byte 119 // to provide a consistent user experience. 120 nodeID = nodeID[:len(nodeID)-1] 121 } 122 123 // Exact lookup failed, try with prefix based search 124 nodes, _, err := client.Nodes().PrefixList(nodeID) 125 if err != nil { 126 c.Ui.Error(fmt.Sprintf("Error querying node info: %s", err)) 127 return 1 128 } 129 // Return error if no nodes are found 130 if len(nodes) == 0 { 131 c.Ui.Error(fmt.Sprintf("No node(s) with prefix %q found", nodeID)) 132 return 1 133 } 134 if len(nodes) > 1 { 135 // Format the nodes list that matches the prefix so that the user 136 // can create a more specific request 137 out := make([]string, len(nodes)+1) 138 out[0] = "ID|Datacenter|Name|Class|Drain|Status" 139 for i, node := range nodes { 140 out[i+1] = fmt.Sprintf("%s|%s|%s|%s|%v|%s", 141 limit(node.ID, length), 142 node.Datacenter, 143 node.Name, 144 node.NodeClass, 145 node.Drain, 146 node.Status) 147 } 148 // Dump the output 149 c.Ui.Output(fmt.Sprintf("Prefix matched multiple nodes\n\n%s", formatList(out))) 150 return 0 151 } 152 // Prefix lookup matched a single node 153 node, _, err = client.Nodes().Info(nodes[0].ID, nil) 154 if err != nil { 155 c.Ui.Error(fmt.Sprintf("Error querying node info: %s", err)) 156 return 1 157 } 158 } 159 160 m := node.Attributes 161 keys := make([]string, len(m)) 162 for k := range m { 163 keys = append(keys, k) 164 } 165 sort.Strings(keys) 166 167 var attributes []string 168 for _, k := range keys { 169 if k != "" { 170 attributes = append(attributes, fmt.Sprintf("%s:%s", k, m[k])) 171 } 172 } 173 174 // Format the output 175 basic := []string{ 176 fmt.Sprintf("ID|%s", limit(node.ID, length)), 177 fmt.Sprintf("Name|%s", node.Name), 178 fmt.Sprintf("Class|%s", node.NodeClass), 179 fmt.Sprintf("Datacenter|%s", node.Datacenter), 180 fmt.Sprintf("Drain|%v", node.Drain), 181 fmt.Sprintf("Status|%s", node.Status), 182 fmt.Sprintf("Attributes|%s", strings.Join(attributes, ", ")), 183 } 184 185 var allocs []string 186 if !short { 187 // Query the node allocations 188 nodeAllocs, _, err := client.Nodes().Allocations(node.ID, nil) 189 if err != nil { 190 c.Ui.Error(fmt.Sprintf("Error querying node allocations: %s", err)) 191 return 1 192 } 193 194 // Format the allocations 195 allocs = make([]string, len(nodeAllocs)+1) 196 allocs[0] = "ID|Eval ID|Job ID|Task Group|Desired Status|Client Status" 197 for i, alloc := range nodeAllocs { 198 allocs[i+1] = fmt.Sprintf("%s|%s|%s|%s|%s|%s", 199 limit(alloc.ID, length), 200 limit(alloc.EvalID, length), 201 alloc.JobID, 202 alloc.TaskGroup, 203 alloc.DesiredStatus, 204 alloc.ClientStatus) 205 } 206 } 207 208 // Dump the output 209 c.Ui.Output(formatKV(basic)) 210 if !short { 211 c.Ui.Output("\n==> Allocations") 212 c.Ui.Output(formatList(allocs)) 213 } 214 return 0 215 }