github.com/Aestek/consul@v1.2.4-0.20190309222502-b2c31e33971a/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  	services, err := tx.Get("services", "node", node.Node)
   488  	if err != nil {
   489  		return fmt.Errorf("failed querying services: %s", err)
   490  	}
   491  	updatedServices := map[string]struct{}{}
   492  	for service := services.Next(); service != nil; service = services.Next() {
   493  		svc := service.(*structs.ServiceNode)
   494  		if _, ok := updatedServices[svc.ServiceName]; ok {
   495  			continue
   496  		}
   497  		if err := tx.Insert("index", &IndexEntry{serviceIndexName(svc.ServiceName), idx}); err != nil {
   498  			return fmt.Errorf("failed updating index: %s", err)
   499  		}
   500  		updatedServices[svc.ServiceName] = struct{}{}
   501  	}
   502  
   503  	return nil
   504  }
   505  
   506  // GetNode is used to retrieve a node registration by node name ID.
   507  func (s *Store) GetNode(id string) (uint64, *structs.Node, error) {
   508  	tx := s.db.Txn(false)
   509  	defer tx.Abort()
   510  
   511  	// Get the table index.
   512  	idx := maxIndexTxn(tx, "nodes")
   513  
   514  	// Retrieve the node from the state store
   515  	node, err := getNodeTxn(tx, id)
   516  	if err != nil {
   517  		return 0, nil, fmt.Errorf("node lookup failed: %s", err)
   518  	}
   519  	return idx, node, nil
   520  }
   521  
   522  func getNodeTxn(tx *memdb.Txn, nodeName string) (*structs.Node, error) {
   523  	node, err := tx.First("nodes", "id", nodeName)
   524  	if err != nil {
   525  		return nil, fmt.Errorf("node lookup failed: %s", err)
   526  	}
   527  	if node != nil {
   528  		return node.(*structs.Node), nil
   529  	}
   530  	return nil, nil
   531  }
   532  
   533  func getNodeIDTxn(tx *memdb.Txn, id types.NodeID) (*structs.Node, error) {
   534  	strnode := string(id)
   535  	uuidValue, err := uuid.ParseUUID(strnode)
   536  	if err != nil {
   537  		return nil, fmt.Errorf("node lookup by ID failed, wrong UUID: %v for '%s'", err, strnode)
   538  	}
   539  
   540  	node, err := tx.First("nodes", "uuid", uuidValue)
   541  	if err != nil {
   542  		return nil, fmt.Errorf("node lookup by ID failed: %s", err)
   543  	}
   544  	if node != nil {
   545  		return node.(*structs.Node), nil
   546  	}
   547  	return nil, nil
   548  }
   549  
   550  // GetNodeID is used to retrieve a node registration by node ID.
   551  func (s *Store) GetNodeID(id types.NodeID) (uint64, *structs.Node, error) {
   552  	tx := s.db.Txn(false)
   553  	defer tx.Abort()
   554  
   555  	// Get the table index.
   556  	idx := maxIndexTxn(tx, "nodes")
   557  
   558  	// Retrieve the node from the state store
   559  	node, err := getNodeIDTxn(tx, id)
   560  	return idx, node, err
   561  }
   562  
   563  // Nodes is used to return all of the known nodes.
   564  func (s *Store) Nodes(ws memdb.WatchSet) (uint64, structs.Nodes, error) {
   565  	tx := s.db.Txn(false)
   566  	defer tx.Abort()
   567  
   568  	// Get the table index.
   569  	idx := maxIndexTxn(tx, "nodes")
   570  
   571  	// Retrieve all of the nodes
   572  	nodes, err := tx.Get("nodes", "id")
   573  	if err != nil {
   574  		return 0, nil, fmt.Errorf("failed nodes lookup: %s", err)
   575  	}
   576  	ws.Add(nodes.WatchCh())
   577  
   578  	// Create and return the nodes list.
   579  	var results structs.Nodes
   580  	for node := nodes.Next(); node != nil; node = nodes.Next() {
   581  		results = append(results, node.(*structs.Node))
   582  	}
   583  	return idx, results, nil
   584  }
   585  
   586  // NodesByMeta is used to return all nodes with the given metadata key/value pairs.
   587  func (s *Store) NodesByMeta(ws memdb.WatchSet, filters map[string]string) (uint64, structs.Nodes, error) {
   588  	tx := s.db.Txn(false)
   589  	defer tx.Abort()
   590  
   591  	// Get the table index.
   592  	idx := maxIndexTxn(tx, "nodes")
   593  
   594  	// Retrieve all of the nodes
   595  	var args []interface{}
   596  	for key, value := range filters {
   597  		args = append(args, key, value)
   598  		break
   599  	}
   600  	nodes, err := tx.Get("nodes", "meta", args...)
   601  	if err != nil {
   602  		return 0, nil, fmt.Errorf("failed nodes lookup: %s", err)
   603  	}
   604  	ws.Add(nodes.WatchCh())
   605  
   606  	// Create and return the nodes list.
   607  	var results structs.Nodes
   608  	for node := nodes.Next(); node != nil; node = nodes.Next() {
   609  		n := node.(*structs.Node)
   610  		if len(filters) <= 1 || structs.SatisfiesMetaFilters(n.Meta, filters) {
   611  			results = append(results, n)
   612  		}
   613  	}
   614  	return idx, results, nil
   615  }
   616  
   617  // DeleteNode is used to delete a given node by its ID.
   618  func (s *Store) DeleteNode(idx uint64, nodeName string) error {
   619  	tx := s.db.Txn(true)
   620  	defer tx.Abort()
   621  
   622  	// Call the node deletion.
   623  	if err := s.deleteNodeTxn(tx, idx, nodeName); err != nil {
   624  		return err
   625  	}
   626  
   627  	tx.Commit()
   628  	return nil
   629  }
   630  
   631  // deleteNodeCASTxn is used to try doing a node delete operation with a given
   632  // raft index. If the CAS index specified is not equal to the last observed index for
   633  // the given check, then the call is a noop, otherwise a normal check delete is invoked.
   634  func (s *Store) deleteNodeCASTxn(tx *memdb.Txn, idx, cidx uint64, nodeName string) (bool, error) {
   635  	// Look up the node.
   636  	node, err := getNodeTxn(tx, nodeName)
   637  	if err != nil {
   638  		return false, err
   639  	}
   640  	if node == nil {
   641  		return false, nil
   642  	}
   643  
   644  	// If the existing index does not match the provided CAS
   645  	// index arg, then we shouldn't update anything and can safely
   646  	// return early here.
   647  	if node.ModifyIndex != cidx {
   648  		return false, nil
   649  	}
   650  
   651  	// Call the actual deletion if the above passed.
   652  	if err := s.deleteNodeTxn(tx, idx, nodeName); err != nil {
   653  		return false, err
   654  	}
   655  
   656  	return true, nil
   657  }
   658  
   659  // deleteNodeTxn is the inner method used for removing a node from
   660  // the store within a given transaction.
   661  func (s *Store) deleteNodeTxn(tx *memdb.Txn, idx uint64, nodeName string) error {
   662  	// Look up the node.
   663  	node, err := tx.First("nodes", "id", nodeName)
   664  	if err != nil {
   665  		return fmt.Errorf("node lookup failed: %s", err)
   666  	}
   667  	if node == nil {
   668  		return nil
   669  	}
   670  
   671  	// Delete all services associated with the node and update the service index.
   672  	services, err := tx.Get("services", "node", nodeName)
   673  	if err != nil {
   674  		return fmt.Errorf("failed service lookup: %s", err)
   675  	}
   676  	var sids []string
   677  	for service := services.Next(); service != nil; service = services.Next() {
   678  		svc := service.(*structs.ServiceNode)
   679  		sids = append(sids, svc.ServiceID)
   680  		if err := tx.Insert("index", &IndexEntry{serviceIndexName(svc.ServiceName), idx}); err != nil {
   681  			return fmt.Errorf("failed updating index: %s", err)
   682  		}
   683  	}
   684  
   685  	// Do the delete in a separate loop so we don't trash the iterator.
   686  	for _, sid := range sids {
   687  		if err := s.deleteServiceTxn(tx, idx, nodeName, sid); err != nil {
   688  			return err
   689  		}
   690  	}
   691  
   692  	// Delete all checks associated with the node. This will invalidate
   693  	// sessions as necessary.
   694  	checks, err := tx.Get("checks", "node", nodeName)
   695  	if err != nil {
   696  		return fmt.Errorf("failed check lookup: %s", err)
   697  	}
   698  	var cids []types.CheckID
   699  	for check := checks.Next(); check != nil; check = checks.Next() {
   700  		cids = append(cids, check.(*structs.HealthCheck).CheckID)
   701  	}
   702  
   703  	// Do the delete in a separate loop so we don't trash the iterator.
   704  	for _, cid := range cids {
   705  		if err := s.deleteCheckTxn(tx, idx, nodeName, cid); err != nil {
   706  			return err
   707  		}
   708  	}
   709  
   710  	// Delete any coordinates associated with this node.
   711  	coords, err := tx.Get("coordinates", "node", nodeName)
   712  	if err != nil {
   713  		return fmt.Errorf("failed coordinate lookup: %s", err)
   714  	}
   715  	for coord := coords.Next(); coord != nil; coord = coords.Next() {
   716  		if err := tx.Delete("coordinates", coord); err != nil {
   717  			return fmt.Errorf("failed deleting coordinate: %s", err)
   718  		}
   719  		if err := tx.Insert("index", &IndexEntry{"coordinates", idx}); err != nil {
   720  			return fmt.Errorf("failed updating index: %s", err)
   721  		}
   722  	}
   723  
   724  	// Delete the node and update the index.
   725  	if err := tx.Delete("nodes", node); err != nil {
   726  		return fmt.Errorf("failed deleting node: %s", err)
   727  	}
   728  	if err := tx.Insert("index", &IndexEntry{"nodes", idx}); err != nil {
   729  		return fmt.Errorf("failed updating index: %s", err)
   730  	}
   731  
   732  	// Invalidate any sessions for this node.
   733  	sessions, err := tx.Get("sessions", "node", nodeName)
   734  	if err != nil {
   735  		return fmt.Errorf("failed session lookup: %s", err)
   736  	}
   737  	var ids []string
   738  	for sess := sessions.Next(); sess != nil; sess = sessions.Next() {
   739  		ids = append(ids, sess.(*structs.Session).ID)
   740  	}
   741  
   742  	// Do the delete in a separate loop so we don't trash the iterator.
   743  	for _, id := range ids {
   744  		if err := s.deleteSessionTxn(tx, idx, id); err != nil {
   745  			return fmt.Errorf("failed session delete: %s", err)
   746  		}
   747  	}
   748  
   749  	return nil
   750  }
   751  
   752  // EnsureService is called to upsert creation of a given NodeService.
   753  func (s *Store) EnsureService(idx uint64, node string, svc *structs.NodeService) error {
   754  	tx := s.db.Txn(true)
   755  	defer tx.Abort()
   756  
   757  	// Call the service registration upsert
   758  	if err := s.ensureServiceTxn(tx, idx, node, svc); err != nil {
   759  		return err
   760  	}
   761  
   762  	tx.Commit()
   763  	return nil
   764  }
   765  
   766  // ensureServiceCASTxn updates a service only if the existing index matches the given index.
   767  // Returns a bool indicating if a write happened and any error.
   768  func (s *Store) ensureServiceCASTxn(tx *memdb.Txn, idx uint64, node string, svc *structs.NodeService) (bool, error) {
   769  	// Retrieve the existing service.
   770  	existing, err := tx.First("services", "id", node, svc.ID)
   771  	if err != nil {
   772  		return false, fmt.Errorf("failed service lookup: %s", err)
   773  	}
   774  
   775  	// Check if the we should do the set. A ModifyIndex of 0 means that
   776  	// we are doing a set-if-not-exists.
   777  	if svc.ModifyIndex == 0 && existing != nil {
   778  		return false, nil
   779  	}
   780  	if svc.ModifyIndex != 0 && existing == nil {
   781  		return false, nil
   782  	}
   783  	e, ok := existing.(*structs.Node)
   784  	if ok && svc.ModifyIndex != 0 && svc.ModifyIndex != e.ModifyIndex {
   785  		return false, nil
   786  	}
   787  
   788  	// Perform the update.
   789  	if err := s.ensureServiceTxn(tx, idx, node, svc); err != nil {
   790  		return false, err
   791  	}
   792  
   793  	return true, nil
   794  }
   795  
   796  // ensureServiceTxn is used to upsert a service registration within an
   797  // existing memdb transaction.
   798  func (s *Store) ensureServiceTxn(tx *memdb.Txn, idx uint64, node string, svc *structs.NodeService) error {
   799  	// Check for existing service
   800  	existing, err := tx.First("services", "id", node, svc.ID)
   801  	if err != nil {
   802  		return fmt.Errorf("failed service lookup: %s", err)
   803  	}
   804  
   805  	if err = structs.ValidateMetadata(svc.Meta, false); err != nil {
   806  		return fmt.Errorf("Invalid Service Meta for node %s and serviceID %s: %v", node, svc.ID, err)
   807  	}
   808  	// Create the service node entry and populate the indexes. Note that
   809  	// conversion doesn't populate any of the node-specific information.
   810  	// That's always populated when we read from the state store.
   811  	entry := svc.ToServiceNode(node)
   812  	// Get the node
   813  	n, err := tx.First("nodes", "id", node)
   814  	if err != nil {
   815  		return fmt.Errorf("failed node lookup: %s", err)
   816  	}
   817  	if n == nil {
   818  		return ErrMissingNode
   819  	}
   820  	if existing != nil {
   821  		serviceNode := existing.(*structs.ServiceNode)
   822  		entry.CreateIndex = serviceNode.CreateIndex
   823  		entry.ModifyIndex = serviceNode.ModifyIndex
   824  		// We cannot return here because: we want to keep existing behavior (ex: failed node lookup -> ErrMissingNode)
   825  		// It might be modified in future, but it requires changing many unit tests
   826  		// Enforcing saving the entry also ensures that if we add default values in .ToServiceNode()
   827  		// those values will be saved even if node is not really modified for a while.
   828  		if entry.IsSameService(serviceNode) {
   829  			return nil
   830  		}
   831  	} else {
   832  		entry.CreateIndex = idx
   833  	}
   834  	entry.ModifyIndex = idx
   835  
   836  	// Insert the service and update the index
   837  	if err := tx.Insert("services", entry); err != nil {
   838  		return fmt.Errorf("failed inserting service: %s", err)
   839  	}
   840  	if err := tx.Insert("index", &IndexEntry{"services", idx}); err != nil {
   841  		return fmt.Errorf("failed updating index: %s", err)
   842  	}
   843  	if err := tx.Insert("index", &IndexEntry{serviceIndexName(svc.Service), idx}); err != nil {
   844  		return fmt.Errorf("failed updating index: %s", err)
   845  	}
   846  
   847  	return nil
   848  }
   849  
   850  // Services returns all services along with a list of associated tags.
   851  func (s *Store) Services(ws memdb.WatchSet) (uint64, structs.Services, error) {
   852  	tx := s.db.Txn(false)
   853  	defer tx.Abort()
   854  
   855  	// Get the table index.
   856  	idx := maxIndexTxn(tx, "services")
   857  
   858  	// List all the services.
   859  	services, err := tx.Get("services", "id")
   860  	if err != nil {
   861  		return 0, nil, fmt.Errorf("failed querying services: %s", err)
   862  	}
   863  	ws.Add(services.WatchCh())
   864  
   865  	// Rip through the services and enumerate them and their unique set of
   866  	// tags.
   867  	unique := make(map[string]map[string]struct{})
   868  	for service := services.Next(); service != nil; service = services.Next() {
   869  		svc := service.(*structs.ServiceNode)
   870  		tags, ok := unique[svc.ServiceName]
   871  		if !ok {
   872  			unique[svc.ServiceName] = make(map[string]struct{})
   873  			tags = unique[svc.ServiceName]
   874  		}
   875  		for _, tag := range svc.ServiceTags {
   876  			tags[tag] = struct{}{}
   877  		}
   878  	}
   879  
   880  	// Generate the output structure.
   881  	var results = make(structs.Services)
   882  	for service, tags := range unique {
   883  		results[service] = make([]string, 0)
   884  		for tag := range tags {
   885  			results[service] = append(results[service], tag)
   886  		}
   887  	}
   888  	return idx, results, nil
   889  }
   890  
   891  // ServicesByNodeMeta returns all services, filtered by the given node metadata.
   892  func (s *Store) ServicesByNodeMeta(ws memdb.WatchSet, filters map[string]string) (uint64, structs.Services, error) {
   893  	tx := s.db.Txn(false)
   894  	defer tx.Abort()
   895  
   896  	// Get the table index.
   897  	idx := maxIndexTxn(tx, "services", "nodes")
   898  
   899  	// Retrieve all of the nodes with the meta k/v pair
   900  	var args []interface{}
   901  	for key, value := range filters {
   902  		args = append(args, key, value)
   903  		break
   904  	}
   905  	nodes, err := tx.Get("nodes", "meta", args...)
   906  	if err != nil {
   907  		return 0, nil, fmt.Errorf("failed nodes lookup: %s", err)
   908  	}
   909  	ws.Add(nodes.WatchCh())
   910  
   911  	// We don't want to track an unlimited number of services, so we pull a
   912  	// top-level watch to use as a fallback.
   913  	allServices, err := tx.Get("services", "id")
   914  	if err != nil {
   915  		return 0, nil, fmt.Errorf("failed services lookup: %s", err)
   916  	}
   917  	allServicesCh := allServices.WatchCh()
   918  
   919  	// Populate the services map
   920  	unique := make(map[string]map[string]struct{})
   921  	for node := nodes.Next(); node != nil; node = nodes.Next() {
   922  		n := node.(*structs.Node)
   923  		if len(filters) > 1 && !structs.SatisfiesMetaFilters(n.Meta, filters) {
   924  			continue
   925  		}
   926  
   927  		// List all the services on the node
   928  		services, err := tx.Get("services", "node", n.Node)
   929  		if err != nil {
   930  			return 0, nil, fmt.Errorf("failed querying services: %s", err)
   931  		}
   932  		ws.AddWithLimit(watchLimit, services.WatchCh(), allServicesCh)
   933  
   934  		// Rip through the services and enumerate them and their unique set of
   935  		// tags.
   936  		for service := services.Next(); service != nil; service = services.Next() {
   937  			svc := service.(*structs.ServiceNode)
   938  			tags, ok := unique[svc.ServiceName]
   939  			if !ok {
   940  				unique[svc.ServiceName] = make(map[string]struct{})
   941  				tags = unique[svc.ServiceName]
   942  			}
   943  			for _, tag := range svc.ServiceTags {
   944  				tags[tag] = struct{}{}
   945  			}
   946  		}
   947  	}
   948  
   949  	// Generate the output structure.
   950  	var results = make(structs.Services)
   951  	for service, tags := range unique {
   952  		results[service] = make([]string, 0)
   953  		for tag := range tags {
   954  			results[service] = append(results[service], tag)
   955  		}
   956  	}
   957  	return idx, results, nil
   958  }
   959  
   960  // maxIndexForService return the maximum Raft Index for a service
   961  // If the index is not set for the service, it will return the missing
   962  // service index.
   963  // The service_last_extinction is set to the last raft index when a service
   964  // was unregistered (or 0 if no services were ever unregistered). This
   965  // allows blocking queries to
   966  //   * return when the last instance of a service is removed
   967  //   * block until an instance for this service is available, or another
   968  //     service is unregistered.
   969  func maxIndexForService(tx *memdb.Txn, serviceName string, serviceExists, checks bool) uint64 {
   970  	if !serviceExists {
   971  		res, err := tx.First("index", "id", serviceLastExtinctionIndexName)
   972  		if missingIdx, ok := res.(*IndexEntry); ok && err == nil {
   973  			return missingIdx.Value
   974  		}
   975  	}
   976  
   977  	res, err := tx.First("index", "id", serviceIndexName(serviceName))
   978  	if idx, ok := res.(*IndexEntry); ok && err == nil {
   979  		return idx.Value
   980  	}
   981  	if checks {
   982  		return maxIndexTxn(tx, "nodes", "services", "checks")
   983  	}
   984  
   985  	return maxIndexTxn(tx, "nodes", "services")
   986  }
   987  
   988  // ConnectServiceNodes returns the nodes associated with a Connect
   989  // compatible destination for the given service name. This will include
   990  // both proxies and native integrations.
   991  func (s *Store) ConnectServiceNodes(ws memdb.WatchSet, serviceName string) (uint64, structs.ServiceNodes, error) {
   992  	return s.serviceNodes(ws, serviceName, true)
   993  }
   994  
   995  // ServiceNodes returns the nodes associated with a given service name.
   996  func (s *Store) ServiceNodes(ws memdb.WatchSet, serviceName string) (uint64, structs.ServiceNodes, error) {
   997  	return s.serviceNodes(ws, serviceName, false)
   998  }
   999  
  1000  func (s *Store) serviceNodes(ws memdb.WatchSet, serviceName string, connect bool) (uint64, structs.ServiceNodes, error) {
  1001  	tx := s.db.Txn(false)
  1002  	defer tx.Abort()
  1003  
  1004  	// Function for lookup
  1005  	var f func() (memdb.ResultIterator, error)
  1006  	if !connect {
  1007  		f = func() (memdb.ResultIterator, error) {
  1008  			return tx.Get("services", "service", serviceName)
  1009  		}
  1010  	} else {
  1011  		f = func() (memdb.ResultIterator, error) {
  1012  			return tx.Get("services", "connect", serviceName)
  1013  		}
  1014  	}
  1015  
  1016  	// List all the services.
  1017  	services, err := f()
  1018  	if err != nil {
  1019  		return 0, nil, fmt.Errorf("failed service lookup: %s", err)
  1020  	}
  1021  	ws.Add(services.WatchCh())
  1022  
  1023  	var results structs.ServiceNodes
  1024  	for service := services.Next(); service != nil; service = services.Next() {
  1025  		results = append(results, service.(*structs.ServiceNode))
  1026  	}
  1027  
  1028  	// Fill in the node details.
  1029  	results, err = s.parseServiceNodes(tx, ws, results)
  1030  	if err != nil {
  1031  		return 0, nil, fmt.Errorf("failed parsing service nodes: %s", err)
  1032  	}
  1033  
  1034  	// Get the table index.
  1035  	idx := maxIndexForService(tx, serviceName, len(results) > 0, false)
  1036  
  1037  	return idx, results, nil
  1038  }
  1039  
  1040  // ServiceTagNodes returns the nodes associated with a given service, filtering
  1041  // out services that don't contain the given tags.
  1042  func (s *Store) ServiceTagNodes(ws memdb.WatchSet, service string, tags []string) (uint64, structs.ServiceNodes, error) {
  1043  	tx := s.db.Txn(false)
  1044  	defer tx.Abort()
  1045  
  1046  	// List all the services.
  1047  	services, err := tx.Get("services", "service", service)
  1048  	if err != nil {
  1049  		return 0, nil, fmt.Errorf("failed service lookup: %s", err)
  1050  	}
  1051  	ws.Add(services.WatchCh())
  1052  
  1053  	// Gather all the services and apply the tag filter.
  1054  	serviceExists := false
  1055  	var results structs.ServiceNodes
  1056  	for service := services.Next(); service != nil; service = services.Next() {
  1057  		svc := service.(*structs.ServiceNode)
  1058  		serviceExists = true
  1059  		if !serviceTagsFilter(svc, tags) {
  1060  			results = append(results, svc)
  1061  		}
  1062  	}
  1063  
  1064  	// Fill in the node details.
  1065  	results, err = s.parseServiceNodes(tx, ws, results)
  1066  	if err != nil {
  1067  		return 0, nil, fmt.Errorf("failed parsing service nodes: %s", err)
  1068  	}
  1069  	// Get the table index.
  1070  	idx := maxIndexForService(tx, service, serviceExists, false)
  1071  
  1072  	return idx, results, nil
  1073  }
  1074  
  1075  // serviceTagFilter returns true (should filter) if the given service node
  1076  // doesn't contain the given tag.
  1077  func serviceTagFilter(sn *structs.ServiceNode, tag string) bool {
  1078  	tag = strings.ToLower(tag)
  1079  
  1080  	// Look for the lower cased version of the tag.
  1081  	for _, t := range sn.ServiceTags {
  1082  		if strings.ToLower(t) == tag {
  1083  			return false
  1084  		}
  1085  	}
  1086  
  1087  	// If we didn't hit the tag above then we should filter.
  1088  	return true
  1089  }
  1090  
  1091  // serviceTagsFilter returns true (should filter) if the given service node
  1092  // doesn't contain the given set of tags.
  1093  func serviceTagsFilter(sn *structs.ServiceNode, tags []string) bool {
  1094  	for _, tag := range tags {
  1095  		if serviceTagFilter(sn, tag) {
  1096  			// If any one of the expected tags was not found, filter the service
  1097  			return true
  1098  		}
  1099  	}
  1100  
  1101  	// If all tags were found, don't filter the service
  1102  	return false
  1103  }
  1104  
  1105  // ServiceAddressNodes returns the nodes associated with a given service, filtering
  1106  // out services that don't match the given serviceAddress
  1107  func (s *Store) ServiceAddressNodes(ws memdb.WatchSet, address string) (uint64, structs.ServiceNodes, error) {
  1108  	tx := s.db.Txn(false)
  1109  	defer tx.Abort()
  1110  
  1111  	// List all the services.
  1112  	services, err := tx.Get("services", "id")
  1113  	if err != nil {
  1114  		return 0, nil, fmt.Errorf("failed service lookup: %s", err)
  1115  	}
  1116  	ws.Add(services.WatchCh())
  1117  
  1118  	// Gather all the services and apply the tag filter.
  1119  	var results structs.ServiceNodes
  1120  	for service := services.Next(); service != nil; service = services.Next() {
  1121  		svc := service.(*structs.ServiceNode)
  1122  		if svc.ServiceAddress == address {
  1123  			results = append(results, svc)
  1124  		}
  1125  	}
  1126  
  1127  	// Fill in the node details.
  1128  	results, err = s.parseServiceNodes(tx, ws, results)
  1129  	if err != nil {
  1130  		return 0, nil, fmt.Errorf("failed parsing service nodes: %s", err)
  1131  	}
  1132  	return 0, results, nil
  1133  }
  1134  
  1135  // parseServiceNodes iterates over a services query and fills in the node details,
  1136  // returning a ServiceNodes slice.
  1137  func (s *Store) parseServiceNodes(tx *memdb.Txn, ws memdb.WatchSet, services structs.ServiceNodes) (structs.ServiceNodes, error) {
  1138  	// We don't want to track an unlimited number of nodes, so we pull a
  1139  	// top-level watch to use as a fallback.
  1140  	allNodes, err := tx.Get("nodes", "id")
  1141  	if err != nil {
  1142  		return nil, fmt.Errorf("failed nodes lookup: %s", err)
  1143  	}
  1144  	allNodesCh := allNodes.WatchCh()
  1145  
  1146  	// Fill in the node data for each service instance.
  1147  	var results structs.ServiceNodes
  1148  	for _, sn := range services {
  1149  		// Note that we have to clone here because we don't want to
  1150  		// modify the node-related fields on the object in the database,
  1151  		// which is what we are referencing.
  1152  		s := sn.PartialClone()
  1153  
  1154  		// Grab the corresponding node record.
  1155  		watchCh, n, err := tx.FirstWatch("nodes", "id", sn.Node)
  1156  		if err != nil {
  1157  			return nil, fmt.Errorf("failed node lookup: %s", err)
  1158  		}
  1159  		ws.AddWithLimit(watchLimit, watchCh, allNodesCh)
  1160  
  1161  		// Populate the node-related fields. The tagged addresses may be
  1162  		// used by agents to perform address translation if they are
  1163  		// configured to do that.
  1164  		node := n.(*structs.Node)
  1165  		s.ID = node.ID
  1166  		s.Address = node.Address
  1167  		s.Datacenter = node.Datacenter
  1168  		s.TaggedAddresses = node.TaggedAddresses
  1169  		s.NodeMeta = node.Meta
  1170  
  1171  		results = append(results, s)
  1172  	}
  1173  	return results, nil
  1174  }
  1175  
  1176  // NodeService is used to retrieve a specific service associated with the given
  1177  // node.
  1178  func (s *Store) NodeService(nodeName string, serviceID string) (uint64, *structs.NodeService, error) {
  1179  	tx := s.db.Txn(false)
  1180  	defer tx.Abort()
  1181  
  1182  	// Get the table index.
  1183  	idx := maxIndexTxn(tx, "services")
  1184  
  1185  	// Query the service
  1186  	service, err := s.getNodeServiceTxn(tx, nodeName, serviceID)
  1187  	if err != nil {
  1188  		return 0, nil, fmt.Errorf("failed querying service for node %q: %s", nodeName, err)
  1189  	}
  1190  
  1191  	return idx, service, nil
  1192  }
  1193  
  1194  func (s *Store) getNodeServiceTxn(tx *memdb.Txn, nodeName, serviceID string) (*structs.NodeService, error) {
  1195  	// Query the service
  1196  	service, err := tx.First("services", "id", nodeName, serviceID)
  1197  	if err != nil {
  1198  		return nil, fmt.Errorf("failed querying service for node %q: %s", nodeName, err)
  1199  	}
  1200  
  1201  	if service != nil {
  1202  		return service.(*structs.ServiceNode).ToNodeService(), nil
  1203  	}
  1204  
  1205  	return nil, nil
  1206  }
  1207  
  1208  // NodeServices is used to query service registrations by node name or UUID.
  1209  func (s *Store) NodeServices(ws memdb.WatchSet, nodeNameOrID string) (uint64, *structs.NodeServices, error) {
  1210  	tx := s.db.Txn(false)
  1211  	defer tx.Abort()
  1212  
  1213  	// Get the table index.
  1214  	idx := maxIndexTxn(tx, "nodes", "services")
  1215  
  1216  	// Query the node by node name
  1217  	watchCh, n, err := tx.FirstWatch("nodes", "id", nodeNameOrID)
  1218  	if err != nil {
  1219  		return 0, nil, fmt.Errorf("node lookup failed: %s", err)
  1220  	}
  1221  
  1222  	if n != nil {
  1223  		ws.Add(watchCh)
  1224  	} else {
  1225  		if len(nodeNameOrID) < minUUIDLookupLen {
  1226  			ws.Add(watchCh)
  1227  			return 0, nil, nil
  1228  		}
  1229  
  1230  		// Attempt to lookup the node by its node ID
  1231  		iter, err := tx.Get("nodes", "uuid_prefix", resizeNodeLookupKey(nodeNameOrID))
  1232  		if err != nil {
  1233  			ws.Add(watchCh)
  1234  			// TODO(sean@): We could/should log an error re: the uuid_prefix lookup
  1235  			// failing once a logger has been introduced to the catalog.
  1236  			return 0, nil, nil
  1237  		}
  1238  
  1239  		n = iter.Next()
  1240  		if n == nil {
  1241  			// No nodes matched, even with the Node ID: add a watch on the node name.
  1242  			ws.Add(watchCh)
  1243  			return 0, nil, nil
  1244  		}
  1245  
  1246  		idWatchCh := iter.WatchCh()
  1247  		if iter.Next() != nil {
  1248  			// More than one match present: Watch on the node name channel and return
  1249  			// an empty result (node lookups can not be ambiguous).
  1250  			ws.Add(watchCh)
  1251  			return 0, nil, nil
  1252  		}
  1253  
  1254  		ws.Add(idWatchCh)
  1255  	}
  1256  
  1257  	node := n.(*structs.Node)
  1258  	nodeName := node.Node
  1259  
  1260  	// Read all of the services
  1261  	services, err := tx.Get("services", "node", nodeName)
  1262  	if err != nil {
  1263  		return 0, nil, fmt.Errorf("failed querying services for node %q: %s", nodeName, err)
  1264  	}
  1265  	ws.Add(services.WatchCh())
  1266  
  1267  	// Initialize the node services struct
  1268  	ns := &structs.NodeServices{
  1269  		Node:     node,
  1270  		Services: make(map[string]*structs.NodeService),
  1271  	}
  1272  
  1273  	// Add all of the services to the map.
  1274  	for service := services.Next(); service != nil; service = services.Next() {
  1275  		svc := service.(*structs.ServiceNode).ToNodeService()
  1276  		ns.Services[svc.ID] = svc
  1277  	}
  1278  
  1279  	return idx, ns, nil
  1280  }
  1281  
  1282  // DeleteService is used to delete a given service associated with a node.
  1283  func (s *Store) DeleteService(idx uint64, nodeName, serviceID string) error {
  1284  	tx := s.db.Txn(true)
  1285  	defer tx.Abort()
  1286  
  1287  	// Call the service deletion
  1288  	if err := s.deleteServiceTxn(tx, idx, nodeName, serviceID); err != nil {
  1289  		return err
  1290  	}
  1291  
  1292  	tx.Commit()
  1293  	return nil
  1294  }
  1295  
  1296  func serviceIndexName(name string) string {
  1297  	return fmt.Sprintf("service.%s", name)
  1298  }
  1299  
  1300  // deleteServiceCASTxn is used to try doing a service delete operation with a given
  1301  // raft index. If the CAS index specified is not equal to the last observed index for
  1302  // the given service, then the call is a noop, otherwise a normal delete is invoked.
  1303  func (s *Store) deleteServiceCASTxn(tx *memdb.Txn, idx, cidx uint64, nodeName, serviceID string) (bool, error) {
  1304  	// Look up the service.
  1305  	service, err := s.getNodeServiceTxn(tx, nodeName, serviceID)
  1306  	if err != nil {
  1307  		return false, fmt.Errorf("service lookup failed: %s", err)
  1308  	}
  1309  	if service == nil {
  1310  		return false, nil
  1311  	}
  1312  
  1313  	// If the existing index does not match the provided CAS
  1314  	// index arg, then we shouldn't update anything and can safely
  1315  	// return early here.
  1316  	if service.ModifyIndex != cidx {
  1317  		return false, nil
  1318  	}
  1319  
  1320  	// Call the actual deletion if the above passed.
  1321  	if err := s.deleteServiceTxn(tx, idx, nodeName, serviceID); err != nil {
  1322  		return false, err
  1323  	}
  1324  
  1325  	return true, nil
  1326  }
  1327  
  1328  // deleteServiceTxn is the inner method called to remove a service
  1329  // registration within an existing transaction.
  1330  func (s *Store) deleteServiceTxn(tx *memdb.Txn, idx uint64, nodeName, serviceID string) error {
  1331  	// Look up the service.
  1332  	service, err := tx.First("services", "id", nodeName, serviceID)
  1333  	if err != nil {
  1334  		return fmt.Errorf("failed service lookup: %s", err)
  1335  	}
  1336  	if service == nil {
  1337  		return nil
  1338  	}
  1339  
  1340  	// Delete any checks associated with the service. This will invalidate
  1341  	// sessions as necessary.
  1342  	checks, err := tx.Get("checks", "node_service", nodeName, serviceID)
  1343  	if err != nil {
  1344  		return fmt.Errorf("failed service check lookup: %s", err)
  1345  	}
  1346  	var cids []types.CheckID
  1347  	for check := checks.Next(); check != nil; check = checks.Next() {
  1348  		cids = append(cids, check.(*structs.HealthCheck).CheckID)
  1349  	}
  1350  
  1351  	// Do the delete in a separate loop so we don't trash the iterator.
  1352  	for _, cid := range cids {
  1353  		if err := s.deleteCheckTxn(tx, idx, nodeName, cid); err != nil {
  1354  			return err
  1355  		}
  1356  	}
  1357  
  1358  	// Update the index.
  1359  	if err := tx.Insert("index", &IndexEntry{"checks", idx}); err != nil {
  1360  		return fmt.Errorf("failed updating index: %s", err)
  1361  	}
  1362  
  1363  	// Delete the service and update the index
  1364  	if err := tx.Delete("services", service); err != nil {
  1365  		return fmt.Errorf("failed deleting service: %s", err)
  1366  	}
  1367  	if err := tx.Insert("index", &IndexEntry{"services", idx}); err != nil {
  1368  		return fmt.Errorf("failed updating index: %s", err)
  1369  	}
  1370  
  1371  	svc := service.(*structs.ServiceNode)
  1372  	if remainingService, err := tx.First("services", "service", svc.ServiceName); err == nil {
  1373  		if remainingService != nil {
  1374  			// We have at least one remaining service, update the index
  1375  			if err := tx.Insert("index", &IndexEntry{serviceIndexName(svc.ServiceName), idx}); err != nil {
  1376  				return fmt.Errorf("failed updating index: %s", err)
  1377  			}
  1378  		} else {
  1379  			// There are no more service instances, cleanup the service.<serviceName> index
  1380  			serviceIndex, err := tx.First("index", "id", serviceIndexName(svc.ServiceName))
  1381  			if err == nil && serviceIndex != nil {
  1382  				// we found service.<serviceName> index, garbage collect it
  1383  				if errW := tx.Delete("index", serviceIndex); errW != nil {
  1384  					return fmt.Errorf("[FAILED] deleting serviceIndex %s: %s", svc.ServiceName, err)
  1385  				}
  1386  			}
  1387  
  1388  			if err := tx.Insert("index", &IndexEntry{serviceLastExtinctionIndexName, idx}); err != nil {
  1389  				return fmt.Errorf("failed updating missing service index: %s", err)
  1390  			}
  1391  
  1392  		}
  1393  	} else {
  1394  		return fmt.Errorf("Could not find any service %s: %s", svc.ServiceName, err)
  1395  	}
  1396  	return nil
  1397  }
  1398  
  1399  // EnsureCheck is used to store a check registration in the db.
  1400  func (s *Store) EnsureCheck(idx uint64, hc *structs.HealthCheck) error {
  1401  	tx := s.db.Txn(true)
  1402  	defer tx.Abort()
  1403  
  1404  	// Call the check registration
  1405  	if err := s.ensureCheckTxn(tx, idx, hc); err != nil {
  1406  		return err
  1407  	}
  1408  
  1409  	tx.Commit()
  1410  	return nil
  1411  }
  1412  
  1413  // updateAllServiceIndexesOfNode updates the Raft index of all the services associated with this node
  1414  func (s *Store) updateAllServiceIndexesOfNode(tx *memdb.Txn, idx uint64, nodeID string) error {
  1415  	services, err := tx.Get("services", "node", nodeID)
  1416  	if err != nil {
  1417  		return fmt.Errorf("failed updating services for node %s: %s", nodeID, err)
  1418  	}
  1419  	for service := services.Next(); service != nil; service = services.Next() {
  1420  		svc := service.(*structs.ServiceNode).ToNodeService()
  1421  		if err := tx.Insert("index", &IndexEntry{serviceIndexName(svc.Service), idx}); err != nil {
  1422  			return fmt.Errorf("failed updating index: %s", err)
  1423  		}
  1424  	}
  1425  	return nil
  1426  }
  1427  
  1428  // ensureCheckCASTxn updates a check only if the existing index matches the given index.
  1429  // Returns a bool indicating if a write happened and any error.
  1430  func (s *Store) ensureCheckCASTxn(tx *memdb.Txn, idx uint64, hc *structs.HealthCheck) (bool, error) {
  1431  	// Retrieve the existing entry.
  1432  	_, existing, err := s.getNodeCheckTxn(tx, hc.Node, hc.CheckID)
  1433  	if err != nil {
  1434  		return false, fmt.Errorf("failed health check lookup: %s", err)
  1435  	}
  1436  
  1437  	// Check if the we should do the set. A ModifyIndex of 0 means that
  1438  	// we are doing a set-if-not-exists.
  1439  	if hc.ModifyIndex == 0 && existing != nil {
  1440  		return false, nil
  1441  	}
  1442  	if hc.ModifyIndex != 0 && existing == nil {
  1443  		return false, nil
  1444  	}
  1445  	if existing != nil && hc.ModifyIndex != 0 && hc.ModifyIndex != existing.ModifyIndex {
  1446  		return false, nil
  1447  	}
  1448  
  1449  	// Perform the update.
  1450  	if err := s.ensureCheckTxn(tx, idx, hc); err != nil {
  1451  		return false, err
  1452  	}
  1453  
  1454  	return true, nil
  1455  }
  1456  
  1457  // ensureCheckTransaction is used as the inner method to handle inserting
  1458  // a health check into the state store. It ensures safety against inserting
  1459  // checks with no matching node or service.
  1460  func (s *Store) ensureCheckTxn(tx *memdb.Txn, idx uint64, hc *structs.HealthCheck) error {
  1461  	// Check if we have an existing health check
  1462  	existing, err := tx.First("checks", "id", hc.Node, string(hc.CheckID))
  1463  	if err != nil {
  1464  		return fmt.Errorf("failed health check lookup: %s", err)
  1465  	}
  1466  
  1467  	// Set the indexes
  1468  	if existing != nil {
  1469  		existingCheck := existing.(*structs.HealthCheck)
  1470  		hc.CreateIndex = existingCheck.CreateIndex
  1471  		hc.ModifyIndex = existingCheck.ModifyIndex
  1472  	} else {
  1473  		hc.CreateIndex = idx
  1474  		hc.ModifyIndex = idx
  1475  	}
  1476  
  1477  	// Use the default check status if none was provided
  1478  	if hc.Status == "" {
  1479  		hc.Status = api.HealthCritical
  1480  	}
  1481  
  1482  	// Get the node
  1483  	node, err := tx.First("nodes", "id", hc.Node)
  1484  	if err != nil {
  1485  		return fmt.Errorf("failed node lookup: %s", err)
  1486  	}
  1487  	if node == nil {
  1488  		return ErrMissingNode
  1489  	}
  1490  
  1491  	modified := true
  1492  	// If the check is associated with a service, check that we have
  1493  	// a registration for the service.
  1494  	if hc.ServiceID != "" {
  1495  		service, err := tx.First("services", "id", hc.Node, hc.ServiceID)
  1496  		if err != nil {
  1497  			return fmt.Errorf("failed service lookup: %s", err)
  1498  		}
  1499  		if service == nil {
  1500  			return ErrMissingService
  1501  		}
  1502  
  1503  		// Copy in the service name and tags
  1504  		svc := service.(*structs.ServiceNode)
  1505  		hc.ServiceName = svc.ServiceName
  1506  		hc.ServiceTags = svc.ServiceTags
  1507  		if existing != nil && existing.(*structs.HealthCheck).IsSame(hc) {
  1508  			modified = false
  1509  		} else {
  1510  			// Check has been modified, we trigger a index service change
  1511  			if err = tx.Insert("index", &IndexEntry{serviceIndexName(svc.ServiceName), idx}); err != nil {
  1512  				return fmt.Errorf("failed updating index: %s", err)
  1513  			}
  1514  		}
  1515  	} else {
  1516  		if existing != nil && existing.(*structs.HealthCheck).IsSame(hc) {
  1517  			modified = false
  1518  		} else {
  1519  			// Since the check has been modified, it impacts all services of node
  1520  			// Update the status for all the services associated with this node
  1521  			err = s.updateAllServiceIndexesOfNode(tx, idx, hc.Node)
  1522  			if err != nil {
  1523  				return err
  1524  			}
  1525  		}
  1526  	}
  1527  
  1528  	// Delete any sessions for this check if the health is critical.
  1529  	if hc.Status == api.HealthCritical {
  1530  		mappings, err := tx.Get("session_checks", "node_check", hc.Node, string(hc.CheckID))
  1531  		if err != nil {
  1532  			return fmt.Errorf("failed session checks lookup: %s", err)
  1533  		}
  1534  
  1535  		var ids []string
  1536  		for mapping := mappings.Next(); mapping != nil; mapping = mappings.Next() {
  1537  			ids = append(ids, mapping.(*sessionCheck).Session)
  1538  		}
  1539  
  1540  		// Delete the session in a separate loop so we don't trash the
  1541  		// iterator.
  1542  		for _, id := range ids {
  1543  			if err := s.deleteSessionTxn(tx, idx, id); err != nil {
  1544  				return fmt.Errorf("failed deleting session: %s", err)
  1545  			}
  1546  		}
  1547  	}
  1548  	if modified {
  1549  		// We update the modify index, ONLY if something has changed, thus
  1550  		// With constant output, no change is seen when watching a service
  1551  		// With huge number of nodes where anti-entropy updates continuously
  1552  		// the checks, but not the values within the check
  1553  		hc.ModifyIndex = idx
  1554  	}
  1555  
  1556  	// Persist the check registration in the db.
  1557  	if err := tx.Insert("checks", hc); err != nil {
  1558  		return fmt.Errorf("failed inserting check: %s", err)
  1559  	}
  1560  	if err := tx.Insert("index", &IndexEntry{"checks", idx}); err != nil {
  1561  		return fmt.Errorf("failed updating index: %s", err)
  1562  	}
  1563  
  1564  	return nil
  1565  }
  1566  
  1567  // NodeCheck is used to retrieve a specific check associated with the given
  1568  // node.
  1569  func (s *Store) NodeCheck(nodeName string, checkID types.CheckID) (uint64, *structs.HealthCheck, error) {
  1570  	tx := s.db.Txn(false)
  1571  	defer tx.Abort()
  1572  
  1573  	return s.getNodeCheckTxn(tx, nodeName, checkID)
  1574  }
  1575  
  1576  // nodeCheckTxn is used as the inner method to handle reading a health check
  1577  // from the state store.
  1578  func (s *Store) getNodeCheckTxn(tx *memdb.Txn, nodeName string, checkID types.CheckID) (uint64, *structs.HealthCheck, error) {
  1579  	// Get the table index.
  1580  	idx := maxIndexTxn(tx, "checks")
  1581  
  1582  	// Return the check.
  1583  	check, err := tx.First("checks", "id", nodeName, string(checkID))
  1584  	if err != nil {
  1585  		return 0, nil, fmt.Errorf("failed check lookup: %s", err)
  1586  	}
  1587  
  1588  	if check != nil {
  1589  		return idx, check.(*structs.HealthCheck), nil
  1590  	}
  1591  	return idx, nil, nil
  1592  }
  1593  
  1594  // NodeChecks is used to retrieve checks associated with the
  1595  // given node from the state store.
  1596  func (s *Store) NodeChecks(ws memdb.WatchSet, nodeName string) (uint64, structs.HealthChecks, error) {
  1597  	tx := s.db.Txn(false)
  1598  	defer tx.Abort()
  1599  
  1600  	// Get the table index.
  1601  	idx := maxIndexTxn(tx, "checks")
  1602  
  1603  	// Return the checks.
  1604  	iter, err := tx.Get("checks", "node", nodeName)
  1605  	if err != nil {
  1606  		return 0, nil, fmt.Errorf("failed check lookup: %s", err)
  1607  	}
  1608  	ws.Add(iter.WatchCh())
  1609  
  1610  	var results structs.HealthChecks
  1611  	for check := iter.Next(); check != nil; check = iter.Next() {
  1612  		results = append(results, check.(*structs.HealthCheck))
  1613  	}
  1614  	return idx, results, nil
  1615  }
  1616  
  1617  // ServiceChecks is used to get all checks associated with a
  1618  // given service ID. The query is performed against a service
  1619  // _name_ instead of a service ID.
  1620  func (s *Store) ServiceChecks(ws memdb.WatchSet, serviceName string) (uint64, structs.HealthChecks, error) {
  1621  	tx := s.db.Txn(false)
  1622  	defer tx.Abort()
  1623  
  1624  	// Get the table index.
  1625  	idx := maxIndexTxn(tx, "checks")
  1626  
  1627  	// Return the checks.
  1628  	iter, err := tx.Get("checks", "service", serviceName)
  1629  	if err != nil {
  1630  		return 0, nil, fmt.Errorf("failed check lookup: %s", err)
  1631  	}
  1632  	ws.Add(iter.WatchCh())
  1633  
  1634  	var results structs.HealthChecks
  1635  	for check := iter.Next(); check != nil; check = iter.Next() {
  1636  		results = append(results, check.(*structs.HealthCheck))
  1637  	}
  1638  	return idx, results, nil
  1639  }
  1640  
  1641  // ServiceChecksByNodeMeta is used to get all checks associated with a
  1642  // given service ID, filtered by the given node metadata values. The query
  1643  // is performed against a service _name_ instead of a service ID.
  1644  func (s *Store) ServiceChecksByNodeMeta(ws memdb.WatchSet, serviceName string,
  1645  	filters map[string]string) (uint64, structs.HealthChecks, error) {
  1646  
  1647  	tx := s.db.Txn(false)
  1648  	defer tx.Abort()
  1649  
  1650  	// Get the table index.
  1651  	idx := maxIndexForService(tx, serviceName, true, true)
  1652  	// Return the checks.
  1653  	iter, err := tx.Get("checks", "service", serviceName)
  1654  	if err != nil {
  1655  		return 0, nil, fmt.Errorf("failed check lookup: %s", err)
  1656  	}
  1657  	ws.Add(iter.WatchCh())
  1658  
  1659  	return s.parseChecksByNodeMeta(tx, ws, idx, iter, filters)
  1660  }
  1661  
  1662  // ChecksInState is used to query the state store for all checks
  1663  // which are in the provided state.
  1664  func (s *Store) ChecksInState(ws memdb.WatchSet, state string) (uint64, structs.HealthChecks, error) {
  1665  	tx := s.db.Txn(false)
  1666  	defer tx.Abort()
  1667  
  1668  	// Get the table index.
  1669  	idx := maxIndexTxn(tx, "checks")
  1670  
  1671  	// Query all checks if HealthAny is passed, otherwise use the index.
  1672  	var iter memdb.ResultIterator
  1673  	var err error
  1674  	if state == api.HealthAny {
  1675  		iter, err = tx.Get("checks", "status")
  1676  	} else {
  1677  		iter, err = tx.Get("checks", "status", state)
  1678  	}
  1679  	if err != nil {
  1680  		return 0, nil, fmt.Errorf("failed check lookup: %s", err)
  1681  	}
  1682  	ws.Add(iter.WatchCh())
  1683  
  1684  	var results structs.HealthChecks
  1685  	for check := iter.Next(); check != nil; check = iter.Next() {
  1686  		results = append(results, check.(*structs.HealthCheck))
  1687  	}
  1688  	return idx, results, nil
  1689  }
  1690  
  1691  // ChecksInStateByNodeMeta is used to query the state store for all checks
  1692  // which are in the provided state, filtered by the given node metadata values.
  1693  func (s *Store) ChecksInStateByNodeMeta(ws memdb.WatchSet, state string, filters map[string]string) (uint64, structs.HealthChecks, error) {
  1694  	tx := s.db.Txn(false)
  1695  	defer tx.Abort()
  1696  
  1697  	// Get the table index.
  1698  	idx := maxIndexTxn(tx, "nodes", "checks")
  1699  
  1700  	// Query all checks if HealthAny is passed, otherwise use the index.
  1701  	var iter memdb.ResultIterator
  1702  	var err error
  1703  	if state == api.HealthAny {
  1704  		iter, err = tx.Get("checks", "status")
  1705  		if err != nil {
  1706  			return 0, nil, fmt.Errorf("failed check lookup: %s", err)
  1707  		}
  1708  	} else {
  1709  		iter, err = tx.Get("checks", "status", state)
  1710  		if err != nil {
  1711  			return 0, nil, fmt.Errorf("failed check lookup: %s", err)
  1712  		}
  1713  	}
  1714  	ws.Add(iter.WatchCh())
  1715  
  1716  	return s.parseChecksByNodeMeta(tx, ws, idx, iter, filters)
  1717  }
  1718  
  1719  // parseChecksByNodeMeta is a helper function used to deduplicate some
  1720  // repetitive code for returning health checks filtered by node metadata fields.
  1721  func (s *Store) parseChecksByNodeMeta(tx *memdb.Txn, ws memdb.WatchSet,
  1722  	idx uint64, iter memdb.ResultIterator, filters map[string]string) (uint64, structs.HealthChecks, error) {
  1723  
  1724  	// We don't want to track an unlimited number of nodes, so we pull a
  1725  	// top-level watch to use as a fallback.
  1726  	allNodes, err := tx.Get("nodes", "id")
  1727  	if err != nil {
  1728  		return 0, nil, fmt.Errorf("failed nodes lookup: %s", err)
  1729  	}
  1730  	allNodesCh := allNodes.WatchCh()
  1731  
  1732  	// Only take results for nodes that satisfy the node metadata filters.
  1733  	var results structs.HealthChecks
  1734  	for check := iter.Next(); check != nil; check = iter.Next() {
  1735  		healthCheck := check.(*structs.HealthCheck)
  1736  		watchCh, node, err := tx.FirstWatch("nodes", "id", healthCheck.Node)
  1737  		if err != nil {
  1738  			return 0, nil, fmt.Errorf("failed node lookup: %s", err)
  1739  		}
  1740  		if node == nil {
  1741  			return 0, nil, ErrMissingNode
  1742  		}
  1743  
  1744  		// Add even the filtered nodes so we wake up if the node metadata
  1745  		// changes.
  1746  		ws.AddWithLimit(watchLimit, watchCh, allNodesCh)
  1747  		if structs.SatisfiesMetaFilters(node.(*structs.Node).Meta, filters) {
  1748  			results = append(results, healthCheck)
  1749  		}
  1750  	}
  1751  	return idx, results, nil
  1752  }
  1753  
  1754  // DeleteCheck is used to delete a health check registration.
  1755  func (s *Store) DeleteCheck(idx uint64, node string, checkID types.CheckID) error {
  1756  	tx := s.db.Txn(true)
  1757  	defer tx.Abort()
  1758  
  1759  	// Call the check deletion
  1760  	if err := s.deleteCheckTxn(tx, idx, node, checkID); err != nil {
  1761  		return err
  1762  	}
  1763  
  1764  	tx.Commit()
  1765  	return nil
  1766  }
  1767  
  1768  // deleteCheckCASTxn is used to try doing a check delete operation with a given
  1769  // raft index. If the CAS index specified is not equal to the last observed index for
  1770  // the given check, then the call is a noop, otherwise a normal check delete is invoked.
  1771  func (s *Store) deleteCheckCASTxn(tx *memdb.Txn, idx, cidx uint64, node string, checkID types.CheckID) (bool, error) {
  1772  	// Try to retrieve the existing health check.
  1773  	_, hc, err := s.getNodeCheckTxn(tx, node, checkID)
  1774  	if err != nil {
  1775  		return false, fmt.Errorf("check lookup failed: %s", err)
  1776  	}
  1777  	if hc == nil {
  1778  		return false, nil
  1779  	}
  1780  
  1781  	// If the existing index does not match the provided CAS
  1782  	// index arg, then we shouldn't update anything and can safely
  1783  	// return early here.
  1784  	if hc.ModifyIndex != cidx {
  1785  		return false, nil
  1786  	}
  1787  
  1788  	// Call the actual deletion if the above passed.
  1789  	if err := s.deleteCheckTxn(tx, idx, node, checkID); err != nil {
  1790  		return false, err
  1791  	}
  1792  
  1793  	return true, nil
  1794  }
  1795  
  1796  // deleteCheckTxn is the inner method used to call a health
  1797  // check deletion within an existing transaction.
  1798  func (s *Store) deleteCheckTxn(tx *memdb.Txn, idx uint64, node string, checkID types.CheckID) error {
  1799  	// Try to retrieve the existing health check.
  1800  	hc, err := tx.First("checks", "id", node, string(checkID))
  1801  	if err != nil {
  1802  		return fmt.Errorf("check lookup failed: %s", err)
  1803  	}
  1804  	if hc == nil {
  1805  		return nil
  1806  	}
  1807  	existing := hc.(*structs.HealthCheck)
  1808  	if existing != nil {
  1809  		// When no service is linked to this service, update all services of node
  1810  		if existing.ServiceID != "" {
  1811  			if err = tx.Insert("index", &IndexEntry{serviceIndexName(existing.ServiceName), idx}); err != nil {
  1812  				return fmt.Errorf("failed updating index: %s", err)
  1813  			}
  1814  		} else {
  1815  			err = s.updateAllServiceIndexesOfNode(tx, idx, existing.Node)
  1816  			if err != nil {
  1817  				return fmt.Errorf("Failed to update services linked to deleted healthcheck: %s", err)
  1818  			}
  1819  			if err := tx.Insert("index", &IndexEntry{"services", idx}); err != nil {
  1820  				return fmt.Errorf("failed updating index: %s", err)
  1821  			}
  1822  		}
  1823  	}
  1824  
  1825  	// Delete the check from the DB and update the index.
  1826  	if err := tx.Delete("checks", hc); err != nil {
  1827  		return fmt.Errorf("failed removing check: %s", err)
  1828  	}
  1829  	if err := tx.Insert("index", &IndexEntry{"checks", idx}); err != nil {
  1830  		return fmt.Errorf("failed updating index: %s", err)
  1831  	}
  1832  
  1833  	// Delete any sessions for this check.
  1834  	mappings, err := tx.Get("session_checks", "node_check", node, string(checkID))
  1835  	if err != nil {
  1836  		return fmt.Errorf("failed session checks lookup: %s", err)
  1837  	}
  1838  	var ids []string
  1839  	for mapping := mappings.Next(); mapping != nil; mapping = mappings.Next() {
  1840  		ids = append(ids, mapping.(*sessionCheck).Session)
  1841  	}
  1842  
  1843  	// Do the delete in a separate loop so we don't trash the iterator.
  1844  	for _, id := range ids {
  1845  		if err := s.deleteSessionTxn(tx, idx, id); err != nil {
  1846  			return fmt.Errorf("failed deleting session: %s", err)
  1847  		}
  1848  	}
  1849  
  1850  	return nil
  1851  }
  1852  
  1853  // CheckServiceNodes is used to query all nodes and checks for a given service.
  1854  func (s *Store) CheckServiceNodes(ws memdb.WatchSet, serviceName string) (uint64, structs.CheckServiceNodes, error) {
  1855  	return s.checkServiceNodes(ws, serviceName, false)
  1856  }
  1857  
  1858  // CheckConnectServiceNodes is used to query all nodes and checks for Connect
  1859  // compatible endpoints for a given service.
  1860  func (s *Store) CheckConnectServiceNodes(ws memdb.WatchSet, serviceName string) (uint64, structs.CheckServiceNodes, error) {
  1861  	return s.checkServiceNodes(ws, serviceName, true)
  1862  }
  1863  
  1864  func (s *Store) checkServiceNodes(ws memdb.WatchSet, serviceName string, connect bool) (uint64, structs.CheckServiceNodes, error) {
  1865  	tx := s.db.Txn(false)
  1866  	defer tx.Abort()
  1867  
  1868  	// Function for lookup
  1869  	var f func() (memdb.ResultIterator, error)
  1870  	if !connect {
  1871  		f = func() (memdb.ResultIterator, error) {
  1872  			return tx.Get("services", "service", serviceName)
  1873  		}
  1874  	} else {
  1875  		f = func() (memdb.ResultIterator, error) {
  1876  			return tx.Get("services", "connect", serviceName)
  1877  		}
  1878  	}
  1879  
  1880  	// Query the state store for the service.
  1881  	iter, err := f()
  1882  	if err != nil {
  1883  		return 0, nil, fmt.Errorf("failed service lookup: %s", err)
  1884  	}
  1885  	ws.Add(iter.WatchCh())
  1886  
  1887  	// Return the results.
  1888  	var results structs.ServiceNodes
  1889  	for service := iter.Next(); service != nil; service = iter.Next() {
  1890  		results = append(results, service.(*structs.ServiceNode))
  1891  	}
  1892  
  1893  	// Get the table index.
  1894  	idx := maxIndexForService(tx, serviceName, len(results) > 0, true)
  1895  
  1896  	return s.parseCheckServiceNodes(tx, ws, idx, serviceName, results, err)
  1897  }
  1898  
  1899  // CheckServiceTagNodes is used to query all nodes and checks for a given
  1900  // service, filtering out services that don't contain the given tag.
  1901  func (s *Store) CheckServiceTagNodes(ws memdb.WatchSet, serviceName string, tags []string) (uint64, structs.CheckServiceNodes, error) {
  1902  	tx := s.db.Txn(false)
  1903  	defer tx.Abort()
  1904  
  1905  	// Query the state store for the service.
  1906  	iter, err := tx.Get("services", "service", serviceName)
  1907  	if err != nil {
  1908  		return 0, nil, fmt.Errorf("failed service lookup: %s", err)
  1909  	}
  1910  	ws.Add(iter.WatchCh())
  1911  
  1912  	// Return the results, filtering by tag.
  1913  	serviceExists := false
  1914  	var results structs.ServiceNodes
  1915  	for service := iter.Next(); service != nil; service = iter.Next() {
  1916  		svc := service.(*structs.ServiceNode)
  1917  		serviceExists = true
  1918  		if !serviceTagsFilter(svc, tags) {
  1919  			results = append(results, svc)
  1920  		}
  1921  	}
  1922  
  1923  	// Get the table index.
  1924  	idx := maxIndexForService(tx, serviceName, serviceExists, true)
  1925  	return s.parseCheckServiceNodes(tx, ws, idx, serviceName, results, err)
  1926  }
  1927  
  1928  // parseCheckServiceNodes is used to parse through a given set of services,
  1929  // and query for an associated node and a set of checks. This is the inner
  1930  // method used to return a rich set of results from a more simple query.
  1931  func (s *Store) parseCheckServiceNodes(
  1932  	tx *memdb.Txn, ws memdb.WatchSet, idx uint64,
  1933  	serviceName string, services structs.ServiceNodes,
  1934  	err error) (uint64, structs.CheckServiceNodes, error) {
  1935  	if err != nil {
  1936  		return 0, nil, err
  1937  	}
  1938  
  1939  	// Special-case the zero return value to nil, since this ends up in
  1940  	// external APIs.
  1941  	if len(services) == 0 {
  1942  		return idx, nil, nil
  1943  	}
  1944  
  1945  	// We don't want to track an unlimited number of nodes, so we pull a
  1946  	// top-level watch to use as a fallback.
  1947  	allNodes, err := tx.Get("nodes", "id")
  1948  	if err != nil {
  1949  		return 0, nil, fmt.Errorf("failed nodes lookup: %s", err)
  1950  	}
  1951  	allNodesCh := allNodes.WatchCh()
  1952  
  1953  	// We need a similar fallback for checks. Since services need the
  1954  	// status of node + service-specific checks, we pull in a top-level
  1955  	// watch over all checks.
  1956  	allChecks, err := tx.Get("checks", "id")
  1957  	if err != nil {
  1958  		return 0, nil, fmt.Errorf("failed checks lookup: %s", err)
  1959  	}
  1960  	allChecksCh := allChecks.WatchCh()
  1961  
  1962  	results := make(structs.CheckServiceNodes, 0, len(services))
  1963  	for _, sn := range services {
  1964  		// Retrieve the node.
  1965  		watchCh, n, err := tx.FirstWatch("nodes", "id", sn.Node)
  1966  		if err != nil {
  1967  			return 0, nil, fmt.Errorf("failed node lookup: %s", err)
  1968  		}
  1969  		ws.AddWithLimit(watchLimit, watchCh, allNodesCh)
  1970  
  1971  		if n == nil {
  1972  			return 0, nil, ErrMissingNode
  1973  		}
  1974  		node := n.(*structs.Node)
  1975  
  1976  		// First add the node-level checks. These always apply to any
  1977  		// service on the node.
  1978  		var checks structs.HealthChecks
  1979  		iter, err := tx.Get("checks", "node_service_check", sn.Node, false)
  1980  		if err != nil {
  1981  			return 0, nil, err
  1982  		}
  1983  		ws.AddWithLimit(watchLimit, iter.WatchCh(), allChecksCh)
  1984  		for check := iter.Next(); check != nil; check = iter.Next() {
  1985  			checks = append(checks, check.(*structs.HealthCheck))
  1986  		}
  1987  
  1988  		// Now add the service-specific checks.
  1989  		iter, err = tx.Get("checks", "node_service", sn.Node, sn.ServiceID)
  1990  		if err != nil {
  1991  			return 0, nil, err
  1992  		}
  1993  		ws.AddWithLimit(watchLimit, iter.WatchCh(), allChecksCh)
  1994  		for check := iter.Next(); check != nil; check = iter.Next() {
  1995  			checks = append(checks, check.(*structs.HealthCheck))
  1996  		}
  1997  
  1998  		// Append to the results.
  1999  		results = append(results, structs.CheckServiceNode{
  2000  			Node:    node,
  2001  			Service: sn.ToNodeService(),
  2002  			Checks:  checks,
  2003  		})
  2004  	}
  2005  
  2006  	return idx, results, nil
  2007  }
  2008  
  2009  // NodeInfo is used to generate a dump of a single node. The dump includes
  2010  // all services and checks which are registered against the node.
  2011  func (s *Store) NodeInfo(ws memdb.WatchSet, node string) (uint64, structs.NodeDump, error) {
  2012  	tx := s.db.Txn(false)
  2013  	defer tx.Abort()
  2014  
  2015  	// Get the table index.
  2016  	idx := maxIndexTxn(tx, "nodes", "services", "checks")
  2017  
  2018  	// Query the node by the passed node
  2019  	nodes, err := tx.Get("nodes", "id", node)
  2020  	if err != nil {
  2021  		return 0, nil, fmt.Errorf("failed node lookup: %s", err)
  2022  	}
  2023  	ws.Add(nodes.WatchCh())
  2024  	return s.parseNodes(tx, ws, idx, nodes)
  2025  }
  2026  
  2027  // NodeDump is used to generate a dump of all nodes. This call is expensive
  2028  // as it has to query every node, service, and check. The response can also
  2029  // be quite large since there is currently no filtering applied.
  2030  func (s *Store) NodeDump(ws memdb.WatchSet) (uint64, structs.NodeDump, error) {
  2031  	tx := s.db.Txn(false)
  2032  	defer tx.Abort()
  2033  
  2034  	// Get the table index.
  2035  	idx := maxIndexTxn(tx, "nodes", "services", "checks")
  2036  
  2037  	// Fetch all of the registered nodes
  2038  	nodes, err := tx.Get("nodes", "id")
  2039  	if err != nil {
  2040  		return 0, nil, fmt.Errorf("failed node lookup: %s", err)
  2041  	}
  2042  	ws.Add(nodes.WatchCh())
  2043  	return s.parseNodes(tx, ws, idx, nodes)
  2044  }
  2045  
  2046  // parseNodes takes an iterator over a set of nodes and returns a struct
  2047  // containing the nodes along with all of their associated services
  2048  // and/or health checks.
  2049  func (s *Store) parseNodes(tx *memdb.Txn, ws memdb.WatchSet, idx uint64,
  2050  	iter memdb.ResultIterator) (uint64, structs.NodeDump, error) {
  2051  
  2052  	// We don't want to track an unlimited number of services, so we pull a
  2053  	// top-level watch to use as a fallback.
  2054  	allServices, err := tx.Get("services", "id")
  2055  	if err != nil {
  2056  		return 0, nil, fmt.Errorf("failed services lookup: %s", err)
  2057  	}
  2058  	allServicesCh := allServices.WatchCh()
  2059  
  2060  	// We need a similar fallback for checks.
  2061  	allChecks, err := tx.Get("checks", "id")
  2062  	if err != nil {
  2063  		return 0, nil, fmt.Errorf("failed checks lookup: %s", err)
  2064  	}
  2065  	allChecksCh := allChecks.WatchCh()
  2066  
  2067  	var results structs.NodeDump
  2068  	for n := iter.Next(); n != nil; n = iter.Next() {
  2069  		node := n.(*structs.Node)
  2070  
  2071  		// Create the wrapped node
  2072  		dump := &structs.NodeInfo{
  2073  			ID:              node.ID,
  2074  			Node:            node.Node,
  2075  			Address:         node.Address,
  2076  			TaggedAddresses: node.TaggedAddresses,
  2077  			Meta:            node.Meta,
  2078  		}
  2079  
  2080  		// Query the node services
  2081  		services, err := tx.Get("services", "node", node.Node)
  2082  		if err != nil {
  2083  			return 0, nil, fmt.Errorf("failed services lookup: %s", err)
  2084  		}
  2085  		ws.AddWithLimit(watchLimit, services.WatchCh(), allServicesCh)
  2086  		for service := services.Next(); service != nil; service = services.Next() {
  2087  			ns := service.(*structs.ServiceNode).ToNodeService()
  2088  			dump.Services = append(dump.Services, ns)
  2089  		}
  2090  
  2091  		// Query the node checks
  2092  		checks, err := tx.Get("checks", "node", node.Node)
  2093  		if err != nil {
  2094  			return 0, nil, fmt.Errorf("failed node lookup: %s", err)
  2095  		}
  2096  		ws.AddWithLimit(watchLimit, checks.WatchCh(), allChecksCh)
  2097  		for check := checks.Next(); check != nil; check = checks.Next() {
  2098  			hc := check.(*structs.HealthCheck)
  2099  			dump.Checks = append(dump.Checks, hc)
  2100  		}
  2101  
  2102  		// Add the result to the slice
  2103  		results = append(results, dump)
  2104  	}
  2105  	return idx, results, nil
  2106  }