From 9dfb10cca6d1d9a2fdb2ec89e5eab5eee789eafb Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Tue, 15 Jul 2025 14:46:05 +0200 Subject: [PATCH] added reset, enable and disable rescue mode functionality --- example.rhai | 21 +++++++++ src/async_handler.rs | 23 +++++++--- src/hetzner_api.rs | 33 ++++++++++++-- src/ping.rs | 16 ------- src/rhai_api.rs | 102 +++++++++++++++++++++++++++++-------------- 5 files changed, 138 insertions(+), 57 deletions(-) diff --git a/example.rhai b/example.rhai index e92432e..0c93ee9 100644 --- a/example.rhai +++ b/example.rhai @@ -21,6 +21,7 @@ try { print("Server is offline."); } + // --- REBOOT --- // To reboot the server, uncomment the following lines: // print("\nAttempting to reboot the server..."); // try { @@ -29,6 +30,26 @@ try { // } catch(e) { // print(`Error during reboot: ${e}`); // } + + // --- ENABLE RESCUE MODE --- + // To enable rescue mode, uncomment the following lines: + // print("\nEnabling rescue mode..."); + // try { + // let root_password = first_server.enable_rescue_mode(client); + // print(`Rescue mode enabled. Root password: ${root_password}`); + // } catch(e) { + // print(`Error enabling rescue mode: ${e}`); + // } + + // --- DISABLE RESCUE MODE --- + // To disable rescue mode, uncomment the following lines: + // print("\nDisabling rescue mode..."); + // try { + // first_server.disable_rescue_mode(client); + // print("Rescue mode disabled."); + // } catch(e) { + // print(`Error disabling rescue mode: ${e}`); + // } } } catch (e) { print(`An error occurred: ${e}`); diff --git a/src/async_handler.rs b/src/async_handler.rs index 3208f5c..0036aff 100644 --- a/src/async_handler.rs +++ b/src/async_handler.rs @@ -1,5 +1,4 @@ use crate::hetzner_api::{HetznerClient, WrappedServer}; -use crate::ping::ping_server; use std::net::IpAddr; use std::sync::mpsc::{Receiver, Sender}; use tokio::runtime::Builder; @@ -10,7 +9,9 @@ pub enum Request { GetServerStatus(HetznerClient, i64), GetServer(HetznerClient, i64), RebootServer(HetznerClient, i64), - PingServer(IpAddr), + ResetServer(HetznerClient, i64), + EnableRescueMode(HetznerClient, i64), + DisableRescueMode(HetznerClient, i64), } pub enum Response { @@ -18,7 +19,9 @@ pub enum Response { GetServerStatus(Result), GetServer(Result), RebootServer(Result<(), String>), - PingServer(Result), + ResetServer(Result<(), String>), + EnableRescueMode(Result), + DisableRescueMode(Result<(), String>), } pub fn run_worker( @@ -49,9 +52,17 @@ pub fn run_worker( let result = rt.block_on(client.reboot_server(server_id)).map_err(|e| e.to_string()); Response::RebootServer(result) } - Request::PingServer(ip) => { - let result = ping_server(ip).map_err(|e| e.to_string()); - Response::PingServer(result) + Request::ResetServer(client, server_id) => { + let result = rt.block_on(client.reset_server(server_id)).map_err(|e| e.to_string()); + Response::ResetServer(result) + } + Request::EnableRescueMode(client, server_id) => { + let result = rt.block_on(client.enable_rescue_mode_for_server(server_id)).map_err(|e| e.to_string()); + Response::EnableRescueMode(result) + } + Request::DisableRescueMode(client, server_id) => { + let result = rt.block_on(client.disable_rescue_mode_for_server(server_id)).map_err(|e| e.to_string()); + Response::DisableRescueMode(result) } }; reply_tx.send(response).expect("Failed to send response"); diff --git a/src/hetzner_api.rs b/src/hetzner_api.rs index dea3c84..2225f5f 100644 --- a/src/hetzner_api.rs +++ b/src/hetzner_api.rs @@ -1,5 +1,5 @@ -use hcloud::apis::{configuration::Configuration, servers_api::{self, ListServersParams}}; -use hcloud::models::Server; +use hcloud::apis::{configuration::Configuration, servers_api::{self, ListServersParams, ResetServerParams, EnableRescueModeForServerParams, DisableRescueModeForServerParams}}; +use hcloud::models::{Server, EnableRescueModeForServerRequest}; #[derive(Debug, Clone)] pub struct HetznerClient { @@ -88,4 +88,31 @@ impl HetznerClient { servers_api::soft_reboot_server(&self.configuration, params).await?; Ok(()) } -} \ No newline at end of file + + pub async fn reset_server(&self, server_id: i64) -> Result<(), Box> { + let params = ResetServerParams { + id: server_id, + }; + servers_api::reset_server(&self.configuration, params).await?; + Ok(()) + } + pub async fn enable_rescue_mode_for_server(&self, server_id: i64) -> Result> { + let params = EnableRescueModeForServerParams { + id: server_id, + enable_rescue_mode_for_server_request: Some(EnableRescueModeForServerRequest { + ssh_keys: None, + r#type: Some(hcloud::models::enable_rescue_mode_for_server_request::Type::Linux64), + }), + }; + let response = servers_api::enable_rescue_mode_for_server(&self.configuration, params).await?; + Ok(response.root_password.expect("Unable to fetch root_password from enabling rescue mode for server response")) + } + + pub async fn disable_rescue_mode_for_server(&self, server_id: i64) -> Result<(), Box> { + let params = DisableRescueModeForServerParams { + id: server_id, + }; + servers_api::disable_rescue_mode_for_server(&self.configuration, params).await?; + Ok(()) + } +} diff --git a/src/ping.rs b/src/ping.rs index 849b397..e69de29 100644 --- a/src/ping.rs +++ b/src/ping.rs @@ -1,16 +0,0 @@ -use std::net::IpAddr; -use std::time::Duration; - -pub fn ping_server(ip: IpAddr) -> Result> { - match ping::new(ip) - .socket_type(ping::SocketType::DGRAM) - .timeout(Duration::from_secs(2)) - .send() - { - Ok(_) => Ok(true), - Err(e) => { - eprintln!("Ping error: {}", e); - Ok(false) - } - } -} \ No newline at end of file diff --git a/src/rhai_api.rs b/src/rhai_api.rs index 91423f2..54d9172 100644 --- a/src/rhai_api.rs +++ b/src/rhai_api.rs @@ -27,8 +27,12 @@ pub fn register_hetzner_api( let get_server_rx = reply_rx.clone(); let reboot_server_tx = command_tx.clone(); let reboot_server_rx = reply_rx.clone(); - let ping_server_tx = command_tx.clone(); - let ping_server_rx = reply_rx.clone(); + let reset_server_tx = command_tx.clone(); + let reset_server_rx = reply_rx.clone(); + let enable_rescue_mode_tx = command_tx.clone(); + let enable_rescue_mode_rx = reply_rx.clone(); + let disable_rescue_mode_tx = command_tx.clone(); + let disable_rescue_mode_rx = reply_rx.clone(); engine .register_fn( @@ -133,7 +137,28 @@ pub fn register_hetzner_api( } }, ) - .register_iterator::>() + .register_fn( + "reset", + move |server: &mut WrappedServer, + client: HetznerClient| + -> Result<(), Box> { + reset_server_tx + .send(Request::ResetServer(client, server.0.id)) + .map_err(|e| e.to_string())?; + + let response = reset_server_rx + .lock() + .unwrap() + .recv() + .map_err(|e| e.to_string())?; + + match response { + Response::ResetServer(result) => result.map_err(|e| e.into()), + _ => Err("Unexpected response".into()), + } + }, + ) + .register_iterator::>() .register_fn("len", |list: &mut Vec| list.len() as i64) .register_indexer_get(|list: &mut Vec, index: i64| list[index as usize].clone()) .register_fn( @@ -158,35 +183,6 @@ pub fn register_hetzner_api( Ok(table.to_string()) }, ) - .register_fn( - "ping", - move |server: &mut WrappedServer| -> Result> { - ping_server_tx - .send(Request::PingServer( - server - .0 - .public_net - .ipv4 - .clone() - .unwrap() - .ip - .parse() - .unwrap(), - )) - .map_err(|e| e.to_string())?; - - let response = ping_server_rx - .lock() - .unwrap() - .recv() - .map_err(|e| e.to_string())?; - - match response { - Response::PingServer(result) => result.map_err(|e| e.into()), - _ => Err("Unexpected response".into()), - } - }, - ) .register_fn( "show_details", |server: &mut WrappedServer| -> Result> { @@ -238,4 +234,46 @@ pub fn register_hetzner_api( Ok(table.to_string()) }, ); + engine.register_fn( + "enable_rescue_mode", + move |server: &mut WrappedServer, + client: HetznerClient| + -> Result> { + enable_rescue_mode_tx + .send(Request::EnableRescueMode(client, server.0.id)) + .map_err(|e| e.to_string())?; + + let response = enable_rescue_mode_rx + .lock() + .unwrap() + .recv() + .map_err(|e| e.to_string())?; + + match response { + Response::EnableRescueMode(result) => result.map_err(|e| e.into()), + _ => Err("Unexpected response".into()), + } + }, + ) + .register_fn( + "disable_rescue_mode", + move |server: &mut WrappedServer, + client: HetznerClient| + -> Result<(), Box> { + disable_rescue_mode_tx + .send(Request::DisableRescueMode(client, server.0.id)) + .map_err(|e| e.to_string())?; + + let response = disable_rescue_mode_rx + .lock() + .unwrap() + .recv() + .map_err(|e| e.to_string())?; + + match response { + Response::DisableRescueMode(result) => result.map_err(|e| e.into()), + _ => Err("Unexpected response".into()), + } + }, + ); } \ No newline at end of file