From a31b459f337dd3de883e6c10908c2acd71aae3bb Mon Sep 17 00:00:00 2001 From: Ian Letourneau Date: Wed, 3 Sep 2025 21:55:23 -0400 Subject: [PATCH] fix: de-duplicate backend servers list mapped from topology --- harmony/src/infra/opnsense/load_balancer.rs | 3 +- .../modules/okd/bootstrap_load_balancer.rs | 3 ++ opnsense-config/src/modules/load_balancer.rs | 31 ++++++++++--------- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/harmony/src/infra/opnsense/load_balancer.rs b/harmony/src/infra/opnsense/load_balancer.rs index 3d981ad..9d8154a 100644 --- a/harmony/src/infra/opnsense/load_balancer.rs +++ b/harmony/src/infra/opnsense/load_balancer.rs @@ -108,8 +108,7 @@ pub(crate) fn haproxy_xml_config_to_harmony_loadbalancer( } None => { warn!( - "HAProxy config could not find a matching backend for frontend {:?}", - frontend + "HAProxy config could not find a matching backend for frontend {frontend:?}" ); } } diff --git a/harmony/src/modules/okd/bootstrap_load_balancer.rs b/harmony/src/modules/okd/bootstrap_load_balancer.rs index d6cd2f3..63725f0 100644 --- a/harmony/src/modules/okd/bootstrap_load_balancer.rs +++ b/harmony/src/modules/okd/bootstrap_load_balancer.rs @@ -54,6 +54,7 @@ impl OKDBootstrapLoadBalancerScore { }, } } + fn topology_to_backend_server(topology: &HAClusterTopology, port: u16) -> Vec { let mut backend: Vec<_> = topology .control_plane @@ -67,6 +68,8 @@ impl OKDBootstrapLoadBalancerScore { address: topology.bootstrap_host.ip.to_string(), port, }); + + backend.dedup(); backend } } diff --git a/opnsense-config/src/modules/load_balancer.rs b/opnsense-config/src/modules/load_balancer.rs index 1a35388..6ef6b9b 100644 --- a/opnsense-config/src/modules/load_balancer.rs +++ b/opnsense-config/src/modules/load_balancer.rs @@ -47,9 +47,22 @@ impl<'a> LoadBalancerConfig<'a> { healthcheck: Option, ) { self.remove_service_by_bind_address(&frontend.bind); + self.remove_servers(&servers); + self.add_new_service(frontend, backend, servers, healthcheck); } + // Remove the corresponding real servers based on their name if they already exist. + fn remove_servers(&mut self, servers: &[HAProxyServer]) { + let server_names: HashSet<_> = servers.iter().map(|s| s.name.clone()).collect(); + self.with_haproxy(|haproxy| { + haproxy + .servers + .servers + .retain(|s| !server_names.contains(&s.name)); + }); + } + /// Removes a service and its dependent components based on the frontend's bind address. /// This performs a cascading delete of the frontend, backend, servers, and health check. fn remove_service_by_bind_address(&mut self, bind_address: &str) { @@ -63,7 +76,7 @@ impl<'a> LoadBalancerConfig<'a> { }; remove_healthcheck(haproxy, &old_backend); - remove_servers(haproxy, &old_backend); + remove_linked_servers(haproxy, &old_backend); }); } @@ -81,19 +94,7 @@ impl<'a> LoadBalancerConfig<'a> { haproxy.healthchecks.healthchecks.push(check); } - 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.servers.servers.extend(servers); haproxy.backends.backends.push(backend); haproxy.frontends.frontend.push(frontend); }); @@ -162,7 +163,7 @@ fn remove_healthcheck(haproxy: &mut HAProxy, backend: &HAProxyBackend) { } /// Remove the backend's servers. This assumes servers are not shared between services. -fn remove_servers(haproxy: &mut HAProxy, backend: &HAProxyBackend) { +fn remove_linked_servers(haproxy: &mut HAProxy, backend: &HAProxyBackend) { if let Some(server_uuids_str) = &backend.linked_servers.content { let server_uuids_to_remove: HashSet<_> = server_uuids_str.split(',').collect(); haproxy