예제 #1
0
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
}
예제 #2
0
파일: helpers.go 프로젝트: achanda/nomad
// 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
}
예제 #3
0
파일: validate.go 프로젝트: PagerDuty/nomad
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
}
예제 #4
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)
}
예제 #5
0
파일: run.go 프로젝트: PagerDuty/nomad
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)

}
예제 #6
0
파일: plan.go 프로젝트: PagerDuty/nomad
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)
}