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