github.com/hernad/nomad@v1.6.112/command/job_eval.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  	"github.com/posener/complete"
    13  )
    14  
    15  type JobEvalCommand struct {
    16  	Meta
    17  	forceRescheduling bool
    18  }
    19  
    20  func (c *JobEvalCommand) Help() string {
    21  	helpText := `
    22  Usage: nomad job eval [options] <job_id>
    23  
    24    Force an evaluation of the provided job ID. Forcing an evaluation will
    25    trigger the scheduler to re-evaluate the job. The force flags allow
    26    operators to force the scheduler to create new allocations under certain
    27    scenarios.
    28  
    29    When ACLs are enabled, this command requires a token with the 'submit-job'
    30    capability for the job's namespace. The 'list-jobs' capability is required to
    31    run the command with a job prefix instead of the exact job ID. The 'read-job'
    32    capability is required to monitor the resulting evaluation when -detach is
    33    not used.
    34  
    35  General Options:
    36  
    37    ` + generalOptionsUsage(usageOptsDefault) + `
    38  
    39  Eval Options:
    40  
    41    -force-reschedule
    42      Force reschedule failed allocations even if they are not currently
    43      eligible for rescheduling.
    44  
    45    -detach
    46      Return immediately instead of entering monitor mode. The ID
    47      of the evaluation created will be printed to the screen, which can be
    48      used 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 *JobEvalCommand) Synopsis() string {
    57  	return "Force an evaluation for the job"
    58  }
    59  
    60  func (c *JobEvalCommand) AutocompleteFlags() complete.Flags {
    61  	return mergeAutocompleteFlags(c.Meta.AutocompleteFlags(FlagSetClient),
    62  		complete.Flags{
    63  			"-force-reschedule": complete.PredictNothing,
    64  			"-detach":           complete.PredictNothing,
    65  			"-verbose":          complete.PredictNothing,
    66  		})
    67  }
    68  
    69  func (c *JobEvalCommand) 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.Jobs, nil)
    77  		if err != nil {
    78  			return []string{}
    79  		}
    80  		return resp.Matches[contexts.Jobs]
    81  	})
    82  }
    83  
    84  func (c *JobEvalCommand) Name() string { return "job eval" }
    85  
    86  func (c *JobEvalCommand) Run(args []string) int {
    87  	var detach, verbose bool
    88  
    89  	flags := c.Meta.FlagSet(c.Name(), FlagSetClient)
    90  	flags.Usage = func() { c.Ui.Output(c.Help()) }
    91  	flags.BoolVar(&c.forceRescheduling, "force-reschedule", false, "")
    92  	flags.BoolVar(&detach, "detach", false, "")
    93  	flags.BoolVar(&verbose, "verbose", false, "")
    94  
    95  	if err := flags.Parse(args); err != nil {
    96  		return 1
    97  	}
    98  
    99  	// Check that we either got no jobs or exactly one.
   100  	args = flags.Args()
   101  	if len(args) != 1 {
   102  		c.Ui.Error("This command takes one argument: <job>")
   103  		c.Ui.Error(commandErrorText(c))
   104  		return 1
   105  	}
   106  
   107  	// Get the HTTP client
   108  	client, err := c.Meta.Client()
   109  	if err != nil {
   110  		c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err))
   111  		return 1
   112  	}
   113  
   114  	// Truncate the id unless full length is requested
   115  	length := shortId
   116  	if verbose {
   117  		length = fullId
   118  	}
   119  
   120  	// Check if the job exists
   121  	jobIDPrefix := strings.TrimSpace(args[0])
   122  	jobID, namespace, err := c.JobIDByPrefix(client, jobIDPrefix, nil)
   123  	if err != nil {
   124  		c.Ui.Error(err.Error())
   125  		return 1
   126  	}
   127  
   128  	// Call eval endpoint
   129  	opts := api.EvalOptions{
   130  		ForceReschedule: c.forceRescheduling,
   131  	}
   132  	w := &api.WriteOptions{
   133  		Namespace: namespace,
   134  	}
   135  	evalId, _, err := client.Jobs().EvaluateWithOpts(jobID, opts, w)
   136  	if err != nil {
   137  		c.Ui.Error(fmt.Sprintf("Error evaluating job: %s", err))
   138  		return 1
   139  	}
   140  
   141  	if detach {
   142  		c.Ui.Output(fmt.Sprintf("Created eval ID: %q ", limit(evalId, length)))
   143  		return 0
   144  	}
   145  
   146  	mon := newMonitor(c.Ui, client, length)
   147  	return mon.monitor(evalId)
   148  }