mirror of
https://github.com/sadoyan/aralez.git
synced 2026-04-29 22:38:36 +08:00
Restructurisation and some fixes.
This commit is contained in:
@@ -17,8 +17,9 @@ Built on Rust, on top of **Cloudflare’s Pingora engine**, **Gazan** delivers w
|
||||
- 🔁 **Hot Reloading:** Modify upstreams on the fly via `upstreams.yaml` — no restart needed
|
||||
- 🔮 **Automatic WebSocket Support:** Zero config — connection upgrades are handled seamlessly
|
||||
- 🔮 **Automatic GRPC Support:** Zero config, Requires `ssl` to proxy, gRPC is handled seamlessly
|
||||
- 🔮 **Upstreams Session Stickiness:** Enable/Disable Sticky session support with single parameter in config file
|
||||
- 🔐 **TLS Termination:** Fully supports TLS for incoming and upstream traffic
|
||||
- 🛡️ **Built-in Auth Support:**
|
||||
- 🛡️ **Built-in Auth Support:** Basic Auth, JWT, API key
|
||||
- 🧠 **CORS & Header Injection:** Global and per-route header configuration
|
||||
- 🧪 **Health Checks:** Pluggable health check methods for upstreams
|
||||
- 🛰️ **Remote Config Push:** Lightweight HTTP API to update configs from CI/CD or other systems
|
||||
@@ -211,5 +212,6 @@ curl -u username:password -H 'Host: myip.mydomain.com' http://127.0.0.1:6193/
|
||||
- Designed for edge proxying, internal routing, or hybrid cloud scenarios.
|
||||
- Transparent, fully automatic WebSocket upgrade support.
|
||||
- Transparent, fully automatic gRPC proxy.
|
||||
- Sticky session support.
|
||||
- HTTP2 ready.
|
||||
- Upcoming Kubernetes integration
|
||||
@@ -1,20 +1,20 @@
|
||||
# Default configuration file for Pingora, read only once at startup
|
||||
threads: 8 # Pingora default setting
|
||||
# Main configuration file , applied on startup
|
||||
threads: 8 # Nubber of daemon threads default setting
|
||||
#user: pastor # Username for running gazan after dropping root privileges, requires program to start as root
|
||||
#group: pastor # Group for running gazan after dropping root privileges, requires program to start as root
|
||||
daemon: false # Run in background
|
||||
upstream_keepalive_pool_size: 500 # Pingora default setting
|
||||
pid_file: /tmp/gazan.pid # Pingora default setting
|
||||
error_log: /tmp/gazan_err.log # Pingora default setting
|
||||
upgrade_sock: /tmp/gazan.sock # Pingora default setting
|
||||
upstream_keepalive_pool_size: 500 # Pool size for upstream keepalive connections
|
||||
pid_file: /tmp/gazan.pid # Path to PID file
|
||||
error_log: /tmp/gazan_err.log # Path to error log
|
||||
upgrade_sock: /tmp/gazan.sock # Path to socket file
|
||||
config_address: 0.0.0.0:3000 # HTTP API address for pushing upstreams.yaml from remote location
|
||||
proxy_address_http: 0.0.0.0:6193 # Pingora default setting
|
||||
proxy_address_tls: 0.0.0.0:6194 # Optional
|
||||
proxy_address_http: 0.0.0.0:6193 # Proxy HTTP bind address
|
||||
proxy_address_tls: 0.0.0.0:6194 # Optional, Proxy TLS bind address
|
||||
tls_certificate: etc/server.crt # Mandatory if proxy_address_tls is set
|
||||
tls_key_file: etc/key.pem # Mandatory if proxy_address_tls is set
|
||||
upstreams_conf: etc/upstreams.yaml # the location of upstreams file
|
||||
log_level: info # info, warn, error, debug, trace, off
|
||||
hc_method: HEAD # Healthcheck method (HEAD, GET, POST are supported) UPPERCASE
|
||||
hc_interval: 2 #Intervak for Healthcheck in seconds
|
||||
master_key: 910517d9-f9a1-48de-8826-dbadacbd84af-cb6f830e-ab16-47ec-9d8f-0090de732774
|
||||
sticky_sessions: # If key exists, the sticky_sessions will be enabled, regardless what is in value. Comment out/delete the line to disable.
|
||||
hc_interval: 2 #Interval for health checks in seconds
|
||||
master_key: 910517d9-f9a1-48de-8826-dbadacbd84af-cb6f830e-ab16-47ec-9d8f-0090de732774 # Mater key for working with API server and JWT Secret
|
||||
sticky_sessions: true # Globally enables/disables Sticky session . Boolean will panic on any other than true/false .
|
||||
@@ -164,13 +164,31 @@ pub fn load_configuration(d: &str, kind: &str) -> Option<Configuration> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parce_main_config(path: &str) -> DashMap<String, String> {
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct AppConfig {
|
||||
pub sticky_sessions: bool,
|
||||
pub hc_interval: u16,
|
||||
pub hc_method: String,
|
||||
pub upstreams_conf: String,
|
||||
pub log_level: String,
|
||||
pub config_address: String,
|
||||
pub proxy_address_http: String,
|
||||
pub master_key: String,
|
||||
pub proxy_address_tls: Option<String>,
|
||||
pub tls_certificate: Option<String>,
|
||||
pub tls_key_file: Option<String>,
|
||||
}
|
||||
|
||||
// pub fn parce_main_config(path: &str) -> DashMap<String, String> {
|
||||
pub fn parce_main_config(path: &str) -> AppConfig {
|
||||
info!("Parsing configuration");
|
||||
let data = fs::read_to_string(path).unwrap();
|
||||
let reply = DashMap::new();
|
||||
let cfg: HashMap<String, String> = serde_yaml::from_str(&*data).expect("Failed to parse main config file");
|
||||
let mut cfo: AppConfig = serde_yaml::from_str(&*data).expect("Failed to parse main config file");
|
||||
cfo.hc_method = cfo.hc_method.to_uppercase();
|
||||
for (k, v) in cfg {
|
||||
reply.insert(k.to_string(), v.to_string());
|
||||
}
|
||||
reply
|
||||
cfo
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ use async_trait::async_trait;
|
||||
use dashmap::DashMap;
|
||||
use futures::channel::mpsc;
|
||||
use futures::StreamExt;
|
||||
use log::{error, info};
|
||||
use log::info;
|
||||
use pingora_core::server::ShutdownWatch;
|
||||
use pingora_core::services::background::BackgroundService;
|
||||
|
||||
@@ -17,42 +17,30 @@ impl BackgroundService for LB {
|
||||
info!("Starting background service");
|
||||
let (tx, mut rx) = mpsc::channel::<Configuration>(0);
|
||||
|
||||
let from_file = self.config.get("upstreams_conf");
|
||||
match from_file {
|
||||
Some(from_file) => {
|
||||
let tx_file = tx.clone();
|
||||
let tx_consul = tx.clone();
|
||||
let tx_file = tx.clone();
|
||||
let tx_consul = tx.clone();
|
||||
|
||||
let file_load = FromFileProvider { path: from_file.to_string() };
|
||||
let consul_load = ConsulProvider { path: from_file.to_string() };
|
||||
let file_load = FromFileProvider {
|
||||
path: self.config.upstreams_conf.clone(),
|
||||
};
|
||||
let consul_load = ConsulProvider {
|
||||
path: self.config.upstreams_conf.clone(),
|
||||
};
|
||||
|
||||
let _ = tokio::spawn(async move { file_load.start(tx_file).await });
|
||||
let _ = tokio::spawn(async move { consul_load.start(tx_consul).await });
|
||||
}
|
||||
None => {
|
||||
error!("Can't read config file");
|
||||
}
|
||||
}
|
||||
let config_address = self.config.get("config_address");
|
||||
let masterkey = self.config.get("master_key").unwrap();
|
||||
match config_address {
|
||||
Some(config_address) => {
|
||||
let api_load = APIUpstreamProvider {
|
||||
address: config_address.to_string(),
|
||||
masterkey: masterkey.value().to_string(),
|
||||
};
|
||||
let tx_api = tx.clone();
|
||||
let _ = tokio::spawn(async move { api_load.start(tx_api).await });
|
||||
}
|
||||
None => {
|
||||
error!("Can't read config file");
|
||||
}
|
||||
}
|
||||
let _ = tokio::spawn(async move { file_load.start(tx_file).await });
|
||||
let _ = tokio::spawn(async move { consul_load.start(tx_consul).await });
|
||||
|
||||
let api_load = APIUpstreamProvider {
|
||||
address: self.config.config_address.clone(),
|
||||
masterkey: self.config.master_key.clone(),
|
||||
};
|
||||
let tx_api = tx.clone();
|
||||
let _ = tokio::spawn(async move { api_load.start(tx_api).await });
|
||||
|
||||
let uu = self.ump_upst.clone();
|
||||
let ff = self.ump_full.clone();
|
||||
let im = self.ump_byid.clone();
|
||||
let (hc_method, hc_interval) = (self.config.get("hc_method").unwrap().clone(), self.config.get("hc_interval").unwrap().clone());
|
||||
let (hc_method, hc_interval) = (self.config.hc_method.clone(), self.config.hc_interval);
|
||||
let _ = tokio::spawn(async move { healthcheck::hc2(uu, ff, im, (&*hc_method.to_string(), hc_interval.to_string().parse().unwrap())).await });
|
||||
|
||||
loop {
|
||||
|
||||
@@ -12,7 +12,7 @@ impl GetHost for LB {
|
||||
fn get_host(&self, peer: &str, path: &str, backend_id: Option<&str>) -> Option<(String, u16, bool)> {
|
||||
if let Some(b) = backend_id {
|
||||
if let Some(bb) = self.ump_byid.get(b) {
|
||||
println!("BIB :===> {:?}", Some(bb.value()));
|
||||
// println!("BIB :===> {:?}", Some(bb.value()));
|
||||
return Some(bb.value().clone());
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,7 @@ impl GetHost for LB {
|
||||
}
|
||||
}
|
||||
}
|
||||
println!("BMT :===> {:?}", best_match);
|
||||
// println!("BMT :===> {:?}", best_match);
|
||||
best_match
|
||||
}
|
||||
fn get_header(&self, peer: &str, path: &str) -> Option<Vec<(String, String)>> {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::utils::auth::authenticate;
|
||||
use crate::utils::parceyaml::AppConfig;
|
||||
use crate::utils::tools::*;
|
||||
use crate::web::gethosts::GetHost;
|
||||
use async_trait::async_trait;
|
||||
@@ -18,7 +19,8 @@ pub struct LB {
|
||||
pub ump_full: Arc<UpstreamsDashMap>,
|
||||
pub ump_byid: Arc<UpstreamsIdMap>,
|
||||
pub headers: Arc<Headers>,
|
||||
pub config: Arc<DashMap<String, String>>,
|
||||
// pub config: Arc<DashMap<String, String>>,
|
||||
pub config: Arc<AppConfig>,
|
||||
pub local: Arc<(String, u16)>,
|
||||
pub proxyconf: Arc<DashMap<String, Vec<String>>>,
|
||||
}
|
||||
@@ -52,7 +54,7 @@ impl ProxyHttp for LB {
|
||||
|
||||
let mut backend_id = None;
|
||||
|
||||
if let Some(_) = self.config.get("sticky_sessions") {
|
||||
if self.config.sticky_sessions {
|
||||
if let Some(cookies) = session.req_header().headers.get("cookie") {
|
||||
if let Ok(cookie_str) = cookies.to_str() {
|
||||
for cookie in cookie_str.split(';') {
|
||||
@@ -132,7 +134,7 @@ impl ProxyHttp for LB {
|
||||
async fn response_filter(&self, _session: &mut Session, _upstream_response: &mut ResponseHeader, _ctx: &mut Self::CTX) -> Result<()> {
|
||||
// _upstream_response.insert_header("X-Proxied-From", "Fooooooooooooooo").unwrap();
|
||||
|
||||
if let Some(_) = self.config.get("sticky_sessions") {
|
||||
if self.config.sticky_sessions {
|
||||
let backend_id = _ctx.backend_id.clone();
|
||||
if let Some(bid) = self.ump_byid.get(&backend_id) {
|
||||
// let _ = _upstream_response.insert_header("set-cookie", format!("backend {}", bid.0));
|
||||
|
||||
@@ -12,8 +12,10 @@ pub fn run() {
|
||||
let file = parameters.conf.clone().unwrap();
|
||||
let maincfg = crate::utils::parceyaml::parce_main_config(file.as_str());
|
||||
|
||||
// println!("{:?}", maincfg);
|
||||
|
||||
let mut local_conf: (String, u16) = ("0.0.0.0".to_string(), 0);
|
||||
if let Some((ip, port_str)) = maincfg.get("config_address").unwrap().split_once(':') {
|
||||
if let Some((ip, port_str)) = maincfg.config_address.split_once(':') {
|
||||
if let Ok(port) = port_str.parse::<u16>() {
|
||||
local_conf = (ip.to_string(), port);
|
||||
}
|
||||
@@ -60,7 +62,7 @@ pub fn run() {
|
||||
// env_logger::Env::new();
|
||||
// env_logger::init();
|
||||
|
||||
let log_level = cfg.get("log_level").unwrap();
|
||||
let log_level = cfg.log_level.clone();
|
||||
match log_level.as_str() {
|
||||
"info" => env::set_var("RUST_LOG", "info"),
|
||||
"error" => env::set_var("RUST_LOG", "error"),
|
||||
@@ -82,17 +84,17 @@ pub fn run() {
|
||||
|
||||
let bg_srvc = background_service("bgsrvc", bg);
|
||||
let mut proxy = pingora_proxy::http_proxy_service(&server.configuration, lb);
|
||||
let bind_address_http = cfg.get("proxy_address_http").unwrap();
|
||||
let bind_address_http = cfg.proxy_address_http.clone();
|
||||
|
||||
let bind_address_tls = cfg.get("proxy_address_tls");
|
||||
let bind_address_tls = cfg.proxy_address_tls.clone();
|
||||
match bind_address_tls {
|
||||
Some(bind_address_tls) => {
|
||||
info!("Running TLS listener on :{}", bind_address_tls.value());
|
||||
let cert_path = cfg.get("tls_certificate").unwrap();
|
||||
let key_path = cfg.get("tls_key_file").unwrap();
|
||||
info!("Running TLS listener on :{}", bind_address_tls);
|
||||
let cert_path = cfg.tls_certificate.clone().unwrap();
|
||||
let key_path = cfg.tls_key_file.clone().unwrap();
|
||||
let mut tls_settings = pingora_core::listeners::tls::TlsSettings::intermediate(&cert_path, &key_path).unwrap();
|
||||
tls_settings.enable_h2();
|
||||
proxy.add_tls_with_settings(bind_address_tls.value(), None, tls_settings);
|
||||
proxy.add_tls_with_settings(&bind_address_tls, None, tls_settings);
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user