···11+//! _grumbles_ ketama doesn't support uds _grumbles_
22+//!
33+//! (also this lets us add an option to choose in the future)
44+55+use std::sync::Arc;
66+77+use pingora::lb::selection::BackendSelection;
88+use pingora::lb::selection::consistent::{KetamaConfig, KetamaHashing};
99+use pingora::lb::{self, Backend};
1010+use pingora::prelude::*;
1111+1212+pub enum SelectionChoice {
1313+ Ketama(Arc<KetamaHashing>),
1414+ RoundRobin(Arc<RoundRobin>),
1515+}
1616+1717+#[allow(
1818+ dead_code,
1919+ reason = "required for trait impl, will use the in the future"
2020+)]
2121+pub enum SelectionConfig {
2222+ Ketama(KetamaConfig),
2323+ RoundRobin(()),
2424+}
2525+pub enum SelectionIter {
2626+ Ketama(<KetamaHashing as BackendSelection>::Iter),
2727+ RoundRobin(<RoundRobin as BackendSelection>::Iter),
2828+}
2929+impl lb::selection::BackendIter for SelectionIter {
3030+ fn next(&mut self) -> Option<&Backend> {
3131+ match self {
3232+ SelectionIter::Ketama(k) => k.next(),
3333+ SelectionIter::RoundRobin(rr) => rr.next(),
3434+ }
3535+ }
3636+}
3737+impl BackendSelection for SelectionChoice {
3838+ type Iter = SelectionIter;
3939+4040+ type Config = SelectionConfig;
4141+4242+ fn build(backends: &std::collections::BTreeSet<lb::Backend>) -> Self {
4343+ // need the arc here for iter
4444+ if backends
4545+ .iter()
4646+ .any(|b| matches!(b.addr, pingora::protocols::l4::socket::SocketAddr::Unix(_)))
4747+ {
4848+ // ketama does not support unix domain sockets
4949+ Self::RoundRobin(Arc::new(RoundRobin::build(backends)))
5050+ } else {
5151+ Self::Ketama(Arc::new(KetamaHashing::build(backends)))
5252+ }
5353+ }
5454+5555+ fn iter(self: &std::sync::Arc<Self>, key: &[u8]) -> Self::Iter
5656+ where
5757+ Self::Iter: lb::selection::BackendIter,
5858+ {
5959+ match &**self {
6060+ SelectionChoice::Ketama(k) => SelectionIter::Ketama(k.iter(key)),
6161+ SelectionChoice::RoundRobin(rr) => SelectionIter::RoundRobin(rr.iter(key)),
6262+ }
6363+ }
6464+6565+ fn build_with_config(
6666+ backends: &std::collections::BTreeSet<Backend>,
6767+ config: &Self::Config,
6868+ ) -> Self {
6969+ // need the arc here for iter
7070+ match config {
7171+ SelectionConfig::Ketama(ketama) => {
7272+ Self::Ketama(Arc::new(KetamaHashing::build_with_config(backends, ketama)))
7373+ }
7474+ SelectionConfig::RoundRobin(rr) => {
7575+ Self::RoundRobin(Arc::new(RoundRobin::build_with_config(backends, rr)))
7676+ }
7777+ }
7878+ }
7979+}
+5-2
src/gateway.rs
···88use cookie_rs::CookieJar;
99use http::status::StatusCode;
1010use http::{HeaderName, HeaderValue};
1111-use pingora::lb::selection::consistent::KetamaHashing;
1211use pingora::prelude::*;
1312use pingora::protocols::tls::CaType;
1413use url::Url;
···2322/// per-domain information about backends and such
2423pub struct DomainInfo {
2524 /// the load balancer to use to select backends
2626- pub balancer: Arc<LoadBalancer<KetamaHashing>>,
2525+ pub balancer: Arc<LoadBalancer<super::SelectionChoice>>,
2726 /// whether or not we allow insecure connections from clients
2827 pub tls_mode: config::format::domain::TlsMode,
2928 /// the sni name of this domain, used to pass to backends
···636635 peer.options.ca = ca;
637636 peer
638637 }
638638+ BackendData::HttpOverUds => {
639639+ HttpPeer::new_from_sockaddr(backend.addr, false, backends.sni_name.to_string())
640640+ }
639641 };
640642 Ok(Box::new(peer))
641643 }
···692694/// for use in [`AuthGateway::upstream_peer`]
693695#[derive(Clone)]
694696pub enum BackendData {
697697+ HttpOverUds,
695698 HttpOnly,
696699 Tls {
697700 /// should skip we verifying the cert (useful if the certs are selfsigned and we don't want to
+6-5
src/main.rs
···11use std::collections::HashMap;
2233use color_eyre::eyre::Context as _;
44-use pingora::lb;
55-use pingora::lb::selection::consistent::KetamaHashing;
44+use pingora::lb::{self, Backend};
65use pingora::listeners::tls::{BundleCert, CertAndKey, TlsSettings};
76use pingora::prelude::*;
87use pingora::utils::tls::CertKey;
9899+use self::backend_selection::SelectionChoice;
1010use self::gateway::{AuthGateway, BackendData, DomainInfo, oidc};
11111212+mod backend_selection;
1213mod config;
1314mod cookies;
1415mod gateway;
···17181819/// constructed load balancer, with [backend info][`BackendInfo`] to be passed to [`AuthGateway`]
1920type BalancerInfo = (
2020- Vec<pingora::services::background::GenBackgroundService<LoadBalancer<KetamaHashing>>>,
2121+ Vec<pingora::services::background::GenBackgroundService<LoadBalancer<SelectionChoice>>>,
2122 HashMap<String, DomainInfo>,
2223);
23242425/// construct the load balancer and initialize the [backend info][`BackendInfo`] for the
2526/// [`AuthGateway`]
2627fn balancer(domains: &HashMap<String, config::format::Domain>) -> color_eyre::Result<BalancerInfo> {
2727- use lb::{self, Backend, discovery};
2828+ use lb::{self, discovery};
2829 use pingora::protocols::l4::socket::SocketAddr;
29303031 let mut balancers = HashMap::with_capacity(domains.len());
···6869 }))
6970 .chain(domain.uds.iter().map(|backend| {
7071 let mut ext = lb::Extensions::new();
7171- ext.insert(BackendData::HttpOnly);
7272+ ext.insert(BackendData::HttpOverUds);
7273 Ok(Backend {
7374 addr: SocketAddr::Unix(
7475 std::os::unix::net::SocketAddr::from_pathname(&backend.path)