added functionality to create servers + example rhai script to demonstrate it
This commit is contained in:
		
							
								
								
									
										9
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										9
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @@ -466,6 +466,7 @@ dependencies = [ | ||||
|  "prettytable-rs", | ||||
|  "reqwest", | ||||
|  "rhai", | ||||
|  "serde", | ||||
|  "tokio", | ||||
| ] | ||||
|  | ||||
| @@ -1261,6 +1262,7 @@ dependencies = [ | ||||
|  "num-traits", | ||||
|  "once_cell", | ||||
|  "rhai_codegen", | ||||
|  "serde", | ||||
|  "smallvec", | ||||
|  "smartstring", | ||||
|  "thin-vec", | ||||
| @@ -1519,6 +1521,9 @@ name = "smallvec" | ||||
| version = "1.15.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" | ||||
| dependencies = [ | ||||
|  "serde", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "smartstring" | ||||
| @@ -1527,6 +1532,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29" | ||||
| dependencies = [ | ||||
|  "autocfg", | ||||
|  "serde", | ||||
|  "static_assertions", | ||||
|  "version_check", | ||||
| ] | ||||
| @@ -1662,6 +1668,9 @@ name = "thin-vec" | ||||
| version = "0.2.14" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "144f754d318415ac792f9d69fc87abbbfc043ce2ef041c60f16ad828f638717d" | ||||
| dependencies = [ | ||||
|  "serde", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "thiserror" | ||||
|   | ||||
| @@ -6,8 +6,9 @@ edition = "2024" | ||||
| [dependencies] | ||||
| hcloud = "0.21.0" | ||||
| reqwest = "0.12.22" | ||||
| rhai = { version = "1.22.2", features = ["sync"] } | ||||
| rhai = { version = "1.22.2", features = ["sync", "serde"] } | ||||
| tokio = { version = "1.46.1", features = ["full"] } | ||||
|  | ||||
| ping = "0.6.1" | ||||
| prettytable-rs = "0.10.0" | ||||
| serde = "1.0.219" | ||||
|   | ||||
							
								
								
									
										44
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										44
									
								
								README.md
									
									
									
									
									
								
							| @@ -39,7 +39,42 @@ All API interactions start by creating a client instance. | ||||
| let client = new_hetzner_client(HETZNER_API_TOKEN); | ||||
| ``` | ||||
|  | ||||
| ### 2. List Servers & Display Details | ||||
| ### 2. Create a Server | ||||
|  | ||||
| You can create a new server using the `ServerBuilder` pattern. This provides a flexible way to configure the server before creation. | ||||
|  | ||||
| ```rust | ||||
| // Create a server builder with required parameters | ||||
| let server_builder = new_server_builder("my-new-server", "cpx11", "ubuntu-20.04"); | ||||
|  | ||||
| // Chain optional parameters | ||||
| let server_builder = server_builder | ||||
|     .with_location("fsn1") | ||||
|     .with_datacenter("fsn1-dc14") | ||||
|     .with_start_after_create(true) | ||||
|     .with_user_data("#cloud-config\nruncmd:\n  - [ ls, -l, / ]"); | ||||
|  | ||||
| // Specify SSH key IDs. If this is omitted, all SSH keys in your project will be used. | ||||
| let server_builder = server_builder.with_ssh_keys([12345, 67890]); | ||||
|  | ||||
| // Create the server | ||||
| let response = client.create_server(server_builder); | ||||
|  | ||||
| print(`Server creation initiated for: ${response.name}`); | ||||
| ``` | ||||
|  | ||||
| The following options are available on the `ServerBuilder`: | ||||
|  | ||||
| | Method | Description | | ||||
| | :--- | :--- | | ||||
| | `with_location(string)` | Sets the server location (e.g., "fsn1"). | | ||||
| | `with_datacenter(string)`| Sets the datacenter (e.g., "fsn1-dc14"). | | ||||
| | `with_user_data(string)` | Provides user data for cloud-init. | | ||||
| | `with_start_after_create(bool)` | Specifies whether the server should start after creation. | | ||||
| | `with_ssh_keys(array)` | An array of SSH Key IDs to attach to the server. | | ||||
|  | ||||
|  | ||||
| ### 3. List Servers & Display Details | ||||
|  | ||||
| You can fetch all your servers and display their details in a formatted table. | ||||
|  | ||||
| @@ -54,7 +89,7 @@ let test_server = client.get_server(104301883); | ||||
| print(test_server.show_details()); | ||||
| ``` | ||||
|  | ||||
| ### 3. List SSH Keys | ||||
| ### 4. List SSH Keys | ||||
|  | ||||
| You can also list all the SSH keys in your project. | ||||
|  | ||||
| @@ -65,7 +100,7 @@ let ssh_keys = client.list_ssh_keys(); | ||||
| print(ssh_keys.show_table()); | ||||
| ``` | ||||
|  | ||||
| ### 4. Manage Server State | ||||
| ### 5. Manage Server State | ||||
|  | ||||
| Perform actions like enabling rescue mode, disabling it, or rebooting the server. | ||||
|  | ||||
| @@ -106,7 +141,7 @@ if ssh_key_from_env != "" { | ||||
| } | ||||
| ``` | ||||
|  | ||||
| ### 5. Example Output (from `test.rhai` script) | ||||
| ### 6. Example Output (from `test.rhai` script) | ||||
|  | ||||
| ```text | ||||
| Listing all servers... | ||||
| @@ -155,4 +190,3 @@ Listing details from server with ID 104301883... | ||||
| +-------------------+----------------------+ | ||||
| | Rescue Enabled    | false                | | ||||
| +-------------------+----------------------+ | ||||
| ``` | ||||
|   | ||||
							
								
								
									
										25
									
								
								create_server.rhai
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								create_server.rhai
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| let client = new_hetzner_client(get_env("HETZNER_API_TOKEN")); | ||||
|  | ||||
| let server_builder = new_server_builder("my-new-test-server", "cx22", "ubuntu-24.04"); | ||||
|  | ||||
| // Example of using the new optional parameters | ||||
| let server_builder = server_builder | ||||
|     .with_location("fsn1"); | ||||
|     // .with_datacenter("fsn1-dc14") | ||||
|     // .with_start_after_create(true) | ||||
|     // .with_user_data("#cloud-config\nruncmd:\n  - [ ls, -l, / ]"); | ||||
|  | ||||
| // Example of specifying SSH key IDs. | ||||
| // If you don't call with_ssh_keys, all keys will be added by default. | ||||
| // let server_builder = server_builder.with_ssh_keys([12345, 67890]); | ||||
|  | ||||
| let response = client.create_server(server_builder); | ||||
|  | ||||
| print(`Server creation initiated for: ${response.name}`); | ||||
| print(`  ID: ${response.id}`); | ||||
| print(`  Status: ${response.status}`); | ||||
| if response.root_password != "" { | ||||
|     print(`  Root Password: ${response.root_password}`); | ||||
| } else { | ||||
|     print("  Root Password: Not set (SSH key id was provided)"); | ||||
| } | ||||
| @@ -1,9 +1,12 @@ | ||||
| use crate::hetzner_api::{HetznerClient, WrappedServer, WrappedSshKey}; | ||||
| use crate::hetzner_api::{ | ||||
|     HetznerClient, ServerBuilder, WrappedCreateServerResponse, WrappedServer, WrappedSshKey, | ||||
| }; | ||||
| use std::sync::mpsc::{Receiver, Sender}; | ||||
| use tokio::runtime::Builder; | ||||
|  | ||||
| #[derive(Clone)] | ||||
| pub enum Request { | ||||
|     CreateServer(HetznerClient, ServerBuilder), | ||||
|     ListServers(HetznerClient), | ||||
|     GetServerStatus(HetznerClient, i64), | ||||
|     GetServer(HetznerClient, i64), | ||||
| @@ -16,6 +19,7 @@ pub enum Request { | ||||
| } | ||||
|  | ||||
| pub enum Response { | ||||
|     CreateServer(Result<WrappedCreateServerResponse, String>), | ||||
|     ListSshKeys(Result<Vec<WrappedSshKey>, String>), | ||||
|     ListServers(Result<Vec<WrappedServer>, String>), | ||||
|     GetServerStatus(Result<String, String>), | ||||
| @@ -38,12 +42,20 @@ pub fn run_worker( | ||||
|  | ||||
|         while let Ok(request) = command_rx.recv() { | ||||
|             let response = match request { | ||||
|                 Request::CreateServer(client, builder) => { | ||||
|                     let result = rt | ||||
|                         .block_on(client.create_server(builder)) | ||||
|                         .map_err(|e| e.to_string()); | ||||
|                     Response::CreateServer(result) | ||||
|                 } | ||||
|                 Request::ListServers(client) => { | ||||
|                     let result = rt.block_on(client.list_servers()).map_err(|e| e.to_string()); | ||||
|                     Response::ListServers(result) | ||||
|                 } | ||||
|                 Request::GetServerStatus(client, server_id) => { | ||||
|                     let result = rt.block_on(client.get_server_status(server_id)).map_err(|e| e.to_string()); | ||||
|                     let result = rt | ||||
|                         .block_on(client.get_server_status(server_id)) | ||||
|                         .map_err(|e| e.to_string()); | ||||
|                     Response::GetServerStatus(result) | ||||
|                 } | ||||
|                 Request::GetServer(client, server_id) => { | ||||
|   | ||||
| @@ -2,11 +2,14 @@ use hcloud::apis::{ | ||||
|     configuration::Configuration, | ||||
|     servers_api::{ | ||||
|         self, DisableRescueModeForServerParams, EnableRescueModeForServerParams, ListServersParams, | ||||
|         ResetServerParams, | ||||
|         ResetServerParams, CreateServerParams, | ||||
|     }, | ||||
|     ssh_keys_api::{self, ListSshKeysParams}, | ||||
| }; | ||||
| use hcloud::models::{EnableRescueModeForServerRequest, Server, SshKey}; | ||||
| use hcloud::models::{ | ||||
|     CreateServerRequest, CreateServerResponse, EnableRescueModeForServerRequest, Server, SshKey, | ||||
| }; | ||||
| use serde::{Deserialize, Serialize}; | ||||
|  | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct HetznerClient { | ||||
| @@ -19,6 +22,77 @@ pub struct WrappedServer(pub Server); | ||||
| #[derive(Clone)] | ||||
| pub struct WrappedSshKey(pub SshKey); | ||||
|  | ||||
| #[derive(Clone, Debug, Serialize, Deserialize)] | ||||
| pub struct ServerBuilder { | ||||
|     pub name: String, | ||||
|     pub server_type: String, | ||||
|     pub image: String, | ||||
|     pub location: Option<String>, | ||||
|     pub datacenter: Option<String>, | ||||
|     pub user_data: Option<String>, | ||||
|     pub start_after_create: Option<bool>, | ||||
|     pub ssh_keys: Option<Vec<i64>>, | ||||
| } | ||||
|  | ||||
| impl ServerBuilder { | ||||
|     pub fn new(name: String, server_type: String, image: String) -> Self { | ||||
|         Self { | ||||
|             name, | ||||
|             server_type, | ||||
|             image, | ||||
|             location: None, | ||||
|             datacenter: None, | ||||
|             user_data: None, | ||||
|             start_after_create: None, | ||||
|             ssh_keys: None, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn with_location(mut self, location: String) -> Self { | ||||
|         self.location = Some(location); | ||||
|         self | ||||
|     } | ||||
|  | ||||
|     pub fn with_datacenter(mut self, datacenter: String) -> Self { | ||||
|         self.datacenter = Some(datacenter); | ||||
|         self | ||||
|     } | ||||
|  | ||||
|     pub fn with_user_data(mut self, user_data: String) -> Self { | ||||
|         self.user_data = Some(user_data); | ||||
|         self | ||||
|     } | ||||
|  | ||||
|     pub fn with_start_after_create(mut self, start_after_create: bool) -> Self { | ||||
|         self.start_after_create = Some(start_after_create); | ||||
|         self | ||||
|     } | ||||
|  | ||||
|     pub fn with_ssh_keys(mut self, ssh_keys: Vec<i64>) -> Self { | ||||
|         self.ssh_keys = Some(ssh_keys); | ||||
|         self | ||||
|     } | ||||
|  | ||||
|     pub fn build(self) -> CreateServerRequest { | ||||
|         CreateServerRequest { | ||||
|             name: self.name, | ||||
|             server_type: self.server_type, | ||||
|             image: self.image, | ||||
|             location: self.location, | ||||
|             datacenter: self.datacenter, | ||||
|             user_data: self.user_data, | ||||
|             start_after_create: self.start_after_create, | ||||
|             ssh_keys: self | ||||
|                 .ssh_keys | ||||
|                 .map(|keys| keys.into_iter().map(|id| id.to_string()).collect()), | ||||
|             ..Default::default() | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(Clone)] | ||||
| pub struct WrappedCreateServerResponse(pub CreateServerResponse); | ||||
|  | ||||
| impl HetznerClient { | ||||
|     pub fn new(api_token: &str) -> Self { | ||||
|         let mut configuration = Configuration::new(); | ||||
| @@ -32,6 +106,23 @@ impl HetznerClient { | ||||
|         Self { configuration } | ||||
|     } | ||||
|  | ||||
|     pub async fn create_server( | ||||
|         &self, | ||||
|         mut builder: ServerBuilder, | ||||
|     ) -> Result<WrappedCreateServerResponse, Box<dyn std::error::Error>> { | ||||
|         if builder.ssh_keys.is_none() { | ||||
|             let all_keys = self.list_ssh_keys().await?; | ||||
|             let key_ids: Vec<i64> = all_keys.into_iter().map(|k| k.0.id).collect(); | ||||
|             builder.ssh_keys = Some(key_ids); | ||||
|         } | ||||
|  | ||||
|         let params = CreateServerParams { | ||||
|             create_server_request: Some(builder.build()), | ||||
|         }; | ||||
|         let response = servers_api::create_server(&self.configuration, params).await?; | ||||
|         Ok(WrappedCreateServerResponse(response)) | ||||
|     } | ||||
|  | ||||
|     pub async fn list_servers(&self) -> Result<Vec<WrappedServer>, Box<dyn std::error::Error>> { | ||||
|         let mut all_servers = Vec::new(); | ||||
|         let mut page = 1; | ||||
|   | ||||
							
								
								
									
										380
									
								
								src/rhai_api.rs
									
									
									
									
									
								
							
							
						
						
									
										380
									
								
								src/rhai_api.rs
									
									
									
									
									
								
							| @@ -1,10 +1,15 @@ | ||||
| use crate::async_handler::Response; | ||||
| use crate::async_handler::Request; | ||||
| use crate::hetzner_api::{HetznerClient, WrappedServer, WrappedSshKey}; | ||||
| use crate::async_handler::Response; | ||||
| use crate::hetzner_api::{ | ||||
|     HetznerClient, ServerBuilder, WrappedCreateServerResponse, WrappedServer, WrappedSshKey, | ||||
| }; | ||||
| use prettytable::{Cell, Row, Table}; | ||||
| use rhai::{Engine, EvalAltResult}; | ||||
| use std::env; | ||||
| use std::sync::{mpsc::{Receiver, Sender}, Arc, Mutex}; | ||||
| use prettytable::{Table, Row, Cell}; | ||||
| use std::sync::{ | ||||
|     Arc, Mutex, | ||||
|     mpsc::{Receiver, Sender}, | ||||
| }; | ||||
|  | ||||
| #[derive(Clone)] | ||||
| struct ApiBridge { | ||||
| @@ -14,7 +19,10 @@ struct ApiBridge { | ||||
|  | ||||
| impl ApiBridge { | ||||
|     fn new(command_tx: Sender<Request>, reply_rx: Arc<Mutex<Receiver<Response>>>) -> Self { | ||||
|         Self { command_tx, reply_rx } | ||||
|         Self { | ||||
|             command_tx, | ||||
|             reply_rx, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn call<T>( | ||||
| @@ -23,7 +31,12 @@ impl ApiBridge { | ||||
|         response_handler: impl FnOnce(Response) -> Result<T, Box<EvalAltResult>>, | ||||
|     ) -> Result<T, Box<EvalAltResult>> { | ||||
|         self.command_tx.send(request).map_err(|e| e.to_string())?; | ||||
|         let response = self.reply_rx.lock().unwrap().recv().map_err(|e| e.to_string())?; | ||||
|         let response = self | ||||
|             .reply_rx | ||||
|             .lock() | ||||
|             .unwrap() | ||||
|             .recv() | ||||
|             .map_err(|e| e.to_string())?; | ||||
|         response_handler(response) | ||||
|     } | ||||
| } | ||||
| @@ -37,171 +50,313 @@ pub fn register_hetzner_api( | ||||
|  | ||||
|     engine | ||||
|         .register_type_with_name::<HetznerClient>("HetznerClient") | ||||
|         .register_fn("new_hetzner_client", |api_token: &str| -> Result<HetznerClient, Box<EvalAltResult>> { | ||||
|             if api_token.is_empty() { | ||||
|                 return Err("HETZNER_API_TOKEN cannot be empty.".into()); | ||||
|             } | ||||
|             Ok(HetznerClient::new(api_token)) | ||||
|         }) | ||||
|         .register_fn( | ||||
|             "new_hetzner_client", | ||||
|             |api_token: &str| -> Result<HetznerClient, Box<EvalAltResult>> { | ||||
|                 if api_token.is_empty() { | ||||
|                     return Err("HETZNER_API_TOKEN cannot be empty.".into()); | ||||
|                 } | ||||
|                 Ok(HetznerClient::new(api_token)) | ||||
|             }, | ||||
|         ) | ||||
|         .register_fn("list_servers", { | ||||
|             let bridge = api_bridge.clone(); | ||||
|             move |client: &mut HetznerClient| { | ||||
|                 bridge.call(Request::ListServers(client.clone()), |response| match response { | ||||
|                     Response::ListServers(result) => result.map_err(|e| e.into()), | ||||
|                     _ => Err("Unexpected response".into()), | ||||
|                 }) | ||||
|                 bridge.call( | ||||
|                     Request::ListServers(client.clone()), | ||||
|                     |response| match response { | ||||
|                         Response::ListServers(result) => result.map_err(|e| e.into()), | ||||
|                         _ => Err("Unexpected response".into()), | ||||
|                     }, | ||||
|                 ) | ||||
|             } | ||||
|         }) | ||||
|         .register_fn("list_ssh_keys", { | ||||
|             let bridge = api_bridge.clone(); | ||||
|             move |client: &mut HetznerClient| { | ||||
|                 bridge.call(Request::ListSshKeys(client.clone()), |response| match response { | ||||
|                     Response::ListSshKeys(result) => result.map_err(|e| e.into()), | ||||
|                     _ => Err("Unexpected response".into()), | ||||
|                 }) | ||||
|                 bridge.call( | ||||
|                     Request::ListSshKeys(client.clone()), | ||||
|                     |response| match response { | ||||
|                         Response::ListSshKeys(result) => result.map_err(|e| e.into()), | ||||
|                         _ => Err("Unexpected response".into()), | ||||
|                     }, | ||||
|                 ) | ||||
|             } | ||||
|         }) | ||||
|         .register_fn("get_server_status", { | ||||
|             let bridge = api_bridge.clone(); | ||||
|             move |client: &mut HetznerClient, server_id: i64| { | ||||
|                 bridge.call(Request::GetServerStatus(client.clone(), server_id), |response| match response { | ||||
|                     Response::GetServerStatus(result) => result.map_err(|e| e.into()), | ||||
|                     _ => Err("Unexpected response".into()), | ||||
|                 }) | ||||
|                 bridge.call( | ||||
|                     Request::GetServerStatus(client.clone(), server_id), | ||||
|                     |response| match response { | ||||
|                         Response::GetServerStatus(result) => result.map_err(|e| e.into()), | ||||
|                         _ => Err("Unexpected response".into()), | ||||
|                     }, | ||||
|                 ) | ||||
|             } | ||||
|         }) | ||||
|         .register_fn("get_server", { | ||||
|             let bridge = api_bridge.clone(); | ||||
|             move |client: &mut HetznerClient, server_id: i64| { | ||||
|                 bridge.call(Request::GetServer(client.clone(), server_id), |response| match response { | ||||
|                     Response::GetServer(result) => result.map_err(|e| e.into()), | ||||
|                     _ => Err("Unexpected response".into()), | ||||
|                 bridge.call( | ||||
|                     Request::GetServer(client.clone(), server_id), | ||||
|                     |response| match response { | ||||
|                         Response::GetServer(result) => result.map_err(|e| e.into()), | ||||
|                         _ => Err("Unexpected response".into()), | ||||
|                     }, | ||||
|                 ) | ||||
|             } | ||||
|         }) | ||||
|         .register_fn("create_server", { | ||||
|             let bridge = api_bridge.clone(); | ||||
|             move |client: &mut HetznerClient, builder: ServerBuilder| { | ||||
|                 bridge.call(Request::CreateServer(client.clone(), builder), |response| { | ||||
|                     match response { | ||||
|                         Response::CreateServer(result) => result.map_err(|e| e.into()), | ||||
|                         _ => Err("Unexpected response".into()), | ||||
|                     } | ||||
|                 }) | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|     engine | ||||
|         .register_type_with_name::<ServerBuilder>("ServerBuilder") | ||||
|         .register_fn( | ||||
|             "new_server_builder", | ||||
|             |name: String, server_type: String, image: String| { | ||||
|                 ServerBuilder::new(name, server_type, image) | ||||
|             }, | ||||
|         ) | ||||
|         .register_fn("with_location", ServerBuilder::with_location) | ||||
|         .register_fn("with_datacenter", ServerBuilder::with_datacenter) | ||||
|         .register_fn("with_user_data", ServerBuilder::with_user_data) | ||||
|         .register_fn( | ||||
|             "with_start_after_create", | ||||
|             ServerBuilder::with_start_after_create, | ||||
|         ) | ||||
|         .register_fn( | ||||
|             "with_ssh_keys", | ||||
|             |builder: ServerBuilder, ssh_keys: rhai::Array| { | ||||
|                 builder.with_ssh_keys( | ||||
|                     ssh_keys | ||||
|                         .into_iter() | ||||
|                         .map(|k| k.as_int().unwrap()) | ||||
|                         .collect(), | ||||
|                 ) | ||||
|             }, | ||||
|         ); | ||||
|  | ||||
|     engine | ||||
|         .register_type_with_name::<WrappedCreateServerResponse>("CreateServerResponse") | ||||
|         .register_get("id", |resp: &mut WrappedCreateServerResponse| { | ||||
|             resp.0.server.id | ||||
|         }) | ||||
|         .register_get("name", |resp: &mut WrappedCreateServerResponse| { | ||||
|             resp.0.server.name.clone() | ||||
|         }) | ||||
|         .register_get("status", |resp: &mut WrappedCreateServerResponse| { | ||||
|             format!("{:?}", resp.0.server.status) | ||||
|         }) | ||||
|         .register_get("root_password", |resp: &mut WrappedCreateServerResponse| { | ||||
|             resp.0.root_password.clone().unwrap_or_default() | ||||
|         }); | ||||
|  | ||||
|     engine | ||||
|         .register_type_with_name::<WrappedServer>("Server") | ||||
|         .register_get("id", |server: &mut WrappedServer| server.0.id) | ||||
|         .register_get("name", |server: &mut WrappedServer| server.0.name.clone()) | ||||
|         .register_get("status", |server: &mut WrappedServer| format!("{:?}", server.0.status)) | ||||
|         .register_get("created", |server: &mut WrappedServer| server.0.created.clone()) | ||||
|         .register_get("public_ipv4", |server: &mut WrappedServer| server.0.public_net.ipv4.clone().unwrap().ip) | ||||
|         .register_get("server_type", |server: &mut WrappedServer| server.0.server_type.clone().name) | ||||
|         .register_get("included_traffic", |server: &mut WrappedServer| server.0.included_traffic.unwrap_or(0)) | ||||
|         .register_get("ingoing_traffic", |server: &mut WrappedServer| server.0.ingoing_traffic.unwrap_or(0)) | ||||
|         .register_get("outgoing_traffic", |server: &mut WrappedServer| server.0.outgoing_traffic.unwrap_or(0)) | ||||
|         .register_get("primary_disk_size", |server: &mut WrappedServer| server.0.primary_disk_size) | ||||
|         .register_get("rescue_enabled", |server: &mut WrappedServer| server.0.rescue_enabled); | ||||
|         .register_get("status", |server: &mut WrappedServer| { | ||||
|             format!("{:?}", server.0.status) | ||||
|         }) | ||||
|         .register_get("created", |server: &mut WrappedServer| { | ||||
|             server.0.created.clone() | ||||
|         }) | ||||
|         .register_get("public_ipv4", |server: &mut WrappedServer| { | ||||
|             server.0.public_net.ipv4.clone().unwrap().ip | ||||
|         }) | ||||
|         .register_get("server_type", |server: &mut WrappedServer| { | ||||
|             server.0.server_type.clone().name | ||||
|         }) | ||||
|         .register_get("included_traffic", |server: &mut WrappedServer| { | ||||
|             server.0.included_traffic.unwrap_or(0) | ||||
|         }) | ||||
|         .register_get("ingoing_traffic", |server: &mut WrappedServer| { | ||||
|             server.0.ingoing_traffic.unwrap_or(0) | ||||
|         }) | ||||
|         .register_get("outgoing_traffic", |server: &mut WrappedServer| { | ||||
|             server.0.outgoing_traffic.unwrap_or(0) | ||||
|         }) | ||||
|         .register_get("primary_disk_size", |server: &mut WrappedServer| { | ||||
|             server.0.primary_disk_size | ||||
|         }) | ||||
|         .register_get("rescue_enabled", |server: &mut WrappedServer| { | ||||
|             server.0.rescue_enabled | ||||
|         }); | ||||
|  | ||||
|     engine | ||||
|         .register_fn("reboot", { | ||||
|             let bridge = api_bridge.clone(); | ||||
|             move |client: &mut HetznerClient, server_id: i64| { | ||||
|                 bridge.call(Request::RebootServer(client.clone(), server_id), |response| { | ||||
|                     match response { | ||||
|                 bridge.call( | ||||
|                     Request::RebootServer(client.clone(), server_id), | ||||
|                     |response| match response { | ||||
|                         Response::RebootServer(result) => result.map_err(|e| e.into()), | ||||
|                         _ => Err("Unexpected response".into()), | ||||
|                     } | ||||
|                 }) | ||||
|                     }, | ||||
|                 ) | ||||
|             } | ||||
|         }) | ||||
|         .register_fn("reset", { | ||||
|             let bridge = api_bridge.clone(); | ||||
|             move |client: &mut HetznerClient, server_id: i64| { | ||||
|                 bridge.call(Request::ResetServer(client.clone(), server_id), |response| { | ||||
|                     match response { | ||||
|                 bridge.call( | ||||
|                     Request::ResetServer(client.clone(), server_id), | ||||
|                     |response| match response { | ||||
|                         Response::ResetServer(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| { | ||||
|                 bridge.call(Request::EnableRescueModeWithAllKeys(client.clone(), server_id), |response| { | ||||
|                     match response { | ||||
|                 bridge.call( | ||||
|                     Request::EnableRescueModeWithAllKeys(client.clone(), server_id), | ||||
|                     |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 { | ||||
|                 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<i64> = 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 { | ||||
|                 let keys: Vec<i64> = 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()), | ||||
|                     } | ||||
|                 }) | ||||
|                     }, | ||||
|                 ) | ||||
|             } | ||||
|         }) | ||||
|         .register_fn("disable_rescue_mode", { | ||||
|             let bridge = api_bridge.clone(); | ||||
|             move |client: &mut HetznerClient, server_id: i64| { | ||||
|                 bridge.call(Request::DisableRescueMode(client.clone(), server_id), |response| { | ||||
|                     match response { | ||||
|                 bridge.call( | ||||
|                     Request::DisableRescueMode(client.clone(), server_id), | ||||
|                     |response| match response { | ||||
|                         Response::DisableRescueMode(result) => result.map_err(|e| e.into()), | ||||
|                         _ => Err("Unexpected response".into()), | ||||
|                     } | ||||
|                 }) | ||||
|                     }, | ||||
|                 ) | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|     engine | ||||
|         .register_iterator::<Vec<WrappedServer>>() | ||||
|         .register_fn("len", |list: &mut Vec<WrappedServer>| list.len() as i64) | ||||
|         .register_indexer_get(|list: &mut Vec<WrappedServer>, index: i64| list[index as usize].clone()) | ||||
|         .register_fn("show_table", |servers: &mut Vec<WrappedServer>| -> Result<String, Box<EvalAltResult>> { | ||||
|             let mut table = Table::new(); | ||||
|             table.set_titles(Row::new(vec![Cell::new("Server List").style_spec("c")])); | ||||
|             table.add_row(Row::new(vec![ | ||||
|                 Cell::new("ID"), | ||||
|                 Cell::new("Name"), | ||||
|                 Cell::new("Status"), | ||||
|                 Cell::new("Public IPv4"), | ||||
|             ])); | ||||
|             for server in servers { | ||||
|         .register_indexer_get(|list: &mut Vec<WrappedServer>, index: i64| { | ||||
|             list[index as usize].clone() | ||||
|         }) | ||||
|         .register_fn( | ||||
|             "show_table", | ||||
|             |servers: &mut Vec<WrappedServer>| -> Result<String, Box<EvalAltResult>> { | ||||
|                 let mut table = Table::new(); | ||||
|                 table.set_titles(Row::new(vec![Cell::new("Server List").style_spec("c")])); | ||||
|                 table.add_row(Row::new(vec![ | ||||
|                     Cell::new("ID"), | ||||
|                     Cell::new("Name"), | ||||
|                     Cell::new("Status"), | ||||
|                     Cell::new("Public IPv4"), | ||||
|                 ])); | ||||
|                 for server in servers { | ||||
|                     table.add_row(Row::new(vec![ | ||||
|                         Cell::new(&server.0.id.to_string()), | ||||
|                         Cell::new(&server.0.name), | ||||
|                         Cell::new(&format!("{:?}", server.0.status)), | ||||
|                         Cell::new(&server.0.public_net.ipv4.clone().unwrap().ip.to_string()), | ||||
|                     ])); | ||||
|                 } | ||||
|                 Ok(table.to_string()) | ||||
|             }, | ||||
|         ) | ||||
|         .register_fn( | ||||
|             "show_details", | ||||
|             |server: &mut WrappedServer| -> Result<String, Box<EvalAltResult>> { | ||||
|                 let mut table = Table::new(); | ||||
|                 table.set_titles(Row::new(vec![Cell::new(&server.0.name).style_spec("c")])); | ||||
|                 table.add_row(Row::new(vec![ | ||||
|                     Cell::new("ID"), | ||||
|                     Cell::new(&server.0.id.to_string()), | ||||
|                     Cell::new(&server.0.name), | ||||
|                 ])); | ||||
|                 table.add_row(Row::new(vec![ | ||||
|                     Cell::new("Status"), | ||||
|                     Cell::new(&format!("{:?}", server.0.status)), | ||||
|                 ])); | ||||
|                 table.add_row(Row::new(vec![ | ||||
|                     Cell::new("Created"), | ||||
|                     Cell::new(&server.0.created), | ||||
|                 ])); | ||||
|                 table.add_row(Row::new(vec![ | ||||
|                     Cell::new("IPv4"), | ||||
|                     Cell::new(&server.0.public_net.ipv4.clone().unwrap().ip.to_string()), | ||||
|                 ])); | ||||
|             } | ||||
|             Ok(table.to_string()) | ||||
|         }) | ||||
|         .register_fn("show_details", |server: &mut WrappedServer| -> Result<String, Box<EvalAltResult>> { | ||||
|             let mut table = Table::new(); | ||||
|             table.set_titles(Row::new(vec![Cell::new(&server.0.name).style_spec("c")])); | ||||
|             table.add_row(Row::new(vec![Cell::new("ID"), Cell::new(&server.0.id.to_string())])); | ||||
|             table.add_row(Row::new(vec![Cell::new("Status"), Cell::new(&format!("{:?}", server.0.status))])); | ||||
|             table.add_row(Row::new(vec![Cell::new("Created"), Cell::new(&server.0.created)])); | ||||
|             table.add_row(Row::new(vec![Cell::new("IPv4"), Cell::new(&server.0.public_net.ipv4.clone().unwrap().ip.to_string())])); | ||||
|             table.add_row(Row::new(vec![Cell::new("Type"), Cell::new(&server.0.server_type.name)])); | ||||
|             table.add_row(Row::new(vec![Cell::new("Included Traffic"), Cell::new(&format!("{} GB", server.0.included_traffic.unwrap_or(0) / 1024 / 1024 / 1024))])); | ||||
|             table.add_row(Row::new(vec![Cell::new("Ingoing Traffic"), Cell::new(&format!("{} MB", server.0.ingoing_traffic.unwrap_or(0) / 1024 / 1024))])); | ||||
|             table.add_row(Row::new(vec![Cell::new("Outgoing Traffic"), Cell::new(&format!("{} MB", server.0.outgoing_traffic.unwrap_or(0) / 1024 / 1024))])); | ||||
|             table.add_row(Row::new(vec![Cell::new("Primary Disk Size"), Cell::new(&server.0.primary_disk_size.to_string())])); | ||||
|             table.add_row(Row::new(vec![Cell::new("Rescue Enabled"), Cell::new(&server.0.rescue_enabled.to_string())])); | ||||
|                 table.add_row(Row::new(vec![ | ||||
|                     Cell::new("Type"), | ||||
|                     Cell::new(&server.0.server_type.name), | ||||
|                 ])); | ||||
|                 table.add_row(Row::new(vec![ | ||||
|                     Cell::new("Included Traffic"), | ||||
|                     Cell::new(&format!( | ||||
|                         "{} GB", | ||||
|                         server.0.included_traffic.unwrap_or(0) / 1024 / 1024 / 1024 | ||||
|                     )), | ||||
|                 ])); | ||||
|                 table.add_row(Row::new(vec![ | ||||
|                     Cell::new("Ingoing Traffic"), | ||||
|                     Cell::new(&format!( | ||||
|                         "{} MB", | ||||
|                         server.0.ingoing_traffic.unwrap_or(0) / 1024 / 1024 | ||||
|                     )), | ||||
|                 ])); | ||||
|                 table.add_row(Row::new(vec![ | ||||
|                     Cell::new("Outgoing Traffic"), | ||||
|                     Cell::new(&format!( | ||||
|                         "{} MB", | ||||
|                         server.0.outgoing_traffic.unwrap_or(0) / 1024 / 1024 | ||||
|                     )), | ||||
|                 ])); | ||||
|                 table.add_row(Row::new(vec![ | ||||
|                     Cell::new("Primary Disk Size"), | ||||
|                     Cell::new(&server.0.primary_disk_size.to_string()), | ||||
|                 ])); | ||||
|                 table.add_row(Row::new(vec![ | ||||
|                     Cell::new("Rescue Enabled"), | ||||
|                     Cell::new(&server.0.rescue_enabled.to_string()), | ||||
|                 ])); | ||||
|  | ||||
|             Ok(table.to_string()) | ||||
|         }); | ||||
|                 Ok(table.to_string()) | ||||
|             }, | ||||
|         ); | ||||
|  | ||||
|     engine.register_fn("get_env", |key: &str| -> String { | ||||
|         env::var(key).unwrap_or("".to_string()) | ||||
| @@ -211,27 +366,34 @@ pub fn register_hetzner_api( | ||||
|         .register_type_with_name::<WrappedSshKey>("SshKey") | ||||
|         .register_get("id", |key: &mut WrappedSshKey| key.0.id) | ||||
|         .register_get("name", |key: &mut WrappedSshKey| key.0.name.clone()) | ||||
|         .register_get("fingerprint", |key: &mut WrappedSshKey| key.0.fingerprint.clone()); | ||||
|         .register_get("fingerprint", |key: &mut WrappedSshKey| { | ||||
|             key.0.fingerprint.clone() | ||||
|         }); | ||||
|  | ||||
|     engine | ||||
|         .register_iterator::<Vec<WrappedSshKey>>() | ||||
|         .register_fn("len", |list: &mut Vec<WrappedSshKey>| list.len() as i64) | ||||
|         .register_indexer_get(|list: &mut Vec<WrappedSshKey>, index: i64| list[index as usize].clone()) | ||||
|         .register_fn("show_table", |keys: &mut Vec<WrappedSshKey>| -> Result<String, Box<EvalAltResult>> { | ||||
|             let mut table = Table::new(); | ||||
|             table.set_titles(Row::new(vec![Cell::new("SSH Keys").style_spec("c")])); | ||||
|             table.add_row(Row::new(vec![ | ||||
|                 Cell::new("ID"), | ||||
|                 Cell::new("Name"), | ||||
|                 Cell::new("Fingerprint"), | ||||
|             ])); | ||||
|             for key in keys { | ||||
|         .register_indexer_get(|list: &mut Vec<WrappedSshKey>, index: i64| { | ||||
|             list[index as usize].clone() | ||||
|         }) | ||||
|         .register_fn( | ||||
|             "show_table", | ||||
|             |keys: &mut Vec<WrappedSshKey>| -> Result<String, Box<EvalAltResult>> { | ||||
|                 let mut table = Table::new(); | ||||
|                 table.set_titles(Row::new(vec![Cell::new("SSH Keys").style_spec("c")])); | ||||
|                 table.add_row(Row::new(vec![ | ||||
|                     Cell::new(&key.0.id.to_string()), | ||||
|                     Cell::new(&key.0.name), | ||||
|                     Cell::new(&key.0.fingerprint), | ||||
|                     Cell::new("ID"), | ||||
|                     Cell::new("Name"), | ||||
|                     Cell::new("Fingerprint"), | ||||
|                 ])); | ||||
|             } | ||||
|             Ok(table.to_string()) | ||||
|         }); | ||||
| } | ||||
|                 for key in keys { | ||||
|                     table.add_row(Row::new(vec![ | ||||
|                         Cell::new(&key.0.id.to_string()), | ||||
|                         Cell::new(&key.0.name), | ||||
|                         Cell::new(&key.0.fingerprint), | ||||
|                     ])); | ||||
|                 } | ||||
|                 Ok(table.to_string()) | ||||
|             }, | ||||
|         ); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user