119 lines
3.2 KiB
Rust
119 lines
3.2 KiB
Rust
use std::{net::SocketAddr, str::FromStr};
|
|
|
|
use async_trait::async_trait;
|
|
use log::debug;
|
|
use serde::Serialize;
|
|
|
|
use super::LogicalHost;
|
|
use crate::executors::ExecutorError;
|
|
use harmony_types::net::IpAddress;
|
|
|
|
impl std::fmt::Debug for dyn LoadBalancer {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
f.write_fmt(format_args!("LoadBalancer {}", self.get_ip()))
|
|
}
|
|
}
|
|
|
|
#[async_trait]
|
|
pub trait LoadBalancer: Send + Sync {
|
|
fn get_ip(&self) -> IpAddress;
|
|
fn get_host(&self) -> LogicalHost;
|
|
async fn add_service(&self, service: &LoadBalancerService) -> Result<(), ExecutorError>;
|
|
async fn remove_service(&self, service: &LoadBalancerService) -> Result<(), ExecutorError>;
|
|
async fn list_services(&self) -> Vec<LoadBalancerService>;
|
|
async fn ensure_initialized(&self) -> Result<(), ExecutorError>;
|
|
async fn commit_config(&self) -> Result<(), ExecutorError>;
|
|
async fn reload_restart(&self) -> Result<(), ExecutorError>;
|
|
async fn ensure_service_exists(
|
|
&self,
|
|
service: &LoadBalancerService,
|
|
) -> Result<(), ExecutorError> {
|
|
debug!(
|
|
"Listing LoadBalancer services {:?}",
|
|
self.list_services().await
|
|
);
|
|
if !self.list_services().await.contains(service) {
|
|
self.add_service(service).await?;
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Clone, Serialize)]
|
|
pub struct LoadBalancerService {
|
|
pub backend_servers: Vec<BackendServer>,
|
|
pub listening_port: SocketAddr,
|
|
pub health_check: Option<HealthCheck>,
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Clone, Serialize)]
|
|
pub struct BackendServer {
|
|
// TODO should not be a string, probably IPAddress
|
|
pub address: String,
|
|
pub port: u16,
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Serialize)]
|
|
pub enum HttpMethod {
|
|
GET,
|
|
POST,
|
|
PUT,
|
|
PATCH,
|
|
DELETE,
|
|
}
|
|
|
|
impl From<String> for HttpMethod {
|
|
fn from(value: String) -> Self {
|
|
Self::from_str(&value).unwrap()
|
|
}
|
|
}
|
|
|
|
impl FromStr for HttpMethod {
|
|
type Err = String;
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
match s.to_uppercase().as_str() {
|
|
"GET" => Ok(HttpMethod::GET),
|
|
"POST" => Ok(HttpMethod::POST),
|
|
"PUT" => Ok(HttpMethod::PUT),
|
|
"PATCH" => Ok(HttpMethod::PATCH),
|
|
"DELETE" => Ok(HttpMethod::DELETE),
|
|
_ => Err(format!("Invalid HTTP method: {}", s)),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Display for HttpMethod {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
match self {
|
|
HttpMethod::GET => write!(f, "GET"),
|
|
HttpMethod::POST => write!(f, "POST"),
|
|
HttpMethod::PUT => write!(f, "PUT"),
|
|
HttpMethod::PATCH => write!(f, "PATCH"),
|
|
HttpMethod::DELETE => write!(f, "DELETE"),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Serialize)]
|
|
pub enum HttpStatusCode {
|
|
Success2xx,
|
|
UserError4xx,
|
|
ServerError5xx,
|
|
}
|
|
|
|
|
|
#[derive(Debug, Clone, PartialEq, Serialize)]
|
|
pub enum SSL {
|
|
SSL,
|
|
Disabled,
|
|
Default,
|
|
SNI,
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Serialize)]
|
|
pub enum HealthCheck {
|
|
HTTP(String, HttpMethod, HttpStatusCode, SSL),
|
|
TCP(Option<u16>),
|
|
}
|