"Update Harmony Opnsense Configuration"

Improved configuration handling for Harmony Opnsense setup. Implemented changes to opnsense-config module to support various settings, including load balancer configuration and DHCP server settings. This update enhances the overall stability and functionality of the Harmony Opnsense setup process.
This commit is contained in:
jeangab 2025-01-11 13:52:57 -05:00
parent 9e6f22d7ea
commit 1665198e66
9 changed files with 33 additions and 23 deletions

View File

@ -15,6 +15,6 @@ impl ManagementInterface for HPIlo {
} }
fn get_supported_protocol_names(&self) -> String { fn get_supported_protocol_names(&self) -> String {
todo!() "ipmi,redfish".to_string()
} }
} }

View File

@ -23,6 +23,7 @@ impl LoadBalancer for OPNSenseFirewall {
} }
async fn add_service(&self, service: &LoadBalancerService) -> Result<(), ExecutorError> { async fn add_service(&self, service: &LoadBalancerService) -> Result<(), ExecutorError> {
warn!("TODO : the current implementation does not check / cleanup / merge with existing haproxy services properly. Make sure to manually verify that the configuration is correct after executing any operation here");
let mut config = self.opnsense_config.write().await; let mut config = self.opnsense_config.write().await;
let (frontend, backend, servers, healthcheck) = let (frontend, backend, servers, healthcheck) =
harmony_load_balancer_service_to_haproxy_xml(service); harmony_load_balancer_service_to_haproxy_xml(service);
@ -66,7 +67,6 @@ impl LoadBalancer for OPNSenseFirewall {
"Executor failed when trying to install os-haproxy package with error {e:?}" "Executor failed when trying to install os-haproxy package with error {e:?}"
)) ))
})?; })?;
todo!()
} }
config.load_balancer().enable(true); config.load_balancer().enable(true);

View File

