From b42632f9c8629ae05f1afa17d03ba74ba4a4b3ab Mon Sep 17 00:00:00 2001 From: garrettmills Date: Tue, 22 Apr 2025 22:08:45 -0400 Subject: [PATCH] Finish implementing /system/discover-nodes endpoint --- src/api/cluster/node.rs | 38 ++++++++++++++++++++++++++++++++++++-- src/api/route/system.rs | 21 +++++++++++++++++++-- src/api/util.rs | 2 ++ 3 files changed, 57 insertions(+), 4 deletions(-) diff --git a/src/api/cluster/node.rs b/src/api/cluster/node.rs index b20d2a1..73d4870 100644 --- a/src/api/cluster/node.rs +++ b/src/api/cluster/node.rs @@ -66,8 +66,42 @@ pub async fn discover_nodes( continue; } - info!(target: "p5x", "Discovered node {name} ({pve_host}:{pve_id}). Attempting to register it."); - // fixme: WIP + // Try to get the IP address from K8s + if node.status.is_none() { + debug!(target: "p5x", "Skipping eligible node {name}: could not load status"); + continue; + } + + let status = node.status.unwrap(); + if status.addresses.is_none() { + debug!(target: "p5x", "Skipping eligible node {name}: status is missing network address metadata"); + continue; + } + + let addresses = status.addresses.unwrap(); + let internal = addresses.into_iter().find(|a| a.type_ == "InternalIP"); + if internal.is_none() { + debug!(target: "p5x", "Skipping eligible node {name}: could not find InternalIP in status.addresses"); + continue; + } + + let assigned_ip = internal.unwrap().address; + let assigned_subnet = svc.config.k8s_node_subnet; + + info!(target: "p5x", "Discovered node {name} ({pve_host}:{pve_id}) at {assigned_ip}/{assigned_subnet}."); + + // Register the node + let np = NodeParams { + id: None, + hostname: name, + pve_id, + pve_host: pve_host.to_string(), + assigned_ip, + assigned_subnet, + is_permanent: true, + }; + + register_node(svc, &np).await?; } Ok(()) diff --git a/src/api/route/system.rs b/src/api/route/system.rs index 3fa1ff0..903ad19 100644 --- a/src/api/route/system.rs +++ b/src/api/route/system.rs @@ -1,6 +1,11 @@ use rocket::fairing::AdHoc; use rocket::response::status; -use crate::api::util::read_p5x_config; +use rocket::serde::json::Json; +use sea_orm_rocket::Connection; +use crate::api; +use crate::api::cluster::node::discover_nodes; +use crate::api::services::Services; +use crate::api::util::{raise_500, read_p5x_config}; #[get("/pubkey")] fn get_pubkey() -> Result> { @@ -8,8 +13,20 @@ fn get_pubkey() -> Result> { Ok(config.ssh_pubkey) } +#[get("/discover-nodes")] +async fn trigger_discover_nodes( + conn: Connection<'_, api::Db>, +) -> Result, status::Custom> { + let db = conn.into_inner(); + let svc = Services::build(db).await.map_err(raise_500)?; + + discover_nodes(&svc).await.map_err(raise_500)?; + + Ok(Json(serde_json::json!({}))) +} + pub(super) fn init() -> AdHoc { AdHoc::on_ignite("Routes: /system", |rocket| async { - rocket.mount("/system", routes![get_pubkey]) + rocket.mount("/system", routes![get_pubkey, trigger_discover_nodes]) }) } diff --git a/src/api/util.rs b/src/api/util.rs index 18e6c6c..55c8416 100644 --- a/src/api/util.rs +++ b/src/api/util.rs @@ -15,6 +15,7 @@ pub struct P5xConfig { pub pve_storage_pool: String, pub pve_storage_driver: String, pub k8s_root_password: String, + pub k8s_node_subnet: u32, pub ssh_pubkey: String, pub ssh_privkey: String, } @@ -32,6 +33,7 @@ pub fn read_p5x_config() -> P5xConfig { pve_storage_pool: env::var("P5X_STORAGE_POOL").expect("Missing env: P5X_STORAGE_POOL"), pve_storage_driver: env::var("P5X_STORAGE_DRIVER").expect("Missing env: P5X_STORAGE_DRIVER"), k8s_root_password: env::var("P5X_K8S_ROOT_PASSWORD").expect("Missing env: P5X_K8S_ROOT_PASSWORD"), + k8s_node_subnet: env::var("P5X_K8S_NODE_SUBNET").expect("Missing env: P5X_K8S_NODE_SUBNET").parse().expect("Bad env: P5X_K8S_NODE_SUBNET must be u32"), ssh_pubkey: fs::read_to_string(&pubkey_path).expect(&format!("Could not read SSH pubkey from file: {pubkey_path}")), ssh_privkey: fs::read_to_string(&privkey_path).expect(&format!("Could not read SSH privkey from file: {privkey_path}")), };