fix(load-balancer): implement missing HAProxy reload and sanitize output handling
Implement the `reload_restart` method in `LoadBalancerConfig` to ensure proper HAProxy configuration management. Additionally, enhance SSH command execution by sanitizing and logging outputs effectively. This ensures robust handling of HAProxy configurations and improves debugging capabilities through trace-level logs.
This commit is contained in:
parent
a55c63ffa6
commit
0af8e7e6a8
@ -15,6 +15,7 @@ pub trait LoadBalancer: Send + Sync {
|
|||||||
async fn list_services(&self) -> Vec<LoadBalancerService>;
|
async fn list_services(&self) -> Vec<LoadBalancerService>;
|
||||||
async fn ensure_initialized(&self) -> Result<(), ExecutorError>;
|
async fn ensure_initialized(&self) -> Result<(), ExecutorError>;
|
||||||
async fn commit_config(&self) -> Result<(), ExecutorError>;
|
async fn commit_config(&self) -> Result<(), ExecutorError>;
|
||||||
|
async fn reload_restart(&self) -> Result<(), ExecutorError>;
|
||||||
async fn ensure_service_exists(
|
async fn ensure_service_exists(
|
||||||
&self,
|
&self,
|
||||||
service: &LoadBalancerService,
|
service: &LoadBalancerService,
|
||||||
|
|||||||
@ -120,8 +120,6 @@ pub enum Action {
|
|||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct MacAddress(pub [u8; 6]);
|
pub struct MacAddress(pub [u8; 6]);
|
||||||
|
|
||||||
// TODO create a small macro to provide a nice API to initiate a MacAddress
|
|
||||||
// MacAddress::from!("00:90:7f:df:2c:23"),
|
|
||||||
|
|
||||||
impl MacAddress {
|
impl MacAddress {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -133,7 +131,7 @@ impl MacAddress {
|
|||||||
impl From<&MacAddress> for String {
|
impl From<&MacAddress> for String {
|
||||||
fn from(value: &MacAddress) -> Self {
|
fn from(value: &MacAddress) -> Self {
|
||||||
format!(
|
format!(
|
||||||
"{}:{}:{}:{}:{}:{}",
|
"{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
|
||||||
value.0[0], value.0[1], value.0[2], value.0[3], value.0[4], value.0[5]
|
value.0[0], value.0[1], value.0[2], value.0[3], value.0[4], value.0[5]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -142,8 +140,8 @@ impl From<&MacAddress> for String {
|
|||||||
impl std::fmt::Display for MacAddress {
|
impl std::fmt::Display for MacAddress {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
f.write_fmt(format_args!(
|
f.write_fmt(format_args!(
|
||||||
"MacAddress {}:{}:{}:{}:{}:{}",
|
"MacAddress {}",
|
||||||
self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5]
|
String::from(self)
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,9 +3,13 @@ use log::{debug, info, warn};
|
|||||||
use opnsense_config_xml::{Frontend, HAProxy, HAProxyBackend, HAProxyHealthCheck, HAProxyServer};
|
use opnsense_config_xml::{Frontend, HAProxy, HAProxyBackend, HAProxyHealthCheck, HAProxyServer};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::{executors::ExecutorError, topology::{
|
use crate::{
|
||||||
BackendServer, HealthCheck, HttpMethod, HttpStatusCode, IpAddress, LoadBalancer, LoadBalancerService, LogicalHost
|
executors::ExecutorError,
|
||||||
}};
|
topology::{
|
||||||
|
BackendServer, HealthCheck, HttpMethod, HttpStatusCode, IpAddress, LoadBalancer,
|
||||||
|
LoadBalancerService, LogicalHost,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
use super::OPNSenseFirewall;
|
use super::OPNSenseFirewall;
|
||||||
|
|
||||||
@ -38,23 +42,33 @@ impl LoadBalancer for OPNSenseFirewall {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn commit_config(&self) -> Result<(), ExecutorError> {
|
async fn commit_config(&self) -> Result<(), ExecutorError> {
|
||||||
OPNSenseFirewall::commit_config(self).await?;
|
OPNSenseFirewall::commit_config(self).await
|
||||||
todo!("Make sure load balancer is reloaded properly")
|
}
|
||||||
|
|
||||||
|
async fn reload_restart(&self) -> Result<(), ExecutorError> {
|
||||||
|
self.opnsense_config
|
||||||
|
.write()
|
||||||
|
.await
|
||||||
|
.load_balancer()
|
||||||
|
.reload_restart()
|
||||||
|
.await
|
||||||
|
.map_err(|e| ExecutorError::UnexpectedError(e.to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn ensure_initialized(&self) -> Result<(), ExecutorError> {
|
async fn ensure_initialized(&self) -> Result<(), ExecutorError> {
|
||||||
let mut config = self.opnsense_config.write().await;
|
let mut config = self.opnsense_config.write().await;
|
||||||
let load_balancer = config.load_balancer();
|
let load_balancer = config.load_balancer();
|
||||||
if let Some(_) = load_balancer.get_full_config() {
|
if let Some(config) = load_balancer.get_full_config() {
|
||||||
debug!("HAProxy config available in opnsense config, assuming it is already installed");
|
debug!("HAProxy config available in opnsense config, assuming it is already installed, {config:?}");
|
||||||
return Ok(());
|
} else {
|
||||||
|
config.install_package("os-haproxy").await.map_err(|e| {
|
||||||
|
ExecutorError::UnexpectedError(format!(
|
||||||
|
"Executor failed when trying to install os-haproxy package with error {e:?}"
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
config.install_package("os-haproxy").await.map_err(|e| {
|
|
||||||
ExecutorError::UnexpectedError(format!(
|
|
||||||
"Executor failed when trying to install os-haproxy package with error {e:?}"
|
|
||||||
))
|
|
||||||
})?;
|
|
||||||
config.load_balancer().enable(true);
|
config.load_balancer().enable(true);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -67,7 +81,6 @@ impl LoadBalancer for OPNSenseFirewall {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub(crate) fn haproxy_xml_config_to_harmony_loadbalancer(
|
pub(crate) fn haproxy_xml_config_to_harmony_loadbalancer(
|
||||||
haproxy: &Option<HAProxy>,
|
haproxy: &Option<HAProxy>,
|
||||||
) -> Vec<LoadBalancerService> {
|
) -> Vec<LoadBalancerService> {
|
||||||
|
|||||||
@ -64,7 +64,12 @@ impl Interpret for LoadBalancerInterpret {
|
|||||||
|
|
||||||
info!("Applying load balancer configuration");
|
info!("Applying load balancer configuration");
|
||||||
topology.load_balancer.commit_config().await?;
|
topology.load_balancer.commit_config().await?;
|
||||||
todo!()
|
info!("Making a full reload and restart of haproxy");
|
||||||
|
topology.load_balancer.reload_restart().await?;
|
||||||
|
Ok(Outcome::success(format!(
|
||||||
|
"Load balancer successfully configured {} services",
|
||||||
|
self.score.public_services.len() + self.score.private_services.len()
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
fn get_name(&self) -> InterpretName {
|
fn get_name(&self) -> InterpretName {
|
||||||
InterpretName::LoadBalancer
|
InterpretName::LoadBalancer
|
||||||
|
|||||||
@ -110,6 +110,7 @@ pub struct Filters {
|
|||||||
#[yaserde(rename = "rule")]
|
#[yaserde(rename = "rule")]
|
||||||
pub rules: Vec<Rule>,
|
pub rules: Vec<Rule>,
|
||||||
pub bypassstaticroutes: Option<MaybeString>,
|
pub bypassstaticroutes: Option<MaybeString>,
|
||||||
|
pub scrub: Option<RawXml>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
|
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
|
||||||
@ -338,6 +339,10 @@ pub struct Snmpd {
|
|||||||
pub struct Syslog {
|
pub struct Syslog {
|
||||||
pub reverse: Option<MaybeString>,
|
pub reverse: Option<MaybeString>,
|
||||||
pub preservelogs: Option<MaybeString>,
|
pub preservelogs: Option<MaybeString>,
|
||||||
|
pub nologdefaultblock: Option<u8>,
|
||||||
|
pub nologdefaultpass: Option<u8>,
|
||||||
|
pub nologbogons: Option<u8>,
|
||||||
|
pub nologprivatenets: Option<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
|
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
|
||||||
|
|||||||
@ -6,7 +6,7 @@ use std::{
|
|||||||
use tokio_stream::StreamExt;
|
use tokio_stream::StreamExt;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use log::{debug, info};
|
use log::{debug, info, trace};
|
||||||
use russh::{
|
use russh::{
|
||||||
client::{Config, Handler, Msg},
|
client::{Config, Handler, Msg},
|
||||||
Channel,
|
Channel,
|
||||||
@ -205,5 +205,7 @@ async fn wait_for_completion(channel: &mut Channel<Msg>) -> Result<String, Error
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(String::from_utf8(output).unwrap_or_default())
|
let output = String::from_utf8(output).expect("Output should be UTF-8 compatible");
|
||||||
|
trace!("{output}");
|
||||||
|
Ok(output)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ use opnsense_config_xml::{
|
|||||||
Frontend, HAProxy, HAProxyBackend, HAProxyHealthCheck, HAProxyServer, OPNsense,
|
Frontend, HAProxy, HAProxyBackend, HAProxyHealthCheck, HAProxyServer, OPNsense,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::config::OPNsenseShell;
|
use crate::{config::OPNsenseShell, Error};
|
||||||
|
|
||||||
pub struct LoadBalancerConfig<'a> {
|
pub struct LoadBalancerConfig<'a> {
|
||||||
opnsense: &'a mut OPNsense,
|
opnsense: &'a mut OPNsense,
|
||||||
@ -56,4 +56,13 @@ impl<'a> LoadBalancerConfig<'a> {
|
|||||||
pub fn add_servers(&mut self, mut servers: Vec<HAProxyServer>) {
|
pub fn add_servers(&mut self, mut servers: Vec<HAProxyServer>) {
|
||||||
self.with_haproxy(|haproxy| haproxy.servers.servers.append(&mut servers));
|
self.with_haproxy(|haproxy| haproxy.servers.servers.append(&mut servers));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn reload_restart(&self) -> Result<(), Error> {
|
||||||
|
self.opnsense_shell.exec("configctl haproxy stop").await?;
|
||||||
|
self.opnsense_shell.exec("configctl template reload OPNsense/HAProxy").await?;
|
||||||
|
self.opnsense_shell.exec("configctl template reload OPNsense/Syslog").await?;
|
||||||
|
self.opnsense_shell.exec("configctl haproxy configtest").await?;
|
||||||
|
self.opnsense_shell.exec("configctl haproxy start").await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user