Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ regex = "1.10"
mac_address = "1.1"
chrono = { version = "0.4.34", features = ["serde"] }
urlencoding = "2.1.3"
rune = "0.14"
sha2 = "0.10"
base64 = "0.22"

[dev-dependencies]
anyhow = { version = "1" }
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@ mod nvidia_gbswitch;
mod nvidia_gbx00;
mod nvidia_gh200;
mod nvidia_viking;
mod rune_vendor;
mod supermicro;
mod vendor_override;
pub use network::{Endpoint, RedfishClientPool, RedfishClientPoolBuilder, REDFISH_ENDPOINT};
pub mod standard;
pub use error::RedfishError;
Expand Down
22 changes: 22 additions & 0 deletions src/model/service_root.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ pub struct ServiceRoot {
pub product: Option<String>,
pub redfish_version: String,
pub vendor: Option<String>,
/// Vendor forced by the override file; set in `get_service_root` and returned by
/// `vendor()` ahead of auto-detection. Not part of the Redfish schema.
#[serde(skip)]
pub override_vendor: Option<RedfishVendor>,
#[serde(rename = "UUID")]
pub uuid: Option<String>,
pub oem: Option<HashMap<String, serde_json::Value>>,
Expand Down Expand Up @@ -72,6 +76,7 @@ pub enum RedfishVendor {
P3809, // dummy for P3809, needs to be set to NvidiaGH200 or NvidiaGBSwitch based on chassis
LiteOnPowerShelf,
DeltaPowerShelf,
Rune,
Unknown,
}

Expand All @@ -93,6 +98,10 @@ impl ServiceRoot {
}

pub fn vendor(&self) -> Option<RedfishVendor> {
// A forced override vendor wins over auto-detection.
if self.override_vendor.is_some() {
return self.override_vendor;
}
let v = self.vendor_string().unwrap_or("Unknown".to_string());
Some(match v.to_lowercase().as_str() {
"ami" => RedfishVendor::AMI,
Expand All @@ -114,6 +123,7 @@ impl ServiceRoot {
"supermicro" => RedfishVendor::Supermicro,
"lite-on technology corp." => RedfishVendor::LiteOnPowerShelf,
"delta" => RedfishVendor::DeltaPowerShelf,
"rune" => RedfishVendor::Rune,
_ => RedfishVendor::Unknown,
})
}
Expand Down Expand Up @@ -157,4 +167,16 @@ mod test {
};
assert_eq!(result.vendor().unwrap(), RedfishVendor::NvidiaDpu);
}

#[test]
fn override_vendor_wins_over_detection() {
// A pinned override vendor (stamped by get_service_root) takes precedence
// over whatever the BMC reports, so detection/auto-detect honor it.
let result = ServiceRoot {
vendor: Some("dell".to_string()),
override_vendor: Some(RedfishVendor::Rune),
..Default::default()
};
assert_eq!(result.vendor().unwrap(), RedfishVendor::Rune);
}
}
31 changes: 22 additions & 9 deletions src/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,23 +196,36 @@ impl RedfishClientPool {
vendor: Option<RedfishVendor>,
custom_headers: Vec<(HeaderName, String)>,
) -> Result<Box<dyn crate::Redfish>, RedfishError> {
// Host is the vendor-override key; capture it before `endpoint` moves.
let host = endpoint.host.clone();
let client = RedfishHttpClient::new(self.http_client.clone(), endpoint, custom_headers);
let mut s = RedfishStandard::new(client);
let service_root = s.get_service_root().await?;

// Resolve the vendor up-front (explicit override, else from the service
// root, which get_service_root backfills from the chassis manufacturer
// for vendorless power shelves). Knowing the vendor here lets us skip
// resource lookups for platforms that don't expose them.
let vendor = match vendor {
Some(v) => v,
None => service_root.vendor().ok_or(RedfishError::MissingVendor)?,
};

// Manager id is needed both as the vendor-override key and for set_manager_id.
let managers = s.get_managers().await?;
let manager_id = managers.first().ok_or_else(|| RedfishError::GenericError {
error: "No managers found in service root".to_string(),
})?;

// Resolve the vendor: override file wins, then the caller's vendor, then
// auto-detection. Knowing it now lets us skip lookups some platforms 404 on.
let ov = crate::vendor_override::resolve(&host, manager_id)?;
let vendor = ov
.as_ref()
.map(|o| o.vendor)
.or(vendor)
.or_else(|| service_root.vendor())
.ok_or(RedfishError::MissingVendor)?;
// Variant and script come only from the override file; they ride the
// `RedfishStandard` clone into `set_vendor`.
let (ov_variant, ov_script) = match ov {
Some(o) => (o.variant, o.script),
None => (None, None),
};
s.set_vendor_variant(ov_variant);
s.set_vendor_script(ov_script);

let chassis = s.get_chassis_all().await?;

// Delta power shelves expose no `/Systems` resource (a real query 404s)
Expand Down
Loading