github.com/djenriquez/nomad-1@v0.8.1/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/flag-helpers"
    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  General Options:
    32  
    33    ` + generalOptionsUsage() + `
    34  
    35  Dispatch Options:
    36  
    37    -meta <key>=<value>
    38      Meta takes a key/value pair separated by "=". The metadata key will be
    39      merged into the job's metadata. The job may define a default value for the
    40      key which is overridden when dispatching. The flag can be provided more than
    41      once to inject multiple metadata key/value pairs. Arbitrary keys are not
    42      allowed. The parameterized job must allow the key to be merged.
    43      
    44    -detach
    45      Return immediately instead of entering monitor mode. After job dispatch,
    46      the evaluation ID will be printed to the screen, which can be used to
    47      examine the evaluation using the eval-status command.
    48  
    49    -verbose
    50      Display full information.
    51  `
    52  	return strings.TrimSpace(helpText)
    53  }
    54  
    55  func (c *JobDispatchCommand) Synopsis() string {
    56  	return "Dispatch an instance of a parameterized job"
    57  }
    58  
    59  func (c *JobDispatchCommand) AutocompleteFlags() complete.Flags {
    60  	return mergeAutocompleteFlags(c.Meta.AutocompleteFlags(FlagSetClient),
    61  		complete.Flags{
    62  			"-meta":    complete.PredictAnything,
    63  			"-detach":  complete.PredictNothing,
    64  			"-verbose": complete.PredictNothing,
    65  		})
    66  }
    67  
    68  func (c *JobDispatchCommand) AutocompleteArgs() complete.Predictor {
    69  	return complete.PredictFunc(func(a complete.Args) []string {
    70  		client, err := c.Meta.Client()
    71  		if err != nil {
    72  			return nil
    73  		}
    74  
    75  		resp, _, err := client.Search().PrefixSearch(a.Last, contexts.Jobs, nil)
    76  		if err != nil {
    77  			return []string{}
    78  		}
    79  		return resp.Matches[contexts.Jobs]
    80  	})
    81  }
    82  
    83  func (c *JobDispatchCommand) Run(args []string) int {
    84  	var detach, verbose bool
    85  	var meta []string
    86  
    87  	flags := c.Meta.FlagSet("job dispatch", 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)(&meta), "meta", "")
    92  
    93  	if err := flags.Parse(args); err != nil {
    94  		return 1
    95  	}
    96  
    97  	// Truncate the id unless full length is requested
    98  	length := shortId
    99  	if verbose {
   100  		length = fullId
   101  	}
   102  
   103  	// Check that we got exactly one node
   104  	args = flags.Args()
   105  	if l := len(args); l < 1 || l > 2 {
   106  		c.Ui.Error(c.Help())
   107  		return 1
   108  	}
   109  
   110  	job := args[0]
   111  	var payload []byte
   112  	var readErr error
   113  
   114  	// Read the input
   115  	if len(args) == 2 {
   116  		switch args[1] {
   117  		case "-":
   118  			payload, readErr = ioutil.ReadAll(os.Stdin)
   119  		default:
   120  			payload, readErr = ioutil.ReadFile(args[1])
   121  		}
   122  		if readErr != nil {
   123  			c.Ui.Error(fmt.Sprintf("Error reading input data: %v", readErr))
   124  			return 1
   125  		}
   126  	}
   127  
   128  	// Build the meta
   129  	metaMap := make(map[string]string, len(meta))
   130  	for _, m := range meta {
   131  		split := strings.SplitN(m, "=", 2)
   132  		if len(split) != 2 {
   133  			c.Ui.Error(fmt.Sprintf("Error parsing meta value: %v", m))
   134  			return 1
   135  		}
   136  
   137  		metaMap[split[0]] = split[1]
   138  	}
   139  
   140  	// Get the HTTP client
   141  	client, err := c.Meta.Client()
   142  	if err != nil {
   143  		c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err))
   144  		return 1
   145  	}
   146  
   147  	// Dispatch the job
   148  	resp, _, err := client.Jobs().Dispatch(job, metaMap, payload, nil)
   149  	if err != nil {
   150  		c.Ui.Error(fmt.Sprintf("Failed to dispatch job: %s", err))
   151  		return 1
   152  	}
   153  
   154  	// See if an evaluation was created. If the job is periodic there will be no
   155  	// eval.
   156  	evalCreated := resp.EvalID != ""
   157  
   158  	basic := []string{
   159  		fmt.Sprintf("Dispatched Job ID|%s", resp.DispatchedJobID),
   160  	}
   161  	if evalCreated {
   162  		basic = append(basic, fmt.Sprintf("Evaluation ID|%s", limit(resp.EvalID, length)))
   163  	}
   164  	c.Ui.Output(formatKV(basic))
   165  
   166  	// Nothing to do
   167  	if detach || !evalCreated {
   168  		return 0
   169  	}
   170  
   171  	c.Ui.Output("")
   172  	mon := newMonitor(c.Ui, client, length)
   173  	return mon.monitor(resp.EvalID, false)
   174  }