github.com/hernad/nomad@v1.6.112/command/deployment_promote.go (about)

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