Skip to content

Commit 046ac4e

Browse files
authored
feat: initial support of Lenovo SR650 V4 (#23)
These are the following errors we get when trying to generate an exploration report on Lenovo SR650 V4s. This MR is a first attempt to fix these issues, more changes coming to support end-to-end ingestion for this model. - Missing key `DevicesandIOPorts_SPRedirection` at Systems/1/Bios - Missing key `DevicesandIOPorts_COMPortActiveAfterBoot` at Systems/1/Bios - Missing key `LegacyBIOS_NonOnboardPXE` at Systems/1/Bios - Missing key `LegacyBIOS_LegacyBIOS` at Systems/1/Bios - Missing field `ScheduledPowerActions` at redfish/v1/Systems/1/Oem - Missing field `NumberOfReboots` at redfish/v1/Systems/1/Oem - Missing field `HistorySysPerformance` at redfish/v1/Systems/1/Oem - Missing field `TotalPowerOnHours` at redfish/v1/Systems/1/Oem - Missing field `Sensors` at redfish/v1/Systems/1/Oem - Missing field `BootSettings` at redfish/v1/Systems/1/Oem --------- Signed-off-by: Krish Dandiwala <kdandiwala@nvidia.com>
1 parent 2ad9985 commit 046ac4e

4 files changed

Lines changed: 84 additions & 62 deletions

File tree

src/lenovo.rs

Lines changed: 71 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -373,36 +373,46 @@ impl Redfish for Bmc {
373373
}
374374

375375
async fn setup_serial_console(&self) -> Result<(), RedfishError> {
376-
let mut body = HashMap::new();
377-
body.insert(
378-
"Attributes",
379-
HashMap::from([
380-
(
381-
"DevicesandIOPorts_COMPort1",
382-
EnabledDisabled::Enabled.to_string(),
383-
),
384-
(
385-
"DevicesandIOPorts_ConsoleRedirection",
386-
"Enabled".to_string(), // not an EnabledDisabled, can be "Auto"
387-
),
388-
(
389-
"DevicesandIOPorts_SPRedirection",
390-
EnabledDisabled::Enabled.to_string(),
391-
),
392-
(
393-
"DevicesandIOPorts_SerialPortSharing",
394-
EnabledDisabled::Enabled.to_string(),
395-
),
396-
(
397-
"DevicesandIOPorts_COMPortActiveAfterBoot",
398-
EnabledDisabled::Enabled.to_string(),
399-
),
400-
(
401-
"DevicesandIOPorts_SerialPortAccessMode",
402-
"Shared".to_string(),
403-
),
404-
]),
376+
let bios = self.bios().await?;
377+
let url = format!("Systems/{}/Bios", self.s.system_id());
378+
let current_attrs = jsonmap::get_object(&bios, "Attributes", &url)?;
379+
380+
let mut attributes = HashMap::new();
381+
382+
attributes.insert(
383+
"DevicesandIOPorts_COMPort1",
384+
EnabledDisabled::Enabled.to_string(),
385+
);
386+
attributes.insert(
387+
"DevicesandIOPorts_ConsoleRedirection",
388+
"Enabled".to_string(),
389+
);
390+
attributes.insert(
391+
"DevicesandIOPorts_SerialPortSharing",
392+
EnabledDisabled::Enabled.to_string(),
405393
);
394+
attributes.insert(
395+
"DevicesandIOPorts_SerialPortAccessMode",
396+
EnabledDisabled::Enabled.to_string(),
397+
);
398+
399+
// Only in older Lenovo systems
400+
if current_attrs.contains_key("DevicesandIOPorts_SPRedirection") {
401+
attributes.insert(
402+
"DevicesandIOPorts_SPRedirection",
403+
EnabledDisabled::Enabled.to_string(),
404+
);
405+
}
406+
if current_attrs.contains_key("DevicesandIOPorts_COMPortActiveAfterBoot") {
407+
attributes.insert(
408+
"DevicesandIOPorts_COMPortActiveAfterBoot",
409+
EnabledDisabled::Enabled.to_string(),
410+
);
411+
}
412+
413+
let mut body = HashMap::new();
414+
body.insert("Attributes", attributes);
415+
406416
let url = format!("Systems/{}/Bios/Pending", self.s.system_id());
407417
self.s.client.patch(&url, body).await.map(|_status_code| ())
408418
}
@@ -412,34 +422,30 @@ impl Redfish for Bmc {
412422
let bios = self.bios().await?;
413423
let attrs = jsonmap::get_object(&bios, "Attributes", &url)?;
414424

425+
// "any" means any value counts as correctly disabled
426+
// Attributes are checked if present, missing attributes are skipped
415427
let expected = vec![
416-
// "any" means any value counts as correctly disabled
417428
("DevicesandIOPorts_COMPort1", "Enabled", "any"),
418429
("DevicesandIOPorts_ConsoleRedirection", "Enabled", "Auto"),
419-
("DevicesandIOPorts_SPRedirection", "Enabled", "Disabled"),
420430
("DevicesandIOPorts_SerialPortSharing", "Enabled", "Disabled"),
421-
(
422-
"DevicesandIOPorts_COMPortActiveAfterBoot",
423-
"Enabled",
424-
"Disabled",
425-
),
426-
(
427-
"DevicesandIOPorts_SerialPortAccessMode",
428-
"Shared",
429-
"Disabled",
430-
),
431+
("DevicesandIOPorts_SPRedirection", "Enabled", "Disabled"),
432+
("DevicesandIOPorts_COMPortActiveAfterBoot", "Enabled", "Disabled"),
433+
("DevicesandIOPorts_SerialPortAccessMode", "Shared", "Disabled"),
431434
];
435+
432436
let mut message = String::new();
433437
let mut enabled = true;
434438
let mut disabled = true;
439+
435440
for (key, val_enabled, val_disabled) in expected {
436-
let val_current = jsonmap::get_str(attrs, key, &url)?;
437-
message.push_str(&format!("{key}={val_current} "));
438-
if val_current != val_enabled {
439-
enabled = false;
440-
}
441-
if val_current != val_disabled && val_disabled != "any" {
442-
disabled = false;
441+
if let Some(val_current) = attrs.get(key).and_then(|v| v.as_str()) {
442+
message.push_str(&format!("{key}={val_current} "));
443+
if val_current != val_enabled {
444+
enabled = false;
445+
}
446+
if val_current != val_disabled && val_disabled != "any" {
447+
disabled = false;
448+
}
443449
}
444450
}
445451

@@ -1372,23 +1378,36 @@ impl Bmc {
13721378
/// Set so that we only UEFI IPv4 HTTP boot, and we retry that.
13731379
///
13741380
/// Disable PXE Boot
1375-
/// Disable LegacyBIOS Mode
1381+
/// Disable LegacyBIOS Mode (if supported)
13761382
/// Set Bootmode to UEFI
13771383
/// Enable IPv4 HTTP Boot
13781384
/// Disable IPv4 PXE Boot
13791385
/// Disable IPv6 PXE Boot
13801386
/// Enable Infinite Boot Mode
13811387
async fn set_uefi_boot_only(&self) -> Result<(), RedfishError> {
1388+
let bios = self.bios().await?;
1389+
let url = format!("Systems/{}/Bios", self.s.system_id());
1390+
let attrs = jsonmap::get_object(&bios, "Attributes", &url)?;
1391+
1392+
let mut attributes = self.uefi_boot_only_attributes();
1393+
1394+
// Legacy BIOS attributes only exist in older systems
1395+
// Only set them if they're present in the current BIOS
1396+
if attrs.contains_key("LegacyBIOS_NonOnboardPXE") {
1397+
attributes.insert("LegacyBIOS_NonOnboardPXE", "Disabled");
1398+
}
1399+
if attrs.contains_key("LegacyBIOS_LegacyBIOS") {
1400+
attributes.insert("LegacyBIOS_LegacyBIOS", "Disabled");
1401+
}
1402+
13821403
let mut body = HashMap::new();
1383-
body.insert("Attributes", self.uefi_boot_only_attributes());
1404+
body.insert("Attributes", attributes);
13841405
let url = format!("Systems/{}/Bios/Pending", self.s.system_id());
13851406
self.s.client.patch(&url, body).await.map(|_status_code| ())
13861407
}
13871408

13881409
fn uefi_boot_only_attributes(&self) -> HashMap<&str, &str> {
13891410
HashMap::from([
1390-
("LegacyBIOS_NonOnboardPXE", "Disabled"),
1391-
("LegacyBIOS_LegacyBIOS", "Disabled"),
13921411
("BootModes_SystemBootMode", "UEFIMode"),
13931412
("NetworkStackSettings_IPv4HTTPSupport", "Enabled"),
13941413
("NetworkStackSettings_IPv4PXESupport", "Disabled"),

src/model/oem/lenovo.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,18 @@ pub struct RecipientSettings {
3838
#[derive(Debug, Serialize, Deserialize, Clone)]
3939
#[serde(rename_all = "PascalCase")]
4040
pub struct System {
41-
pub scheduled_power_actions: ODataId,
41+
pub scheduled_power_actions: Option<ODataId>,
4242
#[serde(rename = "FrontPanelUSB")]
4343
pub front_panel_usb: Option<FrontPanelUSB>,
4444
pub metrics: ODataId,
4545
pub system_status: String,
46-
pub number_of_reboots: i64,
47-
pub history_sys_perf: ODataId,
46+
pub number_of_reboots: Option<i64>,
47+
pub history_sys_perf: Option<ODataId>,
4848
#[serde(rename = "@odata.type")]
4949
pub odata_type: String,
50-
pub total_power_on_hours: i64,
51-
pub sensors: ODataId,
52-
pub boot_settings: ODataId,
50+
pub total_power_on_hours: Option<i64>,
51+
pub sensors: Option<ODataId>,
52+
pub boot_settings: Option<ODataId>,
5353
}
5454

5555
/* Front Panel USB Port Management mapping from UI to redfish API:
@@ -76,10 +76,13 @@ pub struct System {
7676
pub struct FrontPanelUSB {
7777
inactivity_timeout_mins: i64,
7878
#[serde(rename = "IDButton")]
79-
id_button: String,
79+
id_button: Option<String>, // Only in older Lenovo systems
8080
pub port_switching_to: PortSwitchingMode,
8181
#[serde(rename = "FPMode")]
8282
pub fp_mode: FrontPanelUSBMode,
83+
// Fields in newer Lenovo systems
84+
port_id: Option<String>,
85+
status: Option<String>,
8386
}
8487

8588
#[allow(clippy::upper_case_acronyms)]

src/model/system.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ pub struct ComputerSystemLinks {
212212
#[derive(Debug, Serialize, Deserialize, Clone)]
213213
#[serde(rename_all = "PascalCase")]
214214
pub struct SerialConsole {
215-
pub max_concurrent_sessions: usize,
215+
pub max_concurrent_sessions: Option<usize>,
216216
#[serde(rename = "SSH")]
217217
pub ssh: SerialConsoleConnectionType,
218218
#[serde(rename = "IPMI")]
@@ -418,7 +418,7 @@ mod test {
418418
let result: super::ComputerSystem = serde_json::from_str(data).unwrap();
419419
assert_eq!(
420420
result.oem.unwrap().lenovo.unwrap().total_power_on_hours,
421-
3816
421+
Some(3816)
422422
);
423423
assert_eq!(result.processor_summary.unwrap().count, Some(2));
424424
}

src/supermicro.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ impl Redfish for Bmc {
316316
));
317317
};
318318
let is_enabled = sr.ssh.service_enabled
319-
&& sr.max_concurrent_sessions != 0
319+
&& sr.max_concurrent_sessions != Some(0)
320320
&& s_interface.is_supermicro_default();
321321
let status = if is_enabled {
322322
StatusInternal::Enabled

0 commit comments

Comments
 (0)