github.com/iqoqo/nomad@v0.11.3-0.20200911112621-d7021c74d101/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) Name() string { return "job dispatch" } 84 85 func (c *JobDispatchCommand) Run(args []string) int { 86 var detach, verbose bool 87 var meta []string 88 89 flags := c.Meta.FlagSet(c.Name(), FlagSetClient) 90 flags.Usage = func() { c.Ui.Output(c.Help()) } 91 flags.BoolVar(&detach, "detach", false, "") 92 flags.BoolVar(&verbose, "verbose", false, "") 93 flags.Var((*flaghelper.StringFlag)(&meta), "meta", "") 94 95 if err := flags.Parse(args); err != nil { 96 return 1 97 } 98 99 // Truncate the id unless full length is requested 100 length := shortId 101 if verbose { 102 length = fullId 103 } 104 105 // Check that we got one or two arguments 106 args = flags.Args() 107 if l := len(args); l < 1 || l > 2 { 108 c.Ui.Error("This command takes one or two argument: <parameterized job> [input source]") 109 c.Ui.Error(commandErrorText(c)) 110 return 1 111 } 112 113 job := args[0] 114 var payload []byte 115 var readErr error 116 117 // Read the input 118 if len(args) == 2 { 119 switch args[1] { 120 case "-": 121 payload, readErr = ioutil.ReadAll(os.Stdin) 122 default: 123 payload, readErr = ioutil.ReadFile(args[1]) 124 } 125 if readErr != nil { 126 c.Ui.Error(fmt.Sprintf("Error reading input data: %v", readErr)) 127 return 1 128 } 129 } 130 131 // Build the meta 132 metaMap := make(map[string]string, len(meta)) 133 for _, m := range meta { 134 split := strings.SplitN(m, "=", 2) 135 if len(split) != 2 { 136 c.Ui.Error(fmt.Sprintf("Error parsing meta value: %v", m)) 137 return 1 138 } 139 140 metaMap[split[0]] = split[1] 141 } 142 143 // Get the HTTP client 144 client, err := c.Meta.Client() 145 if err != nil { 146 c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err)) 147 return 1 148 } 149 150 // Dispatch the job 151 resp, _, err := client.Jobs().Dispatch(job, metaMap, payload, nil) 152 if err != nil { 153 c.Ui.Error(fmt.Sprintf("Failed to dispatch job: %s", err)) 154 return 1 155 } 156 157 // See if an evaluation was created. If the job is periodic there will be no 158 // eval. 159 evalCreated := resp.EvalID != "" 160 161 basic := []string{ 162 fmt.Sprintf("Dispatched Job ID|%s", resp.DispatchedJobID), 163 } 164 if evalCreated { 165 basic = append(basic, fmt.Sprintf("Evaluation ID|%s", limit(resp.EvalID, length))) 166 } 167 c.Ui.Output(formatKV(basic)) 168 169 // Nothing to do 170 if detach || !evalCreated { 171 return 0 172 } 173 174 c.Ui.Output("") 175 mon := newMonitor(c.Ui, client, length) 176 return mon.monitor(resp.EvalID, false) 177 }