# rufish
[](https://crates.io/crates/rufish)
[](https://docs.rs/rufish)
[](https://github.com/dalof41014/rufish/blob/main/LICENSE-MIT)
**`rufish`** is an asynchronous **Redfish client library** written in Rust for BMC/server out-of-band management via the DMTF Redfish REST API.
---
## Features
* ✅ Async HTTP/HTTPS client (based on `reqwest` + `tokio`)
* ✅ Session-based authentication (X-Auth-Token) with fallback to Basic Auth
* ✅ **Builder pattern** — inject custom `reqwest::Client`, existing session tokens, or credentials
* ✅ Session persistence — get/set tokens for cross-restart reuse
* ✅ Self-signed certificate support (common for BMCs)
* ✅ Typed Rust structs for all major Redfish resources
* ✅ High-level API for common operations:
* Systems, Chassis, Managers
* Power & Thermal monitoring
* Processors, Memory, Storage, Drives
* Ethernet Interfaces (System & Manager)
* Chassis Indicator LED (LocationIndicatorActive / IndicatorLED)
* Power control (On/Off/Restart/Cycle)
* Boot override (PXE, BIOS Setup, HDD, etc.)
* Account management
* Log services
* Update & Event services
* ✅ Low-level GET/POST/PATCH/DELETE for any Redfish endpoint
* ✅ Proper error handling with typed errors
---
## 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?;
// Service Root
let root = client.get_service_root().await?;
println!("Redfish version: {:?}", root.redfish_version);
// List systems
let systems = client.list_systems().await?;
println!("Systems: {:?}", systems.members_count);
// Get system details
let sys = client.get_system("1").await?;
println!("Model: {:?}, Power: {:?}", sys.model, sys.power_state);
// Power control
client.power_on("1").await?;
client.graceful_shutdown("1").await?;
// Thermal monitoring
let thermal = client.get_thermal("1").await?;
for t in thermal.temperatures.unwrap_or_default() {
println!("{}: {}°C", t.name.unwrap_or_default(), t.reading_celsius.unwrap_or(0.0));
}
// Boot override
client.set_boot_pxe("1").await?;
client.logout().await?;
Ok(())
}
```
### Builder Pattern
```rust
use rufish::RedfishClient;
// Custom reqwest client (e.g. native-tls, http1_only)
let custom = reqwest::Client::builder()
.use_native_tls()
.http1_only()
.danger_accept_invalid_certs(true)
.build()?;
let client = RedfishClient::builder("10.0.0.5")
.credentials("admin", "password")
.client(custom)
.build()?;
// Or restore a persisted session (no login needed)
let client = RedfishClient::builder("10.0.0.5")
.credentials("admin", "password")
.session("saved-token", "/redfish/v1/SessionService/Sessions/1")
.build()?;
```
---
## API Summary
### Session & Construction
| `new(host, user, pass)` | Create client (HTTPS, accepts self-signed certs) |
| `builder(host)` | Start building a client with custom options |
| `.credentials(user, pass)` | Set credentials (builder) |
| `.client(reqwest_client)` | Inject custom reqwest Client (builder) |
| `.session(token, uri)` | Inject existing session token (builder) |
| `.build()` | Finalize and create the client (builder) |
| `set_session(token, uri)` | Inject session token after construction |
| `session_token()` | Get current token (for persistence) |
| `session_uri()` | Get current session URI |
| `login()` | Establish Redfish session |
| `logout()` | Close session |
### Resources (GET)
| `get_service_root()` | Service Root |
| `list_systems()` / `get_system(id)` | Computer Systems |
| `list_chassis()` / `get_chassis(id)` | Chassis |
| `list_managers()` / `get_manager(id)` | Managers (BMC) |
| `get_power(chassis_id)` | Power readings & supplies |
| `get_thermal(chassis_id)` | Temperatures & fans |
| `list_processors(sys)` / `get_processor(sys, id)` | CPUs |
| `list_memory(sys)` / `get_memory(sys, id)` | DIMMs |
| `list_storage(sys)` / `get_storage(sys, id)` | Storage controllers |
| `list_ethernet_interfaces(sys)` | NICs |
| `list_manager_ethernet_interfaces(mgr)` | BMC network interfaces |
| `get_manager_ethernet_interface(mgr, id)` | Get BMC NIC details |
| `patch_manager_ethernet_interface(mgr, id, body)` | Update BMC NIC settings |
| `get_chassis_indicator(chassis)` | Get Indicator LED state |
| `get_account_service()` / `list_accounts()` | User accounts |
| `get_update_service()` | Firmware update service |
| `get_event_service()` | Event subscriptions |
| `list_log_entries(mgr, log)` | Log entries |
### Actions (POST/PATCH)
| `reset_system(id, type)` | Reset with any ResetType |
| `power_on(id)` | Power on |
| `power_off(id)` | Force power off |
| `graceful_shutdown(id)` | ACPI shutdown |
| `graceful_restart(id)` | Graceful restart |
| `force_restart(id)` | Force restart |
| `power_cycle(id)` | Power cycle |
| `set_boot_override(id, target, enabled)` | Set boot source |
| `set_boot_pxe(id)` | Boot to PXE |
| `set_boot_bios(id)` | Boot to BIOS Setup |
| `set_chassis_indicator(chassis, on)` | Set Indicator LED on/off |
| `reset_manager(id, type)` | Reset BMC |
| `clear_log(mgr, log)` | Clear log service |
### Virtual Media
| `list_virtual_media(mgr)` | List virtual media devices |
| `get_virtual_media(mgr, id)` | Get virtual media status |
| `insert_media(mgr, id, url)` | Mount ISO/IMG from URL |
| `eject_media(mgr, id)` | Unmount media |
### BIOS & Secure Boot
| `get_bios(sys)` | Get current BIOS attributes |
| `get_bios_settings(sys)` | Get pending BIOS settings |
| `set_bios_attributes(sys, attrs)` | Set BIOS attributes (next boot) |
| `get_secure_boot(sys)` | Get Secure Boot status |
| `set_secure_boot(sys, enabled)` | Enable/disable Secure Boot |
### Storage / RAID
| `list_volumes(sys, storage)` | List RAID volumes |
| `get_volume(sys, storage, vol)` | Get volume details |
| `create_volume(sys, storage, body)` | Create RAID volume |
| `delete_volume(sys, storage, vol)` | Delete volume |
| `get_drive(path)` | Get drive details |
### Network & Certificates
| `get_network_protocol(mgr)` | BMC network services (NTP, SSH, etc.) |
| `set_network_protocol(mgr, settings)` | Update network settings |
| `list_serial_interfaces(mgr)` | List serial interfaces |
| `list_certificates(mgr)` | List HTTPS certificates |
| `replace_certificate(path, pem, type)` | Replace certificate |
### Event Subscriptions
| `list_subscriptions()` | List event subscriptions |
| `create_subscription(dest, types, ctx)` | Create subscription |
| `delete_subscription(id)` | Delete subscription |
### Firmware Update
| `list_firmware_inventory()` | List firmware items |
| `get_firmware_item(id)` | Get firmware version info |
| `simple_update(image_uri)` | Trigger firmware update from URI |
### Tasks & Pagination
| `list_tasks()` | List async tasks |
| `get_task(id)` | Get task status |
| `wait_task(id, timeout_secs)` | Poll until task completes |
| `get_all_members(path)` | Auto-follow @odata.nextLink |
### Raw Access
| `get(path)` | GET any endpoint (returns `serde_json::Value`) |
| `post(path, body)` | POST action |
| `patch(path, body)` | PATCH resource |
| `delete(path)` | DELETE resource |
---
## Dependencies
```toml
[dependencies]
reqwest = { version = "0.12", features = ["json", "rustls-tls"], default-features = false }
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
thiserror = "1"
log = "0.4"
```
---
## License
MIT OR Apache-2.0