fix(opnsense-config): ensure load balancer service configuration is idempotent #129

Merged
letian merged 8 commits from idempotent-load-balancer into master 2025-10-20 19:18:50 +00:00
3 changed files with 43 additions and 8 deletions
Showing only changes of commit 01206f5db1 - Show all commits

View File

@ -36,6 +36,27 @@ pub struct DnsMasq {
pub dhcp_options: Vec<DhcpOptions>,
pub dhcp_boot: Vec<DhcpBoot>,
pub dhcp_tags: Vec<RawXml>,
pub hosts: Vec<DnsmasqHost>,
}
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize, Clone)]
#[yaserde(rename = "hosts")]
pub struct DnsmasqHost {
#[yaserde(attribute = true)]
pub uuid: String,
pub host: String,
pub domain: MaybeString,
pub local: MaybeString,
pub ip: MaybeString,
pub cnames: MaybeString,
pub client_id: MaybeString,
pub hwaddr: MaybeString,
pub lease_time: MaybeString,
pub ignore: Option<u8>,
pub set_tag: MaybeString,
pub descr: MaybeString,
pub comments: MaybeString,
pub aliases: MaybeString,
}
// Represents the <dhcp> element and its nested fields.

View File

@ -189,7 +189,7 @@ pub struct System {
pub timeservers: String,
pub webgui: WebGui,
pub usevirtualterminal: u8,
pub disablenatreflection: String,
pub disablenatreflection: Option<String>,
pub disableconsolemenu: u8,
pub disablevlanhwfilter: u8,
pub disablechecksumoffloading: u8,
@ -256,7 +256,7 @@ pub struct Firmware {
#[yaserde(rename = "type")]
pub firmware_type: MaybeString,
pub subscription: MaybeString,
pub reboot: MaybeString,
pub reboot: Option<MaybeString>,
}
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
@ -1449,6 +1449,9 @@ pub struct Vip {
pub advbase: Option<MaybeString>,
pub advskew: Option<MaybeString>,
pub descr: Option<MaybeString>,
pub peer: Option<MaybeString>,
pub peer6: Option<MaybeString>,
pub nosync: Option<MaybeString>,
}
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]

View File

@ -1,11 +1,8 @@
use std::{collections::HashSet, sync::Arc};
use log::warn;
use crate::{config::OPNsenseShell, Error};
use opnsense_config_xml::{
Frontend, HAProxy, HAProxyBackend, HAProxyHealthCheck, HAProxyServer, OPNsense,
};
use crate::{config::OPNsenseShell, Error};
use std::{collections::HashSet, sync::Arc};
pub struct LoadBalancerConfig<'a> {
opnsense: &'a mut OPNsense,
@ -71,6 +68,7 @@ impl<'a> LoadBalancerConfig<'a> {
}
/// Adds the components of a new service to the HAProxy configuration.
/// This function de-duplicates servers by name to prevent configuration errors.
fn add_new_service(
&mut self,
frontend: Frontend,
@ -82,7 +80,20 @@ impl<'a> LoadBalancerConfig<'a> {
if let Some(check) = healthcheck {
haproxy.healthchecks.healthchecks.push(check);
}
haproxy.servers.servers.extend(servers);
let mut existing_server_names: HashSet<_> = haproxy
.servers
.servers
.iter()
.map(|s| s.name.clone())
.collect();
for server in servers {
if existing_server_names.insert(server.name.clone()) {
haproxy.servers.servers.push(server);
}
}
haproxy.backends.backends.push(backend);
haproxy.frontends.frontend.push(frontend);
});