github.com/huiliang/nomad@v0.2.1-0.20151124023127-7a8b664699ff/command/alloc_status.go (about) 1 package command 2 3 import ( 4 "fmt" 5 "sort" 6 "strings" 7 "time" 8 9 "github.com/hashicorp/nomad/api" 10 ) 11 12 type AllocStatusCommand struct { 13 Meta 14 } 15 16 func (c *AllocStatusCommand) Help() string { 17 helpText := ` 18 Usage: nomad alloc-status [options] <allocation> 19 20 Display information about existing allocations and its tasks. This command can 21 be used to inspect the current status of all allocation, including its running 22 status, metadata, and verbose failure messages reported by internal 23 subsystems. 24 25 General Options: 26 27 ` + generalOptionsUsage() + ` 28 29 Alloc Status Options: 30 31 -short 32 Display short output. Shows only the most recent task event. 33 ` 34 35 return strings.TrimSpace(helpText) 36 } 37 38 func (c *AllocStatusCommand) Synopsis() string { 39 return "Display allocation status information and metadata" 40 } 41 42 func (c *AllocStatusCommand) Run(args []string) int { 43 var short bool 44 45 flags := c.Meta.FlagSet("alloc-status", FlagSetClient) 46 flags.Usage = func() { c.Ui.Output(c.Help()) } 47 flags.BoolVar(&short, "short", false, "") 48 49 if err := flags.Parse(args); err != nil { 50 return 1 51 } 52 53 // Check that we got exactly one allocation ID 54 args = flags.Args() 55 if len(args) != 1 { 56 c.Ui.Error(c.Help()) 57 return 1 58 } 59 allocID := args[0] 60 61 // Get the HTTP client 62 client, err := c.Meta.Client() 63 if err != nil { 64 c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err)) 65 return 1 66 } 67 68 // Query the allocation info 69 alloc, _, err := client.Allocations().Info(allocID, nil) 70 if err != nil { 71 c.Ui.Error(fmt.Sprintf("Error querying allocation: %s", err)) 72 return 1 73 } 74 75 // Format the allocation data 76 basic := []string{ 77 fmt.Sprintf("ID|%s", alloc.ID), 78 fmt.Sprintf("EvalID|%s", alloc.EvalID), 79 fmt.Sprintf("Name|%s", alloc.Name), 80 fmt.Sprintf("NodeID|%s", alloc.NodeID), 81 fmt.Sprintf("JobID|%s", alloc.JobID), 82 fmt.Sprintf("ClientStatus|%s", alloc.ClientStatus), 83 fmt.Sprintf("NodesEvaluated|%d", alloc.Metrics.NodesEvaluated), 84 fmt.Sprintf("NodesFiltered|%d", alloc.Metrics.NodesFiltered), 85 fmt.Sprintf("NodesExhausted|%d", alloc.Metrics.NodesExhausted), 86 fmt.Sprintf("AllocationTime|%s", alloc.Metrics.AllocationTime), 87 fmt.Sprintf("CoalescedFailures|%d", alloc.Metrics.CoalescedFailures), 88 } 89 c.Ui.Output(formatKV(basic)) 90 91 // Print the state of each task. 92 if short { 93 c.shortTaskStatus(alloc) 94 } else { 95 c.taskStatus(alloc) 96 } 97 98 // Format the detailed status 99 c.Ui.Output("\n==> Status") 100 dumpAllocStatus(c.Ui, alloc) 101 102 return 0 103 } 104 105 // shortTaskStatus prints out the current state of each task. 106 func (c *AllocStatusCommand) shortTaskStatus(alloc *api.Allocation) { 107 tasks := make([]string, 0, len(alloc.TaskStates)+1) 108 tasks = append(tasks, "Name|State|LastEvent|Time") 109 for task := range c.sortedTaskStateIterator(alloc.TaskStates) { 110 fmt.Println(task) 111 state := alloc.TaskStates[task] 112 lastState := state.State 113 var lastEvent, lastTime string 114 115 l := len(state.Events) 116 if l != 0 { 117 last := state.Events[l-1] 118 lastEvent = last.Type 119 lastTime = c.formatUnixNanoTime(last.Time) 120 } 121 122 tasks = append(tasks, fmt.Sprintf("%s|%s|%s|%s", 123 task, lastState, lastEvent, lastTime)) 124 } 125 126 c.Ui.Output("\n==> Tasks") 127 c.Ui.Output(formatList(tasks)) 128 } 129 130 // taskStatus prints out the most recent events for each task. 131 func (c *AllocStatusCommand) taskStatus(alloc *api.Allocation) { 132 for task := range c.sortedTaskStateIterator(alloc.TaskStates) { 133 state := alloc.TaskStates[task] 134 events := make([]string, len(state.Events)+1) 135 events[0] = "Time|Type|Description" 136 137 size := len(state.Events) 138 for i, event := range state.Events { 139 formatedTime := c.formatUnixNanoTime(event.Time) 140 141 // Build up the description based on the event type. 142 var desc string 143 switch event.Type { 144 case api.TaskDriverFailure: 145 desc = event.DriverError 146 case api.TaskKilled: 147 desc = event.KillError 148 case api.TaskTerminated: 149 var parts []string 150 parts = append(parts, fmt.Sprintf("Exit Code: %d", event.ExitCode)) 151 152 if event.Signal != 0 { 153 parts = append(parts, fmt.Sprintf("Signal: %d", event.Signal)) 154 } 155 156 if event.Message != "" { 157 parts = append(parts, fmt.Sprintf("Exit Message: %q", event.Message)) 158 } 159 desc = strings.Join(parts, ", ") 160 } 161 162 // Reverse order so we are sorted by time 163 events[size-i] = fmt.Sprintf("%s|%s|%s", formatedTime, event.Type, desc) 164 } 165 166 c.Ui.Output(fmt.Sprintf("\n==> Task %q is %q\nRecent Events:", task, state.State)) 167 c.Ui.Output(formatList(events)) 168 } 169 } 170 171 // formatUnixNanoTime is a helper for formating time for output. 172 func (c *AllocStatusCommand) formatUnixNanoTime(nano int64) string { 173 t := time.Unix(0, nano) 174 return t.Format("15:04:05 01/02/06") 175 } 176 177 // sortedTaskStateIterator is a helper that takes the task state map and returns a 178 // channel that returns the keys in a sorted order. 179 func (c *AllocStatusCommand) sortedTaskStateIterator(m map[string]*api.TaskState) <-chan string { 180 output := make(chan string, len(m)) 181 keys := make([]string, len(m)) 182 i := 0 183 for k := range m { 184 keys[i] = k 185 i++ 186 } 187 sort.Strings(keys) 188 189 for _, key := range keys { 190 output <- key 191 } 192 193 close(output) 194 return output 195 }