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
10 changes: 10 additions & 0 deletions src/model/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,16 @@ pub struct Manager {
#[serde(rename = "UUID")]
pub uuid: Option<String>,
pub oem: Option<ManagerExtensions>,
pub links: Option<ManagerLinks>,
}

#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[serde(rename_all = "PascalCase")]
pub struct ManagerLinks {
#[serde(default)]
pub manager_for_servers: Vec<ODataId>,
#[serde(default)]
pub manager_for_chassis: Vec<ODataId>,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
Expand Down
1 change: 1 addition & 0 deletions src/model/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ pub struct ComputerSystem {
pub asset_tag: Option<String>,
#[serde(default)] // Some viking ComputerSystem has no Boot property; so use the default
pub boot: Boot,
pub bios: Option<ODataId>,
pub bios_version: Option<String>,
pub ethernet_interfaces: Option<ODataId>,
pub id: String,
Expand Down
36 changes: 31 additions & 5 deletions src/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,9 +211,9 @@ impl RedfishClientPool {
};

let managers = s.get_managers().await?;
let manager_id = managers.first().ok_or_else(|| RedfishError::GenericError {
let mut manager_id = managers.first().ok_or_else(|| RedfishError::GenericError {
error: "No managers found in service root".to_string(),
})?;
})?.clone();
let chassis = s.get_chassis_all().await?;

// Delta power shelves expose no `/Systems` resource (a real query 404s)
Expand All @@ -228,18 +228,44 @@ impl RedfishClientPool {
// member blindly targets the wrong system (no BIOS/boot). Falling
// back to the first member preserves behavior for every platform
// that does not expose `System_0` (e.g. Viking's `DGX`).
let system_id = systems
let at_least_one_system_id = systems
.iter()
.find(|id| *id == "System_0")
.or_else(|| systems.first())
.ok_or_else(|| RedfishError::GenericError {
error: "No systems found in service root".to_string(),
})?;

//Find another system with BIOS section
let mut system_with_bios: Option<ComputerSystem> = None;
for system_member in &systems {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be better to use the bios property on the fetched System itself:

for id in &systems {
    let Ok((_, system)) = s
        .client
        .get::<ComputerSystem>(&format!("Systems/{id}"))
        .await
    else {
        break; // Use the existing fallback.
    };
    if system.bios.is_some() {
        system_id = id;
        break;
    }
}

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

// Treat any error as "no BIOS here": we already have
// `at_least_one_system_id` as a fallback, and this also handles the
// test mockup, which drops the connection instead of returning 404
// when the Bios section is empty.
system_with_bios = s.if_system_has_bios(system_member).await;
if system_with_bios.is_some() {
break;
}

}
let manager_from_system = system_with_bios
.as_ref()
.and_then(|swb| swb.links.as_ref())
.and_then(|links| links.managed_by.as_ref())
.and_then(|mb| mb.get(0))
.and_then(|d| d.odata_id.trim_matches('/').split('/').next_back())
.map(|m| m.to_string());
manager_id = manager_from_system.unwrap_or(manager_id);

let system_id = system_with_bios.map(|swb| swb.id.to_owned()).unwrap_or(at_least_one_system_id.to_owned());

// call set_system_id always before calling set_vendor
s.set_system_id(system_id)?;
s.set_system_id(&system_id)?;

}

s.set_manager_id(manager_id)?;
s.set_manager_id(&manager_id)?;
s.set_service_root(service_root.clone())?;

// Resolve placeholder/ambiguous vendors that can only be settled from
Expand Down
23 changes: 22 additions & 1 deletion src/standard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ use crate::model::{job::Job, oem::nvidia_dpu::NicMode};
use crate::model::{
manager_network_protocol::ManagerNetworkProtocol, update_service::TransferProtocolType,
};
use crate::model::{power, thermal, BootOption, InvalidValueError, Manager, Managers, ODataId};
use crate::model::{
power, thermal, BootOption, ComputerSystem, InvalidValueError, Manager, Managers, ODataId,
};
use crate::model::{power::Power, update_service::UpdateService};
use crate::model::{secure_boot::SecureBoot, sensor::GPUSensors};
use crate::model::{sel::LogEntry, ManagerResetType};
Expand Down Expand Up @@ -1408,6 +1410,17 @@ impl RedfishStandard {
Ok(b)
}

pub fn get_manager_with_id<'a>(
&'a self,
manager_id: &'a str,
) -> crate::RedfishFuture<'a, Result<Manager, RedfishError>> {
Box::pin(async move {
let (_, manager): (_, Manager) =
self.client.get(&format!("Managers/{}", manager_id)).await?;
Ok(manager)
})
}

pub async fn fetch_bmc_event_log(
&self,
url: String,
Expand Down Expand Up @@ -1510,6 +1523,14 @@ impl RedfishStandard {
})
}

pub async fn if_system_has_bios(&self, system_id: &str) -> Option<ComputerSystem> {
self.client
.get::<ComputerSystem>(&format!("Systems/{system_id}"))
.await
.map_or(None, |(_code, cs)| Some(cs))
.and_then(|cs| if cs.bios.is_some() { Some(cs) } else { None })
}

pub async fn factory_reset_bios(&self) -> Result<(), RedfishError> {
let url = format!("Systems/{}/Bios/Actions/Bios.ResetBios", self.system_id());
self.client
Expand Down