lisuerhg
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
||||
/target
|
||||
config.toml
|
||||
|
||||
92
Cargo.lock
generated
92
Cargo.lock
generated
@@ -79,6 +79,12 @@ version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.12.0"
|
||||
@@ -162,7 +168,7 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6e524506490a1953d237cb87b1cfc1e46f88c18f10a22dfe0f507dc6bfc7f7f"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"defmt-macros",
|
||||
]
|
||||
|
||||
@@ -217,6 +223,16 @@ version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "find-msvc-tools"
|
||||
version = "0.1.9"
|
||||
@@ -309,12 +325,27 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.186"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
|
||||
dependencies = [
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.33"
|
||||
@@ -384,6 +415,29 @@ version = "1.70.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.9.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.17"
|
||||
@@ -451,6 +505,15 @@ version = "6.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
|
||||
dependencies = [
|
||||
"bitflags 2.13.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.12.4"
|
||||
@@ -527,6 +590,12 @@ dependencies = [
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.228"
|
||||
@@ -572,6 +641,22 @@ version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b"
|
||||
dependencies = [
|
||||
"errno",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.6.4"
|
||||
@@ -634,7 +719,9 @@ dependencies = [
|
||||
"bytes",
|
||||
"libc",
|
||||
"mio",
|
||||
"parking_lot",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"socket2",
|
||||
"tokio-macros",
|
||||
"windows-sys 0.61.2",
|
||||
@@ -735,9 +822,12 @@ dependencies = [
|
||||
"camino",
|
||||
"clap",
|
||||
"env_logger",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"mikrotik-rs",
|
||||
"regex",
|
||||
"serde",
|
||||
"tokio",
|
||||
"toml",
|
||||
]
|
||||
|
||||
|
||||
@@ -8,7 +8,10 @@ anyhow = "1.0.103"
|
||||
camino = { version = "1.2.4", features = ["serde1"] }
|
||||
clap = { version = "4.6.1", features = ["derive"] }
|
||||
env_logger = "0.11.11"
|
||||
lazy_static = "1.5.0"
|
||||
log = "0.4.33"
|
||||
mikrotik-rs = { version = "0.8.0", features = ["tokio-tls"] }
|
||||
regex = "1.12.4"
|
||||
serde = { version = "1.0.228", features = ["derive"] }
|
||||
tokio = { version = "1.52.3", features = ["full"] }
|
||||
toml = "1.1.2"
|
||||
|
||||
@@ -25,7 +25,7 @@ pub struct ConfigDefaultLogins {
|
||||
pub password: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct ConfigHost {
|
||||
pub name: String,
|
||||
pub ip: IpAddr,
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
use core::panic;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
hash::Hash,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use mikrotik_rs::{Command, CommandBuilder, Event, MikrotikDevice};
|
||||
use regex::Regex;
|
||||
|
||||
use crate::config::{Config, ConfigHost};
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref MTC: Arc<Mutex<MtCommanderInternal>> = MtCommanderInternal::new_mutex();
|
||||
}
|
||||
|
||||
pub struct MtCommander;
|
||||
struct MtCommanderInternal {
|
||||
cfg: Option<Config>,
|
||||
}
|
||||
|
||||
impl MtCommander {
|
||||
pub fn init(cfg: Config) -> anyhow::Result<()> {
|
||||
let mut mtc = MTC.lock().map_err(|e| anyhow::anyhow!(e.to_string()))?;
|
||||
mtc.cfg = Some(cfg);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn run_command_on_hosts(
|
||||
hosts: &[ConfigHost],
|
||||
command: &str,
|
||||
) -> anyhow::Result<HashMap<ConfigHost, String>> {
|
||||
let mut res_map = HashMap::new();
|
||||
for host in hosts {
|
||||
let res = Self::run_command_on_host(host, command).await?;
|
||||
res_map.insert(host.clone(), res);
|
||||
}
|
||||
Ok(res_map)
|
||||
}
|
||||
pub async fn run_command_on_host(host: &ConfigHost, command: &str) -> anyhow::Result<String> {
|
||||
let mtc = MTC.lock().map_err(|e| anyhow::anyhow!(e.to_string()))?;
|
||||
mtc.run_command(host, &command).await
|
||||
}
|
||||
|
||||
pub async fn run_command_on_hosts_and_parse_re(
|
||||
hosts: &[ConfigHost],
|
||||
command: &str,
|
||||
parse_re: &Regex,
|
||||
) -> anyhow::Result<HashMap<ConfigHost, Vec<String>>> {
|
||||
let mut res_map = HashMap::new();
|
||||
for host in hosts {
|
||||
let res = Self::run_command_on_host_and_parse_re(host, command, parse_re).await?;
|
||||
res_map.insert(host.clone(), res);
|
||||
}
|
||||
Ok(res_map)
|
||||
}
|
||||
|
||||
pub async fn run_command_on_host_and_parse_re(
|
||||
host: &ConfigHost,
|
||||
command: &str,
|
||||
parse_re: &Regex,
|
||||
) -> anyhow::Result<Vec<String>> {
|
||||
let mtc = MTC.lock().map_err(|e| anyhow::anyhow!(e.to_string()))?;
|
||||
let res = mtc.run_command(host, &command).await?;
|
||||
let out = parse_re
|
||||
.find_iter(&res)
|
||||
.map(|s| s.as_str().to_string())
|
||||
.collect();
|
||||
Ok(out)
|
||||
}
|
||||
}
|
||||
|
||||
impl MtCommanderInternal {
|
||||
fn new(cfg: Config) -> Self {
|
||||
Self { cfg: Some(cfg) }
|
||||
}
|
||||
fn new_mutex() -> Arc<Mutex<Self>> {
|
||||
Arc::new(Mutex::new(Self { cfg: None }))
|
||||
}
|
||||
fn init(&mut self, cfg: Config) -> anyhow::Result<()> {
|
||||
self.cfg = Some(cfg);
|
||||
self.spawn_watcher_thread()?;
|
||||
Ok(())
|
||||
}
|
||||
fn cfg(&self) -> &Config {
|
||||
if let Some(cfg) = &self.cfg {
|
||||
cfg
|
||||
} else {
|
||||
panic!();
|
||||
}
|
||||
}
|
||||
fn spawn_watcher_thread(&mut self) -> anyhow::Result<()> {
|
||||
async fn watcher() {}
|
||||
|
||||
tokio::spawn(watcher());
|
||||
Ok(())
|
||||
}
|
||||
async fn run_command(&self, host: &ConfigHost, cmd: &str) -> anyhow::Result<String> {
|
||||
let dev = MikrotikDevice::connect(
|
||||
format!("{}", &host.ip),
|
||||
&host.username(self.cfg()),
|
||||
Some(&host.password(self.cfg())),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let mut rx = dev
|
||||
.send_command(CommandBuilder::new().command(cmd).build())
|
||||
.await?;
|
||||
|
||||
let mut res = String::new();
|
||||
|
||||
while let Some(event) = rx.recv().await {
|
||||
match event {
|
||||
Event::Reply { response, .. } => {
|
||||
log::debug!("({}) {:?}", &host.ip, response.attributes);
|
||||
}
|
||||
Event::Done { .. } => break,
|
||||
Event::Trap { response, .. } => {
|
||||
log::error!("({}) {:?}", &host.ip, response.message);
|
||||
}
|
||||
other => println!("{other:?}"),
|
||||
}
|
||||
}
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user