linkerd2-proxy/src/app/control.rs

422 lines
11 KiB
Rust

use h2;
use std::fmt;
use std::time::Duration;
use svc;
use transport::tls;
use {Conditional, Addr};
#[derive(Clone, Debug)]
pub struct Config {
host_and_port: Addr,
tls_server_identity: Conditional<tls::Identity, tls::ReasonForNoTls>,
tls_config: tls::ConditionalClientConfig,
backoff: Duration,
connect_timeout: Duration,
builder: h2::client::Builder,
}
impl Config {
pub fn new(
host_and_port: Addr,
tls_server_identity: Conditional<tls::Identity, tls::ReasonForNoTls>,
backoff: Duration,
connect_timeout: Duration,
) -> Self {
Self {
host_and_port,
tls_server_identity,
tls_config: Conditional::None(tls::ReasonForNoTls::Disabled),
backoff,
connect_timeout,
builder: h2::client::Builder::default(),
}
}
}
impl svc::watch::WithUpdate<tls::ConditionalClientConfig> for Config {
type Updated = Self;
fn with_update(&self, tls_config: &tls::ConditionalClientConfig) -> Self::Updated {
let mut c = self.clone();
c.tls_config = tls_config.clone();
c
}
}
impl fmt::Display for Config {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.host_and_port, f)
}
}
/// Sets the request's URI from `Config`.
pub mod add_origin {
extern crate tower_add_origin;
use self::tower_add_origin::AddOrigin;
use bytes::Bytes;
use http::uri;
use std::marker::PhantomData;
use svc;
#[derive(Debug)]
pub struct Layer<M> {
_p: PhantomData<fn() -> M>,
}
#[derive(Clone, Debug)]
pub struct Stack<M> {
inner: M,
}
// === impl Layer ===
impl<M> Layer<M>
where
M: svc::Stack<super::Config>,
{
pub fn new() -> Self {
Self { _p: PhantomData }
}
}
impl<M> Clone for Layer<M>
where
M: svc::Stack<super::Config>,
{
fn clone(&self) -> Self {
Self::new()
}
}
impl<M> svc::Layer<super::Config, super::Config, M> for Layer<M>
where
M: svc::Stack<super::Config>,
{
type Value = <Stack<M> as svc::Stack<super::Config>>::Value;
type Error = <Stack<M> as svc::Stack<super::Config>>::Error;
type Stack = Stack<M>;
fn bind(&self, inner: M) -> Self::Stack {
Stack { inner }
}
}
// === impl Stack ===
impl<M> svc::Stack<super::Config> for Stack<M>
where
M: svc::Stack<super::Config>,
{
type Value = AddOrigin<M::Value>;
type Error = M::Error;
fn make(&self, config: &super::Config) -> Result<Self::Value, Self::Error> {
let inner = self.inner.make(config)?;
let scheme = uri::Scheme::from_shared(Bytes::from_static(b"http")).unwrap();
let authority = config.host_and_port.as_authority();
Ok(AddOrigin::new(inner, scheme, authority))
}
}
}
/// Resolves the controller's `host_and_port` once before building a client.
pub mod resolve {
use futures::{Future, Poll};
use std::marker::PhantomData;
use std::net::SocketAddr;
use std::{error, fmt};
use super::client;
use dns;
use svc;
use transport::{connect, tls};
#[derive(Debug)]
pub struct Layer<M> {
dns: dns::Resolver,
_p: PhantomData<fn() -> M>,
}
#[derive(Clone, Debug)]
pub struct Stack<M> {
dns: dns::Resolver,
inner: M,
}
pub struct NewService<M> {
config: super::Config,
dns: dns::Resolver,
stack: M,
}
pub struct Init<M>
where
M: svc::Stack<client::Target>,
M::Value: svc::NewService,
{
state: State<M>,
}
enum State<M>
where
M: svc::Stack<client::Target>,
M::Value: svc::NewService,
{
Resolve {
future: dns::IpAddrFuture,
config: super::Config,
stack: M,
},
Inner(<M::Value as svc::NewService>::Future),
}
#[derive(Debug)]
pub enum Error<S, I> {
Dns(dns::Error),
Invalid(S),
Inner(I),
}
// === impl Layer ===
impl<M> Layer<M>
where
M: svc::Stack<client::Target> + Clone,
{
pub fn new(dns: dns::Resolver) -> Self {
Self {
dns,
_p: PhantomData,
}
}
}
impl<M> Clone for Layer<M>
where
M: svc::Stack<client::Target> + Clone,
{
fn clone(&self) -> Self {
Self::new(self.dns.clone())
}
}
impl<M> svc::Layer<super::Config, client::Target, M> for Layer<M>
where
M: svc::Stack<client::Target> + Clone,
{
type Value = <Stack<M> as svc::Stack<super::Config>>::Value;
type Error = <Stack<M> as svc::Stack<super::Config>>::Error;
type Stack = Stack<M>;
fn bind(&self, inner: M) -> Self::Stack {
Stack {
inner,
dns: self.dns.clone(),
}
}
}
// === impl Stack ===
impl<M> svc::Stack<super::Config> for Stack<M>
where
M: svc::Stack<client::Target> + Clone,
{
type Value = NewService<M>;
type Error = M::Error;
fn make(&self, config: &super::Config) -> Result<Self::Value, Self::Error> {
Ok(NewService {
dns: self.dns.clone(),
config: config.clone(),
stack: self.inner.clone(),
})
}
}
// === impl NewService ===
impl<M> svc::NewService for NewService<M>
where
M: svc::Stack<client::Target> + Clone,
M::Value: svc::NewService,
{
type Request = <M::Value as svc::NewService>::Request;
type Response = <M::Value as svc::NewService>::Response;
type Error = <M::Value as svc::NewService>::Error;
type Service = <M::Value as svc::NewService>::Service;
type InitError = <Init<M> as Future>::Error;
type Future = Init<M>;
fn new_service(&self) -> Self::Future {
Init {
state: State::Resolve {
future: self.dns.resolve_one_ip(&self.config.host_and_port),
stack: self.stack.clone(),
config: self.config.clone(),
},
}
}
}
// === impl Init ===
impl<M> Future for Init<M>
where
M: svc::Stack<client::Target>,
M::Value: svc::NewService,
{
type Item = <M::Value as svc::NewService>::Service;
type Error = Error<M::Error, <M::Value as svc::NewService>::InitError>;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
loop {
self.state = match self.state {
State::Inner(ref mut fut) => {
return fut.poll().map_err(Error::Inner);
}
State::Resolve {
ref mut future,
ref config,
ref stack,
} => {
let ip = try_ready!(future.poll().map_err(Error::Dns));
let sa = SocketAddr::from((ip, config.host_and_port.port()));
let tls = config.tls_server_identity.as_ref().and_then(|id| {
config
.tls_config
.as_ref()
.map(|config| tls::ConnectionConfig {
server_identity: id.clone(),
config: config.clone(),
})
});
let target = client::Target {
connect: connect::Target::new(sa, tls),
builder: config.builder.clone(),
log_ctx: ::logging::admin()
.client("control", config.host_and_port.clone()),
};
let inner = stack.make(&target).map_err(Error::Invalid)?;
State::Inner(svc::NewService::new_service(&inner))
}
};
}
}
}
// === impl Error ===
impl<S: fmt::Display, I: fmt::Display> fmt::Display for Error<S, I> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Error::Dns(dns::Error::NoAddressesFound) => write!(f, "no addresses found"),
Error::Dns(dns::Error::ResolutionFailed(e)) => fmt::Display::fmt(&e, f),
Error::Invalid(ref e) => fmt::Display::fmt(&e, f),
Error::Inner(ref e) => fmt::Display::fmt(&e, f),
}
}
}
impl<S: error::Error, I: error::Error> error::Error for Error<S, I> {}
}
/// Creates a client suitable for gRPC.
pub mod client {
use h2;
use std::marker::PhantomData;
use tower_h2::{client, BoxBody};
use svc;
use transport::connect;
use Addr;
#[derive(Clone, Debug)]
pub struct Target {
pub(super) connect: connect::Target,
pub(super) builder: h2::client::Builder,
pub(super) log_ctx: ::logging::Client<&'static str, Addr>,
}
#[derive(Debug)]
pub struct Layer<C> {
_p: PhantomData<fn() -> C>,
}
#[derive(Clone, Debug)]
pub struct Stack<C> {
connect: C,
}
// === impl Layer ===
impl<C> Layer<C>
where
C: svc::Stack<connect::Target> + Clone,
C::Value: connect::Connect,
<C::Value as connect::Connect>::Connected: Send + 'static,
{
pub fn new() -> Self {
Self { _p: PhantomData }
}
}
impl<C> Clone for Layer<C>
where
C: svc::Stack<connect::Target> + Clone,
C::Value: connect::Connect,
<C::Value as connect::Connect>::Connected: Send + 'static,
{
fn clone(&self) -> Self {
Self::new()
}
}
impl<C> svc::Layer<Target, connect::Target, C> for Layer<C>
where
C: svc::Stack<connect::Target> + Clone,
C::Value: connect::Connect,
<C::Value as connect::Connect>::Connected: Send + 'static,
{
type Value = <Stack<C> as svc::Stack<Target>>::Value;
type Error = <Stack<C> as svc::Stack<Target>>::Error;
type Stack = Stack<C>;
fn bind(&self, connect: C) -> Self::Stack {
Stack { connect }
}
}
// === impl Stack ===
impl<C> svc::Stack<Target> for Stack<C>
where
C: svc::Stack<connect::Target> + Clone,
C::Value: connect::Connect,
<C::Value as connect::Connect>::Connected: Send + 'static,
{
type Value = client::Connect<
C::Value,
::logging::ClientExecutor<&'static str, Addr>,
BoxBody,
>;
type Error = C::Error;
fn make(&self, target: &Target) -> Result<Self::Value, Self::Error> {
let c = self.connect.make(&target.connect)?;
let h2 = target.builder.clone();
let e = target
.log_ctx
.clone()
.with_remote(target.connect.addr)
.executor();
Ok(client::Connect::new(c, h2, e))
}
}
}