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 }