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