@ -18,38 +18,24 @@ impl OKDBootstrapLoadBalancerScore {
pub fn new(topology: &HAClusterTopology) -> Self { pub fn new(topology: &HAClusterTopology) -> Self {
let private_ip = topology.router.get_gateway(); let private_ip = topology.router.get_gateway();
let bootstrap_host = &topology.bootstrap_host;
let private_services = vec![ let private_services = vec![
LoadBalancerService { LoadBalancerService {
backend_servers: vec![BackendServer { backend_servers: Self::topology_to_backend_server(topology, 80),
address: bootstrap_host.ip.to_string(),
port: 80,
}],
listening_port: SocketAddr::new(private_ip, 80), listening_port: SocketAddr::new(private_ip, 80),
health_check: Some(HealthCheck::TCP(None)), health_check: Some(HealthCheck::TCP(None)),
}, },
LoadBalancerService { LoadBalancerService {
backend_servers: vec![BackendServer { backend_servers: Self::topology_to_backend_server(topology, 443),
address: bootstrap_host.ip.to_string(),
port: 443,
}],
listening_port: SocketAddr::new(private_ip, 443), listening_port: SocketAddr::new(private_ip, 443),
health_check: Some(HealthCheck::TCP(None)), health_check: Some(HealthCheck::TCP(None)),
}, },
LoadBalancerService { LoadBalancerService {
backend_servers: vec![BackendServer { backend_servers: Self::topology_to_backend_server(topology, 22623),
address: bootstrap_host.ip.to_string(),
port: 22623,
}],
listening_port: SocketAddr::new(private_ip, 22623), listening_port: SocketAddr::new(private_ip, 22623),
health_check: Some(HealthCheck::TCP(None)), health_check: Some(HealthCheck::TCP(None)),
}, },
LoadBalancerService { LoadBalancerService {
backend_servers: vec![BackendServer { backend_servers: Self::topology_to_backend_server(topology, 6443),
address: bootstrap_host.ip.to_string(),
port: 6443,
}],
listening_port: SocketAddr::new(private_ip, 6443), listening_port: SocketAddr::new(private_ip, 6443),
health_check: Some(HealthCheck::HTTP( health_check: Some(HealthCheck::HTTP(
"/readyz".to_string(), "/readyz".to_string(),
@ -65,6 +51,24 @@ impl OKDBootstrapLoadBalancerScore {
}, },
} }
} }
fn topology_to_backend_server(
topology: &HAClusterTopology,
port: u16,
) -> Vec<BackendServer> {
let mut backend: Vec<_> = topology
.control_plane
.iter()
.map(|cp| BackendServer {
address: cp.ip.to_string(),
port,
})
.collect();
backend.push(BackendServer {
address: topology.bootstrap_host.ip.to_string(),
port,
});
backend
}
} }
impl Score for OKDBootstrapLoadBalancerScore { impl Score for OKDBootstrapLoadBalancerScore {

View File

@ -16,6 +16,8 @@ pub struct DhcpInterface {
pub enable: Option<MaybeString>, pub enable: Option<MaybeString>,
pub gateway: Option<MaybeString>, pub gateway: Option<MaybeString>,
pub domain: Option<MaybeString>, pub domain: Option<MaybeString>,
pub tftp: Option<String>,
pub bootfilename: Option<String>,
pub netboot: Option<u32>, pub netboot: Option<u32>,
pub nextserver: Option<String>, pub nextserver: Option<String>,
pub filename64: Option<String>, pub filename64: Option<String>,

View File

@ -32,6 +32,7 @@ pub struct Interface {
pub dhcp6_ia_pd_len: Option<MaybeString>, pub dhcp6_ia_pd_len: Option<MaybeString>,
pub networks: Option<MaybeString>, pub networks: Option<MaybeString>,
pub subnetv6: Option<MaybeString>, pub subnetv6: Option<MaybeString>,
pub gateway: Option<MaybeString>,
pub media: Option<MaybeString>, pub media: Option<MaybeString>,
pub mediaopt: Option<MaybeString>, pub mediaopt: Option<MaybeString>,
#[yaserde(rename = "track6-interface")] #[yaserde(rename = "track6-interface")]

View File

@ -1380,7 +1380,7 @@ pub struct StaticRoutes {
#[yaserde(attribute)] #[yaserde(attribute)]
pub version: String, pub version: String,
#[yaserde(rename = "route")] #[yaserde(rename = "route")]
pub route: MaybeString, pub route: Option<MaybeString>,
} }
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)] #[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]

View File

@ -68,7 +68,7 @@ impl Config {
pub async fn install_package(&mut self, package_name: &str) -> Result<(), Error> { pub async fn install_package(&mut self, package_name: &str) -> Result<(), Error> {
info!("Installing opnsense package {package_name}"); info!("Installing opnsense package {package_name}");
let output = self.shell let output = self.shell
.exec(&format!("/usr/local/opnsense/scripts/firmware/install.sh {package_name}")) .exec(&format!("/bin/sh -c \"export LOCKFILE=/dev/stdout && /usr/local/opnsense/scripts/firmware/install.sh {package_name}\""))
.await?; .await?;
info!("Installation output {output}"); info!("Installation output {output}");
self.reload_config().await?; self.reload_config().await?;
@ -107,7 +107,7 @@ impl Config {
password: &str, password: &str,
) -> Self { ) -> Self {
let config = Arc::new(client::Config { let config = Arc::new(client::Config {
inactivity_timeout: Some(Duration::from_secs(5)), inactivity_timeout: None,
..<_>::default() ..<_>::default()
}); });

View File

@ -201,11 +201,13 @@ impl<'a> DhcpConfig<'a> {
pub fn set_next_server(&mut self, ip: Ipv4Addr) { pub fn set_next_server(&mut self, ip: Ipv4Addr) {
self.enable_netboot(); self.enable_netboot();
self.get_lan_dhcpd().nextserver = Some(ip.to_string()); self.get_lan_dhcpd().nextserver = Some(ip.to_string());
self.get_lan_dhcpd().tftp = Some(ip.to_string());
} }
pub fn set_boot_filename(&mut self, boot_filename: &str) { pub fn set_boot_filename(&mut self, boot_filename: &str) {
self.enable_netboot(); self.enable_netboot();
self.get_lan_dhcpd().filename64 = Some(boot_filename.to_string()); self.get_lan_dhcpd().filename64 = Some(boot_filename.to_string());
self.get_lan_dhcpd().bootfilename = Some(boot_filename.to_string());
} }
} }

View File

@ -61,6 +61,7 @@ impl<'a> LoadBalancerConfig<'a> {
self.opnsense_shell.exec("configctl haproxy stop").await?; 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/HAProxy").await?;
self.opnsense_shell.exec("configctl template reload OPNsense/Syslog").await?; self.opnsense_shell.exec("configctl template reload OPNsense/Syslog").await?;
self.opnsense_shell.exec("/usr/local/sbin/haproxy -c -f /usr/local/etc/haproxy.conf.staging").await?;
// This script copies the staging config to production config. I am not 100% sure it is // This script copies the staging config to production config. I am not 100% sure it is
// required in the context // required in the context