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