use async_trait::async_trait; use harmony_macros::ip; use harmony_types::net::MacAddress; use log::info; use crate::executors::ExecutorError; use crate::interpret::InterpretError; use crate::interpret::Outcome; use super::DHCPStaticEntry; use super::DhcpServer; use super::DnsRecord; use super::DnsRecordType; use super::DnsServer; use super::Firewall; use super::HttpServer; use super::IpAddress; use super::K8sclient; use super::LoadBalancer; use super::LoadBalancerService; use super::LogicalHost; use super::Router; use super::TftpServer; use super::Topology; use super::Url; use super::k8s::K8sClient; use std::sync::Arc; #[derive(Debug, Clone)] pub struct HAClusterTopology { pub domain_name: String, pub router: Arc, pub load_balancer: Arc, pub firewall: Arc, pub dhcp_server: Arc, pub tftp_server: Arc, pub http_server: Arc, pub dns_server: Arc, pub bootstrap_host: LogicalHost, pub control_plane: Vec, pub workers: Vec, pub switch: Vec, } #[async_trait] impl Topology for HAClusterTopology { fn name(&self) -> &str { "HAClusterTopology" } async fn ensure_ready(&self) -> Result { todo!( "ensure_ready, not entirely sure what it should do here, probably something like verify that the hosts are reachable and all services are up and ready." ) } } #[async_trait] impl K8sclient for HAClusterTopology { async fn k8s_client(&self) -> Result, String> { Ok(Arc::new( K8sClient::try_default().await.map_err(|e| e.to_string())?, )) } } impl HAClusterTopology { pub fn autoload() -> Self { let dummy_infra = Arc::new(DummyInfra {}); let dummy_host = LogicalHost { ip: ip!("0.0.0.0"), name: "dummyhost".to_string(), }; Self { domain_name: "DummyTopology".to_string(), router: dummy_infra.clone(), load_balancer: dummy_infra.clone(), firewall: dummy_infra.clone(), dhcp_server: dummy_infra.clone(), tftp_server: dummy_infra.clone(), http_server: dummy_infra.clone(), dns_server: dummy_infra.clone(), bootstrap_host: dummy_host, control_plane: vec![], workers: vec![], switch: vec![], } } } #[async_trait] impl DnsServer for HAClusterTopology { async fn register_dhcp_leases(&self, register: bool) -> Result<(), ExecutorError> { self.dns_server.register_dhcp_leases(register).await } async fn register_hosts(&self, hosts: Vec) -> Result<(), ExecutorError> { self.dns_server.register_hosts(hosts).await } fn remove_record(&self, name: &str, record_type: DnsRecordType) -> Result<(), ExecutorError> { self.dns_server.remove_record(name, record_type) } async fn list_records(&self) -> Vec { self.dns_server.list_records().await } fn get_ip(&self) -> IpAddress { self.dns_server.get_ip() } fn get_host(&self) -> LogicalHost { self.dns_server.get_host() } async fn commit_config(&self) -> Result<(), ExecutorError> { self.dns_server.commit_config().await } } #[async_trait] impl LoadBalancer for HAClusterTopology { fn get_ip(&self) -> IpAddress { self.load_balancer.get_ip() } fn get_host(&self) -> LogicalHost { self.load_balancer.get_host() } async fn add_service(&self, service: &LoadBalancerService) -> Result<(), ExecutorError> { self.load_balancer.add_service(service).await } async fn remove_service(&self, service: &LoadBalancerService) -> Result<(), ExecutorError> { self.load_balancer.remove_service(service).await } async fn list_services(&self) -> Vec { self.load_balancer.list_services().await } async fn ensure_initialized(&self) -> Result<(), ExecutorError> { self.load_balancer.ensure_initialized().await } async fn commit_config(&self) -> Result<(), ExecutorError> { self.load_balancer.commit_config().await } async fn reload_restart(&self) -> Result<(), ExecutorError> { self.load_balancer.reload_restart().await } } #[async_trait] impl DhcpServer for HAClusterTopology { async fn add_static_mapping(&self, entry: &DHCPStaticEntry) -> Result<(), ExecutorError> { self.dhcp_server.add_static_mapping(entry).await } async fn remove_static_mapping(&self, mac: &MacAddress) -> Result<(), ExecutorError> { self.dhcp_server.remove_static_mapping(mac).await } async fn list_static_mappings(&self) -> Vec<(MacAddress, IpAddress)> { self.dhcp_server.list_static_mappings().await } async fn set_next_server(&self, ip: IpAddress) -> Result<(), ExecutorError> { self.dhcp_server.set_next_server(ip).await } async fn set_boot_filename(&self, boot_filename: &str) -> Result<(), ExecutorError> { self.dhcp_server.set_boot_filename(boot_filename).await } fn get_ip(&self) -> IpAddress { self.dhcp_server.get_ip() } fn get_host(&self) -> LogicalHost { self.dhcp_server.get_host() } async fn commit_config(&self) -> Result<(), ExecutorError> { self.dhcp_server.commit_config().await } async fn set_filename(&self, filename: &str) -> Result<(), ExecutorError> { self.dhcp_server.set_filename(filename).await } async fn set_filename64(&self, filename64: &str) -> Result<(), ExecutorError> { self.dhcp_server.set_filename64(filename64).await } async fn set_filenameipxe(&self, filenameipxe: &str) -> Result<(), ExecutorError> { self.dhcp_server.set_filenameipxe(filenameipxe).await } } #[async_trait] impl TftpServer for HAClusterTopology { async fn serve_files(&self, url: &Url) -> Result<(), ExecutorError> { self.tftp_server.serve_files(url).await } fn get_ip(&self) -> IpAddress { self.tftp_server.get_ip() } async fn set_ip(&self, ip: IpAddress) -> Result<(), ExecutorError> { self.tftp_server.set_ip(ip).await } async fn ensure_initialized(&self) -> Result<(), ExecutorError> { self.tftp_server.ensure_initialized().await } async fn commit_config(&self) -> Result<(), ExecutorError> { self.tftp_server.commit_config().await } async fn reload_restart(&self) -> Result<(), ExecutorError> { self.tftp_server.reload_restart().await } } impl Router for HAClusterTopology { fn get_gateway(&self) -> super::IpAddress { self.router.get_gateway() } fn get_cidr(&self) -> cidr::Ipv4Cidr { self.router.get_cidr() } fn get_host(&self) -> LogicalHost { self.router.get_host() } } #[async_trait] impl HttpServer for HAClusterTopology { async fn serve_files(&self, url: &Url) -> Result<(), ExecutorError> { self.http_server.serve_files(url).await } fn get_ip(&self) -> IpAddress { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } async fn ensure_initialized(&self) -> Result<(), ExecutorError> { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } async fn commit_config(&self) -> Result<(), ExecutorError> { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } async fn reload_restart(&self) -> Result<(), ExecutorError> { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } } #[derive(Debug)] pub struct DummyInfra; #[async_trait] impl Topology for DummyInfra { fn name(&self) -> &str { todo!() } async fn ensure_ready(&self) -> Result { let dummy_msg = "This is a dummy infrastructure that does nothing"; info!("{dummy_msg}"); Ok(Outcome::success(dummy_msg.to_string())) } } const UNIMPLEMENTED_DUMMY_INFRA: &str = "This is a dummy infrastructure, no operation is supported"; impl Router for DummyInfra { fn get_gateway(&self) -> super::IpAddress { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } fn get_cidr(&self) -> cidr::Ipv4Cidr { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } fn get_host(&self) -> LogicalHost { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } } impl Firewall for DummyInfra { fn add_rule( &mut self, _rule: super::FirewallRule, ) -> Result<(), crate::executors::ExecutorError> { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } fn remove_rule(&mut self, _rule_id: &str) -> Result<(), crate::executors::ExecutorError> { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } fn list_rules(&self) -> Vec { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } fn get_ip(&self) -> super::IpAddress { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } fn get_host(&self) -> LogicalHost { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } } #[async_trait] impl DhcpServer for DummyInfra { async fn add_static_mapping(&self, _entry: &DHCPStaticEntry) -> Result<(), ExecutorError> { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } async fn remove_static_mapping(&self, _mac: &MacAddress) -> Result<(), ExecutorError> { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } async fn list_static_mappings(&self) -> Vec<(MacAddress, IpAddress)> { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } async fn set_next_server(&self, _ip: IpAddress) -> Result<(), ExecutorError> { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } async fn set_boot_filename(&self, _boot_filename: &str) -> Result<(), ExecutorError> { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } async fn set_filename(&self, _filename: &str) -> Result<(), ExecutorError> { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } async fn set_filename64(&self, _filename: &str) -> Result<(), ExecutorError> { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } async fn set_filenameipxe(&self, _filenameipxe: &str) -> Result<(), ExecutorError> { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } fn get_ip(&self) -> IpAddress { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } fn get_host(&self) -> LogicalHost { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } async fn commit_config(&self) -> Result<(), ExecutorError> { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } } #[async_trait] impl LoadBalancer for DummyInfra { fn get_ip(&self) -> IpAddress { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } fn get_host(&self) -> LogicalHost { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } async fn add_service(&self, _service: &LoadBalancerService) -> Result<(), ExecutorError> { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } async fn remove_service(&self, _service: &LoadBalancerService) -> Result<(), ExecutorError> { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } async fn list_services(&self) -> Vec { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } async fn ensure_initialized(&self) -> Result<(), ExecutorError> { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } async fn commit_config(&self) -> Result<(), ExecutorError> { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } async fn reload_restart(&self) -> Result<(), ExecutorError> { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } } #[async_trait] impl TftpServer for DummyInfra { async fn serve_files(&self, _url: &Url) -> Result<(), ExecutorError> { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } fn get_ip(&self) -> IpAddress { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } async fn set_ip(&self, _ip: IpAddress) -> Result<(), ExecutorError> { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } async fn ensure_initialized(&self) -> Result<(), ExecutorError> { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } async fn commit_config(&self) -> Result<(), ExecutorError> { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } async fn reload_restart(&self) -> Result<(), ExecutorError> { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } } #[async_trait] impl HttpServer for DummyInfra { async fn serve_files(&self, _url: &Url) -> Result<(), ExecutorError> { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } fn get_ip(&self) -> IpAddress { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } async fn ensure_initialized(&self) -> Result<(), ExecutorError> { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } async fn commit_config(&self) -> Result<(), ExecutorError> { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } async fn reload_restart(&self) -> Result<(), ExecutorError> { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } } #[async_trait] impl DnsServer for DummyInfra { async fn register_dhcp_leases(&self, _register: bool) -> Result<(), ExecutorError> { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } async fn register_hosts(&self, _hosts: Vec) -> Result<(), ExecutorError> { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } fn remove_record(&self, _name: &str, _record_type: DnsRecordType) -> Result<(), ExecutorError> { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } async fn list_records(&self) -> Vec { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } fn get_ip(&self) -> IpAddress { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } fn get_host(&self) -> LogicalHost { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } async fn commit_config(&self) -> Result<(), ExecutorError> { unimplemented!("{}", UNIMPLEMENTED_DUMMY_INFRA) } }