github.com/outbrain/consul@v1.4.5/agent/structs/prepared_query.go (about)

     1  package structs
     2  
     3  import (
     4  	"strconv"
     5  
     6  	"github.com/hashicorp/consul/agent/cache"
     7  	"github.com/hashicorp/consul/types"
     8  	"github.com/mitchellh/hashstructure"
     9  )
    10  
    11  // QueryDatacenterOptions sets options about how we fail over if there are no
    12  // healthy nodes in the local datacenter.
    13  type QueryDatacenterOptions struct {
    14  	// NearestN is set to the number of remote datacenters to try, based on
    15  	// network coordinates.
    16  	NearestN int
    17  
    18  	// Datacenters is a fixed list of datacenters to try after NearestN. We
    19  	// never try a datacenter multiple times, so those are subtracted from
    20  	// this list before proceeding.
    21  	Datacenters []string
    22  }
    23  
    24  // QueryDNSOptions controls settings when query results are served over DNS.
    25  type QueryDNSOptions struct {
    26  	// TTL is the time to live for the served DNS results.
    27  	TTL string
    28  }
    29  
    30  // ServiceQuery is used to query for a set of healthy nodes offering a specific
    31  // service.
    32  type ServiceQuery struct {
    33  	// Service is the service to query.
    34  	Service string
    35  
    36  	// Failover controls what we do if there are no healthy nodes in the
    37  	// local datacenter.
    38  	Failover QueryDatacenterOptions
    39  
    40  	// If OnlyPassing is true then we will only include nodes with passing
    41  	// health checks (critical AND warning checks will cause a node to be
    42  	// discarded)
    43  	OnlyPassing bool
    44  
    45  	// IgnoreCheckIDs is an optional list of health check IDs to ignore when
    46  	// considering which nodes are healthy. It is useful as an emergency measure
    47  	// to temporarily override some health check that is producing false negatives
    48  	// for example.
    49  	IgnoreCheckIDs []types.CheckID
    50  
    51  	// Near allows the query to always prefer the node nearest the given
    52  	// node. If the node does not exist, results are returned in their
    53  	// normal randomly-shuffled order. Supplying the magic "_agent" value
    54  	// is supported to sort near the agent which initiated the request.
    55  	Near string
    56  
    57  	// Tags are a set of required and/or disallowed tags. If a tag is in
    58  	// this list it must be present. If the tag is preceded with "!" then
    59  	// it is disallowed.
    60  	Tags []string
    61  
    62  	// NodeMeta is a map of required node metadata fields. If a key/value
    63  	// pair is in this map it must be present on the node in order for the
    64  	// service entry to be returned.
    65  	NodeMeta map[string]string
    66  
    67  	// ServiceMeta is a map of required service metadata fields. If a key/value
    68  	// pair is in this map it must be present on the node in order for the
    69  	// service entry to be returned.
    70  	ServiceMeta map[string]string
    71  
    72  	// Connect if true will filter the prepared query results to only
    73  	// include Connect-capable services. These include both native services
    74  	// and proxies for matching services. Note that if a proxy matches,
    75  	// the constraints in the query above (Near, OnlyPassing, etc.) apply
    76  	// to the _proxy_ and not the service being proxied. In practice, proxies
    77  	// should be directly next to their services so this isn't an issue.
    78  	Connect bool
    79  }
    80  
    81  const (
    82  	// QueryTemplateTypeNamePrefixMatch uses the Name field of the query as
    83  	// a prefix to select the template.
    84  	QueryTemplateTypeNamePrefixMatch = "name_prefix_match"
    85  )
    86  
    87  // QueryTemplateOptions controls settings if this query is a template.
    88  type QueryTemplateOptions struct {
    89  	// Type, if non-empty, means that this query is a template. This is
    90  	// set to one of the QueryTemplateType* constants above.
    91  	Type string
    92  
    93  	// Regexp is an optional regular expression to use to parse the full
    94  	// name, once the prefix match has selected a template. This can be
    95  	// used to extract parts of the name and choose a service name, set
    96  	// tags, etc.
    97  	Regexp string
    98  
    99  	// RemoveEmptyTags, if true, removes empty tags from matched tag list
   100  	RemoveEmptyTags bool
   101  }
   102  
   103  // PreparedQuery defines a complete prepared query, and is the structure we
   104  // maintain in the state store.
   105  type PreparedQuery struct {
   106  	// ID is this UUID-based ID for the query, always generated by Consul.
   107  	ID string
   108  
   109  	// Name is an optional friendly name for the query supplied by the
   110  	// user. NOTE - if this feature is used then it will reduce the security
   111  	// of any read ACL associated with this query/service since this name
   112  	// can be used to locate nodes with supplying any ACL.
   113  	Name string
   114  
   115  	// Session is an optional session to tie this query's lifetime to. If
   116  	// this is omitted then the query will not expire.
   117  	Session string
   118  
   119  	// Token is the ACL token used when the query was created, and it is
   120  	// used when a query is subsequently executed. This token, or a token
   121  	// with management privileges, must be used to change the query later.
   122  	Token string
   123  
   124  	// Template is used to configure this query as a template, which will
   125  	// respond to queries based on the Name, and then will be rendered
   126  	// before it is executed.
   127  	Template QueryTemplateOptions
   128  
   129  	// Service defines a service query (leaving things open for other types
   130  	// later).
   131  	Service ServiceQuery
   132  
   133  	// DNS has options that control how the results of this query are
   134  	// served over DNS.
   135  	DNS QueryDNSOptions
   136  
   137  	RaftIndex
   138  }
   139  
   140  // GetACLPrefix returns the prefix to look up the prepared_query ACL policy for
   141  // this query, and whether the prefix applies to this query. You always need to
   142  // check the ok value before using the prefix.
   143  func (pq *PreparedQuery) GetACLPrefix() (string, bool) {
   144  	if pq.Name != "" || pq.Template.Type != "" {
   145  		return pq.Name, true
   146  	}
   147  
   148  	return "", false
   149  }
   150  
   151  type PreparedQueries []*PreparedQuery
   152  
   153  type IndexedPreparedQueries struct {
   154  	Queries PreparedQueries
   155  	QueryMeta
   156  }
   157  
   158  type PreparedQueryOp string
   159  
   160  const (
   161  	PreparedQueryCreate PreparedQueryOp = "create"
   162  	PreparedQueryUpdate PreparedQueryOp = "update"
   163  	PreparedQueryDelete PreparedQueryOp = "delete"
   164  )
   165  
   166  // QueryRequest is used to create or change prepared queries.
   167  type PreparedQueryRequest struct {
   168  	// Datacenter is the target this request is intended for.
   169  	Datacenter string
   170  
   171  	// Op is the operation to apply.
   172  	Op PreparedQueryOp
   173  
   174  	// Query is the query itself.
   175  	Query *PreparedQuery
   176  
   177  	// WriteRequest holds the ACL token to go along with this request.
   178  	WriteRequest
   179  }
   180  
   181  // RequestDatacenter returns the datacenter for a given request.
   182  func (q *PreparedQueryRequest) RequestDatacenter() string {
   183  	return q.Datacenter
   184  }
   185  
   186  // PreparedQuerySpecificRequest is used to get information about a prepared
   187  // query.
   188  type PreparedQuerySpecificRequest struct {
   189  	// Datacenter is the target this request is intended for.
   190  	Datacenter string
   191  
   192  	// QueryID is the ID of a query.
   193  	QueryID string
   194  
   195  	// QueryOptions (unfortunately named here) controls the consistency
   196  	// settings for the query lookup itself, as well as the service lookups.
   197  	QueryOptions
   198  }
   199  
   200  // RequestDatacenter returns the datacenter for a given request.
   201  func (q *PreparedQuerySpecificRequest) RequestDatacenter() string {
   202  	return q.Datacenter
   203  }
   204  
   205  // PreparedQueryExecuteRequest is used to execute a prepared query.
   206  type PreparedQueryExecuteRequest struct {
   207  	// Datacenter is the target this request is intended for.
   208  	Datacenter string
   209  
   210  	// QueryIDOrName is the ID of a query _or_ the name of one, either can
   211  	// be provided.
   212  	QueryIDOrName string
   213  
   214  	// Limit will trim the resulting list down to the given limit.
   215  	Limit int
   216  
   217  	// Connect will force results to be Connect-enabled nodes for the
   218  	// matching services. This is equivalent in semantics exactly to
   219  	// setting "Connect" in the query template itself, but allows callers
   220  	// to use any prepared query in a Connect setting.
   221  	Connect bool
   222  
   223  	// Source is used to sort the results relative to a given node using
   224  	// network coordinates.
   225  	Source QuerySource
   226  
   227  	// Agent is used to carry around a reference to the agent which initiated
   228  	// the execute request. Used to distance-sort relative to the local node.
   229  	Agent QuerySource
   230  
   231  	// QueryOptions (unfortunately named here) controls the consistency
   232  	// settings for the query lookup itself, as well as the service lookups.
   233  	QueryOptions
   234  }
   235  
   236  // RequestDatacenter returns the datacenter for a given request.
   237  func (q *PreparedQueryExecuteRequest) RequestDatacenter() string {
   238  	return q.Datacenter
   239  }
   240  
   241  // CacheInfo implements cache.Request allowing requests to be cached on agent.
   242  func (q *PreparedQueryExecuteRequest) CacheInfo() cache.RequestInfo {
   243  	info := cache.RequestInfo{
   244  		Token:          q.Token,
   245  		Datacenter:     q.Datacenter,
   246  		MinIndex:       q.MinQueryIndex,
   247  		Timeout:        q.MaxQueryTime,
   248  		MaxAge:         q.MaxAge,
   249  		MustRevalidate: q.MustRevalidate,
   250  	}
   251  
   252  	// To calculate the cache key we hash over all the fields that affect the
   253  	// output other than Datacenter and Token which are dealt with in the cache
   254  	// framework already. Note the order here is important for the outcome - if we
   255  	// ever care about cache-invalidation on updates e.g. because we persist
   256  	// cached results, we need to be careful we maintain the same order of fields
   257  	// here. We could alternatively use `hash:set` struct tag on an anonymous
   258  	// struct to make it more robust if it becomes significant.
   259  	v, err := hashstructure.Hash([]interface{}{
   260  		q.QueryIDOrName,
   261  		q.Limit,
   262  		q.Connect,
   263  	}, nil)
   264  	if err == nil {
   265  		// If there is an error, we don't set the key. A blank key forces
   266  		// no cache for this request so the request is forwarded directly
   267  		// to the server.
   268  		info.Key = strconv.FormatUint(v, 10)
   269  	}
   270  
   271  	return info
   272  }
   273  
   274  // PreparedQueryExecuteRemoteRequest is used when running a local query in a
   275  // remote datacenter.
   276  type PreparedQueryExecuteRemoteRequest struct {
   277  	// Datacenter is the target this request is intended for.
   278  	Datacenter string
   279  
   280  	// Query is a copy of the query to execute.  We have to ship the entire
   281  	// query over since it won't be present in the remote state store.
   282  	Query PreparedQuery
   283  
   284  	// Limit will trim the resulting list down to the given limit.
   285  	Limit int
   286  
   287  	// Connect is the same as ExecuteRequest.
   288  	Connect bool
   289  
   290  	// QueryOptions (unfortunately named here) controls the consistency
   291  	// settings for the the service lookups.
   292  	QueryOptions
   293  }
   294  
   295  // RequestDatacenter returns the datacenter for a given request.
   296  func (q *PreparedQueryExecuteRemoteRequest) RequestDatacenter() string {
   297  	return q.Datacenter
   298  }
   299  
   300  // PreparedQueryExecuteResponse has the results of executing a query.
   301  type PreparedQueryExecuteResponse struct {
   302  	// Service is the service that was queried.
   303  	Service string
   304  
   305  	// Nodes has the nodes that were output by the query.
   306  	Nodes CheckServiceNodes
   307  
   308  	// DNS has the options for serving these results over DNS.
   309  	DNS QueryDNSOptions
   310  
   311  	// Datacenter is the datacenter that these results came from.
   312  	Datacenter string
   313  
   314  	// Failovers is a count of how many times we had to query a remote
   315  	// datacenter.
   316  	Failovers int
   317  
   318  	// QueryMeta has freshness information about the query.
   319  	QueryMeta
   320  }
   321  
   322  // PreparedQueryExplainResponse has the results when explaining a query/
   323  type PreparedQueryExplainResponse struct {
   324  	// Query has the fully-rendered query.
   325  	Query PreparedQuery
   326  
   327  	// QueryMeta has freshness information about the query.
   328  	QueryMeta
   329  }