feat(harmony): enhance PhysicalHost with builder methods and update dependencies
- Added builder methods to `PhysicalHost` for configuring CPU, memory size, storage, MAC address, labels, and management interface. - Updated the edition of various Cargo.toml files to 2024. - Implemented workspace inheritance for version, readme, and license fields in Cargo.toml files.
This commit is contained in:
20
harmony-rs/examples/kube-rs/Cargo.toml
Normal file
20
harmony-rs/examples/kube-rs/Cargo.toml
Normal file
@@ -0,0 +1,20 @@
|
||||
[package]
|
||||
name = "example-kube-rs"
|
||||
edition = "2024"
|
||||
version.workspace = true
|
||||
readme.workspace = true
|
||||
license.workspace = true
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
harmony = { version = "0.1.0", path = "../../harmony" }
|
||||
cidr = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
harmony_macros = { path = "../../harmony_macros" }
|
||||
log = { workspace = true }
|
||||
env_logger = { workspace = true }
|
||||
url = { workspace = true }
|
||||
kube = "0.98.0"
|
||||
k8s-openapi = { version = "0.24.0", features = [ "v1_30" ] }
|
||||
http = "1.2.0"
|
||||
serde_yaml = "0.9.34"
|
||||
194
harmony-rs/examples/kube-rs/src/main.rs
Normal file
194
harmony-rs/examples/kube-rs/src/main.rs
Normal file
@@ -0,0 +1,194 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use harmony_macros::yaml;
|
||||
use k8s_openapi::{
|
||||
api::{
|
||||
apps::v1::{Deployment, DeploymentSpec},
|
||||
core::v1::{Container, Node, Pod, PodSpec, PodTemplateSpec},
|
||||
},
|
||||
apimachinery::pkg::apis::meta::v1::LabelSelector,
|
||||
};
|
||||
use kube::{
|
||||
Api, Client, Config, ResourceExt,
|
||||
api::{ListParams, ObjectMeta, PostParams},
|
||||
};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let client = Client::try_default()
|
||||
.await
|
||||
.expect("Should instanciate client from defaults");
|
||||
println!("apiserver_version {:?}", client.apiserver_version().await);
|
||||
println!("default namespace {:?}", client.default_namespace());
|
||||
// println!(
|
||||
// "apiserver_groups {:?}",
|
||||
// client
|
||||
// .list_api_groups()
|
||||
// .await
|
||||
// .unwrap()
|
||||
// .groups
|
||||
// .iter()
|
||||
// .map(|g| g.name.clone())
|
||||
// .collect::<Vec<_>>()
|
||||
// );
|
||||
|
||||
// let pods: Api<Pod> = Api::default_namespaced(client.clone());
|
||||
// for p in pods.list(&ListParams::default()).await.unwrap() {
|
||||
// println!("found pod {}", p.name_any())
|
||||
// }
|
||||
|
||||
// let nodes : Api<Node> = Api::all(client.clone());
|
||||
// for n in nodes.list(&ListParams::default()).await.unwrap() {
|
||||
// println!("found node {} status {:?}", n.name_any(), n.status.unwrap())
|
||||
// }
|
||||
|
||||
let nginxdeployment = nginx_deployment_2();
|
||||
let nginxdeployment = nginx_deployment_serde();
|
||||
assert_eq!(nginx_deployment_2(), nginx_macro());
|
||||
assert_eq!(nginx_deployment_serde(), nginx_macro());
|
||||
let nginxdeployment = nginx_macro();
|
||||
let deployment: Api<Deployment> = Api::default_namespaced(client.clone());
|
||||
match deployment
|
||||
.create(&PostParams::default(), &nginxdeployment)
|
||||
.await
|
||||
{
|
||||
Ok(_d) => println!("Deployment success"),
|
||||
Err(e) => {
|
||||
println!("Error creating deployment {}", e);
|
||||
if let kube::Error::Api(error_response) = &e {
|
||||
if error_response.code == http::StatusCode::CONFLICT.as_u16() {
|
||||
println!("Already exists");
|
||||
return;
|
||||
}
|
||||
}
|
||||
panic!("{}", e)
|
||||
}
|
||||
};
|
||||
println!(
|
||||
"{:?}",
|
||||
deployment
|
||||
.get_status(&nginxdeployment.name_unchecked())
|
||||
.await
|
||||
.unwrap()
|
||||
);
|
||||
println!("Hello world");
|
||||
}
|
||||
|
||||
fn nginx_macro() -> Deployment {
|
||||
yaml!(
|
||||
r#"
|
||||
metadata:
|
||||
name: "nginx-test"
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nginx-test
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx-test
|
||||
spec:
|
||||
containers:
|
||||
- image: nginx
|
||||
name: nginx"#
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn nginx_deployment_serde() -> Deployment {
|
||||
let deployment: Deployment = serde_yaml::from_str(
|
||||
r#"
|
||||
metadata:
|
||||
name: "nginx-test"
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nginx-test
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx-test
|
||||
spec:
|
||||
containers:
|
||||
- image: nginx
|
||||
name: nginx"#,
|
||||
)
|
||||
.unwrap();
|
||||
return deployment;
|
||||
}
|
||||
fn nginx_deployment_2() -> Deployment {
|
||||
let mut pod_template = PodTemplateSpec::default();
|
||||
pod_template.metadata = Some(ObjectMeta {
|
||||
labels: Some(BTreeMap::from([(
|
||||
"app".to_string(),
|
||||
"nginx-test".to_string(),
|
||||
)])),
|
||||
..Default::default()
|
||||
});
|
||||
pod_template.spec = Some(PodSpec {
|
||||
containers: vec![Container {
|
||||
name: "nginx".to_string(),
|
||||
image: Some("nginx".to_string()),
|
||||
..Default::default()
|
||||
}],
|
||||
..Default::default()
|
||||
});
|
||||
let mut spec = DeploymentSpec::default();
|
||||
spec.template = pod_template;
|
||||
spec.selector = LabelSelector {
|
||||
match_expressions: None,
|
||||
match_labels: Some(BTreeMap::from([(
|
||||
"app".to_string(),
|
||||
"nginx-test".to_string(),
|
||||
)])),
|
||||
};
|
||||
|
||||
let mut deployment = Deployment::default();
|
||||
deployment.spec = Some(spec);
|
||||
deployment.metadata.name = Some("nginx-test".to_string());
|
||||
|
||||
deployment
|
||||
}
|
||||
fn nginx_deployment() -> Deployment {
|
||||
let deployment = Deployment {
|
||||
metadata: ObjectMeta {
|
||||
name: Some("nginx-test".to_string()),
|
||||
..Default::default()
|
||||
},
|
||||
spec: Some(DeploymentSpec {
|
||||
min_ready_seconds: None,
|
||||
paused: None,
|
||||
progress_deadline_seconds: None,
|
||||
replicas: Some(1),
|
||||
revision_history_limit: Some(10),
|
||||
selector: LabelSelector {
|
||||
match_expressions: None,
|
||||
match_labels: Some(BTreeMap::from([(
|
||||
"app".to_string(),
|
||||
"nginx-test".to_string(),
|
||||
)])),
|
||||
},
|
||||
strategy: None,
|
||||
template: PodTemplateSpec {
|
||||
metadata: Some(ObjectMeta {
|
||||
labels: Some(BTreeMap::from([(
|
||||
"app".to_string(),
|
||||
"nginx-test".to_string(),
|
||||
)])),
|
||||
..Default::default()
|
||||
}),
|
||||
spec: Some(PodSpec {
|
||||
containers: vec![Container {
|
||||
name: "nginx".to_string(),
|
||||
image: Some("nginx".to_string()),
|
||||
..Default::default()
|
||||
}],
|
||||
..Default::default()
|
||||
}),
|
||||
},
|
||||
}),
|
||||
status: None,
|
||||
};
|
||||
println!("{:?}", deployment.managed_fields());
|
||||
deployment
|
||||
}
|
||||
18
harmony-rs/examples/opnsense/Cargo.toml
Normal file
18
harmony-rs/examples/opnsense/Cargo.toml
Normal file
@@ -0,0 +1,18 @@
|
||||
[package]
|
||||
name = "example-opnsense"
|
||||
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" }
|
||||
log = { workspace = true }
|
||||
env_logger = { workspace = true }
|
||||
url = { workspace = true }
|
||||
15
harmony-rs/examples/opnsense/README.md
Normal file
15
harmony-rs/examples/opnsense/README.md
Normal file
@@ -0,0 +1,15 @@
|
||||
## OPNSense demo
|
||||
|
||||
Download the virtualbox snapshot from {{TODO URL}}
|
||||
|
||||
Start the virtualbox image
|
||||
|
||||
This virtualbox image is configured to use a bridge on the host's physical interface, make sure the bridge is up and the virtual machine can reach internet.
|
||||
|
||||
Credentials are opnsense default (root/opnsense)
|
||||
|
||||
Run the project with the correct ip address on the command line :
|
||||
|
||||
```bash
|
||||
cargo run -p example-opnsense -- 192.168.5.229
|
||||
```
|
||||
93
harmony-rs/examples/opnsense/src/main.rs
Normal file
93
harmony-rs/examples/opnsense/src/main.rs
Normal file
@@ -0,0 +1,93 @@
|
||||
use std::{
|
||||
net::{IpAddr, Ipv4Addr},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use cidr::Ipv4Cidr;
|
||||
use harmony::{
|
||||
hardware::{FirewallGroup, HostCategory, Location, PhysicalHost, SwitchGroup},
|
||||
infra::opnsense::OPNSenseManagementInterface,
|
||||
inventory::Inventory,
|
||||
maestro::Maestro,
|
||||
modules::{
|
||||
http::HttpScore,
|
||||
okd::{dhcp::OKDDhcpScore, dns::OKDDnsScore},
|
||||
tftp::TftpScore,
|
||||
},
|
||||
topology::{LogicalHost, UnmanagedRouter, Url},
|
||||
};
|
||||
use harmony_macros::{ip, mac_address};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
|
||||
let firewall = harmony::topology::LogicalHost {
|
||||
ip: ip!("192.168.5.229"),
|
||||
name: String::from("opnsense-1"),
|
||||
};
|
||||
|
||||
let opnsense = Arc::new(
|
||||
harmony::infra::opnsense::OPNSenseFirewall::new(firewall, None, "root", "opnsense").await,
|
||||
);
|
||||
let lan_subnet = Ipv4Addr::new(10, 100, 8, 0);
|
||||
let gateway_ipv4 = Ipv4Addr::new(10, 100, 8, 1);
|
||||
let gateway_ip = IpAddr::V4(gateway_ipv4);
|
||||
let topology = 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![],
|
||||
};
|
||||
|
||||
let inventory = Inventory {
|
||||
location: Location::new(
|
||||
"232 des Éperviers, Wendake, Qc, G0A 4V0".to_string(),
|
||||
"wk".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![PhysicalHost::empty(HostCategory::Server).mac_address(mac_address!("08:00:27:62:EC:C3"))],
|
||||
};
|
||||
|
||||
// TODO regroup smaller scores in a larger one such as this
|
||||
// let okd_boostrap_preparation();
|
||||
|
||||
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 tftp_score = TftpScore::new(Url::LocalFolder("../../../watchguard/tftpboot".to_string()));
|
||||
let http_score = HttpScore::new(Url::LocalFolder(
|
||||
"../../../watchguard/pxe-http-files".to_string(),
|
||||
));
|
||||
let mut maestro = Maestro::new(inventory, topology);
|
||||
maestro.register_all(vec![
|
||||
Box::new(dns_score),
|
||||
Box::new(dhcp_score),
|
||||
Box::new(load_balancer_score),
|
||||
Box::new(tftp_score),
|
||||
Box::new(http_score),
|
||||
]);
|
||||
harmony_tui::init(maestro).await.unwrap();
|
||||
}
|
||||
Reference in New Issue
Block a user