github.com/hhrutter/nomad@v0.6.0-rc2.0.20170723054333-80c4b03f0705/command/deployment_status.go (about)

     1  package command
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/hashicorp/nomad/api"
     8  )
     9  
    10  type DeploymentStatusCommand struct {
    11  	Meta
    12  }
    13  
    14  func (c *DeploymentStatusCommand) Help() string {
    15  	helpText := `
    16  Usage: nomad deployment status [options] <deployment id>
    17  
    18  Status is used to display the status of a deployment. The status will display
    19  the number of desired changes as well as the currently applied changes.
    20  
    21  General Options:
    22  
    23    ` + generalOptionsUsage() + `
    24  
    25  Status Options:
    26  
    27    -verbose
    28      Display full information.
    29  
    30    -json
    31      Output the deployment in its JSON format.
    32  
    33    -t
    34      Format and display deployment using a Go template.
    35  `
    36  	return strings.TrimSpace(helpText)
    37  }
    38  
    39  func (c *DeploymentStatusCommand) Synopsis() string {
    40  	return "Display the status of a deployment"
    41  }
    42  
    43  func (c *DeploymentStatusCommand) Run(args []string) int {
    44  	var json, verbose bool
    45  	var tmpl string
    46  
    47  	flags := c.Meta.FlagSet("deployment status", FlagSetClient)
    48  	flags.Usage = func() { c.Ui.Output(c.Help()) }
    49  	flags.BoolVar(&verbose, "verbose", false, "")
    50  	flags.BoolVar(&json, "json", false, "")
    51  	flags.StringVar(&tmpl, "t", "", "")
    52  
    53  	if err := flags.Parse(args); err != nil {
    54  		return 1
    55  	}
    56  
    57  	// Check that we got no arguments
    58  	args = flags.Args()
    59  	if l := len(args); l != 1 {
    60  		c.Ui.Error(c.Help())
    61  		return 1
    62  	}
    63  
    64  	dID := args[0]
    65  
    66  	// Truncate the id unless full length is requested
    67  	length := shortId
    68  	if verbose {
    69  		length = fullId
    70  	}
    71  
    72  	// Get the HTTP client
    73  	client, err := c.Meta.Client()
    74  	if err != nil {
    75  		c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err))
    76  		return 1
    77  	}
    78  
    79  	// Do a prefix lookup
    80  	deploy, possible, err := getDeployment(client.Deployments(), dID)
    81  	if err != nil {
    82  		c.Ui.Error(fmt.Sprintf("Error retrieving deployment: %s", err))
    83  		return 1
    84  	}
    85  
    86  	if len(possible) != 0 {
    87  		c.Ui.Error(fmt.Sprintf("Prefix matched multiple deployments\n\n%s", formatDeployments(possible, length)))
    88  		return 1
    89  	}
    90  
    91  	if json || len(tmpl) > 0 {
    92  		out, err := Format(json, tmpl, deploy)
    93  		if err != nil {
    94  			c.Ui.Error(err.Error())
    95  			return 1
    96  		}
    97  
    98  		c.Ui.Output(out)
    99  		return 0
   100  	}
   101  
   102  	c.Ui.Output(c.Colorize().Color(formatDeployment(deploy, length)))
   103  	return 0
   104  }
   105  
   106  func getDeployment(client *api.Deployments, dID string) (match *api.Deployment, possible []*api.Deployment, err error) {
   107  	// First attempt an immediate lookup if we have a proper length
   108  	if len(dID) == 36 {
   109  		d, _, err := client.Info(dID, nil)
   110  		if err != nil {
   111  			return nil, nil, err
   112  		}
   113  
   114  		return d, nil, nil
   115  	}
   116  
   117  	dID = strings.Replace(dID, "-", "", -1)
   118  	if len(dID) == 1 {
   119  		return nil, nil, fmt.Errorf("Identifier must contain at least two characters.")
   120  	}
   121  	if len(dID)%2 == 1 {
   122  		// Identifiers must be of even length, so we strip off the last byte
   123  		// to provide a consistent user experience.
   124  		dID = dID[:len(dID)-1]
   125  	}
   126  
   127  	// Have to do a prefix lookup
   128  	deploys, _, err := client.PrefixList(dID)
   129  	if err != nil {
   130  		return nil, nil, err
   131  	}
   132  
   133  	l := len(deploys)
   134  	switch {
   135  	case l == 0:
   136  		return nil, nil, fmt.Errorf("Deployment ID %q matched no deployments", dID)
   137  	case l == 1:
   138  		return deploys[0], nil, nil
   139  	default:
   140  		return nil, deploys, nil
   141  	}
   142  }
   143  
   144  func formatDeployment(d *api.Deployment, uuidLength int) string {
   145  	// Format the high-level elements
   146  	high := []string{
   147  		fmt.Sprintf("ID|%s", limit(d.ID, uuidLength)),
   148  		fmt.Sprintf("Job ID|%s", d.JobID),
   149  		fmt.Sprintf("Job Version|%d", d.JobVersion),
   150  		fmt.Sprintf("Status|%s", d.Status),
   151  		fmt.Sprintf("Description|%s", d.StatusDescription),
   152  	}
   153  
   154  	base := formatKV(high)
   155  	if len(d.TaskGroups) == 0 {
   156  		return base
   157  	}
   158  	base += "\n\n[bold]Deployed[reset]\n"
   159  	base += formatDeploymentGroups(d, uuidLength)
   160  	return base
   161  }
   162  
   163  func formatDeploymentGroups(d *api.Deployment, uuidLength int) string {
   164  	// Detect if we need to add these columns
   165  	canaries, autorevert := false, false
   166  	for _, state := range d.TaskGroups {
   167  		if state.AutoRevert {
   168  			autorevert = true
   169  		}
   170  		if state.DesiredCanaries > 0 {
   171  			canaries = true
   172  		}
   173  	}
   174  
   175  	// Build the row string
   176  	rowString := "Task Group|"
   177  	if autorevert {
   178  		rowString += "Auto Revert|"
   179  	}
   180  	if canaries {
   181  		rowString += "Promoted|"
   182  	}
   183  	rowString += "Desired|"
   184  	if canaries {
   185  		rowString += "Canaries|"
   186  	}
   187  	rowString += "Placed|Healthy|Unhealthy"
   188  
   189  	rows := make([]string, len(d.TaskGroups)+1)
   190  	rows[0] = rowString
   191  	i := 1
   192  	for tg, state := range d.TaskGroups {
   193  		row := fmt.Sprintf("%s|", tg)
   194  		if autorevert {
   195  			row += fmt.Sprintf("%v|", state.AutoRevert)
   196  		}
   197  		if canaries {
   198  			row += fmt.Sprintf("%v|", state.Promoted)
   199  		}
   200  		row += fmt.Sprintf("%d|", state.DesiredTotal)
   201  		if canaries {
   202  			row += fmt.Sprintf("%d|", state.DesiredCanaries)
   203  		}
   204  		row += fmt.Sprintf("%d|%d|%d", state.PlacedAllocs, state.HealthyAllocs, state.UnhealthyAllocs)
   205  		rows[i] = row
   206  		i++
   207  	}
   208  
   209  	return formatList(rows)
   210  }