Skip to content

Commit 1b42e7c

Browse files
committed
chore: cleanup
1 parent c68fe7c commit 1b42e7c

5 files changed

Lines changed: 103 additions & 103 deletions

File tree

src/delta_powershelf.rs

Lines changed: 14 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{Assembly, REDFISH_ENDPOINT};
1+
use crate::Assembly;
22
use reqwest::StatusCode;
33
use std::{collections::HashMap, path::Path, time::Duration};
44
use tokio::fs::File;
@@ -8,8 +8,7 @@ use crate::model::boot::BootOverride;
88
use crate::model::certificate::Certificate;
99
use crate::model::component_integrity::ComponentIntegrities;
1010
use crate::model::oem::nvidia_dpu::{HostPrivilegeLevel, NicMode};
11-
use crate::model::power::{Power, PowerSupplies, PowerSupply, Voltages};
12-
use crate::model::sensor::{GPUSensors, Sensor, Sensors};
11+
use crate::model::sensor::GPUSensors;
1312
use crate::model::service_root::RedfishVendor;
1413
use crate::model::task::Task;
1514
use crate::model::update_service::{ComponentType, TransferProtocolType, UpdateService};
@@ -26,8 +25,6 @@ use crate::{
2625
};
2726
use crate::{EnabledDisabled, JobState, MachineSetupStatus, RoleId};
2827

29-
const UEFI_PASSWORD_NAME: &str = "AdminPassword";
30-
3128
pub struct Bmc {
3229
s: RedfishStandard,
3330
}
@@ -120,47 +117,9 @@ impl Redfish for Bmc {
120117
fn get_power_metrics<'a>(
121118
&'a self,
122119
) -> crate::RedfishFuture<'a, Result<crate::Power, RedfishError>> {
123-
Box::pin(async move {
124-
let mut voltages = Vec::new();
125-
let mut power_supplies = Vec::new();
126-
// delta powershelf has a strange redfish tree. assemble this
127-
let mut url = "Chassis/chassis/PowerSubsystem/PowerSupplies".to_string();
128-
let (_status_code, ps): (StatusCode, PowerSupplies) = self.s.client.get(&url).await?;
129-
for supply in ps.members {
130-
url = supply
131-
.odata_id
132-
.replace(&format!("/{REDFISH_ENDPOINT}/"), "");
133-
let (_status_code, power_supply): (StatusCode, PowerSupply) =
134-
self.s.client.get(&url).await?;
135-
power_supplies.push(power_supply);
136-
}
137-
138-
url = "Chassis/chassis/Sensors".to_string();
139-
let (_status_code, sensors): (StatusCode, Sensors) = self.s.client.get(&url).await?;
140-
for sensor in sensors.members {
141-
// now all voltage sensors in all chassis
142-
if !sensor.odata_id.contains("voltage") {
143-
continue;
144-
}
145-
url = sensor
146-
.odata_id
147-
.replace(&format!("/{REDFISH_ENDPOINT}/"), "");
148-
let (_status_code, t): (StatusCode, Sensor) = self.s.client.get(&url).await?;
149-
let sensor: Voltages = Voltages::from(t);
150-
voltages.push(sensor);
151-
}
152-
153-
let power = Power {
154-
odata: None,
155-
id: "Power".to_string(),
156-
name: "Power".to_string(),
157-
power_control: vec![],
158-
power_supplies: Some(power_supplies),
159-
voltages: Some(voltages),
160-
redundancy: None,
161-
};
162-
Ok(power)
163-
})
120+
// Discover the chassis carrying the PowerSubsystem rather than
121+
// hard-coding the Delta-specific id.
122+
Box::pin(async move { self.s.get_power_metrics_from_chassis().await })
164123
}
165124

166125
fn power<'a>(
@@ -672,17 +631,17 @@ impl Redfish for Bmc {
672631
})
673632
}
674633

675-
// Set current_uefi_password to "" if there isn't one yet. By default there isn't a password.
676-
/// Set new_uefi_password to "" to disable it.
634+
/// Delta power shelves have no UEFI/BIOS, so there is no UEFI password to
635+
/// manage.
677636
fn change_uefi_password<'a>(
678637
&'a self,
679-
current_uefi_password: &'a str,
680-
new_uefi_password: &'a str,
638+
_current_uefi_password: &'a str,
639+
_new_uefi_password: &'a str,
681640
) -> crate::RedfishFuture<'a, Result<Option<String>, RedfishError>> {
682641
Box::pin(async move {
683-
self.s
684-
.change_bios_password(UEFI_PASSWORD_NAME, current_uefi_password, new_uefi_password)
685-
.await
642+
Err(RedfishError::NotSupported(
643+
"Delta powershelf UEFI password unsupported".to_string(),
644+
))
686645
})
687646
}
688647

