linkerd2-proxy-api 0.7.0

Linkerd Proxy API gRPC bindings and utilities
Documentation
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
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetDestination {
    #[prost(string, tag="1")]
    pub scheme: ::prost::alloc::string::String,
    #[prost(string, tag="2")]
    pub path: ::prost::alloc::string::String,
    /// 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.
    #[prost(string, tag="3")]
    pub context_token: ::prost::alloc::string::String,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Update {
    #[prost(oneof="update::Update", tags="1, 2, 3")]
    pub update: ::core::option::Option<update::Update>,
}
/// Nested message and enum types in `Update`.
pub mod update {
    #[derive(Clone, PartialEq, ::prost::Oneof)]
    pub enum Update {
        /// A new set of endpoints are available for the service. The set might be
        /// empty.
        #[prost(message, tag="1")]
        Add(super::WeightedAddrSet),
        /// Some endpoints have been removed from the service.
        #[prost(message, tag="2")]
        Remove(super::AddrSet),
        /// `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.
        #[prost(message, tag="3")]
        NoEndpoints(super::NoEndpoints),
    }
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct AddrSet {
    #[prost(message, repeated, tag="1")]
    pub addrs: ::prost::alloc::vec::Vec<super::net::TcpAddress>,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct WeightedAddrSet {
    #[prost(message, repeated, tag="1")]
    pub addrs: ::prost::alloc::vec::Vec<WeightedAddr>,
    #[prost(map="string, string", tag="2")]
    pub metric_labels: ::std::collections::HashMap<::prost::alloc::string::String, ::prost::alloc::string::String>,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct WeightedAddr {
    #[prost(message, optional, tag="1")]
    pub addr: ::core::option::Option<super::net::TcpAddress>,
    #[prost(uint32, tag="3")]
    pub weight: u32,
    #[prost(map="string, string", tag="4")]
    pub metric_labels: ::std::collections::HashMap<::prost::alloc::string::String, ::prost::alloc::string::String>,
    #[prost(message, optional, tag="5")]
    pub tls_identity: ::core::option::Option<TlsIdentity>,
    #[prost(message, optional, tag="6")]
    pub protocol_hint: ::core::option::Option<ProtocolHint>,
    #[prost(message, optional, tag="7")]
    pub authority_override: ::core::option::Option<AuthorityOverride>,
}
/// Which strategy should be used for verifying TLS.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct TlsIdentity {
    #[prost(oneof="tls_identity::Strategy", tags="1")]
    pub strategy: ::core::option::Option<tls_identity::Strategy>,
}
/// Nested message and enum types in `TlsIdentity`.
pub mod tls_identity {
    /// Verify the certificate based on the Kubernetes pod identity.
    #[derive(Clone, PartialEq, ::prost::Message)]
    pub struct DnsLikeIdentity {
        /// A DNS-like name that encodes workload coordinates.
        ///
        /// For example:
        ///     {name}.{namespace}.{type}.identity.{control-namespace}.{trust-domain...}
        #[prost(string, tag="1")]
        pub name: ::prost::alloc::string::String,
    }
    #[derive(Clone, PartialEq, ::prost::Oneof)]
    pub enum Strategy {
        #[prost(message, tag="1")]
        DnsLikeIdentity(DnsLikeIdentity),
    }
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct AuthorityOverride {
    #[prost(string, tag="1")]
    pub authority_override: ::prost::alloc::string::String,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct NoEndpoints {
    #[prost(bool, tag="1")]
    pub exists: bool,
}
/// A hint of what protocol the service knows. The default value is
/// for the `hint` field to be not be set, essentially meaning "unknown".
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ProtocolHint {
    /// When set, indicates that the target supports receiving opaque traffic
    /// wrapped with the Linkerd connection header on the specified port.
    #[prost(message, optional, tag="2")]
    pub opaque_transport: ::core::option::Option<protocol_hint::OpaqueTransport>,
    #[prost(oneof="protocol_hint::Protocol", tags="1")]
    pub protocol: ::core::option::Option<protocol_hint::Protocol>,
}
/// Nested message and enum types in `ProtocolHint`.
pub mod protocol_hint {
    #[derive(Clone, PartialEq, ::prost::Message)]
    pub struct H2 {
    }
    #[derive(Clone, PartialEq, ::prost::Message)]
    pub struct OpaqueTransport {
        /// The target proxy's inbound port.
        #[prost(uint32, tag="1")]
        pub inbound_port: u32,
    }
    #[derive(Clone, PartialEq, ::prost::Oneof)]
    pub enum Protocol {
        /// Hints that the service understands HTTP2 and the proxy's internal
        /// http2-upgrade mechanism.
        #[prost(message, tag="1")]
        H2(H2),
    }
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct 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.
    #[prost(string, tag="5")]
    pub fully_qualified_name: ::prost::alloc::string::String,
    /// Indicates that connections on this service address should be handled as
    /// opaque TCP streams. HTTP routes returned on for such services will be
    /// ignored.
    #[prost(bool, tag="4")]
    pub opaque_protocol: bool,
    /// A list of routes, each with a RequestMatch.  If a request matches
    /// more than one route, the first match wins.
    #[prost(message, repeated, tag="1")]
    pub routes: ::prost::alloc::vec::Vec<Route>,
    /// 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.
    #[prost(message, optional, tag="2")]
    pub retry_budget: ::core::option::Option<RetryBudget>,
    /// 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.
    #[prost(message, repeated, tag="3")]
    pub dst_overrides: ::prost::alloc::vec::Vec<WeightedDst>,
    /// 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.
    #[prost(message, optional, tag="6")]
    pub endpoint: ::core::option::Option<WeightedAddr>,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Route {
    /// This route contains requests which match this condition.
    #[prost(message, optional, tag="1")]
    pub condition: ::core::option::Option<RequestMatch>,
    /// 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.
    #[prost(message, repeated, tag="2")]
    pub response_classes: ::prost::alloc::vec::Vec<ResponseClass>,
    /// Metric labels to attach to requests and responses that match this route.
    #[prost(map="string, string", tag="3")]
    pub metrics_labels: ::std::collections::HashMap<::prost::alloc::string::String, ::prost::alloc::string::String>,
    /// If a route is retryable, any failed requests on that route may be retried
    /// by the proxy.
    #[prost(bool, tag="4")]
    pub is_retryable: bool,
    /// 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.
    #[prost(message, optional, tag="5")]
    pub timeout: ::core::option::Option<::prost_types::Duration>,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct 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).
    #[prost(float, tag="1")]
    pub retry_ratio: f32,
    /// 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.
    #[prost(uint32, tag="2")]
    pub min_retries_per_second: u32,
    /// 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.
    #[prost(message, optional, tag="3")]
    pub ttl: ::core::option::Option<::prost_types::Duration>,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ResponseClass {
    /// This class contains responses which match this condition.
    #[prost(message, optional, tag="1")]
    pub condition: ::core::option::Option<ResponseMatch>,
    /// If responses in this class should be considered failures.  This defaults
    /// to false (success).
    #[prost(bool, tag="2")]
    pub is_failure: bool,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct RequestMatch {
    #[prost(oneof="request_match::Match", tags="1, 2, 3, 4, 5")]
    pub r#match: ::core::option::Option<request_match::Match>,
}
/// Nested message and enum types in `RequestMatch`.
pub mod request_match {
    #[derive(Clone, PartialEq, ::prost::Message)]
    pub struct Seq {
        #[prost(message, repeated, tag="1")]
        pub matches: ::prost::alloc::vec::Vec<super::RequestMatch>,
    }
    #[derive(Clone, PartialEq, ::prost::Oneof)]
    pub enum Match {
        #[prost(message, tag="1")]
        All(Seq),
        #[prost(message, tag="2")]
        Any(Seq),
        #[prost(message, tag="3")]
        Not(::prost::alloc::boxed::Box<super::RequestMatch>),
        #[prost(message, tag="4")]
        Path(super::PathMatch),
        /// TODO: match on arbitrary header
        #[prost(message, tag="5")]
        Method(super::super::http_types::HttpMethod),
    }
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct PathMatch {
    /// Match if the request path matches this regex.
    #[prost(string, tag="1")]
    pub regex: ::prost::alloc::string::String,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ResponseMatch {
    #[prost(oneof="response_match::Match", tags="1, 2, 3, 4")]
    pub r#match: ::core::option::Option<response_match::Match>,
}
/// Nested message and enum types in `ResponseMatch`.
pub mod response_match {
    #[derive(Clone, PartialEq, ::prost::Message)]
    pub struct Seq {
        #[prost(message, repeated, tag="1")]
        pub matches: ::prost::alloc::vec::Vec<super::ResponseMatch>,
    }
    #[derive(Clone, PartialEq, ::prost::Oneof)]
    pub enum Match {
        #[prost(message, tag="1")]
        All(Seq),
        #[prost(message, tag="2")]
        Any(Seq),
        #[prost(message, tag="3")]
        Not(::prost::alloc::boxed::Box<super::ResponseMatch>),
        /// TODO: match on arbitrary header or trailer
        #[prost(message, tag="4")]
        Status(super::HttpStatusRange),
    }
}
/// If either a minimum or maximum is not specified, the range is considered to
/// be over a discrete value.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct HttpStatusRange {
    /// Minimum matching http status code (inclusive), if specified.
    #[prost(uint32, tag="1")]
    pub min: u32,
    /// Maximum matching http status code (inclusive), if specified.
    #[prost(uint32, tag="2")]
    pub max: u32,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct WeightedDst {
    /// This authority will be used as the `path` in a call to the Destination.Get
    /// rpc.
    #[prost(string, tag="1")]
    pub authority: ::prost::alloc::string::String,
    /// The proportion of requests to send to this destination.  This value is
    /// relative to other weights in the same dst_overrides list.
    #[prost(uint32, tag="2")]
    pub weight: u32,
}
/// Generated client implementations.
pub mod destination_client {
    #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)]
    use tonic::codegen::*;
    use tonic::codegen::http::Uri;
    #[derive(Debug, Clone)]
    pub struct DestinationClient<T> {
        inner: tonic::client::Grpc<T>,
    }
    impl<T> DestinationClient<T>
    where
        T: tonic::client::GrpcService<tonic::body::BoxBody>,
        T::Error: Into<StdError>,
        T::ResponseBody: Body<Data = Bytes> + Send + 'static,
        <T::ResponseBody as Body>::Error: Into<StdError> + Send,
    {
        pub fn new(inner: T) -> Self {
            let inner = tonic::client::Grpc::new(inner);
            Self { inner }
        }
        pub fn with_origin(inner: T, origin: Uri) -> Self {
            let inner = tonic::client::Grpc::with_origin(inner, origin);
            Self { inner }
        }
        pub fn with_interceptor<F>(
            inner: T,
            interceptor: F,
        ) -> DestinationClient<InterceptedService<T, F>>
        where
            F: tonic::service::Interceptor,
            T::ResponseBody: Default,
            T: tonic::codegen::Service<
                http::Request<tonic::body::BoxBody>,
                Response = http::Response<
                    <T as tonic::client::GrpcService<tonic::body::BoxBody>>::ResponseBody,
                >,
            >,
            <T as tonic::codegen::Service<
                http::Request<tonic::body::BoxBody>,
            >>::Error: Into<StdError> + Send + Sync,
        {
            DestinationClient::new(InterceptedService::new(inner, interceptor))
        }
        /// Compress requests with the given encoding.
        ///
        /// This requires the server to support it otherwise it might respond with an
        /// error.
        #[must_use]
        pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {
            self.inner = self.inner.send_compressed(encoding);
            self
        }
        /// Enable decompressing responses.
        #[must_use]
        pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {
            self.inner = self.inner.accept_compressed(encoding);
            self
        }
        /// Given a destination, return all addresses in that destination as a long-
        /// running stream of updates.
        pub async fn get(
            &mut self,
            request: impl tonic::IntoRequest<super::GetDestination>,
        ) -> Result<
            tonic::Response<tonic::codec::Streaming<super::Update>>,
            tonic::Status,
        > {
            self.inner
                .ready()
                .await
                .map_err(|e| {
                    tonic::Status::new(
                        tonic::Code::Unknown,
                        format!("Service was not ready: {}", e.into()),
                    )
                })?;
            let codec = tonic::codec::ProstCodec::default();
            let path = http::uri::PathAndQuery::from_static(
                "/io.linkerd.proxy.destination.Destination/Get",
            );
            self.inner.server_streaming(request.into_request(), path, codec).await
        }
        /// Given a destination, return that destination's profile and send an update
        /// whenever it changes.
        pub async fn get_profile(
            &mut self,
            request: impl tonic::IntoRequest<super::GetDestination>,
        ) -> Result<
            tonic::Response<tonic::codec::Streaming<super::DestinationProfile>>,
            tonic::Status,
        > {
            self.inner
                .ready()
                .await
                .map_err(|e| {
                    tonic::Status::new(
                        tonic::Code::Unknown,
                        format!("Service was not ready: {}", e.into()),
                    )
                })?;
            let codec = tonic::codec::ProstCodec::default();
            let path = http::uri::PathAndQuery::from_static(
                "/io.linkerd.proxy.destination.Destination/GetProfile",
            );
            self.inner.server_streaming(request.into_request(), path, codec).await
        }
    }
}
/// Generated server implementations.
pub mod destination_server {
    #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)]
    use tonic::codegen::*;
    ///Generated trait containing gRPC methods that should be implemented for use with DestinationServer.
    #[async_trait]
    pub trait Destination: Send + Sync + 'static {
        ///Server streaming response type for the Get method.
        type GetStream: futures_core::Stream<Item = Result<super::Update, tonic::Status>>
            + Send
            + 'static;
        /// Given a destination, return all addresses in that destination as a long-
        /// running stream of updates.
        async fn get(
            &self,
            request: tonic::Request<super::GetDestination>,
        ) -> Result<tonic::Response<Self::GetStream>, tonic::Status>;
        ///Server streaming response type for the GetProfile method.
        type GetProfileStream: futures_core::Stream<
                Item = Result<super::DestinationProfile, tonic::Status>,
            >
            + Send
            + 'static;
        /// Given a destination, return that destination's profile and send an update
        /// whenever it changes.
        async fn get_profile(
            &self,
            request: tonic::Request<super::GetDestination>,
        ) -> Result<tonic::Response<Self::GetProfileStream>, tonic::Status>;
    }
    #[derive(Debug)]
    pub struct DestinationServer<T: Destination> {
        inner: _Inner<T>,
        accept_compression_encodings: EnabledCompressionEncodings,
        send_compression_encodings: EnabledCompressionEncodings,
    }
    struct _Inner<T>(Arc<T>);
    impl<T: Destination> DestinationServer<T> {
        pub fn new(inner: T) -> Self {
            Self::from_arc(Arc::new(inner))
        }
        pub fn from_arc(inner: Arc<T>) -> Self {
            let inner = _Inner(inner);
            Self {
                inner,
                accept_compression_encodings: Default::default(),
                send_compression_encodings: Default::default(),
            }
        }
        pub fn with_interceptor<F>(
            inner: T,
            interceptor: F,
        ) -> InterceptedService<Self, F>
        where
            F: tonic::service::Interceptor,
        {
            InterceptedService::new(Self::new(inner), interceptor)
        }
        /// Enable decompressing requests with the given encoding.
        #[must_use]
        pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {
            self.accept_compression_encodings.enable(encoding);
            self
        }
        /// Compress responses with the given encoding, if the client supports it.
        #[must_use]
        pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {
            self.send_compression_encodings.enable(encoding);
            self
        }
    }
    impl<T, B> tonic::codegen::Service<http::Request<B>> for DestinationServer<T>
    where
        T: Destination,
        B: Body + Send + 'static,
        B::Error: Into<StdError> + Send + 'static,
    {
        type Response = http::Response<tonic::body::BoxBody>;
        type Error = std::convert::Infallible;
        type Future = BoxFuture<Self::Response, Self::Error>;
        fn poll_ready(
            &mut self,
            _cx: &mut Context<'_>,
        ) -> Poll<Result<(), Self::Error>> {
            Poll::Ready(Ok(()))
        }
        fn call(&mut self, req: http::Request<B>) -> Self::Future {
            let inner = self.inner.clone();
            match req.uri().path() {
                "/io.linkerd.proxy.destination.Destination/Get" => {
                    #[allow(non_camel_case_types)]
                    struct GetSvc<T: Destination>(pub Arc<T>);
                    impl<
                        T: Destination,
                    > tonic::server::ServerStreamingService<super::GetDestination>
                    for GetSvc<T> {
                        type Response = super::Update;
                        type ResponseStream = T::GetStream;
                        type Future = BoxFuture<
                            tonic::Response<Self::ResponseStream>,
                            tonic::Status,
                        >;
                        fn call(
                            &mut self,
                            request: tonic::Request<super::GetDestination>,
                        ) -> Self::Future {
                            let inner = self.0.clone();
                            let fut = async move { (*inner).get(request).await };
                            Box::pin(fut)
                        }
                    }
                    let accept_compression_encodings = self.accept_compression_encodings;
                    let send_compression_encodings = self.send_compression_encodings;
                    let inner = self.inner.clone();
                    let fut = async move {
                        let inner = inner.0;
                        let method = GetSvc(inner);
                        let codec = tonic::codec::ProstCodec::default();
                        let mut grpc = tonic::server::Grpc::new(codec)
                            .apply_compression_config(
                                accept_compression_encodings,
                                send_compression_encodings,
                            );
                        let res = grpc.server_streaming(method, req).await;
                        Ok(res)
                    };
                    Box::pin(fut)
                }
                "/io.linkerd.proxy.destination.Destination/GetProfile" => {
                    #[allow(non_camel_case_types)]
                    struct GetProfileSvc<T: Destination>(pub Arc<T>);
                    impl<
                        T: Destination,
                    > tonic::server::ServerStreamingService<super::GetDestination>
                    for GetProfileSvc<T> {
                        type Response = super::DestinationProfile;
                        type ResponseStream = T::GetProfileStream;
                        type Future = BoxFuture<
                            tonic::Response<Self::ResponseStream>,
                            tonic::Status,
                        >;
                        fn call(
                            &mut self,
                            request: tonic::Request<super::GetDestination>,
                        ) -> Self::Future {
                            let inner = self.0.clone();
                            let fut = async move { (*inner).get_profile(request).await };
                            Box::pin(fut)
                        }
                    }
                    let accept_compression_encodings = self.accept_compression_encodings;
                    let send_compression_encodings = self.send_compression_encodings;
                    let inner = self.inner.clone();
                    let fut = async move {
                        let inner = inner.0;
                        let method = GetProfileSvc(inner);
                        let codec = tonic::codec::ProstCodec::default();
                        let mut grpc = tonic::server::Grpc::new(codec)
                            .apply_compression_config(
                                accept_compression_encodings,
                                send_compression_encodings,
                            );
                        let res = grpc.server_streaming(method, req).await;
                        Ok(res)
                    };
                    Box::pin(fut)
                }
                _ => {
                    Box::pin(async move {
                        Ok(
                            http::Response::builder()
                                .status(200)
                                .header("grpc-status", "12")
                                .header("content-type", "application/grpc")
                                .body(empty_body())
                                .unwrap(),
                        )
                    })
                }
            }
        }
    }
    impl<T: Destination> Clone for DestinationServer<T> {
        fn clone(&self) -> Self {
            let inner = self.inner.clone();
            Self {
                inner,
                accept_compression_encodings: self.accept_compression_encodings,
                send_compression_encodings: self.send_compression_encodings,
            }
        }
    }
    impl<T: Destination> Clone for _Inner<T> {
        fn clone(&self) -> Self {
            Self(self.0.clone())
        }
    }
    impl<T: std::fmt::Debug> std::fmt::Debug for _Inner<T> {
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
            write!(f, "{:?}", self.0)
        }
    }
    impl<T: Destination> tonic::server::NamedService for DestinationServer<T> {
        const NAME: &'static str = "io.linkerd.proxy.destination.Destination";
    }
}