linkerd2-proxy/tests/support/tap.rs

218 lines
6.2 KiB
Rust

use support::*;
use bytes::BytesMut;
use linkerd2_proxy_api::tap as pb;
pub fn client(addr: SocketAddr) -> Client {
let api = pb::client::Tap::new(SyncSvc(client::http2(addr, "localhost")));
Client {
api,
}
}
pub struct Client {
api: pb::client::Tap<SyncSvc>,
}
impl Client {
pub fn observe(&mut self, req: ObserveBuilder) -> impl Stream<Item = pb::TapEvent, Error = tower_grpc::Error> {
let req = tower_grpc::Request::new(req.0);
self.api.observe(req)
.wait()
.expect("tap observe wait")
.into_inner()
}
}
pub fn observe_request() -> ObserveBuilder {
ObserveBuilder(pb::ObserveRequest {
limit: 100,
match_: Some(pb::observe_request::Match {
match_: Some(pb::observe_request::match_::Match::Http(
pb::observe_request::match_::Http {
match_: Some(pb::observe_request::match_::http::Match::Path(
pb::observe_request::match_::http::StringMatch {
match_: Some(pb::observe_request::match_::http::string_match::Match::Prefix(
"/".to_string()
)),
},
)),
},
)),
}),
})
}
#[derive(Debug)]
pub struct ObserveBuilder(pb::ObserveRequest);
impl ObserveBuilder {
pub fn limit(mut self, limit: u32) -> Self {
self.0.limit = limit;
self
}
pub fn ports(mut self, min: u16, max: u16) -> Self {
self.0.match_ = Some(pb::observe_request::Match {
match_: Some(
pb::observe_request::match_::Match::Destination(
pb::observe_request::match_::Tcp {
match_: Some(pb::observe_request::match_::tcp::Match::Ports(
pb::observe_request::match_::tcp::PortRange {
min: min.into(),
max: max.into(),
},
)),
},
),
),
});
self
}
}
pub trait TapEventExt {
fn is_inbound(&self) -> bool;
fn is_outbound(&self) -> bool;
//fn id(&self) -> (u32, u64);
fn event(&self) -> &pb::tap_event::http::Event;
fn request_init_method(&self) -> String;
fn request_init_authority(&self) -> &str;
fn request_init_path(&self) -> &str;
fn response_init_status(&self) -> u16;
fn response_end_bytes(&self) -> u64;
fn response_end_eos_grpc(&self) -> u32;
}
impl TapEventExt for pb::TapEvent {
fn is_inbound(&self) -> bool {
self.proxy_direction == pb::tap_event::ProxyDirection::Inbound as i32
}
fn is_outbound(&self) -> bool {
self.proxy_direction == pb::tap_event::ProxyDirection::Outbound as i32
}
fn event(&self) -> &pb::tap_event::http::Event {
match self.event {
Some(
pb::tap_event::Event::Http(
pb::tap_event::Http {
event: Some(ref ev),
}
)
) => ev,
_ => panic!("unknown event: {:?}", self.event),
}
}
fn request_init_method(&self) -> String {
match self.event() {
pb::tap_event::http::Event::RequestInit(_ev) => {
//TODO: ugh
unimplemented!("method");
},
_ => panic!("not RequestInit event"),
}
}
fn request_init_authority(&self) -> &str {
match self.event() {
pb::tap_event::http::Event::RequestInit(ev) => {
&ev.authority
},
_ => panic!("not RequestInit event"),
}
}
fn request_init_path(&self) -> &str {
match self.event() {
pb::tap_event::http::Event::RequestInit(ev) => {
&ev.path
},
_ => panic!("not RequestInit event"),
}
}
fn response_init_status(&self) -> u16 {
match self.event() {
pb::tap_event::http::Event::ResponseInit(ev) => {
ev.http_status as u16
},
_ => panic!("not ResponseInit event"),
}
}
fn response_end_bytes(&self) -> u64 {
match self.event() {
pb::tap_event::http::Event::ResponseEnd(ev) => {
ev.response_bytes
},
_ => panic!("not ResponseEnd event"),
}
}
fn response_end_eos_grpc(&self) -> u32 {
match self.event() {
pb::tap_event::http::Event::ResponseEnd(ev) => {
match ev.eos {
Some(pb::Eos {
end: Some(pb::eos::End::GrpcStatusCode(code)),
}) => code,
_ => panic!("not Eos GrpcStatusCode: {:?}", ev.eos),
}
},
_ => panic!("not ResponseEnd event"),
}
}
}
struct SyncSvc(client::Client);
impl<B> tower_service::Service<http::Request<B>> for SyncSvc
where
B: tower_grpc::Body<Data = Bytes>,
{
type Response = http::Response<GrpcBody>;
type Error = String;
type Future = Box<Future<Item = Self::Response, Error = Self::Error> + Send>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
unreachable!("tap SyncSvc poll_ready");
}
fn call(&mut self, req: http::Request<B>) -> Self::Future {
let req = req.map(|mut body| {
let mut buf = BytesMut::new();
while let Some(bytes) = future::poll_fn(|| body.poll_data()).wait().expect("req body") {
buf.extend_from_slice(&bytes);
}
buf.freeze()
});
Box::new(self.0.request_body_async(req)
.map(|res| res.map(GrpcBody)))
}
}
struct GrpcBody(client::BytesBody);
impl tower_grpc::Body for GrpcBody {
type Data = Bytes;
fn poll_data(&mut self) -> Poll<Option<Self::Data>, tower_grpc::Error> {
self.0.poll_data().map_err(|err| {
unimplemented!("grpc poll_data error: {}", err)
})
}
fn poll_metadata(&mut self) -> Poll<Option<http::HeaderMap>, tower_grpc::Error> {
self.0.poll_trailers().map_err(|err| {
unimplemented!("grpc poll_trailers error: {}", err)
})
}
}