harmony/harmony/src/domain/topology/load_balancer.rs

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>),
}