diff --git a/README.md b/README.md index e62fb56..e08d064 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,28 @@ client.disable_rescue_mode(test_server.id); print(`Rebooting server with ID: ${test_server.id}`); client.reboot(test_server.id); ``` +#### Injecting SSH Keys into Rescue Mode + +You can also inject SSH keys into the rescue image. The `enable_rescue_mode` function accepts an optional SSH key ID (integer) or an array of SSH key IDs. + +**Important:** The SSH keys must already exist in your Hetzner Cloud project. You can add them in the [Hetzner Cloud Console](https://console.hetzner.cloud/). For more details, refer to the [official documentation on enabling rescue mode](https://docs.hetzner.cloud/reference/cloud#server-actions-enable-rescue-mode-for-a-server). + +Here are some examples of how to use this feature in your Rhai script: + +```rust +// A single SSH key ID +client.enable_rescue_mode(test_server.id, 1337); + +// An array of SSH key IDs +let ssh_keys = [123, 456, 789]; +client.enable_rescue_mode(test_server.id, ssh_keys); + +// Reading an SSH key from an environment variable +let ssh_key_from_env = get_env("SSH_KEY_ID"); +if ssh_key_from_env != "" { + client.enable_rescue_mode(test_server.id, ssh_key_from_env.parse_int()); +} +``` ### 4. Example Output (from `test.rhai` script) diff --git a/src/async_handler.rs b/src/async_handler.rs index 93ccbd7..f6c32aa 100644 --- a/src/async_handler.rs +++ b/src/async_handler.rs @@ -9,7 +9,7 @@ pub enum Request { GetServer(HetznerClient, i64), RebootServer(HetznerClient, i64), ResetServer(HetznerClient, i64), - EnableRescueMode(HetznerClient, i64), + EnableRescueMode(HetznerClient, i64, Vec), DisableRescueMode(HetznerClient, i64), } @@ -55,8 +55,8 @@ pub fn run_worker( 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()); + Request::EnableRescueMode(client, server_id, ssh_keys) => { + let result = rt.block_on(client.enable_rescue_mode_for_server(server_id, ssh_keys)).map_err(|e| e.to_string()); Response::EnableRescueMode(result) } Request::DisableRescueMode(client, server_id) => { diff --git a/src/hetzner_api.rs b/src/hetzner_api.rs index d43655b..efc8a17 100644 --- a/src/hetzner_api.rs +++ b/src/hetzner_api.rs @@ -94,11 +94,11 @@ impl HetznerClient { servers_api::reset_server(&self.configuration, params).await?; Ok(()) } - pub async fn enable_rescue_mode_for_server(&self, server_id: i64) -> Result> { + pub async fn enable_rescue_mode_for_server(&self, server_id: i64, ssh_keys: Vec) -> Result> { let params = EnableRescueModeForServerParams { id: server_id, enable_rescue_mode_for_server_request: Some(EnableRescueModeForServerRequest { - ssh_keys: None, + ssh_keys: if ssh_keys.is_empty() { None } else { Some(ssh_keys) }, r#type: Some(hcloud::models::enable_rescue_mode_for_server_request::Type::Linux64), }), }; diff --git a/src/rhai_api.rs b/src/rhai_api.rs index e7fce39..2558ef3 100644 --- a/src/rhai_api.rs +++ b/src/rhai_api.rs @@ -2,6 +2,7 @@ use crate::async_handler::Response; use crate::async_handler::Request; use crate::hetzner_api::{HetznerClient, WrappedServer}; use rhai::{Engine, EvalAltResult}; +use std::env; use std::sync::{mpsc::{Receiver, Sender}, Arc, Mutex}; use prettytable::{Table, Row, Cell}; @@ -110,7 +111,30 @@ pub fn register_hetzner_api( .register_fn("enable_rescue_mode", { let bridge = api_bridge.clone(); move |client: &mut HetznerClient, server_id: i64| { - bridge.call(Request::EnableRescueMode(client.clone(), server_id), |response| { + bridge.call(Request::EnableRescueMode(client.clone(), server_id, Vec::new()), |response| { + match response { + Response::EnableRescueMode(result) => result.map_err(|e| e.into()), + _ => Err("Unexpected response".into()), + } + }) + } + }) + .register_fn("enable_rescue_mode", { + let bridge = api_bridge.clone(); + move |client: &mut HetznerClient, server_id: i64, ssh_key: i64| { + bridge.call(Request::EnableRescueMode(client.clone(), server_id, vec![ssh_key]), |response| { + match response { + Response::EnableRescueMode(result) => result.map_err(|e| e.into()), + _ => Err("Unexpected response".into()), + } + }) + } + }) + .register_fn("enable_rescue_mode", { + let bridge = api_bridge.clone(); + move |client: &mut HetznerClient, server_id: i64, ssh_keys: rhai::Array| { + let keys: Vec = ssh_keys.into_iter().map(|k| k.as_int().unwrap_or(0)).collect(); + bridge.call(Request::EnableRescueMode(client.clone(), server_id, keys), |response| { match response { Response::EnableRescueMode(result) => result.map_err(|e| e.into()), _ => Err("Unexpected response".into()), @@ -169,4 +193,8 @@ pub fn register_hetzner_api( Ok(table.to_string()) }); + + engine.register_fn("get_env", |key: &str| -> String { + env::var(key).unwrap_or("".to_string()) + }); } \ No newline at end of file diff --git a/test.rhai b/test.rhai index 98e85a8..76d9667 100644 --- a/test.rhai +++ b/test.rhai @@ -13,9 +13,19 @@ print(test_server.show_details()); // Enable rescue mode flag on server print(`Enabling rescue mode on server with ID: ${test_server.id}`); -let root_password = client.enable_rescue_mode(test_server.id); +let root_password = client.enable_rescue_mode(test_server.id, 1337); print(`Root password is: ${root_password}`); +// Enable rescue mode with multiple keys from array +let ssh_keys = [123, 456, 789]; +let root_password = client.enable_rescue_mode(test_server.id, ssh_keys); + +// read SSH key from env var +let ssh_key_from_env = get_env("SSH_KEY_ID"); +if ssh_key_from_env != "" { + client.enable_rescue_mode(test_server.id, ssh_key_from_env.parse_int()); +} + // Disable rescue mode flag on server print(`Disabling rescue mode on server with ID: ${test_server.id}`); client.disable_rescue_mode(test_server.id);