forked from NationTech/harmony
		
	feat(bootstrapping): add bootstrap load balancer and DHCP configurations
- Introduce `bootstrap_load_balancer` module for handling initial load balancing configuration. - Add `bootstrap_dhcp` module for bootstrapping DHCP settings. - Create `harmony_types` crate to house shared types, including `MacAddress`. - Update `harmony_macros` to use `harmony_types` instead of directly referencing `harmony`.
This commit is contained in:
		
							parent
							
								
									a80ead418e
								
							
						
					
					
						commit
						bec96c2954
					
				
							
								
								
									
										8
									
								
								harmony-rs/Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										8
									
								
								harmony-rs/Cargo.lock
									
									
									
										generated
									
									
									
								
							| @ -893,6 +893,8 @@ dependencies = [ | |||||||
|  "cidr", |  "cidr", | ||||||
|  "derive-new", |  "derive-new", | ||||||
|  "env_logger", |  "env_logger", | ||||||
|  |  "harmony_macros", | ||||||
|  |  "harmony_types", | ||||||
|  "libredfish", |  "libredfish", | ||||||
|  "log", |  "log", | ||||||
|  "opnsense-config", |  "opnsense-config", | ||||||
| @ -912,11 +914,15 @@ dependencies = [ | |||||||
| name = "harmony_macros" | name = "harmony_macros" | ||||||
| version = "1.0.0" | version = "1.0.0" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "harmony", |  "harmony_types", | ||||||
|  "quote", |  "quote", | ||||||
|  "syn 2.0.90", |  "syn 2.0.90", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "harmony_types" | ||||||
|  | version = "1.0.0" | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "hashbrown" | name = "hashbrown" | ||||||
| version = "0.14.5" | version = "0.14.5" | ||||||
|  | |||||||
| @ -4,7 +4,10 @@ members = [ | |||||||
|   "private_repos/*", |   "private_repos/*", | ||||||
|   "demo/*", |   "demo/*", | ||||||
|   "harmony", |   "harmony", | ||||||
|   "opnsense-config", "opnsense-config-xml", "harmony_macros", |   "harmony_types", | ||||||
|  |   "harmony_macros", | ||||||
|  |   "opnsense-config", | ||||||
|  |   "opnsense-config-xml", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
| [workspace.package] | [workspace.package] | ||||||
|  | |||||||
| @ -10,7 +10,9 @@ use harmony::{ | |||||||
|     inventory::Inventory, |     inventory::Inventory, | ||||||
|     maestro::Maestro, |     maestro::Maestro, | ||||||
|     modules::{ |     modules::{ | ||||||
|         http::HttpScore, okd::{dhcp::OKDBootstrapDhcpScore, dns::OKDBootstrapDnsScore}, tftp::TftpScore |         http::HttpScore, | ||||||
|  |         okd::{dhcp::OKDDhcpScore, dns::OKDDnsScore}, | ||||||
|  |         tftp::TftpScore, | ||||||
|     }, |     }, | ||||||
|     topology::{LogicalHost, UnmanagedRouter, Url}, |     topology::{LogicalHost, UnmanagedRouter, Url}, | ||||||
| }; | }; | ||||||
| @ -48,6 +50,10 @@ async fn main() { | |||||||
|             ip: ip!("10.100.8.20"), |             ip: ip!("10.100.8.20"), | ||||||
|             name: "cp0".to_string(), |             name: "cp0".to_string(), | ||||||
|         }], |         }], | ||||||
|  |         bootstrap_host: LogicalHost { | ||||||
|  |             ip: ip!("10.100.8.20"), | ||||||
|  |             name: "cp0".to_string(), | ||||||
|  |         }, | ||||||
|         workers: vec![], |         workers: vec![], | ||||||
|         switch: vec![], |         switch: vec![], | ||||||
|     }; |     }; | ||||||
| @ -73,8 +79,8 @@ async fn main() { | |||||||
|     // TODO regroup smaller scores in a larger one such as this
 |     // TODO regroup smaller scores in a larger one such as this
 | ||||||
|     // let okd_boostrap_preparation();
 |     // let okd_boostrap_preparation();
 | ||||||
| 
 | 
 | ||||||
|     // let dhcp_score = OKDBootstrapDhcpScore::new(&topology, &inventory);
 |     // let dhcp_score = OKDDhcpScore::new(&topology, &inventory);
 | ||||||
|     // let dns_score = OKDBootstrapDnsScore::new(&topology);
 |     // let dns_score = OKDDnsScore::new(&topology);
 | ||||||
|     // let load_balancer_score =
 |     // let load_balancer_score =
 | ||||||
|     //     harmony::modules::okd::load_balancer::OKDLoadBalancerScore::new(&topology);
 |     //     harmony::modules::okd::load_balancer::OKDLoadBalancerScore::new(&topology);
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -19,5 +19,7 @@ async-trait = { workspace = true } | |||||||
| cidr = { workspace = true } | cidr = { workspace = true } | ||||||
| opnsense-config = { path = "../opnsense-config" } | opnsense-config = { path = "../opnsense-config" } | ||||||
| opnsense-config-xml = { path = "../opnsense-config-xml" } | opnsense-config-xml = { path = "../opnsense-config-xml" } | ||||||
|  | harmony_macros = { path = "../harmony_macros" } | ||||||
|  | harmony_types = { path = "../harmony_types" } | ||||||
| uuid = { workspace = true } | uuid = { workspace = true } | ||||||
| url = { workspace = true } | url = { workspace = true } | ||||||
|  | |||||||
| @ -1,8 +1,8 @@ | |||||||
| use std::sync::Arc; | use std::sync::Arc; | ||||||
| 
 | 
 | ||||||
| use derive_new::new; | use derive_new::new; | ||||||
|  | use harmony_types::net::MacAddress; | ||||||
| 
 | 
 | ||||||
| use crate::topology::MacAddress; |  | ||||||
| 
 | 
 | ||||||
| pub type HostGroup = Vec<PhysicalHost>; | pub type HostGroup = Vec<PhysicalHost>; | ||||||
| pub type SwitchGroup = Vec<Switch>; | pub type SwitchGroup = Vec<Switch>; | ||||||
|  | |||||||
| @ -1,15 +1,15 @@ | |||||||
| mod host_binding; | mod host_binding; | ||||||
|  | mod http; | ||||||
| mod load_balancer; | mod load_balancer; | ||||||
| mod router; | mod router; | ||||||
| mod tftp; | mod tftp; | ||||||
| mod http; |  | ||||||
| pub use load_balancer::*; | pub use load_balancer::*; | ||||||
| pub use router::*; | pub use router::*; | ||||||
| mod network; | mod network; | ||||||
| pub use host_binding::*; | pub use host_binding::*; | ||||||
|  | pub use http::*; | ||||||
| pub use network::*; | pub use network::*; | ||||||
| pub use tftp::*; | pub use tftp::*; | ||||||
| pub use http::*; |  | ||||||
| 
 | 
 | ||||||
| use std::{net::IpAddr, sync::Arc}; | use std::{net::IpAddr, sync::Arc}; | ||||||
| 
 | 
 | ||||||
| @ -23,6 +23,7 @@ pub struct HAClusterTopology { | |||||||
|     pub tftp_server: Arc<dyn TftpServer>, |     pub tftp_server: Arc<dyn TftpServer>, | ||||||
|     pub http_server: Arc<dyn HttpServer>, |     pub http_server: Arc<dyn HttpServer>, | ||||||
|     pub dns_server: Arc<dyn DnsServer>, |     pub dns_server: Arc<dyn DnsServer>, | ||||||
|  |     pub bootstrap_host: LogicalHost, | ||||||
|     pub control_plane: Vec<LogicalHost>, |     pub control_plane: Vec<LogicalHost>, | ||||||
|     pub workers: Vec<LogicalHost>, |     pub workers: Vec<LogicalHost>, | ||||||
|     pub switch: Vec<LogicalHost>, |     pub switch: Vec<LogicalHost>, | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| use std::{error::Error, net::Ipv4Addr, str::FromStr}; | use std::{error::Error, net::Ipv4Addr, str::FromStr}; | ||||||
| 
 | 
 | ||||||
| use async_trait::async_trait; | use async_trait::async_trait; | ||||||
|  | use harmony_types::net::MacAddress; | ||||||
| 
 | 
 | ||||||
| use crate::executors::ExecutorError; | use crate::executors::ExecutorError; | ||||||
| 
 | 
 | ||||||
| @ -117,35 +118,6 @@ pub enum Action { | |||||||
|     Deny, |     Deny, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Clone, Debug, PartialEq, Eq, Hash)] |  | ||||||
| pub struct MacAddress(pub [u8; 6]); |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| impl MacAddress { |  | ||||||
|     #[cfg(test)] |  | ||||||
|     pub fn dummy() -> Self { |  | ||||||
|         Self([0, 0, 0, 0, 0, 0]) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl From<&MacAddress> for String { |  | ||||||
|     fn from(value: &MacAddress) -> Self { |  | ||||||
|         format!( |  | ||||||
|             "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", |  | ||||||
|             value.0[0], value.0[1], value.0[2], value.0[3], value.0[4], value.0[5] |  | ||||||
|         ) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl std::fmt::Display for MacAddress { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |  | ||||||
|         f.write_fmt(format_args!( |  | ||||||
|             "MacAddress {}", |  | ||||||
|             String::from(self) |  | ||||||
|         )) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Clone, Debug, PartialEq, Eq)] | #[derive(Clone, Debug, PartialEq, Eq)] | ||||||
| pub enum DnsRecordType { | pub enum DnsRecordType { | ||||||
|     A, |     A, | ||||||
|  | |||||||
| @ -1,9 +1,12 @@ | |||||||
| use crate::{hardware::ManagementInterface, topology::{IpAddress, MacAddress}}; | use crate::hardware::ManagementInterface; | ||||||
|  | use crate::topology::IpAddress; | ||||||
| use derive_new::new; | use derive_new::new; | ||||||
|  | use harmony_types::net::MacAddress; | ||||||
| 
 | 
 | ||||||
| #[derive(new)] | #[derive(new)] | ||||||
| pub struct HPIlo { | pub struct HPIlo { | ||||||
|     ip_address: IpAddress, |     ip_address: Option<IpAddress>, | ||||||
|  |     mac_address: Option<MacAddress>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl ManagementInterface for HPIlo { | impl ManagementInterface for HPIlo { | ||||||
|  | |||||||
| @ -1,8 +1,6 @@ | |||||||
| use crate::{ | use crate::hardware::ManagementInterface; | ||||||
|     hardware::ManagementInterface, |  | ||||||
|     topology::{IpAddress, MacAddress}, |  | ||||||
| }; |  | ||||||
| use derive_new::new; | use derive_new::new; | ||||||
|  | use harmony_types::net::MacAddress; | ||||||
| 
 | 
 | ||||||
| #[derive(new)] | #[derive(new)] | ||||||
| pub struct IntelAmtManagement { | pub struct IntelAmtManagement { | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| use async_trait::async_trait; | use async_trait::async_trait; | ||||||
|  | use harmony_types::net::MacAddress; | ||||||
| use log::debug; | use log::debug; | ||||||
| 
 | 
 | ||||||
| use crate::{executors::ExecutorError, topology::{DHCPStaticEntry, DhcpServer, IpAddress, LogicalHost}}; | use crate::{executors::ExecutorError, topology::{DHCPStaticEntry, DhcpServer, IpAddress, LogicalHost}}; | ||||||
| @ -28,12 +29,12 @@ impl DhcpServer for OPNSenseFirewall { | |||||||
| 
 | 
 | ||||||
|     async fn remove_static_mapping( |     async fn remove_static_mapping( | ||||||
|         &self, |         &self, | ||||||
|         _mac: &crate::topology::MacAddress, |         _mac: &MacAddress, | ||||||
|     ) -> Result<(), ExecutorError> { |     ) -> Result<(), ExecutorError> { | ||||||
|         todo!() |         todo!() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async fn list_static_mappings(&self) -> Vec<(crate::topology::MacAddress, IpAddress)> { |     async fn list_static_mappings(&self) -> Vec<(MacAddress, IpAddress)> { | ||||||
|         todo!() |         todo!() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,6 +1,5 @@ | |||||||
| use derive_new::new; | use derive_new::new; | ||||||
| 
 | use crate::hardware::ManagementInterface; | ||||||
| use crate::{hardware::ManagementInterface, topology::MacAddress}; |  | ||||||
| 
 | 
 | ||||||
| #[derive(new)] | #[derive(new)] | ||||||
| pub struct OPNSenseManagementInterface {} | pub struct OPNSenseManagementInterface {} | ||||||
|  | |||||||
							
								
								
									
										55
									
								
								harmony-rs/harmony/src/modules/okd/bootstrap_dhcp.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								harmony-rs/harmony/src/modules/okd/bootstrap_dhcp.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,55 @@ | |||||||
|  | use crate::{ | ||||||
|  |     inventory::Inventory, | ||||||
|  |     modules::dhcp::DhcpScore, | ||||||
|  |     score::Score, | ||||||
|  |     topology::{HAClusterTopology, HostBinding, LogicalHost}, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | use harmony_macros::ip; | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct OKDBootstrapDhcpScore { | ||||||
|  |     dhcp_score: DhcpScore, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl OKDBootstrapDhcpScore { | ||||||
|  |     pub fn new(topology: &HAClusterTopology, inventory: &Inventory) -> Self { | ||||||
|  |         let mut host_binding: Vec<_> = topology | ||||||
|  |             .control_plane | ||||||
|  |             .iter() | ||||||
|  |             .enumerate() | ||||||
|  |             .map(|(index, topology_entry)| HostBinding { | ||||||
|  |                 logical_host: topology_entry.clone(), | ||||||
|  |                 physical_host: inventory | ||||||
|  |                     .control_plane_host | ||||||
|  |                     .get(index) | ||||||
|  |                     .expect("Iventory should contain at least as many physical hosts as topology") | ||||||
|  |                     .clone(), | ||||||
|  |             }) | ||||||
|  |             .collect(); | ||||||
|  |         host_binding.push(HostBinding { | ||||||
|  |             logical_host: topology.bootstrap_host.clone(), | ||||||
|  |             physical_host: inventory | ||||||
|  |                 .worker_host | ||||||
|  |                 .get(0) | ||||||
|  |                 .expect("Should have at least one worker to be used as bootstrap node") | ||||||
|  |                 .clone(), | ||||||
|  |         }); | ||||||
|  |         Self { | ||||||
|  |             dhcp_score: DhcpScore::new( | ||||||
|  |                 host_binding, | ||||||
|  |                 // TODO : we should add a tftp server to the topology instead of relying on the
 | ||||||
|  |                 // router address, this is leaking implementation details
 | ||||||
|  |                 Some(topology.router.get_gateway()), | ||||||
|  |                 Some("bootx64.efi".to_string()), | ||||||
|  |             ), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Score for OKDBootstrapDhcpScore { | ||||||
|  |     type InterpretType = <DhcpScore as Score>::InterpretType; | ||||||
|  | 
 | ||||||
|  |     fn create_interpret(self) -> Self::InterpretType { | ||||||
|  |         self.dhcp_score.create_interpret() | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,76 @@ | |||||||
|  | use std::net::SocketAddr; | ||||||
|  | 
 | ||||||
|  | use crate::{ | ||||||
|  |     modules::load_balancer::LoadBalancerScore, | ||||||
|  |     score::Score, | ||||||
|  |     topology::{ | ||||||
|  |         BackendServer, HAClusterTopology, HealthCheck, HttpMethod, HttpStatusCode, | ||||||
|  |         LoadBalancerService, | ||||||
|  |     }, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct OKDBootstrapLoadBalancerScore { | ||||||
|  |     load_balancer_score: LoadBalancerScore, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl OKDBootstrapLoadBalancerScore { | ||||||
|  |     pub fn new(topology: &HAClusterTopology) -> Self { | ||||||
|  |         let private_ip = topology.router.get_gateway(); | ||||||
|  | 
 | ||||||
|  |         let bootstrap_host = &topology.bootstrap_host; | ||||||
|  | 
 | ||||||
|  |         let private_services = vec![ | ||||||
|  |             LoadBalancerService { | ||||||
|  |                 backend_servers: vec![BackendServer { | ||||||
|  |                     address: bootstrap_host.ip.to_string(), | ||||||
|  |                     port: 80, | ||||||
|  |                 }], | ||||||
|  |                 listening_port: SocketAddr::new(private_ip, 80), | ||||||
|  |                 health_check: Some(HealthCheck::TCP(None)), | ||||||
|  |             }, | ||||||
|  |             LoadBalancerService { | ||||||
|  |                 backend_servers: vec![BackendServer { | ||||||
|  |                     address: bootstrap_host.ip.to_string(), | ||||||
|  |                     port: 443, | ||||||
|  |                 }], | ||||||
|  |                 listening_port: SocketAddr::new(private_ip, 443), | ||||||
|  |                 health_check: Some(HealthCheck::TCP(None)), | ||||||
|  |             }, | ||||||
|  |             LoadBalancerService { | ||||||
|  |                 backend_servers: vec![BackendServer { | ||||||
|  |                     address: bootstrap_host.ip.to_string(), | ||||||
|  |                     port: 22623, | ||||||
|  |                 }], | ||||||
|  |                 listening_port: SocketAddr::new(private_ip, 22623), | ||||||
|  |                 health_check: Some(HealthCheck::TCP(None)), | ||||||
|  |             }, | ||||||
|  |             LoadBalancerService { | ||||||
|  |                 backend_servers: vec![BackendServer { | ||||||
|  |                     address: bootstrap_host.ip.to_string(), | ||||||
|  |                     port: 6443, | ||||||
|  |                 }], | ||||||
|  |                 listening_port: SocketAddr::new(private_ip, 6443), | ||||||
|  |                 health_check: Some(HealthCheck::HTTP( | ||||||
|  |                     "/readyz".to_string(), | ||||||
|  |                     HttpMethod::GET, | ||||||
|  |                     HttpStatusCode::Success2xx, | ||||||
|  |                 )), | ||||||
|  |             }, | ||||||
|  |         ]; | ||||||
|  |         Self { | ||||||
|  |             load_balancer_score: LoadBalancerScore { | ||||||
|  |                 public_services: vec![], | ||||||
|  |                 private_services, | ||||||
|  |             }, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Score for OKDBootstrapLoadBalancerScore { | ||||||
|  |     type InterpretType = <LoadBalancerScore as Score>::InterpretType; | ||||||
|  | 
 | ||||||
|  |     fn create_interpret(self) -> Self::InterpretType { | ||||||
|  |         self.load_balancer_score.create_interpret() | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -6,11 +6,11 @@ use crate::{ | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub struct OKDBootstrapDhcpScore { | pub struct OKDDhcpScore { | ||||||
|     dhcp_score: DhcpScore, |     dhcp_score: DhcpScore, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl OKDBootstrapDhcpScore { | impl OKDDhcpScore { | ||||||
|     pub fn new(topology: &HAClusterTopology, inventory: &Inventory) -> Self { |     pub fn new(topology: &HAClusterTopology, inventory: &Inventory) -> Self { | ||||||
|         let host_binding = topology |         let host_binding = topology | ||||||
|             .control_plane |             .control_plane | ||||||
| @ -37,7 +37,7 @@ impl OKDBootstrapDhcpScore { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Score for OKDBootstrapDhcpScore { | impl Score for OKDDhcpScore { | ||||||
|     type InterpretType = <DhcpScore as Score>::InterpretType; |     type InterpretType = <DhcpScore as Score>::InterpretType; | ||||||
| 
 | 
 | ||||||
|     fn create_interpret(self) -> Self::InterpretType { |     fn create_interpret(self) -> Self::InterpretType { | ||||||
|  | |||||||
| @ -5,11 +5,11 @@ use crate::{ | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub struct OKDBootstrapDnsScore { | pub struct OKDDnsScore { | ||||||
|     dns_score: DnsScore, |     dns_score: DnsScore, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl OKDBootstrapDnsScore { | impl OKDDnsScore { | ||||||
|     pub fn new(topology: &HAClusterTopology) -> Self { |     pub fn new(topology: &HAClusterTopology) -> Self { | ||||||
|         let cluster_domain_name = &topology.domain_name; |         let cluster_domain_name = &topology.domain_name; | ||||||
|         let dns_entries = vec![ |         let dns_entries = vec![ | ||||||
| @ -39,7 +39,7 @@ impl OKDBootstrapDnsScore { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Score for OKDBootstrapDnsScore { | impl Score for OKDDnsScore { | ||||||
|     type InterpretType = <DnsScore as Score>::InterpretType; |     type InterpretType = <DnsScore as Score>::InterpretType; | ||||||
| 
 | 
 | ||||||
|     fn create_interpret(self) -> Self::InterpretType { |     fn create_interpret(self) -> Self::InterpretType { | ||||||
|  | |||||||
| @ -1,4 +1,6 @@ | |||||||
| pub mod dhcp; | pub mod dhcp; | ||||||
| pub mod dns; | pub mod dns; | ||||||
| pub mod load_balancer; | pub mod load_balancer; | ||||||
|  | pub mod bootstrap_load_balancer; | ||||||
|  | pub mod bootstrap_dhcp; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -7,6 +7,6 @@ version = "1.0.0" | |||||||
| proc-macro = true | proc-macro = true | ||||||
| 
 | 
 | ||||||
| [dependencies] | [dependencies] | ||||||
| harmony = { version = "0.1.0", path = "../harmony" } | harmony_types = { path = "../harmony_types" } | ||||||
| quote = "1.0.37" | quote = "1.0.37" | ||||||
| syn = "2.0.90" | syn = "2.0.90" | ||||||
|  | |||||||
| @ -1,6 +1,5 @@ | |||||||
| extern crate proc_macro; | extern crate proc_macro; | ||||||
| 
 | 
 | ||||||
| use harmony::topology::MacAddress; |  | ||||||
| use proc_macro::TokenStream; | use proc_macro::TokenStream; | ||||||
| use quote::quote; | use quote::quote; | ||||||
| use syn::{LitStr, parse_macro_input}; | use syn::{LitStr, parse_macro_input}; | ||||||
|  | |||||||
							
								
								
									
										4
									
								
								harmony-rs/harmony_types/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								harmony-rs/harmony_types/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | |||||||
|  | [package] | ||||||
|  | name = "harmony_types" | ||||||
|  | edition = "2024" | ||||||
|  | version = "1.0.0" | ||||||
							
								
								
									
										26
									
								
								harmony-rs/harmony_types/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								harmony-rs/harmony_types/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | |||||||
|  | pub mod net { | ||||||
|  |     #[derive(Clone, Debug, PartialEq, Eq, Hash)] | ||||||
|  |     pub struct MacAddress(pub [u8; 6]); | ||||||
|  | 
 | ||||||
|  |     impl MacAddress { | ||||||
|  |         #[cfg(test)] | ||||||
|  |         pub fn dummy() -> Self { | ||||||
|  |             Self([0, 0, 0, 0, 0, 0]) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     impl From<&MacAddress> for String { | ||||||
|  |         fn from(value: &MacAddress) -> Self { | ||||||
|  |             format!( | ||||||
|  |                 "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", | ||||||
|  |                 value.0[0], value.0[1], value.0[2], value.0[3], value.0[4], value.0[5] | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     impl std::fmt::Display for MacAddress { | ||||||
|  |         fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||||
|  |             f.write_fmt(format_args!("MacAddress {}", String::from(self))) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user