github.com/Ilhicas/nomad@v1.0.4-0.20210304152020-e86851182bc3/command/job_dispatch.go (about)

     1  package command
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"strings"
     8  
     9  	"github.com/hashicorp/nomad/api/contexts"
    10  	flaghelper "github.com/hashicorp/nomad/helper/flags"
    11  	"github.com/posener/complete"
    12  )
    13  
    14  type JobDispatchCommand struct {
    15  	Meta
    16  }
    17  
    18  func (c *JobDispatchCommand) Help() string {
    19  	helpText := `
    20  Usage: nomad job dispatch [options] <parameterized job> [input source]
    21  
    22    Dispatch creates an instance of a parameterized job. A data payload to the
    23    dispatched instance can be provided via stdin by using "-" or by specifying a
    24    path to a file. Metadata can be supplied by using the meta flag one or more
    25    times.
    26  
    27    Upon successful creation, the dispatched job ID will be printed and the
    28    triggered evaluation will be monitored. This can be disabled by supplying the
    29    detach flag.
    30  
    31    When ACLs are enabled, this command requires a token with the 'dispatch-job'
    32    capability for the job's namespace.
    33  
    34  General Options:
    35  
    36    ` + generalOptionsUsage(usageOptsDefault) + `
    37  
    38  Dispatch Options:
    39  
    40    -meta <key>=<value>
    41      Meta takes a key/value pair separated by "=". The metadata key will be
    42      merged into the job's metadata. The job may define a default value for the
    43      key which is overridden when dispatching. The flag can be provided more than
    44      once to inject multiple metadata key/value pairs. Arbitrary keys are not
    45      allowed. The parameterized job must allow the key to be merged.
    46  
    47    -detach
    48      Return immediately instead of entering monitor mode. After job dispatch,
    49      the evaluation ID will be printed to the screen, which can be used to
    50      examine the evaluation using the eval-status command.
    51  
    52    -verbose
    53      Display full information.
    54  `
    55  	return strings.TrimSpace(helpText)
    56  }
    57  
    58  func (c *JobDispatchCommand) Synopsis() string {
    59  	return "Dispatch an instance of a parameterized job"
    60  }
    61  
    62  func (c *JobDispatchCommand) AutocompleteFlags() complete.Flags {
    63  	return mergeAutocompleteFlags(c.Meta.AutocompleteFlags(FlagSetClient),
    64  		complete.Flags{
    65  			"-meta":    complete.PredictAnything,
    66  			"-detach":  complete.PredictNothing,
    67  			"-verbose": complete.PredictNothing,
    68  		})
    69  }
    70  
    71  func (c *JobDispatchCommand) AutocompleteArgs() complete.Predictor {
    72  	return complete.PredictFunc(func(a complete.Args) []string {
    73  		client, err := c.Meta.Client()
    74  		if err != nil {
    75  			return nil
    76  		}
    77  
    78  		resp, _, err := client.Search().PrefixSearch(a.Last, contexts.Jobs, nil)
    79  		if err != nil {
    80  			return []string{}
    81  		}
    82  		return resp.Matches[contexts.Jobs]
    83  	})
    84  }
    85  
    86  func (c *JobDispatchCommand) Name() string { return "job dispatch" }
    87  
    88  func (c *JobDispatchCommand) Run(args []string) int {
    89  	var detach, verbose bool
    90  	var meta []string
    91  
    92  	flags := c.Meta.FlagSet(c.Name(), FlagSetClient)
    93  	flags.Usage = func() { c.Ui.Output(c.Help()) }
    94  	flags.BoolVar(&detach, "detach", false, "")
    95  	flags.BoolVar(&verbose, "verbose", false, "")
    96  	flags.Var((*flaghelper.StringFlag)(&meta), "meta", "")
    97  
    98  	if err := flags.Parse(args); err != nil {
    99  		return 1
   100  	}
   101  
   102  	// Truncate the id unless full length is requested
   103  	length := shortId
   104  	if verbose {
   105  		length = fullId
   106  	}
   107  
   108  	// Check that we got one or two arguments
   109  	args = flags.Args()
   110  	if l := len(args); l < 1 || l > 2 {
   111  		c.Ui.Error("This command takes one or two argument: <parameterized job> [input source]")
   112  		c.Ui.Error(commandErrorText(c))
   113  		return 1
   114  	}
   115  
   116  	job := args[0]
   117  	var payload []byte
   118  	var readErr error
   119  
   120  	// Read the input
   121  	if len(args) == 2 {
   122  		switch args[1] {
   123  		case "-":
   124  			payload, readErr = ioutil.ReadAll(os.Stdin)
   125  		default:
   126  			payload, readErr = ioutil.ReadFile(args[1])
   127  		}
   128  		if readErr != nil {
   129  			c.Ui.Error(fmt.Sprintf("Error reading input data: %v", readErr))
   130  			return 1
   131  		}
   132  	}
   133  
   134  	// Build the meta
   135  	metaMap := make(map[string]string, len(meta))
   136  	for _, m := range meta {
   137  		split := strings.SplitN(m, "=", 2)
   138  		if len(split) != 2 {
   139  			c.Ui.Error(fmt.Sprintf("Error parsing meta value: %v", m))
   140  			return 1
   141  		}
   142  
   143  		metaMap[split[0]] = split[1]
   144  	}
   145  
   146  	// Get the HTTP client
   147  	client, err := c.Meta.Client()
   148  	if err != nil {
   149  		c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err))
   150  		return 1
   151  	}
   152  
   153  	// Dispatch the job
   154  	resp, _, err := client.Jobs().Dispatch(job, metaMap, payload, nil)
   155  	if err != nil {
   156  		c.Ui.Error(fmt.Sprintf("Failed to dispatch job: %s", err))
   157  		return 1
   158  	}
   159  
   160  	// See if an evaluation was created. If the job is periodic there will be no
   161  	// eval.
   162  	evalCreated := resp.EvalID != ""
   163  
   164  	basic := []string{
   165  		fmt.Sprintf("Dispatched Job ID|%s", resp.DispatchedJobID),
   166  	}
   167  	if evalCreated {
   168  		basic = append(basic, fmt.Sprintf("Evaluation ID|%s", limit(resp.EvalID, length)))
   169  	}
   170  	c.Ui.Output(formatKV(basic))
   171  
   172  	// Nothing to do
   173  	if detach || !evalCreated {
   174  		return 0
   175  	}
   176  
   177  	c.Ui.Output("")
   178  	mon := newMonitor(c.Ui, client, length)
   179  	return mon.monitor(resp.EvalID)
   180  }