Skip to content

Commit c30d93f

Browse files
cratelynunleashed
andauthored
refactor(proxy/tap): remove unused trait system (#4477)
`linkerd-proxy-tap` contains data plane facilities that undergird "tap", a system for inspecting traffic inside of a service mesh. this crate contains an `iface` submodule that defines a number of traits intended to provide a set of generic interfaces for uses like testing, or other transport protocols. however, this suite has not been used for these purposes. these traits are only used internally. some types implement these traits, only to provide empty implementations that do nothing. this means that we pay for the complexity associated with this abstraction, for no current benefit. this branch removes these traits, to help simplify the `linkerd-proxy-tap` crate. * refactor(tap): remove unused `Tap` trait this commit concerns the `linkerd-proxy-tap::iface::Tap` trait. this trait was, per the documentation of the `iface` submodule: > These interfaces are provided to decouple the service implementation from any > Protobuf or gRPC concerns, hopefully to make this module more testable and > easier to change. > > This module is necessary to seal the traits, which must be public > for Registry/Layer/grpc, but need not be implemented outside of the `tap` > module. traits like this *are* a useful way to permit e.g. tests to mock i/o, decouple implementations from the particulars of certain protocols, and so forth. however, this `Tap` trait is only used within the context of the `Registry` structure, and is not used for tests. traits like this have a cost, in the form of complexity in the implementation. a registry that is generic across a "tap" then leaks complexity into our middleware, which must include e.g. bounds for the tap, its request payload, and its response payload. this commit removes this generic flexibility, and phrases calling code in terms of this concrete structure. the `can_tap_more()` and `tap()` methods are now inherent methods, rather than trait methods implementations. see `linkerd/proxy/tap/src/grpc/server.rs`. doing this simplifies bounds in `linkerd/proxy/tap/src/service.rs`. Signed-off-by: katelyn martin <kate@buoyant.io> * refactor(tap): remove noöp `TapRequestPayload` type this commit removes `TapRequestPayload`. we define a `TapPayload` trait, ostensibly to abstract over the task of "tapping" streams going in and out of workloads. this trait is implemented by two types, `TapRequestPayload` and `TapResponsePayload`. note this trait implementation, however: ```rust impl iface::TapPayload for TapRequestPayload { fn data<B: Buf>(&mut self, _: &B) {} fn eos(self, _: Option<&http::HeaderMap>) {} fn fail<E: HasH2Reason>(self, _: &E) {} } ``` ..and this struct definiction: ```rust #[derive(Debug)] pub struct TapRequestPayload {} ``` we do not tap the request payload. we don't store any state in this type, not is it affiliated with a meaningful trait implementation. all of `Body<B, T>`'s relevant logic is related to managing its `TapPayload`s, which as we can see above, are inert. we do not need to wrap the body in a `Body<B, T>` wrapper if `T` does not apply any behavior. as in the removal of the `Tap` trait, this is introducing complexity without any concrete motivating need. we can remove this trait implementation, and the TapRequestPayload type. Signed-off-by: katelyn martin <kate@buoyant.io> * refactor(tap): remove unused `TapResponse` trait again, we have a trait that is only implemented once, by a single type. we define an interface here, without any consumers using it. this commit removes the `TapResponse` trait and replaces calling code with invocations of inherent methods. Signed-off-by: katelyn martin <kate@buoyant.io> * refactor(tap): remove `TapPayload` trait in a previous commit, we removed the `TapRequestPayload` trait. this leaves us with a single implementer of this trait. as before, this is defining an interface with no other consumers. not only can we remove this trait, but in doing so, we'll discover that one of these trait methods was never being used! by removing this unused abstraction, we not only simplify the code relying on that interface, but the compiler can note that certain parts of that interface aren't serving us any purpose. Signed-off-by: katelyn martin <kate@buoyant.io> * nit(tap): remove inert `Registry` type alias now that we aren't defining `Registry` as a generic structure, this type alias is inert. we can instead reëxport it. Signed-off-by: katelyn martin <kate@buoyant.io> * refactor(tap): `Inner` is not generic this type does not need to be defined as a generic. see <#4477 (comment)>. Co-Authored-By: Co-authored-by: Alejandro Martinez Ruiz <amr@buoyant.io> Signed-off-by: katelyn martin <kate@buoyant.io> * refactor(tap): remove `TapRequestPayload` see: - #4477 (comment) - #4477 (comment) we removed trait implementations for this type in 337ceda. we can go further than this, and remove it altogether. Co-Authored-By: Co-authored-by: Alejandro Martinez Ruiz <amr@buoyant.io> Signed-off-by: katelyn martin <kate@buoyant.io> --------- Signed-off-by: katelyn martin <kate@buoyant.io> Co-authored-by: Co-authored-by: Alejandro Martinez Ruiz <amr@buoyant.io>
1 parent 4ebadca commit c30d93f

5 files changed

Lines changed: 49 additions & 157 deletions

File tree

linkerd/proxy/tap/src/grpc.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
mod match_;
22
mod server;
33

4+
pub(crate) use self::server::TapResponsePayload;
45
pub use self::server::{Server, Tap};

linkerd/proxy/tap/src/grpc/server.rs

Lines changed: 12 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use super::match_::Match;
2-
use crate::{iface, Inspect, Registry};
3-
use bytes::Buf;
2+
use crate::{Inspect, Registry};
43
use futures::ready;
54
use futures::stream::Stream;
65
use http_body::Body;
@@ -63,9 +62,6 @@ pub struct TapResponse {
6362
tap: TapTx,
6463
}
6564

66-
#[derive(Debug)]
67-
pub struct TapRequestPayload {}
68-
6965
#[derive(Debug)]
7066
pub struct TapResponsePayload {
7167
base_event: api::TapEvent,
@@ -219,23 +215,15 @@ impl Shared {
219215

220216
// === impl Tap ===
221217

222-
impl iface::Tap for Tap {
223-
type TapRequestPayload = TapRequestPayload;
224-
type TapResponse = TapResponse;
225-
type TapResponsePayload = TapResponsePayload;
226-
227-
fn can_tap_more(&self) -> bool {
218+
impl Tap {
219+
pub(crate) fn can_tap_more(&self) -> bool {
228220
self.shared
229221
.upgrade()
230222
.map(|shared| shared.is_under_limit())
231223
.unwrap_or(false)
232224
}
233225

234-
fn tap<B, I>(
235-
&mut self,
236-
req: &http::Request<B>,
237-
inspect: &I,
238-
) -> Option<(TapRequestPayload, TapResponse)>
226+
pub(crate) fn tap<B, I>(&mut self, req: &http::Request<B>, inspect: &I) -> Option<TapResponse>
239227
where
240228
B: Body,
241229
I: Inspect,
@@ -331,23 +319,19 @@ impl iface::Tap for Tap {
331319

332320
let tap = TapTx { id, tx: events_tx };
333321

334-
let req = TapRequestPayload {};
335-
let rsp = TapResponse {
322+
Some(TapResponse {
336323
tap,
337324
base_event,
338325
request_init_at,
339326
extract_headers,
340-
};
341-
Some((req, rsp))
327+
})
342328
}
343329
}
344330

345331
// === impl TapResponse ===
346332

347-
impl iface::TapResponse for TapResponse {
348-
type TapPayload = TapResponsePayload;
349-
350-
fn tap<B: Body>(self, rsp: &http::Response<B>) -> TapResponsePayload {
333+
impl TapResponse {
334+
pub(crate) fn tap<B: Body>(self, rsp: &http::Response<B>) -> TapResponsePayload {
351335
let response_init_at = Instant::now();
352336

353337
let headers = if self.extract_headers {
@@ -395,7 +379,7 @@ impl iface::TapResponse for TapResponse {
395379
}
396380
}
397381

398-
fn fail<E: HasH2Reason>(self, err: &E) {
382+
pub(crate) fn fail<E: HasH2Reason>(self, err: &E) {
399383
let response_end_at = Instant::now();
400384
let reason = err.h2_reason();
401385
let since_request_init = response_end_at.saturating_duration_since(self.request_init_at);
@@ -420,24 +404,10 @@ impl iface::TapResponse for TapResponse {
420404
}
421405
}
422406

423-
// === impl TapRequestPayload ===
424-
425-
impl iface::TapPayload for TapRequestPayload {
426-
fn data<B: Buf>(&mut self, _: &B) {}
427-
428-
fn eos(self, _: Option<&http::HeaderMap>) {}
429-
430-
fn fail<E: HasH2Reason>(self, _: &E) {}
431-
}
432-
433407
// === impl TapResponsePayload ===
434408

435-
impl iface::TapPayload for TapResponsePayload {
436-
fn data<B: Buf>(&mut self, data: &B) {
437-
self.response_bytes += data.remaining();
438-
}
439-
440-
fn eos(self, trls: Option<&http::HeaderMap>) {
409+
impl TapResponsePayload {
410+
pub(crate) fn eos(self, trls: Option<&http::HeaderMap>) {
441411
let status = match trls {
442412
None => self.grpc_status,
443413
Some(t) => t
@@ -449,15 +419,13 @@ impl iface::TapPayload for TapResponsePayload {
449419
self.send(status.map(api::eos::End::GrpcStatusCode), trls);
450420
}
451421

452-
fn fail<E: HasH2Reason>(self, e: &E) {
422+
pub(crate) fn fail<E: HasH2Reason>(self, e: &E) {
453423
let end = e
454424
.h2_reason()
455425
.map(|r| api::eos::End::ResetErrorCode(r.into()));
456426
self.send(end, None);
457427
}
458-
}
459428

460-
impl TapResponsePayload {
461429
fn send(self, end: Option<api::eos::End>, trls: Option<&http::HeaderMap>) {
462430
let response_end_at = Instant::now();
463431
let trailers = if self.extract_headers {

linkerd/proxy/tap/src/lib.rs

Lines changed: 1 addition & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,7 @@ mod grpc;
99
mod registry;
1010
mod service;
1111

12-
pub use self::{accept::AcceptPermittedClients, service::NewTapHttp};
13-
14-
/// A registry containing all the active taps that have registered with the
15-
/// gRPC server.
16-
pub type Registry = registry::Registry<grpc::Tap>;
12+
pub use self::{accept::AcceptPermittedClients, registry::Registry, service::NewTapHttp};
1713

1814
// The number of events that may be buffered for a given response.
1915
const PER_RESPONSE_EVENT_BUFFER_CAPACITY: usize = 400;
@@ -61,54 +57,3 @@ pub trait Inspect {
6157
})
6258
}
6359
}
64-
65-
/// The internal interface used between Registry, Layer, and grpc.
66-
///
67-
/// These interfaces are provided to decouple the service implementation from any
68-
/// Protobuf or gRPC concerns, hopefully to make this module more testable and
69-
/// easier to change.
70-
///
71-
/// This module is necessary to seal the traits, which must be public
72-
/// for Registry/Layer/grpc, but need not be implemented outside of the `tap`
73-
/// module.
74-
mod iface {
75-
use bytes::Buf;
76-
use linkerd_proxy_http::HasH2Reason;
77-
78-
pub trait Tap: Clone {
79-
type TapRequestPayload: TapPayload;
80-
type TapResponse: TapResponse<TapPayload = Self::TapResponsePayload>;
81-
type TapResponsePayload: TapPayload;
82-
83-
/// Returns `true` as l
84-
fn can_tap_more(&self) -> bool;
85-
86-
/// Initiate a tap, if it matches.
87-
///
88-
/// If the tap cannot be initialized, for instance because the tap has
89-
/// completed or been canceled, then `None` is returned.
90-
fn tap<B: http_body::Body, I: super::Inspect>(
91-
&mut self,
92-
req: &http::Request<B>,
93-
inspect: &I,
94-
) -> Option<(Self::TapRequestPayload, Self::TapResponse)>;
95-
}
96-
97-
pub trait TapPayload {
98-
fn data<B: Buf>(&mut self, data: &B);
99-
100-
fn eos(self, headers: Option<&http::HeaderMap>);
101-
102-
fn fail<E: HasH2Reason>(self, error: &E);
103-
}
104-
105-
pub trait TapResponse {
106-
type TapPayload: TapPayload;
107-
108-
/// Record a response and obtain a handle to tap its body.
109-
fn tap<B: http_body::Body>(self, rsp: &http::Response<B>) -> Self::TapPayload;
110-
111-
/// Record a service failure.
112-
fn fail<E: HasH2Reason>(self, error: &E);
113-
}
114-
}

linkerd/proxy/tap/src/registry.rs

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,25 @@
1-
use crate::iface;
1+
use crate::grpc::Tap;
22
use futures::{Stream, StreamExt};
33
use parking_lot::Mutex;
44
use std::sync::Arc;
55
use tokio::sync::watch;
66
use tracing::trace;
77

8+
/// A registry containing all the active taps that have registered with the
9+
/// gRPC server.
810
#[derive(Debug)]
9-
pub struct Registry<T> {
10-
inner: Arc<Mutex<Inner<T>>>,
11-
taps_recv: watch::Receiver<Vec<T>>,
11+
pub struct Registry {
12+
inner: Arc<Mutex<Inner>>,
13+
taps_recv: watch::Receiver<Vec<Tap>>,
1214
}
1315

1416
#[derive(Debug)]
15-
struct Inner<T> {
16-
taps: Vec<T>,
17-
taps_send: watch::Sender<Vec<T>>,
17+
struct Inner {
18+
taps: Vec<Tap>,
19+
taps_send: watch::Sender<Vec<Tap>>,
1820
}
1921

20-
impl<T> Default for Registry<T> {
22+
impl Default for Registry {
2123
fn default() -> Self {
2224
let (taps_send, taps_recv) = watch::channel(vec![]);
2325
let inner = Inner {
@@ -31,19 +33,16 @@ impl<T> Default for Registry<T> {
3133
}
3234
}
3335

34-
impl<T> Registry<T>
35-
where
36-
T: iface::Tap + Clone,
37-
{
36+
impl Registry {
3837
pub fn new() -> Self {
3938
Self::default()
4039
}
4140

42-
pub fn get_taps(&self) -> Vec<T> {
41+
pub fn get_taps(&self) -> Vec<Tap> {
4342
self.taps_recv.borrow().clone()
4443
}
4544

46-
pub fn register(&self, tap: T) {
45+
pub fn register(&self, tap: Tap) {
4746
let mut inner = self.inner.lock();
4847
inner.taps.push(tap);
4948
let _ = inner.taps_send.send(inner.taps.clone());
@@ -60,7 +59,7 @@ where
6059
}
6160
}
6261

63-
impl<T> Clone for Registry<T> {
62+
impl Clone for Registry {
6463
fn clone(&self) -> Self {
6564
Self {
6665
inner: self.inner.clone(),

0 commit comments

Comments
 (0)