// UpsertJobSummary upserts a job summary into the state store.
559002
func (s *StateStore) UpsertJobSummary(index uint64, jobSummary *structs.JobSummary) error {
	txn := s.db.Txn(true)
	defer txn.Abort()

	// COMPAT 0.7: Upgrade old objects that do not have namespaces
	if jobSummary.Namespace == "" {
		jobSummary.Namespace = structs.DefaultNamespace
	}

	// Check if the job summary already exists
	existing, err := txn.First("job_summary", "id", jobSummary.Namespace, jobSummary.JobID)
	if err != nil {
		return fmt.Errorf("job summary lookup failed: %v", err)
	}

	// Setup the indexes correctly
	if existing != nil {
		jobSummary.CreateIndex = existing.(*structs.JobSummary).CreateIndex
		jobSummary.ModifyIndex = index
	} else {
		jobSummary.CreateIndex = index
		jobSummary.ModifyIndex = index
	}

	// Update the index
	if err := txn.Insert("job_summary", jobSummary); err != nil {
		return err
	}

	// Update the indexes table for job summary
	if err := txn.Insert("index", &IndexEntry{"job_summary", index}); err != nil {
		return fmt.Errorf("index update failed: %v", err)
	}

	txn.Commit()
	return nil
}
338306
func (p *ReadOnlySchedulerClient) GetJobUpdateSummaries(ctx context.Context, jobUpdateQuery *JobUpdateQuery) (r *Response, err error) {
  var _args70 ReadOnlySchedulerGetJobUpdateSummariesArgs
  _args70.JobUpdateQuery = jobUpdateQuery
  var _result71 ReadOnlySchedulerGetJobUpdateSummariesResult
  if err = p.Client_().Call(ctx, "getJobUpdateSummaries", &_args70, &_result71); err != nil {
    return
  }
  return _result71.GetSuccess(), nil
}
607043
func (s *StateStore) ReconcileJobSummaries(index uint64) error {
	txn := s.db.Txn(true)
	defer txn.Abort()

	// Get all the jobs
	iter, err := txn.Get("jobs", "id")
	if err != nil {
		return err
	}
	// COMPAT: Remove after 0.11
	// Iterate over jobs to build a list of parent jobs and their children
	parentMap := make(map[string][]*structs.Job)
	for {
		rawJob := iter.Next()
		if rawJob == nil {
			break
		}
		job := rawJob.(*structs.Job)
		if job.ParentID != "" {
			children := parentMap[job.ParentID]
			children = append(children, job)
			parentMap[job.ParentID] = children
		}
	}

	// Get all the jobs again
	iter, err = txn.Get("jobs", "id")
	if err != nil {
		return err
	}

	for {
		rawJob := iter.Next()
		if rawJob == nil {
			break
		}
		job := rawJob.(*structs.Job)

		if job.IsParameterized() || job.IsPeriodic() {
			// COMPAT: Remove after 0.11

			// The following block of code fixes incorrect child summaries due to a bug
			// See https://github.com/hashicorp/nomad/issues/3886 for details
			rawSummary, err := txn.First("job_summary", "id", job.Namespace, job.ID)
			if err != nil {
				return err
			}
			if rawSummary == nil {
				continue
			}

			oldSummary := rawSummary.(*structs.JobSummary)

			// Create an empty summary
			summary := &structs.JobSummary{
				JobID:     job.ID,
				Namespace: job.Namespace,
				Summary:   make(map[string]structs.TaskGroupSummary),
				Children:  &structs.JobChildrenSummary{},
			}

			// Iterate over children of this job if any to fix summary counts
			children := parentMap[job.ID]
			for _, childJob := range children {
				switch childJob.Status {
				case structs.JobStatusPending:
					summary.Children.Pending++
				case structs.JobStatusDead:
					summary.Children.Dead++
				case structs.JobStatusRunning:
					summary.Children.Running++
				}
			}

			// Insert the job summary if its different
			if !reflect.DeepEqual(summary, oldSummary) {
				// Set the create index of the summary same as the job's create index
				// and the modify index to the current index
				summary.CreateIndex = job.CreateIndex
				summary.ModifyIndex = index

				if err := txn.Insert("job_summary", summary); err != nil {
					return fmt.Errorf("error inserting job summary: %v", err)
				}
			}

			// Done with handling a parent job, continue to next
			continue
		}

		// Create a job summary for the job
		summary := &structs.JobSummary{
			JobID:     job.ID,
			Namespace: job.Namespace,
			Summary:   make(map[string]structs.TaskGroupSummary),
		}
		for _, tg := range job.TaskGroups {
			summary.Summary[tg.Name] = structs.TaskGroupSummary{}
		}

		// COMPAT 0.7: Upgrade old objects that do not have namespaces
		if job.Namespace == "" {
			job.Namespace = structs.DefaultNamespace
		}

		// Find all the allocations for the jobs
		iterAllocs, err := txn.Get("allocs", "job", job.Namespace, job.ID)
		if err != nil {
			return err
		}

		// Calculate the summary for the job
		for {
			rawAlloc := iterAllocs.Next()
			if rawAlloc == nil {
				break
			}
			alloc := rawAlloc.(*structs.Allocation)

			// Ignore the allocation if it doesn't belong to the currently
			// registered job. The allocation is checked because of issue #2304
			if alloc.Job == nil || alloc.Job.CreateIndex != job.CreateIndex {
				continue
			}

			tg := summary.Summary[alloc.TaskGroup]
			switch alloc.ClientStatus {
			case structs.AllocClientStatusFailed:
				tg.Failed += 1
			case structs.AllocClientStatusLost:
				tg.Lost += 1
			case structs.AllocClientStatusComplete:
				tg.Complete += 1
			case structs.AllocClientStatusRunning:
				tg.Running += 1
			case structs.AllocClientStatusPending:
				tg.Starting += 1
			default:
				s.logger.Error("invalid client status set on allocation", "client_status", alloc.ClientStatus, "alloc_id", alloc.ID)
			}
			summary.Summary[alloc.TaskGroup] = tg
		}

		// Set the create index of the summary same as the job's create index
		// and the modify index to the current index
		summary.CreateIndex = job.CreateIndex
		summary.ModifyIndex = index

		// Insert the job summary
		if err := txn.Insert("job_summary", summary); err != nil {
			return fmt.Errorf("error inserting job summary: %v", err)
		}
	}

	// Update the indexes table for job summary
	if err := txn.Insert("index", &IndexEntry{"job_summary", index}); err != nil {
		return fmt.Errorf("index update failed: %v", err)
	}
	txn.Commit()
	return nil
}
379848
func (s *Server) UpdateJob(j *Job, status JobStatus, code int, message string) error {
	var mr multipartRequest
	mr.init()
	mr.WriteField("jobid", j.ID)
	mr.WriteField("printerid", j.PrinterID)
	mr.WriteField("status", string(status))
	if status == JobError {
		mr.WriteField("code", fmt.Sprint(code))
		mr.WriteField("message", message)
	}

	err := jsonRPC(&s.auth, "POST", cloudprintURL+"/control", &mr, nil)
	if err != nil {
		return fmt.Errorf("UpdateJob: %v", err)
	}
	return nil
}
944585
func (s *StateStore) upsertJobVersion(index uint64, job *structs.Job, txn *memdb.Txn) error {
	// COMPAT 0.7: Upgrade old objects that do not have namespaces
	if job.Namespace == "" {
		job.Namespace = structs.DefaultNamespace
	}

	// Insert the job
	if err := txn.Insert("job_version", job); err != nil {
		return fmt.Errorf("failed to insert job into job_version table: %v", err)
	}

	if err := txn.Insert("index", &IndexEntry{"job_version", index}); err != nil {
		return fmt.Errorf("index update failed: %v", err)
	}

	// Get all the historic jobs for this ID
	all, err := s.jobVersionByID(txn, nil, job.Namespace, job.ID)
	if err != nil {
		return fmt.Errorf("failed to look up job versions for %q: %v", job.ID, err)
	}

	// If we are below the limit there is no GCing to be done
	if len(all) <= structs.JobTrackedVersions {
		return nil
	}

	// We have to delete a historic job to make room.
	// Find index of the highest versioned stable job
	stableIdx := -1
	for i, j := range all {
		if j.Stable {
			stableIdx = i
			break
		}
	}

	// If the stable job is the oldest version, do a swap to bring it into the
	// keep set.
	max := structs.JobTrackedVersions
	if stableIdx == max {
		all[max-1], all[max] = all[max], all[max-1]
	}

	// Delete the job outside of the set that are being kept.
	d := all[max]
	if err := txn.Delete("job_version", d); err != nil {
		return fmt.Errorf("failed to delete job %v (%d) from job_version", d.ID, d.Version)
	}

	return nil
}
190974
func (s *BoltStateDB) PutDeploymentStatus(allocID string, ds *structs.AllocDeploymentStatus) error {
	return s.db.Update(func(tx *boltdd.Tx) error {
		return putDeploymentStatusImpl(tx, allocID, ds)
	})
}
90807
func (s *System) ReconcileJobSummaries(args *structs.GenericRequest, reply *structs.GenericResponse) error {
	if done, err := s.srv.forward("System.ReconcileJobSummaries", args, args, reply); done {
		return err
	}

	// Check management level permissions
	if acl, err := s.srv.ResolveToken(args.AuthToken); err != nil {
		return err
	} else if acl != nil && !acl.IsManagement() {
		return structs.ErrPermissionDenied
	}

	_, index, err := s.srv.raftApply(structs.ReconcileJobSummariesRequestType, args)
	if err != nil {
		return fmt.Errorf("reconciliation of job summaries failed: %v", err)
	}
	reply.Index = index
	return nil
}
721913
func (db *DB) StoreBlockSummary(bd *apitypes.BlockDataBasic) error {
	return db.StoreBlock(bd, true, true)
}
1198878
func (c *JobStatusCommand) outputJobSummary(client *api.Client, job *api.Job) error {
	// Query the summary
	summary, _, err := client.Jobs().Summary(*job.ID, nil)
	if err != nil {
		return fmt.Errorf("Error querying job summary: %s", err)
	}

	if summary == nil {
		return nil
	}

	periodic := job.IsPeriodic()
	parameterizedJob := job.IsParameterized()

	// Print the summary
	if !periodic && !parameterizedJob {
		c.Ui.Output(c.Colorize().Color("\n[bold]Summary[reset]"))
		summaries := make([]string, len(summary.Summary)+1)
		summaries[0] = "Task Group|Queued|Starting|Running|Failed|Complete|Lost"
		taskGroups := make([]string, 0, len(summary.Summary))
		for taskGroup := range summary.Summary {
			taskGroups = append(taskGroups, taskGroup)
		}
		sort.Strings(taskGroups)
		for idx, taskGroup := range taskGroups {
			tgs := summary.Summary[taskGroup]
			summaries[idx+1] = fmt.Sprintf("%s|%d|%d|%d|%d|%d|%d",
				taskGroup, tgs.Queued, tgs.Starting,
				tgs.Running, tgs.Failed,
				tgs.Complete, tgs.Lost,
			)
		}
		c.Ui.Output(formatList(summaries))
	}

	// Always display the summary if we are periodic or parameterized, but
	// only display if the summary is non-zero on normal jobs
	if summary.Children != nil && (parameterizedJob || periodic || summary.Children.Sum() > 0) {
		if parameterizedJob {
			c.Ui.Output(c.Colorize().Color("\n[bold]Parameterized Job Summary[reset]"))
		} else {
			c.Ui.Output(c.Colorize().Color("\n[bold]Children Job Summary[reset]"))
		}
		summaries := make([]string, 2)
		summaries[0] = "Pending|Running|Dead"
		summaries[1] = fmt.Sprintf("%d|%d|%d",
			summary.Children.Pending, summary.Children.Running, summary.Children.Dead)
		c.Ui.Output(formatList(summaries))
	}

	return nil
}
602157
func (s *StateStore) deleteJobVersions(index uint64, job *structs.Job, txn *memdb.Txn) error {
	// COMPAT 0.7: Upgrade old objects that do not have namespaces
	if job.Namespace == "" {
		job.Namespace = structs.DefaultNamespace
	}

	iter, err := txn.Get("job_version", "id_prefix", job.Namespace, job.ID)
	if err != nil {
		return err
	}

	// Put them into a slice so there are no safety concerns while actually
	// performing the deletes
	jobs := []*structs.Job{}
	for {
		raw := iter.Next()
		if raw == nil {
			break
		}

		// Ensure the ID is an exact match
		j := raw.(*structs.Job)
		if j.ID != job.ID {
			continue
		}

		jobs = append(jobs, j)
	}

	// Do the deletes
	for _, j := range jobs {
		if err := txn.Delete("job_version", j); err != nil {
			return fmt.Errorf("deleting job versions failed: %v", err)
		}
	}

	if err := txn.Insert("index", &IndexEntry{"job_version", index}); err != nil {
		return fmt.Errorf("index update failed: %v", err)
	}

	return nil
}
615026
func (s *StateStore) setJobStatuses(index uint64, txn *memdb.Txn,
	jobs map[structs.NamespacedID]string, evalDelete bool) error {
	for tuple, forceStatus := range jobs {
		// COMPAT 0.7: Upgrade old objects that do not have namespaces
		if tuple.Namespace == "" {
			tuple.Namespace = structs.DefaultNamespace
		}

		existing, err := txn.First("jobs", "id", tuple.Namespace, tuple.ID)
		if err != nil {
			return fmt.Errorf("job lookup failed: %v", err)
		}

		if existing == nil {
			continue
		}

		if err := s.setJobStatus(index, txn, existing.(*structs.Job), evalDelete, forceStatus); err != nil {
			return err
		}
	}

	return nil
}
280225
func (s *StopJobOutput) SetJobSummary(v *JobSummary) *StopJobOutput {
	s.JobSummary = v
	return s
}
460356
func (ctl *Controller) updateJobStateHandler(c context.Context, payload proto.Message) error {
	msg := payload.(*tasks.UpdateJobState)

	// Get the job and all its shards in their most recent state.
	job, err := getJobInState(c, JobID(msg.JobId), State_RUNNING, State_ABORTING)
	if err != nil || job == nil {
		return errors.Annotate(err, "in UpdateJobState").Err()
	}
	shards, err := job.fetchShards(c)
	if err != nil {
		return errors.Annotate(err, "failed to fetch shards").Err()
	}

	// Switch the job into a final state only when all shards are done running.
	perState := make(map[State]int, len(State_name))
	finished := 0
	for _, sh := range shards {
		logging.Infof(c, "Shard #%d (%d) is in state %s", sh.Index, sh.ID, sh.State)
		perState[sh.State]++
		if isFinalState(sh.State) {
			finished++
		}
	}
	if finished != len(shards) {
		return nil
	}

	jobState := State_SUCCESS
	switch {
	case perState[State_ABORTED] != 0:
		jobState = State_ABORTED
	case perState[State_FAIL] != 0:
		jobState = State_FAIL
	}

	return runTxn(c, func(c context.Context) error {
		job, err := getJobInState(c, JobID(msg.JobId), State_RUNNING, State_ABORTING)
		if err != nil || job == nil {
			return errors.Annotate(err, "in UpdateJobState txn").Err()
		}

		// Make sure an aborting job ends up in aborted state, even if all its
		// shards manged to finish. It looks weird when an ABORTING job moves
		// into e.g. SUCCESS state.
		if job.State == State_ABORTING {
			job.State = State_ABORTED
		} else {
			job.State = jobState
		}
		job.Updated = clock.Now(c).UTC()

		runtime := job.Updated.Sub(job.Created)
		switch job.State {
		case State_SUCCESS:
			logging.Infof(c, "The job finished successfully in %s", runtime)
		case State_FAIL:
			logging.Errorf(c, "The job finished with %d shards failing in %s", perState[State_FAIL], runtime)
			for _, sh := range shards {
				if sh.State == State_FAIL {
					logging.Errorf(c, "Shard #%d (%d) error - %s", sh.Index, sh.ID, sh.Error)
				}
			}
		case State_ABORTED:
			logging.Warningf(c, "The job has been aborted after %s: %d shards succeeded, %d shards failed, %d shards aborted",
				runtime, perState[State_SUCCESS], perState[State_FAIL], perState[State_ABORTED])
		}

		return transient.Tag.Apply(datastore.Put(c, job))
	})
}
183632
func (s *StateStore) UpdateJobStability(index uint64, namespace, jobID string, jobVersion uint64, stable bool) error {
	txn := s.db.Txn(true)
	defer txn.Abort()

	// COMPAT 0.7: Upgrade old objects that do not have namespaces
	if namespace == "" {
		namespace = structs.DefaultNamespace
	}

	if err := s.updateJobStabilityImpl(index, namespace, jobID, jobVersion, stable, txn); err != nil {
		return err
	}

	txn.Commit()
	return nil
}
396567
func (s *ListTrainingJobsOutput) SetTrainingJobSummaries(v []*TrainingJobSummary) *ListTrainingJobsOutput {
	s.TrainingJobSummaries = v
	return s
}
442101
func (s *boshDirector) ChangeJobState(deployment, job, state string, index int) (int, error) {
	endpoint := fmt.Sprintf("%s:%d/deployments/%s/jobs/%s/%d?state=%s", s.ip, s.port, deployment, job, index, state)
	req, err := s.client.NewRequest("PUT", endpoint, nil)
	if err != nil {
		return 0, errwrap.Wrap(err, "failed creating request")
	}
	req.Header.Set("content-type", "text/yaml")
	res, err := s.client.HTTPClient().Do(req)
	if err != nil {
		return 0, errwrap.Wrap(err, "failed calling http client")
	}
	taskID, err := retrieveTaskID(res)
	if err != nil {
		return 0, errwrap.Wrap(err, "failed retrieving taskid from response body")
	}

	if taskID == 0 {
		return 0, fmt.Errorf("invalid taskid returned. value is: %v", taskID)
	}
	return taskID, nil
}
171227
func (s *StateStore) UpsertJobTxn(index uint64, job *structs.Job, txn Txn) error {
	return s.upsertJobImpl(index, job, false, txn)
}