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  }