github.com/Ilhicas/nomad@v1.0.4-0.20210304152020-e86851182bc3/command/alloc_restart.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  	"github.com/posener/complete"
    10  )
    11  
    12  type AllocRestartCommand struct {
    13  	Meta
    14  }
    15  
    16  func (a *AllocRestartCommand) Help() string {
    17  	helpText := `
    18  Usage: nomad alloc restart [options] <allocation> <task>
    19  
    20    Restart an existing allocation. This command is used to restart a specific alloc
    21    and its tasks. If no task is provided then all of the allocation's tasks will
    22    be restarted.
    23  
    24    When ACLs are enabled, this command requires a token with the
    25    'alloc-lifecycle', 'read-job', and 'list-jobs' capabilities for the
    26    allocation's namespace.
    27  
    28  General Options:
    29  
    30    ` + generalOptionsUsage(usageOptsDefault) + `
    31  
    32  Restart Specific Options:
    33  
    34    -verbose
    35      Show full information.
    36  `
    37  	return strings.TrimSpace(helpText)
    38  }
    39  
    40  func (c *AllocRestartCommand) Name() string { return "alloc restart" }
    41  
    42  func (c *AllocRestartCommand) Run(args []string) int {
    43  	var verbose bool
    44  
    45  	flags := c.Meta.FlagSet(c.Name(), FlagSetClient)
    46  	flags.Usage = func() { c.Ui.Output(c.Help()) }
    47  	flags.BoolVar(&verbose, "verbose", false, "")
    48  
    49  	if err := flags.Parse(args); err != nil {
    50  		return 1
    51  	}
    52  
    53  	// Check that we got exactly one alloc
    54  	args = flags.Args()
    55  	if len(args) < 1 || len(args) > 2 {
    56  		c.Ui.Error("This command takes one or two arguments: <alloc-id> <task-name>")
    57  		c.Ui.Error(commandErrorText(c))
    58  		return 1
    59  	}
    60  
    61  	allocID := args[0]
    62  
    63  	// Truncate the id unless full length is requested
    64  	length := shortId
    65  	if verbose {
    66  		length = fullId
    67  	}
    68  
    69  	// Query the allocation info
    70  	if len(allocID) == 1 {
    71  		c.Ui.Error("Alloc ID must contain at least two characters.")
    72  		return 1
    73  	}
    74  
    75  	allocID = sanitizeUUIDPrefix(allocID)
    76  
    77  	// Get the HTTP client
    78  	client, err := c.Meta.Client()
    79  	if err != nil {
    80  		c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err))
    81  		return 1
    82  	}
    83  
    84  	allocs, _, err := client.Allocations().PrefixList(allocID)
    85  	if err != nil {
    86  		c.Ui.Error(fmt.Sprintf("Error querying allocation: %v", err))
    87  		return 1
    88  	}
    89  
    90  	if len(allocs) == 0 {
    91  		c.Ui.Error(fmt.Sprintf("No allocation(s) with prefix or id %q found", allocID))
    92  		return 1
    93  	}
    94  
    95  	if len(allocs) > 1 {
    96  		// Format the allocs
    97  		out := formatAllocListStubs(allocs, verbose, length)
    98  		c.Ui.Error(fmt.Sprintf("Prefix matched multiple allocations\n\n%s", out))
    99  		return 1
   100  	}
   101  
   102  	// Prefix lookup matched a single allocation
   103  	q := &api.QueryOptions{Namespace: allocs[0].Namespace}
   104  	alloc, _, err := client.Allocations().Info(allocs[0].ID, q)
   105  	if err != nil {
   106  		c.Ui.Error(fmt.Sprintf("Error querying allocation: %s", err))
   107  		return 1
   108  	}
   109  
   110  	var taskName string
   111  	if len(args) == 2 {
   112  		// Validate Task
   113  		taskName = args[1]
   114  		err := validateTaskExistsInAllocation(taskName, alloc)
   115  		if err != nil {
   116  			c.Ui.Error(err.Error())
   117  			return 1
   118  		}
   119  	}
   120  
   121  	err = client.Allocations().Restart(alloc, taskName, nil)
   122  	if err != nil {
   123  		c.Ui.Error(fmt.Sprintf("Failed to restart allocation:\n\n%s", err.Error()))
   124  		return 1
   125  	}
   126  
   127  	return 0
   128  }
   129  
   130  func validateTaskExistsInAllocation(taskName string, alloc *api.Allocation) error {
   131  	tg := alloc.Job.LookupTaskGroup(alloc.TaskGroup)
   132  	if tg == nil {
   133  		return fmt.Errorf("Could not find allocation task group: %s", alloc.TaskGroup)
   134  	}
   135  
   136  	foundTaskNames := make([]string, len(tg.Tasks))
   137  	for i, task := range tg.Tasks {
   138  		foundTaskNames[i] = task.Name
   139  		if task.Name == taskName {
   140  			return nil
   141  		}
   142  	}
   143  
   144  	return fmt.Errorf("Could not find task named: %s, found:\n%s", taskName, formatList(foundTaskNames))
   145  }
   146  
   147  func (a *AllocRestartCommand) Synopsis() string {
   148  	return "Restart a running allocation"
   149  }
   150  
   151  func (c *AllocRestartCommand) AutocompleteArgs() complete.Predictor {
   152  	// Here we attempt to autocomplete allocations for any position of arg.
   153  	// We should eventually try to auto complete the task name if the arg is
   154  	// at position 2.
   155  	return complete.PredictFunc(func(a complete.Args) []string {
   156  		client, err := c.Meta.Client()
   157  		if err != nil {
   158  			return nil
   159  		}
   160  
   161  		resp, _, err := client.Search().PrefixSearch(a.Last, contexts.Allocs, nil)
   162  		if err != nil {
   163  			return []string{}
   164  		}
   165  		return resp.Matches[contexts.Allocs]
   166  	})
   167  }