func resourceJobRegister(d *schema.ResourceData, meta interface{}) error { client := meta.(*api.Client) // Get the jobspec itself jobspecRaw := d.Get("jobspec").(string) // Parse it jobspecStruct, err := jobspec.Parse(strings.NewReader(jobspecRaw)) if err != nil { return fmt.Errorf("error parsing jobspec: %s", err) } // Initialize and validate jobspecStruct.Canonicalize() if err := jobspecStruct.Validate(); err != nil { return fmt.Errorf("Error validating job: %v", err) } // If we have an ID and its not equal to this jobspec, then we // have to deregister the old job before we register the new job. prevId := d.Id() if !d.Get("deregister_on_id_change").(bool) { // If we aren't deregistering on ID change, just pretend we // don't have a prior ID. prevId = "" } if prevId != "" && prevId != jobspecStruct.ID { log.Printf( "[INFO] Deregistering %q before registering %q", prevId, jobspecStruct.ID) log.Printf("[DEBUG] Deregistering job: %q", prevId) _, _, err := client.Jobs().Deregister(prevId, nil) if err != nil { return fmt.Errorf( "error deregistering previous job %q "+ "before registering new job %q: %s", prevId, jobspecStruct.ID, err) } // Success! Clear our state. d.SetId("") } // Convert it so that we can use it with the API jobspecAPI, err := convertStructJob(jobspecStruct) if err != nil { return fmt.Errorf("error converting jobspec: %s", err) } // Register the job _, _, err = client.Jobs().Register(jobspecAPI, nil) if err != nil { return fmt.Errorf("error applying jobspec: %s", err) } d.SetId(jobspecAPI.ID) return nil }
// StructJob returns the Job struct from jobfile. func (j *JobGetter) StructJob(jpath string) (*structs.Job, error) { var jobfile io.Reader switch jpath { case "-": if j.testStdin != nil { jobfile = j.testStdin } else { jobfile = os.Stdin } default: if len(jpath) == 0 { return nil, fmt.Errorf("Error jobfile path has to be specified.") } job, err := ioutil.TempFile("", "jobfile") if err != nil { return nil, err } defer os.Remove(job.Name()) if err := job.Close(); err != nil { return nil, err } // Get the pwd pwd, err := os.Getwd() if err != nil { return nil, err } client := &gg.Client{ Src: jpath, Pwd: pwd, Dst: job.Name(), } if err := client.Get(); err != nil { return nil, fmt.Errorf("Error getting jobfile from %q: %v", jpath, err) } else { file, err := os.Open(job.Name()) defer file.Close() if err != nil { return nil, fmt.Errorf("Error opening file %q: %v", jpath, err) } jobfile = file } } // Parse the JobFile jobStruct, err := jobspec.Parse(jobfile) if err != nil { fmt.Errorf("Error parsing job file from %s: %v", jpath, err) return nil, err } return jobStruct, nil }
func (c *ValidateCommand) Run(args []string) int { flags := c.Meta.FlagSet("validate", FlagSetNone) flags.Usage = func() { c.Ui.Output(c.Help()) } if err := flags.Parse(args); err != nil { return 1 } // Check that we got exactly one node args = flags.Args() if len(args) != 1 { c.Ui.Error(c.Help()) return 1 } // Read the Jobfile path := args[0] var f io.Reader switch path { case "-": if c.testStdin != nil { f = c.testStdin } else { f = os.Stdin } path = "stdin" default: file, err := os.Open(path) defer file.Close() if err != nil { c.Ui.Error(fmt.Sprintf("Error opening file %q: %v", path, err)) return 1 } f = file } // Parse the JobFile job, err := jobspec.Parse(f) if err != nil { c.Ui.Error(fmt.Sprintf("Error parsing job file from %s: %v", path, err)) return 1 } // Initialize any fields that need to be. job.Canonicalize() // Check that the job is valid if err := job.Validate(); err != nil { c.Ui.Error(fmt.Sprintf("Error validating job: %s", err)) return 1 } // Done! c.Ui.Output("Job validation successful") return 0 }
// jobspecDiffSuppress is the DiffSuppressFunc used by the schema to // check if two jobspecs are equal. func jobspecDiffSuppress(k, old, new string, d *schema.ResourceData) bool { // Parse the old job oldJob, err := jobspec.Parse(strings.NewReader(old)) if err != nil { return false } // Parse the new job newJob, err := jobspec.Parse(strings.NewReader(new)) if err != nil { return false } // Init oldJob.Canonicalize() newJob.Canonicalize() // Check for jobspec equality return reflect.DeepEqual(oldJob, newJob) }
func (c *RunCommand) Run(args []string) int { var detach, verbose, output bool var checkIndexStr string flags := c.Meta.FlagSet("run", FlagSetClient) flags.Usage = func() { c.Ui.Output(c.Help()) } flags.BoolVar(&detach, "detach", false, "") flags.BoolVar(&verbose, "verbose", false, "") flags.BoolVar(&output, "output", false, "") flags.StringVar(&checkIndexStr, "check-index", "", "") if err := flags.Parse(args); err != nil { return 1 } // Truncate the id unless full length is requested length := shortId if verbose { length = fullId } // Check that we got exactly one argument args = flags.Args() if len(args) != 1 { c.Ui.Error(c.Help()) return 1 } // Read the Jobfile path := args[0] var f io.Reader switch path { case "-": if c.testStdin != nil { f = c.testStdin } else { f = os.Stdin } path = "stdin" default: file, err := os.Open(path) defer file.Close() if err != nil { c.Ui.Error(fmt.Sprintf("Error opening file %q: %v", path, err)) return 1 } f = file } // Parse the JobFile job, err := jobspec.Parse(f) if err != nil { c.Ui.Error(fmt.Sprintf("Error parsing job file from %s: %v", path, err)) return 1 } // Initialize any fields that need to be. job.Canonicalize() // Check that the job is valid if err := job.Validate(); err != nil { c.Ui.Error(fmt.Sprintf("Error validating job: %v", err)) return 1 } // Check if the job is periodic. periodic := job.IsPeriodic() // Convert it to something we can use apiJob, err := convertStructJob(job) if err != nil { c.Ui.Error(fmt.Sprintf("Error converting job: %s", err)) return 1 } if output { req := api.RegisterJobRequest{Job: apiJob} buf, err := json.MarshalIndent(req, "", " ") if err != nil { c.Ui.Error(fmt.Sprintf("Error converting job: %s", err)) return 1 } c.Ui.Output(string(buf)) return 0 } // Get the HTTP client client, err := c.Meta.Client() if err != nil { c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err)) return 1 } // Force the region to be that of the job. if r := job.Region; r != "" { client.SetRegion(r) } // Parse the check-index checkIndex, enforce, err := parseCheckIndex(checkIndexStr) if err != nil { c.Ui.Error(fmt.Sprintf("Error parsing check-index value %q: %v", checkIndexStr, err)) return 1 } // Submit the job var evalID string if enforce { evalID, _, err = client.Jobs().EnforceRegister(apiJob, checkIndex, nil) } else { evalID, _, err = client.Jobs().Register(apiJob, nil) } if err != nil { if strings.Contains(err.Error(), api.RegisterEnforceIndexErrPrefix) { // Format the error specially if the error is due to index // enforcement matches := enforceIndexRegex.FindStringSubmatch(err.Error()) if len(matches) == 2 { c.Ui.Error(matches[1]) // The matched group c.Ui.Error("Job not updated") return 1 } } c.Ui.Error(fmt.Sprintf("Error submitting job: %s", err)) return 1 } // Check if we should enter monitor mode if detach || periodic { c.Ui.Output("Job registration successful") if periodic { now := time.Now().UTC() next := job.Periodic.Next(now) c.Ui.Output(fmt.Sprintf("Approximate next launch time: %s (%s from now)", formatTime(next), formatTimeDifference(now, next, time.Second))) } else { c.Ui.Output("Evaluation ID: " + evalID) } return 0 } // Detach was not specified, so start monitoring mon := newMonitor(c.Ui, client, length) return mon.monitor(evalID, false) }
func (c *PlanCommand) Run(args []string) int { var diff, verbose bool flags := c.Meta.FlagSet("plan", FlagSetClient) flags.Usage = func() { c.Ui.Output(c.Help()) } flags.BoolVar(&diff, "diff", true, "") flags.BoolVar(&verbose, "verbose", false, "") if err := flags.Parse(args); err != nil { return 255 } // Check that we got exactly one job args = flags.Args() if len(args) != 1 { c.Ui.Error(c.Help()) return 255 } // Read the Jobfile path := args[0] var f io.Reader switch path { case "-": if c.testStdin != nil { f = c.testStdin } else { f = os.Stdin } path = "stdin" default: file, err := os.Open(path) defer file.Close() if err != nil { c.Ui.Error(fmt.Sprintf("Error opening file %q: %v", path, err)) return 255 } f = file } // Parse the JobFile job, err := jobspec.Parse(f) if err != nil { c.Ui.Error(fmt.Sprintf("Error parsing job file %s: %v", path, err)) return 255 } // Initialize any fields that need to be. job.Canonicalize() // Check that the job is valid if err := job.Validate(); err != nil { c.Ui.Error(fmt.Sprintf("Error validating job: %s", err)) return 255 } // Convert it to something we can use apiJob, err := convertStructJob(job) if err != nil { c.Ui.Error(fmt.Sprintf("Error converting job: %s", err)) return 255 } // Get the HTTP client client, err := c.Meta.Client() if err != nil { c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err)) return 255 } // Force the region to be that of the job. if r := job.Region; r != "" { client.SetRegion(r) } // Submit the job resp, _, err := client.Jobs().Plan(apiJob, diff, nil) if err != nil { c.Ui.Error(fmt.Sprintf("Error during plan: %s", err)) return 255 } // Print the diff if not disabled if diff { c.Ui.Output(fmt.Sprintf("%s\n", c.Colorize().Color(strings.TrimSpace(formatJobDiff(resp.Diff, verbose))))) } // Print the scheduler dry-run output c.Ui.Output(c.Colorize().Color("[bold]Scheduler dry-run:[reset]")) c.Ui.Output(c.Colorize().Color(formatDryRun(resp, job))) c.Ui.Output("") // Print the job index info c.Ui.Output(c.Colorize().Color(formatJobModifyIndex(resp.JobModifyIndex, path))) return getExitCode(resp) }