github.phpd.cn/hashicorp/consul@v1.4.5/agent/consul/state/catalog.go (about)

     1  package state
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/hashicorp/consul/agent/structs"
     8  	"github.com/hashicorp/consul/api"
     9  	"github.com/hashicorp/consul/types"
    10  	"github.com/hashicorp/go-memdb"
    11  	uuid "github.com/hashicorp/go-uuid"
    12  )
    13  
    14  const (
    15  	servicesTableName = "services"
    16  
    17  	// serviceLastExtinctionIndexName keeps track of the last raft index when the last instance
    18  	// of any service was unregistered. This is used by blocking queries on missing services.
    19  	serviceLastExtinctionIndexName = "service_last_extinction"
    20  )
    21  
    22  // nodesTableSchema returns a new table schema used for storing node
    23  // information.
    24  func nodesTableSchema() *memdb.TableSchema {
    25  	return &memdb.TableSchema{
    26  		Name: "nodes",
    27  		Indexes: map[string]*memdb.IndexSchema{
    28  			"id": &memdb.IndexSchema{
    29  				Name:         "id",
    30  				AllowMissing: false,
    31  				Unique:       true,
    32  				Indexer: &memdb.StringFieldIndex{
    33  					Field:     "Node",
    34  					Lowercase: true,
    35  				},
    36  			},
    37  			"uuid": &memdb.IndexSchema{
    38  				Name:         "uuid",
    39  				AllowMissing: true,
    40  				Unique:       true,
    41  				Indexer: &memdb.UUIDFieldIndex{
    42  					Field: "ID",
    43  				},
    44  			},
    45  			"meta": &memdb.IndexSchema{
    46  				Name:         "meta",
    47  				AllowMissing: true,
    48  				Unique:       false,
    49  				Indexer: &memdb.StringMapFieldIndex{
    50  					Field:     "Meta",
    51  					Lowercase: false,
    52  				},
    53  			},
    54  		},
    55  	}
    56  }
    57  
    58  // servicesTableSchema returns a new table schema used to store information
    59  // about services.
    60  func servicesTableSchema() *memdb.TableSchema {
    61  	return &memdb.TableSchema{
    62  		Name: "services",
    63  		Indexes: map[string]*memdb.IndexSchema{
    64  			"id": &memdb.IndexSchema{
    65  				Name:         "id",
    66  				AllowMissing: false,
    67  				Unique:       true,
    68  				Indexer: &memdb.CompoundIndex{
    69  					Indexes: []memdb.Indexer{
    70  						&memdb.StringFieldIndex{
    71  							Field:     "Node",
    72  							Lowercase: true,
    73  						},
    74  						&memdb.StringFieldIndex{
    75  							Field:     "ServiceID",
    76  							Lowercase: true,
    77  						},
    78  					},
    79  				},
    80  			},
    81  			"node": &memdb.IndexSchema{
    82  				Name:         "node",
    83  				AllowMissing: false,
    84  				Unique:       false,
    85  				Indexer: &memdb.StringFieldIndex{
    86  					Field:     "Node",
    87  					Lowercase: true,
    88  				},
    89  			},
    90  			"service": &memdb.IndexSchema{
    91  				Name:         "service",
    92  				AllowMissing: true,
    93  				Unique:       false,
    94  				Indexer: &memdb.StringFieldIndex{
    95  					Field:     "ServiceName",
    96  					Lowercase: true,
    97  				},
    98  			},
    99  			"connect": &memdb.IndexSchema{
   100  				Name:         "connect",
   101  				AllowMissing: true,
   102  				Unique:       false,
   103  				Indexer:      &IndexConnectService{},
   104  			},
   105  		},
   106  	}
   107  }
   108  
   109  // checksTableSchema returns a new table schema used for storing and indexing
   110  // health check information. Health checks have a number of different attributes
   111  // we want to filter by, so this table is a bit more complex.
   112  func checksTableSchema() *memdb.TableSchema {
   113  	return &memdb.TableSchema{
   114  		Name: "checks",
   115  		Indexes: map[string]*memdb.IndexSchema{
   116  			"id": &memdb.IndexSchema{
   117  				Name:         "id",
   118  				AllowMissing: false,
   119  				Unique:       true,
   120  				Indexer: &memdb.CompoundIndex{
   121  					Indexes: []memdb.Indexer{
   122  						&memdb.StringFieldIndex{
   123  							Field:     "Node",
   124  							Lowercase: true,
   125  						},
   126  						&memdb.StringFieldIndex{
   127  							Field:     "CheckID",
   128  							Lowercase: true,
   129  						},
   130  					},
   131  				},
   132  			},
   133  			"status": &memdb.IndexSchema{
   134  				Name:         "status",
   135  				AllowMissing: false,
   136  				Unique:       false,
   137  				Indexer: &memdb.StringFieldIndex{
   138  					Field:     "Status",
   139  					Lowercase: false,
   140  				},
   141  			},
   142  			"service": &memdb.IndexSchema{
   143  				Name:         "service",
   144  				AllowMissing: true,
   145  				Unique:       false,
   146  				Indexer: &memdb.StringFieldIndex{
   147  					Field:     "ServiceName",
   148  					Lowercase: true,
   149  				},
   150  			},
   151  			"node": &memdb.IndexSchema{
   152  				Name:         "node",
   153  				AllowMissing: true,
   154  				Unique:       false,
   155  				Indexer: &memdb.StringFieldIndex{
   156  					Field:     "Node",
   157  					Lowercase: true,
   158  				},
   159  			},
   160  			"node_service_check": &memdb.IndexSchema{
   161  				Name:         "node_service_check",
   162  				AllowMissing: true,
   163  				Unique:       false,
   164  				Indexer: &memdb.CompoundIndex{
   165  					Indexes: []memdb.Indexer{
   166  						&memdb.StringFieldIndex{
   167  							Field:     "Node",
   168  							Lowercase: true,
   169  						},
   170  						&memdb.FieldSetIndex{
   171  							Field: "ServiceID",
   172  						},
   173  					},
   174  				},
   175  			},
   176  			"node_service": &memdb.IndexSchema{
   177  				Name:         "node_service",
   178  				AllowMissing: true,
   179  				Unique:       false,
   180  				Indexer: &memdb.CompoundIndex{
   181  					Indexes: []memdb.Indexer{
   182  						&memdb.StringFieldIndex{
   183  							Field:     "Node",
   184  							Lowercase: true,
   185  						},
   186  						&memdb.StringFieldIndex{
   187  							Field:     "ServiceID",
   188  							Lowercase: true,
   189  						},
   190  					},
   191  				},
   192  			},
   193  		},
   194  	}
   195  }
   196  
   197  func init() {
   198  	registerSchema(nodesTableSchema)
   199  	registerSchema(servicesTableSchema)
   200  	registerSchema(checksTableSchema)
   201  }
   202  
   203  const (
   204  	// minUUIDLookupLen is used as a minimum length of a node name required before
   205  	// we test to see if the name is actually a UUID and perform an ID-based node
   206  	// lookup.
   207  	minUUIDLookupLen = 2
   208  )
   209  
   210  func resizeNodeLookupKey(s string) string {
   211  	l := len(s)
   212  
   213  	if l%2 != 0 {
   214  		return s[0 : l-1]
   215  	}
   216  
   217  	return s
   218  }
   219  
   220  // Nodes is used to pull the full list of nodes for use during snapshots.
   221  func (s *Snapshot) Nodes() (memdb.ResultIterator, error) {
   222  	iter, err := s.tx.Get("nodes", "id")
   223  	if err != nil {
   224  		return nil, err
   225  	}
   226  	return iter, nil
   227  }
   228  
   229  // Services is used to pull the full list of services for a given node for use
   230  // during snapshots.
   231  func (s *Snapshot) Services(node string) (memdb.ResultIterator, error) {
   232  	iter, err := s.tx.Get("services", "node", node)
   233  	if err != nil {
   234  		return nil, err
   235  	}
   236  	return iter, nil
   237  }
   238  
   239  // Checks is used to pull the full list of checks for a given node for use
   240  // during snapshots.
   241  func (s *Snapshot) Checks(node string) (memdb.ResultIterator, error) {
   242  	iter, err := s.tx.Get("checks", "node", node)
   243  	if err != nil {
   244  		return nil, err
   245  	}
   246  	return iter, nil
   247  }
   248  
   249  // Registration is used to make sure a node, service, and check registration is
   250  // performed within a single transaction to avoid race conditions on state
   251  // updates.
   252  func (s *Restore) Registration(idx uint64, req *structs.RegisterRequest) error {
   253  	if err := s.store.ensureRegistrationTxn(s.tx, idx, req); err != nil {
   254  		return err
   255  	}
   256  	return nil
   257  }
   258  
   259  // EnsureRegistration is used to make sure a node, service, and check
   260  // registration is performed within a single transaction to avoid race
   261  // conditions on state updates.
   262  func (s *Store) EnsureRegistration(idx uint64, req *structs.RegisterRequest) error {
   263  	tx := s.db.Txn(true)
   264  	defer tx.Abort()
   265  
   266  	if err := s.ensureRegistrationTxn(tx, idx, req); err != nil {
   267  		return err
   268  	}
   269  
   270  	tx.Commit()
   271  	return nil
   272  }
   273  
   274  func (s *Store) ensureCheckIfNodeMatches(tx *memdb.Txn, idx uint64, node string, check *structs.HealthCheck) error {
   275  	if check.Node != node {
   276  		return fmt.Errorf("check node %q does not match node %q",
   277  			check.Node, node)
   278  	}
   279  	if err := s.ensureCheckTxn(tx, idx, check); err != nil {
   280  		return fmt.Errorf("failed inserting check: %s on node %q", err, check.Node)
   281  	}
   282  	return nil
   283  }
   284  
   285  // ensureRegistrationTxn is used to make sure a node, service, and check
   286  // registration is performed within a single transaction to avoid race
   287  // conditions on state updates.
   288  func (s *Store) ensureRegistrationTxn(tx *memdb.Txn, idx uint64, req *structs.RegisterRequest) error {
   289  	// Create a node structure.
   290  	node := &structs.Node{
   291  		ID:              req.ID,
   292  		Node:            req.Node,
   293  		Address:         req.Address,
   294  		Datacenter:      req.Datacenter,
   295  		TaggedAddresses: req.TaggedAddresses,
   296  		Meta:            req.NodeMeta,
   297  	}
   298  
   299  	// Since this gets called for all node operations (service and check
   300  	// updates) and churn on the node itself is basically none after the
   301  	// node updates itself the first time, it's worth seeing if we need to
   302  	// modify the node at all so we prevent watch churn and useless writes
   303  	// and modify index bumps on the node.
   304  	{
   305  		existing, err := tx.First("nodes", "id", node.Node)
   306  		if err != nil {
   307  			return fmt.Errorf("node lookup failed: %s", err)
   308  		}
   309  		if existing == nil || req.ChangesNode(existing.(*structs.Node)) {
   310  			if err := s.ensureNodeTxn(tx, idx, node); err != nil {
   311  				return fmt.Errorf("failed inserting node: %s", err)
   312  			}
   313  		}
   314  	}
   315  
   316  	// Add the service, if any. We perform a similar check as we do for the
   317  	// node info above to make sure we actually need to update the service
   318  	// definition in order to prevent useless churn if nothing has changed.
   319  	if req.Service != nil {
   320  		existing, err := tx.First("services", "id", req.Node, req.Service.ID)
   321  		if err != nil {
   322  			return fmt.Errorf("failed service lookup: %s", err)
   323  		}
   324  		if existing == nil || !(existing.(*structs.ServiceNode).ToNodeService()).IsSame(req.Service) {
   325  			if err := s.ensureServiceTxn(tx, idx, req.Node, req.Service); err != nil {
   326  				return fmt.Errorf("failed inserting service: %s", err)
   327  
   328  			}
   329  		}
   330  	}
   331  
   332  	// Add the checks, if any.
   333  	if req.Check != nil {
   334  		if err := s.ensureCheckIfNodeMatches(tx, idx, req.Node, req.Check); err != nil {
   335  			return err
   336  		}
   337  	}
   338  	for _, check := range req.Checks {
   339  		if err := s.ensureCheckIfNodeMatches(tx, idx, req.Node, check); err != nil {
   340  			return err
   341  		}
   342  	}
   343  
   344  	return nil
   345  }
   346  
   347  // EnsureNode is used to upsert node registration or modification.
   348  func (s *Store) EnsureNode(idx uint64, node *structs.Node) error {
   349  	tx := s.db.Txn(true)
   350  	defer tx.Abort()
   351  
   352  	// Call the node upsert
   353  	if err := s.ensureNodeTxn(tx, idx, node); err != nil {
   354  		return err
   355  	}
   356  
   357  	tx.Commit()
   358  	return nil
   359  }
   360  
   361  // ensureNoNodeWithSimilarNameTxn checks that no other node has conflict in its name
   362  // If allowClashWithoutID then, getting a conflict on another node without ID will be allowed
   363  func (s *Store) ensureNoNodeWithSimilarNameTxn(tx *memdb.Txn, node *structs.Node, allowClashWithoutID bool) error {
   364  	// Retrieve all of the nodes
   365  	enodes, err := tx.Get("nodes", "id")
   366  	if err != nil {
   367  		return fmt.Errorf("Cannot lookup all nodes: %s", err)
   368  	}
   369  	for nodeIt := enodes.Next(); nodeIt != nil; nodeIt = enodes.Next() {
   370  		enode := nodeIt.(*structs.Node)
   371  		if strings.EqualFold(node.Node, enode.Node) && node.ID != enode.ID {
   372  			if !(enode.ID == "" && allowClashWithoutID) {
   373  				return fmt.Errorf("Node name %s is reserved by node %s with name %s", node.Node, enode.ID, enode.Node)
   374  			}
   375  		}
   376  	}
   377  	return nil
   378  }
   379  
   380  // ensureNodeCASTxn updates a node only if the existing index matches the given index.
   381  // Returns a bool indicating if a write happened and any error.
   382  func (s *Store) ensureNodeCASTxn(tx *memdb.Txn, idx uint64, node *structs.Node) (bool, error) {
   383  	// Retrieve the existing entry.
   384  	existing, err := getNodeTxn(tx, node.Node)
   385  	if err != nil {
   386  		return false, err
   387  	}
   388  
   389  	// Check if the we should do the set. A ModifyIndex of 0 means that
   390  	// we are doing a set-if-not-exists.
   391  	if node.ModifyIndex == 0 && existing != nil {
   392  		return false, nil
   393  	}
   394  	if node.ModifyIndex != 0 && existing == nil {
   395  		return false, nil
   396  	}
   397  	if existing != nil && node.ModifyIndex != 0 && node.ModifyIndex != existing.ModifyIndex {
   398  		return false, nil
   399  	}
   400  
   401  	// Perform the update.
   402  	if err := s.ensureNodeTxn(tx, idx, node); err != nil {
   403  		return false, err
   404  	}
   405  
   406  	return true, nil
   407  }
   408  
   409  // ensureNodeTxn is the inner function called to actually create a node
   410  // registration or modify an existing one in the state store. It allows
   411  // passing in a memdb transaction so it may be part of a larger txn.
   412  func (s *Store) ensureNodeTxn(tx *memdb.Txn, idx uint64, node *structs.Node) error {
   413  	// See if there's an existing node with this UUID, and make sure the
   414  	// name is the same.
   415  	var n *structs.Node
   416  	if node.ID != "" {
   417  		existing, err := getNodeIDTxn(tx, node.ID)
   418  		if err != nil {
   419  			return fmt.Errorf("node lookup failed: %s", err)
   420  		}
   421  		if existing != nil {
   422  			n = existing
   423  			if n.Node != node.Node {
   424  				// Lets first get all nodes and check whether name do match, we do not allow clash on nodes without ID
   425  				dupNameError := s.ensureNoNodeWithSimilarNameTxn(tx, node, false)
   426  				if dupNameError != nil {
   427  					return fmt.Errorf("Error while renaming Node ID: %q: %s", node.ID, dupNameError)
   428  				}
   429  				// We are actually renaming a node, remove its reference first
   430  				err := s.deleteNodeTxn(tx, idx, n.Node)
   431  				if err != nil {
   432  					return fmt.Errorf("Error while renaming Node ID: %q from %s to %s",
   433  						node.ID, n.Node, node.Node)
   434  				}
   435  			}
   436  		} else {
   437  			// We allow to "steal" another node name that would have no ID
   438  			// It basically means that we allow upgrading a node without ID and add the ID
   439  			dupNameError := s.ensureNoNodeWithSimilarNameTxn(tx, node, true)
   440  			if dupNameError != nil {
   441  				return fmt.Errorf("Error while renaming Node ID: %q: %s", node.ID, dupNameError)
   442  			}
   443  		}
   444  	}
   445  	// TODO: else Node.ID == "" should be forbidden in future Consul releases
   446  	// See https://github.com/hashicorp/consul/pull/3983 for context
   447  
   448  	// Check for an existing node by name to support nodes with no IDs.
   449  	if n == nil {
   450  		existing, err := tx.First("nodes", "id", node.Node)
   451  		if err != nil {
   452  			return fmt.Errorf("node name lookup failed: %s", err)
   453  		}
   454  
   455  		if existing != nil {
   456  			n = existing.(*structs.Node)
   457  		}
   458  		// WARNING, for compatibility reasons with tests, we do not check
   459  		// for case insensitive matches, which may lead to DB corruption
   460  		// See https://github.com/hashicorp/consul/pull/3983 for context
   461  	}
   462  
   463  	// Get the indexes.
   464  	if n != nil {
   465  		node.CreateIndex = n.CreateIndex
   466  		node.ModifyIndex = n.ModifyIndex
   467  		// We do not need to update anything
   468  		if node.IsSame(n) {
   469  			return nil
   470  		}
   471  		node.ModifyIndex = idx
   472  	} else {
   473  		node.CreateIndex = idx
   474  		node.ModifyIndex = idx
   475  	}
   476  
   477  	// Insert the node and update the index.
   478  	if err := tx.Insert("nodes", node); err != nil {
   479  		return fmt.Errorf("failed inserting node: %s", err)
   480  	}
   481  	if err := tx.Insert("index", &IndexEntry{"nodes", idx}); err != nil {
   482  		return fmt.Errorf("failed updating index: %s", err)
   483  	}
   484  	// Update the node's service indexes as the node information is included
   485  	// in health queries and we would otherwise miss node updates in some cases
   486  	// for those queries.
   487  	if err := s.updateAllServiceIndexesOfNode(tx, idx, node.Node); err != nil {
   488  		return fmt.Errorf("failed updating index: %s", err)
   489  	}
   490  
   491  	return nil
   492  }
   493  
   494  // GetNode is used to retrieve a node registration by node name ID.
   495  func (s *Store) GetNode(id string) (uint64, *structs.Node, error) {
   496  	tx := s.db.Txn(false)
   497  	defer tx.Abort()
   498  
   499  	// Get the table index.
   500  	idx := maxIndexTxn(tx, "nodes")
   501  
   502  	// Retrieve the node from the state store
   503  	node, err := getNodeTxn(tx, id)
   504  	if err != nil {
   505  		return 0, nil, fmt.Errorf("node lookup failed: %s", err)
   506  	}
   507  	return idx, node, nil
   508  }
   509  
   510  func getNodeTxn(tx *memdb.Txn, nodeName string) (*structs.Node, error) {
   511  	node, err := tx.First("nodes", "id", nodeName)
   512  	if err != nil {
   513  		return nil, fmt.Errorf("node lookup failed: %s", err)
   514  	}
   515  	if node != nil {
   516  		return node.(*structs.Node), nil
   517  	}
   518  	return nil, nil
   519  }
   520  
   521  func getNodeIDTxn(tx *memdb.Txn, id types.NodeID) (*structs.Node, error) {
   522  	strnode := string(id)
   523  	uuidValue, err := uuid.ParseUUID(strnode)
   524  	if err != nil {
   525  		return nil, fmt.Errorf("node lookup by ID failed, wrong UUID: %v for '%s'", err, strnode)
   526  	}
   527  
   528  	node, err := tx.First("nodes", "uuid", uuidValue)
   529  	if err != nil {
   530  		return nil, fmt.Errorf("node lookup by ID failed: %s", err)
   531  	}
   532  	if node != nil {
   533  		return node.(*structs.Node), nil
   534  	}
   535  	return nil, nil
   536  }
   537  
   538  // GetNodeID is used to retrieve a node registration by node ID.
   539  func (s *Store) GetNodeID(id types.NodeID) (uint64, *structs.Node, error) {
   540  	tx := s.db.Txn(false)
   541  	defer tx.Abort()
   542  
   543  	// Get the table index.
   544  	idx := maxIndexTxn(tx, "nodes")
   545  
   546  	// Retrieve the node from the state store
   547  	node, err := getNodeIDTxn(tx, id)
   548  	return idx, node, err
   549  }
   550  
   551  // Nodes is used to return all of the known nodes.
   552  func (s *Store) Nodes(ws memdb.WatchSet) (uint64, structs.Nodes, error) {
   553  	tx := s.db.Txn(false)
   554  	defer tx.Abort()
   555  
   556  	// Get the table index.
   557  	idx := maxIndexTxn(tx, "nodes")
   558  
   559  	// Retrieve all of the nodes
   560  	nodes, err := tx.Get("nodes", "id")
   561  	if err != nil {
   562  		return 0, nil, fmt.Errorf("failed nodes lookup: %s", err)
   563  	}
   564  	ws.Add(nodes.WatchCh())
   565  
   566  	// Create and return the nodes list.
   567  	var results structs.Nodes
   568  	for node := nodes.Next(); node != nil; node = nodes.Next() {
   569  		results = append(results, node.(*structs.Node))
   570  	}
   571  	return idx, results, nil
   572  }
   573  
   574  // NodesByMeta is used to return all nodes with the given metadata key/value pairs.
   575  func (s *Store) NodesByMeta(ws memdb.WatchSet, filters map[string]string) (uint64, structs.Nodes, error) {
   576  	tx := s.db.Txn(false)
   577  	defer tx.Abort()
   578  
   579  	// Get the table index.
   580  	idx := maxIndexTxn(tx, "nodes")
   581  
   582  	// Retrieve all of the nodes
   583  	var args []interface{}
   584  	for key, value := range filters {
   585  		args = append(args, key, value)
   586  		break
   587  	}
   588  	nodes, err := tx.Get("nodes", "meta", args...)
   589  	if err != nil {
   590  		return 0, nil, fmt.Errorf("failed nodes lookup: %s", err)
   591  	}
   592  	ws.Add(nodes.WatchCh())
   593  
   594  	// Create and return the nodes list.
   595  	var results structs.Nodes
   596  	for node := nodes.Next(); node != nil; node = nodes.Next() {
   597  		n := node.(*structs.Node)
   598  		if len(filters) <= 1 || structs.SatisfiesMetaFilters(n.Meta, filters) {
   599  			results = append(results, n)
   600  		}
   601  	}
   602  	return idx, results, nil
   603  }
   604  
   605  // DeleteNode is used to delete a given node by its ID.
   606  func (s *Store) DeleteNode(idx uint64, nodeName string) error {
   607  	tx := s.db.Txn(true)
   608  	defer tx.Abort()
   609  
   610  	// Call the node deletion.
   611  	if err := s.deleteNodeTxn(tx, idx, nodeName); err != nil {
   612  		return err
   613  	}
   614  
   615  	tx.Commit()
   616  	return nil
   617  }
   618  
   619  // deleteNodeCASTxn is used to try doing a node delete operation with a given
   620  // raft index. If the CAS index specified is not equal to the last observed index for
   621  // the given check, then the call is a noop, otherwise a normal check delete is invoked.
   622  func (s *Store) deleteNodeCASTxn(tx *memdb.Txn, idx, cidx uint64, nodeName string) (bool, error) {
   623  	// Look up the node.
   624  	node, err := getNodeTxn(tx, nodeName)
   625  	if err != nil {
   626  		return false, err
   627  	}
   628  	if node == nil {
   629  		return false, nil
   630  	}
   631  
   632  	// If the existing index does not match the provided CAS
   633  	// index arg, then we shouldn't update anything and can safely
   634  	// return early here.
   635  	if node.ModifyIndex != cidx {
   636  		return false, nil
   637  	}
   638  
   639  	// Call the actual deletion if the above passed.
   640  	if err := s.deleteNodeTxn(tx, idx, nodeName); err != nil {
   641  		return false, err
   642  	}
   643  
   644  	return true, nil
   645  }
   646  
   647  // deleteNodeTxn is the inner method used for removing a node from
   648  // the store within a given transaction.
   649  func (s *Store) deleteNodeTxn(tx *memdb.Txn, idx uint64, nodeName string) error {
   650  	// Look up the node.
   651  	node, err := tx.First("nodes", "id", nodeName)
   652  	if err != nil {
   653  		return fmt.Errorf("node lookup failed: %s", err)
   654  	}
   655  	if node == nil {
   656  		return nil
   657  	}
   658  
   659  	// Delete all services associated with the node and update the service index.
   660  	services, err := tx.Get("services", "node", nodeName)
   661  	if err != nil {
   662  		return fmt.Errorf("failed service lookup: %s", err)
   663  	}
   664  	var sids []string
   665  	for service := services.Next(); service != nil; service = services.Next() {
   666  		svc := service.(*structs.ServiceNode)
   667  		sids = append(sids, svc.ServiceID)
   668  		if err := tx.Insert("index", &IndexEntry{serviceIndexName(svc.ServiceName), idx}); err != nil {
   669  			return fmt.Errorf("failed updating index: %s", err)
   670  		}
   671  	}
   672  
   673  	// Do the delete in a separate loop so we don't trash the iterator.
   674  	for _, sid := range sids {
   675  		if err := s.deleteServiceTxn(tx, idx, nodeName, sid); err != nil {
   676  			return err
   677  		}
   678  	}
   679  
   680  	// Delete all checks associated with the node. This will invalidate
   681  	// sessions as necessary.
   682  	checks, err := tx.Get("checks", "node", nodeName)
   683  	if err != nil {
   684  		return fmt.Errorf("failed check lookup: %s", err)
   685  	}
   686  	var cids []types.CheckID
   687  	for check := checks.Next(); check != nil; check = checks.Next() {
   688  		cids = append(cids, check.(*structs.HealthCheck).CheckID)
   689  	}
   690  
   691  	// Do the delete in a separate loop so we don't trash the iterator.
   692  	for _, cid := range cids {
   693  		if err := s.deleteCheckTxn(tx, idx, nodeName, cid); err != nil {
   694  			return err
   695  		}
   696  	}
   697  
   698  	// Delete any coordinates associated with this node.
   699  	coords, err := tx.Get("coordinates", "node", nodeName)
   700  	if err != nil {
   701  		return fmt.Errorf("failed coordinate lookup: %s", err)
   702  	}
   703  	for coord := coords.Next(); coord != nil; coord = coords.Next() {
   704  		if err := tx.Delete("coordinates", coord); err != nil {
   705  			return fmt.Errorf("failed deleting coordinate: %s", err)
   706  		}
   707  		if err := tx.Insert("index", &IndexEntry{"coordinates", idx}); err != nil {
   708  			return fmt.Errorf("failed updating index: %s", err)
   709  		}
   710  	}
   711  
   712  	// Delete the node and update the index.
   713  	if err := tx.Delete("nodes", node); err != nil {
   714  		return fmt.Errorf("failed deleting node: %s", err)
   715  	}
   716  	if err := tx.Insert("index", &IndexEntry{"nodes", idx}); err != nil {
   717  		return fmt.Errorf("failed updating index: %s", err)
   718  	}
   719  
   720  	// Invalidate any sessions for this node.
   721  	sessions, err := tx.Get("sessions", "node", nodeName)
   722  	if err != nil {
   723  		return fmt.Errorf("failed session lookup: %s", err)
   724  	}
   725  	var ids []string
   726  	for sess := sessions.Next(); sess != nil; sess = sessions.Next() {
   727  		ids = append(ids, sess.(*structs.Session).ID)
   728  	}
   729  
   730  	// Do the delete in a separate loop so we don't trash the iterator.
   731  	for _, id := range ids {
   732  		if err := s.deleteSessionTxn(tx, idx, id); err != nil {
   733  			return fmt.Errorf("failed session delete: %s", err)
   734  		}
   735  	}
   736  
   737  	return nil
   738  }
   739  
   740  // EnsureService is called to upsert creation of a given NodeService.
   741  func (s *Store) EnsureService(idx uint64, node string, svc *structs.NodeService) error {
   742  	tx := s.db.Txn(true)
   743  	defer tx.Abort()
   744  
   745  	// Call the service registration upsert
   746  	if err := s.ensureServiceTxn(tx, idx, node, svc); err != nil {
   747  		return err
   748  	}
   749  
   750  	tx.Commit()
   751  	return nil
   752  }
   753  
   754  // ensureServiceCASTxn updates a service only if the existing index matches the given index.
   755  // Returns a bool indicating if a write happened and any error.
   756  func (s *Store) ensureServiceCASTxn(tx *memdb.Txn, idx uint64, node string, svc *structs.NodeService) (bool, error) {
   757  	// Retrieve the existing service.
   758  	existing, err := tx.First("services", "id", node, svc.ID)
   759  	if err != nil {
   760  		return false, fmt.Errorf("failed service lookup: %s", err)
   761  	}
   762  
   763  	// Check if the we should do the set. A ModifyIndex of 0 means that
   764  	// we are doing a set-if-not-exists.
   765  	if svc.ModifyIndex == 0 && existing != nil {
   766  		return false, nil
   767  	}
   768  	if svc.ModifyIndex != 0 && existing == nil {
   769  		return false, nil
   770  	}
   771  	e, ok := existing.(*structs.Node)
   772  	if ok && svc.ModifyIndex != 0 && svc.ModifyIndex != e.ModifyIndex {
   773  		return false, nil
   774  	}
   775  
   776  	// Perform the update.
   777  	if err := s.ensureServiceTxn(tx, idx, node, svc); err != nil {
   778  		return false, err
   779  	}
   780  
   781  	return true, nil
   782  }
   783  
   784  // ensureServiceTxn is used to upsert a service registration within an
   785  // existing memdb transaction.
   786  func (s *Store) ensureServiceTxn(tx *memdb.Txn, idx uint64, node string, svc *structs.NodeService) error {
   787  	// Check for existing service
   788  	existing, err := tx.First("services", "id", node, svc.ID)
   789  	if err != nil {
   790  		return fmt.Errorf("failed service lookup: %s", err)
   791  	}
   792  
   793  	if err = structs.ValidateMetadata(svc.Meta, false); err != nil {
   794  		return fmt.Errorf("Invalid Service Meta for node %s and serviceID %s: %v", node, svc.ID, err)
   795  	}
   796  	// Create the service node entry and populate the indexes. Note that
   797  	// conversion doesn't populate any of the node-specific information.
   798  	// That's always populated when we read from the state store.
   799  	entry := svc.ToServiceNode(node)
   800  	// Get the node
   801  	n, err := tx.First("nodes", "id", node)
   802  	if err != nil {
   803  		return fmt.Errorf("failed node lookup: %s", err)
   804  	}
   805  	if n == nil {
   806  		return ErrMissingNode
   807  	}
   808  	if existing != nil {
   809  		serviceNode := existing.(*structs.ServiceNode)
   810  		entry.CreateIndex = serviceNode.CreateIndex
   811  		entry.ModifyIndex = serviceNode.ModifyIndex
   812  		// We cannot return here because: we want to keep existing behavior (ex: failed node lookup -> ErrMissingNode)
   813  		// It might be modified in future, but it requires changing many unit tests
   814  		// Enforcing saving the entry also ensures that if we add default values in .ToServiceNode()
   815  		// those values will be saved even if node is not really modified for a while.
   816  		if entry.IsSameService(serviceNode) {
   817  			return nil
   818  		}
   819  	} else {
   820  		entry.CreateIndex = idx
   821  	}
   822  	entry.ModifyIndex = idx
   823  
   824  	// Insert the service and update the index
   825  	if err := tx.Insert("services", entry); err != nil {
   826  		return fmt.Errorf("failed inserting service: %s", err)
   827  	}
   828  	if err := tx.Insert("index", &IndexEntry{"services", idx}); err != nil {
   829  		return fmt.Errorf("failed updating index: %s", err)
   830  	}
   831  	if err := tx.Insert("index", &IndexEntry{serviceIndexName(svc.Service), idx}); err != nil {
   832  		return fmt.Errorf("failed updating index: %s", err)
   833  	}
   834  
   835  	return nil
   836  }
   837  
   838  // Services returns all services along with a list of associated tags.
   839  func (s *Store) Services(ws memdb.WatchSet) (uint64, structs.Services, error) {
   840  	tx := s.db.Txn(false)
   841  	defer tx.Abort()
   842  
   843  	// Get the table index.
   844  	idx := maxIndexTxn(tx, "services")
   845  
   846  	// List all the services.
   847  	services, err := tx.Get("services", "id")
   848  	if err != nil {
   849  		return 0, nil, fmt.Errorf("failed querying services: %s", err)
   850  	}
   851  	ws.Add(services.WatchCh())
   852  
   853  	// Rip through the services and enumerate them and their unique set of
   854  	// tags.
   855  	unique := make(map[string]map[string]struct{})
   856  	for service := services.Next(); service != nil; service = services.Next() {
   857  		svc := service.(*structs.ServiceNode)
   858  		tags, ok := unique[svc.ServiceName]
   859  		if !ok {
   860  			unique[svc.ServiceName] = make(map[string]struct{})
   861  			tags = unique[svc.ServiceName]
   862  		}
   863  		for _, tag := range svc.ServiceTags {
   864  			tags[tag] = struct{}{}
   865  		}
   866  	}
   867  
   868  	// Generate the output structure.
   869  	var results = make(structs.Services)
   870  	for service, tags := range unique {
   871  		results[service] = make([]string, 0)
   872  		for tag := range tags {
   873  			results[service] = append(results[service], tag)
   874  		}
   875  	}
   876  	return idx, results, nil
   877  }
   878  
   879  // ServicesByNodeMeta returns all services, filtered by the given node metadata.
   880  func (s *Store) ServicesByNodeMeta(ws memdb.WatchSet, filters map[string]string) (uint64, structs.Services, error) {
   881  	tx := s.db.Txn(false)
   882  	defer tx.Abort()
   883  
   884  	// Get the table index.
   885  	idx := maxIndexTxn(tx, "services", "nodes")
   886  
   887  	// Retrieve all of the nodes with the meta k/v pair
   888  	var args []interface{}
   889  	for key, value := range filters {
   890  		args = append(args, key, value)
   891  		break
   892  	}
   893  	nodes, err := tx.Get("nodes", "meta", args...)
   894  	if err != nil {
   895  		return 0, nil, fmt.Errorf("failed nodes lookup: %s", err)
   896  	}
   897  	ws.Add(nodes.WatchCh())
   898  
   899  	// We don't want to track an unlimited number of services, so we pull a
   900  	// top-level watch to use as a fallback.
   901  	allServices, err := tx.Get("services", "id")
   902  	if err != nil {
   903  		return 0, nil, fmt.Errorf("failed services lookup: %s", err)
   904  	}
   905  	allServicesCh := allServices.WatchCh()
   906  
   907  	// Populate the services map
   908  	unique := make(map[string]map[string]struct{})
   909  	for node := nodes.Next(); node != nil; node = nodes.Next() {
   910  		n := node.(*structs.Node)
   911  		if len(filters) > 1 && !structs.SatisfiesMetaFilters(n.Meta, filters) {
   912  			continue
   913  		}
   914  
   915  		// List all the services on the node
   916  		services, err := tx.Get("services", "node", n.Node)
   917  		if err != nil {
   918  			return 0, nil, fmt.Errorf("failed querying services: %s", err)
   919  		}
   920  		ws.AddWithLimit(watchLimit, services.WatchCh(), allServicesCh)
   921  
   922  		// Rip through the services and enumerate them and their unique set of
   923  		// tags.
   924  		for service := services.Next(); service != nil; service = services.Next() {
   925  			svc := service.(*structs.ServiceNode)
   926  			tags, ok := unique[svc.ServiceName]
   927  			if !ok {
   928  				unique[svc.ServiceName] = make(map[string]struct{})
   929  				tags = unique[svc.ServiceName]
   930  			}
   931  			for _, tag := range svc.ServiceTags {
   932  				tags[tag] = struct{}{}
   933  			}
   934  		}
   935  	}
   936  
   937  	// Generate the output structure.
   938  	var results = make(structs.Services)
   939  	for service, tags := range unique {
   940  		results[service] = make([]string, 0)
   941  		for tag := range tags {
   942  			results[service] = append(results[service], tag)
   943  		}
   944  	}
   945  	return idx, results, nil
   946  }
   947  
   948  // maxIndexForService return the maximum Raft Index for a service
   949  // If the index is not set for the service, it will return the missing
   950  // service index.
   951  // The service_last_extinction is set to the last raft index when a service
   952  // was unregistered (or 0 if no services were ever unregistered). This
   953  // allows blocking queries to
   954  //   * return when the last instance of a service is removed
   955  //   * block until an instance for this service is available, or another
   956  //     service is unregistered.
   957  func maxIndexForService(tx *memdb.Txn, serviceName string, serviceExists, checks bool) uint64 {
   958  	idx, _ := maxIndexAndWatchChForService(tx, serviceName, serviceExists, checks)
   959  	return idx
   960  }
   961  
   962  // maxIndexAndWatchChForService return the maximum Raft Index for a service. If
   963  // the index is not set for the service, it will return the missing service
   964  // index. The service_last_extinction is set to the last raft index when a
   965  // service was unregistered (or 0 if no services were ever unregistered). This
   966  // allows blocking queries to
   967  //   * return when the last instance of a service is removed
   968  //   * block until an instance for this service is available, or another
   969  //     service is unregistered.
   970  //
   971  // It also _may_ return a watch chan to add to a WatchSet. It will only return
   972  // one if the service exists, and has a service index. If it doesn't then nil is
   973  // returned for the chan. This allows for blocking watchers to _only_ watch this
   974  // one chan in the common case, falling back to watching all touched MemDB
   975  // indexes in more complicated cases.
   976  func maxIndexAndWatchChForService(tx *memdb.Txn, serviceName string, serviceExists, checks bool) (uint64, <-chan struct{}) {
   977  	if !serviceExists {
   978  		res, err := tx.First("index", "id", serviceLastExtinctionIndexName)
   979  		if missingIdx, ok := res.(*IndexEntry); ok && err == nil {
   980  			// Not safe to only watch the extinction index as it's not updated when
   981  			// new instances come along so return nil watchCh.
   982  			return missingIdx.Value, nil
   983  		}
   984  	}
   985  
   986  	ch, res, err := tx.FirstWatch("index", "id", serviceIndexName(serviceName))
   987  	if idx, ok := res.(*IndexEntry); ok && err == nil {
   988  		return idx.Value, ch
   989  	}
   990  	if checks {
   991  		return maxIndexTxn(tx, "nodes", "services", "checks"), nil
   992  	}
   993  
   994  	return maxIndexTxn(tx, "nodes", "services"), nil
   995  }
   996  
   997  // ConnectServiceNodes returns the nodes associated with a Connect
   998  // compatible destination for the given service name. This will include
   999  // both proxies and native integrations.
  1000  func (s *Store) ConnectServiceNodes(ws memdb.WatchSet, serviceName string) (uint64, structs.ServiceNodes, error) {
  1001  	return s.serviceNodes(ws, serviceName, true)
  1002  }
  1003  
  1004  // ServiceNodes returns the nodes associated with a given service name.
  1005  func (s *Store) ServiceNodes(ws memdb.WatchSet, serviceName string) (uint64, structs.ServiceNodes, error) {
  1006  	return s.serviceNodes(ws, serviceName, false)
  1007  }
  1008  
  1009  func (s *Store) serviceNodes(ws memdb.WatchSet, serviceName string, connect bool) (uint64, structs.ServiceNodes, error) {
  1010  	tx := s.db.Txn(false)
  1011  	defer tx.Abort()
  1012  
  1013  	// Function for lookup
  1014  	var f func() (memdb.ResultIterator, error)
  1015  	if !connect {
  1016  		f = func() (memdb.ResultIterator, error) {
  1017  			return tx.Get("services", "service", serviceName)
  1018  		}
  1019  	} else {
  1020  		f = func() (memdb.ResultIterator, error) {
  1021  			return tx.Get("services", "connect", serviceName)
  1022  		}
  1023  	}
  1024  
  1025  	// List all the services.
  1026  	services, err := f()
  1027  	if err != nil {
  1028  		return 0, nil, fmt.Errorf("failed service lookup: %s", err)
  1029  	}
  1030  	ws.Add(services.WatchCh())
  1031  
  1032  	var results structs.ServiceNodes
  1033  	for service := services.Next(); service != nil; service = services.Next() {
  1034  		results = append(results, service.(*structs.ServiceNode))
  1035  	}
  1036  
  1037  	// Fill in the node details.
  1038  	results, err = s.parseServiceNodes(tx, ws, results)
  1039  	if err != nil {
  1040  		return 0, nil, fmt.Errorf("failed parsing service nodes: %s", err)
  1041  	}
  1042  
  1043  	// Get the table index.
  1044  	idx := maxIndexForService(tx, serviceName, len(results) > 0, false)
  1045  
  1046  	return idx, results, nil
  1047  }
  1048  
  1049  // ServiceTagNodes returns the nodes associated with a given service, filtering
  1050  // out services that don't contain the given tags.
  1051  func (s *Store) ServiceTagNodes(ws memdb.WatchSet, service string, tags []string) (uint64, structs.ServiceNodes, error) {
  1052  	tx := s.db.Txn(false)
  1053  	defer tx.Abort()
  1054  
  1055  	// List all the services.
  1056  	services, err := tx.Get("services", "service", service)
  1057  	if err != nil {
  1058  		return 0, nil, fmt.Errorf("failed service lookup: %s", err)
  1059  	}
  1060  	ws.Add(services.WatchCh())
  1061  
  1062  	// Gather all the services and apply the tag filter.
  1063  	serviceExists := false
  1064  	var results structs.ServiceNodes
  1065  	for service := services.Next(); service != nil; service = services.Next() {
  1066  		svc := service.(*structs.ServiceNode)
  1067  		serviceExists = true
  1068  		if !serviceTagsFilter(svc, tags) {
  1069  			results = append(results, svc)
  1070  		}
  1071  	}
  1072  
  1073  	// Fill in the node details.
  1074  	results, err = s.parseServiceNodes(tx, ws, results)
  1075  	if err != nil {
  1076  		return 0, nil, fmt.Errorf("failed parsing service nodes: %s", err)
  1077  	}
  1078  	// Get the table index.
  1079  	idx := maxIndexForService(tx, service, serviceExists, false)
  1080  
  1081  	return idx, results, nil
  1082  }
  1083  
  1084  // serviceTagFilter returns true (should filter) if the given service node
  1085  // doesn't contain the given tag.
  1086  func serviceTagFilter(sn *structs.ServiceNode, tag string) bool {
  1087  	tag = strings.ToLower(tag)
  1088  
  1089  	// Look for the lower cased version of the tag.
  1090  	for _, t := range sn.ServiceTags {
  1091  		if strings.ToLower(t) == tag {
  1092  			return false
  1093  		}
  1094  	}
  1095  
  1096  	// If we didn't hit the tag above then we should filter.
  1097  	return true
  1098  }
  1099  
  1100  // serviceTagsFilter returns true (should filter) if the given service node
  1101  // doesn't contain the given set of tags.
  1102  func serviceTagsFilter(sn *structs.ServiceNode, tags []string) bool {
  1103  	for _, tag := range tags {
  1104  		if serviceTagFilter(sn, tag) {
  1105  			// If any one of the expected tags was not found, filter the service
  1106  			return true
  1107  		}
  1108  	}
  1109  
  1110  	// If all tags were found, don't filter the service
  1111  	return false
  1112  }
  1113  
  1114  // ServiceAddressNodes returns the nodes associated with a given service, filtering
  1115  // out services that don't match the given serviceAddress
  1116  func (s *Store) ServiceAddressNodes(ws memdb.WatchSet, address string) (uint64, structs.ServiceNodes, error) {
  1117  	tx := s.db.Txn(false)
  1118  	defer tx.Abort()
  1119  
  1120  	// List all the services.
  1121  	services, err := tx.Get("services", "id")
  1122  	if err != nil {
  1123  		return 0, nil, fmt.Errorf("failed service lookup: %s", err)
  1124  	}
  1125  	ws.Add(services.WatchCh())
  1126  
  1127  	// Gather all the services and apply the tag filter.
  1128  	var results structs.ServiceNodes
  1129  	for service := services.Next(); service != nil; service = services.Next() {
  1130  		svc := service.(*structs.ServiceNode)
  1131  		if svc.ServiceAddress == address {
  1132  			results = append(results, svc)
  1133  		}
  1134  	}
  1135  
  1136  	// Fill in the node details.
  1137  	results, err = s.parseServiceNodes(tx, ws, results)
  1138  	if err != nil {
  1139  		return 0, nil, fmt.Errorf("failed parsing service nodes: %s", err)
  1140  	}
  1141  	return 0, results, nil
  1142  }
  1143  
  1144  // parseServiceNodes iterates over a services query and fills in the node details,
  1145  // returning a ServiceNodes slice.
  1146  func (s *Store) parseServiceNodes(tx *memdb.Txn, ws memdb.WatchSet, services structs.ServiceNodes) (structs.ServiceNodes, error) {
  1147  	// We don't want to track an unlimited number of nodes, so we pull a
  1148  	// top-level watch to use as a fallback.
  1149  	allNodes, err := tx.Get("nodes", "id")
  1150  	if err != nil {
  1151  		return nil, fmt.Errorf("failed nodes lookup: %s", err)
  1152  	}
  1153  	allNodesCh := allNodes.WatchCh()
  1154  
  1155  	// Fill in the node data for each service instance.
  1156  	var results structs.ServiceNodes
  1157  	for _, sn := range services {
  1158  		// Note that we have to clone here because we don't want to
  1159  		// modify the node-related fields on the object in the database,
  1160  		// which is what we are referencing.
  1161  		s := sn.PartialClone()
  1162  
  1163  		// Grab the corresponding node record.
  1164  		watchCh, n, err := tx.FirstWatch("nodes", "id", sn.Node)
  1165  		if err != nil {
  1166  			return nil, fmt.Errorf("failed node lookup: %s", err)
  1167  		}
  1168  		ws.AddWithLimit(watchLimit, watchCh, allNodesCh)
  1169  
  1170  		// Populate the node-related fields. The tagged addresses may be
  1171  		// used by agents to perform address translation if they are
  1172  		// configured to do that.
  1173  		node := n.(*structs.Node)
  1174  		s.ID = node.ID
  1175  		s.Address = node.Address
  1176  		s.Datacenter = node.Datacenter
  1177  		s.TaggedAddresses = node.TaggedAddresses
  1178  		s.NodeMeta = node.Meta
  1179  
  1180  		results = append(results, s)
  1181  	}
  1182  	return results, nil
  1183  }
  1184  
  1185  // NodeService is used to retrieve a specific service associated with the given
  1186  // node.
  1187  func (s *Store) NodeService(nodeName string, serviceID string) (uint64, *structs.NodeService, error) {
  1188  	tx := s.db.Txn(false)
  1189  	defer tx.Abort()
  1190  
  1191  	// Get the table index.
  1192  	idx := maxIndexTxn(tx, "services")
  1193  
  1194  	// Query the service
  1195  	service, err := s.getNodeServiceTxn(tx, nodeName, serviceID)
  1196  	if err != nil {
  1197  		return 0, nil, fmt.Errorf("failed querying service for node %q: %s", nodeName, err)
  1198  	}
  1199  
  1200  	return idx, service, nil
  1201  }
  1202  
  1203  func (s *Store) getNodeServiceTxn(tx *memdb.Txn, nodeName, serviceID string) (*structs.NodeService, error) {
  1204  	// Query the service
  1205  	service, err := tx.First("services", "id", nodeName, serviceID)
  1206  	if err != nil {
  1207  		return nil, fmt.Errorf("failed querying service for node %q: %s", nodeName, err)
  1208  	}
  1209  
  1210  	if service != nil {
  1211  		return service.(*structs.ServiceNode).ToNodeService(), nil
  1212  	}
  1213  
  1214  	return nil, nil
  1215  }
  1216  
  1217  // NodeServices is used to query service registrations by node name or UUID.
  1218  func (s *Store) NodeServices(ws memdb.WatchSet, nodeNameOrID string) (uint64, *structs.NodeServices, error) {
  1219  	tx := s.db.Txn(false)
  1220  	defer tx.Abort()
  1221  
  1222  	// Get the table index.
  1223  	idx := maxIndexTxn(tx, "nodes", "services")
  1224  
  1225  	// Query the node by node name
  1226  	watchCh, n, err := tx.FirstWatch("nodes", "id", nodeNameOrID)
  1227  	if err != nil {
  1228  		return 0, nil, fmt.Errorf("node lookup failed: %s", err)
  1229  	}
  1230  
  1231  	if n != nil {
  1232  		ws.Add(watchCh)
  1233  	} else {
  1234  		if len(nodeNameOrID) < minUUIDLookupLen {
  1235  			ws.Add(watchCh)
  1236  			return 0, nil, nil
  1237  		}
  1238  
  1239  		// Attempt to lookup the node by its node ID
  1240  		iter, err := tx.Get("nodes", "uuid_prefix", resizeNodeLookupKey(nodeNameOrID))
  1241  		if err != nil {
  1242  			ws.Add(watchCh)
  1243  			// TODO(sean@): We could/should log an error re: the uuid_prefix lookup
  1244  			// failing once a logger has been introduced to the catalog.
  1245  			return 0, nil, nil
  1246  		}
  1247  
  1248  		n = iter.Next()
  1249  		if n == nil {
  1250  			// No nodes matched, even with the Node ID: add a watch on the node name.
  1251  			ws.Add(watchCh)
  1252  			return 0, nil, nil
  1253  		}
  1254  
  1255  		idWatchCh := iter.WatchCh()
  1256  		if iter.Next() != nil {
  1257  			// More than one match present: Watch on the node name channel and return
  1258  			// an empty result (node lookups can not be ambiguous).
  1259  			ws.Add(watchCh)
  1260  			return 0, nil, nil
  1261  		}
  1262  
  1263  		ws.Add(idWatchCh)
  1264  	}
  1265  
  1266  	node := n.(*structs.Node)
  1267  	nodeName := node.Node
  1268  
  1269  	// Read all of the services
  1270  	services, err := tx.Get("services", "node", nodeName)
  1271  	if err != nil {
  1272  		return 0, nil, fmt.Errorf("failed querying services for node %q: %s", nodeName, err)
  1273  	}
  1274  	ws.Add(services.WatchCh())
  1275  
  1276  	// Initialize the node services struct
  1277  	ns := &structs.NodeServices{
  1278  		Node:     node,
  1279  		Services: make(map[string]*structs.NodeService),
  1280  	}
  1281  
  1282  	// Add all of the services to the map.
  1283  	for service := services.Next(); service != nil; service = services.Next() {
  1284  		svc := service.(*structs.ServiceNode).ToNodeService()
  1285  		ns.Services[svc.ID] = svc
  1286  	}
  1287  
  1288  	return idx, ns, nil
  1289  }
  1290  
  1291  // DeleteService is used to delete a given service associated with a node.
  1292  func (s *Store) DeleteService(idx uint64, nodeName, serviceID string) error {
  1293  	tx := s.db.Txn(true)
  1294  	defer tx.Abort()
  1295  
  1296  	// Call the service deletion
  1297  	if err := s.deleteServiceTxn(tx, idx, nodeName, serviceID); err != nil {
  1298  		return err
  1299  	}
  1300  
  1301  	tx.Commit()
  1302  	return nil
  1303  }
  1304  
  1305  func serviceIndexName(name string) string {
  1306  	return fmt.Sprintf("service.%s", name)
  1307  }
  1308  
  1309  // deleteServiceCASTxn is used to try doing a service delete operation with a given
  1310  // raft index. If the CAS index specified is not equal to the last observed index for
  1311  // the given service, then the call is a noop, otherwise a normal delete is invoked.
  1312  func (s *Store) deleteServiceCASTxn(tx *memdb.Txn, idx, cidx uint64, nodeName, serviceID string) (bool, error) {
  1313  	// Look up the service.
  1314  	service, err := s.getNodeServiceTxn(tx, nodeName, serviceID)
  1315  	if err != nil {
  1316  		return false, fmt.Errorf("service lookup failed: %s", err)
  1317  	}
  1318  	if service == nil {
  1319  		return false, nil
  1320  	}
  1321  
  1322  	// If the existing index does not match the provided CAS
  1323  	// index arg, then we shouldn't update anything and can safely
  1324  	// return early here.
  1325  	if service.ModifyIndex != cidx {
  1326  		return false, nil
  1327  	}
  1328  
  1329  	// Call the actual deletion if the above passed.
  1330  	if err := s.deleteServiceTxn(tx, idx, nodeName, serviceID); err != nil {
  1331  		return false, err
  1332  	}
  1333  
  1334  	return true, nil
  1335  }
  1336  
  1337  // deleteServiceTxn is the inner method called to remove a service
  1338  // registration within an existing transaction.
  1339  func (s *Store) deleteServiceTxn(tx *memdb.Txn, idx uint64, nodeName, serviceID string) error {
  1340  	// Look up the service.
  1341  	service, err := tx.First("services", "id", nodeName, serviceID)
  1342  	if err != nil {
  1343  		return fmt.Errorf("failed service lookup: %s", err)
  1344  	}
  1345  	if service == nil {
  1346  		return nil
  1347  	}
  1348  
  1349  	// Delete any checks associated with the service. This will invalidate
  1350  	// sessions as necessary.
  1351  	checks, err := tx.Get("checks", "node_service", nodeName, serviceID)
  1352  	if err != nil {
  1353  		return fmt.Errorf("failed service check lookup: %s", err)
  1354  	}
  1355  	var cids []types.CheckID
  1356  	for check := checks.Next(); check != nil; check = checks.Next() {
  1357  		cids = append(cids, check.(*structs.HealthCheck).CheckID)
  1358  	}
  1359  
  1360  	// Do the delete in a separate loop so we don't trash the iterator.
  1361  	for _, cid := range cids {
  1362  		if err := s.deleteCheckTxn(tx, idx, nodeName, cid); err != nil {
  1363  			return err
  1364  		}
  1365  	}
  1366  
  1367  	// Update the index.
  1368  	if err := tx.Insert("index", &IndexEntry{"checks", idx}); err != nil {
  1369  		return fmt.Errorf("failed updating index: %s", err)
  1370  	}
  1371  
  1372  	// Delete the service and update the index
  1373  	if err := tx.Delete("services", service); err != nil {
  1374  		return fmt.Errorf("failed deleting service: %s", err)
  1375  	}
  1376  	if err := tx.Insert("index", &IndexEntry{"services", idx}); err != nil {
  1377  		return fmt.Errorf("failed updating index: %s", err)
  1378  	}
  1379  
  1380  	svc := service.(*structs.ServiceNode)
  1381  	if remainingService, err := tx.First("services", "service", svc.ServiceName); err == nil {
  1382  		if remainingService != nil {
  1383  			// We have at least one remaining service, update the index
  1384  			if err := tx.Insert("index", &IndexEntry{serviceIndexName(svc.ServiceName), idx}); err != nil {
  1385  				return fmt.Errorf("failed updating index: %s", err)
  1386  			}
  1387  		} else {
  1388  			// There are no more service instances, cleanup the service.<serviceName> index
  1389  			serviceIndex, err := tx.First("index", "id", serviceIndexName(svc.ServiceName))
  1390  			if err == nil && serviceIndex != nil {
  1391  				// we found service.<serviceName> index, garbage collect it
  1392  				if errW := tx.Delete("index", serviceIndex); errW != nil {
  1393  					return fmt.Errorf("[FAILED] deleting serviceIndex %s: %s", svc.ServiceName, err)
  1394  				}
  1395  			}
  1396  
  1397  			if err := tx.Insert("index", &IndexEntry{serviceLastExtinctionIndexName, idx}); err != nil {
  1398  				return fmt.Errorf("failed updating missing service index: %s", err)
  1399  			}
  1400  
  1401  		}
  1402  	} else {
  1403  		return fmt.Errorf("Could not find any service %s: %s", svc.ServiceName, err)
  1404  	}
  1405  	return nil
  1406  }
  1407  
  1408  // EnsureCheck is used to store a check registration in the db.
  1409  func (s *Store) EnsureCheck(idx uint64, hc *structs.HealthCheck) error {
  1410  	tx := s.db.Txn(true)
  1411  	defer tx.Abort()
  1412  
  1413  	// Call the check registration
  1414  	if err := s.ensureCheckTxn(tx, idx, hc); err != nil {
  1415  		return err
  1416  	}
  1417  
  1418  	tx.Commit()
  1419  	return nil
  1420  }
  1421  
  1422  // updateAllServiceIndexesOfNode updates the Raft index of all the services associated with this node
  1423  func (s *Store) updateAllServiceIndexesOfNode(tx *memdb.Txn, idx uint64, nodeID string) error {
  1424  	services, err := tx.Get("services", "node", nodeID)
  1425  	if err != nil {
  1426  		return fmt.Errorf("failed updating services for node %s: %s", nodeID, err)
  1427  	}
  1428  	for service := services.Next(); service != nil; service = services.Next() {
  1429  		svc := service.(*structs.ServiceNode).ToNodeService()
  1430  		if err := tx.Insert("index", &IndexEntry{serviceIndexName(svc.Service), idx}); err != nil {
  1431  			return fmt.Errorf("failed updating index: %s", err)
  1432  		}
  1433  	}
  1434  	return nil
  1435  }
  1436  
  1437  // ensureCheckCASTxn updates a check only if the existing index matches the given index.
  1438  // Returns a bool indicating if a write happened and any error.
  1439  func (s *Store) ensureCheckCASTxn(tx *memdb.Txn, idx uint64, hc *structs.HealthCheck) (bool, error) {
  1440  	// Retrieve the existing entry.
  1441  	_, existing, err := s.getNodeCheckTxn(tx, hc.Node, hc.CheckID)
  1442  	if err != nil {
  1443  		return false, fmt.Errorf("failed health check lookup: %s", err)
  1444  	}
  1445  
  1446  	// Check if the we should do the set. A ModifyIndex of 0 means that
  1447  	// we are doing a set-if-not-exists.
  1448  	if hc.ModifyIndex == 0 && existing != nil {
  1449  		return false, nil
  1450  	}
  1451  	if hc.ModifyIndex != 0 && existing == nil {
  1452  		return false, nil
  1453  	}
  1454  	if existing != nil && hc.ModifyIndex != 0 && hc.ModifyIndex != existing.ModifyIndex {
  1455  		return false, nil
  1456  	}
  1457  
  1458  	// Perform the update.
  1459  	if err := s.ensureCheckTxn(tx, idx, hc); err != nil {
  1460  		return false, err
  1461  	}
  1462  
  1463  	return true, nil
  1464  }
  1465  
  1466  // ensureCheckTransaction is used as the inner method to handle inserting
  1467  // a health check into the state store. It ensures safety against inserting
  1468  // checks with no matching node or service.
  1469  func (s *Store) ensureCheckTxn(tx *memdb.Txn, idx uint64, hc *structs.HealthCheck) error {
  1470  	// Check if we have an existing health check
  1471  	existing, err := tx.First("checks", "id", hc.Node, string(hc.CheckID))
  1472  	if err != nil {
  1473  		return fmt.Errorf("failed health check lookup: %s", err)
  1474  	}
  1475  
  1476  	// Set the indexes
  1477  	if existing != nil {
  1478  		existingCheck := existing.(*structs.HealthCheck)
  1479  		hc.CreateIndex = existingCheck.CreateIndex
  1480  		hc.ModifyIndex = existingCheck.ModifyIndex
  1481  	} else {
  1482  		hc.CreateIndex = idx
  1483  		hc.ModifyIndex = idx
  1484  	}
  1485  
  1486  	// Use the default check status if none was provided
  1487  	if hc.Status == "" {
  1488  		hc.Status = api.HealthCritical
  1489  	}
  1490  
  1491  	// Get the node
  1492  	node, err := tx.First("nodes", "id", hc.Node)
  1493  	if err != nil {
  1494  		return fmt.Errorf("failed node lookup: %s", err)
  1495  	}
  1496  	if node == nil {
  1497  		return ErrMissingNode
  1498  	}
  1499  
  1500  	modified := true
  1501  	// If the check is associated with a service, check that we have
  1502  	// a registration for the service.
  1503  	if hc.ServiceID != "" {
  1504  		service, err := tx.First("services", "id", hc.Node, hc.ServiceID)
  1505  		if err != nil {
  1506  			return fmt.Errorf("failed service lookup: %s", err)
  1507  		}
  1508  		if service == nil {
  1509  			return ErrMissingService
  1510  		}
  1511  
  1512  		// Copy in the service name and tags
  1513  		svc := service.(*structs.ServiceNode)
  1514  		hc.ServiceName = svc.ServiceName
  1515  		hc.ServiceTags = svc.ServiceTags
  1516  		if existing != nil && existing.(*structs.HealthCheck).IsSame(hc) {
  1517  			modified = false
  1518  		} else {
  1519  			// Check has been modified, we trigger a index service change
  1520  			if err = tx.Insert("index", &IndexEntry{serviceIndexName(svc.ServiceName), idx}); err != nil {
  1521  				return fmt.Errorf("failed updating index: %s", err)
  1522  			}
  1523  		}
  1524  	} else {
  1525  		if existing != nil && existing.(*structs.HealthCheck).IsSame(hc) {
  1526  			modified = false
  1527  		} else {
  1528  			// Since the check has been modified, it impacts all services of node
  1529  			// Update the status for all the services associated with this node
  1530  			err = s.updateAllServiceIndexesOfNode(tx, idx, hc.Node)
  1531  			if err != nil {
  1532  				return err
  1533  			}
  1534  		}
  1535  	}
  1536  
  1537  	// Delete any sessions for this check if the health is critical.
  1538  	if hc.Status == api.HealthCritical {
  1539  		mappings, err := tx.Get("session_checks", "node_check", hc.Node, string(hc.CheckID))
  1540  		if err != nil {
  1541  			return fmt.Errorf("failed session checks lookup: %s", err)
  1542  		}
  1543  
  1544  		var ids []string
  1545  		for mapping := mappings.Next(); mapping != nil; mapping = mappings.Next() {
  1546  			ids = append(ids, mapping.(*sessionCheck).Session)
  1547  		}
  1548  
  1549  		// Delete the session in a separate loop so we don't trash the
  1550  		// iterator.
  1551  		for _, id := range ids {
  1552  			if err := s.deleteSessionTxn(tx, idx, id); err != nil {
  1553  				return fmt.Errorf("failed deleting session: %s", err)
  1554  			}
  1555  		}
  1556  	}
  1557  	if modified {
  1558  		// We update the modify index, ONLY if something has changed, thus
  1559  		// With constant output, no change is seen when watching a service
  1560  		// With huge number of nodes where anti-entropy updates continuously
  1561  		// the checks, but not the values within the check
  1562  		hc.ModifyIndex = idx
  1563  	}
  1564  
  1565  	// Persist the check registration in the db.
  1566  	if err := tx.Insert("checks", hc); err != nil {
  1567  		return fmt.Errorf("failed inserting check: %s", err)
  1568  	}
  1569  	if err := tx.Insert("index", &IndexEntry{"checks", idx}); err != nil {
  1570  		return fmt.Errorf("failed updating index: %s", err)
  1571  	}
  1572  
  1573  	return nil
  1574  }
  1575  
  1576  // NodeCheck is used to retrieve a specific check associated with the given
  1577  // node.
  1578  func (s *Store) NodeCheck(nodeName string, checkID types.CheckID) (uint64, *structs.HealthCheck, error) {
  1579  	tx := s.db.Txn(false)
  1580  	defer tx.Abort()
  1581  
  1582  	return s.getNodeCheckTxn(tx, nodeName, checkID)
  1583  }
  1584  
  1585  // nodeCheckTxn is used as the inner method to handle reading a health check
  1586  // from the state store.
  1587  func (s *Store) getNodeCheckTxn(tx *memdb.Txn, nodeName string, checkID types.CheckID) (uint64, *structs.HealthCheck, error) {
  1588  	// Get the table index.
  1589  	idx := maxIndexTxn(tx, "checks")
  1590  
  1591  	// Return the check.
  1592  	check, err := tx.First("checks", "id", nodeName, string(checkID))
  1593  	if err != nil {
  1594  		return 0, nil, fmt.Errorf("failed check lookup: %s", err)
  1595  	}
  1596  
  1597  	if check != nil {
  1598  		return idx, check.(*structs.HealthCheck), nil
  1599  	}
  1600  	return idx, nil, nil
  1601  }
  1602  
  1603  // NodeChecks is used to retrieve checks associated with the
  1604  // given node from the state store.
  1605  func (s *Store) NodeChecks(ws memdb.WatchSet, nodeName string) (uint64, structs.HealthChecks, error) {
  1606  	tx := s.db.Txn(false)
  1607  	defer tx.Abort()
  1608  
  1609  	// Get the table index.
  1610  	idx := maxIndexTxn(tx, "checks")
  1611  
  1612  	// Return the checks.
  1613  	iter, err := tx.Get("checks", "node", nodeName)
  1614  	if err != nil {
  1615  		return 0, nil, fmt.Errorf("failed check lookup: %s", err)
  1616  	}
  1617  	ws.Add(iter.WatchCh())
  1618  
  1619  	var results structs.HealthChecks
  1620  	for check := iter.Next(); check != nil; check = iter.Next() {
  1621  		results = append(results, check.(*structs.HealthCheck))
  1622  	}
  1623  	return idx, results, nil
  1624  }
  1625  
  1626  // ServiceChecks is used to get all checks associated with a
  1627  // given service ID. The query is performed against a service
  1628  // _name_ instead of a service ID.
  1629  func (s *Store) ServiceChecks(ws memdb.WatchSet, serviceName string) (uint64, structs.HealthChecks, error) {
  1630  	tx := s.db.Txn(false)
  1631  	defer tx.Abort()
  1632  
  1633  	// Get the table index.
  1634  	idx := maxIndexTxn(tx, "checks")
  1635  
  1636  	// Return the checks.
  1637  	iter, err := tx.Get("checks", "service", serviceName)
  1638  	if err != nil {
  1639  		return 0, nil, fmt.Errorf("failed check lookup: %s", err)
  1640  	}
  1641  	ws.Add(iter.WatchCh())
  1642  
  1643  	var results structs.HealthChecks
  1644  	for check := iter.Next(); check != nil; check = iter.Next() {
  1645  		results = append(results, check.(*structs.HealthCheck))
  1646  	}
  1647  	return idx, results, nil
  1648  }
  1649  
  1650  // ServiceChecksByNodeMeta is used to get all checks associated with a
  1651  // given service ID, filtered by the given node metadata values. The query
  1652  // is performed against a service _name_ instead of a service ID.
  1653  func (s *Store) ServiceChecksByNodeMeta(ws memdb.WatchSet, serviceName string,
  1654  	filters map[string]string) (uint64, structs.HealthChecks, error) {
  1655  
  1656  	tx := s.db.Txn(false)
  1657  	defer tx.Abort()
  1658  
  1659  	// Get the table index.
  1660  	idx := maxIndexForService(tx, serviceName, true, true)
  1661  	// Return the checks.
  1662  	iter, err := tx.Get("checks", "service", serviceName)
  1663  	if err != nil {
  1664  		return 0, nil, fmt.Errorf("failed check lookup: %s", err)
  1665  	}
  1666  	ws.Add(iter.WatchCh())
  1667  
  1668  	return s.parseChecksByNodeMeta(tx, ws, idx, iter, filters)
  1669  }
  1670  
  1671  // ChecksInState is used to query the state store for all checks
  1672  // which are in the provided state.
  1673  func (s *Store) ChecksInState(ws memdb.WatchSet, state string) (uint64, structs.HealthChecks, error) {
  1674  	tx := s.db.Txn(false)
  1675  	defer tx.Abort()
  1676  
  1677  	// Get the table index.
  1678  	idx := maxIndexTxn(tx, "checks")
  1679  
  1680  	// Query all checks if HealthAny is passed, otherwise use the index.
  1681  	var iter memdb.ResultIterator
  1682  	var err error
  1683  	if state == api.HealthAny {
  1684  		iter, err = tx.Get("checks", "status")
  1685  	} else {
  1686  		iter, err = tx.Get("checks", "status", state)
  1687  	}
  1688  	if err != nil {
  1689  		return 0, nil, fmt.Errorf("failed check lookup: %s", err)
  1690  	}
  1691  	ws.Add(iter.WatchCh())
  1692  
  1693  	var results structs.HealthChecks
  1694  	for check := iter.Next(); check != nil; check = iter.Next() {
  1695  		results = append(results, check.(*structs.HealthCheck))
  1696  	}
  1697  	return idx, results, nil
  1698  }
  1699  
  1700  // ChecksInStateByNodeMeta is used to query the state store for all checks
  1701  // which are in the provided state, filtered by the given node metadata values.
  1702  func (s *Store) ChecksInStateByNodeMeta(ws memdb.WatchSet, state string, filters map[string]string) (uint64, structs.HealthChecks, error) {
  1703  	tx := s.db.Txn(false)
  1704  	defer tx.Abort()
  1705  
  1706  	// Get the table index.
  1707  	idx := maxIndexTxn(tx, "nodes", "checks")
  1708  
  1709  	// Query all checks if HealthAny is passed, otherwise use the index.
  1710  	var iter memdb.ResultIterator
  1711  	var err error
  1712  	if state == api.HealthAny {
  1713  		iter, err = tx.Get("checks", "status")
  1714  		if err != nil {
  1715  			return 0, nil, fmt.Errorf("failed check lookup: %s", err)
  1716  		}
  1717  	} else {
  1718  		iter, err = tx.Get("checks", "status", state)
  1719  		if err != nil {
  1720  			return 0, nil, fmt.Errorf("failed check lookup: %s", err)
  1721  		}
  1722  	}
  1723  	ws.Add(iter.WatchCh())
  1724  
  1725  	return s.parseChecksByNodeMeta(tx, ws, idx, iter, filters)
  1726  }
  1727  
  1728  // parseChecksByNodeMeta is a helper function used to deduplicate some
  1729  // repetitive code for returning health checks filtered by node metadata fields.
  1730  func (s *Store) parseChecksByNodeMeta(tx *memdb.Txn, ws memdb.WatchSet,
  1731  	idx uint64, iter memdb.ResultIterator, filters map[string]string) (uint64, structs.HealthChecks, error) {
  1732  
  1733  	// We don't want to track an unlimited number of nodes, so we pull a
  1734  	// top-level watch to use as a fallback.
  1735  	allNodes, err := tx.Get("nodes", "id")
  1736  	if err != nil {
  1737  		return 0, nil, fmt.Errorf("failed nodes lookup: %s", err)
  1738  	}
  1739  	allNodesCh := allNodes.WatchCh()
  1740  
  1741  	// Only take results for nodes that satisfy the node metadata filters.
  1742  	var results structs.HealthChecks
  1743  	for check := iter.Next(); check != nil; check = iter.Next() {
  1744  		healthCheck := check.(*structs.HealthCheck)
  1745  		watchCh, node, err := tx.FirstWatch("nodes", "id", healthCheck.Node)
  1746  		if err != nil {
  1747  			return 0, nil, fmt.Errorf("failed node lookup: %s", err)
  1748  		}
  1749  		if node == nil {
  1750  			return 0, nil, ErrMissingNode
  1751  		}
  1752  
  1753  		// Add even the filtered nodes so we wake up if the node metadata
  1754  		// changes.
  1755  		ws.AddWithLimit(watchLimit, watchCh, allNodesCh)
  1756  		if structs.SatisfiesMetaFilters(node.(*structs.Node).Meta, filters) {
  1757  			results = append(results, healthCheck)
  1758  		}
  1759  	}
  1760  	return idx, results, nil
  1761  }
  1762  
  1763  // DeleteCheck is used to delete a health check registration.
  1764  func (s *Store) DeleteCheck(idx uint64, node string, checkID types.CheckID) error {
  1765  	tx := s.db.Txn(true)
  1766  	defer tx.Abort()
  1767  
  1768  	// Call the check deletion
  1769  	if err := s.deleteCheckTxn(tx, idx, node, checkID); err != nil {
  1770  		return err
  1771  	}
  1772  
  1773  	tx.Commit()
  1774  	return nil
  1775  }
  1776  
  1777  // deleteCheckCASTxn is used to try doing a check delete operation with a given
  1778  // raft index. If the CAS index specified is not equal to the last observed index for
  1779  // the given check, then the call is a noop, otherwise a normal check delete is invoked.
  1780  func (s *Store) deleteCheckCASTxn(tx *memdb.Txn, idx, cidx uint64, node string, checkID types.CheckID) (bool, error) {
  1781  	// Try to retrieve the existing health check.
  1782  	_, hc, err := s.getNodeCheckTxn(tx, node, checkID)
  1783  	if err != nil {
  1784  		return false, fmt.Errorf("check lookup failed: %s", err)
  1785  	}
  1786  	if hc == nil {
  1787  		return false, nil
  1788  	}
  1789  
  1790  	// If the existing index does not match the provided CAS
  1791  	// index arg, then we shouldn't update anything and can safely
  1792  	// return early here.
  1793  	if hc.ModifyIndex != cidx {
  1794  		return false, nil
  1795  	}
  1796  
  1797  	// Call the actual deletion if the above passed.
  1798  	if err := s.deleteCheckTxn(tx, idx, node, checkID); err != nil {
  1799  		return false, err
  1800  	}
  1801  
  1802  	return true, nil
  1803  }
  1804  
  1805  // deleteCheckTxn is the inner method used to call a health
  1806  // check deletion within an existing transaction.
  1807  func (s *Store) deleteCheckTxn(tx *memdb.Txn, idx uint64, node string, checkID types.CheckID) error {
  1808  	// Try to retrieve the existing health check.
  1809  	hc, err := tx.First("checks", "id", node, string(checkID))
  1810  	if err != nil {
  1811  		return fmt.Errorf("check lookup failed: %s", err)
  1812  	}
  1813  	if hc == nil {
  1814  		return nil
  1815  	}
  1816  	existing := hc.(*structs.HealthCheck)
  1817  	if existing != nil {
  1818  		// When no service is linked to this service, update all services of node
  1819  		if existing.ServiceID != "" {
  1820  			if err = tx.Insert("index", &IndexEntry{serviceIndexName(existing.ServiceName), idx}); err != nil {
  1821  				return fmt.Errorf("failed updating index: %s", err)
  1822  			}
  1823  		} else {
  1824  			err = s.updateAllServiceIndexesOfNode(tx, idx, existing.Node)
  1825  			if err != nil {
  1826  				return fmt.Errorf("Failed to update services linked to deleted healthcheck: %s", err)
  1827  			}
  1828  			if err := tx.Insert("index", &IndexEntry{"services", idx}); err != nil {
  1829  				return fmt.Errorf("failed updating index: %s", err)
  1830  			}
  1831  		}
  1832  	}
  1833  
  1834  	// Delete the check from the DB and update the index.
  1835  	if err := tx.Delete("checks", hc); err != nil {
  1836  		return fmt.Errorf("failed removing check: %s", err)
  1837  	}
  1838  	if err := tx.Insert("index", &IndexEntry{"checks", idx}); err != nil {
  1839  		return fmt.Errorf("failed updating index: %s", err)
  1840  	}
  1841  
  1842  	// Delete any sessions for this check.
  1843  	mappings, err := tx.Get("session_checks", "node_check", node, string(checkID))
  1844  	if err != nil {
  1845  		return fmt.Errorf("failed session checks lookup: %s", err)
  1846  	}
  1847  	var ids []string
  1848  	for mapping := mappings.Next(); mapping != nil; mapping = mappings.Next() {
  1849  		ids = append(ids, mapping.(*sessionCheck).Session)
  1850  	}
  1851  
  1852  	// Do the delete in a separate loop so we don't trash the iterator.
  1853  	for _, id := range ids {
  1854  		if err := s.deleteSessionTxn(tx, idx, id); err != nil {
  1855  			return fmt.Errorf("failed deleting session: %s", err)
  1856  		}
  1857  	}
  1858  
  1859  	return nil
  1860  }
  1861  
  1862  // CheckServiceNodes is used to query all nodes and checks for a given service.
  1863  func (s *Store) CheckServiceNodes(ws memdb.WatchSet, serviceName string) (uint64, structs.CheckServiceNodes, error) {
  1864  	return s.checkServiceNodes(ws, serviceName, false)
  1865  }
  1866  
  1867  // CheckConnectServiceNodes is used to query all nodes and checks for Connect
  1868  // compatible endpoints for a given service.
  1869  func (s *Store) CheckConnectServiceNodes(ws memdb.WatchSet, serviceName string) (uint64, structs.CheckServiceNodes, error) {
  1870  	return s.checkServiceNodes(ws, serviceName, true)
  1871  }
  1872  
  1873  func (s *Store) checkServiceNodes(ws memdb.WatchSet, serviceName string, connect bool) (uint64, structs.CheckServiceNodes, error) {
  1874  	tx := s.db.Txn(false)
  1875  	defer tx.Abort()
  1876  
  1877  	// Function for lookup
  1878  	var f func() (memdb.ResultIterator, error)
  1879  	if !connect {
  1880  		f = func() (memdb.ResultIterator, error) {
  1881  			return tx.Get("services", "service", serviceName)
  1882  		}
  1883  	} else {
  1884  		f = func() (memdb.ResultIterator, error) {
  1885  			return tx.Get("services", "connect", serviceName)
  1886  		}
  1887  	}
  1888  
  1889  	// Query the state store for the service.
  1890  	iter, err := f()
  1891  	if err != nil {
  1892  		return 0, nil, fmt.Errorf("failed service lookup: %s", err)
  1893  	}
  1894  	// Note we decide if we want to watch this iterator or not down below. We need
  1895  	// to see if it returned anything first.
  1896  
  1897  	// Return the results.
  1898  	var results structs.ServiceNodes
  1899  	for service := iter.Next(); service != nil; service = iter.Next() {
  1900  		results = append(results, service.(*structs.ServiceNode))
  1901  	}
  1902  
  1903  	// Get the table index.
  1904  	idx, ch := maxIndexAndWatchChForService(tx, serviceName, len(results) > 0, true)
  1905  
  1906  	// Create a nil watchset to pass below, we'll only pass the real one if we
  1907  	// need to. Nil watchers are safe/allowed and saves some allocation too.
  1908  	var fallbackWS memdb.WatchSet
  1909  	if ch == nil {
  1910  		// There was no explicit channel returned that corresponds to the service
  1911  		// index. That means we need to fallback to watching everything we touch in
  1912  		// the DB as normal. We plumb the caller's watchset through (note it's a map
  1913  		// so this is a by-reference assignment.)
  1914  		fallbackWS = ws
  1915  		// We also need to watch the iterator from earlier too.
  1916  		fallbackWS.Add(iter.WatchCh())
  1917  	} else {
  1918  		// There was a valid service index, and non-empty result. In this case it is
  1919  		// sufficient just to watch the service index's chan since that _must_ be
  1920  		// written to if the result of this method is going to change. This saves us
  1921  		// watching potentially thousands of watch chans for large services which
  1922  		// may need many goroutines. It also avoid the performance cliff that is hit
  1923  		// when watchLimit is hit (~682 service instances). See
  1924  		// https://github.com/hashicorp/consul/issues/4984
  1925  		ws.Add(ch)
  1926  	}
  1927  
  1928  	return s.parseCheckServiceNodes(tx, fallbackWS, idx, serviceName, results, err)
  1929  }
  1930  
  1931  // CheckServiceTagNodes is used to query all nodes and checks for a given
  1932  // service, filtering out services that don't contain the given tag.
  1933  func (s *Store) CheckServiceTagNodes(ws memdb.WatchSet, serviceName string, tags []string) (uint64, structs.CheckServiceNodes, error) {
  1934  	tx := s.db.Txn(false)
  1935  	defer tx.Abort()
  1936  
  1937  	// Query the state store for the service.
  1938  	iter, err := tx.Get("services", "service", serviceName)
  1939  	if err != nil {
  1940  		return 0, nil, fmt.Errorf("failed service lookup: %s", err)
  1941  	}
  1942  	ws.Add(iter.WatchCh())
  1943  
  1944  	// Return the results, filtering by tag.
  1945  	serviceExists := false
  1946  	var results structs.ServiceNodes
  1947  	for service := iter.Next(); service != nil; service = iter.Next() {
  1948  		svc := service.(*structs.ServiceNode)
  1949  		serviceExists = true
  1950  		if !serviceTagsFilter(svc, tags) {
  1951  			results = append(results, svc)
  1952  		}
  1953  	}
  1954  
  1955  	// Get the table index.
  1956  	idx := maxIndexForService(tx, serviceName, serviceExists, true)
  1957  	return s.parseCheckServiceNodes(tx, ws, idx, serviceName, results, err)
  1958  }
  1959  
  1960  // parseCheckServiceNodes is used to parse through a given set of services,
  1961  // and query for an associated node and a set of checks. This is the inner
  1962  // method used to return a rich set of results from a more simple query.
  1963  func (s *Store) parseCheckServiceNodes(
  1964  	tx *memdb.Txn, ws memdb.WatchSet, idx uint64,
  1965  	serviceName string, services structs.ServiceNodes,
  1966  	err error) (uint64, structs.CheckServiceNodes, error) {
  1967  	if err != nil {
  1968  		return 0, nil, err
  1969  	}
  1970  
  1971  	// Special-case the zero return value to nil, since this ends up in
  1972  	// external APIs.
  1973  	if len(services) == 0 {
  1974  		return idx, nil, nil
  1975  	}
  1976  
  1977  	// We don't want to track an unlimited number of nodes, so we pull a
  1978  	// top-level watch to use as a fallback.
  1979  	allNodes, err := tx.Get("nodes", "id")
  1980  	if err != nil {
  1981  		return 0, nil, fmt.Errorf("failed nodes lookup: %s", err)
  1982  	}
  1983  	allNodesCh := allNodes.WatchCh()
  1984  
  1985  	// We need a similar fallback for checks. Since services need the
  1986  	// status of node + service-specific checks, we pull in a top-level
  1987  	// watch over all checks.
  1988  	allChecks, err := tx.Get("checks", "id")
  1989  	if err != nil {
  1990  		return 0, nil, fmt.Errorf("failed checks lookup: %s", err)
  1991  	}
  1992  	allChecksCh := allChecks.WatchCh()
  1993  
  1994  	results := make(structs.CheckServiceNodes, 0, len(services))
  1995  	for _, sn := range services {
  1996  		// Retrieve the node.
  1997  		watchCh, n, err := tx.FirstWatch("nodes", "id", sn.Node)
  1998  		if err != nil {
  1999  			return 0, nil, fmt.Errorf("failed node lookup: %s", err)
  2000  		}
  2001  		ws.AddWithLimit(watchLimit, watchCh, allNodesCh)
  2002  
  2003  		if n == nil {
  2004  			return 0, nil, ErrMissingNode
  2005  		}
  2006  		node := n.(*structs.Node)
  2007  
  2008  		// First add the node-level checks. These always apply to any
  2009  		// service on the node.
  2010  		var checks structs.HealthChecks
  2011  		iter, err := tx.Get("checks", "node_service_check", sn.Node, false)
  2012  		if err != nil {
  2013  			return 0, nil, err
  2014  		}
  2015  		ws.AddWithLimit(watchLimit, iter.WatchCh(), allChecksCh)
  2016  		for check := iter.Next(); check != nil; check = iter.Next() {
  2017  			checks = append(checks, check.(*structs.HealthCheck))
  2018  		}
  2019  
  2020  		// Now add the service-specific checks.
  2021  		iter, err = tx.Get("checks", "node_service", sn.Node, sn.ServiceID)
  2022  		if err != nil {
  2023  			return 0, nil, err
  2024  		}
  2025  		ws.AddWithLimit(watchLimit, iter.WatchCh(), allChecksCh)
  2026  		for check := iter.Next(); check != nil; check = iter.Next() {
  2027  			checks = append(checks, check.(*structs.HealthCheck))
  2028  		}
  2029  
  2030  		// Append to the results.
  2031  		results = append(results, structs.CheckServiceNode{
  2032  			Node:    node,
  2033  			Service: sn.ToNodeService(),
  2034  			Checks:  checks,
  2035  		})
  2036  	}
  2037  
  2038  	return idx, results, nil
  2039  }
  2040  
  2041  // NodeInfo is used to generate a dump of a single node. The dump includes
  2042  // all services and checks which are registered against the node.
  2043  func (s *Store) NodeInfo(ws memdb.WatchSet, node string) (uint64, structs.NodeDump, error) {
  2044  	tx := s.db.Txn(false)
  2045  	defer tx.Abort()
  2046  
  2047  	// Get the table index.
  2048  	idx := maxIndexTxn(tx, "nodes", "services", "checks")
  2049  
  2050  	// Query the node by the passed node
  2051  	nodes, err := tx.Get("nodes", "id", node)
  2052  	if err != nil {
  2053  		return 0, nil, fmt.Errorf("failed node lookup: %s", err)
  2054  	}
  2055  	ws.Add(nodes.WatchCh())
  2056  	return s.parseNodes(tx, ws, idx, nodes)
  2057  }
  2058  
  2059  // NodeDump is used to generate a dump of all nodes. This call is expensive
  2060  // as it has to query every node, service, and check. The response can also
  2061  // be quite large since there is currently no filtering applied.
  2062  func (s *Store) NodeDump(ws memdb.WatchSet) (uint64, structs.NodeDump, error) {
  2063  	tx := s.db.Txn(false)
  2064  	defer tx.Abort()
  2065  
  2066  	// Get the table index.
  2067  	idx := maxIndexTxn(tx, "nodes", "services", "checks")
  2068  
  2069  	// Fetch all of the registered nodes
  2070  	nodes, err := tx.Get("nodes", "id")
  2071  	if err != nil {
  2072  		return 0, nil, fmt.Errorf("failed node lookup: %s", err)
  2073  	}
  2074  	ws.Add(nodes.WatchCh())
  2075  	return s.parseNodes(tx, ws, idx, nodes)
  2076  }
  2077  
  2078  // parseNodes takes an iterator over a set of nodes and returns a struct
  2079  // containing the nodes along with all of their associated services
  2080  // and/or health checks.
  2081  func (s *Store) parseNodes(tx *memdb.Txn, ws memdb.WatchSet, idx uint64,
  2082  	iter memdb.ResultIterator) (uint64, structs.NodeDump, error) {
  2083  
  2084  	// We don't want to track an unlimited number of services, so we pull a
  2085  	// top-level watch to use as a fallback.
  2086  	allServices, err := tx.Get("services", "id")
  2087  	if err != nil {
  2088  		return 0, nil, fmt.Errorf("failed services lookup: %s", err)
  2089  	}
  2090  	allServicesCh := allServices.WatchCh()
  2091  
  2092  	// We need a similar fallback for checks.
  2093  	allChecks, err := tx.Get("checks", "id")
  2094  	if err != nil {
  2095  		return 0, nil, fmt.Errorf("failed checks lookup: %s", err)
  2096  	}
  2097  	allChecksCh := allChecks.WatchCh()
  2098  
  2099  	var results structs.NodeDump
  2100  	for n := iter.Next(); n != nil; n = iter.Next() {
  2101  		node := n.(*structs.Node)
  2102  
  2103  		// Create the wrapped node
  2104  		dump := &structs.NodeInfo{
  2105  			ID:              node.ID,
  2106  			Node:            node.Node,
  2107  			Address:         node.Address,
  2108  			TaggedAddresses: node.TaggedAddresses,
  2109  			Meta:            node.Meta,
  2110  		}
  2111  
  2112  		// Query the node services
  2113  		services, err := tx.Get("services", "node", node.Node)
  2114  		if err != nil {
  2115  			return 0, nil, fmt.Errorf("failed services lookup: %s", err)
  2116  		}
  2117  		ws.AddWithLimit(watchLimit, services.WatchCh(), allServicesCh)
  2118  		for service := services.Next(); service != nil; service = services.Next() {
  2119  			ns := service.(*structs.ServiceNode).ToNodeService()
  2120  			dump.Services = append(dump.Services, ns)
  2121  		}
  2122  
  2123  		// Query the node checks
  2124  		checks, err := tx.Get("checks", "node", node.Node)
  2125  		if err != nil {
  2126  			return 0, nil, fmt.Errorf("failed node lookup: %s", err)
  2127  		}
  2128  		ws.AddWithLimit(watchLimit, checks.WatchCh(), allChecksCh)
  2129  		for check := checks.Next(); check != nil; check = checks.Next() {
  2130  			hc := check.(*structs.HealthCheck)
  2131  			dump.Checks = append(dump.Checks, hc)
  2132  		}
  2133  
  2134  		// Add the result to the slice
  2135  		results = append(results, dump)
  2136  	}
  2137  	return idx, results, nil
  2138  }