blob: 3fb055342c0662c6b4ce1a4d567484ae3b236631 [file] [log] [blame]
divyadesai81bb7ba2020-03-11 11:45:23 +00001package api
2
3import (
4 "net"
5 "strconv"
6)
7
8type Weights struct {
9 Passing int
10 Warning int
11}
12
13type Node struct {
14 ID string
15 Node string
16 Address string
17 Datacenter string
18 TaggedAddresses map[string]string
19 Meta map[string]string
20 CreateIndex uint64
21 ModifyIndex uint64
22}
23
24type ServiceAddress struct {
25 Address string
26 Port int
27}
28
29type CatalogService struct {
30 ID string
31 Node string
32 Address string
33 Datacenter string
34 TaggedAddresses map[string]string
35 NodeMeta map[string]string
36 ServiceID string
37 ServiceName string
38 ServiceAddress string
39 ServiceTaggedAddresses map[string]ServiceAddress
40 ServiceTags []string
41 ServiceMeta map[string]string
42 ServicePort int
43 ServiceWeights Weights
44 ServiceEnableTagOverride bool
45 ServiceProxy *AgentServiceConnectProxyConfig
46 CreateIndex uint64
47 Checks HealthChecks
48 ModifyIndex uint64
49}
50
51type CatalogNode struct {
52 Node *Node
53 Services map[string]*AgentService
54}
55
56type CatalogRegistration struct {
57 ID string
58 Node string
59 Address string
60 TaggedAddresses map[string]string
61 NodeMeta map[string]string
62 Datacenter string
63 Service *AgentService
64 Check *AgentCheck
65 Checks HealthChecks
66 SkipNodeUpdate bool
67}
68
69type CatalogDeregistration struct {
70 Node string
71 Address string // Obsolete.
72 Datacenter string
73 ServiceID string
74 CheckID string
75}
76
77// Catalog can be used to query the Catalog endpoints
78type Catalog struct {
79 c *Client
80}
81
82// Catalog returns a handle to the catalog endpoints
83func (c *Client) Catalog() *Catalog {
84 return &Catalog{c}
85}
86
87func (c *Catalog) Register(reg *CatalogRegistration, q *WriteOptions) (*WriteMeta, error) {
88 r := c.c.newRequest("PUT", "/v1/catalog/register")
89 r.setWriteOptions(q)
90 r.obj = reg
91 rtt, resp, err := requireOK(c.c.doRequest(r))
92 if err != nil {
93 return nil, err
94 }
95 resp.Body.Close()
96
97 wm := &WriteMeta{}
98 wm.RequestTime = rtt
99
100 return wm, nil
101}
102
103func (c *Catalog) Deregister(dereg *CatalogDeregistration, q *WriteOptions) (*WriteMeta, error) {
104 r := c.c.newRequest("PUT", "/v1/catalog/deregister")
105 r.setWriteOptions(q)
106 r.obj = dereg
107 rtt, resp, err := requireOK(c.c.doRequest(r))
108 if err != nil {
109 return nil, err
110 }
111 resp.Body.Close()
112
113 wm := &WriteMeta{}
114 wm.RequestTime = rtt
115
116 return wm, nil
117}
118
119// Datacenters is used to query for all the known datacenters
120func (c *Catalog) Datacenters() ([]string, error) {
121 r := c.c.newRequest("GET", "/v1/catalog/datacenters")
122 _, resp, err := requireOK(c.c.doRequest(r))
123 if err != nil {
124 return nil, err
125 }
126 defer resp.Body.Close()
127
128 var out []string
129 if err := decodeBody(resp, &out); err != nil {
130 return nil, err
131 }
132 return out, nil
133}
134
135// Nodes is used to query all the known nodes
136func (c *Catalog) Nodes(q *QueryOptions) ([]*Node, *QueryMeta, error) {
137 r := c.c.newRequest("GET", "/v1/catalog/nodes")
138 r.setQueryOptions(q)
139 rtt, resp, err := requireOK(c.c.doRequest(r))
140 if err != nil {
141 return nil, nil, err
142 }
143 defer resp.Body.Close()
144
145 qm := &QueryMeta{}
146 parseQueryMeta(resp, qm)
147 qm.RequestTime = rtt
148
149 var out []*Node
150 if err := decodeBody(resp, &out); err != nil {
151 return nil, nil, err
152 }
153 return out, qm, nil
154}
155
156// Services is used to query for all known services
157func (c *Catalog) Services(q *QueryOptions) (map[string][]string, *QueryMeta, error) {
158 r := c.c.newRequest("GET", "/v1/catalog/services")
159 r.setQueryOptions(q)
160 rtt, resp, err := requireOK(c.c.doRequest(r))
161 if err != nil {
162 return nil, nil, err
163 }
164 defer resp.Body.Close()
165
166 qm := &QueryMeta{}
167 parseQueryMeta(resp, qm)
168 qm.RequestTime = rtt
169
170 var out map[string][]string
171 if err := decodeBody(resp, &out); err != nil {
172 return nil, nil, err
173 }
174 return out, qm, nil
175}
176
177// Service is used to query catalog entries for a given service
178func (c *Catalog) Service(service, tag string, q *QueryOptions) ([]*CatalogService, *QueryMeta, error) {
179 var tags []string
180 if tag != "" {
181 tags = []string{tag}
182 }
183 return c.service(service, tags, q, false)
184}
185
186// Supports multiple tags for filtering
187func (c *Catalog) ServiceMultipleTags(service string, tags []string, q *QueryOptions) ([]*CatalogService, *QueryMeta, error) {
188 return c.service(service, tags, q, false)
189}
190
191// Connect is used to query catalog entries for a given Connect-enabled service
192func (c *Catalog) Connect(service, tag string, q *QueryOptions) ([]*CatalogService, *QueryMeta, error) {
193 var tags []string
194 if tag != "" {
195 tags = []string{tag}
196 }
197 return c.service(service, tags, q, true)
198}
199
200// Supports multiple tags for filtering
201func (c *Catalog) ConnectMultipleTags(service string, tags []string, q *QueryOptions) ([]*CatalogService, *QueryMeta, error) {
202 return c.service(service, tags, q, true)
203}
204
205func (c *Catalog) service(service string, tags []string, q *QueryOptions, connect bool) ([]*CatalogService, *QueryMeta, error) {
206 path := "/v1/catalog/service/" + service
207 if connect {
208 path = "/v1/catalog/connect/" + service
209 }
210 r := c.c.newRequest("GET", path)
211 r.setQueryOptions(q)
212 if len(tags) > 0 {
213 for _, tag := range tags {
214 r.params.Add("tag", tag)
215 }
216 }
217 rtt, resp, err := requireOK(c.c.doRequest(r))
218 if err != nil {
219 return nil, nil, err
220 }
221 defer resp.Body.Close()
222
223 qm := &QueryMeta{}
224 parseQueryMeta(resp, qm)
225 qm.RequestTime = rtt
226
227 var out []*CatalogService
228 if err := decodeBody(resp, &out); err != nil {
229 return nil, nil, err
230 }
231 return out, qm, nil
232}
233
234// Node is used to query for service information about a single node
235func (c *Catalog) Node(node string, q *QueryOptions) (*CatalogNode, *QueryMeta, error) {
236 r := c.c.newRequest("GET", "/v1/catalog/node/"+node)
237 r.setQueryOptions(q)
238 rtt, resp, err := requireOK(c.c.doRequest(r))
239 if err != nil {
240 return nil, nil, err
241 }
242 defer resp.Body.Close()
243
244 qm := &QueryMeta{}
245 parseQueryMeta(resp, qm)
246 qm.RequestTime = rtt
247
248 var out *CatalogNode
249 if err := decodeBody(resp, &out); err != nil {
250 return nil, nil, err
251 }
252 return out, qm, nil
253}
254
255func ParseServiceAddr(addrPort string) (ServiceAddress, error) {
256 port := 0
257 host, portStr, err := net.SplitHostPort(addrPort)
258 if err == nil {
259 port, err = strconv.Atoi(portStr)
260 }
261 return ServiceAddress{Address: host, Port: port}, err
262}