feat: Added new crate harmony_macros with ip! macro to facilitate creating ip addresses

This commit is contained in:
Jean-Gabriel Gill-Couture 2024-12-09 15:23:12 -05:00
parent 3592b176e5
commit 1e0c2eb470
7 changed files with 189 additions and 56 deletions

50
harmony-rs/Cargo.lock generated
View File

@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
version = 4
[[package]]
name = "addr2line"
@ -152,7 +152,7 @@ checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.90",
]
[[package]]
@ -471,7 +471,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.90",
]
[[package]]
@ -499,7 +499,7 @@ checksum = "2cdc8d50f426189eef89dac62fabfa0abb27d5cc008f25bf4156a0203325becc"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.90",
]
[[package]]
@ -784,7 +784,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.90",
]
[[package]]
@ -905,6 +905,14 @@ dependencies = [
"tokio",
]
[[package]]
name = "harmony_macros"
version = "1.0.0"
dependencies = [
"quote",
"syn 2.0.90",
]
[[package]]
name = "hashbrown"
version = "0.14.5"
@ -1346,7 +1354,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.90",
]
[[package]]
@ -1620,9 +1628,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.86"
version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
dependencies = [
"unicode-ident",
]
@ -2062,7 +2070,7 @@ checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.90",
]
[[package]]
@ -2247,9 +2255,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.77"
version = "2.0.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31"
dependencies = [
"proc-macro2",
"quote",
@ -2319,7 +2327,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.90",
]
[[package]]
@ -2371,7 +2379,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.90",
]
[[package]]
@ -2542,7 +2550,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.90",
"wasm-bindgen-shared",
]
@ -2576,7 +2584,7 @@ checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.90",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@ -2786,6 +2794,16 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "wk"
version = "0.1.0"
dependencies = [
"cidr",
"harmony",
"harmony_macros",
"tokio",
]
[[package]]
name = "wyz"
version = "0.5.1"
@ -2845,7 +2863,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
"syn 2.0.90",
]
[[package]]

View File

@ -3,7 +3,7 @@ resolver = "2"
members = [
"private_repos/*",
"harmony",
"opnsense-config", "opnsense-config-xml",
"opnsense-config", "opnsense-config-xml", "harmony_macros",
]
[workspace.package]

View File

@ -34,7 +34,79 @@ pub type IpAddress = IpAddr;
/// This abstraction focuses on the logical role and services, independent of the physical hardware.
#[derive(Debug, Clone)]
pub struct LogicalHost {
/// The set of services this logical host provides
/// The IP address of this logical host.
pub ip: IpAddress,
/// The name of this logical host.
pub name: String,
}
impl LogicalHost {
/// Creates a list of `LogicalHost` instances.
///
/// # Arguments
///
/// * `number_hosts` - The number of logical hosts to create.
/// * `start_ip` - The starting IP address. Each subsequent host's IP will be incremented.
/// * `hostname_prefix` - The prefix for the host names. Host names will be in the form `prefix<index>`.
///
/// # Returns
///
/// A `Vec<LogicalHost>` containing the specified number of logical hosts, each with a unique IP and name.
///
/// # Panics
///
/// This function will panic if adding `number_hosts` to `start_ip` exceeds the valid range of IP addresses.
///
/// # Examples
///
/// ```
/// use std::str::FromStr;
/// use harmony::topology::{IpAddress, LogicalHost};
///
/// let start_ip = IpAddress::from_str("192.168.0.20").unwrap();
/// let hosts = LogicalHost::create_hosts(3, start_ip, "worker");
///
/// assert_eq!(hosts.len(), 3);
/// assert_eq!(hosts[0].ip, IpAddress::from_str("192.168.0.20").unwrap());
/// assert_eq!(hosts[0].name, "worker0");
/// assert_eq!(hosts[1].ip, IpAddress::from_str("192.168.0.21").unwrap());
/// assert_eq!(hosts[1].name, "worker1");
/// assert_eq!(hosts[2].ip, IpAddress::from_str("192.168.0.22").unwrap());
/// assert_eq!(hosts[2].name, "worker2");
/// ```
pub fn create_hosts(number_hosts: u32, start_ip: IpAddress, hostname_prefix: &str) -> Vec<LogicalHost> {
let mut hosts = Vec::with_capacity(number_hosts.try_into().unwrap());
for i in 0..number_hosts {
let new_ip = increment_ip(start_ip, i).expect("IP address overflow");
let name = format!("{}{}", hostname_prefix, i);
hosts.push(LogicalHost { ip: new_ip, name });
}
hosts
}
}
/// Increments an IP address by a given value.
///
/// # Arguments
///
/// * `ip` - The starting IP address.
/// * `increment` - The amount to add to the IP address.
///
/// # Returns
///
/// A new `IpAddress` that is the result of incrementing the original by `increment`.
///
/// # Panics
///
/// This function panics if the resulting IP address exceeds the valid range.
fn increment_ip(ip: IpAddress, increment: u32) -> Option<IpAddress> {
match ip {
IpAddress::V4(ipv4) => {
let new_ip = u32::from(ipv4) + increment;
Some(IpAddress::V4(new_ip.into()))
}
IpAddress::V6(_) => {
todo!("Ipv6 not supported yet")
}
}
}

