1package api
2
3// QueryDatacenterOptions sets options about how we fail over if there are no
4// healthy nodes in the local datacenter.
5type QueryDatacenterOptions struct {
6	// NearestN is set to the number of remote datacenters to try, based on
7	// network coordinates.
8	NearestN int
9
10	// Datacenters is a fixed list of datacenters to try after NearestN. We
11	// never try a datacenter multiple times, so those are subtracted from
12	// this list before proceeding.
13	Datacenters []string
14}
15
16// QueryDNSOptions controls settings when query results are served over DNS.
17type QueryDNSOptions struct {
18	// TTL is the time to live for the served DNS results.
19	TTL string
20}
21
22// ServiceQuery is used to query for a set of healthy nodes offering a specific
23// service.
24type ServiceQuery struct {
25	// Service is the service to query.
26	Service string
27
28	// Namespace of the service to query
29	Namespace string `json:",omitempty"`
30
31	// Near allows baking in the name of a node to automatically distance-
32	// sort from. The magic "_agent" value is supported, which sorts near
33	// the agent which initiated the request by default.
34	Near string
35
36	// Failover controls what we do if there are no healthy nodes in the
37	// local datacenter.
38	Failover QueryDatacenterOptions
39
40	// IgnoreCheckIDs is an optional list of health check IDs to ignore when
41	// considering which nodes are healthy. It is useful as an emergency measure
42	// to temporarily override some health check that is producing false negatives
43	// for example.
44	IgnoreCheckIDs []string
45
46	// If OnlyPassing is true then we will only include nodes with passing
47	// health checks (critical AND warning checks will cause a node to be
48	// discarded)
49	OnlyPassing bool
50
51	// Tags are a set of required and/or disallowed tags. If a tag is in
52	// this list it must be present. If the tag is preceded with "!" then
53	// it is disallowed.
54	Tags []string
55
56	// NodeMeta is a map of required node metadata fields. If a key/value
57	// pair is in this map it must be present on the node in order for the
58	// service entry to be returned.
59	NodeMeta map[string]string
60
61	// ServiceMeta is a map of required service metadata fields. If a key/value
62	// pair is in this map it must be present on the node in order for the
63	// service entry to be returned.
64	ServiceMeta map[string]string
65
66	// Connect if true will filter the prepared query results to only
67	// include Connect-capable services. These include both native services
68	// and proxies for matching services. Note that if a proxy matches,
69	// the constraints in the query above (Near, OnlyPassing, etc.) apply
70	// to the _proxy_ and not the service being proxied. In practice, proxies
71	// should be directly next to their services so this isn't an issue.
72	Connect bool
73}
74
75// QueryTemplate carries the arguments for creating a templated query.
76type QueryTemplate struct {
77	// Type specifies the type of the query template. Currently only
78	// "name_prefix_match" is supported. This field is required.
79	Type string
80
81	// Regexp allows specifying a regex pattern to match against the name
82	// of the query being executed.
83	Regexp string
84}
85
86// PreparedQueryDefinition defines a complete prepared query.
87type PreparedQueryDefinition struct {
88	// ID is this UUID-based ID for the query, always generated by Consul.
89	ID string
90
91	// Name is an optional friendly name for the query supplied by the
92	// user. NOTE - if this feature is used then it will reduce the security
93	// of any read ACL associated with this query/service since this name
94	// can be used to locate nodes with supplying any ACL.
95	Name string
96
97	// Session is an optional session to tie this query's lifetime to. If
98	// this is omitted then the query will not expire.
99	Session string
100
101	// Token is the ACL token used when the query was created, and it is
102	// used when a query is subsequently executed. This token, or a token
103	// with management privileges, must be used to change the query later.
104	Token string
105
106	// Service defines a service query (leaving things open for other types
107	// later).
108	Service ServiceQuery
109
110	// DNS has options that control how the results of this query are
111	// served over DNS.
112	DNS QueryDNSOptions
113
114	// Template is used to pass through the arguments for creating a
115	// prepared query with an attached template. If a template is given,
116	// interpolations are possible in other struct fields.
117	Template QueryTemplate
118}
119
120// PreparedQueryExecuteResponse has the results of executing a query.
121type PreparedQueryExecuteResponse struct {
122	// Service is the service that was queried.
123	Service string
124
125	// Namespace of the service that was queried
126	Namespace string `json:",omitempty"`
127
128	// Nodes has the nodes that were output by the query.
129	Nodes []ServiceEntry
130
131	// DNS has the options for serving these results over DNS.
132	DNS QueryDNSOptions
133
134	// Datacenter is the datacenter that these results came from.
135	Datacenter string
136
137	// Failovers is a count of how many times we had to query a remote
138	// datacenter.
139	Failovers int
140}
141
142// PreparedQuery can be used to query the prepared query endpoints.
143type PreparedQuery struct {
144	c *Client
145}
146
147// PreparedQuery returns a handle to the prepared query endpoints.
148func (c *Client) PreparedQuery() *PreparedQuery {
149	return &PreparedQuery{c}
150}
151
152// Create makes a new prepared query. The ID of the new query is returned.
153func (c *PreparedQuery) Create(query *PreparedQueryDefinition, q *WriteOptions) (string, *WriteMeta, error) {
154	r := c.c.newRequest("POST", "/v1/query")
155	r.setWriteOptions(q)
156	r.obj = query
157	rtt, resp, err := requireOK(c.c.doRequest(r))
158	if err != nil {
159		return "", nil, err
160	}
161	defer closeResponseBody(resp)
162
163	wm := &WriteMeta{}
164	wm.RequestTime = rtt
165
166	var out struct{ ID string }
167	if err := decodeBody(resp, &out); err != nil {
168		return "", nil, err
169	}
170	return out.ID, wm, nil
171}
172
173// Update makes updates to an existing prepared query.
174func (c *PreparedQuery) Update(query *PreparedQueryDefinition, q *WriteOptions) (*WriteMeta, error) {
175	return c.c.write("/v1/query/"+query.ID, query, nil, q)
176}
177
178// List is used to fetch all the prepared queries (always requires a management
179// token).
180func (c *PreparedQuery) List(q *QueryOptions) ([]*PreparedQueryDefinition, *QueryMeta, error) {
181	var out []*PreparedQueryDefinition
182	qm, err := c.c.query("/v1/query", &out, q)
183	if err != nil {
184		return nil, nil, err
185	}
186	return out, qm, nil
187}
188
189// Get is used to fetch a specific prepared query.
190func (c *PreparedQuery) Get(queryID string, q *QueryOptions) ([]*PreparedQueryDefinition, *QueryMeta, error) {
191	var out []*PreparedQueryDefinition
192	qm, err := c.c.query("/v1/query/"+queryID, &out, q)
193	if err != nil {
194		return nil, nil, err
195	}
196	return out, qm, nil
197}
198
199// Delete is used to delete a specific prepared query.
200func (c *PreparedQuery) Delete(queryID string, q *WriteOptions) (*WriteMeta, error) {
201	r := c.c.newRequest("DELETE", "/v1/query/"+queryID)
202	r.setWriteOptions(q)
203	rtt, resp, err := requireOK(c.c.doRequest(r))
204	if err != nil {
205		return nil, err
206	}
207	defer closeResponseBody(resp)
208
209	wm := &WriteMeta{}
210	wm.RequestTime = rtt
211	return wm, nil
212}
213
214// Execute is used to execute a specific prepared query. You can execute using
215// a query ID or name.
216func (c *PreparedQuery) Execute(queryIDOrName string, q *QueryOptions) (*PreparedQueryExecuteResponse, *QueryMeta, error) {
217	var out *PreparedQueryExecuteResponse
218	qm, err := c.c.query("/v1/query/"+queryIDOrName+"/execute", &out, q)
219	if err != nil {
220		return nil, nil, err
221	}
222	return out, qm, nil
223}
224