register and list workers
This commit is contained in:
@@ -75,8 +75,12 @@ pub enum Command {
|
|||||||
name: Option<String>,
|
name: Option<String>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// List registered workers and their reachability status
|
/// List registered workers
|
||||||
Workers,
|
Workers {
|
||||||
|
/// Check reachability of each worker over SSH
|
||||||
|
#[arg(short, long)]
|
||||||
|
check: bool,
|
||||||
|
},
|
||||||
|
|
||||||
/// Set the default worker
|
/// Set the default worker
|
||||||
Default {
|
Default {
|
||||||
|
|||||||
@@ -1,6 +1,43 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
|
use crate::{config, ssh};
|
||||||
|
|
||||||
pub fn execute(connection: &str, name: Option<&str>) -> Result<()> {
|
pub fn execute(connection: &str, name: Option<&str>) -> Result<()> {
|
||||||
let _ = (connection, name);
|
let mut cfg = config::load()?;
|
||||||
anyhow::bail!("not yet implemented")
|
|
||||||
|
let name = match name {
|
||||||
|
Some(n) => n.to_string(),
|
||||||
|
None => ssh::hostname_from_connection(connection),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Reject duplicates (same name or same connection string).
|
||||||
|
if cfg.get_worker(&name).is_some() {
|
||||||
|
anyhow::bail!(
|
||||||
|
"a worker named '{}' is already registered\n\
|
||||||
|
Use 'p default {}' to make it the default, or choose a different name with -n",
|
||||||
|
name, name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let first = cfg.workers.is_empty();
|
||||||
|
cfg.workers.push(config::WorkerConfig {
|
||||||
|
name: name.clone(),
|
||||||
|
connection: connection.to_string(),
|
||||||
|
});
|
||||||
|
|
||||||
|
// First registered worker becomes the default automatically.
|
||||||
|
if first {
|
||||||
|
cfg.default_worker = Some(name.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
config::save(&cfg)?;
|
||||||
|
|
||||||
|
if first {
|
||||||
|
println!("Registered '{}' and set as default worker.", name);
|
||||||
|
} else {
|
||||||
|
println!("Registered '{}'.", name);
|
||||||
|
println!("Run 'p default {}' to make it the default.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,25 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
|
use crate::config;
|
||||||
|
|
||||||
pub fn execute(worker: &str) -> Result<()> {
|
pub fn execute(worker: &str) -> Result<()> {
|
||||||
let _ = worker;
|
let mut cfg = config::load()?;
|
||||||
anyhow::bail!("not yet implemented")
|
|
||||||
|
if cfg.get_worker(worker).is_none() {
|
||||||
|
let known: Vec<&str> = cfg.workers.iter().map(|w| w.name.as_str()).collect();
|
||||||
|
if known.is_empty() {
|
||||||
|
anyhow::bail!("no workers registered yet — run 'p register <connection>' first");
|
||||||
|
}
|
||||||
|
anyhow::bail!(
|
||||||
|
"unknown worker '{}'\n\nKnown workers: {}",
|
||||||
|
worker,
|
||||||
|
known.join(", ")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.default_worker = Some(worker.to_string());
|
||||||
|
config::save(&cfg)?;
|
||||||
|
|
||||||
|
println!("Default worker set to '{}'.", worker);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,37 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
pub fn execute() -> Result<()> {
|
use crate::{config, ssh};
|
||||||
anyhow::bail!("not yet implemented")
|
|
||||||
|
pub fn execute(check: bool) -> Result<()> {
|
||||||
|
let cfg = config::load()?;
|
||||||
|
|
||||||
|
if cfg.workers.is_empty() {
|
||||||
|
println!("No workers registered. Run 'p register <connection>' to add one.");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let name_w = cfg.workers.iter().map(|w| w.name.len()).max().unwrap_or(0).max(4);
|
||||||
|
let conn_w = cfg.workers.iter().map(|w| w.connection.len()).max().unwrap_or(0).max(10);
|
||||||
|
|
||||||
|
if check {
|
||||||
|
println!(" {:<name_w$} {:<conn_w$} STATUS", "NAME", "CONNECTION");
|
||||||
|
println!(" {:<name_w$} {:<conn_w$} ------", "-".repeat(name_w), "-".repeat(conn_w));
|
||||||
|
} else {
|
||||||
|
println!(" {:<name_w$} CONNECTION", "NAME");
|
||||||
|
println!(" {:<name_w$} ----------", "-".repeat(name_w));
|
||||||
|
}
|
||||||
|
|
||||||
|
for worker in &cfg.workers {
|
||||||
|
let is_default = cfg.default_worker.as_deref() == Some(&worker.name);
|
||||||
|
let prefix = if is_default { "* " } else { " " };
|
||||||
|
|
||||||
|
if check {
|
||||||
|
let status = if ssh::is_reachable(worker) { "reachable" } else { "unreachable" };
|
||||||
|
println!("{}{:<name_w$} {:<conn_w$} {}", prefix, worker.name, worker.connection, status);
|
||||||
|
} else {
|
||||||
|
println!("{}{:<name_w$} {}", prefix, worker.name, worker.connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ fn main() -> Result<()> {
|
|||||||
cli::Command::Register { connection, name } => {
|
cli::Command::Register { connection, name } => {
|
||||||
commands::register::execute(&connection, name.as_deref())
|
commands::register::execute(&connection, name.as_deref())
|
||||||
}
|
}
|
||||||
cli::Command::Workers => commands::workers::execute(),
|
cli::Command::Workers { check } => commands::workers::execute(check),
|
||||||
cli::Command::Default { worker } => commands::set_default::execute(&worker),
|
cli::Command::Default { worker } => commands::set_default::execute(&worker),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
18
p/src/ssh.rs
18
p/src/ssh.rs
@@ -32,6 +32,24 @@ pub fn hostname_from_connection(conn: &str) -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check whether a worker is reachable over SSH (5 s timeout, no auth prompts).
|
||||||
|
pub fn is_reachable(worker: &WorkerConfig) -> bool {
|
||||||
|
let mut args = vec![
|
||||||
|
"-o".to_string(), "ConnectTimeout=5".to_string(),
|
||||||
|
"-o".to_string(), "BatchMode=yes".to_string(),
|
||||||
|
];
|
||||||
|
args.extend(ssh_args(worker));
|
||||||
|
args.push("true".to_string());
|
||||||
|
|
||||||
|
std::process::Command::new("ssh")
|
||||||
|
.args(&args)
|
||||||
|
.stdout(std::process::Stdio::null())
|
||||||
|
.stderr(std::process::Stdio::null())
|
||||||
|
.status()
|
||||||
|
.map(|s| s.success())
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
/// Build the base ssh argument list for a worker (handles custom port).
|
/// Build the base ssh argument list for a worker (handles custom port).
|
||||||
pub fn ssh_args(worker: &WorkerConfig) -> Vec<String> {
|
pub fn ssh_args(worker: &WorkerConfig) -> Vec<String> {
|
||||||
let (user_host, port) = parse_connection(&worker.connection);
|
let (user_host, port) = parse_connection(&worker.connection);
|
||||||
|
|||||||
Reference in New Issue
Block a user