From 9978acf16d016910f73f5a946b606c75d8a962e9 Mon Sep 17 00:00:00 2001 From: Sylvain Tremblay Date: Sun, 18 Jan 2026 10:06:15 -0500 Subject: [PATCH] feat: change staticroutes->route to Option instead of MaybeString --- examples/sttest/Cargo.toml | 21 +++ examples/sttest/src/main.rs | 159 +++++++++++++++++++++++ opnsense-config-xml/src/data/opnsense.rs | 4 +- 3 files changed, 182 insertions(+), 2 deletions(-) create mode 100644 examples/sttest/Cargo.toml create mode 100644 examples/sttest/src/main.rs diff --git a/examples/sttest/Cargo.toml b/examples/sttest/Cargo.toml new file mode 100644 index 0000000..5b41e51 --- /dev/null +++ b/examples/sttest/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "sttest" +edition = "2024" +version.workspace = true +readme.workspace = true +license.workspace = true +publish = false + +[dependencies] +harmony = { path = "../../harmony" } +harmony_tui = { path = "../../harmony_tui" } +harmony_types = { path = "../../harmony_types" } +cidr = { workspace = true } +tokio = { workspace = true } +harmony_macros = { path = "../../harmony_macros" } +harmony_secret = { path = "../../harmony_secret" } +log = { workspace = true } +env_logger = { workspace = true } +url = { workspace = true } +serde = { workspace = true } +brocade = { path = "../../brocade" } diff --git a/examples/sttest/src/main.rs b/examples/sttest/src/main.rs new file mode 100644 index 0000000..fe40e8e --- /dev/null +++ b/examples/sttest/src/main.rs @@ -0,0 +1,159 @@ +use std::{ + net::{IpAddr, Ipv4Addr}, + sync::{Arc, OnceLock}, +}; + +use cidr::Ipv4Cidr; +use harmony::{ + config::secret::SshKeyPair, + data::{FileContent, FilePath}, + hardware::{HostCategory, Location, PhysicalHost, SwitchGroup}, + infra::{brocade::UnmanagedSwitch, opnsense::OPNSenseManagementInterface}, + inventory::Inventory, + modules::{ + http::StaticFilesHttpScore, + okd::{ + bootstrap_dhcp::OKDBootstrapDhcpScore, + bootstrap_load_balancer::OKDBootstrapLoadBalancerScore, dhcp::OKDDhcpScore, + dns::OKDDnsScore, ipxe::OKDIpxeScore, + }, + tftp::TftpScore, + }, + topology::{LogicalHost, UnmanagedRouter}, +}; +use harmony_macros::{ip, mac_address}; +use harmony_secret::{Secret, SecretManager}; +use harmony_types::net::Url; +use serde::{Deserialize, Serialize}; + +#[tokio::main] +async fn main() { + let firewall = harmony::topology::LogicalHost { + ip: ip!("192.168.40.1"), + name: String::from("fw0"), // settings -> general -> hostname on the opnsense firewall + }; + + let switch_client = UnmanagedSwitch::init() + .await + .expect("Failed to connect to switch"); + + let switch_client = Arc::new(switch_client); + + let opnsense = Arc::new( + harmony::infra::opnsense::OPNSenseFirewall::new(firewall, None, "root", "opnsense").await, + ); + let lan_subnet = Ipv4Addr::new(192, 168, 40, 0); + let gateway_ipv4 = Ipv4Addr::new(192, 168, 40, 1); + let gateway_ip = IpAddr::V4(gateway_ipv4); + let topology = harmony::topology::HAClusterTopology { + kubeconfig: None, + domain_name: "sttest0.harmony.mcd".to_string(), // TODO this must be set manually correctly + // when setting up the opnsense firewall in settings -> general -> domain + router: Arc::new(UnmanagedRouter::new( + gateway_ip, + Ipv4Cidr::new(lan_subnet, 24).unwrap(), + )), + load_balancer: opnsense.clone(), + firewall: opnsense.clone(), + tftp_server: opnsense.clone(), + http_server: opnsense.clone(), + dhcp_server: opnsense.clone(), + dns_server: opnsense.clone(), + control_plane: vec![ + LogicalHost { + ip: ip!("192.168.40.20"), + name: "cp0".to_string(), + }, + LogicalHost { + ip: ip!("192.168.40.21"), + name: "cp1".to_string(), + }, + LogicalHost { + ip: ip!("192.168.40.22"), + name: "cp2".to_string(), + }, + ], + bootstrap_host: LogicalHost { + ip: ip!("192.168.40.66"), + name: "bootstrap".to_string(), + }, + workers: vec![ + LogicalHost { + ip: ip!("192.168.40.30"), + name: "wk0".to_string(), + }, + ], + node_exporter: opnsense.clone(), + switch_client: switch_client.clone(), + network_manager: OnceLock::new(), + }; + + let inventory = Inventory { + location: Location::new("I am mobile".to_string(), "earth".to_string()), + switch: SwitchGroup::from([]), + firewall_mgmt: Box::new(OPNSenseManagementInterface::new()), + storage_host: vec![], + worker_host: vec![ + PhysicalHost::empty(HostCategory::Server) + .mac_address(mac_address!("64:00:6A:88:A3:50")), + ], + control_plane_host: vec![ + PhysicalHost::empty(HostCategory::Server) + .mac_address(mac_address!("F4:39:09:16:65:33")), + PhysicalHost::empty(HostCategory::Server) + .mac_address(mac_address!("F4:39:09:07:C8:F2")), + PhysicalHost::empty(HostCategory::Server) + .mac_address(mac_address!("F4:39:09:16:65:EA")), + ], + }; + + // TODO regroup smaller scores in a larger one such as this + // let okd_boostrap_preparation(); + + let bootstrap_dhcp_score = OKDBootstrapDhcpScore::new(&topology, &inventory); + let bootstrap_load_balancer_score = OKDBootstrapLoadBalancerScore::new(&topology); + let dhcp_score = OKDDhcpScore::new(&topology, &inventory); + let dns_score = OKDDnsScore::new(&topology); + let load_balancer_score = + harmony::modules::okd::load_balancer::OKDLoadBalancerScore::new(&topology); + + let ssh_key = SecretManager::get_or_prompt::().await.unwrap(); + + let tftp_score = TftpScore::new(Url::LocalFolder("./data/watchguard/tftpboot".to_string())); + let http_score = StaticFilesHttpScore { + folder_to_serve: Some(Url::LocalFolder( + "./data/watchguard/pxe-http-files".to_string(), + )), + files: vec![], + remote_path: None, + }; + + let kickstart_filename = "inventory.kickstart".to_string(); + let harmony_inventory_agent = "harmony_inventory_agent".to_string(); + + let ipxe_score = OKDIpxeScore { + kickstart_filename, + harmony_inventory_agent, + cluster_pubkey: FileContent { + path: FilePath::Relative("cluster_ssh_key.pub".to_string()), + content: ssh_key.public, + }, + }; + + harmony_tui::run( + inventory, + topology, + vec![ + // Box::new(dns_score), + Box::new(bootstrap_dhcp_score), + // Box::new(bootstrap_load_balancer_score), + // Box::new(load_balancer_score), + // Box::new(tftp_score), + // Box::new(http_score), + // Box::new(ipxe_score), + // Box::new(dhcp_score), + ], + ) + .await + .unwrap(); +} diff --git a/opnsense-config-xml/src/data/opnsense.rs b/opnsense-config-xml/src/data/opnsense.rs index ae277dc..26a83c0 100644 --- a/opnsense-config-xml/src/data/opnsense.rs +++ b/opnsense-config-xml/src/data/opnsense.rs @@ -1153,7 +1153,7 @@ pub struct UnboundGeneral { pub local_zone_type: String, pub outgoing_interface: MaybeString, pub enable_wpad: MaybeString, - pub safesearch: MaybeString, + pub safesearch: Option, } #[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)] @@ -1421,7 +1421,7 @@ pub struct StaticRoutes { #[yaserde(attribute = true)] pub version: String, #[yaserde(rename = "route")] - pub route: Option, + pub route: Option, } #[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]