github.com/emate/nomad@v0.8.2-wo-binpacking/nomad/state/state_store.go (about)

     1  package state
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io"
     7  	"log"
     8  	"sort"
     9  	"time"
    10  
    11  	"github.com/hashicorp/go-memdb"
    12  	multierror "github.com/hashicorp/go-multierror"
    13  	"github.com/hashicorp/nomad/helper"
    14  	"github.com/hashicorp/nomad/nomad/structs"
    15  )
    16  
    17  // IndexEntry is used with the "index" table
    18  // for managing the latest Raft index affecting a table.
    19  type IndexEntry struct {
    20  	Key   string
    21  	Value uint64
    22  }
    23  
    24  // StateStoreConfig is used to configure a new state store
    25  type StateStoreConfig struct {
    26  	// LogOutput is used to configure the output of the state store's logs
    27  	LogOutput io.Writer
    28  
    29  	// Region is the region of the server embedding the state store.
    30  	Region string
    31  }
    32  
    33  // The StateStore is responsible for maintaining all the Nomad
    34  // state. It is manipulated by the FSM which maintains consistency
    35  // through the use of Raft. The goals of the StateStore are to provide
    36  // high concurrency for read operations without blocking writes, and
    37  // to provide write availability in the face of reads. EVERY object
    38  // returned as a result of a read against the state store should be
    39  // considered a constant and NEVER modified in place.
    40  type StateStore struct {
    41  	logger *log.Logger
    42  	db     *memdb.MemDB
    43  
    44  	// config is the passed in configuration
    45  	config *StateStoreConfig
    46  
    47  	// abandonCh is used to signal watchers that this state store has been
    48  	// abandoned (usually during a restore). This is only ever closed.
    49  	abandonCh chan struct{}
    50  }
    51  
    52  // NewStateStore is used to create a new state store
    53  func NewStateStore(config *StateStoreConfig) (*StateStore, error) {
    54  	// Create the MemDB
    55  	db, err := memdb.NewMemDB(stateStoreSchema())
    56  	if err != nil {
    57  		return nil, fmt.Errorf("state store setup failed: %v", err)
    58  	}
    59  
    60  	// Create the state store
    61  	s := &StateStore{
    62  		logger:    log.New(config.LogOutput, "", log.LstdFlags),
    63  		db:        db,
    64  		config:    config,
    65  		abandonCh: make(chan struct{}),
    66  	}
    67  	return s, nil
    68  }
    69  
    70  // Config returns the state store configuration.
    71  func (s *StateStore) Config() *StateStoreConfig {
    72  	return s.config
    73  }
    74  
    75  // Snapshot is used to create a point in time snapshot. Because
    76  // we use MemDB, we just need to snapshot the state of the underlying
    77  // database.
    78  func (s *StateStore) Snapshot() (*StateSnapshot, error) {
    79  	snap := &StateSnapshot{
    80  		StateStore: StateStore{
    81  			logger: s.logger,
    82  			config: s.config,
    83  			db:     s.db.Snapshot(),
    84  		},
    85  	}
    86  	return snap, nil
    87  }
    88  
    89  // Restore is used to optimize the efficiency of rebuilding
    90  // state by minimizing the number of transactions and checking
    91  // overhead.
    92  func (s *StateStore) Restore() (*StateRestore, error) {
    93  	txn := s.db.Txn(true)
    94  	r := &StateRestore{
    95  		txn: txn,
    96  	}
    97  	return r, nil
    98  }
    99  
   100  // AbandonCh returns a channel you can wait on to know if the state store was
   101  // abandoned.
   102  func (s *StateStore) AbandonCh() <-chan struct{} {
   103  	return s.abandonCh
   104  }
   105  
   106  // Abandon is used to signal that the given state store has been abandoned.
   107  // Calling this more than one time will panic.
   108  func (s *StateStore) Abandon() {
   109  	close(s.abandonCh)
   110  }
   111  
   112  // QueryFn is the definition of a function that can be used to implement a basic
   113  // blocking query against the state store.
   114  type QueryFn func(memdb.WatchSet, *StateStore) (resp interface{}, index uint64, err error)
   115  
   116  // BlockingQuery takes a query function and runs the function until the minimum
   117  // query index is met or until the passed context is cancelled.
   118  func (s *StateStore) BlockingQuery(query QueryFn, minIndex uint64, ctx context.Context) (
   119  	resp interface{}, index uint64, err error) {
   120  
   121  RUN_QUERY:
   122  	// We capture the state store and its abandon channel but pass a snapshot to
   123  	// the blocking query function. We operate on the snapshot to allow separate
   124  	// calls to the state store not all wrapped within the same transaction.
   125  	abandonCh := s.AbandonCh()
   126  	snap, _ := s.Snapshot()
   127  	stateSnap := &snap.StateStore
   128  
   129  	// We can skip all watch tracking if this isn't a blocking query.
   130  	var ws memdb.WatchSet
   131  	if minIndex > 0 {
   132  		ws = memdb.NewWatchSet()
   133  
   134  		// This channel will be closed if a snapshot is restored and the
   135  		// whole state store is abandoned.
   136  		ws.Add(abandonCh)
   137  	}
   138  
   139  	resp, index, err = query(ws, stateSnap)
   140  	if err != nil {
   141  		return nil, index, err
   142  	}
   143  
   144  	// We haven't reached the min-index yet.
   145  	if minIndex > 0 && index <= minIndex {
   146  		if err := ws.WatchCtx(ctx); err != nil {
   147  			return nil, index, err
   148  		}
   149  
   150  		goto RUN_QUERY
   151  	}
   152  
   153  	return resp, index, nil
   154  }
   155  
   156  // UpsertPlanResults is used to upsert the results of a plan.
   157  func (s *StateStore) UpsertPlanResults(index uint64, results *structs.ApplyPlanResultsRequest) error {
   158  	txn := s.db.Txn(true)
   159  	defer txn.Abort()
   160  
   161  	// Upsert the newly created or updated deployment
   162  	if results.Deployment != nil {
   163  		if err := s.upsertDeploymentImpl(index, results.Deployment, txn); err != nil {
   164  			return err
   165  		}
   166  	}
   167  
   168  	// Update the status of deployments effected by the plan.
   169  	if len(results.DeploymentUpdates) != 0 {
   170  		s.upsertDeploymentUpdates(index, results.DeploymentUpdates, txn)
   171  	}
   172  
   173  	// Attach the job to all the allocations. It is pulled out in the payload to
   174  	// avoid the redundancy of encoding, but should be denormalized prior to
   175  	// being inserted into MemDB.
   176  	structs.DenormalizeAllocationJobs(results.Job, results.Alloc)
   177  
   178  	// Calculate the total resources of allocations. It is pulled out in the
   179  	// payload to avoid encoding something that can be computed, but should be
   180  	// denormalized prior to being inserted into MemDB.
   181  	for _, alloc := range results.Alloc {
   182  		if alloc.Resources != nil {
   183  			continue
   184  		}
   185  
   186  		alloc.Resources = new(structs.Resources)
   187  		for _, task := range alloc.TaskResources {
   188  			alloc.Resources.Add(task)
   189  		}
   190  
   191  		// Add the shared resources
   192  		alloc.Resources.Add(alloc.SharedResources)
   193  	}
   194  
   195  	// Upsert the allocations
   196  	if err := s.upsertAllocsImpl(index, results.Alloc, txn); err != nil {
   197  		return err
   198  	}
   199  
   200  	// COMPAT: Nomad versions before 0.7.1 did not include the eval ID when
   201  	// applying the plan. Thus while we are upgrading, we ignore updating the
   202  	// modify index of evaluations from older plans.
   203  	if results.EvalID != "" {
   204  		// Update the modify index of the eval id
   205  		if err := s.updateEvalModifyIndex(txn, index, results.EvalID); err != nil {
   206  			return err
   207  		}
   208  	}
   209  
   210  	txn.Commit()
   211  	return nil
   212  }
   213  
   214  // upsertDeploymentUpdates updates the deployments given the passed status
   215  // updates.
   216  func (s *StateStore) upsertDeploymentUpdates(index uint64, updates []*structs.DeploymentStatusUpdate, txn *memdb.Txn) error {
   217  	for _, u := range updates {
   218  		if err := s.updateDeploymentStatusImpl(index, u, txn); err != nil {
   219  			return err
   220  		}
   221  	}
   222  
   223  	return nil
   224  }
   225  
   226  // UpsertJobSummary upserts a job summary into the state store.
   227  func (s *StateStore) UpsertJobSummary(index uint64, jobSummary *structs.JobSummary) error {
   228  	txn := s.db.Txn(true)
   229  	defer txn.Abort()
   230  
   231  	// COMPAT 0.7: Upgrade old objects that do not have namespaces
   232  	if jobSummary.Namespace == "" {
   233  		jobSummary.Namespace = structs.DefaultNamespace
   234  	}
   235  
   236  	// Check if the job summary already exists
   237  	existing, err := txn.First("job_summary", "id", jobSummary.Namespace, jobSummary.JobID)
   238  	if err != nil {
   239  		return fmt.Errorf("job summary lookup failed: %v", err)
   240  	}
   241  
   242  	// Setup the indexes correctly
   243  	if existing != nil {
   244  		jobSummary.CreateIndex = existing.(*structs.JobSummary).CreateIndex
   245  		jobSummary.ModifyIndex = index
   246  	} else {
   247  		jobSummary.CreateIndex = index
   248  		jobSummary.ModifyIndex = index
   249  	}
   250  
   251  	// Update the index
   252  	if err := txn.Insert("job_summary", jobSummary); err != nil {
   253  		return err
   254  	}
   255  
   256  	// Update the indexes table for job summary
   257  	if err := txn.Insert("index", &IndexEntry{"job_summary", index}); err != nil {
   258  		return fmt.Errorf("index update failed: %v", err)
   259  	}
   260  
   261  	txn.Commit()
   262  	return nil
   263  }
   264  
   265  // DeleteJobSummary deletes the job summary with the given ID. This is for
   266  // testing purposes only.
   267  func (s *StateStore) DeleteJobSummary(index uint64, namespace, id string) error {
   268  	txn := s.db.Txn(true)
   269  	defer txn.Abort()
   270  
   271  	// COMPAT 0.7: Upgrade old objects that do not have namespaces
   272  	if namespace == "" {
   273  		namespace = structs.DefaultNamespace
   274  	}
   275  
   276  	// Delete the job summary
   277  	if _, err := txn.DeleteAll("job_summary", "id", namespace, id); err != nil {
   278  		return fmt.Errorf("deleting job summary failed: %v", err)
   279  	}
   280  	if err := txn.Insert("index", &IndexEntry{"job_summary", index}); err != nil {
   281  		return fmt.Errorf("index update failed: %v", err)
   282  	}
   283  	txn.Commit()
   284  	return nil
   285  }
   286  
   287  // UpsertDeployment is used to insert a new deployment. If cancelPrior is set to
   288  // true, all prior deployments for the same job will be cancelled.
   289  func (s *StateStore) UpsertDeployment(index uint64, deployment *structs.Deployment) error {
   290  	txn := s.db.Txn(true)
   291  	defer txn.Abort()
   292  	if err := s.upsertDeploymentImpl(index, deployment, txn); err != nil {
   293  		return err
   294  	}
   295  	txn.Commit()
   296  	return nil
   297  }
   298  
   299  func (s *StateStore) upsertDeploymentImpl(index uint64, deployment *structs.Deployment, txn *memdb.Txn) error {
   300  	// Check if the deployment already exists
   301  	existing, err := txn.First("deployment", "id", deployment.ID)
   302  	if err != nil {
   303  		return fmt.Errorf("deployment lookup failed: %v", err)
   304  	}
   305  
   306  	// COMPAT 0.7: Upgrade old objects that do not have namespaces
   307  	if deployment.Namespace == "" {
   308  		deployment.Namespace = structs.DefaultNamespace
   309  	}
   310  
   311  	// Setup the indexes correctly
   312  	if existing != nil {
   313  		deployment.CreateIndex = existing.(*structs.Deployment).CreateIndex
   314  		deployment.ModifyIndex = index
   315  	} else {
   316  		deployment.CreateIndex = index
   317  		deployment.ModifyIndex = index
   318  	}
   319  
   320  	// Insert the deployment
   321  	if err := txn.Insert("deployment", deployment); err != nil {
   322  		return err
   323  	}
   324  
   325  	// Update the indexes table for deployment
   326  	if err := txn.Insert("index", &IndexEntry{"deployment", index}); err != nil {
   327  		return fmt.Errorf("index update failed: %v", err)
   328  	}
   329  
   330  	// If the deployment is being marked as complete, set the job to stable.
   331  	if deployment.Status == structs.DeploymentStatusSuccessful {
   332  		if err := s.updateJobStabilityImpl(index, deployment.Namespace, deployment.JobID, deployment.JobVersion, true, txn); err != nil {
   333  			return fmt.Errorf("failed to update job stability: %v", err)
   334  		}
   335  	}
   336  
   337  	return nil
   338  }
   339  
   340  func (s *StateStore) Deployments(ws memdb.WatchSet) (memdb.ResultIterator, error) {
   341  	txn := s.db.Txn(false)
   342  
   343  	// Walk the entire deployments table
   344  	iter, err := txn.Get("deployment", "id")
   345  	if err != nil {
   346  		return nil, err
   347  	}
   348  
   349  	ws.Add(iter.WatchCh())
   350  	return iter, nil
   351  }
   352  
   353  func (s *StateStore) DeploymentsByNamespace(ws memdb.WatchSet, namespace string) (memdb.ResultIterator, error) {
   354  	txn := s.db.Txn(false)
   355  
   356  	// Walk the entire deployments table
   357  	iter, err := txn.Get("deployment", "namespace", namespace)
   358  	if err != nil {
   359  		return nil, err
   360  	}
   361  
   362  	ws.Add(iter.WatchCh())
   363  	return iter, nil
   364  }
   365  
   366  func (s *StateStore) DeploymentsByIDPrefix(ws memdb.WatchSet, namespace, deploymentID string) (memdb.ResultIterator, error) {
   367  	txn := s.db.Txn(false)
   368  
   369  	// Walk the entire deployments table
   370  	iter, err := txn.Get("deployment", "id_prefix", deploymentID)
   371  	if err != nil {
   372  		return nil, err
   373  	}
   374  
   375  	ws.Add(iter.WatchCh())
   376  
   377  	// Wrap the iterator in a filter
   378  	wrap := memdb.NewFilterIterator(iter, deploymentNamespaceFilter(namespace))
   379  	return wrap, nil
   380  }
   381  
   382  // deploymentNamespaceFilter returns a filter function that filters all
   383  // deployment not in the given namespace.
   384  func deploymentNamespaceFilter(namespace string) func(interface{}) bool {
   385  	return func(raw interface{}) bool {
   386  		d, ok := raw.(*structs.Deployment)
   387  		if !ok {
   388  			return true
   389  		}
   390  
   391  		return d.Namespace != namespace
   392  	}
   393  }
   394  
   395  func (s *StateStore) DeploymentByID(ws memdb.WatchSet, deploymentID string) (*structs.Deployment, error) {
   396  	txn := s.db.Txn(false)
   397  	return s.deploymentByIDImpl(ws, deploymentID, txn)
   398  }
   399  
   400  func (s *StateStore) deploymentByIDImpl(ws memdb.WatchSet, deploymentID string, txn *memdb.Txn) (*structs.Deployment, error) {
   401  	watchCh, existing, err := txn.FirstWatch("deployment", "id", deploymentID)
   402  	if err != nil {
   403  		return nil, fmt.Errorf("deployment lookup failed: %v", err)
   404  	}
   405  	ws.Add(watchCh)
   406  
   407  	if existing != nil {
   408  		return existing.(*structs.Deployment), nil
   409  	}
   410  
   411  	return nil, nil
   412  }
   413  
   414  func (s *StateStore) DeploymentsByJobID(ws memdb.WatchSet, namespace, jobID string) ([]*structs.Deployment, error) {
   415  	txn := s.db.Txn(false)
   416  
   417  	// COMPAT 0.7: Upgrade old objects that do not have namespaces
   418  	if namespace == "" {
   419  		namespace = structs.DefaultNamespace
   420  	}
   421  
   422  	// Get an iterator over the deployments
   423  	iter, err := txn.Get("deployment", "job", namespace, jobID)
   424  	if err != nil {
   425  		return nil, err
   426  	}
   427  
   428  	ws.Add(iter.WatchCh())
   429  
   430  	var out []*structs.Deployment
   431  	for {
   432  		raw := iter.Next()
   433  		if raw == nil {
   434  			break
   435  		}
   436  
   437  		d := raw.(*structs.Deployment)
   438  		out = append(out, d)
   439  	}
   440  
   441  	return out, nil
   442  }
   443  
   444  // LatestDeploymentByJobID returns the latest deployment for the given job. The
   445  // latest is determined strictly by CreateIndex.
   446  func (s *StateStore) LatestDeploymentByJobID(ws memdb.WatchSet, namespace, jobID string) (*structs.Deployment, error) {
   447  	txn := s.db.Txn(false)
   448  
   449  	// COMPAT 0.7: Upgrade old objects that do not have namespaces
   450  	if namespace == "" {
   451  		namespace = structs.DefaultNamespace
   452  	}
   453  
   454  	// Get an iterator over the deployments
   455  	iter, err := txn.Get("deployment", "job", namespace, jobID)
   456  	if err != nil {
   457  		return nil, err
   458  	}
   459  
   460  	ws.Add(iter.WatchCh())
   461  
   462  	var out *structs.Deployment
   463  	for {
   464  		raw := iter.Next()
   465  		if raw == nil {
   466  			break
   467  		}
   468  
   469  		d := raw.(*structs.Deployment)
   470  		if out == nil || out.CreateIndex < d.CreateIndex {
   471  			out = d
   472  		}
   473  	}
   474  
   475  	return out, nil
   476  }
   477  
   478  // DeleteDeployment is used to delete a set of deployments by ID
   479  func (s *StateStore) DeleteDeployment(index uint64, deploymentIDs []string) error {
   480  	txn := s.db.Txn(true)
   481  	defer txn.Abort()
   482  
   483  	if len(deploymentIDs) == 0 {
   484  		return nil
   485  	}
   486  
   487  	for _, deploymentID := range deploymentIDs {
   488  		// Lookup the deployment
   489  		existing, err := txn.First("deployment", "id", deploymentID)
   490  		if err != nil {
   491  			return fmt.Errorf("deployment lookup failed: %v", err)
   492  		}
   493  		if existing == nil {
   494  			return fmt.Errorf("deployment not found")
   495  		}
   496  
   497  		// Delete the deployment
   498  		if err := txn.Delete("deployment", existing); err != nil {
   499  			return fmt.Errorf("deployment delete failed: %v", err)
   500  		}
   501  	}
   502  
   503  	if err := txn.Insert("index", &IndexEntry{"deployment", index}); err != nil {
   504  		return fmt.Errorf("index update failed: %v", err)
   505  	}
   506  
   507  	txn.Commit()
   508  	return nil
   509  }
   510  
   511  // UpsertNode is used to register a node or update a node definition
   512  // This is assumed to be triggered by the client, so we retain the value
   513  // of drain/eligibility which is set by the scheduler.
   514  func (s *StateStore) UpsertNode(index uint64, node *structs.Node) error {
   515  	txn := s.db.Txn(true)
   516  	defer txn.Abort()
   517  
   518  	// Check if the node already exists
   519  	existing, err := txn.First("nodes", "id", node.ID)
   520  	if err != nil {
   521  		return fmt.Errorf("node lookup failed: %v", err)
   522  	}
   523  
   524  	// Setup the indexes correctly
   525  	if existing != nil {
   526  		exist := existing.(*structs.Node)
   527  		node.CreateIndex = exist.CreateIndex
   528  		node.ModifyIndex = index
   529  
   530  		// Retain node events that have already been set on the node
   531  		node.Events = exist.Events
   532  
   533  		node.Drain = exist.Drain                                 // Retain the drain mode
   534  		node.SchedulingEligibility = exist.SchedulingEligibility // Retain the eligibility
   535  		node.DrainStrategy = exist.DrainStrategy                 // Retain the drain strategy
   536  	} else {
   537  		// Because this is the first time the node is being registered, we should
   538  		// also create a node registration event
   539  		nodeEvent := &structs.NodeEvent{
   540  			Message:   "Node Registered",
   541  			Subsystem: "Cluster",
   542  			Timestamp: time.Unix(node.StatusUpdatedAt, 0),
   543  		}
   544  		node.Events = []*structs.NodeEvent{nodeEvent}
   545  		node.CreateIndex = index
   546  		node.ModifyIndex = index
   547  	}
   548  
   549  	// Insert the node
   550  	if err := txn.Insert("nodes", node); err != nil {
   551  		return fmt.Errorf("node insert failed: %v", err)
   552  	}
   553  	if err := txn.Insert("index", &IndexEntry{"nodes", index}); err != nil {
   554  		return fmt.Errorf("index update failed: %v", err)
   555  	}
   556  
   557  	txn.Commit()
   558  	return nil
   559  }
   560  
   561  // DeleteNode is used to deregister a node
   562  func (s *StateStore) DeleteNode(index uint64, nodeID string) error {
   563  	txn := s.db.Txn(true)
   564  	defer txn.Abort()
   565  
   566  	// Lookup the node
   567  	existing, err := txn.First("nodes", "id", nodeID)
   568  	if err != nil {
   569  		return fmt.Errorf("node lookup failed: %v", err)
   570  	}
   571  	if existing == nil {
   572  		return fmt.Errorf("node not found")
   573  	}
   574  
   575  	// Delete the node
   576  	if err := txn.Delete("nodes", existing); err != nil {
   577  		return fmt.Errorf("node delete failed: %v", err)
   578  	}
   579  	if err := txn.Insert("index", &IndexEntry{"nodes", index}); err != nil {
   580  		return fmt.Errorf("index update failed: %v", err)
   581  	}
   582  
   583  	txn.Commit()
   584  	return nil
   585  }
   586  
   587  // UpdateNodeStatus is used to update the status of a node
   588  func (s *StateStore) UpdateNodeStatus(index uint64, nodeID, status string) error {
   589  	txn := s.db.Txn(true)
   590  	defer txn.Abort()
   591  
   592  	// Lookup the node
   593  	existing, err := txn.First("nodes", "id", nodeID)
   594  	if err != nil {
   595  		return fmt.Errorf("node lookup failed: %v", err)
   596  	}
   597  	if existing == nil {
   598  		return fmt.Errorf("node not found")
   599  	}
   600  
   601  	// Copy the existing node
   602  	existingNode := existing.(*structs.Node)
   603  	copyNode := existingNode.Copy()
   604  
   605  	// Update the status in the copy
   606  	copyNode.Status = status
   607  	copyNode.ModifyIndex = index
   608  
   609  	// Insert the node
   610  	if err := txn.Insert("nodes", copyNode); err != nil {
   611  		return fmt.Errorf("node update failed: %v", err)
   612  	}
   613  	if err := txn.Insert("index", &IndexEntry{"nodes", index}); err != nil {
   614  		return fmt.Errorf("index update failed: %v", err)
   615  	}
   616  
   617  	txn.Commit()
   618  	return nil
   619  }
   620  
   621  // BatchUpdateNodeDrain is used to update the drain of a node set of nodes
   622  func (s *StateStore) BatchUpdateNodeDrain(index uint64, updates map[string]*structs.DrainUpdate) error {
   623  	txn := s.db.Txn(true)
   624  	defer txn.Abort()
   625  	for node, update := range updates {
   626  		if err := s.updateNodeDrainImpl(txn, index, node, update.DrainStrategy, update.MarkEligible); err != nil {
   627  			return err
   628  		}
   629  	}
   630  	txn.Commit()
   631  	return nil
   632  }
   633  
   634  // UpdateNodeDrain is used to update the drain of a node
   635  func (s *StateStore) UpdateNodeDrain(index uint64, nodeID string,
   636  	drain *structs.DrainStrategy, markEligible bool) error {
   637  
   638  	txn := s.db.Txn(true)
   639  	defer txn.Abort()
   640  	if err := s.updateNodeDrainImpl(txn, index, nodeID, drain, markEligible); err != nil {
   641  		return err
   642  	}
   643  	txn.Commit()
   644  	return nil
   645  }
   646  
   647  func (s *StateStore) updateNodeDrainImpl(txn *memdb.Txn, index uint64, nodeID string,
   648  	drain *structs.DrainStrategy, markEligible bool) error {
   649  
   650  	// Lookup the node
   651  	existing, err := txn.First("nodes", "id", nodeID)
   652  	if err != nil {
   653  		return fmt.Errorf("node lookup failed: %v", err)
   654  	}
   655  	if existing == nil {
   656  		return fmt.Errorf("node not found")
   657  	}
   658  
   659  	// Copy the existing node
   660  	existingNode := existing.(*structs.Node)
   661  	copyNode := existingNode.Copy()
   662  
   663  	// Update the drain in the copy
   664  	copyNode.Drain = drain != nil // COMPAT: Remove in Nomad 0.9
   665  	copyNode.DrainStrategy = drain
   666  	if drain != nil {
   667  		copyNode.SchedulingEligibility = structs.NodeSchedulingIneligible
   668  	} else if markEligible {
   669  		copyNode.SchedulingEligibility = structs.NodeSchedulingEligible
   670  	}
   671  
   672  	copyNode.ModifyIndex = index
   673  
   674  	// Insert the node
   675  	if err := txn.Insert("nodes", copyNode); err != nil {
   676  		return fmt.Errorf("node update failed: %v", err)
   677  	}
   678  	if err := txn.Insert("index", &IndexEntry{"nodes", index}); err != nil {
   679  		return fmt.Errorf("index update failed: %v", err)
   680  	}
   681  
   682  	return nil
   683  }
   684  
   685  // UpdateNodeEligibility is used to update the scheduling eligibility of a node
   686  func (s *StateStore) UpdateNodeEligibility(index uint64, nodeID string, eligibility string) error {
   687  
   688  	txn := s.db.Txn(true)
   689  	defer txn.Abort()
   690  
   691  	// Lookup the node
   692  	existing, err := txn.First("nodes", "id", nodeID)
   693  	if err != nil {
   694  		return fmt.Errorf("node lookup failed: %v", err)
   695  	}
   696  	if existing == nil {
   697  		return fmt.Errorf("node not found")
   698  	}
   699  
   700  	// Copy the existing node
   701  	existingNode := existing.(*structs.Node)
   702  	copyNode := existingNode.Copy()
   703  
   704  	// Check if this is a valid action
   705  	if copyNode.DrainStrategy != nil && eligibility == structs.NodeSchedulingEligible {
   706  		return fmt.Errorf("can not set node's scheduling eligibility to eligible while it is draining")
   707  	}
   708  
   709  	// Update the eligibility in the copy
   710  	copyNode.SchedulingEligibility = eligibility
   711  	copyNode.ModifyIndex = index
   712  
   713  	// Insert the node
   714  	if err := txn.Insert("nodes", copyNode); err != nil {
   715  		return fmt.Errorf("node update failed: %v", err)
   716  	}
   717  	if err := txn.Insert("index", &IndexEntry{"nodes", index}); err != nil {
   718  		return fmt.Errorf("index update failed: %v", err)
   719  	}
   720  
   721  	txn.Commit()
   722  	return nil
   723  }
   724  
   725  // UpsertNodeEvents adds the node events to the nodes, rotating events as
   726  // necessary.
   727  func (s *StateStore) UpsertNodeEvents(index uint64, nodeEvents map[string][]*structs.NodeEvent) error {
   728  	txn := s.db.Txn(true)
   729  	defer txn.Abort()
   730  
   731  	for nodeID, events := range nodeEvents {
   732  		if err := s.upsertNodeEvents(index, nodeID, events, txn); err != nil {
   733  			return err
   734  		}
   735  	}
   736  
   737  	txn.Commit()
   738  	return nil
   739  }
   740  
   741  // upsertNodeEvent upserts a node event for a respective node. It also maintains
   742  // that a fixed number of node events are ever stored simultaneously, deleting
   743  // older events once this bound has been reached.
   744  func (s *StateStore) upsertNodeEvents(index uint64, nodeID string, events []*structs.NodeEvent, txn *memdb.Txn) error {
   745  	// Lookup the node
   746  	existing, err := txn.First("nodes", "id", nodeID)
   747  	if err != nil {
   748  		return fmt.Errorf("node lookup failed: %v", err)
   749  	}
   750  	if existing == nil {
   751  		return fmt.Errorf("node not found")
   752  	}
   753  
   754  	// Copy the existing node
   755  	existingNode := existing.(*structs.Node)
   756  	copyNode := existingNode.Copy()
   757  
   758  	// Add the events, updating the indexes
   759  	for _, e := range events {
   760  		e.CreateIndex = index
   761  		copyNode.Events = append(copyNode.Events, e)
   762  	}
   763  
   764  	// Keep node events pruned to not exceed the max allowed
   765  	if l := len(copyNode.Events); l > structs.MaxRetainedNodeEvents {
   766  		delta := l - structs.MaxRetainedNodeEvents
   767  		copyNode.Events = copyNode.Events[delta:]
   768  	}
   769  
   770  	// Insert the node
   771  	if err := txn.Insert("nodes", copyNode); err != nil {
   772  		return fmt.Errorf("node update failed: %v", err)
   773  	}
   774  	if err := txn.Insert("index", &IndexEntry{"nodes", index}); err != nil {
   775  		return fmt.Errorf("index update failed: %v", err)
   776  	}
   777  
   778  	return nil
   779  }
   780  
   781  // NodeByID is used to lookup a node by ID
   782  func (s *StateStore) NodeByID(ws memdb.WatchSet, nodeID string) (*structs.Node, error) {
   783  	txn := s.db.Txn(false)
   784  
   785  	watchCh, existing, err := txn.FirstWatch("nodes", "id", nodeID)
   786  	if err != nil {
   787  		return nil, fmt.Errorf("node lookup failed: %v", err)
   788  	}
   789  	ws.Add(watchCh)
   790  
   791  	if existing != nil {
   792  		return existing.(*structs.Node), nil
   793  	}
   794  	return nil, nil
   795  }
   796  
   797  // NodesByIDPrefix is used to lookup nodes by prefix
   798  func (s *StateStore) NodesByIDPrefix(ws memdb.WatchSet, nodeID string) (memdb.ResultIterator, error) {
   799  	txn := s.db.Txn(false)
   800  
   801  	iter, err := txn.Get("nodes", "id_prefix", nodeID)
   802  	if err != nil {
   803  		return nil, fmt.Errorf("node lookup failed: %v", err)
   804  	}
   805  	ws.Add(iter.WatchCh())
   806  
   807  	return iter, nil
   808  }
   809  
   810  // NodeBySecretID is used to lookup a node by SecretID
   811  func (s *StateStore) NodeBySecretID(ws memdb.WatchSet, secretID string) (*structs.Node, error) {
   812  	txn := s.db.Txn(false)
   813  
   814  	watchCh, existing, err := txn.FirstWatch("nodes", "secret_id", secretID)
   815  	if err != nil {
   816  		return nil, fmt.Errorf("node lookup by SecretID failed: %v", err)
   817  	}
   818  	ws.Add(watchCh)
   819  
   820  	if existing != nil {
   821  		return existing.(*structs.Node), nil
   822  	}
   823  	return nil, nil
   824  }
   825  
   826  // Nodes returns an iterator over all the nodes
   827  func (s *StateStore) Nodes(ws memdb.WatchSet) (memdb.ResultIterator, error) {
   828  	txn := s.db.Txn(false)
   829  
   830  	// Walk the entire nodes table
   831  	iter, err := txn.Get("nodes", "id")
   832  	if err != nil {
   833  		return nil, err
   834  	}
   835  	ws.Add(iter.WatchCh())
   836  	return iter, nil
   837  }
   838  
   839  // UpsertJob is used to register a job or update a job definition
   840  func (s *StateStore) UpsertJob(index uint64, job *structs.Job) error {
   841  	txn := s.db.Txn(true)
   842  	defer txn.Abort()
   843  	if err := s.upsertJobImpl(index, job, false, txn); err != nil {
   844  		return err
   845  	}
   846  	txn.Commit()
   847  	return nil
   848  }
   849  
   850  // upsertJobImpl is the implementation for registering a job or updating a job definition
   851  func (s *StateStore) upsertJobImpl(index uint64, job *structs.Job, keepVersion bool, txn *memdb.Txn) error {
   852  	// COMPAT 0.7: Upgrade old objects that do not have namespaces
   853  	if job.Namespace == "" {
   854  		job.Namespace = structs.DefaultNamespace
   855  	}
   856  
   857  	// Assert the namespace exists
   858  	if exists, err := s.namespaceExists(txn, job.Namespace); err != nil {
   859  		return err
   860  	} else if !exists {
   861  		return fmt.Errorf("job %q is in nonexistent namespace %q", job.ID, job.Namespace)
   862  	}
   863  
   864  	// Check if the job already exists
   865  	existing, err := txn.First("jobs", "id", job.Namespace, job.ID)
   866  	if err != nil {
   867  		return fmt.Errorf("job lookup failed: %v", err)
   868  	}
   869  
   870  	// Setup the indexes correctly
   871  	if existing != nil {
   872  		job.CreateIndex = existing.(*structs.Job).CreateIndex
   873  		job.ModifyIndex = index
   874  
   875  		// Bump the version unless asked to keep it. This should only be done
   876  		// when changing an internal field such as Stable. A spec change should
   877  		// always come with a version bump
   878  		if !keepVersion {
   879  			job.JobModifyIndex = index
   880  			job.Version = existing.(*structs.Job).Version + 1
   881  		}
   882  
   883  		// Compute the job status
   884  		var err error
   885  		job.Status, err = s.getJobStatus(txn, job, false)
   886  		if err != nil {
   887  			return fmt.Errorf("setting job status for %q failed: %v", job.ID, err)
   888  		}
   889  	} else {
   890  		job.CreateIndex = index
   891  		job.ModifyIndex = index
   892  		job.JobModifyIndex = index
   893  		job.Version = 0
   894  
   895  		if err := s.setJobStatus(index, txn, job, false, ""); err != nil {
   896  			return fmt.Errorf("setting job status for %q failed: %v", job.ID, err)
   897  		}
   898  
   899  		// Have to get the job again since it could have been updated
   900  		updated, err := txn.First("jobs", "id", job.Namespace, job.ID)
   901  		if err != nil {
   902  			return fmt.Errorf("job lookup failed: %v", err)
   903  		}
   904  		if updated != nil {
   905  			job = updated.(*structs.Job)
   906  		}
   907  	}
   908  
   909  	if err := s.updateSummaryWithJob(index, job, txn); err != nil {
   910  		return fmt.Errorf("unable to create job summary: %v", err)
   911  	}
   912  
   913  	if err := s.upsertJobVersion(index, job, txn); err != nil {
   914  		return fmt.Errorf("unable to upsert job into job_version table: %v", err)
   915  	}
   916  
   917  	// Create the EphemeralDisk if it's nil by adding up DiskMB from task resources.
   918  	// COMPAT 0.4.1 -> 0.5
   919  	s.addEphemeralDiskToTaskGroups(job)
   920  
   921  	// Insert the job
   922  	if err := txn.Insert("jobs", job); err != nil {
   923  		return fmt.Errorf("job insert failed: %v", err)
   924  	}
   925  	if err := txn.Insert("index", &IndexEntry{"jobs", index}); err != nil {
   926  		return fmt.Errorf("index update failed: %v", err)
   927  	}
   928  
   929  	return nil
   930  }
   931  
   932  // DeleteJob is used to deregister a job
   933  func (s *StateStore) DeleteJob(index uint64, namespace, jobID string) error {
   934  	txn := s.db.Txn(true)
   935  	defer txn.Abort()
   936  
   937  	// COMPAT 0.7: Upgrade old objects that do not have namespaces
   938  	if namespace == "" {
   939  		namespace = structs.DefaultNamespace
   940  	}
   941  
   942  	// Lookup the node
   943  	existing, err := txn.First("jobs", "id", namespace, jobID)
   944  	if err != nil {
   945  		return fmt.Errorf("job lookup failed: %v", err)
   946  	}
   947  	if existing == nil {
   948  		return fmt.Errorf("job not found")
   949  	}
   950  
   951  	// Check if we should update a parent job summary
   952  	job := existing.(*structs.Job)
   953  	if job.ParentID != "" {
   954  		summaryRaw, err := txn.First("job_summary", "id", namespace, job.ParentID)
   955  		if err != nil {
   956  			return fmt.Errorf("unable to retrieve summary for parent job: %v", err)
   957  		}
   958  
   959  		// Only continue if the summary exists. It could not exist if the parent
   960  		// job was removed
   961  		if summaryRaw != nil {
   962  			existing := summaryRaw.(*structs.JobSummary)
   963  			pSummary := existing.Copy()
   964  			if pSummary.Children != nil {
   965  
   966  				modified := false
   967  				switch job.Status {
   968  				case structs.JobStatusPending:
   969  					pSummary.Children.Pending--
   970  					pSummary.Children.Dead++
   971  					modified = true
   972  				case structs.JobStatusRunning:
   973  					pSummary.Children.Running--
   974  					pSummary.Children.Dead++
   975  					modified = true
   976  				case structs.JobStatusDead:
   977  				default:
   978  					return fmt.Errorf("unknown old job status %q", job.Status)
   979  				}
   980  
   981  				if modified {
   982  					// Update the modify index
   983  					pSummary.ModifyIndex = index
   984  
   985  					// COMPAT 0.7: Upgrade old objects that do not have namespaces
   986  					if pSummary.Namespace == "" {
   987  						pSummary.Namespace = structs.DefaultNamespace
   988  					}
   989  
   990  					// Insert the summary
   991  					if err := txn.Insert("job_summary", pSummary); err != nil {
   992  						return fmt.Errorf("job summary insert failed: %v", err)
   993  					}
   994  					if err := txn.Insert("index", &IndexEntry{"job_summary", index}); err != nil {
   995  						return fmt.Errorf("index update failed: %v", err)
   996  					}
   997  				}
   998  			}
   999  		}
  1000  	}
  1001  
  1002  	// Delete the job
  1003  	if err := txn.Delete("jobs", existing); err != nil {
  1004  		return fmt.Errorf("job delete failed: %v", err)
  1005  	}
  1006  	if err := txn.Insert("index", &IndexEntry{"jobs", index}); err != nil {
  1007  		return fmt.Errorf("index update failed: %v", err)
  1008  	}
  1009  
  1010  	// Delete the job versions
  1011  	if err := s.deleteJobVersions(index, job, txn); err != nil {
  1012  		return err
  1013  	}
  1014  
  1015  	// Delete the job summary
  1016  	if _, err = txn.DeleteAll("job_summary", "id", namespace, jobID); err != nil {
  1017  		return fmt.Errorf("deleing job summary failed: %v", err)
  1018  	}
  1019  	if err := txn.Insert("index", &IndexEntry{"job_summary", index}); err != nil {
  1020  		return fmt.Errorf("index update failed: %v", err)
  1021  	}
  1022  
  1023  	txn.Commit()
  1024  	return nil
  1025  }
  1026  
  1027  // deleteJobVersions deletes all versions of the given job.
  1028  func (s *StateStore) deleteJobVersions(index uint64, job *structs.Job, txn *memdb.Txn) error {
  1029  	// COMPAT 0.7: Upgrade old objects that do not have namespaces
  1030  	if job.Namespace == "" {
  1031  		job.Namespace = structs.DefaultNamespace
  1032  	}
  1033  
  1034  	iter, err := txn.Get("job_version", "id_prefix", job.Namespace, job.ID)
  1035  	if err != nil {
  1036  		return err
  1037  	}
  1038  
  1039  	for {
  1040  		raw := iter.Next()
  1041  		if raw == nil {
  1042  			break
  1043  		}
  1044  
  1045  		// Ensure the ID is an exact match
  1046  		j := raw.(*structs.Job)
  1047  		if j.ID != job.ID {
  1048  			continue
  1049  		}
  1050  
  1051  		if _, err = txn.DeleteAll("job_version", "id", j.Namespace, j.ID, j.Version); err != nil {
  1052  			return fmt.Errorf("deleting job versions failed: %v", err)
  1053  		}
  1054  	}
  1055  
  1056  	if err := txn.Insert("index", &IndexEntry{"job_version", index}); err != nil {
  1057  		return fmt.Errorf("index update failed: %v", err)
  1058  	}
  1059  
  1060  	return nil
  1061  }
  1062  
  1063  // upsertJobVersion inserts a job into its historic version table and limits the
  1064  // number of job versions that are tracked.
  1065  func (s *StateStore) upsertJobVersion(index uint64, job *structs.Job, txn *memdb.Txn) error {
  1066  	// COMPAT 0.7: Upgrade old objects that do not have namespaces
  1067  	if job.Namespace == "" {
  1068  		job.Namespace = structs.DefaultNamespace
  1069  	}
  1070  
  1071  	// Insert the job
  1072  	if err := txn.Insert("job_version", job); err != nil {
  1073  		return fmt.Errorf("failed to insert job into job_version table: %v", err)
  1074  	}
  1075  
  1076  	if err := txn.Insert("index", &IndexEntry{"job_version", index}); err != nil {
  1077  		return fmt.Errorf("index update failed: %v", err)
  1078  	}
  1079  
  1080  	// Get all the historic jobs for this ID
  1081  	all, err := s.jobVersionByID(txn, nil, job.Namespace, job.ID)
  1082  	if err != nil {
  1083  		return fmt.Errorf("failed to look up job versions for %q: %v", job.ID, err)
  1084  	}
  1085  
  1086  	// If we are below the limit there is no GCing to be done
  1087  	if len(all) <= structs.JobTrackedVersions {
  1088  		return nil
  1089  	}
  1090  
  1091  	// We have to delete a historic job to make room.
  1092  	// Find index of the highest versioned stable job
  1093  	stableIdx := -1
  1094  	for i, j := range all {
  1095  		if j.Stable {
  1096  			stableIdx = i
  1097  			break
  1098  		}
  1099  	}
  1100  
  1101  	// If the stable job is the oldest version, do a swap to bring it into the
  1102  	// keep set.
  1103  	max := structs.JobTrackedVersions
  1104  	if stableIdx == max {
  1105  		all[max-1], all[max] = all[max], all[max-1]
  1106  	}
  1107  
  1108  	// Delete the job outside of the set that are being kept.
  1109  	d := all[max]
  1110  	if err := txn.Delete("job_version", d); err != nil {
  1111  		return fmt.Errorf("failed to delete job %v (%d) from job_version", d.ID, d.Version)
  1112  	}
  1113  
  1114  	return nil
  1115  }
  1116  
  1117  // JobByID is used to lookup a job by its ID. JobByID returns the current/latest job
  1118  // version.
  1119  func (s *StateStore) JobByID(ws memdb.WatchSet, namespace, id string) (*structs.Job, error) {
  1120  	txn := s.db.Txn(false)
  1121  
  1122  	// COMPAT 0.7: Upgrade old objects that do not have namespaces
  1123  	if namespace == "" {
  1124  		namespace = structs.DefaultNamespace
  1125  	}
  1126  
  1127  	watchCh, existing, err := txn.FirstWatch("jobs", "id", namespace, id)
  1128  	if err != nil {
  1129  		return nil, fmt.Errorf("job lookup failed: %v", err)
  1130  	}
  1131  	ws.Add(watchCh)
  1132  
  1133  	if existing != nil {
  1134  		return existing.(*structs.Job), nil
  1135  	}
  1136  	return nil, nil
  1137  }
  1138  
  1139  // JobsByIDPrefix is used to lookup a job by prefix
  1140  func (s *StateStore) JobsByIDPrefix(ws memdb.WatchSet, namespace, id string) (memdb.ResultIterator, error) {
  1141  	txn := s.db.Txn(false)
  1142  
  1143  	// COMPAT 0.7: Upgrade old objects that do not have namespaces
  1144  	if namespace == "" {
  1145  		namespace = structs.DefaultNamespace
  1146  	}
  1147  
  1148  	iter, err := txn.Get("jobs", "id_prefix", namespace, id)
  1149  	if err != nil {
  1150  		return nil, fmt.Errorf("job lookup failed: %v", err)
  1151  	}
  1152  
  1153  	ws.Add(iter.WatchCh())
  1154  
  1155  	return iter, nil
  1156  }
  1157  
  1158  // JobVersionsByID returns all the tracked versions of a job.
  1159  func (s *StateStore) JobVersionsByID(ws memdb.WatchSet, namespace, id string) ([]*structs.Job, error) {
  1160  	txn := s.db.Txn(false)
  1161  
  1162  	// COMPAT 0.7: Upgrade old objects that do not have namespaces
  1163  	if namespace == "" {
  1164  		namespace = structs.DefaultNamespace
  1165  	}
  1166  
  1167  	return s.jobVersionByID(txn, &ws, namespace, id)
  1168  }
  1169  
  1170  // jobVersionByID is the underlying implementation for retrieving all tracked
  1171  // versions of a job and is called under an existing transaction. A watch set
  1172  // can optionally be passed in to add the job histories to the watch set.
  1173  func (s *StateStore) jobVersionByID(txn *memdb.Txn, ws *memdb.WatchSet, namespace, id string) ([]*structs.Job, error) {
  1174  	// COMPAT 0.7: Upgrade old objects that do not have namespaces
  1175  	if namespace == "" {
  1176  		namespace = structs.DefaultNamespace
  1177  	}
  1178  
  1179  	// Get all the historic jobs for this ID
  1180  	iter, err := txn.Get("job_version", "id_prefix", namespace, id)
  1181  	if err != nil {
  1182  		return nil, err
  1183  	}
  1184  
  1185  	if ws != nil {
  1186  		ws.Add(iter.WatchCh())
  1187  	}
  1188  
  1189  	var all []*structs.Job
  1190  	for {
  1191  		raw := iter.Next()
  1192  		if raw == nil {
  1193  			break
  1194  		}
  1195  
  1196  		// Ensure the ID is an exact match
  1197  		j := raw.(*structs.Job)
  1198  		if j.ID != id {
  1199  			continue
  1200  		}
  1201  
  1202  		all = append(all, j)
  1203  	}
  1204  
  1205  	// Sort in reverse order so that the highest version is first
  1206  	sort.Slice(all, func(i, j int) bool {
  1207  		return all[i].Version > all[j].Version
  1208  	})
  1209  
  1210  	return all, nil
  1211  }
  1212  
  1213  // JobByIDAndVersion returns the job identified by its ID and Version. The
  1214  // passed watchset may be nil.
  1215  func (s *StateStore) JobByIDAndVersion(ws memdb.WatchSet, namespace, id string, version uint64) (*structs.Job, error) {
  1216  	// COMPAT 0.7: Upgrade old objects that do not have namespaces
  1217  	if namespace == "" {
  1218  		namespace = structs.DefaultNamespace
  1219  	}
  1220  	txn := s.db.Txn(false)
  1221  	return s.jobByIDAndVersionImpl(ws, namespace, id, version, txn)
  1222  }
  1223  
  1224  // jobByIDAndVersionImpl returns the job identified by its ID and Version. The
  1225  // passed watchset may be nil.
  1226  func (s *StateStore) jobByIDAndVersionImpl(ws memdb.WatchSet, namespace, id string,
  1227  	version uint64, txn *memdb.Txn) (*structs.Job, error) {
  1228  	// COMPAT 0.7: Upgrade old objects that do not have namespaces
  1229  	if namespace == "" {
  1230  		namespace = structs.DefaultNamespace
  1231  	}
  1232  
  1233  	watchCh, existing, err := txn.FirstWatch("job_version", "id", namespace, id, version)
  1234  	if err != nil {
  1235  		return nil, err
  1236  	}
  1237  
  1238  	if ws != nil {
  1239  		ws.Add(watchCh)
  1240  	}
  1241  
  1242  	if existing != nil {
  1243  		job := existing.(*structs.Job)
  1244  		return job, nil
  1245  	}
  1246  
  1247  	return nil, nil
  1248  }
  1249  
  1250  func (s *StateStore) JobVersions(ws memdb.WatchSet) (memdb.ResultIterator, error) {
  1251  	txn := s.db.Txn(false)
  1252  
  1253  	// Walk the entire deployments table
  1254  	iter, err := txn.Get("job_version", "id")
  1255  	if err != nil {
  1256  		return nil, err
  1257  	}
  1258  
  1259  	ws.Add(iter.WatchCh())
  1260  	return iter, nil
  1261  }
  1262  
  1263  // Jobs returns an iterator over all the jobs
  1264  func (s *StateStore) Jobs(ws memdb.WatchSet) (memdb.ResultIterator, error) {
  1265  	txn := s.db.Txn(false)
  1266  
  1267  	// Walk the entire jobs table
  1268  	iter, err := txn.Get("jobs", "id")
  1269  	if err != nil {
  1270  		return nil, err
  1271  	}
  1272  
  1273  	ws.Add(iter.WatchCh())
  1274  
  1275  	return iter, nil
  1276  }
  1277  
  1278  // JobsByNamespace returns an iterator over all the jobs for the given namespace
  1279  func (s *StateStore) JobsByNamespace(ws memdb.WatchSet, namespace string) (memdb.ResultIterator, error) {
  1280  	txn := s.db.Txn(false)
  1281  	return s.jobsByNamespaceImpl(ws, namespace, txn)
  1282  }
  1283  
  1284  // jobsByNamespaceImpl returns an iterator over all the jobs for the given namespace
  1285  func (s *StateStore) jobsByNamespaceImpl(ws memdb.WatchSet, namespace string, txn *memdb.Txn) (memdb.ResultIterator, error) {
  1286  	// Walk the entire jobs table
  1287  	iter, err := txn.Get("jobs", "id_prefix", namespace, "")
  1288  	if err != nil {
  1289  		return nil, err
  1290  	}
  1291  
  1292  	ws.Add(iter.WatchCh())
  1293  
  1294  	return iter, nil
  1295  }
  1296  
  1297  // JobsByPeriodic returns an iterator over all the periodic or non-periodic jobs.
  1298  func (s *StateStore) JobsByPeriodic(ws memdb.WatchSet, periodic bool) (memdb.ResultIterator, error) {
  1299  	txn := s.db.Txn(false)
  1300  
  1301  	iter, err := txn.Get("jobs", "periodic", periodic)
  1302  	if err != nil {
  1303  		return nil, err
  1304  	}
  1305  
  1306  	ws.Add(iter.WatchCh())
  1307  
  1308  	return iter, nil
  1309  }
  1310  
  1311  // JobsByScheduler returns an iterator over all the jobs with the specific
  1312  // scheduler type.
  1313  func (s *StateStore) JobsByScheduler(ws memdb.WatchSet, schedulerType string) (memdb.ResultIterator, error) {
  1314  	txn := s.db.Txn(false)
  1315  
  1316  	// Return an iterator for jobs with the specific type.
  1317  	iter, err := txn.Get("jobs", "type", schedulerType)
  1318  	if err != nil {
  1319  		return nil, err
  1320  	}
  1321  
  1322  	ws.Add(iter.WatchCh())
  1323  
  1324  	return iter, nil
  1325  }
  1326  
  1327  // JobsByGC returns an iterator over all jobs eligible or uneligible for garbage
  1328  // collection.
  1329  func (s *StateStore) JobsByGC(ws memdb.WatchSet, gc bool) (memdb.ResultIterator, error) {
  1330  	txn := s.db.Txn(false)
  1331  
  1332  	iter, err := txn.Get("jobs", "gc", gc)
  1333  	if err != nil {
  1334  		return nil, err
  1335  	}
  1336  
  1337  	ws.Add(iter.WatchCh())
  1338  
  1339  	return iter, nil
  1340  }
  1341  
  1342  // JobSummary returns a job summary object which matches a specific id.
  1343  func (s *StateStore) JobSummaryByID(ws memdb.WatchSet, namespace, jobID string) (*structs.JobSummary, error) {
  1344  	txn := s.db.Txn(false)
  1345  
  1346  	// COMPAT 0.7: Upgrade old objects that do not have namespaces
  1347  	if namespace == "" {
  1348  		namespace = structs.DefaultNamespace
  1349  	}
  1350  
  1351  	watchCh, existing, err := txn.FirstWatch("job_summary", "id", namespace, jobID)
  1352  	if err != nil {
  1353  		return nil, err
  1354  	}
  1355  
  1356  	ws.Add(watchCh)
  1357  
  1358  	if existing != nil {
  1359  		summary := existing.(*structs.JobSummary)
  1360  		return summary, nil
  1361  	}
  1362  
  1363  	return nil, nil
  1364  }
  1365  
  1366  // JobSummaries walks the entire job summary table and returns all the job
  1367  // summary objects
  1368  func (s *StateStore) JobSummaries(ws memdb.WatchSet) (memdb.ResultIterator, error) {
  1369  	txn := s.db.Txn(false)
  1370  
  1371  	iter, err := txn.Get("job_summary", "id")
  1372  	if err != nil {
  1373  		return nil, err
  1374  	}
  1375  
  1376  	ws.Add(iter.WatchCh())
  1377  
  1378  	return iter, nil
  1379  }
  1380  
  1381  // JobSummaryByPrefix is used to look up Job Summary by id prefix
  1382  func (s *StateStore) JobSummaryByPrefix(ws memdb.WatchSet, namespace, id string) (memdb.ResultIterator, error) {
  1383  	txn := s.db.Txn(false)
  1384  
  1385  	// COMPAT 0.7: Upgrade old objects that do not have namespaces
  1386  	if namespace == "" {
  1387  		namespace = structs.DefaultNamespace
  1388  	}
  1389  
  1390  	iter, err := txn.Get("job_summary", "id_prefix", namespace, id)
  1391  	if err != nil {
  1392  		return nil, fmt.Errorf("eval lookup failed: %v", err)
  1393  	}
  1394  
  1395  	ws.Add(iter.WatchCh())
  1396  
  1397  	return iter, nil
  1398  }
  1399  
  1400  // UpsertPeriodicLaunch is used to register a launch or update it.
  1401  func (s *StateStore) UpsertPeriodicLaunch(index uint64, launch *structs.PeriodicLaunch) error {
  1402  	txn := s.db.Txn(true)
  1403  	defer txn.Abort()
  1404  
  1405  	// COMPAT 0.7: Upgrade old objects that do not have namespaces
  1406  	if launch.Namespace == "" {
  1407  		launch.Namespace = structs.DefaultNamespace
  1408  	}
  1409  
  1410  	// Check if the job already exists
  1411  	existing, err := txn.First("periodic_launch", "id", launch.Namespace, launch.ID)
  1412  	if err != nil {
  1413  		return fmt.Errorf("periodic launch lookup failed: %v", err)
  1414  	}
  1415  
  1416  	// Setup the indexes correctly
  1417  	if existing != nil {
  1418  		launch.CreateIndex = existing.(*structs.PeriodicLaunch).CreateIndex
  1419  		launch.ModifyIndex = index
  1420  	} else {
  1421  		launch.CreateIndex = index
  1422  		launch.ModifyIndex = index
  1423  	}
  1424  
  1425  	// Insert the job
  1426  	if err := txn.Insert("periodic_launch", launch); err != nil {
  1427  		return fmt.Errorf("launch insert failed: %v", err)
  1428  	}
  1429  	if err := txn.Insert("index", &IndexEntry{"periodic_launch", index}); err != nil {
  1430  		return fmt.Errorf("index update failed: %v", err)
  1431  	}
  1432  
  1433  	txn.Commit()
  1434  	return nil
  1435  }
  1436  
  1437  // DeletePeriodicLaunch is used to delete the periodic launch
  1438  func (s *StateStore) DeletePeriodicLaunch(index uint64, namespace, jobID string) error {
  1439  	txn := s.db.Txn(true)
  1440  	defer txn.Abort()
  1441  
  1442  	// COMPAT 0.7: Upgrade old objects that do not have namespaces
  1443  	if namespace == "" {
  1444  		namespace = structs.DefaultNamespace
  1445  	}
  1446  
  1447  	// Lookup the launch
  1448  	existing, err := txn.First("periodic_launch", "id", namespace, jobID)
  1449  	if err != nil {
  1450  		return fmt.Errorf("launch lookup failed: %v", err)
  1451  	}
  1452  	if existing == nil {
  1453  		return fmt.Errorf("launch not found")
  1454  	}
  1455  
  1456  	// Delete the launch
  1457  	if err := txn.Delete("periodic_launch", existing); err != nil {
  1458  		return fmt.Errorf("launch delete failed: %v", err)
  1459  	}
  1460  	if err := txn.Insert("index", &IndexEntry{"periodic_launch", index}); err != nil {
  1461  		return fmt.Errorf("index update failed: %v", err)
  1462  	}
  1463  
  1464  	txn.Commit()
  1465  	return nil
  1466  }
  1467  
  1468  // PeriodicLaunchByID is used to lookup a periodic launch by the periodic job
  1469  // ID.
  1470  func (s *StateStore) PeriodicLaunchByID(ws memdb.WatchSet, namespace, id string) (*structs.PeriodicLaunch, error) {
  1471  	txn := s.db.Txn(false)
  1472  
  1473  	// COMPAT 0.7: Upgrade old objects that do not have namespaces
  1474  	if namespace == "" {
  1475  		namespace = structs.DefaultNamespace
  1476  	}
  1477  
  1478  	watchCh, existing, err := txn.FirstWatch("periodic_launch", "id", namespace, id)
  1479  	if err != nil {
  1480  		return nil, fmt.Errorf("periodic launch lookup failed: %v", err)
  1481  	}
  1482  
  1483  	ws.Add(watchCh)
  1484  
  1485  	if existing != nil {
  1486  		return existing.(*structs.PeriodicLaunch), nil
  1487  	}
  1488  	return nil, nil
  1489  }
  1490  
  1491  // PeriodicLaunches returns an iterator over all the periodic launches
  1492  func (s *StateStore) PeriodicLaunches(ws memdb.WatchSet) (memdb.ResultIterator, error) {
  1493  	txn := s.db.Txn(false)
  1494  
  1495  	// Walk the entire table
  1496  	iter, err := txn.Get("periodic_launch", "id")
  1497  	if err != nil {
  1498  		return nil, err
  1499  	}
  1500  
  1501  	ws.Add(iter.WatchCh())
  1502  
  1503  	return iter, nil
  1504  }
  1505  
  1506  // UpsertEvals is used to upsert a set of evaluations
  1507  func (s *StateStore) UpsertEvals(index uint64, evals []*structs.Evaluation) error {
  1508  	txn := s.db.Txn(true)
  1509  	defer txn.Abort()
  1510  
  1511  	// Do a nested upsert
  1512  	jobs := make(map[structs.NamespacedID]string, len(evals))
  1513  	for _, eval := range evals {
  1514  		if err := s.nestedUpsertEval(txn, index, eval); err != nil {
  1515  			return err
  1516  		}
  1517  
  1518  		tuple := structs.NamespacedID{
  1519  			ID:        eval.JobID,
  1520  			Namespace: eval.Namespace,
  1521  		}
  1522  		jobs[tuple] = ""
  1523  	}
  1524  
  1525  	// Set the job's status
  1526  	if err := s.setJobStatuses(index, txn, jobs, false); err != nil {
  1527  		return fmt.Errorf("setting job status failed: %v", err)
  1528  	}
  1529  
  1530  	txn.Commit()
  1531  	return nil
  1532  }
  1533  
  1534  // nestedUpsertEvaluation is used to nest an evaluation upsert within a transaction
  1535  func (s *StateStore) nestedUpsertEval(txn *memdb.Txn, index uint64, eval *structs.Evaluation) error {
  1536  	// Lookup the evaluation
  1537  	existing, err := txn.First("evals", "id", eval.ID)
  1538  	if err != nil {
  1539  		return fmt.Errorf("eval lookup failed: %v", err)
  1540  	}
  1541  
  1542  	// COMPAT 0.7: Upgrade old objects that do not have namespaces
  1543  	if eval.Namespace == "" {
  1544  		eval.Namespace = structs.DefaultNamespace
  1545  	}
  1546  
  1547  	// Update the indexes
  1548  	if existing != nil {
  1549  		eval.CreateIndex = existing.(*structs.Evaluation).CreateIndex
  1550  		eval.ModifyIndex = index
  1551  	} else {
  1552  		eval.CreateIndex = index
  1553  		eval.ModifyIndex = index
  1554  	}
  1555  
  1556  	// Update the job summary
  1557  	summaryRaw, err := txn.First("job_summary", "id", eval.Namespace, eval.JobID)
  1558  	if err != nil {
  1559  		return fmt.Errorf("job summary lookup failed: %v", err)
  1560  	}
  1561  	if summaryRaw != nil {
  1562  		js := summaryRaw.(*structs.JobSummary).Copy()
  1563  		hasSummaryChanged := false
  1564  		for tg, num := range eval.QueuedAllocations {
  1565  			if summary, ok := js.Summary[tg]; ok {
  1566  				if summary.Queued != num {
  1567  					summary.Queued = num
  1568  					js.Summary[tg] = summary
  1569  					hasSummaryChanged = true
  1570  				}
  1571  			} else {
  1572  				s.logger.Printf("[ERR] state_store: unable to update queued for job %q and task group %q", eval.JobID, tg)
  1573  			}
  1574  		}
  1575  
  1576  		// Insert the job summary
  1577  		if hasSummaryChanged {
  1578  			// COMPAT 0.7: Upgrade old objects that do not have namespaces
  1579  			if js.Namespace == "" {
  1580  				js.Namespace = structs.DefaultNamespace
  1581  			}
  1582  
  1583  			js.ModifyIndex = index
  1584  			if err := txn.Insert("job_summary", js); err != nil {
  1585  				return fmt.Errorf("job summary insert failed: %v", err)
  1586  			}
  1587  			if err := txn.Insert("index", &IndexEntry{"job_summary", index}); err != nil {
  1588  				return fmt.Errorf("index update failed: %v", err)
  1589  			}
  1590  		}
  1591  	}
  1592  
  1593  	// Check if the job has any blocked evaluations and cancel them
  1594  	if eval.Status == structs.EvalStatusComplete && len(eval.FailedTGAllocs) == 0 {
  1595  		// Get the blocked evaluation for a job if it exists
  1596  		iter, err := txn.Get("evals", "job", eval.Namespace, eval.JobID, structs.EvalStatusBlocked)
  1597  		if err != nil {
  1598  			return fmt.Errorf("failed to get blocked evals for job %q in namespace %q: %v", eval.JobID, eval.Namespace, err)
  1599  		}
  1600  
  1601  		var blocked []*structs.Evaluation
  1602  		for {
  1603  			raw := iter.Next()
  1604  			if raw == nil {
  1605  				break
  1606  			}
  1607  			blocked = append(blocked, raw.(*structs.Evaluation))
  1608  		}
  1609  
  1610  		// Go through and update the evals
  1611  		for _, eval := range blocked {
  1612  			newEval := eval.Copy()
  1613  			newEval.Status = structs.EvalStatusCancelled
  1614  			newEval.StatusDescription = fmt.Sprintf("evaluation %q successful", newEval.ID)
  1615  			newEval.ModifyIndex = index
  1616  
  1617  			// COMPAT 0.7: Upgrade old objects that do not have namespaces
  1618  			if newEval.Namespace == "" {
  1619  				newEval.Namespace = structs.DefaultNamespace
  1620  			}
  1621  
  1622  			if err := txn.Insert("evals", newEval); err != nil {
  1623  				return fmt.Errorf("eval insert failed: %v", err)
  1624  			}
  1625  		}
  1626  	}
  1627  
  1628  	// Insert the eval
  1629  	if err := txn.Insert("evals", eval); err != nil {
  1630  		return fmt.Errorf("eval insert failed: %v", err)
  1631  	}
  1632  	if err := txn.Insert("index", &IndexEntry{"evals", index}); err != nil {
  1633  		return fmt.Errorf("index update failed: %v", err)
  1634  	}
  1635  	return nil
  1636  }
  1637  
  1638  // updateEvalModifyIndex is used to update the modify index of an evaluation that has been
  1639  // through a scheduler pass. This is done as part of plan apply. It ensures that when a subsequent
  1640  // scheduler workers process a re-queued evaluation it sees any partial updates from the plan apply.
  1641  func (s *StateStore) updateEvalModifyIndex(txn *memdb.Txn, index uint64, evalID string) error {
  1642  	// Lookup the evaluation
  1643  	existing, err := txn.First("evals", "id", evalID)
  1644  	if err != nil {
  1645  		return fmt.Errorf("eval lookup failed: %v", err)
  1646  	}
  1647  	if existing == nil {
  1648  		err := fmt.Errorf("unable to find eval id %q", evalID)
  1649  		s.logger.Printf("[ERR] state_store: %v", err)
  1650  		return err
  1651  	}
  1652  	eval := existing.(*structs.Evaluation).Copy()
  1653  	// Update the indexes
  1654  	eval.ModifyIndex = index
  1655  
  1656  	// Insert the eval
  1657  	if err := txn.Insert("evals", eval); err != nil {
  1658  		return fmt.Errorf("eval insert failed: %v", err)
  1659  	}
  1660  	if err := txn.Insert("index", &IndexEntry{"evals", index}); err != nil {
  1661  		return fmt.Errorf("index update failed: %v", err)
  1662  	}
  1663  	return nil
  1664  }
  1665  
  1666  // DeleteEval is used to delete an evaluation
  1667  func (s *StateStore) DeleteEval(index uint64, evals []string, allocs []string) error {
  1668  	txn := s.db.Txn(true)
  1669  	defer txn.Abort()
  1670  
  1671  	jobs := make(map[structs.NamespacedID]string, len(evals))
  1672  	for _, eval := range evals {
  1673  		existing, err := txn.First("evals", "id", eval)
  1674  		if err != nil {
  1675  			return fmt.Errorf("eval lookup failed: %v", err)
  1676  		}
  1677  		if existing == nil {
  1678  			continue
  1679  		}
  1680  		if err := txn.Delete("evals", existing); err != nil {
  1681  			return fmt.Errorf("eval delete failed: %v", err)
  1682  		}
  1683  		eval := existing.(*structs.Evaluation)
  1684  
  1685  		tuple := structs.NamespacedID{
  1686  			ID:        eval.JobID,
  1687  			Namespace: eval.Namespace,
  1688  		}
  1689  		jobs[tuple] = ""
  1690  	}
  1691  
  1692  	for _, alloc := range allocs {
  1693  		raw, err := txn.First("allocs", "id", alloc)
  1694  		if err != nil {
  1695  			return fmt.Errorf("alloc lookup failed: %v", err)
  1696  		}
  1697  		if raw == nil {
  1698  			continue
  1699  		}
  1700  		if err := txn.Delete("allocs", raw); err != nil {
  1701  			return fmt.Errorf("alloc delete failed: %v", err)
  1702  		}
  1703  	}
  1704  
  1705  	// Update the indexes
  1706  	if err := txn.Insert("index", &IndexEntry{"evals", index}); err != nil {
  1707  		return fmt.Errorf("index update failed: %v", err)
  1708  	}
  1709  	if err := txn.Insert("index", &IndexEntry{"allocs", index}); err != nil {
  1710  		return fmt.Errorf("index update failed: %v", err)
  1711  	}
  1712  
  1713  	// Set the job's status
  1714  	if err := s.setJobStatuses(index, txn, jobs, true); err != nil {
  1715  		return fmt.Errorf("setting job status failed: %v", err)
  1716  	}
  1717  
  1718  	txn.Commit()
  1719  	return nil
  1720  }
  1721  
  1722  // EvalByID is used to lookup an eval by its ID
  1723  func (s *StateStore) EvalByID(ws memdb.WatchSet, id string) (*structs.Evaluation, error) {
  1724  	txn := s.db.Txn(false)
  1725  
  1726  	watchCh, existing, err := txn.FirstWatch("evals", "id", id)
  1727  	if err != nil {
  1728  		return nil, fmt.Errorf("eval lookup failed: %v", err)
  1729  	}
  1730  
  1731  	ws.Add(watchCh)
  1732  
  1733  	if existing != nil {
  1734  		return existing.(*structs.Evaluation), nil
  1735  	}
  1736  	return nil, nil
  1737  }
  1738  
  1739  // EvalsByIDPrefix is used to lookup evaluations by prefix in a particular
  1740  // namespace
  1741  func (s *StateStore) EvalsByIDPrefix(ws memdb.WatchSet, namespace, id string) (memdb.ResultIterator, error) {
  1742  	txn := s.db.Txn(false)
  1743  
  1744  	// Get an iterator over all evals by the id prefix
  1745  	iter, err := txn.Get("evals", "id_prefix", id)
  1746  	if err != nil {
  1747  		return nil, fmt.Errorf("eval lookup failed: %v", err)
  1748  	}
  1749  
  1750  	ws.Add(iter.WatchCh())
  1751  
  1752  	// COMPAT 0.7: Upgrade old objects that do not have namespaces
  1753  	if namespace == "" {
  1754  		namespace = structs.DefaultNamespace
  1755  	}
  1756  
  1757  	// Wrap the iterator in a filter
  1758  	wrap := memdb.NewFilterIterator(iter, evalNamespaceFilter(namespace))
  1759  	return wrap, nil
  1760  }
  1761  
  1762  // evalNamespaceFilter returns a filter function that filters all evaluations
  1763  // not in the given namespace.
  1764  func evalNamespaceFilter(namespace string) func(interface{}) bool {
  1765  	return func(raw interface{}) bool {
  1766  		eval, ok := raw.(*structs.Evaluation)
  1767  		if !ok {
  1768  			return true
  1769  		}
  1770  
  1771  		return eval.Namespace != namespace
  1772  	}
  1773  }
  1774  
  1775  // EvalsByJob returns all the evaluations by job id
  1776  func (s *StateStore) EvalsByJob(ws memdb.WatchSet, namespace, jobID string) ([]*structs.Evaluation, error) {
  1777  	txn := s.db.Txn(false)
  1778  
  1779  	// COMPAT 0.7: Upgrade old objects that do not have namespaces
  1780  	if namespace == "" {
  1781  		namespace = structs.DefaultNamespace
  1782  	}
  1783  
  1784  	// Get an iterator over the node allocations
  1785  	iter, err := txn.Get("evals", "job_prefix", namespace, jobID)
  1786  	if err != nil {
  1787  		return nil, err
  1788  	}
  1789  
  1790  	ws.Add(iter.WatchCh())
  1791  
  1792  	var out []*structs.Evaluation
  1793  	for {
  1794  		raw := iter.Next()
  1795  		if raw == nil {
  1796  			break
  1797  		}
  1798  
  1799  		e := raw.(*structs.Evaluation)
  1800  
  1801  		// Filter non-exact matches
  1802  		if e.JobID != jobID {
  1803  			continue
  1804  		}
  1805  
  1806  		out = append(out, e)
  1807  	}
  1808  	return out, nil
  1809  }
  1810  
  1811  // Evals returns an iterator over all the evaluations
  1812  func (s *StateStore) Evals(ws memdb.WatchSet) (memdb.ResultIterator, error) {
  1813  	txn := s.db.Txn(false)
  1814  
  1815  	// Walk the entire table
  1816  	iter, err := txn.Get("evals", "id")
  1817  	if err != nil {
  1818  		return nil, err
  1819  	}
  1820  
  1821  	ws.Add(iter.WatchCh())
  1822  
  1823  	return iter, nil
  1824  }
  1825  
  1826  // EvalsByNamespace returns an iterator over all the evaluations in the given
  1827  // namespace
  1828  func (s *StateStore) EvalsByNamespace(ws memdb.WatchSet, namespace string) (memdb.ResultIterator, error) {
  1829  	txn := s.db.Txn(false)
  1830  
  1831  	// Walk the entire table
  1832  	iter, err := txn.Get("evals", "namespace", namespace)
  1833  	if err != nil {
  1834  		return nil, err
  1835  	}
  1836  
  1837  	ws.Add(iter.WatchCh())
  1838  
  1839  	return iter, nil
  1840  }
  1841  
  1842  // UpdateAllocsFromClient is used to update an allocation based on input
  1843  // from a client. While the schedulers are the authority on the allocation for
  1844  // most things, some updates are authoritative from the client. Specifically,
  1845  // the desired state comes from the schedulers, while the actual state comes
  1846  // from clients.
  1847  func (s *StateStore) UpdateAllocsFromClient(index uint64, allocs []*structs.Allocation) error {
  1848  	txn := s.db.Txn(true)
  1849  	defer txn.Abort()
  1850  
  1851  	// Handle each of the updated allocations
  1852  	for _, alloc := range allocs {
  1853  		if err := s.nestedUpdateAllocFromClient(txn, index, alloc); err != nil {
  1854  			return err
  1855  		}
  1856  	}
  1857  
  1858  	// Update the indexes
  1859  	if err := txn.Insert("index", &IndexEntry{"allocs", index}); err != nil {
  1860  		return fmt.Errorf("index update failed: %v", err)
  1861  	}
  1862  
  1863  	txn.Commit()
  1864  	return nil
  1865  }
  1866  
  1867  // nestedUpdateAllocFromClient is used to nest an update of an allocation with client status
  1868  func (s *StateStore) nestedUpdateAllocFromClient(txn *memdb.Txn, index uint64, alloc *structs.Allocation) error {
  1869  	// Look for existing alloc
  1870  	existing, err := txn.First("allocs", "id", alloc.ID)
  1871  	if err != nil {
  1872  		return fmt.Errorf("alloc lookup failed: %v", err)
  1873  	}
  1874  
  1875  	// Nothing to do if this does not exist
  1876  	if existing == nil {
  1877  		return nil
  1878  	}
  1879  	exist := existing.(*structs.Allocation)
  1880  
  1881  	// Copy everything from the existing allocation
  1882  	copyAlloc := exist.Copy()
  1883  
  1884  	// COMPAT 0.7: Upgrade old objects that do not have namespaces
  1885  	if copyAlloc.Namespace == "" {
  1886  		copyAlloc.Namespace = structs.DefaultNamespace
  1887  	}
  1888  
  1889  	// Pull in anything the client is the authority on
  1890  	copyAlloc.ClientStatus = alloc.ClientStatus
  1891  	copyAlloc.ClientDescription = alloc.ClientDescription
  1892  	copyAlloc.TaskStates = alloc.TaskStates
  1893  	copyAlloc.DeploymentStatus = alloc.DeploymentStatus
  1894  
  1895  	// Update the modify index
  1896  	copyAlloc.ModifyIndex = index
  1897  
  1898  	// Update the modify time
  1899  	copyAlloc.ModifyTime = alloc.ModifyTime
  1900  
  1901  	if err := s.updateDeploymentWithAlloc(index, copyAlloc, exist, txn); err != nil {
  1902  		return fmt.Errorf("error updating deployment: %v", err)
  1903  	}
  1904  
  1905  	if err := s.updateSummaryWithAlloc(index, copyAlloc, exist, txn); err != nil {
  1906  		return fmt.Errorf("error updating job summary: %v", err)
  1907  	}
  1908  
  1909  	if err := s.updateEntWithAlloc(index, copyAlloc, exist, txn); err != nil {
  1910  		return err
  1911  	}
  1912  
  1913  	// Update the allocation
  1914  	if err := txn.Insert("allocs", copyAlloc); err != nil {
  1915  		return fmt.Errorf("alloc insert failed: %v", err)
  1916  	}
  1917  
  1918  	// Set the job's status
  1919  	forceStatus := ""
  1920  	if !copyAlloc.TerminalStatus() {
  1921  		forceStatus = structs.JobStatusRunning
  1922  	}
  1923  
  1924  	tuple := structs.NamespacedID{
  1925  		ID:        exist.JobID,
  1926  		Namespace: exist.Namespace,
  1927  	}
  1928  	jobs := map[structs.NamespacedID]string{tuple: forceStatus}
  1929  
  1930  	if err := s.setJobStatuses(index, txn, jobs, false); err != nil {
  1931  		return fmt.Errorf("setting job status failed: %v", err)
  1932  	}
  1933  	return nil
  1934  }
  1935  
  1936  // UpsertAllocs is used to evict a set of allocations and allocate new ones at
  1937  // the same time.
  1938  func (s *StateStore) UpsertAllocs(index uint64, allocs []*structs.Allocation) error {
  1939  	txn := s.db.Txn(true)
  1940  	defer txn.Abort()
  1941  	if err := s.upsertAllocsImpl(index, allocs, txn); err != nil {
  1942  		return err
  1943  	}
  1944  	txn.Commit()
  1945  	return nil
  1946  }
  1947  
  1948  // upsertAllocs is the actual implementation of UpsertAllocs so that it may be
  1949  // used with an existing transaction.
  1950  func (s *StateStore) upsertAllocsImpl(index uint64, allocs []*structs.Allocation, txn *memdb.Txn) error {
  1951  	// Handle the allocations
  1952  	jobs := make(map[structs.NamespacedID]string, 1)
  1953  	for _, alloc := range allocs {
  1954  		existing, err := txn.First("allocs", "id", alloc.ID)
  1955  		if err != nil {
  1956  			return fmt.Errorf("alloc lookup failed: %v", err)
  1957  		}
  1958  		exist, _ := existing.(*structs.Allocation)
  1959  
  1960  		if exist == nil {
  1961  			alloc.CreateIndex = index
  1962  			alloc.ModifyIndex = index
  1963  			alloc.AllocModifyIndex = index
  1964  
  1965  			// Issue https://github.com/hashicorp/nomad/issues/2583 uncovered
  1966  			// the a race between a forced garbage collection and the scheduler
  1967  			// marking an allocation as terminal. The issue is that the
  1968  			// allocation from the scheduler has its job normalized and the FSM
  1969  			// will only denormalize if the allocation is not terminal.  However
  1970  			// if the allocation is garbage collected, that will result in a
  1971  			// allocation being upserted for the first time without a job
  1972  			// attached. By returning an error here, it will cause the FSM to
  1973  			// error, causing the plan_apply to error and thus causing the
  1974  			// evaluation to be failed. This will force an index refresh that
  1975  			// should solve this issue.
  1976  			if alloc.Job == nil {
  1977  				return fmt.Errorf("attempting to upsert allocation %q without a job", alloc.ID)
  1978  			}
  1979  		} else {
  1980  			alloc.CreateIndex = exist.CreateIndex
  1981  			alloc.ModifyIndex = index
  1982  			alloc.AllocModifyIndex = index
  1983  
  1984  			// Keep the clients task states
  1985  			alloc.TaskStates = exist.TaskStates
  1986  
  1987  			// If the scheduler is marking this allocation as lost we do not
  1988  			// want to reuse the status of the existing allocation.
  1989  			if alloc.ClientStatus != structs.AllocClientStatusLost {
  1990  				alloc.ClientStatus = exist.ClientStatus
  1991  				alloc.ClientDescription = exist.ClientDescription
  1992  			}
  1993  
  1994  			// The job has been denormalized so re-attach the original job
  1995  			if alloc.Job == nil {
  1996  				alloc.Job = exist.Job
  1997  			}
  1998  		}
  1999  
  2000  		// COMPAT 0.7: Upgrade old objects that do not have namespaces
  2001  		if alloc.Namespace == "" {
  2002  			alloc.Namespace = structs.DefaultNamespace
  2003  		}
  2004  
  2005  		// OPTIMIZATION:
  2006  		// These should be given a map of new to old allocation and the updates
  2007  		// should be one on all changes. The current implementation causes O(n)
  2008  		// lookups/copies/insertions rather than O(1)
  2009  		if err := s.updateDeploymentWithAlloc(index, alloc, exist, txn); err != nil {
  2010  			return fmt.Errorf("error updating deployment: %v", err)
  2011  		}
  2012  
  2013  		if err := s.updateSummaryWithAlloc(index, alloc, exist, txn); err != nil {
  2014  			return fmt.Errorf("error updating job summary: %v", err)
  2015  		}
  2016  
  2017  		if err := s.updateEntWithAlloc(index, alloc, exist, txn); err != nil {
  2018  			return err
  2019  		}
  2020  
  2021  		// Create the EphemeralDisk if it's nil by adding up DiskMB from task resources.
  2022  		// COMPAT 0.4.1 -> 0.5
  2023  		if alloc.Job != nil {
  2024  			s.addEphemeralDiskToTaskGroups(alloc.Job)
  2025  		}
  2026  
  2027  		if err := txn.Insert("allocs", alloc); err != nil {
  2028  			return fmt.Errorf("alloc insert failed: %v", err)
  2029  		}
  2030  
  2031  		if alloc.PreviousAllocation != "" {
  2032  			prevAlloc, err := txn.First("allocs", "id", alloc.PreviousAllocation)
  2033  			if err != nil {
  2034  				return fmt.Errorf("alloc lookup failed: %v", err)
  2035  			}
  2036  			existingPrevAlloc, _ := prevAlloc.(*structs.Allocation)
  2037  			if existingPrevAlloc != nil {
  2038  				prevAllocCopy := existingPrevAlloc.Copy()
  2039  				prevAllocCopy.NextAllocation = alloc.ID
  2040  				if err := txn.Insert("allocs", prevAllocCopy); err != nil {
  2041  					return fmt.Errorf("alloc insert failed: %v", err)
  2042  				}
  2043  			}
  2044  		}
  2045  
  2046  		// If the allocation is running, force the job to running status.
  2047  		forceStatus := ""
  2048  		if !alloc.TerminalStatus() {
  2049  			forceStatus = structs.JobStatusRunning
  2050  		}
  2051  
  2052  		tuple := structs.NamespacedID{
  2053  			ID:        alloc.JobID,
  2054  			Namespace: alloc.Namespace,
  2055  		}
  2056  		jobs[tuple] = forceStatus
  2057  	}
  2058  
  2059  	// Update the indexes
  2060  	if err := txn.Insert("index", &IndexEntry{"allocs", index}); err != nil {
  2061  		return fmt.Errorf("index update failed: %v", err)
  2062  	}
  2063  
  2064  	// Set the job's status
  2065  	if err := s.setJobStatuses(index, txn, jobs, false); err != nil {
  2066  		return fmt.Errorf("setting job status failed: %v", err)
  2067  	}
  2068  
  2069  	return nil
  2070  }
  2071  
  2072  // UpdateAllocsDesiredTransitions is used to update a set of allocations
  2073  // desired transitions.
  2074  func (s *StateStore) UpdateAllocsDesiredTransitions(index uint64, allocs map[string]*structs.DesiredTransition,
  2075  	evals []*structs.Evaluation) error {
  2076  
  2077  	txn := s.db.Txn(true)
  2078  	defer txn.Abort()
  2079  
  2080  	// Handle each of the updated allocations
  2081  	for id, transition := range allocs {
  2082  		if err := s.nestedUpdateAllocDesiredTransition(txn, index, id, transition); err != nil {
  2083  			return err
  2084  		}
  2085  	}
  2086  
  2087  	// Update the indexes
  2088  	if err := txn.Insert("index", &IndexEntry{"allocs", index}); err != nil {
  2089  		return fmt.Errorf("index update failed: %v", err)
  2090  	}
  2091  
  2092  	txn.Commit()
  2093  	return nil
  2094  }
  2095  
  2096  // nestedUpdateAllocDesiredTransition is used to nest an update of an
  2097  // allocations desired transition
  2098  func (s *StateStore) nestedUpdateAllocDesiredTransition(
  2099  	txn *memdb.Txn, index uint64, allocID string,
  2100  	transition *structs.DesiredTransition) error {
  2101  
  2102  	// Look for existing alloc
  2103  	existing, err := txn.First("allocs", "id", allocID)
  2104  	if err != nil {
  2105  		return fmt.Errorf("alloc lookup failed: %v", err)
  2106  	}
  2107  
  2108  	// Nothing to do if this does not exist
  2109  	if existing == nil {
  2110  		return nil
  2111  	}
  2112  	exist := existing.(*structs.Allocation)
  2113  
  2114  	// Copy everything from the existing allocation
  2115  	copyAlloc := exist.Copy()
  2116  
  2117  	// Merge the desired transitions
  2118  	copyAlloc.DesiredTransition.Merge(transition)
  2119  
  2120  	// Update the modify index
  2121  	copyAlloc.ModifyIndex = index
  2122  
  2123  	// Update the allocation
  2124  	if err := txn.Insert("allocs", copyAlloc); err != nil {
  2125  		return fmt.Errorf("alloc insert failed: %v", err)
  2126  	}
  2127  
  2128  	return nil
  2129  }
  2130  
  2131  // AllocByID is used to lookup an allocation by its ID
  2132  func (s *StateStore) AllocByID(ws memdb.WatchSet, id string) (*structs.Allocation, error) {
  2133  	txn := s.db.Txn(false)
  2134  
  2135  	watchCh, existing, err := txn.FirstWatch("allocs", "id", id)
  2136  	if err != nil {
  2137  		return nil, fmt.Errorf("alloc lookup failed: %v", err)
  2138  	}
  2139  
  2140  	ws.Add(watchCh)
  2141  
  2142  	if existing != nil {
  2143  		return existing.(*structs.Allocation), nil
  2144  	}
  2145  	return nil, nil
  2146  }
  2147  
  2148  // AllocsByIDPrefix is used to lookup allocs by prefix
  2149  func (s *StateStore) AllocsByIDPrefix(ws memdb.WatchSet, namespace, id string) (memdb.ResultIterator, error) {
  2150  	txn := s.db.Txn(false)
  2151  
  2152  	iter, err := txn.Get("allocs", "id_prefix", id)
  2153  	if err != nil {
  2154  		return nil, fmt.Errorf("alloc lookup failed: %v", err)
  2155  	}
  2156  
  2157  	ws.Add(iter.WatchCh())
  2158  
  2159  	// Wrap the iterator in a filter
  2160  	wrap := memdb.NewFilterIterator(iter, allocNamespaceFilter(namespace))
  2161  	return wrap, nil
  2162  }
  2163  
  2164  // allocNamespaceFilter returns a filter function that filters all allocations
  2165  // not in the given namespace.
  2166  func allocNamespaceFilter(namespace string) func(interface{}) bool {
  2167  	return func(raw interface{}) bool {
  2168  		alloc, ok := raw.(*structs.Allocation)
  2169  		if !ok {
  2170  			return true
  2171  		}
  2172  
  2173  		return alloc.Namespace != namespace
  2174  	}
  2175  }
  2176  
  2177  // AllocsByNode returns all the allocations by node
  2178  func (s *StateStore) AllocsByNode(ws memdb.WatchSet, node string) ([]*structs.Allocation, error) {
  2179  	txn := s.db.Txn(false)
  2180  
  2181  	// Get an iterator over the node allocations, using only the
  2182  	// node prefix which ignores the terminal status
  2183  	iter, err := txn.Get("allocs", "node_prefix", node)
  2184  	if err != nil {
  2185  		return nil, err
  2186  	}
  2187  
  2188  	ws.Add(iter.WatchCh())
  2189  
  2190  	var out []*structs.Allocation
  2191  	for {
  2192  		raw := iter.Next()
  2193  		if raw == nil {
  2194  			break
  2195  		}
  2196  		out = append(out, raw.(*structs.Allocation))
  2197  	}
  2198  	return out, nil
  2199  }
  2200  
  2201  // AllocsByNode returns all the allocations by node and terminal status
  2202  func (s *StateStore) AllocsByNodeTerminal(ws memdb.WatchSet, node string, terminal bool) ([]*structs.Allocation, error) {
  2203  	txn := s.db.Txn(false)
  2204  
  2205  	// Get an iterator over the node allocations
  2206  	iter, err := txn.Get("allocs", "node", node, terminal)
  2207  	if err != nil {
  2208  		return nil, err
  2209  	}
  2210  
  2211  	ws.Add(iter.WatchCh())
  2212  
  2213  	var out []*structs.Allocation
  2214  	for {
  2215  		raw := iter.Next()
  2216  		if raw == nil {
  2217  			break
  2218  		}
  2219  		out = append(out, raw.(*structs.Allocation))
  2220  	}
  2221  	return out, nil
  2222  }
  2223  
  2224  // AllocsByJob returns all the allocations by job id
  2225  func (s *StateStore) AllocsByJob(ws memdb.WatchSet, namespace, jobID string, all bool) ([]*structs.Allocation, error) {
  2226  	txn := s.db.Txn(false)
  2227  
  2228  	// COMPAT 0.7: Upgrade old objects that do not have namespaces
  2229  	if namespace == "" {
  2230  		namespace = structs.DefaultNamespace
  2231  	}
  2232  
  2233  	// Get the job
  2234  	var job *structs.Job
  2235  	rawJob, err := txn.First("jobs", "id", namespace, jobID)
  2236  	if err != nil {
  2237  		return nil, err
  2238  	}
  2239  	if rawJob != nil {
  2240  		job = rawJob.(*structs.Job)
  2241  	}
  2242  
  2243  	// Get an iterator over the node allocations
  2244  	iter, err := txn.Get("allocs", "job", namespace, jobID)
  2245  	if err != nil {
  2246  		return nil, err
  2247  	}
  2248  
  2249  	ws.Add(iter.WatchCh())
  2250  
  2251  	var out []*structs.Allocation
  2252  	for {
  2253  		raw := iter.Next()
  2254  		if raw == nil {
  2255  			break
  2256  		}
  2257  
  2258  		alloc := raw.(*structs.Allocation)
  2259  		// If the allocation belongs to a job with the same ID but a different
  2260  		// create index and we are not getting all the allocations whose Jobs
  2261  		// matches the same Job ID then we skip it
  2262  		if !all && job != nil && alloc.Job.CreateIndex != job.CreateIndex {
  2263  			continue
  2264  		}
  2265  		out = append(out, raw.(*structs.Allocation))
  2266  	}
  2267  	return out, nil
  2268  }
  2269  
  2270  // AllocsByEval returns all the allocations by eval id
  2271  func (s *StateStore) AllocsByEval(ws memdb.WatchSet, evalID string) ([]*structs.Allocation, error) {
  2272  	txn := s.db.Txn(false)
  2273  
  2274  	// Get an iterator over the eval allocations
  2275  	iter, err := txn.Get("allocs", "eval", evalID)
  2276  	if err != nil {
  2277  		return nil, err
  2278  	}
  2279  
  2280  	ws.Add(iter.WatchCh())
  2281  
  2282  	var out []*structs.Allocation
  2283  	for {
  2284  		raw := iter.Next()
  2285  		if raw == nil {
  2286  			break
  2287  		}
  2288  		out = append(out, raw.(*structs.Allocation))
  2289  	}
  2290  	return out, nil
  2291  }
  2292  
  2293  // AllocsByDeployment returns all the allocations by deployment id
  2294  func (s *StateStore) AllocsByDeployment(ws memdb.WatchSet, deploymentID string) ([]*structs.Allocation, error) {
  2295  	txn := s.db.Txn(false)
  2296  
  2297  	// Get an iterator over the deployments allocations
  2298  	iter, err := txn.Get("allocs", "deployment", deploymentID)
  2299  	if err != nil {
  2300  		return nil, err
  2301  	}
  2302  
  2303  	ws.Add(iter.WatchCh())
  2304  
  2305  	var out []*structs.Allocation
  2306  	for {
  2307  		raw := iter.Next()
  2308  		if raw == nil {
  2309  			break
  2310  		}
  2311  		out = append(out, raw.(*structs.Allocation))
  2312  	}
  2313  	return out, nil
  2314  }
  2315  
  2316  // Allocs returns an iterator over all the evaluations
  2317  func (s *StateStore) Allocs(ws memdb.WatchSet) (memdb.ResultIterator, error) {
  2318  	txn := s.db.Txn(false)
  2319  
  2320  	// Walk the entire table
  2321  	iter, err := txn.Get("allocs", "id")
  2322  	if err != nil {
  2323  		return nil, err
  2324  	}
  2325  
  2326  	ws.Add(iter.WatchCh())
  2327  
  2328  	return iter, nil
  2329  }
  2330  
  2331  // AllocsByNamespace returns an iterator over all the allocations in the
  2332  // namespace
  2333  func (s *StateStore) AllocsByNamespace(ws memdb.WatchSet, namespace string) (memdb.ResultIterator, error) {
  2334  	txn := s.db.Txn(false)
  2335  	return s.allocsByNamespaceImpl(ws, txn, namespace)
  2336  }
  2337  
  2338  // allocsByNamespaceImpl returns an iterator over all the allocations in the
  2339  // namespace
  2340  func (s *StateStore) allocsByNamespaceImpl(ws memdb.WatchSet, txn *memdb.Txn, namespace string) (memdb.ResultIterator, error) {
  2341  	// Walk the entire table
  2342  	iter, err := txn.Get("allocs", "namespace", namespace)
  2343  	if err != nil {
  2344  		return nil, err
  2345  	}
  2346  
  2347  	ws.Add(iter.WatchCh())
  2348  
  2349  	return iter, nil
  2350  }
  2351  
  2352  // UpsertVaultAccessors is used to register a set of Vault Accessors
  2353  func (s *StateStore) UpsertVaultAccessor(index uint64, accessors []*structs.VaultAccessor) error {
  2354  	txn := s.db.Txn(true)
  2355  	defer txn.Abort()
  2356  
  2357  	for _, accessor := range accessors {
  2358  		// Set the create index
  2359  		accessor.CreateIndex = index
  2360  
  2361  		// Insert the accessor
  2362  		if err := txn.Insert("vault_accessors", accessor); err != nil {
  2363  			return fmt.Errorf("accessor insert failed: %v", err)
  2364  		}
  2365  	}
  2366  
  2367  	if err := txn.Insert("index", &IndexEntry{"vault_accessors", index}); err != nil {
  2368  		return fmt.Errorf("index update failed: %v", err)
  2369  	}
  2370  
  2371  	txn.Commit()
  2372  	return nil
  2373  }
  2374  
  2375  // DeleteVaultAccessors is used to delete a set of Vault Accessors
  2376  func (s *StateStore) DeleteVaultAccessors(index uint64, accessors []*structs.VaultAccessor) error {
  2377  	txn := s.db.Txn(true)
  2378  	defer txn.Abort()
  2379  
  2380  	// Lookup the accessor
  2381  	for _, accessor := range accessors {
  2382  		// Delete the accessor
  2383  		if err := txn.Delete("vault_accessors", accessor); err != nil {
  2384  			return fmt.Errorf("accessor delete failed: %v", err)
  2385  		}
  2386  	}
  2387  
  2388  	if err := txn.Insert("index", &IndexEntry{"vault_accessors", index}); err != nil {
  2389  		return fmt.Errorf("index update failed: %v", err)
  2390  	}
  2391  
  2392  	txn.Commit()
  2393  	return nil
  2394  }
  2395  
  2396  // VaultAccessor returns the given Vault accessor
  2397  func (s *StateStore) VaultAccessor(ws memdb.WatchSet, accessor string) (*structs.VaultAccessor, error) {
  2398  	txn := s.db.Txn(false)
  2399  
  2400  	watchCh, existing, err := txn.FirstWatch("vault_accessors", "id", accessor)
  2401  	if err != nil {
  2402  		return nil, fmt.Errorf("accessor lookup failed: %v", err)
  2403  	}
  2404  
  2405  	ws.Add(watchCh)
  2406  
  2407  	if existing != nil {
  2408  		return existing.(*structs.VaultAccessor), nil
  2409  	}
  2410  
  2411  	return nil, nil
  2412  }
  2413  
  2414  // VaultAccessors returns an iterator of Vault accessors.
  2415  func (s *StateStore) VaultAccessors(ws memdb.WatchSet) (memdb.ResultIterator, error) {
  2416  	txn := s.db.Txn(false)
  2417  
  2418  	iter, err := txn.Get("vault_accessors", "id")
  2419  	if err != nil {
  2420  		return nil, err
  2421  	}
  2422  
  2423  	ws.Add(iter.WatchCh())
  2424  
  2425  	return iter, nil
  2426  }
  2427  
  2428  // VaultAccessorsByAlloc returns all the Vault accessors by alloc id
  2429  func (s *StateStore) VaultAccessorsByAlloc(ws memdb.WatchSet, allocID string) ([]*structs.VaultAccessor, error) {
  2430  	txn := s.db.Txn(false)
  2431  
  2432  	// Get an iterator over the accessors
  2433  	iter, err := txn.Get("vault_accessors", "alloc_id", allocID)
  2434  	if err != nil {
  2435  		return nil, err
  2436  	}
  2437  
  2438  	ws.Add(iter.WatchCh())
  2439  
  2440  	var out []*structs.VaultAccessor
  2441  	for {
  2442  		raw := iter.Next()
  2443  		if raw == nil {
  2444  			break
  2445  		}
  2446  		out = append(out, raw.(*structs.VaultAccessor))
  2447  	}
  2448  	return out, nil
  2449  }
  2450  
  2451  // VaultAccessorsByNode returns all the Vault accessors by node id
  2452  func (s *StateStore) VaultAccessorsByNode(ws memdb.WatchSet, nodeID string) ([]*structs.VaultAccessor, error) {
  2453  	txn := s.db.Txn(false)
  2454  
  2455  	// Get an iterator over the accessors
  2456  	iter, err := txn.Get("vault_accessors", "node_id", nodeID)
  2457  	if err != nil {
  2458  		return nil, err
  2459  	}
  2460  
  2461  	ws.Add(iter.WatchCh())
  2462  
  2463  	var out []*structs.VaultAccessor
  2464  	for {
  2465  		raw := iter.Next()
  2466  		if raw == nil {
  2467  			break
  2468  		}
  2469  		out = append(out, raw.(*structs.VaultAccessor))
  2470  	}
  2471  	return out, nil
  2472  }
  2473  
  2474  // UpdateDeploymentStatus is used to make deployment status updates and
  2475  // potentially make a evaluation
  2476  func (s *StateStore) UpdateDeploymentStatus(index uint64, req *structs.DeploymentStatusUpdateRequest) error {
  2477  	txn := s.db.Txn(true)
  2478  	defer txn.Abort()
  2479  
  2480  	if err := s.updateDeploymentStatusImpl(index, req.DeploymentUpdate, txn); err != nil {
  2481  		return err
  2482  	}
  2483  
  2484  	// Upsert the job if necessary
  2485  	if req.Job != nil {
  2486  		if err := s.upsertJobImpl(index, req.Job, false, txn); err != nil {
  2487  			return err
  2488  		}
  2489  	}
  2490  
  2491  	// Upsert the optional eval
  2492  	if req.Eval != nil {
  2493  		if err := s.nestedUpsertEval(txn, index, req.Eval); err != nil {
  2494  			return err
  2495  		}
  2496  	}
  2497  
  2498  	txn.Commit()
  2499  	return nil
  2500  }
  2501  
  2502  // updateDeploymentStatusImpl is used to make deployment status updates
  2503  func (s *StateStore) updateDeploymentStatusImpl(index uint64, u *structs.DeploymentStatusUpdate, txn *memdb.Txn) error {
  2504  	// Retrieve deployment
  2505  	ws := memdb.NewWatchSet()
  2506  	deployment, err := s.deploymentByIDImpl(ws, u.DeploymentID, txn)
  2507  	if err != nil {
  2508  		return err
  2509  	} else if deployment == nil {
  2510  		return fmt.Errorf("Deployment ID %q couldn't be updated as it does not exist", u.DeploymentID)
  2511  	} else if !deployment.Active() {
  2512  		return fmt.Errorf("Deployment %q has terminal status %q:", deployment.ID, deployment.Status)
  2513  	}
  2514  
  2515  	// Apply the new status
  2516  	copy := deployment.Copy()
  2517  	copy.Status = u.Status
  2518  	copy.StatusDescription = u.StatusDescription
  2519  	copy.ModifyIndex = index
  2520  
  2521  	// COMPAT 0.7: Upgrade old objects that do not have namespaces
  2522  	if copy.Namespace == "" {
  2523  		copy.Namespace = structs.DefaultNamespace
  2524  	}
  2525  
  2526  	// Insert the deployment
  2527  	if err := txn.Insert("deployment", copy); err != nil {
  2528  		return err
  2529  	}
  2530  
  2531  	// Update the index
  2532  	if err := txn.Insert("index", &IndexEntry{"deployment", index}); err != nil {
  2533  		return fmt.Errorf("index update failed: %v", err)
  2534  	}
  2535  
  2536  	// If the deployment is being marked as complete, set the job to stable.
  2537  	if copy.Status == structs.DeploymentStatusSuccessful {
  2538  		if err := s.updateJobStabilityImpl(index, copy.Namespace, copy.JobID, copy.JobVersion, true, txn); err != nil {
  2539  			return fmt.Errorf("failed to update job stability: %v", err)
  2540  		}
  2541  	}
  2542  
  2543  	return nil
  2544  }
  2545  
  2546  // UpdateJobStability updates the stability of the given job and version to the
  2547  // desired status.
  2548  func (s *StateStore) UpdateJobStability(index uint64, namespace, jobID string, jobVersion uint64, stable bool) error {
  2549  	txn := s.db.Txn(true)
  2550  	defer txn.Abort()
  2551  
  2552  	// COMPAT 0.7: Upgrade old objects that do not have namespaces
  2553  	if namespace == "" {
  2554  		namespace = structs.DefaultNamespace
  2555  	}
  2556  
  2557  	if err := s.updateJobStabilityImpl(index, namespace, jobID, jobVersion, stable, txn); err != nil {
  2558  		return err
  2559  	}
  2560  
  2561  	txn.Commit()
  2562  	return nil
  2563  }
  2564  
  2565  // updateJobStabilityImpl updates the stability of the given job and version
  2566  func (s *StateStore) updateJobStabilityImpl(index uint64, namespace, jobID string, jobVersion uint64, stable bool, txn *memdb.Txn) error {
  2567  	// COMPAT 0.7: Upgrade old objects that do not have namespaces
  2568  	if namespace == "" {
  2569  		namespace = structs.DefaultNamespace
  2570  	}
  2571  
  2572  	// Get the job that is referenced
  2573  	job, err := s.jobByIDAndVersionImpl(nil, namespace, jobID, jobVersion, txn)
  2574  	if err != nil {
  2575  		return err
  2576  	}
  2577  
  2578  	// Has already been cleared, nothing to do
  2579  	if job == nil {
  2580  		return nil
  2581  	}
  2582  
  2583  	// If the job already has the desired stability, nothing to do
  2584  	if job.Stable == stable {
  2585  		return nil
  2586  	}
  2587  
  2588  	copy := job.Copy()
  2589  	copy.Stable = stable
  2590  	return s.upsertJobImpl(index, copy, true, txn)
  2591  }
  2592  
  2593  // UpdateDeploymentPromotion is used to promote canaries in a deployment and
  2594  // potentially make a evaluation
  2595  func (s *StateStore) UpdateDeploymentPromotion(index uint64, req *structs.ApplyDeploymentPromoteRequest) error {
  2596  	txn := s.db.Txn(true)
  2597  	defer txn.Abort()
  2598  
  2599  	// Retrieve deployment and ensure it is not terminal and is active
  2600  	ws := memdb.NewWatchSet()
  2601  	deployment, err := s.deploymentByIDImpl(ws, req.DeploymentID, txn)
  2602  	if err != nil {
  2603  		return err
  2604  	} else if deployment == nil {
  2605  		return fmt.Errorf("Deployment ID %q couldn't be updated as it does not exist", req.DeploymentID)
  2606  	} else if !deployment.Active() {
  2607  		return fmt.Errorf("Deployment %q has terminal status %q:", deployment.ID, deployment.Status)
  2608  	}
  2609  
  2610  	// Retrieve effected allocations
  2611  	iter, err := txn.Get("allocs", "deployment", req.DeploymentID)
  2612  	if err != nil {
  2613  		return err
  2614  	}
  2615  
  2616  	groupIndex := make(map[string]struct{}, len(req.Groups))
  2617  	for _, g := range req.Groups {
  2618  		groupIndex[g] = struct{}{}
  2619  	}
  2620  
  2621  	canaryIndex := make(map[string]struct{}, len(deployment.TaskGroups))
  2622  	for _, state := range deployment.TaskGroups {
  2623  		for _, c := range state.PlacedCanaries {
  2624  			canaryIndex[c] = struct{}{}
  2625  		}
  2626  	}
  2627  
  2628  	haveCanaries := false
  2629  	var unhealthyErr multierror.Error
  2630  	for {
  2631  		raw := iter.Next()
  2632  		if raw == nil {
  2633  			break
  2634  		}
  2635  
  2636  		alloc := raw.(*structs.Allocation)
  2637  
  2638  		// Check that the alloc is a canary
  2639  		if _, ok := canaryIndex[alloc.ID]; !ok {
  2640  			continue
  2641  		}
  2642  
  2643  		// Check that the canary is part of a group being promoted
  2644  		if _, ok := groupIndex[alloc.TaskGroup]; !req.All && !ok {
  2645  			continue
  2646  		}
  2647  
  2648  		// Ensure the canaries are healthy
  2649  		if !alloc.DeploymentStatus.IsHealthy() {
  2650  			multierror.Append(&unhealthyErr, fmt.Errorf("Canary allocation %q for group %q is not healthy", alloc.ID, alloc.TaskGroup))
  2651  			continue
  2652  		}
  2653  
  2654  		haveCanaries = true
  2655  	}
  2656  
  2657  	if err := unhealthyErr.ErrorOrNil(); err != nil {
  2658  		return err
  2659  	}
  2660  
  2661  	if !haveCanaries {
  2662  		return fmt.Errorf("no canaries to promote")
  2663  	}
  2664  
  2665  	// Update deployment
  2666  	copy := deployment.Copy()
  2667  	copy.ModifyIndex = index
  2668  	for tg, status := range copy.TaskGroups {
  2669  		_, ok := groupIndex[tg]
  2670  		if !req.All && !ok {
  2671  			continue
  2672  		}
  2673  
  2674  		status.Promoted = true
  2675  	}
  2676  
  2677  	// If the deployment no longer needs promotion, update its status
  2678  	if !copy.RequiresPromotion() && copy.Status == structs.DeploymentStatusRunning {
  2679  		copy.StatusDescription = structs.DeploymentStatusDescriptionRunning
  2680  	}
  2681  
  2682  	// Insert the deployment
  2683  	if err := s.upsertDeploymentImpl(index, copy, txn); err != nil {
  2684  		return err
  2685  	}
  2686  
  2687  	// Upsert the optional eval
  2688  	if req.Eval != nil {
  2689  		if err := s.nestedUpsertEval(txn, index, req.Eval); err != nil {
  2690  			return err
  2691  		}
  2692  	}
  2693  
  2694  	txn.Commit()
  2695  	return nil
  2696  }
  2697  
  2698  // UpdateDeploymentAllocHealth is used to update the health of allocations as
  2699  // part of the deployment and potentially make a evaluation
  2700  func (s *StateStore) UpdateDeploymentAllocHealth(index uint64, req *structs.ApplyDeploymentAllocHealthRequest) error {
  2701  	txn := s.db.Txn(true)
  2702  	defer txn.Abort()
  2703  
  2704  	// Retrieve deployment and ensure it is not terminal and is active
  2705  	ws := memdb.NewWatchSet()
  2706  	deployment, err := s.deploymentByIDImpl(ws, req.DeploymentID, txn)
  2707  	if err != nil {
  2708  		return err
  2709  	} else if deployment == nil {
  2710  		return fmt.Errorf("Deployment ID %q couldn't be updated as it does not exist", req.DeploymentID)
  2711  	} else if !deployment.Active() {
  2712  		return fmt.Errorf("Deployment %q has terminal status %q:", deployment.ID, deployment.Status)
  2713  	}
  2714  
  2715  	// Update the health status of each allocation
  2716  	if total := len(req.HealthyAllocationIDs) + len(req.UnhealthyAllocationIDs); total != 0 {
  2717  		setAllocHealth := func(id string, healthy bool) error {
  2718  			existing, err := txn.First("allocs", "id", id)
  2719  			if err != nil {
  2720  				return fmt.Errorf("alloc %q lookup failed: %v", id, err)
  2721  			}
  2722  			if existing == nil {
  2723  				return fmt.Errorf("unknown alloc %q", id)
  2724  			}
  2725  
  2726  			old := existing.(*structs.Allocation)
  2727  			if old.DeploymentID != req.DeploymentID {
  2728  				return fmt.Errorf("alloc %q is not part of deployment %q", id, req.DeploymentID)
  2729  			}
  2730  
  2731  			// Set the health
  2732  			copy := old.Copy()
  2733  			if copy.DeploymentStatus == nil {
  2734  				copy.DeploymentStatus = &structs.AllocDeploymentStatus{}
  2735  			}
  2736  			copy.DeploymentStatus.Healthy = helper.BoolToPtr(healthy)
  2737  			copy.DeploymentStatus.ModifyIndex = index
  2738  
  2739  			if err := s.updateDeploymentWithAlloc(index, copy, old, txn); err != nil {
  2740  				return fmt.Errorf("error updating deployment: %v", err)
  2741  			}
  2742  
  2743  			if err := txn.Insert("allocs", copy); err != nil {
  2744  				return fmt.Errorf("alloc insert failed: %v", err)
  2745  			}
  2746  
  2747  			return nil
  2748  		}
  2749  
  2750  		for _, id := range req.HealthyAllocationIDs {
  2751  			if err := setAllocHealth(id, true); err != nil {
  2752  				return err
  2753  			}
  2754  		}
  2755  		for _, id := range req.UnhealthyAllocationIDs {
  2756  			if err := setAllocHealth(id, false); err != nil {
  2757  				return err
  2758  			}
  2759  		}
  2760  
  2761  		// Update the indexes
  2762  		if err := txn.Insert("index", &IndexEntry{"allocs", index}); err != nil {
  2763  			return fmt.Errorf("index update failed: %v", err)
  2764  		}
  2765  	}
  2766  
  2767  	// Update the deployment status as needed.
  2768  	if req.DeploymentUpdate != nil {
  2769  		if err := s.updateDeploymentStatusImpl(index, req.DeploymentUpdate, txn); err != nil {
  2770  			return err
  2771  		}
  2772  	}
  2773  
  2774  	// Upsert the job if necessary
  2775  	if req.Job != nil {
  2776  		if err := s.upsertJobImpl(index, req.Job, false, txn); err != nil {
  2777  			return err
  2778  		}
  2779  	}
  2780  
  2781  	// Upsert the optional eval
  2782  	if req.Eval != nil {
  2783  		if err := s.nestedUpsertEval(txn, index, req.Eval); err != nil {
  2784  			return err
  2785  		}
  2786  	}
  2787  
  2788  	txn.Commit()
  2789  	return nil
  2790  }
  2791  
  2792  // LastIndex returns the greatest index value for all indexes
  2793  func (s *StateStore) LatestIndex() (uint64, error) {
  2794  	indexes, err := s.Indexes()
  2795  	if err != nil {
  2796  		return 0, err
  2797  	}
  2798  
  2799  	var max uint64 = 0
  2800  	for {
  2801  		raw := indexes.Next()
  2802  		if raw == nil {
  2803  			break
  2804  		}
  2805  
  2806  		// Prepare the request struct
  2807  		idx := raw.(*IndexEntry)
  2808  
  2809  		// Determine the max
  2810  		if idx.Value > max {
  2811  			max = idx.Value
  2812  		}
  2813  	}
  2814  
  2815  	return max, nil
  2816  }
  2817  
  2818  // Index finds the matching index value
  2819  func (s *StateStore) Index(name string) (uint64, error) {
  2820  	txn := s.db.Txn(false)
  2821  
  2822  	// Lookup the first matching index
  2823  	out, err := txn.First("index", "id", name)
  2824  	if err != nil {
  2825  		return 0, err
  2826  	}
  2827  	if out == nil {
  2828  		return 0, nil
  2829  	}
  2830  	return out.(*IndexEntry).Value, nil
  2831  }
  2832  
  2833  // RemoveIndex is a helper method to remove an index for testing purposes
  2834  func (s *StateStore) RemoveIndex(name string) error {
  2835  	txn := s.db.Txn(true)
  2836  	defer txn.Abort()
  2837  
  2838  	if _, err := txn.DeleteAll("index", "id", name); err != nil {
  2839  		return err
  2840  	}
  2841  
  2842  	txn.Commit()
  2843  	return nil
  2844  }
  2845  
  2846  // Indexes returns an iterator over all the indexes
  2847  func (s *StateStore) Indexes() (memdb.ResultIterator, error) {
  2848  	txn := s.db.Txn(false)
  2849  
  2850  	// Walk the entire nodes table
  2851  	iter, err := txn.Get("index", "id")
  2852  	if err != nil {
  2853  		return nil, err
  2854  	}
  2855  	return iter, nil
  2856  }
  2857  
  2858  // ReconcileJobSummaries re-creates summaries for all jobs present in the state
  2859  // store
  2860  func (s *StateStore) ReconcileJobSummaries(index uint64) error {
  2861  	txn := s.db.Txn(true)
  2862  	defer txn.Abort()
  2863  
  2864  	// Get all the jobs
  2865  	iter, err := txn.Get("jobs", "id")
  2866  	if err != nil {
  2867  		return err
  2868  	}
  2869  	for {
  2870  		rawJob := iter.Next()
  2871  		if rawJob == nil {
  2872  			break
  2873  		}
  2874  		job := rawJob.(*structs.Job)
  2875  
  2876  		// Create a job summary for the job
  2877  		summary := &structs.JobSummary{
  2878  			JobID:     job.ID,
  2879  			Namespace: job.Namespace,
  2880  			Summary:   make(map[string]structs.TaskGroupSummary),
  2881  		}
  2882  		for _, tg := range job.TaskGroups {
  2883  			summary.Summary[tg.Name] = structs.TaskGroupSummary{}
  2884  		}
  2885  
  2886  		// COMPAT 0.7: Upgrade old objects that do not have namespaces
  2887  		if job.Namespace == "" {
  2888  			job.Namespace = structs.DefaultNamespace
  2889  		}
  2890  
  2891  		// Find all the allocations for the jobs
  2892  		iterAllocs, err := txn.Get("allocs", "job", job.Namespace, job.ID)
  2893  		if err != nil {
  2894  			return err
  2895  		}
  2896  
  2897  		// Calculate the summary for the job
  2898  		for {
  2899  			rawAlloc := iterAllocs.Next()
  2900  			if rawAlloc == nil {
  2901  				break
  2902  			}
  2903  			alloc := rawAlloc.(*structs.Allocation)
  2904  
  2905  			// Ignore the allocation if it doesn't belong to the currently
  2906  			// registered job. The allocation is checked because of issue #2304
  2907  			if alloc.Job == nil || alloc.Job.CreateIndex != job.CreateIndex {
  2908  				continue
  2909  			}
  2910  
  2911  			tg := summary.Summary[alloc.TaskGroup]
  2912  			switch alloc.ClientStatus {
  2913  			case structs.AllocClientStatusFailed:
  2914  				tg.Failed += 1
  2915  			case structs.AllocClientStatusLost:
  2916  				tg.Lost += 1
  2917  			case structs.AllocClientStatusComplete:
  2918  				tg.Complete += 1
  2919  			case structs.AllocClientStatusRunning:
  2920  				tg.Running += 1
  2921  			case structs.AllocClientStatusPending:
  2922  				tg.Starting += 1
  2923  			default:
  2924  				s.logger.Printf("[ERR] state_store: invalid client status: %v in allocation %q", alloc.ClientStatus, alloc.ID)
  2925  			}
  2926  			summary.Summary[alloc.TaskGroup] = tg
  2927  		}
  2928  
  2929  		// Set the create index of the summary same as the job's create index
  2930  		// and the modify index to the current index
  2931  		summary.CreateIndex = job.CreateIndex
  2932  		summary.ModifyIndex = index
  2933  
  2934  		// Insert the job summary
  2935  		if err := txn.Insert("job_summary", summary); err != nil {
  2936  			return fmt.Errorf("error inserting job summary: %v", err)
  2937  		}
  2938  	}
  2939  
  2940  	// Update the indexes table for job summary
  2941  	if err := txn.Insert("index", &IndexEntry{"job_summary", index}); err != nil {
  2942  		return fmt.Errorf("index update failed: %v", err)
  2943  	}
  2944  	txn.Commit()
  2945  	return nil
  2946  }
  2947  
  2948  // setJobStatuses is a helper for calling setJobStatus on multiple jobs by ID.
  2949  // It takes a map of job IDs to an optional forceStatus string. It returns an
  2950  // error if the job doesn't exist or setJobStatus fails.
  2951  func (s *StateStore) setJobStatuses(index uint64, txn *memdb.Txn,
  2952  	jobs map[structs.NamespacedID]string, evalDelete bool) error {
  2953  	for tuple, forceStatus := range jobs {
  2954  		// COMPAT 0.7: Upgrade old objects that do not have namespaces
  2955  		if tuple.Namespace == "" {
  2956  			tuple.Namespace = structs.DefaultNamespace
  2957  		}
  2958  
  2959  		existing, err := txn.First("jobs", "id", tuple.Namespace, tuple.ID)
  2960  		if err != nil {
  2961  			return fmt.Errorf("job lookup failed: %v", err)
  2962  		}
  2963  
  2964  		if existing == nil {
  2965  			continue
  2966  		}
  2967  
  2968  		if err := s.setJobStatus(index, txn, existing.(*structs.Job), evalDelete, forceStatus); err != nil {
  2969  			return err
  2970  		}
  2971  	}
  2972  
  2973  	return nil
  2974  }
  2975  
  2976  // setJobStatus sets the status of the job by looking up associated evaluations
  2977  // and allocations. evalDelete should be set to true if setJobStatus is being
  2978  // called because an evaluation is being deleted (potentially because of garbage
  2979  // collection). If forceStatus is non-empty, the job's status will be set to the
  2980  // passed status.
  2981  func (s *StateStore) setJobStatus(index uint64, txn *memdb.Txn,
  2982  	job *structs.Job, evalDelete bool, forceStatus string) error {
  2983  
  2984  	// Capture the current status so we can check if there is a change
  2985  	oldStatus := job.Status
  2986  	if index == job.CreateIndex {
  2987  		oldStatus = ""
  2988  	}
  2989  	newStatus := forceStatus
  2990  
  2991  	// If forceStatus is not set, compute the jobs status.
  2992  	if forceStatus == "" {
  2993  		var err error
  2994  		newStatus, err = s.getJobStatus(txn, job, evalDelete)
  2995  		if err != nil {
  2996  			return err
  2997  		}
  2998  	}
  2999  
  3000  	// Fast-path if nothing has changed.
  3001  	if oldStatus == newStatus {
  3002  		return nil
  3003  	}
  3004  
  3005  	// Copy and update the existing job
  3006  	updated := job.Copy()
  3007  	updated.Status = newStatus
  3008  	updated.ModifyIndex = index
  3009  
  3010  	// COMPAT 0.7: Upgrade old objects that do not have namespaces
  3011  	if updated.Namespace == "" {
  3012  		updated.Namespace = structs.DefaultNamespace
  3013  	}
  3014  
  3015  	// Insert the job
  3016  	if err := txn.Insert("jobs", updated); err != nil {
  3017  		return fmt.Errorf("job insert failed: %v", err)
  3018  	}
  3019  	if err := txn.Insert("index", &IndexEntry{"jobs", index}); err != nil {
  3020  		return fmt.Errorf("index update failed: %v", err)
  3021  	}
  3022  
  3023  	// Update the children summary
  3024  	if updated.ParentID != "" {
  3025  		// Try to update the summary of the parent job summary
  3026  		summaryRaw, err := txn.First("job_summary", "id", updated.Namespace, updated.ParentID)
  3027  		if err != nil {
  3028  			return fmt.Errorf("unable to retrieve summary for parent job: %v", err)
  3029  		}
  3030  
  3031  		// Only continue if the summary exists. It could not exist if the parent
  3032  		// job was removed
  3033  		if summaryRaw != nil {
  3034  			existing := summaryRaw.(*structs.JobSummary)
  3035  			pSummary := existing.Copy()
  3036  			if pSummary.Children == nil {
  3037  				pSummary.Children = new(structs.JobChildrenSummary)
  3038  			}
  3039  
  3040  			// COMPAT 0.7: Upgrade old objects that do not have namespaces
  3041  			if pSummary.Namespace == "" {
  3042  				pSummary.Namespace = structs.DefaultNamespace
  3043  			}
  3044  
  3045  			// Determine the transition and update the correct fields
  3046  			children := pSummary.Children
  3047  
  3048  			// Decrement old status
  3049  			if oldStatus != "" {
  3050  				switch oldStatus {
  3051  				case structs.JobStatusPending:
  3052  					children.Pending--
  3053  				case structs.JobStatusRunning:
  3054  					children.Running--
  3055  				case structs.JobStatusDead:
  3056  					children.Dead--
  3057  				default:
  3058  					return fmt.Errorf("unknown old job status %q", oldStatus)
  3059  				}
  3060  			}
  3061  
  3062  			// Increment new status
  3063  			switch newStatus {
  3064  			case structs.JobStatusPending:
  3065  				children.Pending++
  3066  			case structs.JobStatusRunning:
  3067  				children.Running++
  3068  			case structs.JobStatusDead:
  3069  				children.Dead++
  3070  			default:
  3071  				return fmt.Errorf("unknown new job status %q", newStatus)
  3072  			}
  3073  
  3074  			// Update the index
  3075  			pSummary.ModifyIndex = index
  3076  
  3077  			// Insert the summary
  3078  			if err := txn.Insert("job_summary", pSummary); err != nil {
  3079  				return fmt.Errorf("job summary insert failed: %v", err)
  3080  			}
  3081  			if err := txn.Insert("index", &IndexEntry{"job_summary", index}); err != nil {
  3082  				return fmt.Errorf("index update failed: %v", err)
  3083  			}
  3084  		}
  3085  	}
  3086  
  3087  	return nil
  3088  }
  3089  
  3090  func (s *StateStore) getJobStatus(txn *memdb.Txn, job *structs.Job, evalDelete bool) (string, error) {
  3091  	// COMPAT 0.7: Upgrade old objects that do not have namespaces
  3092  	if job.Namespace == "" {
  3093  		job.Namespace = structs.DefaultNamespace
  3094  	}
  3095  
  3096  	// System, Periodic and Parameterized jobs are running until explicitly
  3097  	// stopped
  3098  	if job.Type == structs.JobTypeSystem || job.IsParameterized() || job.IsPeriodic() {
  3099  		if job.Stop {
  3100  			return structs.JobStatusDead, nil
  3101  		}
  3102  
  3103  		return structs.JobStatusRunning, nil
  3104  	}
  3105  
  3106  	allocs, err := txn.Get("allocs", "job", job.Namespace, job.ID)
  3107  	if err != nil {
  3108  		return "", err
  3109  	}
  3110  
  3111  	// If there is a non-terminal allocation, the job is running.
  3112  	hasAlloc := false
  3113  	for alloc := allocs.Next(); alloc != nil; alloc = allocs.Next() {
  3114  		hasAlloc = true
  3115  		if !alloc.(*structs.Allocation).TerminalStatus() {
  3116  			return structs.JobStatusRunning, nil
  3117  		}
  3118  	}
  3119  
  3120  	evals, err := txn.Get("evals", "job_prefix", job.Namespace, job.ID)
  3121  	if err != nil {
  3122  		return "", err
  3123  	}
  3124  
  3125  	hasEval := false
  3126  	for raw := evals.Next(); raw != nil; raw = evals.Next() {
  3127  		e := raw.(*structs.Evaluation)
  3128  
  3129  		// Filter non-exact matches
  3130  		if e.JobID != job.ID {
  3131  			continue
  3132  		}
  3133  
  3134  		hasEval = true
  3135  		if !e.TerminalStatus() {
  3136  			return structs.JobStatusPending, nil
  3137  		}
  3138  	}
  3139  
  3140  	// The job is dead if all the allocations and evals are terminal or if there
  3141  	// are no evals because of garbage collection.
  3142  	if evalDelete || hasEval || hasAlloc {
  3143  		return structs.JobStatusDead, nil
  3144  	}
  3145  
  3146  	return structs.JobStatusPending, nil
  3147  }
  3148  
  3149  // updateSummaryWithJob creates or updates job summaries when new jobs are
  3150  // upserted or existing ones are updated
  3151  func (s *StateStore) updateSummaryWithJob(index uint64, job *structs.Job,
  3152  	txn *memdb.Txn) error {
  3153  
  3154  	// COMPAT 0.7: Upgrade old objects that do not have namespaces
  3155  	if job.Namespace == "" {
  3156  		job.Namespace = structs.DefaultNamespace
  3157  	}
  3158  
  3159  	// Update the job summary
  3160  	summaryRaw, err := txn.First("job_summary", "id", job.Namespace, job.ID)
  3161  	if err != nil {
  3162  		return fmt.Errorf("job summary lookup failed: %v", err)
  3163  	}
  3164  
  3165  	// Get the summary or create if necessary
  3166  	var summary *structs.JobSummary
  3167  	hasSummaryChanged := false
  3168  	if summaryRaw != nil {
  3169  		summary = summaryRaw.(*structs.JobSummary).Copy()
  3170  	} else {
  3171  		summary = &structs.JobSummary{
  3172  			JobID:       job.ID,
  3173  			Namespace:   job.Namespace,
  3174  			Summary:     make(map[string]structs.TaskGroupSummary),
  3175  			Children:    new(structs.JobChildrenSummary),
  3176  			CreateIndex: index,
  3177  		}
  3178  		hasSummaryChanged = true
  3179  	}
  3180  
  3181  	for _, tg := range job.TaskGroups {
  3182  		if _, ok := summary.Summary[tg.Name]; !ok {
  3183  			newSummary := structs.TaskGroupSummary{
  3184  				Complete: 0,
  3185  				Failed:   0,
  3186  				Running:  0,
  3187  				Starting: 0,
  3188  			}
  3189  			summary.Summary[tg.Name] = newSummary
  3190  			hasSummaryChanged = true
  3191  		}
  3192  	}
  3193  
  3194  	// The job summary has changed, so update the modify index.
  3195  	if hasSummaryChanged {
  3196  		summary.ModifyIndex = index
  3197  
  3198  		// COMPAT 0.7: Upgrade old objects that do not have namespaces
  3199  		if summary.Namespace == "" {
  3200  			summary.Namespace = structs.DefaultNamespace
  3201  		}
  3202  
  3203  		// Update the indexes table for job summary
  3204  		if err := txn.Insert("index", &IndexEntry{"job_summary", index}); err != nil {
  3205  			return fmt.Errorf("index update failed: %v", err)
  3206  		}
  3207  		if err := txn.Insert("job_summary", summary); err != nil {
  3208  			return err
  3209  		}
  3210  	}
  3211  
  3212  	return nil
  3213  }
  3214  
  3215  // updateDeploymentWithAlloc is used to update the deployment state associated
  3216  // with the given allocation. The passed alloc may be updated if the deployment
  3217  // status has changed to capture the modify index at which it has changed.
  3218  func (s *StateStore) updateDeploymentWithAlloc(index uint64, alloc, existing *structs.Allocation, txn *memdb.Txn) error {
  3219  	// Nothing to do if the allocation is not associated with a deployment
  3220  	if alloc.DeploymentID == "" {
  3221  		return nil
  3222  	}
  3223  
  3224  	// Get the deployment
  3225  	ws := memdb.NewWatchSet()
  3226  	deployment, err := s.deploymentByIDImpl(ws, alloc.DeploymentID, txn)
  3227  	if err != nil {
  3228  		return err
  3229  	}
  3230  	if deployment == nil {
  3231  		return nil
  3232  	}
  3233  
  3234  	// Retrieve the deployment state object
  3235  	_, ok := deployment.TaskGroups[alloc.TaskGroup]
  3236  	if !ok {
  3237  		// If the task group isn't part of the deployment, the task group wasn't
  3238  		// part of a rolling update so nothing to do
  3239  		return nil
  3240  	}
  3241  
  3242  	// Do not modify in-place. Instead keep track of what must be done
  3243  	placed := 0
  3244  	healthy := 0
  3245  	unhealthy := 0
  3246  
  3247  	// If there was no existing allocation, this is a placement and we increment
  3248  	// the placement
  3249  	existingHealthSet := existing != nil && existing.DeploymentStatus.HasHealth()
  3250  	allocHealthSet := alloc.DeploymentStatus.HasHealth()
  3251  	if existing == nil || existing.DeploymentID != alloc.DeploymentID {
  3252  		placed++
  3253  	} else if !existingHealthSet && allocHealthSet {
  3254  		if *alloc.DeploymentStatus.Healthy {
  3255  			healthy++
  3256  		} else {
  3257  			unhealthy++
  3258  		}
  3259  	} else if existingHealthSet && allocHealthSet {
  3260  		// See if it has gone from healthy to unhealthy
  3261  		if *existing.DeploymentStatus.Healthy && !*alloc.DeploymentStatus.Healthy {
  3262  			healthy--
  3263  			unhealthy++
  3264  		}
  3265  	}
  3266  
  3267  	// Nothing to do
  3268  	if placed == 0 && healthy == 0 && unhealthy == 0 {
  3269  		return nil
  3270  	}
  3271  
  3272  	// Update the allocation's deployment status modify index
  3273  	if alloc.DeploymentStatus != nil && healthy+unhealthy != 0 {
  3274  		alloc.DeploymentStatus.ModifyIndex = index
  3275  	}
  3276  
  3277  	// Create a copy of the deployment object
  3278  	deploymentCopy := deployment.Copy()
  3279  	deploymentCopy.ModifyIndex = index
  3280  
  3281  	state := deploymentCopy.TaskGroups[alloc.TaskGroup]
  3282  	state.PlacedAllocs += placed
  3283  	state.HealthyAllocs += healthy
  3284  	state.UnhealthyAllocs += unhealthy
  3285  
  3286  	// Upsert the deployment
  3287  	if err := s.upsertDeploymentImpl(index, deploymentCopy, txn); err != nil {
  3288  		return err
  3289  	}
  3290  
  3291  	return nil
  3292  }
  3293  
  3294  // updateSummaryWithAlloc updates the job summary when allocations are updated
  3295  // or inserted
  3296  func (s *StateStore) updateSummaryWithAlloc(index uint64, alloc *structs.Allocation,
  3297  	existingAlloc *structs.Allocation, txn *memdb.Txn) error {
  3298  
  3299  	// We don't have to update the summary if the job is missing
  3300  	if alloc.Job == nil {
  3301  		return nil
  3302  	}
  3303  	// COMPAT 0.7: Upgrade old objects that do not have namespaces
  3304  	if alloc.Namespace == "" {
  3305  		alloc.Namespace = structs.DefaultNamespace
  3306  	}
  3307  
  3308  	summaryRaw, err := txn.First("job_summary", "id", alloc.Namespace, alloc.JobID)
  3309  	if err != nil {
  3310  		return fmt.Errorf("unable to lookup job summary for job id %q in namespace %q: %v", alloc.JobID, alloc.Namespace, err)
  3311  	}
  3312  
  3313  	if summaryRaw == nil {
  3314  		// Check if the job is de-registered
  3315  		rawJob, err := txn.First("jobs", "id", alloc.Namespace, alloc.JobID)
  3316  		if err != nil {
  3317  			return fmt.Errorf("unable to query job: %v", err)
  3318  		}
  3319  
  3320  		// If the job is de-registered then we skip updating it's summary
  3321  		if rawJob == nil {
  3322  			return nil
  3323  		}
  3324  
  3325  		return fmt.Errorf("job summary for job %q in namespace %q is not present", alloc.JobID, alloc.Namespace)
  3326  	}
  3327  
  3328  	// Get a copy of the existing summary
  3329  	jobSummary := summaryRaw.(*structs.JobSummary).Copy()
  3330  
  3331  	// Not updating the job summary because the allocation doesn't belong to the
  3332  	// currently registered job
  3333  	if jobSummary.CreateIndex != alloc.Job.CreateIndex {
  3334  		return nil
  3335  	}
  3336  
  3337  	tgSummary, ok := jobSummary.Summary[alloc.TaskGroup]
  3338  	if !ok {
  3339  		return fmt.Errorf("unable to find task group in the job summary: %v", alloc.TaskGroup)
  3340  	}
  3341  
  3342  	summaryChanged := false
  3343  	if existingAlloc == nil {
  3344  		switch alloc.DesiredStatus {
  3345  		case structs.AllocDesiredStatusStop, structs.AllocDesiredStatusEvict:
  3346  			s.logger.Printf("[ERR] state_store: new allocation inserted into state store with id: %v and state: %v",
  3347  				alloc.ID, alloc.DesiredStatus)
  3348  		}
  3349  		switch alloc.ClientStatus {
  3350  		case structs.AllocClientStatusPending:
  3351  			tgSummary.Starting += 1
  3352  			if tgSummary.Queued > 0 {
  3353  				tgSummary.Queued -= 1
  3354  			}
  3355  			summaryChanged = true
  3356  		case structs.AllocClientStatusRunning, structs.AllocClientStatusFailed,
  3357  			structs.AllocClientStatusComplete:
  3358  			s.logger.Printf("[ERR] state_store: new allocation inserted into state store with id: %v and state: %v",
  3359  				alloc.ID, alloc.ClientStatus)
  3360  		}
  3361  	} else if existingAlloc.ClientStatus != alloc.ClientStatus {
  3362  		// Incrementing the client of the bin of the current state
  3363  		switch alloc.ClientStatus {
  3364  		case structs.AllocClientStatusRunning:
  3365  			tgSummary.Running += 1
  3366  		case structs.AllocClientStatusFailed:
  3367  			tgSummary.Failed += 1
  3368  		case structs.AllocClientStatusPending:
  3369  			tgSummary.Starting += 1
  3370  		case structs.AllocClientStatusComplete:
  3371  			tgSummary.Complete += 1
  3372  		case structs.AllocClientStatusLost:
  3373  			tgSummary.Lost += 1
  3374  		}
  3375  
  3376  		// Decrementing the count of the bin of the last state
  3377  		switch existingAlloc.ClientStatus {
  3378  		case structs.AllocClientStatusRunning:
  3379  			tgSummary.Running -= 1
  3380  		case structs.AllocClientStatusPending:
  3381  			tgSummary.Starting -= 1
  3382  		case structs.AllocClientStatusLost:
  3383  			tgSummary.Lost -= 1
  3384  		case structs.AllocClientStatusFailed, structs.AllocClientStatusComplete:
  3385  		default:
  3386  			s.logger.Printf("[ERR] state_store: invalid old state of allocation with id: %v, and state: %v",
  3387  				existingAlloc.ID, existingAlloc.ClientStatus)
  3388  		}
  3389  		summaryChanged = true
  3390  	}
  3391  	jobSummary.Summary[alloc.TaskGroup] = tgSummary
  3392  
  3393  	if summaryChanged {
  3394  		jobSummary.ModifyIndex = index
  3395  
  3396  		// COMPAT 0.7: Upgrade old objects that do not have namespaces
  3397  		if jobSummary.Namespace == "" {
  3398  			jobSummary.Namespace = structs.DefaultNamespace
  3399  		}
  3400  
  3401  		// Update the indexes table for job summary
  3402  		if err := txn.Insert("index", &IndexEntry{"job_summary", index}); err != nil {
  3403  			return fmt.Errorf("index update failed: %v", err)
  3404  		}
  3405  
  3406  		if err := txn.Insert("job_summary", jobSummary); err != nil {
  3407  			return fmt.Errorf("updating job summary failed: %v", err)
  3408  		}
  3409  	}
  3410  
  3411  	return nil
  3412  }
  3413  
  3414  // addEphemeralDiskToTaskGroups adds missing EphemeralDisk objects to TaskGroups
  3415  func (s *StateStore) addEphemeralDiskToTaskGroups(job *structs.Job) {
  3416  	for _, tg := range job.TaskGroups {
  3417  		var diskMB int
  3418  		for _, task := range tg.Tasks {
  3419  			if task.Resources != nil {
  3420  				diskMB += task.Resources.DiskMB
  3421  				task.Resources.DiskMB = 0
  3422  			}
  3423  		}
  3424  		if tg.EphemeralDisk != nil {
  3425  			continue
  3426  		}
  3427  		tg.EphemeralDisk = &structs.EphemeralDisk{
  3428  			SizeMB: diskMB,
  3429  		}
  3430  	}
  3431  }
  3432  
  3433  // UpsertACLPolicies is used to create or update a set of ACL policies
  3434  func (s *StateStore) UpsertACLPolicies(index uint64, policies []*structs.ACLPolicy) error {
  3435  	txn := s.db.Txn(true)
  3436  	defer txn.Abort()
  3437  
  3438  	for _, policy := range policies {
  3439  		// Ensure the policy hash is non-nil. This should be done outside the state store
  3440  		// for performance reasons, but we check here for defense in depth.
  3441  		if len(policy.Hash) == 0 {
  3442  			policy.SetHash()
  3443  		}
  3444  
  3445  		// Check if the policy already exists
  3446  		existing, err := txn.First("acl_policy", "id", policy.Name)
  3447  		if err != nil {
  3448  			return fmt.Errorf("policy lookup failed: %v", err)
  3449  		}
  3450  
  3451  		// Update all the indexes
  3452  		if existing != nil {
  3453  			policy.CreateIndex = existing.(*structs.ACLPolicy).CreateIndex
  3454  			policy.ModifyIndex = index
  3455  		} else {
  3456  			policy.CreateIndex = index
  3457  			policy.ModifyIndex = index
  3458  		}
  3459  
  3460  		// Update the policy
  3461  		if err := txn.Insert("acl_policy", policy); err != nil {
  3462  			return fmt.Errorf("upserting policy failed: %v", err)
  3463  		}
  3464  	}
  3465  
  3466  	// Update the indexes tabl
  3467  	if err := txn.Insert("index", &IndexEntry{"acl_policy", index}); err != nil {
  3468  		return fmt.Errorf("index update failed: %v", err)
  3469  	}
  3470  
  3471  	txn.Commit()
  3472  	return nil
  3473  }
  3474  
  3475  // DeleteACLPolicies deletes the policies with the given names
  3476  func (s *StateStore) DeleteACLPolicies(index uint64, names []string) error {
  3477  	txn := s.db.Txn(true)
  3478  	defer txn.Abort()
  3479  
  3480  	// Delete the policy
  3481  	for _, name := range names {
  3482  		if _, err := txn.DeleteAll("acl_policy", "id", name); err != nil {
  3483  			return fmt.Errorf("deleting acl policy failed: %v", err)
  3484  		}
  3485  	}
  3486  	if err := txn.Insert("index", &IndexEntry{"acl_policy", index}); err != nil {
  3487  		return fmt.Errorf("index update failed: %v", err)
  3488  	}
  3489  	txn.Commit()
  3490  	return nil
  3491  }
  3492  
  3493  // ACLPolicyByName is used to lookup a policy by name
  3494  func (s *StateStore) ACLPolicyByName(ws memdb.WatchSet, name string) (*structs.ACLPolicy, error) {
  3495  	txn := s.db.Txn(false)
  3496  
  3497  	watchCh, existing, err := txn.FirstWatch("acl_policy", "id", name)
  3498  	if err != nil {
  3499  		return nil, fmt.Errorf("acl policy lookup failed: %v", err)
  3500  	}
  3501  	ws.Add(watchCh)
  3502  
  3503  	if existing != nil {
  3504  		return existing.(*structs.ACLPolicy), nil
  3505  	}
  3506  	return nil, nil
  3507  }
  3508  
  3509  // ACLPolicyByNamePrefix is used to lookup policies by prefix
  3510  func (s *StateStore) ACLPolicyByNamePrefix(ws memdb.WatchSet, prefix string) (memdb.ResultIterator, error) {
  3511  	txn := s.db.Txn(false)
  3512  
  3513  	iter, err := txn.Get("acl_policy", "id_prefix", prefix)
  3514  	if err != nil {
  3515  		return nil, fmt.Errorf("acl policy lookup failed: %v", err)
  3516  	}
  3517  	ws.Add(iter.WatchCh())
  3518  
  3519  	return iter, nil
  3520  }
  3521  
  3522  // ACLPolicies returns an iterator over all the acl policies
  3523  func (s *StateStore) ACLPolicies(ws memdb.WatchSet) (memdb.ResultIterator, error) {
  3524  	txn := s.db.Txn(false)
  3525  
  3526  	// Walk the entire table
  3527  	iter, err := txn.Get("acl_policy", "id")
  3528  	if err != nil {
  3529  		return nil, err
  3530  	}
  3531  	ws.Add(iter.WatchCh())
  3532  	return iter, nil
  3533  }
  3534  
  3535  // UpsertACLTokens is used to create or update a set of ACL tokens
  3536  func (s *StateStore) UpsertACLTokens(index uint64, tokens []*structs.ACLToken) error {
  3537  	txn := s.db.Txn(true)
  3538  	defer txn.Abort()
  3539  
  3540  	for _, token := range tokens {
  3541  		// Ensure the policy hash is non-nil. This should be done outside the state store
  3542  		// for performance reasons, but we check here for defense in depth.
  3543  		if len(token.Hash) == 0 {
  3544  			token.SetHash()
  3545  		}
  3546  
  3547  		// Check if the token already exists
  3548  		existing, err := txn.First("acl_token", "id", token.AccessorID)
  3549  		if err != nil {
  3550  			return fmt.Errorf("token lookup failed: %v", err)
  3551  		}
  3552  
  3553  		// Update all the indexes
  3554  		if existing != nil {
  3555  			existTK := existing.(*structs.ACLToken)
  3556  			token.CreateIndex = existTK.CreateIndex
  3557  			token.ModifyIndex = index
  3558  
  3559  			// Do not allow SecretID or create time to change
  3560  			token.SecretID = existTK.SecretID
  3561  			token.CreateTime = existTK.CreateTime
  3562  
  3563  		} else {
  3564  			token.CreateIndex = index
  3565  			token.ModifyIndex = index
  3566  		}
  3567  
  3568  		// Update the token
  3569  		if err := txn.Insert("acl_token", token); err != nil {
  3570  			return fmt.Errorf("upserting token failed: %v", err)
  3571  		}
  3572  	}
  3573  
  3574  	// Update the indexes table
  3575  	if err := txn.Insert("index", &IndexEntry{"acl_token", index}); err != nil {
  3576  		return fmt.Errorf("index update failed: %v", err)
  3577  	}
  3578  	txn.Commit()
  3579  	return nil
  3580  }
  3581  
  3582  // DeleteACLTokens deletes the tokens with the given accessor ids
  3583  func (s *StateStore) DeleteACLTokens(index uint64, ids []string) error {
  3584  	txn := s.db.Txn(true)
  3585  	defer txn.Abort()
  3586  
  3587  	// Delete the tokens
  3588  	for _, id := range ids {
  3589  		if _, err := txn.DeleteAll("acl_token", "id", id); err != nil {
  3590  			return fmt.Errorf("deleting acl token failed: %v", err)
  3591  		}
  3592  	}
  3593  	if err := txn.Insert("index", &IndexEntry{"acl_token", index}); err != nil {
  3594  		return fmt.Errorf("index update failed: %v", err)
  3595  	}
  3596  	txn.Commit()
  3597  	return nil
  3598  }
  3599  
  3600  // ACLTokenByAccessorID is used to lookup a token by accessor ID
  3601  func (s *StateStore) ACLTokenByAccessorID(ws memdb.WatchSet, id string) (*structs.ACLToken, error) {
  3602  	txn := s.db.Txn(false)
  3603  
  3604  	watchCh, existing, err := txn.FirstWatch("acl_token", "id", id)
  3605  	if err != nil {
  3606  		return nil, fmt.Errorf("acl token lookup failed: %v", err)
  3607  	}
  3608  	ws.Add(watchCh)
  3609  
  3610  	if existing != nil {
  3611  		return existing.(*structs.ACLToken), nil
  3612  	}
  3613  	return nil, nil
  3614  }
  3615  
  3616  // ACLTokenBySecretID is used to lookup a token by secret ID
  3617  func (s *StateStore) ACLTokenBySecretID(ws memdb.WatchSet, secretID string) (*structs.ACLToken, error) {
  3618  	txn := s.db.Txn(false)
  3619  
  3620  	watchCh, existing, err := txn.FirstWatch("acl_token", "secret", secretID)
  3621  	if err != nil {
  3622  		return nil, fmt.Errorf("acl token lookup failed: %v", err)
  3623  	}
  3624  	ws.Add(watchCh)
  3625  
  3626  	if existing != nil {
  3627  		return existing.(*structs.ACLToken), nil
  3628  	}
  3629  	return nil, nil
  3630  }
  3631  
  3632  // ACLTokenByAccessorIDPrefix is used to lookup tokens by prefix
  3633  func (s *StateStore) ACLTokenByAccessorIDPrefix(ws memdb.WatchSet, prefix string) (memdb.ResultIterator, error) {
  3634  	txn := s.db.Txn(false)
  3635  
  3636  	iter, err := txn.Get("acl_token", "id_prefix", prefix)
  3637  	if err != nil {
  3638  		return nil, fmt.Errorf("acl token lookup failed: %v", err)
  3639  	}
  3640  	ws.Add(iter.WatchCh())
  3641  	return iter, nil
  3642  }
  3643  
  3644  // ACLTokens returns an iterator over all the tokens
  3645  func (s *StateStore) ACLTokens(ws memdb.WatchSet) (memdb.ResultIterator, error) {
  3646  	txn := s.db.Txn(false)
  3647  
  3648  	// Walk the entire table
  3649  	iter, err := txn.Get("acl_token", "id")
  3650  	if err != nil {
  3651  		return nil, err
  3652  	}
  3653  	ws.Add(iter.WatchCh())
  3654  	return iter, nil
  3655  }
  3656  
  3657  // ACLTokensByGlobal returns an iterator over all the tokens filtered by global value
  3658  func (s *StateStore) ACLTokensByGlobal(ws memdb.WatchSet, globalVal bool) (memdb.ResultIterator, error) {
  3659  	txn := s.db.Txn(false)
  3660  
  3661  	// Walk the entire table
  3662  	iter, err := txn.Get("acl_token", "global", globalVal)
  3663  	if err != nil {
  3664  		return nil, err
  3665  	}
  3666  	ws.Add(iter.WatchCh())
  3667  	return iter, nil
  3668  }
  3669  
  3670  // CanBootstrapACLToken checks if bootstrapping is possible and returns the reset index
  3671  func (s *StateStore) CanBootstrapACLToken() (bool, uint64, error) {
  3672  	txn := s.db.Txn(false)
  3673  
  3674  	// Lookup the bootstrap sentinel
  3675  	out, err := txn.First("index", "id", "acl_token_bootstrap")
  3676  	if err != nil {
  3677  		return false, 0, err
  3678  	}
  3679  
  3680  	// No entry, we haven't bootstrapped yet
  3681  	if out == nil {
  3682  		return true, 0, nil
  3683  	}
  3684  
  3685  	// Return the reset index if we've already bootstrapped
  3686  	return false, out.(*IndexEntry).Value, nil
  3687  }
  3688  
  3689  // BootstrapACLToken is used to create an initial ACL token
  3690  func (s *StateStore) BootstrapACLTokens(index, resetIndex uint64, token *structs.ACLToken) error {
  3691  	txn := s.db.Txn(true)
  3692  	defer txn.Abort()
  3693  
  3694  	// Check if we have already done a bootstrap
  3695  	existing, err := txn.First("index", "id", "acl_token_bootstrap")
  3696  	if err != nil {
  3697  		return fmt.Errorf("bootstrap check failed: %v", err)
  3698  	}
  3699  	if existing != nil {
  3700  		if resetIndex == 0 {
  3701  			return fmt.Errorf("ACL bootstrap already done")
  3702  		} else if resetIndex != existing.(*IndexEntry).Value {
  3703  			return fmt.Errorf("Invalid reset index for ACL bootstrap")
  3704  		}
  3705  	}
  3706  
  3707  	// Update the Create/Modify time
  3708  	token.CreateIndex = index
  3709  	token.ModifyIndex = index
  3710  
  3711  	// Insert the token
  3712  	if err := txn.Insert("acl_token", token); err != nil {
  3713  		return fmt.Errorf("upserting token failed: %v", err)
  3714  	}
  3715  
  3716  	// Update the indexes table, prevents future bootstrap until reset
  3717  	if err := txn.Insert("index", &IndexEntry{"acl_token", index}); err != nil {
  3718  		return fmt.Errorf("index update failed: %v", err)
  3719  	}
  3720  	if err := txn.Insert("index", &IndexEntry{"acl_token_bootstrap", index}); err != nil {
  3721  		return fmt.Errorf("index update failed: %v", err)
  3722  	}
  3723  	txn.Commit()
  3724  	return nil
  3725  }
  3726  
  3727  // StateSnapshot is used to provide a point-in-time snapshot
  3728  type StateSnapshot struct {
  3729  	StateStore
  3730  }
  3731  
  3732  // StateRestore is used to optimize the performance when
  3733  // restoring state by only using a single large transaction
  3734  // instead of thousands of sub transactions
  3735  type StateRestore struct {
  3736  	txn *memdb.Txn
  3737  }
  3738  
  3739  // Abort is used to abort the restore operation
  3740  func (s *StateRestore) Abort() {
  3741  	s.txn.Abort()
  3742  }
  3743  
  3744  // Commit is used to commit the restore operation
  3745  func (s *StateRestore) Commit() {
  3746  	s.txn.Commit()
  3747  }
  3748  
  3749  // NodeRestore is used to restore a node
  3750  func (r *StateRestore) NodeRestore(node *structs.Node) error {
  3751  	if err := r.txn.Insert("nodes", node); err != nil {
  3752  		return fmt.Errorf("node insert failed: %v", err)
  3753  	}
  3754  	return nil
  3755  }
  3756  
  3757  // JobRestore is used to restore a job
  3758  func (r *StateRestore) JobRestore(job *structs.Job) error {
  3759  	// Create the EphemeralDisk if it's nil by adding up DiskMB from task resources.
  3760  	// COMPAT 0.4.1 -> 0.5
  3761  	r.addEphemeralDiskToTaskGroups(job)
  3762  
  3763  	if err := r.txn.Insert("jobs", job); err != nil {
  3764  		return fmt.Errorf("job insert failed: %v", err)
  3765  	}
  3766  	return nil
  3767  }
  3768  
  3769  // EvalRestore is used to restore an evaluation
  3770  func (r *StateRestore) EvalRestore(eval *structs.Evaluation) error {
  3771  	if err := r.txn.Insert("evals", eval); err != nil {
  3772  		return fmt.Errorf("eval insert failed: %v", err)
  3773  	}
  3774  	return nil
  3775  }
  3776  
  3777  // AllocRestore is used to restore an allocation
  3778  func (r *StateRestore) AllocRestore(alloc *structs.Allocation) error {
  3779  	// Set the shared resources if it's not present
  3780  	// COMPAT 0.4.1 -> 0.5
  3781  	if alloc.SharedResources == nil {
  3782  		alloc.SharedResources = &structs.Resources{
  3783  			DiskMB: alloc.Resources.DiskMB,
  3784  		}
  3785  	}
  3786  
  3787  	// Create the EphemeralDisk if it's nil by adding up DiskMB from task resources.
  3788  	if alloc.Job != nil {
  3789  		r.addEphemeralDiskToTaskGroups(alloc.Job)
  3790  	}
  3791  
  3792  	if err := r.txn.Insert("allocs", alloc); err != nil {
  3793  		return fmt.Errorf("alloc insert failed: %v", err)
  3794  	}
  3795  	return nil
  3796  }
  3797  
  3798  // IndexRestore is used to restore an index
  3799  func (r *StateRestore) IndexRestore(idx *IndexEntry) error {
  3800  	if err := r.txn.Insert("index", idx); err != nil {
  3801  		return fmt.Errorf("index insert failed: %v", err)
  3802  	}
  3803  	return nil
  3804  }
  3805  
  3806  // PeriodicLaunchRestore is used to restore a periodic launch.
  3807  func (r *StateRestore) PeriodicLaunchRestore(launch *structs.PeriodicLaunch) error {
  3808  	if err := r.txn.Insert("periodic_launch", launch); err != nil {
  3809  		return fmt.Errorf("periodic launch insert failed: %v", err)
  3810  	}
  3811  	return nil
  3812  }
  3813  
  3814  // JobSummaryRestore is used to restore a job summary
  3815  func (r *StateRestore) JobSummaryRestore(jobSummary *structs.JobSummary) error {
  3816  	if err := r.txn.Insert("job_summary", jobSummary); err != nil {
  3817  		return fmt.Errorf("job summary insert failed: %v", err)
  3818  	}
  3819  	return nil
  3820  }
  3821  
  3822  // JobVersionRestore is used to restore a job version
  3823  func (r *StateRestore) JobVersionRestore(version *structs.Job) error {
  3824  	if err := r.txn.Insert("job_version", version); err != nil {
  3825  		return fmt.Errorf("job version insert failed: %v", err)
  3826  	}
  3827  	return nil
  3828  }
  3829  
  3830  // DeploymentRestore is used to restore a deployment
  3831  func (r *StateRestore) DeploymentRestore(deployment *structs.Deployment) error {
  3832  	if err := r.txn.Insert("deployment", deployment); err != nil {
  3833  		return fmt.Errorf("deployment insert failed: %v", err)
  3834  	}
  3835  	return nil
  3836  }
  3837  
  3838  // VaultAccessorRestore is used to restore a vault accessor
  3839  func (r *StateRestore) VaultAccessorRestore(accessor *structs.VaultAccessor) error {
  3840  	if err := r.txn.Insert("vault_accessors", accessor); err != nil {
  3841  		return fmt.Errorf("vault accessor insert failed: %v", err)
  3842  	}
  3843  	return nil
  3844  }
  3845  
  3846  // ACLPolicyRestore is used to restore an ACL policy
  3847  func (r *StateRestore) ACLPolicyRestore(policy *structs.ACLPolicy) error {
  3848  	if err := r.txn.Insert("acl_policy", policy); err != nil {
  3849  		return fmt.Errorf("inserting acl policy failed: %v", err)
  3850  	}
  3851  	return nil
  3852  }
  3853  
  3854  // ACLTokenRestore is used to restore an ACL token
  3855  func (r *StateRestore) ACLTokenRestore(token *structs.ACLToken) error {
  3856  	if err := r.txn.Insert("acl_token", token); err != nil {
  3857  		return fmt.Errorf("inserting acl token failed: %v", err)
  3858  	}
  3859  	return nil
  3860  }
  3861  
  3862  // addEphemeralDiskToTaskGroups adds missing EphemeralDisk objects to TaskGroups
  3863  func (r *StateRestore) addEphemeralDiskToTaskGroups(job *structs.Job) {
  3864  	for _, tg := range job.TaskGroups {
  3865  		if tg.EphemeralDisk != nil {
  3866  			continue
  3867  		}
  3868  		var sizeMB int
  3869  		for _, task := range tg.Tasks {
  3870  			if task.Resources != nil {
  3871  				sizeMB += task.Resources.DiskMB
  3872  				task.Resources.DiskMB = 0
  3873  			}
  3874  		}
  3875  		tg.EphemeralDisk = &structs.EphemeralDisk{
  3876  			SizeMB: sizeMB,
  3877  		}
  3878  	}
  3879  }