@@ -942,11 +901,12 @@ impl Redfish for Bmc {
942901
false
943902
}
944903

904+
/// Delta power shelves have no boot order, so there is nothing to set up.
945905
fn is_boot_order_setup<'a>(
946906
&'a self,
947907
_mac_address: &'a str,
948908
) -> crate::RedfishFuture<'a, Result<bool, RedfishError>> {
949-
Box::pin(async move { Err(RedfishError::NotSupported("not supported".to_string())) })
909+
Box::pin(async move { Ok(true) })
950910
}
951911

952912
fn get_component_integrities<'a>(

src/liteon_powershelf.rs

Lines changed: 6 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
use crate::{Assembly, REDFISH_ENDPOINT};
2-
use reqwest::StatusCode;
1+
use crate::Assembly;
32
use std::{collections::HashMap, path::Path, time::Duration};
43
use tokio::fs::File;
54

@@ -8,8 +7,8 @@ use crate::model::boot::BootOverride;
87
use crate::model::certificate::Certificate;
98
use crate::model::component_integrity::ComponentIntegrities;
109
use crate::model::oem::nvidia_dpu::{HostPrivilegeLevel, NicMode};
11-
use crate::model::power::{Power, PowerSupplies, PowerSupply, Voltages};
12-
use crate::model::sensor::{GPUSensors, Sensor, Sensors};
10+
use crate::model::power::Power;
11+
use crate::model::sensor::GPUSensors;
1312
use crate::model::service_root::RedfishVendor;
1413
use crate::model::task::Task;
1514
use crate::model::update_service::{ComponentType, TransferProtocolType, UpdateService};
@@ -124,47 +123,9 @@ impl Redfish for Bmc {
124123
fn get_power_metrics<'a>(
125124
&'a self,
126125
) -> crate::RedfishFuture<'a, Result<crate::Power, RedfishError>> {
127-
Box::pin(async move {
128-
let mut voltages = Vec::new();
129-
let mut power_supplies = Vec::new();
130-
// liteon powershelf has a strange redfish tree. assemble this
131-
let mut url = "Chassis/powershelf/PowerSubsystem/PowerSupplies".to_string();
132-
let (_status_code, ps): (StatusCode, PowerSupplies) = self.s.client.get(&url).await?;
133-
for supply in ps.members {
134-
url = supply
135-
.odata_id
136-
.replace(&format!("/{REDFISH_ENDPOINT}/"), "");
137-
let (_status_code, power_supply): (StatusCode, PowerSupply) =
138-
self.s.client.get(&url).await?;
139-
power_supplies.push(power_supply);
140-
}
141-
142-
url = "Chassis/powershelf/Sensors".to_string();
143-
let (_status_code, sensors): (StatusCode, Sensors) = self.s.client.get(&url).await?;
144-
for sensor in sensors.members {
145-
// now all voltage sensors in all chassis
146-
if !sensor.odata_id.contains("voltage") {
147-
continue;
148-
}
149-
url = sensor
150-
.odata_id
151-
.replace(&format!("/{REDFISH_ENDPOINT}/"), "");
152-
let (_status_code, t): (StatusCode, Sensor) = self.s.client.get(&url).await?;
153-
let sensor: Voltages = Voltages::from(t);
154-
voltages.push(sensor);
155-
}
156-
157-
let power = Power {
158-
odata: None,
159-
id: "Power".to_string(),
160-
name: "Power".to_string(),
161-
power_control: vec![],
162-
power_supplies: Some(power_supplies),
163-
voltages: Some(voltages),
164-
redundancy: None,
165-
};
166-
Ok(power)
167-
})
126+
// Discover the chassis carrying the PowerSubsystem rather than
127+
// hard-coding the Lite-On-specific id.
128+
Box::pin(async move { self.s.get_power_metrics_from_chassis().await })
168129
}
169130

170131
fn power<'a>(

src/model/chassis.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,13 @@ use serde_json::Value;
2525
use tracing::debug;
2626

2727
use super::oem::ChassisExtensions;
28+
use super::power::{Power, PowerSupplies, PowerSupply, Voltages};
2829
use super::resource::OData;
30+
use super::sensor::{Sensor, Sensors};
2931
use super::{ODataId, ODataLinks, PCIeFunction, PowerState, ResourceStatus};
32+
use crate::network::{RedfishHttpClient, REDFISH_ENDPOINT};
3033
use crate::NetworkDeviceFunction;
34+
use crate::RedfishError;
3135

