Skip to content

Commit 1690950

Browse files
committed
update: help documents (#19)
1 parent 84129c2 commit 1690950

1 file changed

Lines changed: 49 additions & 18 deletions

File tree

src/cli.rs

Lines changed: 49 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ use std::path::PathBuf;
2121
version,
2222
before_help = "",
2323
about = "Backend.AI SSH - Parallel command execution across cluster nodes",
24-
after_help = "Developed and maintained as part of the Backend.AI project.",
25-
long_about = None
24+
long_about = "bssh is a high-performance parallel SSH command execution tool for cluster management, built with Rust.\nIt enables efficient execution of commands across multiple nodes simultaneously with real-time output streaming.\nThe tool provides secure file transfer capabilities using SFTP protocol and supports multiple authentication\nmethods including SSH keys (with passphrase support), SSH agent, and password authentication.\nIt automatically detects Backend.AI multi-node session environments.",
25+
after_help = "EXAMPLES:\n Execute command on hosts: bssh -H \"user@host1,host2\" \"uptime\"\n Use cluster configuration: bssh -c production \"df -h\"\n Upload files with glob: bssh -c staging upload \"*.log\" /tmp/\n Download from all nodes: bssh -c web download /var/log/app.log ./logs/\n Interactive mode (multiplex): bssh -c production interactive\n Test connectivity: bssh -c staging ping\n\nDeveloped and maintained as part of the Backend.AI project.\nFor more examples and documentation, visit: https://github.com/lablup/bssh"
2626
)]
2727
pub struct Cli {
2828
#[command(subcommand)]
@@ -32,7 +32,7 @@ pub struct Cli {
3232
short = 'H',
3333
long,
3434
value_delimiter = ',',
35-
help = "Comma-separated list of hosts (user@host:port format)"
35+
help = "Comma-separated list of hosts in [user@]hostname[:port] format\nExamples: 'host1,host2' or 'user1@host1:2222,user2@host2'\nDefault user and port from config or current environment will be used if not specified"
3636
)]
3737
pub hosts: Option<Vec<String>>,
3838

@@ -42,7 +42,7 @@ pub struct Cli {
4242
#[arg(
4343
long,
4444
default_value = "~/.config/bssh/config.yaml",
45-
help = "Configuration file path"
45+
help = "Configuration file path [default: ~/.config/bssh/config.yaml]\nConfig loading priority:\n 1. Backend.AI env vars (auto-detected)\n 2. Current directory (./config.yaml)\n 3. User config (~/.config/bssh/config.yaml)\n 4. This flag's value"
4646
)]
4747
pub config: PathBuf,
4848

@@ -52,14 +52,14 @@ pub struct Cli {
5252
#[arg(
5353
short = 'i',
5454
long,
55-
help = "SSH private key file path (prompts for passphrase if encrypted)"
55+
help = "SSH private key file path (prompts for passphrase if encrypted)\nAutomatically detects encrypted keys and prompts for passphrase\nFalls back to default keys (~/.ssh/id_ed25519, ~/.ssh/id_rsa, etc.) if not specified"
5656
)]
5757
pub identity: Option<PathBuf>,
5858

5959
#[arg(
6060
short = 'A',
6161
long,
62-
help = "Use SSH agent for authentication (Unix/Linux/macOS only)"
62+
help = "Use SSH agent for authentication (Unix/Linux/macOS only)\nAuto-detected when SSH_AUTH_SOCK is set. Falls back to key file if agent auth fails"
6363
)]
6464
pub use_agent: bool,
6565

@@ -78,7 +78,10 @@ pub struct Cli {
7878
)]
7979
pub parallel: usize,
8080

81-
#[arg(long, help = "Output directory for command results")]
81+
#[arg(
82+
long,
83+
help = "Output directory for per-node command results\nCreates timestamped files:\n - hostname_TIMESTAMP.stdout (command output)\n - hostname_TIMESTAMP.stderr (error output)\n - hostname_TIMESTAMP.error (connection failures)\n - summary_TIMESTAMP.txt (execution summary)"
84+
)]
8285
pub output_dir: Option<PathBuf>,
8386

8487
#[arg(
@@ -92,7 +95,7 @@ pub struct Cli {
9295
#[arg(
9396
long,
9497
default_value = "accept-new",
95-
help = "Host key checking mode (yes/no/accept-new)"
98+
help = "Host key checking mode (yes/no/accept-new) [default: accept-new]\n yes - Strict checking against known_hosts (most secure)\n no - Accept all host keys (insecure, testing only)\n accept-new - Accept new hosts, reject changed keys (recommended)"
9699
)]
97100
pub strict_host_key_checking: String,
98101

@@ -109,44 +112,72 @@ pub struct Cli {
109112

110113
#[derive(Subcommand, Debug)]
111114
pub enum Commands {
112-
#[command(about = "Execute a command on specified hosts")]
115+
#[command(
116+
about = "Execute a command on specified hosts",
117+
long_about = "Executes the specified command on all target hosts simultaneously.\nOutput is streamed in real-time with host prefixes for identification.\nSupports command timeout, output redirection, and partial failure handling.\n\nExit codes: 0 (all succeed), 1 (any failures)",
118+
after_help = "Examples:\n bssh exec \"uptime\" # Execute on auto-detected or default hosts\n bssh -c prod exec \"systemctl status\" # Execute on cluster 'prod'\n bssh -p 20 exec \"apt update\" # Increase parallelism to 20\n bssh --output-dir logs exec \"df -h\" # Save outputs to files"
119+
)]
113120
Exec {
114121
#[arg(trailing_var_arg = true)]
115122
command: Vec<String>,
116123
},
117124

