forked from linkerd/linkerd2-proxy-api
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdestination.proto
351 lines (297 loc) · 12.2 KB
/
destination.proto
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
syntax = "proto3";
package io.linkerd.proxy.destination;
option go_package = "github.com/linkerd/linkerd2-proxy-api/go/destination";
import "google/protobuf/duration.proto";
import "http_types.proto";
import "net.proto";
/// Destination Service ///
//
// This is the service discovery API. Given a destination, this returns a
// weighted set of addresses and address metadata. Can be implemented with DNS
// or lookups against other service discovery backends.
//
// If the service does not exist then the controller must send
// `no_endpoints{exists: false}` ASAP when a client subscribes or when the
// service stops existing. If the service exists and has endpoints available
// then the controller must send `add` that lists all (or at least a large
// number) of the endpoints for the service. If and only if the service exists
// but does not have any endpoints available then the controller SHOULD send
// `no_endpoints{exists: true}` when a client subscribes. In other words, the
// `no_endpoints` message must only be sent when there are *no*endpoints for
// the service.
//
// The controller is expected to send an Update every time there is a
// change in service discovery.
//
// The client MUST be prepared to receive messages in any order and the client
// MUST be able to cope with the presence or absence of redundant messages.
//
// `no_endpoints` followed by an `add` is *not* equivalent to just sending the
// `add` regardless of the value of the `exists` field in the `no_endpoints`
// message. `remove` followed by a `no_endpoints` message is equivalent to
// sending just the `no_endpoints` message, and a `remove` that removes the
// last endpoint is equivalent to a `no_endpoints{exists: true}` message.
//
// When the client gets disconnected from the controller and reconnects, the
// client may use stale results from its previous subscription until, and only
// until, it receives the first message. This is why the controller must send
// a message at the start of a subscription. This is also why the controller
// must not send a `no_endpoints` message before an `add` message; the client
// would clear its cached messages between the time it receives the
// `no_endpoints` message and the time it receives the `add` message, which is
// not the desired behavior.
service Destination {
// Given a destination, return all addresses in that destination as a long-
// running stream of updates.
rpc Get(GetDestination) returns(stream Update) {}
// Given a destination, return that destination's profile and send an update
// whenever it changes.
rpc GetProfile(GetDestination) returns(stream DestinationProfile) {}
}
message GetDestination {
string scheme = 1;
string path = 2;
// An opaque value that is set at injection-time and sent with destintion
// lookups.
//
// If, for instance, the token encodes a namespace or some locality
// information, the service may alter its results to take this locality into
// account.
string context_token = 3;
}
message Update {
oneof update {
// A new set of endpoints are available for the service. The set might be
// empty.
WeightedAddrSet add = 1;
// Some endpoints have been removed from the service.
AddrSet remove = 2;
// `no_endpoints{exists: false}` indicates that the service does not exist
// and the client MAY try an alternate service discovery method (e.g. DNS).
//
// `no_endpoints(exists: true)` indicates that the service does exist and
// the client MUST NOT fall back to an alternate service discovery method.
NoEndpoints no_endpoints = 3;
}
}
message AddrSet { repeated net.TcpAddress addrs = 1; }
message WeightedAddrSet {
repeated WeightedAddr addrs = 1;
map<string, string> metric_labels = 2;
}
message WeightedAddr {
net.TcpAddress addr = 1;
uint32 weight = 3;
map<string, string> metric_labels = 4;
TlsIdentity tls_identity = 5;
ProtocolHint protocol_hint = 6;
AuthorityOverride authority_override = 7;
// The HTTP/2 parameters to use when connecting to the destination, if HTTP/2
// is used. These parameters are used by proxies when the application traffic
// is HTTP/2 or when the H2 ProtocolHint is used to transport HTTP/1
// connections over HTTP/2.
Http2ClientParams http2 = 8;
}
message TlsIdentity {
reserved 2;
reserved "k8s_pod_identity";
oneof strategy {
DnsLikeIdentity dns_like_identity = 1;
UriLikeIdentity uri_like_identity = 3;
}
// The server name of the endpoint. This is the value that needs to be included
// by clients in the ClientHello SNI extension of the TLS handshake when they
// initiate TLS connections to servers.
DnsLikeIdentity server_name = 4;
// Verify the certificate based on the Kubernetes pod identity.
message DnsLikeIdentity {
// A DNS-like name that encodes workload coordinates.
//
// For example:
// {name}.{namespace}.{type}.identity.{control-namespace}.{trust-domain...}
string name = 1;
}
// Verify the certificate based on an URI identity.
message UriLikeIdentity {
// A URI name that encodes workload identity.
//
// For example:
// spiffe://trust-domain/workload-dentifier
string uri = 1;
}
}
message AuthorityOverride { string authority_override = 1; }
message NoEndpoints { bool exists = 1; }
// A hint of what protocol the service knows. The default value is
// for the `hint` field to be not be set, essentially meaning "unknown".
message ProtocolHint {
oneof protocol {
// Hints that the service understands HTTP2 and the proxy's internal
// http2-upgrade mechanism.
H2 h2 = 1;
// Hints that the destination will handle this connection as an opaque TCP
// stream, and (if `opaque_transport` is set) that the proxy should not send
// a `SessionProtocol` as part of its transport header.
Opaque opaque = 3;
}
message H2 {}
message Opaque {}
// When set, indicates that the target supports receiving opaque traffic
// wrapped with the Linkerd connection header on the specified port.
OpaqueTransport opaque_transport = 2;
message OpaqueTransport {
// The target proxy's inbound port.
uint32 inbound_port = 1;
}
}
// Configures the parameters used to initialize an HTTP/2 connection.
message Http2ClientParams {
// Overrides the default client flow control settings.
FlowControl flow_control = 1;
// Enables keep-alive timeouts.
KeepAlive keep_alive = 2;
// Configures Hyper internals.
Internals internals = 3;
message FlowControl {
// Configures the maximum connection-level flow control window size.
uint32 initial_connection_window_size = 1;
// Configures the maximum stream-level flow control window size.
uint32 initial_stream_window_size = 2;
// Enables Hyper's adaptive flow control, ignoring other window settings.
bool adaptive_flow_control = 3;
}
message KeepAlive {
// The time between pings.
google.protobuf.Duration interval = 1;
// The time to wait for a ping response before considering the connection
// dead.
google.protobuf.Duration timeout = 2;
// Whether to send pings when there is no other traffic.
bool while_idle = 3;
}
message Internals {
uint32 max_concurrent_reset_streams = 1;
uint32 max_frame_size = 2;
uint32 max_send_buf_size = 3;
}
}
message DestinationProfile {
// The fully-qualified service name, if one exists.
//
// When resolving (especially by IP), this field provides the fully-qualified
// name of the resolved service, if one exists. This field does NOT include
// any port information. E.g. a lookup for 10.2.3.4:8080 might have a name
// like `foo.bar.svc.cluster.local`.
//
// Implementations MAY provide names for non-service IP-lookups (e.g., pod or
// node dns names), but this is not required.
//
// If the lookup does not refer to a known named entity, this field MUST be
// left empty.
string fully_qualified_name = 5;
// Indicates that connections on this service address should be handled as
// opaque TCP streams. HTTP routes returned on for such services will be
// ignored.
bool opaque_protocol = 4;
// A list of routes, each with a RequestMatch. If a request matches
// more than one route, the first match wins.
repeated Route routes = 1;
// The retry budget controls how much additional load the proxy can generate
// as retries. Failured requests on retryable routes will not be retried if
// there is no available budget.
RetryBudget retry_budget = 2;
// If this list is non-empty, requests to this destination should instead be
// split between the destinations in this list. Each destination should
// receive a portion of the requests proportional to its weight. If this
// list is empty, requests should be sent to this destination as normal.
repeated WeightedDst dst_overrides = 3;
// If this field is set, it indicates that the target is a known endpoint (and
// not a service address). The values of `fully_qualified_name` and
// `dst_overrides` will be ignored for the purposes of service discovery--
// traffic split and load balancing will be skipped and the single endpoint
// are used.
//
// No endpoint should be set If the target is unknown.
WeightedAddr endpoint = 6;
}
message Route {
// This route contains requests which match this condition.
RequestMatch condition = 1;
// A list of response classes for this route. If a response matches
// more than one ResponseClass, the first match wins. If a response does not
// match any ResponseClasses, it is considered to be a successful response.
repeated ResponseClass response_classes = 2;
// Metric labels to attach to requests and responses that match this route.
map<string, string> metrics_labels = 3;
// If a route is retryable, any failed requests on that route may be retried
// by the proxy.
bool is_retryable = 4;
// After this time has elapsed since receiving the initial request, any
// outstanding request will be cancelled, a timeout error response will be
// returned, and no more retries will be attempted.
google.protobuf.Duration timeout = 5;
}
message RetryBudget {
// The ratio of additional traffic that may be added by retries. A
// retry_ratio of 0.1 means that 1 retry may be attempted for every 10 regular
// requests. A retry_ratio of 1.0 means that 1 retry may be attempted for
// every 1 regular request (in other words, total request load may be doubled
// as a result of retries).
float retry_ratio = 1;
// The proxy may always attempt this number of retries per second, even if it
// would violate the retry_ratio. This is to allow retries to happen even
// when the request rate is very low.
uint32 min_retries_per_second = 2;
// This duration indicates for how long requests should be considered for the
// purposes of enforcing the retry_ratio. A higher value considers a larger
// window and therefore allows burstier retries.
google.protobuf.Duration ttl = 3;
}
message ResponseClass {
// This class contains responses which match this condition.
ResponseMatch condition = 1;
// If responses in this class should be considered failures. This defaults
// to false (success).
bool is_failure = 2;
}
message RequestMatch {
message Seq { repeated RequestMatch matches = 1; }
oneof match {
Seq all = 1;
Seq any = 2;
RequestMatch not = 3;
PathMatch path = 4;
http_types.HttpMethod method = 5;
// TODO: match on arbitrary header
}
}
message PathMatch {
// Match if the request path matches this regex.
string regex = 1;
}
message ResponseMatch {
message Seq { repeated ResponseMatch matches = 1; }
oneof match {
Seq all = 1;
Seq any = 2;
ResponseMatch not = 3;
HttpStatusRange status = 4;
// TODO: match on arbitrary header or trailer
}
}
// If either a minimum or maximum is not specified, the range is considered to
// be over a discrete value.
message HttpStatusRange {
// Minimum matching http status code (inclusive), if specified.
uint32 min = 1;
// Maximum matching http status code (inclusive), if specified.
uint32 max = 2;
}
message WeightedDst {
// This authority will be used as the `path` in a call to the Destination.Get
// rpc.
string authority = 1;
// The proportion of requests to send to this destination. This value is
// relative to other weights in the same dst_overrides list.
uint32 weight = 2;
}