# lmrc-ssh
> Part of the [LMRC Stack](https://gitlab.com/lemarco/lmrc-stack) - Infrastructure-as-Code toolkit for building production-ready Rust applications
[](https://crates.io/crates/lmrc-ssh)
[](https://docs.rs/lmrc-ssh)
[](https://gitlab.com/lemarco/lmrc-stack#license)
A comprehensive Rust library for executing SSH commands programmatically. Built on top of the robust `ssh2` library, `lmrc-ssh` provides a clean, intuitive API for managing SSH connections and executing remote commands.
## Features
- 🔐 **Flexible Authentication** - Support for password and public key authentication
- 🚀 **Simple API** - Intuitive builder pattern for easy connection setup
- 📦 **Batch Execution** - Execute multiple commands in sequence
- 🛡️ **Comprehensive Error Handling** - Detailed error types with helpful messages
- 📚 **Well Documented** - Extensive documentation with examples
- ✅ **Well Tested** - Thorough test coverage
## Installation
Add this to your `Cargo.toml`:
```toml
[dependencies]
lmrc-ssh = "0.1"
```
## Quick Start
### Password Authentication
```rust
use lmrc_ssh::{SshClient, AuthMethod};
fn main() -> Result<(), lmrc_ssh::Error> {
let mut client = SshClient::new("example.com", 22)?
.with_auth(AuthMethod::Password {
username: "user".to_string(),
password: "password".to_string(),
})
.connect()?;
let output = client.execute("hostname")?;
println!("Hostname: {}", output.stdout);
Ok(())
}
```
### Public Key Authentication
```rust
use lmrc_ssh::{SshClient, AuthMethod};
fn main() -> Result<(), lmrc_ssh::Error> {
let mut client = SshClient::new("example.com", 22)?
.with_auth(AuthMethod::PublicKey {
username: "user".to_string(),
private_key_path: "/home/user/.ssh/id_rsa".to_string(),
passphrase: None,
})
.connect()?;
let output = client.execute("ls -la")?;
println!("Output:\n{}", output.stdout);
Ok(())
}
```
## Usage Examples
### Executing Multiple Commands
```rust
use lmrc_ssh::{SshClient, AuthMethod};
fn main() -> Result<(), lmrc_ssh::Error> {
let mut client = SshClient::new("192.168.1.100", 22)?
.with_auth(AuthMethod::Password {
username: "admin".to_string(),
password: "secret".to_string(),
})
.connect()?;
let commands = vec!["whoami", "hostname", "pwd"];
let outputs = client.execute_batch(&commands)?;
for (cmd, output) in commands.iter().zip(outputs.iter()) {
println!("Command: {}", cmd);
println!("Output: {}", output.stdout);
println!("---");
}
Ok(())
}
```
### Handling Command Output
```rust
use lmrc_ssh::{SshClient, AuthMethod};
fn main() -> Result<(), lmrc_ssh::Error> {
let mut client = SshClient::new("example.com", 22)?
.with_auth(AuthMethod::Password {
username: "user".to_string(),
password: "pass".to_string(),
})
.connect()?;
let output = client.execute("some-command")?;
if output.is_success() {
println!("Success! Output: {}", output.stdout);
} else {
eprintln!("Command failed with exit code: {}", output.exit_status);
eprintln!("Error: {}", output.stderr);
}
Ok(())
}
```
### Error Handling
```rust
use lmrc_ssh::{SshClient, AuthMethod, Error};
fn main() {
let result = SshClient::new("example.com", 22)
.and_then(|client| {
client.with_auth(AuthMethod::Password {
username: "user".to_string(),
password: "wrong_password".to_string(),
})
.connect()
});
match result {
Ok(_) => println!("Connected successfully"),
Err(Error::AuthenticationFailed { username, reason }) => {
eprintln!("Authentication failed for {}: {}", username, reason);
}
Err(Error::ConnectionFailed { host, port, .. }) => {
eprintln!("Failed to connect to {}:{}", host, port);
}
Err(e) => eprintln!("Error: {}", e),
}
}
```
## API Overview
### `SshClient`
The main client for SSH connections.
- `new(host, port)` - Create a new client instance
- `with_auth(auth_method)` - Set the authentication method
- `connect()` - Establish the SSH connection
- `execute(command)` - Execute a single command
- `execute_batch(commands)` - Execute multiple commands
- `is_connected()` - Check if the client is connected
### `AuthMethod`
Authentication methods for SSH:
- `Password { username, password }` - Password authentication
- `PublicKey { username, private_key_path, passphrase }` - Public key authentication
### `CommandOutput`
Represents the output of an executed command:
- `stdout` - Standard output
- `stderr` - Standard error
- `exit_status` - Exit status code
- `is_success()` - Check if the command succeeded
- `is_failure()` - Check if the command failed
- `combined_output()` - Get stdout + stderr combined
### Error Types
Comprehensive error types for better error handling:
- `ConnectionFailed` - Failed to establish TCP connection
- `AuthenticationFailed` - Authentication failed
- `ExecutionFailed` - Command execution failed
- `NotConnected` - Client is not connected
- `InvalidConfig` - Invalid configuration
- And more...
## Examples
Check out the [examples](examples/) directory for more usage examples:
- `simple_connection.rs` - Basic SSH connection and command execution
- `batch_commands.rs` - Execute multiple commands
- `error_handling.rs` - Comprehensive error handling examples
Run an example with:
```bash
cargo run --example simple_connection
```
## Testing
Run the test suite:
```bash
cargo test
```
Run tests with output:
```bash
cargo test -- --nocapture
```
## Building Documentation
Generate and view the documentation:
```bash
cargo doc --open
```
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
## License
Part of the LMRC Stack project. Licensed under either of:
- Apache License, Version 2.0 ([LICENSE-APACHE](../../LICENSE-APACHE) or <http://www.apache.org/licenses/LICENSE-2.0>)
- MIT license ([LICENSE-MIT](../../LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
at your option.
## Acknowledgments
This library is built on top of the excellent [ssh2](https://github.com/alexcrichton/ssh2-rs) crate.
## Security
If you discover a security vulnerability, please email lemarc.dev@gmail.com.
## Changelog
See [CHANGELOG.md](CHANGELOG.md) for release history.