github.com/blixtra/nomad@v0.7.2-0.20171221000451-da9a1d7bb050/command/job_promote.go (about)

     1  package command
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/hashicorp/nomad/api"
     8  	"github.com/hashicorp/nomad/api/contexts"
     9  	flaghelper "github.com/hashicorp/nomad/helper/flag-helpers"
    10  	"github.com/posener/complete"
    11  )
    12  
    13  type JobPromoteCommand struct {
    14  	Meta
    15  }
    16  
    17  func (c *JobPromoteCommand) Help() string {
    18  	helpText := `
    19  Usage: nomad job promote [options] <job id>
    20  
    21    Promote is used to promote task groups in the most recent deployment for the
    22    given job. Promotion should occur when the deployment has placed canaries for a
    23    task group and those canaries have been deemed healthy. When a task group is
    24    promoted, the rolling upgrade of the remaining allocations is unblocked. If the
    25    canaries are found to be unhealthy, the deployment may either be failed using
    26    the "nomad deployment fail" command, the job can be failed forward by submitting
    27    a new version or failed backwards by reverting to an older version using the
    28    "nomad job revert" command.
    29  
    30  General Options:
    31  
    32    ` + generalOptionsUsage() + `
    33  
    34  Promote Options:
    35  
    36    -group
    37      Group may be specified many times and is used to promote that particular
    38      group. If no specific groups are specified, all groups are promoted.
    39  
    40    -detach
    41      Return immediately instead of entering monitor mode. After deployment
    42      resume, the evaluation ID will be printed to the screen, which can be used
    43      to examine the evaluation using the eval-status command.
    44  
    45    -verbose
    46      Display full information.
    47  `
    48  	return strings.TrimSpace(helpText)
    49  }
    50  
    51  func (c *JobPromoteCommand) Synopsis() string {
    52  	return "Promote a job's canaries"
    53  }
    54  
    55  func (c *JobPromoteCommand) AutocompleteFlags() complete.Flags {
    56  	return mergeAutocompleteFlags(c.Meta.AutocompleteFlags(FlagSetClient),
    57  		complete.Flags{
    58  			"-group":   complete.PredictAnything,
    59  			"-detach":  complete.PredictNothing,
    60  			"-verbose": complete.PredictNothing,
    61  		})
    62  }
    63  
    64  func (c *JobPromoteCommand) AutocompleteArgs() complete.Predictor {
    65  	return complete.PredictFunc(func(a complete.Args) []string {
    66  		client, err := c.Meta.Client()
    67  		if err != nil {
    68  			return nil
    69  		}
    70  
    71  		resp, _, err := client.Search().PrefixSearch(a.Last, contexts.Jobs, nil)
    72  		if err != nil {
    73  			return []string{}
    74  		}
    75  		return resp.Matches[contexts.Jobs]
    76  	})
    77  }
    78  
    79  func (c *JobPromoteCommand) Run(args []string) int {
    80  	var detach, verbose bool
    81  	var groups []string
    82  
    83  	flags := c.Meta.FlagSet("job promote", FlagSetClient)
    84  	flags.Usage = func() { c.Ui.Output(c.Help()) }
    85  	flags.BoolVar(&detach, "detach", false, "")
    86  	flags.BoolVar(&verbose, "verbose", false, "")
    87  	flags.Var((*flaghelper.StringFlag)(&groups), "group", "")
    88  
    89  	if err := flags.Parse(args); err != nil {
    90  		return 1
    91  	}
    92  
    93  	// Check that we got no arguments
    94  	args = flags.Args()
    95  	if l := len(args); l != 1 {
    96  		c.Ui.Error(c.Help())
    97  		return 1
    98  	}
    99  
   100  	// Truncate the id unless full length is requested
   101  	length := shortId
   102  	if verbose {
   103  		length = fullId
   104  	}
   105  
   106  	// Get the HTTP client
   107  	client, err := c.Meta.Client()
   108  	if err != nil {
   109  		c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err))
   110  		return 1
   111  	}
   112  
   113  	// Check if the job exists
   114  	jobID := args[0]
   115  	jobs, _, err := client.Jobs().PrefixList(jobID)
   116  	if err != nil {
   117  		c.Ui.Error(fmt.Sprintf("Error promoting job: %s", err))
   118  		return 1
   119  	}
   120  	if len(jobs) == 0 {
   121  		c.Ui.Error(fmt.Sprintf("No job(s) with prefix or id %q found", jobID))
   122  		return 1
   123  	}
   124  	if len(jobs) > 1 && strings.TrimSpace(jobID) != jobs[0].ID {
   125  		c.Ui.Error(fmt.Sprintf("Prefix matched multiple jobs\n\n%s", createStatusListOutput(jobs)))
   126  		return 1
   127  	}
   128  	jobID = jobs[0].ID
   129  
   130  	// Do a prefix lookup
   131  	deploy, _, err := client.Jobs().LatestDeployment(jobID, nil)
   132  	if err != nil {
   133  		c.Ui.Error(fmt.Sprintf("Error retrieving deployment: %s", err))
   134  		return 1
   135  	}
   136  
   137  	if deploy == nil {
   138  		c.Ui.Error(fmt.Sprintf("Job %q has no deployment to promote", jobID))
   139  		return 1
   140  	}
   141  
   142  	var u *api.DeploymentUpdateResponse
   143  	if len(groups) == 0 {
   144  		u, _, err = client.Deployments().PromoteAll(deploy.ID, nil)
   145  	} else {
   146  		u, _, err = client.Deployments().PromoteGroups(deploy.ID, groups, nil)
   147  	}
   148  
   149  	if err != nil {
   150  		c.Ui.Error(fmt.Sprintf("Error promoting deployment %q for job %q: %s", deploy.ID, jobID, err))
   151  		return 1
   152  	}
   153  
   154  	// Nothing to do
   155  	evalCreated := u.EvalID != ""
   156  	if detach || !evalCreated {
   157  		return 0
   158  	}
   159  
   160  	mon := newMonitor(c.Ui, client, length)
   161  	return mon.monitor(u.EvalID, false)
   162  }