rufish 0.4.1

An asynchronous Redfish client library for BMC/server management in Rust.
Documentation
# rufish

[![Crates.io](https://img.shields.io/crates/v/rufish.svg)](https://crates.io/crates/rufish)
[![Docs.rs](https://docs.rs/rufish/badge.svg)](https://docs.rs/rufish)
[![CI](https://github.com/dalof41014/rufish/actions/workflows/ci.yml/badge.svg)](https://github.com/dalof41014/rufish/actions)
[![License](https://img.shields.io/crates/l/rufish.svg)](https://github.com/dalof41014/rufish/blob/main/LICENSE-MIT)

An asynchronous Redfish client library for BMC/server out-of-band management in Rust.

```toml
[dependencies]
rufish = "0.4"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
```

---

## Quick Start

```rust
use rufish::RedfishClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut client = RedfishClient::new("10.0.0.5", "admin", "password")?;
    client.login().await?;

    let sys = client.get_system("1").await?;
    println!("{:?} — {:?}", sys.model, sys.power_state);

    client.graceful_shutdown("1").await?;
    client.logout().await?;
    Ok(())
}
```

---

## Features

| Category | Capabilities |
|----------|-------------|
| **Core** | Async HTTP/HTTPS, session auth (X-Auth-Token) + Basic Auth fallback, self-signed cert support, builder pattern |
| **Resources** | Systems, Chassis, Managers, Processors, Memory, Storage, Drives, NICs, Virtual Media, Certificates |
| **Actions** | Power control, boot override, BIOS settings, Secure Boot, RAID management, firmware update, log management |
| **UI-Friendly** | Registry metadata parsing, system health summary, storage overview, enriched logs, hardware topology |
| **Fleet Management** | Multi-host pool with concurrency control, BIOS config export/import/diff |
| **Reliability** | Auto-retry with exponential backoff, session auto-renewal on 401 |
| **Real-time** | SSE event streaming, event subscriptions |

---

## Usage Examples

### System Health Dashboard

```rust
// One call → aggregated health from System + Thermal + Power
let health = client.get_system_health("1", "1").await?;
println!("Overall: {:?}", health.overall);       // OK / Warning / Critical
println!("CPU: {:?}", health.processors);
for t in &health.temperatures {
    println!("  {} = {:?}°C ({:?})", t.name, t.reading, t.status);
}
```

### BIOS Configuration (UI-Friendly)

```rust
// Get BIOS attributes with full metadata for rendering forms
let attrs = client.get_bios_attributes_full("1").await?;
for attr in &attrs {
    println!("[{}] {} = {:?}", attr.group.as_deref().unwrap_or("General"),
             attr.display_name, attr.current_value);
    if let Some(allowed) = &attr.allowed_values {
        println!("  Options: {:?}", allowed.iter().map(|v| &v.value).collect::<Vec<_>>());
    }
}

// Set BIOS attributes (applied on next boot)
client.set_bios_attributes("1", &serde_json::json!({
    "BootMode": "Uefi",
    "HyperThreading": "Enabled"
})).await?;
```

### BIOS Config Export/Import (Fleet Deployment)

```rust
use rufish::BiosConfig;

// Export from golden image server
let config = client.export_bios_config("1").await?;
let json = config.to_json()?;
std::fs::write("bios_golden.json", &json)?;

// Import to other servers
let config = BiosConfig::from_json(&std::fs::read_to_string("bios_golden.json")?)?;
let diff = client.diff_bios_config("1", &config).await?;
println!("Changes needed: {}", diff.changed.len());
client.import_bios_config("1", &config).await?;
```

### Storage Overview

```rust
let storage = client.get_storage_overview("1").await?;
for vol in &storage.volumes {
    println!("Volume {} — {} {:?} ({} drives)",
             vol.name, vol.raid_type.as_deref().unwrap_or("?"),
             vol.status, vol.drive_count);
}
println!("Unassigned drives: {}", storage.unassigned_drives.len());
```

### Enriched Logs (Auto-Translated)

```rust
let logs = client.get_enriched_logs("1", "Sel").await?;
for entry in &logs {
    println!("[{}] {} — {}",
             entry.severity.as_deref().unwrap_or("?"),
             entry.message,
             entry.resolution.as_deref().unwrap_or(""));
}
```

### Real-Time Events (SSE)

```rust
use tokio_stream::StreamExt;

let mut stream = client.subscribe_sse().await?;
while let Some(Ok(event)) = stream.next().await {
    println!("Event: {:?}", event.body);
}
```

### Multi-Host Fleet Management

```rust
use rufish::RedfishPool;

let mut pool = RedfishPool::new(10); // max 10 concurrent connections
pool.add("bmc-01", "admin", "pass")?;
pool.add("bmc-02", "admin", "pass")?;
pool.add("bmc-03", "admin", "pass")?;
pool.login_all().await;

// Power on all servers
let results = pool.for_each(|c| async move { c.power_on("1").await }).await;
for r in &results {
    println!("{}: {:?}", r.host, r.result.is_ok());
}
```

### Firmware Update with Progress

```rust
client.update_firmware_with_progress(
    "http://fileserver/bmc_fw.bin",
    600, // timeout seconds
    |state, percent| {
        println!("State: {} — {:?}%", state, percent);
    },
).await?;
```

### Hardware Topology

```rust
let topo = client.get_topology("1").await?;
println!("System: {:?} ({:?})", topo.system.model, topo.system.power_state);
for cpu in &topo.system.processors {
    println!("  CPU: {:?} — {:?}", cpu.name, cpu.status);
}
for dimm in &topo.system.memory {
    println!("  MEM: {:?} — {:?}", dimm.name, dimm.description);
}
```

### Auto-Retry (Session Renewal + Backoff)

```rust
// Automatically re-login on 401, exponential backoff on network errors
let val = client.get_with_retry("/redfish/v1/Systems/1", 3).await?;
```

### User Account Management

```rust
let users = client.list_users().await?;
for u in &users {
    println!("{} (role={:?}, enabled={})", u.username, u.role, u.enabled);
}

client.create_user("operator", "SecureP@ss1", "Operator").await?;
client.change_password("3", "NewP@ss2").await?;
client.set_user_role("3", "Administrator").await?;
```

### Builder Pattern (Advanced)

```rust
let custom = reqwest::Client::builder()
    .danger_accept_invalid_certs(true)
    .timeout(std::time::Duration::from_secs(60))
    .build()?;

let client = RedfishClient::builder("10.0.0.5")
    .credentials("admin", "password")
    .client(custom)
    .session("saved-token", "/redfish/v1/Sessions/1") // restore session
    .build()?;
```

---

## Full API Reference

See [docs.rs/rufish](https://docs.rs/rufish) for complete API documentation.

### Module Overview

| Module | Purpose |
|--------|---------|
| `rufish` (root) | `RedfishClient` + all typed resource structs |
| `rufish::registry` | BIOS/attribute/message registry parsing |
| `rufish::enriched` | Health summary, storage overview, enriched logs |
| `rufish::bios_config` | BIOS config export/import/diff |
| `rufish::topology` | Hardware topology types |
| `rufish::multi` | `RedfishPool` for fleet management |
| `rufish::sse` | SSE event stream types |

---

## Supported Operations

<details>
<summary>Click to expand full method list</summary>

**Session**: `new`, `builder`, `login`, `logout`, `set_session`, `session_token`, `session_uri`

**Systems**: `list_systems`, `get_system`, `list_processors`, `get_processor`, `list_memory`, `get_memory`, `list_storage`, `get_storage`, `list_ethernet_interfaces`, `get_ethernet_interface`

**Chassis**: `list_chassis`, `get_chassis`, `get_power`, `get_thermal`, `get_chassis_indicator`, `set_chassis_indicator`

**Managers**: `list_managers`, `get_manager`, `get_network_protocol`, `set_network_protocol`, `list_manager_ethernet_interfaces`, `get_manager_ethernet_interface`, `patch_manager_ethernet_interface`, `list_serial_interfaces`, `get_serial_interface`, `list_virtual_media`, `get_virtual_media`, `insert_media`, `eject_media`

**Power**: `reset_system`, `power_on`, `power_off`, `graceful_shutdown`, `graceful_restart`, `force_restart`, `power_cycle`, `reset_manager`

**Boot**: `set_boot_override`, `set_boot_pxe`, `set_boot_bios`

**BIOS**: `get_bios`, `get_bios_settings`, `set_bios_attributes`, `reset_bios_defaults`, `get_bios_attributes_full`, `get_secure_boot`, `set_secure_boot`

**Storage**: `list_volumes`, `get_volume`, `create_volume`, `delete_volume`, `get_drive`

**Accounts**: `get_account_service`, `list_accounts`, `list_users`, `create_user`, `change_password`, `set_user_role`, `set_user_enabled`, `unlock_user`, `delete_user`

**Logs**: `list_log_entries`, `clear_log`, `get_enriched_logs`

**Events**: `get_event_service`, `list_subscriptions`, `create_subscription`, `delete_subscription`, `subscribe`, `subscribe_sse`

**Firmware**: `get_update_service`, `list_firmware_inventory`, `get_firmware_item`, `simple_update`, `update_firmware_with_progress`

**Certificates**: `list_certificates`, `get_certificate`, `replace_certificate`

**Tasks**: `list_tasks`, `get_task`, `wait_task`

**Registry**: `list_registries`, `get_registry`, `get_message_registry`, `get_attributes_full`

**Enriched**: `get_system_health`, `get_storage_overview`, `get_topology`, `export_bios_config`, `import_bios_config`, `diff_bios_config`

**Fleet**: `RedfishPool::new`, `add`, `add_client`, `remove`, `hosts`, `get`, `get_mut`, `login_all`, `logout_all`, `for_each`

**Retry**: `get_with_retry`, `patch_with_retry`, `post_with_retry`

**Raw**: `get`, `get_as`, `post`, `patch`, `delete`, `get_all_members`

</details>

---

## License

MIT OR Apache-2.0