118-
#[command(about = "List available clusters")]
125+
#[command(
126+
about = "List available clusters",
127+
long_about = "Displays all clusters defined in configuration files.\nShows cluster names, node counts, and configuration sources.\nIncludes auto-detected Backend.AI clusters if present.\n\nConfiguration sources checked (in order):\n - Backend.AI environment variables\n - Current directory (./config.yaml)\n - User config (~/.config/bssh/config.yaml)"
128+
)]
119129
List,
120130

121-
#[command(about = "Test connectivity to hosts")]
131+
#[command(
132+
about = "Test connectivity to hosts",
133+
long_about = "Verifies SSH connectivity and authentication to all target hosts.\nReports connection status, authentication success, and response times.\nUseful for validating cluster configuration and SSH key setup.\n\nExit codes: 0 (all reachable), 1 (any unreachable)"
134+
)]
122135
Ping,
123136

124-
#[command(about = "Upload files to remote hosts")]
137+
#[command(
138+
about = "Upload files to remote hosts",
139+
long_about = "Uploads local file(s) to all specified remote hosts in parallel using SFTP.\nSupports glob patterns for batch uploads (e.g., *.txt, logs/*.log).\nWhen uploading multiple files, destination should be a directory (end with /).\nUses secure SFTP protocol with progress indicators for each transfer.\n\nRequirements: Remote SSH servers must have SFTP subsystem enabled.",
140+
after_help = "Examples:\n bssh upload config.yaml /etc/app/ # Single file to directory\n bssh upload app.tar.gz /tmp/app.tar.gz # Single file with rename\n bssh upload \"*.log\" /var/logs/ # Multiple files with glob\n bssh upload -r ./configs/ /etc/app/ # Recursive directory upload"
141+
)]
125142
Upload {
126-
#[arg(help = "Local file path")]
143+
#[arg(
144+
help = "Local file path or glob pattern (e.g., *.txt, logs/*.log)\nUse quotes around patterns to prevent shell expansion"
145+
)]
127146
source: PathBuf,
128147

129-
#[arg(help = "Remote destination path")]
148+
#[arg(
149+
help = "Remote destination path\nUse trailing slash (/) for directory when uploading multiple files\nPath will be created if it doesn't exist (requires appropriate permissions)"
150+
)]
130151
destination: String,
131152

132153
#[arg(short = 'r', long, help = "Recursively upload directories")]
133154
recursive: bool,
134155
},
135156

136-
#[command(about = "Download files from remote hosts")]
157+
#[command(
158+
about = "Download files from remote hosts",
159+
long_about = "Downloads remote file(s) from all specified hosts to local destination using SFTP.\nEach file is prefixed with hostname to avoid conflicts (e.g., host1_file.txt).\nSupports glob patterns for batch downloads (e.g., /var/log/*.log).\nUses secure SFTP protocol with progress indicators and parallel transfers.\n\nNote: Creates destination directory if it doesn't exist.",
160+
after_help = "Examples:\n bssh download /etc/passwd ./configs/ # Single file from all hosts\n bssh download \"/var/log/*.log\" ./logs/ # Multiple logs with glob\n bssh download -r /etc/nginx/ ./backups/ # Recursive directory download\n\nFiles saved as: hostname_filename (e.g., web1_passwd, web2_passwd)"
161+
)]
137162
Download {
138-
#[arg(help = "Remote file path")]
163+
#[arg(
164+
help = "Remote file path or glob pattern (e.g., /var/log/*.log)\nSupports wildcards for batch downloads"
165+
)]
139166
source: String,
140167

141-
#[arg(help = "Local destination directory")]
168+
#[arg(
169+
help = "Local destination directory\nFiles will be prefixed with hostname (e.g., host1_filename)"
170+
)]
142171
destination: PathBuf,
143172

144173
#[arg(short = 'r', long, help = "Recursively download directories")]
145174
recursive: bool,
146175
},
147176

148177
#[command(
149-
about = "Start interactive shell session\n\nInteractive mode settings can be configured globally or per-cluster in the configuration file.\nCLI arguments override configuration file settings."
178+
about = "Start interactive shell session",
179+
long_about = "Opens an interactive shell session with one or more remote hosts.\nSupports both single-node and multiplex modes for efficient cluster management.\nIn multiplex mode, commands are sent to all active nodes simultaneously.\n\nSpecial commands (default prefix '!'):\n !all - Activate all connected nodes\n !broadcast <cmd> - Execute on all nodes temporarily\n !node<N> - Switch to specific node (e.g., !node1)\n !list - List all nodes and connection status\n !status - Show currently active nodes\n !help - Show special commands help\n exit - Exit interactive mode\n\nSettings can be configured globally or per-cluster in config file.\nCLI arguments override configuration file settings.",
180+
after_help = "Examples:\n bssh interactive # Auto-detect or use defaults\n bssh -c prod interactive # Use production cluster\n bssh interactive --single-node # Connect to one node only\n bssh interactive --prompt-format '{user}>' # Custom prompt\n bssh interactive --work-dir /var/www # Set initial directory"
150181
)]
151182
Interactive {
152183
#[arg(

0 commit comments

Comments
 (0)