diff --git a/data/pxe/okd/README.md b/data/pxe/okd/README.md new file mode 100644 index 0000000..69a4b35 --- /dev/null +++ b/data/pxe/okd/README.md @@ -0,0 +1,3 @@ +Here lies all the data files required for an OKD cluster PXE boot setup. + +This inclues ISO files, binary boot files, ipxe, etc. diff --git a/data/pxe/okd/tftpboot/ipxe.efi b/data/pxe/okd/tftpboot/ipxe.efi new file mode 100644 index 0000000..24a9510 Binary files /dev/null and b/data/pxe/okd/tftpboot/ipxe.efi differ diff --git a/data/pxe/okd/tftpboot/undionly.kpxe b/data/pxe/okd/tftpboot/undionly.kpxe new file mode 100644 index 0000000..a265f30 Binary files /dev/null and b/data/pxe/okd/tftpboot/undionly.kpxe differ diff --git a/examples/okd_pxe/Cargo.toml b/examples/okd_pxe/Cargo.toml new file mode 100644 index 0000000..04a70b0 --- /dev/null +++ b/examples/okd_pxe/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "example-pxe" +edition = "2024" +version.workspace = true +readme.workspace = true +license.workspace = true +publish = false + +[dependencies] +harmony = { path = "../../harmony" } +harmony_cli = { path = "../../harmony_cli" } +harmony_types = { path = "../../harmony_types" } +cidr = { workspace = true } +tokio = { workspace = true } +harmony_macros = { path = "../../harmony_macros" } +log = { workspace = true } +env_logger = { workspace = true } +url = { workspace = true } diff --git a/examples/okd_pxe/src/main.rs b/examples/okd_pxe/src/main.rs new file mode 100644 index 0000000..576d09d --- /dev/null +++ b/examples/okd_pxe/src/main.rs @@ -0,0 +1,32 @@ +mod topology; + +use harmony::{ + modules::{dhcp::DhcpScore, tftp::TftpScore}, + score::Score, + topology::{HAClusterTopology, Url}, +}; + +use crate::topology::{get_inventory, get_topology}; + +#[tokio::main] +async fn main() { + let inventory = get_inventory(); + let topology = get_topology().await; + let gateway_ip = topology.router.get_gateway(); + + let scores: Vec>> = vec![ + Box::new(DhcpScore { + host_binding: vec![], + next_server: Some(topology.router.get_gateway()), + boot_filename: None, + filename: Some("undionly.kpxe".to_string()), + filename64: Some("ipxe.efi".to_string()), + filenameipxe: Some(format!("http://{gateway_ip}:8080/boot.ipxe").to_string()), + }), + Box::new(TftpScore { + files_to_serve: Url::LocalFolder("./data/pxe/okd/tftpboot/".to_string()), + }), + ]; + + harmony_cli::run(inventory, topology, scores, None).await.unwrap(); +} diff --git a/examples/okd_pxe/src/topology.rs b/examples/okd_pxe/src/topology.rs new file mode 100644 index 0000000..3e3d1f0 --- /dev/null +++ b/examples/okd_pxe/src/topology.rs @@ -0,0 +1,65 @@ +use std::{ + net::{IpAddr, Ipv4Addr}, + sync::Arc, +}; + +use cidr::Ipv4Cidr; +use harmony::{ + hardware::{FirewallGroup, HostCategory, Location, PhysicalHost, SwitchGroup}, + infra::opnsense::OPNSenseManagementInterface, + inventory::Inventory, + topology::{HAClusterTopology, LogicalHost, UnmanagedRouter}, +}; +use harmony_macros::{ip, ipv4}; + +pub async fn get_topology() -> HAClusterTopology { + let firewall = harmony::topology::LogicalHost { + ip: ip!("192.168.1.1"), + name: String::from("opnsense-1"), + }; + + let opnsense = Arc::new( + harmony::infra::opnsense::OPNSenseFirewall::new(firewall, None, "root", "opnsense").await, + ); + let lan_subnet = ipv4!("192.168.1.0"); + let gateway_ipv4 = ipv4!("192.168.1.1"); + let gateway_ip = IpAddr::V4(gateway_ipv4); + harmony::topology::HAClusterTopology { + domain_name: "demo.harmony.mcd".to_string(), + 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!("10.100.8.20"), + name: "cp0".to_string(), + }], + bootstrap_host: LogicalHost { + ip: ip!("10.100.8.20"), + name: "cp0".to_string(), + }, + workers: vec![], + switch: vec![], + } +} + +pub fn get_inventory() -> Inventory { + Inventory { + location: Location::new( + "Some virtual machine or maybe a physical machine if you're cool".to_string(), + "testopnsense".to_string(), + ), + switch: SwitchGroup::from([]), + firewall: FirewallGroup::from([PhysicalHost::empty(HostCategory::Firewall) + .management(Arc::new(OPNSenseManagementInterface::new()))]), + storage_host: vec![], + worker_host: vec![], + control_plane_host: vec![], + } +}