blob: 407a3b08e37d4d42bb80ba52b0b429b3c89a7fac [file] [log] [blame]
divyadesai81bb7ba2020-03-11 11:45:23 +00001package api
2
3import (
4 "encoding/json"
5 "fmt"
6 "time"
7)
8
9// DiscoveryChain can be used to query the discovery-chain endpoints
10type DiscoveryChain struct {
11 c *Client
12}
13
14// DiscoveryChain returns a handle to the discovery-chain endpoints
15func (c *Client) DiscoveryChain() *DiscoveryChain {
16 return &DiscoveryChain{c}
17}
18
19func (d *DiscoveryChain) Get(name string, opts *DiscoveryChainOptions, q *QueryOptions) (*DiscoveryChainResponse, *QueryMeta, error) {
20 if name == "" {
21 return nil, nil, fmt.Errorf("Name parameter must not be empty")
22 }
23
24 method := "GET"
25 if opts != nil && opts.requiresPOST() {
26 method = "POST"
27 }
28
29 r := d.c.newRequest(method, fmt.Sprintf("/v1/discovery-chain/%s", name))
30 r.setQueryOptions(q)
31
32 if opts != nil {
33 if opts.EvaluateInDatacenter != "" {
34 r.params.Set("compile-dc", opts.EvaluateInDatacenter)
35 }
36 // TODO(namespaces): handle possible EvaluateInNamespace here
37 }
38
39 if method == "POST" {
40 r.obj = opts
41 }
42
43 rtt, resp, err := requireOK(d.c.doRequest(r))
44 if err != nil {
45 return nil, nil, err
46 }
47 defer resp.Body.Close()
48
49 qm := &QueryMeta{}
50 parseQueryMeta(resp, qm)
51 qm.RequestTime = rtt
52
53 var out DiscoveryChainResponse
54
55 if err := decodeBody(resp, &out); err != nil {
56 return nil, nil, err
57 }
58
59 return &out, qm, nil
60}
61
62type DiscoveryChainOptions struct {
63 EvaluateInDatacenter string `json:"-"`
64
65 // OverrideMeshGateway allows for the mesh gateway setting to be overridden
66 // for any resolver in the compiled chain.
67 OverrideMeshGateway MeshGatewayConfig `json:",omitempty"`
68
69 // OverrideProtocol allows for the final protocol for the chain to be
70 // altered.
71 //
72 // - If the chain ordinarily would be TCP and an L7 protocol is passed here
73 // the chain will not include Routers or Splitters.
74 //
75 // - If the chain ordinarily would be L7 and TCP is passed here the chain
76 // will not include Routers or Splitters.
77 OverrideProtocol string `json:",omitempty"`
78
79 // OverrideConnectTimeout allows for the ConnectTimeout setting to be
80 // overridden for any resolver in the compiled chain.
81 OverrideConnectTimeout time.Duration `json:",omitempty"`
82}
83
84func (o *DiscoveryChainOptions) requiresPOST() bool {
85 if o == nil {
86 return false
87 }
88 return o.OverrideMeshGateway.Mode != "" ||
89 o.OverrideProtocol != "" ||
90 o.OverrideConnectTimeout != 0
91}
92
93type DiscoveryChainResponse struct {
94 Chain *CompiledDiscoveryChain
95}
96
97type CompiledDiscoveryChain struct {
98 ServiceName string
99 Namespace string
100 Datacenter string
101
102 // CustomizationHash is a unique hash of any data that affects the
103 // compilation of the discovery chain other than config entries or the
104 // name/namespace/datacenter evaluation criteria.
105 //
106 // If set, this value should be used to prefix/suffix any generated load
107 // balancer data plane objects to avoid sharing customized and
108 // non-customized versions.
109 CustomizationHash string
110
111 // Protocol is the overall protocol shared by everything in the chain.
112 Protocol string
113
114 // StartNode is the first key into the Nodes map that should be followed
115 // when walking the discovery chain.
116 StartNode string
117
118 // Nodes contains all nodes available for traversal in the chain keyed by a
119 // unique name. You can walk this by starting with StartNode.
120 //
121 // NOTE: The names should be treated as opaque values and are only
122 // guaranteed to be consistent within a single compilation.
123 Nodes map[string]*DiscoveryGraphNode
124
125 // Targets is a list of all targets used in this chain.
126 //
127 // NOTE: The names should be treated as opaque values and are only
128 // guaranteed to be consistent within a single compilation.
129 Targets map[string]*DiscoveryTarget
130}
131
132const (
133 DiscoveryGraphNodeTypeRouter = "router"
134 DiscoveryGraphNodeTypeSplitter = "splitter"
135 DiscoveryGraphNodeTypeResolver = "resolver"
136)
137
138// DiscoveryGraphNode is a single node in the compiled discovery chain.
139type DiscoveryGraphNode struct {
140 Type string
141 Name string // this is NOT necessarily a service
142
143 // fields for Type==router
144 Routes []*DiscoveryRoute
145
146 // fields for Type==splitter
147 Splits []*DiscoverySplit
148
149 // fields for Type==resolver
150 Resolver *DiscoveryResolver
151}
152
153// compiled form of ServiceRoute
154type DiscoveryRoute struct {
155 Definition *ServiceRoute
156 NextNode string
157}
158
159// compiled form of ServiceSplit
160type DiscoverySplit struct {
161 Weight float32
162 NextNode string
163}
164
165// compiled form of ServiceResolverConfigEntry
166type DiscoveryResolver struct {
167 Default bool
168 ConnectTimeout time.Duration
169 Target string
170 Failover *DiscoveryFailover
171}
172
173func (r *DiscoveryResolver) MarshalJSON() ([]byte, error) {
174 type Alias DiscoveryResolver
175 exported := &struct {
176 ConnectTimeout string `json:",omitempty"`
177 *Alias
178 }{
179 ConnectTimeout: r.ConnectTimeout.String(),
180 Alias: (*Alias)(r),
181 }
182 if r.ConnectTimeout == 0 {
183 exported.ConnectTimeout = ""
184 }
185
186 return json.Marshal(exported)
187}
188
189func (r *DiscoveryResolver) UnmarshalJSON(data []byte) error {
190 type Alias DiscoveryResolver
191 aux := &struct {
192 ConnectTimeout string
193 *Alias
194 }{
195 Alias: (*Alias)(r),
196 }
197 if err := json.Unmarshal(data, &aux); err != nil {
198 return err
199 }
200 var err error
201 if aux.ConnectTimeout != "" {
202 if r.ConnectTimeout, err = time.ParseDuration(aux.ConnectTimeout); err != nil {
203 return err
204 }
205 }
206 return nil
207}
208
209// compiled form of ServiceResolverFailover
210type DiscoveryFailover struct {
211 Targets []string
212}
213
214// DiscoveryTarget represents all of the inputs necessary to use a resolver
215// config entry to execute a catalog query to generate a list of service
216// instances during discovery.
217type DiscoveryTarget struct {
218 ID string
219
220 Service string
221 ServiceSubset string
222 Namespace string
223 Datacenter string
224
225 MeshGateway MeshGatewayConfig
226 Subset ServiceResolverSubset
227 External bool
228 SNI string
229 Name string
230}