Skip to content

Commit b199e7b

Browse files
fix: pick the correct manager/system on multi-system, multi-chassis hosts (#108)
Match the system by presence of a Bios resource and select the manager whose Links.ManagerForServers references it, instead of blindly taking the first entry. --------- Signed-off-by: Evgeny Shevchenko <eshevchenko@mirantis.com>
1 parent 6bb45d0 commit b199e7b

4 files changed

Lines changed: 64 additions & 6 deletions

File tree

src/model/manager.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,16 @@ pub struct Manager {
5959
#[serde(rename = "UUID")]
6060
pub uuid: Option<String>,
6161
pub oem: Option<ManagerExtensions>,
62+
pub links: Option<ManagerLinks>,
63+
}
64+
65+
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
66+
#[serde(rename_all = "PascalCase")]
67+
pub struct ManagerLinks {
68+
#[serde(default)]
69+
pub manager_for_servers: Vec<ODataId>,
70+
#[serde(default)]
71+
pub manager_for_chassis: Vec<ODataId>,
6272
}
6373

6474
#[derive(Debug, Serialize, Deserialize, Clone)]

src/model/system.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ pub struct ComputerSystem {
179179
pub asset_tag: Option<String>,
180180
#[serde(default)] // Some viking ComputerSystem has no Boot property; so use the default
181181
pub boot: Boot,
182+
pub bios: Option<ODataId>,
182183
pub bios_version: Option<String>,
183184
pub ethernet_interfaces: Option<ODataId>,
184185
pub id: String,

src/network.rs

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -211,9 +211,9 @@ impl RedfishClientPool {
211211
};
212212

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

219219
// Delta power shelves expose no `/Systems` resource (a real query 404s)
@@ -228,18 +228,44 @@ impl RedfishClientPool {
228228
// member blindly targets the wrong system (no BIOS/boot). Falling
229229
// back to the first member preserves behavior for every platform
230230
// that does not expose `System_0` (e.g. Viking's `DGX`).
231-
let system_id = systems
231+
let at_least_one_system_id = systems
232232
.iter()
233233
.find(|id| *id == "System_0")
234234
.or_else(|| systems.first())
235235
.ok_or_else(|| RedfishError::GenericError {
236236
error: "No systems found in service root".to_string(),
237237
})?;
238+
239+
//Find another system with BIOS section
240+
let mut system_with_bios: Option<ComputerSystem> = None;
241+
for system_member in &systems {
242+
// Treat any error as "no BIOS here": we already have
243+
// `at_least_one_system_id` as a fallback, and this also handles the
244+
// test mockup, which drops the connection instead of returning 404
245+
// when the Bios section is empty.
246+
system_with_bios = s.if_system_has_bios(system_member).await;
247+
if system_with_bios.is_some() {
248+
break;
249+
}
250+
251+
}
252+
let manager_from_system = system_with_bios
253+
.as_ref()
254+
.and_then(|swb| swb.links.as_ref())
255+
.and_then(|links| links.managed_by.as_ref())
256+
.and_then(|mb| mb.get(0))
257+
.and_then(|d| d.odata_id.trim_matches('/').split('/').next_back())
258+
.map(|m| m.to_string());
259+
manager_id = manager_from_system.unwrap_or(manager_id);
260+
261+
let system_id = system_with_bios.map(|swb| swb.id.to_owned()).unwrap_or(at_least_one_system_id.to_owned());
262+
238263
// call set_system_id always before calling set_vendor
239-
s.set_system_id(system_id)?;
264+
s.set_system_id(&system_id)?;
265+
240266
}
241267

242-
s.set_manager_id(manager_id)?;
268+
s.set_manager_id(&manager_id)?;
243269
s.set_service_root(service_root.clone())?;
244270

245271
// Resolve placeholder/ambiguous vendors that can only be settled from

src/standard.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ use crate::model::{job::Job, oem::nvidia_dpu::NicMode};
4141
use crate::model::{
4242
manager_network_protocol::ManagerNetworkProtocol, update_service::TransferProtocolType,
4343
};
44-
use crate::model::{power, thermal, BootOption, InvalidValueError, Manager, Managers, ODataId};
44+
use crate::model::{
45+
power, thermal, BootOption, ComputerSystem, InvalidValueError, Manager, Managers, ODataId,
46+
};
4547
use crate::model::{power::Power, update_service::UpdateService};
4648
use crate::model::{secure_boot::SecureBoot, sensor::GPUSensors};
4749
use crate::model::{sel::LogEntry, ManagerResetType};
@@ -1449,6 +1451,17 @@ impl RedfishStandard {
14491451
Ok(b)
14501452
}
14511453

1454+
pub fn get_manager_with_id<'a>(
1455+
&'a self,
1456+
manager_id: &'a str,
1457+
) -> crate::RedfishFuture<'a, Result<Manager, RedfishError>> {
1458+
Box::pin(async move {
1459+
let (_, manager): (_, Manager) =
1460+
self.client.get(&format!("Managers/{}", manager_id)).await?;
1461+
Ok(manager)
1462+
})
1463+
}
1464+
14521465
pub async fn fetch_bmc_event_log(
14531466
&self,
14541467
url: String,
@@ -1551,6 +1564,14 @@ impl RedfishStandard {
15511564
})
15521565
}
15531566

1567+
pub async fn if_system_has_bios(&self, system_id: &str) -> Option<ComputerSystem> {
1568+
self.client
1569+
.get::<ComputerSystem>(&format!("Systems/{system_id}"))
1570+
.await
1571+
.map_or(None, |(_code, cs)| Some(cs))
1572+
.and_then(|cs| if cs.bios.is_some() { Some(cs) } else { None })
1573+
}
1574+
15541575
pub async fn factory_reset_bios(&self) -> Result<(), RedfishError> {
15551576
let url = format!("Systems/{}/Bios/Actions/Bios.ResetBios", self.system_id());
15561577
self.client

0 commit comments

Comments
 (0)