3236
#[derive(Debug, Serialize, Deserialize, Clone)]
3337
pub struct ChassisActions {
@@ -128,6 +132,66 @@ pub struct Chassis {
128132
pub oem: Option<ChassisExtensions>,
129133
}
130134

135+
impl Chassis {
136+
/// Assemble power metrics (PSUs + voltage sensors) by following this
137+
/// chassis's own `PowerSubsystem` and `Sensors` links.
138+
///
139+
/// Power shelves (e.g. Lite-On, Delta) expose PSUs under
140+
/// `PowerSubsystem/PowerSupplies` and voltage readings under `Sensors`,
141+
/// rather than the legacy `Chassis/<id>/Power` resource. Because the chassis
142+
/// id also differs per vendor (`powershelf` vs `chassis`), following the
143+
/// links recorded on the chassis itself avoids hard-coding either.
144+
///
145+
/// Returns empty collections (not an error) when the chassis advertises no
146+
/// `PowerSubsystem`/`Sensors` links.
147+
pub(crate) async fn get_power_metrics(
148+
&self,
149+
client: &RedfishHttpClient,
150+
) -> Result<Power, RedfishError> {
151+
// Resource links are absolute (`/redfish/v1/...`); the HTTP client
152+
// expects paths relative to the service root, so strip the prefix.
153+
let to_relative =
154+
|odata_id: &str| odata_id.replace(&format!("/{REDFISH_ENDPOINT}/"), "");
155+
156+
let mut power_supplies = Vec::new();
157+
if let Some(subsystem) = &self.power_subsystem {
158+
let base = subsystem.odata_id.trim_end_matches('/');
159+
let url = to_relative(&format!("{base}/PowerSupplies"));
160+
let (_, ps): (_, PowerSupplies) = client.get(&url).await?;
161+
for supply in ps.members {
162+
let url = to_relative(&supply.odata_id);
163+
let (_, power_supply): (_, PowerSupply) = client.get(&url).await?;
164+
power_supplies.push(power_supply);
165+
}
166+
}
167+
168+
let mut voltages = Vec::new();
169+
if let Some(sensors_link) = &self.sensors {
170+
let url = to_relative(&sensors_link.odata_id);
171+
let (_, sensors): (_, Sensors) = client.get(&url).await?;
172+
for sensor in sensors.members {
173+
// only voltage sensors
174+
if !sensor.odata_id.contains("voltage") {
175+
continue;
176+
}
177+
let url = to_relative(&sensor.odata_id);
178+
let (_, reading): (_, Sensor) = client.get(&url).await?;
179+
voltages.push(Voltages::from(reading));
180+
}
181+
}
182+
183+
Ok(Power {
184+
odata: None,
185+
id: "Power".to_string(),
186+
name: "Power".to_string(),
187+
power_control: vec![],
188+
power_supplies: Some(power_supplies),
189+
voltages: Some(voltages),
190+
redundancy: None,
191+
})
192+
}
193+
}
194+
131195
#[derive(Debug, Serialize, Deserialize, Clone)]
132196
#[serde(rename_all = "PascalCase")]
133197
pub struct NetworkAdapter {

src/model/service_root.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,6 @@ impl ServiceRoot {
113113
"wiwynn" => RedfishVendor::NvidiaGBx00,
114114
"supermicro" => RedfishVendor::Supermicro,
115115
"lite-on technology corp." => RedfishVendor::LiteOnPowerShelf,
116-
// Real Delta shelves (PMC firmware common-pmc-2.2.7) omit Vendor from
117-
// the service root, so detection happens via the chassis Manufacturer
118-
// ("DELTA") fallback in the site-explorer. This arm is here for parity
119-
// in case a future firmware populates the service-root vendor.
120116
"delta" => RedfishVendor::DeltaPowerShelf,
121117
_ => RedfishVendor::Unknown,
122118
})

src/standard.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1577,6 +1577,25 @@ impl RedfishStandard {
15771577
Ok(body)
15781578
}
15791579

1580+
/// Assemble power metrics by discovering the chassis that carries a
1581+
/// `PowerSubsystem` link and following that chassis's own
1582+
/// `PowerSubsystem`/`Sensors` links, rather than hard-coding a chassis id.
1583+
/// This avoids vendor-specific assumptions (e.g. Lite-On names the chassis
1584+
/// `powershelf`, Delta names it `chassis`).
1585+
pub(crate) async fn get_power_metrics_from_chassis(
1586+
&self,
1587+
) -> Result<power::Power, RedfishError> {
1588+
for chassis_id in self.get_chassis_all().await? {
1589+
let chassis = self.get_chassis(&chassis_id).await?;
1590+
if chassis.power_subsystem.is_some() {
1591+
return chassis.get_power_metrics(&self.client).await;
1592+
}
1593+
}
1594+
Err(RedfishError::GenericError {
1595+
error: "No chassis with a PowerSubsystem found".to_string(),
1596+
})
1597+
}
1598+
15801599
/// Query the thermal status from the server
15811600
pub async fn get_thermal_metrics(&self) -> Result<thermal::Thermal, RedfishError> {
15821601
let url = format!("Chassis/{}/Thermal/", self.system_id());

0 commit comments

Comments
 (0)