From a246b210ee2a087e033eb5b49d169eb7146f4e58 Mon Sep 17 00:00:00 2001 From: Sugui Date: Sun, 7 Jul 2024 19:01:11 +0200 Subject: [PATCH] Added ssh functionality and improved hostnames --- Cargo.lock | 406 +++++++++++++++++++++++++++++++++++++++++--- Cargo.toml | 4 +- src/hostname.rs | 31 ++-- src/machine.rs | 24 +-- src/main.rs | 24 ++- src/monitor.rs | 7 + src/ping_monitor.rs | 18 -- src/ssh_monitor.rs | 35 ++++ 8 files changed, 464 insertions(+), 85 deletions(-) create mode 100644 src/monitor.rs delete mode 100644 src/ping_monitor.rs create mode 100644 src/ssh_monitor.rs diff --git a/Cargo.lock b/Cargo.lock index b6d216f..98e76a1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,20 +3,75 @@ version = 3 [[package]] -name = "aho-corasick" -version = "1.1.3" +name = "addr2line" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" dependencies = [ - "memchr", + "gimli", ] +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "backtrace" +version = "0.3.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "bytes" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" + +[[package]] +name = "cc" +version = "1.0.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5208975e568d83b6b05cc0a063c8e7e9acc2b43bee6da15616a5b73e109d7437" + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "fastrand" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" + [[package]] name = "getrandom" version = "0.2.15" @@ -28,12 +83,36 @@ dependencies = [ "wasi", ] +[[package]] +name = "gimli" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hostname-validator" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f558a64ac9af88b5ba400d99b579451af0d39c6d360980045b91aac966d705e2" + [[package]] name = "libc" version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + [[package]] name = "memchr" version = "2.7.4" @@ -44,11 +123,79 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" name = "minimon" version = "0.1.0" dependencies = [ + "hostname-validator", + "openssh", "ping", - "regex", "thiserror", + "tokio", ] +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "openssh" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "432f4a7e4d194272876710557e6b712fc304e7b4711e2063655df1e446b4b8e3" +dependencies = [ + "libc", + "once_cell", + "shell-escape", + "tempfile", + "thiserror", + "tokio", + "tokio-pipe", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + [[package]] name = "ping" version = "0.5.2" @@ -56,7 +203,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "122ee1f5a6843bec84fcbd5c6ba3622115337a6b8965b93a61aad347648f4e8d" dependencies = [ "rand", - "socket2", + "socket2 0.4.10", "thiserror", ] @@ -115,33 +262,38 @@ dependencies = [ ] [[package]] -name = "regex" -version = "1.10.5" +name = "rustc-demangle" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", ] [[package]] -name = "regex-automata" -version = "0.4.7" +name = "shell-escape" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] +checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f" [[package]] -name = "regex-syntax" -version = "0.8.4" +name = "signal-hook-registry" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] [[package]] name = "socket2" @@ -154,16 +306,38 @@ dependencies = [ ] [[package]] -name = "syn" -version = "2.0.68" +name = "socket2" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "syn" +version = "2.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "201fcda3845c23e8212cd466bfebf0bd20694490fc0356ae8e428e0824a915a6" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "tempfile" +version = "3.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +dependencies = [ + "cfg-if", + "fastrand", + "rustix", + "windows-sys 0.52.0", +] + [[package]] name = "thiserror" version = "1.0.61" @@ -184,6 +358,45 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio" +version = "1.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "pin-project-lite", + "signal-hook-registry", + "socket2 0.5.7", + "tokio-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-macros" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-pipe" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f213a84bffbd61b8fa0ba8a044b4bbe35d471d0b518867181e82bd5c15542784" +dependencies = [ + "libc", + "tokio", +] + [[package]] name = "unicode-ident" version = "1.0.12" @@ -217,3 +430,142 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/Cargo.toml b/Cargo.toml index b2a058d..aea6496 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,8 @@ version = "0.1.0" edition = "2021" [dependencies] +hostname-validator = "1.1.1" +openssh = "0.10.4" ping = "0.5.2" -regex = "1.10.5" thiserror = "1.0.61" +tokio = { version = "1.38.0", features = ["rt-multi-thread"] } diff --git a/src/hostname.rs b/src/hostname.rs index a04fe6e..4a343f8 100644 --- a/src/hostname.rs +++ b/src/hostname.rs @@ -1,35 +1,26 @@ use ::thiserror::Error; -use regex::Regex; - -const VALID_IP_ADDRESS_PATTERN: &str = r"^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$"; -const VALID_HOSTNAME_PATTERN: &str = r"^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$"; #[derive(Clone, Debug, Error)] #[error("The hostname \"{0}\" is invalid")] pub struct InvalidHostnameError(String); pub struct Hostname { - hostname: String, + pub value: String, } impl Hostname { pub fn new(hostname: &str) -> Result { - if Self::is_valid_ip(&hostname) || Self::is_valid_hostname(&hostname) { + if Self::is_valid_hostname(&hostname) { Ok(Hostname { - hostname: hostname.to_string(), + value: hostname.to_string(), }) } else { Err(InvalidHostnameError(hostname.to_string())) } } - fn is_valid_ip(ip: &str) -> bool { - let re = Regex::new(VALID_IP_ADDRESS_PATTERN).unwrap(); - re.is_match(ip) - } fn is_valid_hostname(hostname: &str) -> bool { - let re = Regex::new(VALID_HOSTNAME_PATTERN).unwrap(); - re.is_match(hostname) + hostname_validator::is_valid(hostname) } } @@ -57,12 +48,24 @@ mod tests { assert!(Hostname::new("is-42-the-response").is_ok()); assert!(Hostname::new("GoB.NaSa-42.eu").is_ok()); assert!(Hostname::new("256.127.63.31").is_ok()); + assert!(Hostname::new( + "es.this-large-hostname-is-destined-to-work.so-you-dont-need-to-worry-for-anything.com" + ) + .is_ok()); } #[test] fn invalid_hostnames() { assert!(Hostname::new("no..double.dots").is_err()); - assert!(Hostname::new("#illegal-character").is_err()); // We don't support IPv6 yet + assert!(Hostname::new("#illegal-character").is_err()); + assert!(Hostname::new( + "es.this-large-hostname-is-destined-to-panic-so-hard-that-it-will-break-computer.com" + ) + .is_err()); + assert!(Hostname::new( + "too-large-hostname.too-large-hostname.too-large-hostname.too-large-hostname.too-large-hostname.too-large-hostname.too-large-hostname.too-large-hostname.too-large-hostname.too-large-hostname.too-large-hostname.too-large-hostname.too-large-hostname.too-large-hostname" + ) + .is_err()); assert!(Hostname::new("").is_err()); assert!(Hostname::new("not-end-with-hyphen-").is_err()); } diff --git a/src/machine.rs b/src/machine.rs index 3b6284a..37853a8 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -1,15 +1,8 @@ use crate::hostname::Hostname; -use std::collections::HashMap; pub struct Machine { - name: String, - hostname: Hostname, -} - -pub enum Status { - Unreachable, - Forbidden, - Success(HashMap), + pub name: String, + pub hostname: Hostname, } impl Machine { @@ -20,16 +13,3 @@ impl Machine { } } } - -pub trait Monitor { - fn monitor(machine: &Machine) -> Status; -} - -#[derive(Debug)] -struct SshMonitor {} - -impl Monitor for SshMonitor { - fn monitor(machine: &Machine) -> Status { - todo!() - } -} diff --git a/src/main.rs b/src/main.rs index 56152c9..5fb1a46 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,26 @@ +use hostname::Hostname; +use machine::Machine; +use monitor::Monitor; +use ssh_monitor::SshMonitor; + mod hostname; mod machine; -mod ping_monitor; -use machine::Machine; +mod monitor; +mod ssh_monitor; -fn main() { +#[tokio::main] +async fn main() { println!("Hello, world!"); + + let machine = Machine::new("kogasa", Hostname::new("kogasa").unwrap()); + + let status = SshMonitor::monitor(&machine).await; + + println!("{}:", machine.name); + + if let Ok(commands) = status { + for (command, output) in commands.iter() { + println!("{}: {}", command, output); + } + } } diff --git a/src/monitor.rs b/src/monitor.rs new file mode 100644 index 0000000..bcfaed0 --- /dev/null +++ b/src/monitor.rs @@ -0,0 +1,7 @@ +use std::{collections::HashMap, error::Error}; + +use crate::machine::Machine; + +pub trait Monitor { + async fn monitor(machine: &Machine) -> Result, Box>; +} diff --git a/src/ping_monitor.rs b/src/ping_monitor.rs deleted file mode 100644 index cbc7a25..0000000 --- a/src/ping_monitor.rs +++ /dev/null @@ -1,18 +0,0 @@ -use crate::machine::{Machine, Monitor, Status}; - -#[derive(Debug)] -struct PingMonitor {} - -impl Monitor for PingMonitor { - fn monitor(machine: &Machine) -> Status { - todo!() - } -} - -#[cfg(test)] -mod test { - #[test] - fn monitor_works() { - assert!(true) - } -} diff --git a/src/ssh_monitor.rs b/src/ssh_monitor.rs new file mode 100644 index 0000000..01817cb --- /dev/null +++ b/src/ssh_monitor.rs @@ -0,0 +1,35 @@ +use std::{collections::HashMap, error::Error}; + +use openssh::{KnownHosts, Session}; + +use crate::{machine::Machine, monitor::Monitor}; + +#[derive(Debug)] +pub struct SshMonitor {} + +impl Monitor for SshMonitor { + async fn monitor(machine: &Machine) -> Result, Box> { + let result = Self::monitor_with_ssh(&machine).await; + match result { + Ok(commands) => Ok(commands), + Err(ssh_error) => Err(Box::new(ssh_error)), + } + } +} + +impl SshMonitor { + async fn monitor_with_ssh( + machine: &Machine, + ) -> Result, openssh::Error> { + let uri = format!("ssh://{}", &machine.hostname.value); + let session = Session::connect(uri, KnownHosts::Accept).await?; + let output = session.command("neofetch").output().await?; + let mut commands = HashMap::new(); + commands.insert( + "neofetch".to_string(), + String::from_utf8(output.stdout).unwrap(), + ); + + Ok(commands) + } +}