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