use std::{collections::HashMap, fmt, path::Path, time::Duration};
pub mod model;
use model::account_service::ManagerAccount;
pub use model::chassis::{Assembly, Chassis, NetworkAdapter};
pub use model::ethernet_interface::EthernetInterface;
pub use model::network_device_function::NetworkDeviceFunction;
use model::oem::nvidia_dpu::{HostPrivilegeLevel, InternalCPUModel, NicMode};
pub use model::port::NetworkPort;
pub use model::resource::{Collection, OData, Resource};
use model::sensor::GPUSensors;
use model::service_root::{RedfishVendor, ServiceRoot};
use model::software_inventory::SoftwareInventory;
pub use model::system::{BootOptions, PCIeDevice, PowerState, SystemPowerControl, Systems};
use model::task::Task;
use model::update_service::{ComponentType, TransferProtocolType, UpdateService};
pub use model::EnabledDisabled;
use model::Manager;
use model::{secure_boot::SecureBoot, BootOption, ComputerSystem, ODataId};
use serde::{Deserialize, Serialize};
mod ami;
mod dell;
mod error;
mod hpe;
pub mod jsonmap;
mod lenovo;
mod liteon_powershelf;
mod network;
mod nvidia_dpu;
mod nvidia_gbswitch;
mod nvidia_gbx00;
mod nvidia_gh200;
mod nvidia_viking;
mod supermicro;
pub use network::{Endpoint, RedfishClientPool, RedfishClientPoolBuilder, REDFISH_ENDPOINT};
pub mod standard;
pub use error::RedfishError;
pub use reqwest;
use crate::model::certificate::Certificate;
use crate::model::component_integrity::ComponentIntegrities;
use crate::model::power::Power;
use crate::model::sel::LogEntry;
use crate::model::storage::Drives;
use crate::model::thermal::Thermal;
#[async_trait::async_trait]
pub trait Redfish: Send + Sync + 'static {
async fn change_username(&self, old_name: &str, new_name: &str) -> Result<(), RedfishError>;
async fn change_password(&self, username: &str, new_pass: &str) -> Result<(), RedfishError>;
async fn change_password_by_id(
&self,
account_id: &str,
new_pass: &str,
) -> Result<(), RedfishError>;
async fn get_accounts(&self) -> Result<Vec<ManagerAccount>, RedfishError>;
async fn create_user(
&self,
username: &str,
password: &str,
role_id: RoleId,
) -> Result<(), RedfishError>;
async fn delete_user(&self, username: &str) -> Result<(), RedfishError>;
async fn get_firmware(&self, id: &str) -> Result<SoftwareInventory, RedfishError>;
async fn get_software_inventories(&self) -> Result<Vec<String>, RedfishError>;
async fn get_tasks(&self) -> Result<Vec<String>, RedfishError>;
async fn get_task(&self, id: &str) -> Result<Task, RedfishError>;
async fn get_power_state(&self) -> Result<PowerState, RedfishError>;
async fn get_service_root(&self) -> Result<ServiceRoot, RedfishError>;
async fn get_systems(&self) -> Result<Vec<String>, RedfishError>;
async fn get_system(&self) -> Result<ComputerSystem, RedfishError>;
async fn get_managers(&self) -> Result<Vec<String>, RedfishError>;
async fn get_manager(&self) -> Result<Manager, RedfishError>;
async fn get_secure_boot(&self) -> Result<SecureBoot, RedfishError>;
async fn disable_secure_boot(&self) -> Result<(), RedfishError>;
async fn enable_secure_boot(&self) -> Result<(), RedfishError>;
async fn get_secure_boot_certificate(
&self,
database_id: &str,
certificate_id: &str,
) -> Result<Certificate, RedfishError>;
async fn get_secure_boot_certificates(
&self,
database_id: &str,
) -> Result<Vec<String>, RedfishError>;
async fn add_secure_boot_certificate(
&self,
pem_cert: &str,
database_id: &str,
) -> Result<Task, RedfishError>;
async fn get_power_metrics(&self) -> Result<Power, RedfishError>;
async fn power(&self, action: SystemPowerControl) -> Result<(), RedfishError>;
async fn bmc_reset(&self) -> Result<(), RedfishError>;
async fn chassis_reset(
&self,
chassis_id: &str,
reset_type: SystemPowerControl,
) -> Result<(), RedfishError>;
async fn bmc_reset_to_defaults(&self) -> Result<(), RedfishError>;
async fn get_thermal_metrics(&self) -> Result<Thermal, RedfishError>;
async fn get_gpu_sensors(&self) -> Result<Vec<GPUSensors>, RedfishError>;
async fn get_system_event_log(&self) -> Result<Vec<LogEntry>, RedfishError>;
async fn get_bmc_event_log(
&self,
from: Option<chrono::DateTime<chrono::Utc>>,
) -> Result<Vec<LogEntry>, RedfishError>;
async fn get_drives_metrics(&self) -> Result<Vec<Drives>, RedfishError>;
async fn machine_setup(
&self,
boot_interface_mac: Option<&str>,
bios_profiles: &BiosProfileVendor,
selected_profile: BiosProfileType,
) -> Result<(), RedfishError>;
async fn machine_setup_status(
&self,
boot_interface_mac: Option<&str>,
) -> Result<MachineSetupStatus, RedfishError>;
async fn is_bios_setup(&self, boot_interface_mac: Option<&str>) -> Result<bool, RedfishError>;
async fn set_machine_password_policy(&self) -> Result<(), RedfishError>;
async fn lockdown(&self, target: EnabledDisabled) -> Result<(), RedfishError>;
async fn lockdown_status(&self) -> Result<Status, RedfishError>;
async fn setup_serial_console(&self) -> Result<(), RedfishError>;
async fn serial_console_status(&self) -> Result<Status, RedfishError>;
async fn get_boot_options(&self) -> Result<BootOptions, RedfishError>;
async fn get_boot_option(&self, option_id: &str) -> Result<BootOption, RedfishError>;
async fn boot_once(&self, target: Boot) -> Result<(), RedfishError>;
async fn boot_first(&self, target: Boot) -> Result<(), RedfishError>;
async fn change_boot_order(&self, boot_array: Vec<String>) -> Result<(), RedfishError>;
async fn clear_tpm(&self) -> Result<(), RedfishError>;
async fn pcie_devices(&self) -> Result<Vec<PCIeDevice>, RedfishError>;
async fn update_firmware(&self, filename: tokio::fs::File) -> Result<Task, RedfishError>;
async fn update_firmware_multipart(
&self,
firmware: &Path,
reboot: bool,
timeout: Duration,
component_type: ComponentType,
) -> Result<String, RedfishError>;
async fn update_firmware_simple_update(
&self,
image_uri: &str,
targets: Vec<String>,
transfer_protocol: TransferProtocolType,
) -> Result<Task, RedfishError>;
async fn bios(&self) -> Result<HashMap<String, serde_json::Value>, RedfishError>;
async fn set_bios(
&self,
values: HashMap<String, serde_json::Value>,
) -> Result<(), RedfishError>;
async fn reset_bios(&self) -> Result<(), RedfishError>;
async fn pending(&self) -> Result<HashMap<String, serde_json::Value>, RedfishError>;
async fn clear_pending(&self) -> Result<(), RedfishError>;
async fn get_network_device_functions(
&self,
chassis_id: &str,
) -> Result<Vec<String>, RedfishError>;
async fn get_network_device_function(
&self,
chassis_id: &str,
id: &str,
port: Option<&str>,
) -> Result<NetworkDeviceFunction, RedfishError>;
async fn get_chassis_all(&self) -> Result<Vec<String>, RedfishError>;
async fn get_chassis(&self, id: &str) -> Result<Chassis, RedfishError>;
async fn get_chassis_assembly(&self, chassis_id: &str) -> Result<Assembly, RedfishError>;
async fn get_chassis_network_adapters(
&self,
chassis_id: &str,
) -> Result<Vec<String>, RedfishError>;
async fn get_chassis_network_adapter(
&self,
chassis_id: &str,
id: &str,
) -> Result<NetworkAdapter, RedfishError>;
async fn get_base_network_adapters(&self, system_id: &str)
-> Result<Vec<String>, RedfishError>;
async fn get_base_network_adapter(
&self,
system_id: &str,
id: &str,
) -> Result<NetworkAdapter, RedfishError>;
async fn get_ports(
&self,
chassis_id: &str,
network_adapter: &str,
) -> Result<Vec<String>, RedfishError>;
async fn get_port(
&self,
chassis_id: &str,
network_adapter: &str,
id: &str,
) -> Result<NetworkPort, RedfishError>;
async fn get_manager_ethernet_interfaces(&self) -> Result<Vec<String>, RedfishError>;
async fn get_manager_ethernet_interface(
&self,
id: &str,
) -> Result<EthernetInterface, RedfishError>;
async fn get_system_ethernet_interfaces(&self) -> Result<Vec<String>, RedfishError>;
async fn get_system_ethernet_interface(
&self,
id: &str,
) -> Result<EthernetInterface, RedfishError>;
async fn change_uefi_password(
&self,
current_uefi_password: &str,
new_uefi_password: &str,
) -> Result<Option<String>, RedfishError>;
async fn get_job_state(&self, job_id: &str) -> Result<JobState, RedfishError>;
async fn get_resource(&self, id: ODataId) -> Result<Resource, RedfishError>;
async fn get_collection(&self, id: ODataId) -> Result<Collection, RedfishError>;
async fn set_boot_order_dpu_first(
&self,
mac_address: &str,
) -> Result<Option<String>, RedfishError>;
async fn clear_uefi_password(
&self,
current_uefi_password: &str,
) -> Result<Option<String>, RedfishError>;
async fn get_update_service(&self) -> Result<UpdateService, RedfishError>;
async fn get_base_mac_address(&self) -> Result<Option<String>, RedfishError>;
async fn lockdown_bmc(&self, target: EnabledDisabled) -> Result<(), RedfishError>;
async fn is_ipmi_over_lan_enabled(&self) -> Result<bool, RedfishError>;
async fn enable_ipmi_over_lan(&self, target: EnabledDisabled) -> Result<(), RedfishError>;
async fn enable_rshim_bmc(&self) -> Result<(), RedfishError>;
async fn clear_nvram(&self) -> Result<(), RedfishError>;
async fn get_nic_mode(&self) -> Result<Option<NicMode>, RedfishError>;
async fn set_nic_mode(&self, mode: NicMode) -> Result<(), RedfishError>;
async fn enable_infinite_boot(&self) -> Result<(), RedfishError>;
async fn is_infinite_boot_enabled(&self) -> Result<Option<bool>, RedfishError>;
async fn set_host_rshim(&self, enabled: EnabledDisabled) -> Result<(), RedfishError>;
async fn get_host_rshim(&self) -> Result<Option<EnabledDisabled>, RedfishError>;
async fn set_idrac_lockdown(&self, enabled: EnabledDisabled) -> Result<(), RedfishError>;
async fn get_boss_controller(&self) -> Result<Option<String>, RedfishError>;
async fn decommission_storage_controller(
&self,
controller_id: &str,
) -> Result<Option<String>, RedfishError>;
async fn create_storage_volume(
&self,
controller_id: &str,
volume_name: &str,
raid_type: &str,
) -> Result<Option<String>, RedfishError>;
fn ac_powercycle_supported_by_power(&self) -> bool;
async fn is_boot_order_setup(&self, mac_address: &str) -> Result<bool, RedfishError>;
async fn get_component_integrities(&self) -> Result<ComponentIntegrities, RedfishError>;
async fn get_firmware_for_component(
&self,
component_integrity_id: &str,
) -> Result<SoftwareInventory, RedfishError>;
async fn get_component_ca_certificate(
&self,
url: &str,
) -> Result<model::component_integrity::CaCertificate, RedfishError>;
async fn trigger_evidence_collection(
&self,
url: &str,
nonce: &str,
) -> Result<Task, RedfishError>;
async fn get_evidence(
&self,
url: &str,
) -> Result<model::component_integrity::Evidence, RedfishError>;
async fn set_host_privilege_level(&self, level: HostPrivilegeLevel) -> Result<(), RedfishError>;
async fn set_utc_timezone(&self) -> Result<(), RedfishError>;
}
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq)]
pub enum Boot {
Pxe,
HardDisk,
UefiHttp,
}
impl fmt::Display for Boot {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self, f)
}
}
#[derive(Clone, PartialEq, Debug)]
pub struct Status {
pub(crate) status: StatusInternal,
pub(crate) message: String,
}
impl std::fmt::Display for Status {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Debug::fmt(self, f)
}
}
#[derive(Copy, Clone, PartialEq, Debug)]
enum StatusInternal {
Enabled,
Partial,
Disabled,
}
impl fmt::Display for StatusInternal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self, f)
}
}
#[derive(Serialize, Deserialize, Clone, Copy, Debug)]
pub enum RoleId {
Administrator,
Operator,
ReadOnly,
NoAccess,
}
impl fmt::Display for RoleId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self, f)
}
}
impl Status {
pub fn is_fully_enabled(&self) -> bool {
self.status == StatusInternal::Enabled
}
pub fn is_fully_disabled(&self) -> bool {
self.status == StatusInternal::Disabled
}
pub fn is_partially_enabled(&self) -> bool {
self.status == StatusInternal::Partial
}
pub fn message(&self) -> &str {
&self.message
}
pub fn build_fake(enabled: EnabledDisabled) -> Self {
Self {
status: match enabled {
EnabledDisabled::Enabled => StatusInternal::Enabled,
EnabledDisabled::Disabled => StatusInternal::Disabled,
},
message: "Fake".to_string(),
}
}
}
#[derive(Debug)]
pub struct MachineSetupStatus {
pub is_done: bool,
pub diffs: Vec<MachineSetupDiff>,
}
impl fmt::Display for MachineSetupStatus {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.is_done {
write!(f, "OK")
} else {
write!(
f,
"Mismatch: {:?}",
self.diffs
.iter()
.map(|d| d.to_string())
.collect::<Vec<_>>()
.join(", ")
)?;
Ok(())
}
}
}
#[derive(Debug)]
pub struct MachineSetupDiff {
pub key: String,
pub expected: String,
pub actual: String,
}
impl fmt::Display for MachineSetupDiff {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{} is '{}' expected '{}'",
self.key, self.actual, self.expected
)
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
#[serde(rename_all = "lowercase")] pub enum JobState {
Scheduled,
ScheduledWithErrors,
Running,
Completed,
CompletedWithErrors,
Unknown,
}
impl JobState {
fn from_str(s: &str) -> JobState {
match s {
"Scheduled" => JobState::Scheduled,
"Running" => JobState::Running,
"Completed" => JobState::Completed,
"CompletedWithErrors" => JobState::CompletedWithErrors,
_ => JobState::Unknown,
}
}
}
#[derive(
Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash, Copy, clap::ValueEnum, Default,
)]
#[serde(rename_all = "lowercase")]
pub enum BiosProfileType {
#[default]
Performance,
PowerEfficiency,
}
pub type BiosProfileProfiles = HashMap<BiosProfileType, HashMap<String, serde_json::Value>>;
pub type BiosProfileModel = HashMap<String, BiosProfileProfiles>;
pub type BiosProfileVendor = HashMap<RedfishVendor, BiosProfileModel>;
pub fn model_coerce(original: &str) -> String {
str::replace(original, " ", "_")
}