View File

@ -1,4 +1,4 @@
use std::{net::Ipv4Addr, sync::Arc};
use std::sync::Arc;
use async_trait::async_trait;
use derive_new::new;
@ -16,43 +16,6 @@ use crate::{
use crate::domain::score::Score;
/**
OPNSenseDhcpScore will set static DHCP entries using index based hostname
and ip addresses.
For example :
```rust
let node1 = todo!(); // Node pointing to clustermember controlplane0 with ip 10.10.0.20 and host with mac 01
let node2 = todo!(); // Node pointing to clustermember controlplane1 with ip 10.10.0.21 and host with mac 02
let node3 = todo!(); // Node pointing to clustermember controlplane2 with ip 10.10.0.22 and host with mac 03
let score = OPNSenseDhcpScore {
nodes: vec![node1, node2, node3],
}
```
Running such a score would create these static entries :
```rust
let entries = vec![
DHCPEntry {
mac: 01,
ip: 10.10.0.20,
hostname: "controlplane0"
}
DHCPEntry {
mac: 02,
ip: 10.10.0.21,
hostname: "controlplane0"
}
DHCPEntry {
mac: 03,
ip: 10.10.0.22,
hostname: "controlplane2"
}
]
```
*/
#[derive(Debug, new, Clone)]
pub struct DhcpScore {
host_binding: Vec<HostBinding>,

46
harmony-rs/harmony_macros/Cargo.lock generated Normal file
View File

@ -0,0 +1,46 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "harmony_macros"
version = "1.0.0"
dependencies = [
"quote",
"syn",
]
[[package]]
name = "proc-macro2"
version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [
"proc-macro2",
]
[[package]]
name = "syn"
version = "2.0.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"

View File

@ -0,0 +1,11 @@
[package]
name = "harmony_macros"
edition = "2024"
version = "1.0.0"
[lib]
proc-macro = true
[dependencies]
quote = "1.0.37"
syn = "2.0.90"

View File

@ -0,0 +1,23 @@
extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, LitStr};
#[proc_macro]
pub fn ip(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as LitStr);
let ip_str = input.value();
if let Ok(_) = ip_str.parse::<std::net::Ipv4Addr>() {
let expanded = quote! { std::net::IpAddr::V4(#ip_str.parse::<std::net::Ipv4Addr>().unwrap()) };
return TokenStream::from(expanded);
}
if let Ok(_) = ip_str.parse::<std::net::Ipv6Addr>() {
let expanded = quote! { std::net::IpAddr::V4(#ip_str.parse::<std::net::Ipv6Addr>().unwrap()) };
return TokenStream::from(expanded);
}
panic!("Invalid IP address: {}", ip_str);
}