# lmrc-ssh

> Part of the [LMRC Stack](https://gitlab.com/lemarco/lmrc-stack) - Infrastructure-as-Code toolkit for building production-ready Rust applications

[![Crates.io](https://img.shields.io/crates/v/lmrc-ssh.svg)](https://crates.io/crates/lmrc-ssh)
[![Documentation](https://docs.rs/lmrc-ssh/badge.svg)](https://docs.rs/lmrc-ssh)
[![License](https://img.shields.io/crates/l/lmrc-ssh.svg)](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.
