1package structs
2
3import (
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.
13type 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.
25type 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.
32type 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	// EnterpriseMeta is the embedded enterprise metadata
81	EnterpriseMeta `hcl:",squash" mapstructure:",squash"`
82}
83
84const (
85	// QueryTemplateTypeNamePrefixMatch uses the Name field of the query as
86	// a prefix to select the template.
87	QueryTemplateTypeNamePrefixMatch = "name_prefix_match"
88)
89
90// QueryTemplateOptions controls settings if this query is a template.
91type QueryTemplateOptions struct {
92	// Type, if non-empty, means that this query is a template. This is
93	// set to one of the QueryTemplateType* constants above.
94	Type string
95
96	// Regexp is an optional regular expression to use to parse the full
97	// name, once the prefix match has selected a template. This can be
98	// used to extract parts of the name and choose a service name, set
99	// tags, etc.
100	Regexp string
101
102	// RemoveEmptyTags, if true, removes empty tags from matched tag list
103	RemoveEmptyTags bool
104}
105
106// PreparedQuery defines a complete prepared query, and is the structure we
107// maintain in the state store.
108type PreparedQuery struct {
109	// ID is this UUID-based ID for the query, always generated by Consul.
110	ID string
111
112	// Name is an optional friendly name for the query supplied by the
113	// user. NOTE - if this feature is used then it will reduce the security
114	// of any read ACL associated with this query/service since this name
115	// can be used to locate nodes with supplying any ACL.
116	Name string
117
118	// Session is an optional session to tie this query's lifetime to. If
119	// this is omitted then the query will not expire.
120	Session string
121
122	// Token is the ACL token used when the query was created, and it is
123	// used when a query is subsequently executed. This token, or a token
124	// with management privileges, must be used to change the query later.
125	Token string
126
127	// Template is used to configure this query as a template, which will
128	// respond to queries based on the Name, and then will be rendered
129	// before it is executed.
130	Template QueryTemplateOptions
131
132	// Service defines a service query (leaving things open for other types
133	// later).
134	Service ServiceQuery
135
136	// DNS has options that control how the results of this query are
137	// served over DNS.
138	DNS QueryDNSOptions
139
140	RaftIndex
141}
142
143// GetACLPrefix returns the prefix to look up the prepared_query ACL policy for
144// this query, and whether the prefix applies to this query. You always need to
145// check the ok value before using the prefix.
146func (pq *PreparedQuery) GetACLPrefix() (string, bool) {
147	if pq.Name != "" || pq.Template.Type != "" {
148		return pq.Name, true
149	}
150
151	return "", false
152}
153
154type PreparedQueries []*PreparedQuery
155
156type IndexedPreparedQueries struct {
157	Queries PreparedQueries
158	QueryMeta
159}
160
161type PreparedQueryOp string
162
163const (
164	PreparedQueryCreate PreparedQueryOp = "create"
165	PreparedQueryUpdate PreparedQueryOp = "update"
166	PreparedQueryDelete PreparedQueryOp = "delete"
167)
168
169// QueryRequest is used to create or change prepared queries.
170type PreparedQueryRequest struct {
171	// Datacenter is the target this request is intended for.
172	Datacenter string
173
174	// Op is the operation to apply.
175	Op PreparedQueryOp
176
177	// Query is the query itself.
178	Query *PreparedQuery
179
180	// WriteRequest holds the ACL token to go along with this request.
181	WriteRequest
182}
183
184// RequestDatacenter returns the datacenter for a given request.
185func (q *PreparedQueryRequest) RequestDatacenter() string {
186	return q.Datacenter
187}
188
189// PreparedQuerySpecificRequest is used to get information about a prepared
190// query.
191type PreparedQuerySpecificRequest struct {
192	// Datacenter is the target this request is intended for.
193	Datacenter string
194
195	// QueryID is the ID of a query.
196	QueryID string
197
198	// QueryOptions (unfortunately named here) controls the consistency
199	// settings for the query lookup itself, as well as the service lookups.
200	QueryOptions
201}
202
203// RequestDatacenter returns the datacenter for a given request.
204func (q *PreparedQuerySpecificRequest) RequestDatacenter() string {
205	return q.Datacenter
206}
207
208// PreparedQueryExecuteRequest is used to execute a prepared query.
209type PreparedQueryExecuteRequest struct {
210	// Datacenter is the target this request is intended for.
211	Datacenter string
212
213	// QueryIDOrName is the ID of a query _or_ the name of one, either can
214	// be provided.
215	QueryIDOrName string
216
217	// Limit will trim the resulting list down to the given limit.
218	Limit int
219
220	// Connect will force results to be Connect-enabled nodes for the
221	// matching services. This is equivalent in semantics exactly to
222	// setting "Connect" in the query template itself, but allows callers
223	// to use any prepared query in a Connect setting.
224	Connect bool
225
226	// Source is used to sort the results relative to a given node using
227	// network coordinates.
228	Source QuerySource
229
230	// Agent is used to carry around a reference to the agent which initiated
231	// the execute request. Used to distance-sort relative to the local node.
232	Agent QuerySource
233
234	// QueryOptions (unfortunately named here) controls the consistency
235	// settings for the query lookup itself, as well as the service lookups.
236	QueryOptions
237}
238
239// RequestDatacenter returns the datacenter for a given request.
240func (q *PreparedQueryExecuteRequest) RequestDatacenter() string {
241	return q.Datacenter
242}
243
244// CacheInfo implements cache.Request allowing requests to be cached on agent.
245func (q *PreparedQueryExecuteRequest) CacheInfo() cache.RequestInfo {
246	info := cache.RequestInfo{
247		Token:          q.Token,
248		Datacenter:     q.Datacenter,
249		MinIndex:       q.MinQueryIndex,
250		Timeout:        q.MaxQueryTime,
251		MaxAge:         q.MaxAge,
252		MustRevalidate: q.MustRevalidate,
253	}
254
255	// To calculate the cache key we hash over all the fields that affect the
256	// output other than Datacenter and Token which are dealt with in the cache
257	// framework already. Note the order here is important for the outcome - if we
258	// ever care about cache-invalidation on updates e.g. because we persist
259	// cached results, we need to be careful we maintain the same order of fields
260	// here. We could alternatively use `hash:set` struct tag on an anonymous
261	// struct to make it more robust if it becomes significant.
262	v, err := hashstructure.Hash([]interface{}{
263		q.QueryIDOrName,
264		q.Limit,
265		q.Connect,
266	}, nil)
267	if err == nil {
268		// If there is an error, we don't set the key. A blank key forces
269		// no cache for this request so the request is forwarded directly
270		// to the server.
271		info.Key = strconv.FormatUint(v, 10)
272	}
273
274	return info
275}
276
277// PreparedQueryExecuteRemoteRequest is used when running a local query in a
278// remote datacenter.
279type PreparedQueryExecuteRemoteRequest struct {
280	// Datacenter is the target this request is intended for.
281	Datacenter string
282
283	// Query is a copy of the query to execute.  We have to ship the entire
284	// query over since it won't be present in the remote state store.
285	Query PreparedQuery
286
287	// Limit will trim the resulting list down to the given limit.
288	Limit int
289
290	// Connect is the same as ExecuteRequest.
291	Connect bool
292
293	// QueryOptions (unfortunately named here) controls the consistency
294	// settings for the the service lookups.
295	QueryOptions
296}
297
298// RequestDatacenter returns the datacenter for a given request.
299func (q *PreparedQueryExecuteRemoteRequest) RequestDatacenter() string {
300	return q.Datacenter
301}
302
303// PreparedQueryExecuteResponse has the results of executing a query.
304type PreparedQueryExecuteResponse struct {
305	// Service is the service that was queried.
306	Service string
307
308	// EnterpriseMeta of the service that was queried.
309	EnterpriseMeta
310
311	// Nodes has the nodes that were output by the query.
312	Nodes CheckServiceNodes
313
314	// DNS has the options for serving these results over DNS.
315	DNS QueryDNSOptions
316
317	// Datacenter is the datacenter that these results came from.
318	Datacenter string
319
320	// Failovers is a count of how many times we had to query a remote
321	// datacenter.
322	Failovers int
323
324	// QueryMeta has freshness information about the query.
325	QueryMeta
326}
327
328// PreparedQueryExplainResponse has the results when explaining a query/
329type PreparedQueryExplainResponse struct {
330	// Query has the fully-rendered query.
331	Query PreparedQuery
332
333	// QueryMeta has freshness information about the query.
334	QueryMeta
335}
336