Skip to content

Commit dfde741

Browse files
committed
feat: add support to create_client_with_vendor, plumb through
Trying to approach this as something that makes sense, in the general sense, even though this is the first use-case for it. The motivator here is, since a Lite-On power shelf has no vendor details in the service root, the Redfish client cannot determine the vendor hardware type, so it defaults back to a `RedfishStandard` client, and not a `LiteOnPowerShelf` client. This means that when the client calls `set_machine_password_policy`, it fails, because it's using the `RedfishStandard` implementation, and not the `LiteOnPowerShelf` implementation; the Lite-On imlpementation uses an `AccountService` call, and not the "default" `AccountLockoutCounterResetAfter` call). So right now my choices are to either: - Skip `set_machine_password_policy` entirely for power shelves. - Introduce a way to set a specific vendor on a client, and bypass the service root check.
1 parent add2409 commit dfde741

1 file changed

Lines changed: 57 additions & 15 deletions

File tree

src/network.rs

Lines changed: 57 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -149,15 +149,51 @@ impl RedfishClientPool {
149149
.await
150150
}
151151

152-
/// Creates a Redfish BMC client for a certain endpoint and adds custom headers to subsequent requests.
152+
/// Creates a Redfish BMC client for a certain endpoint,
153+
/// and adds custom headers to subsequent requests.
153154
///
154-
/// Creating the client will immediately start a HTTP requests
155-
/// to set system_id, manager_id and vendor type.
156-
/// `custom_headers` will be added to any headers used by vendor specific implementations or the http client.
155+
/// Creating the client will immediately start HTTP requests
156+
/// to set system_id, manager_id, and vendor type (the vendor
157+
/// is auto-detected from the service root.
158+
///
159+
/// `custom_headers` will be added to any headers used by vendor
160+
/// specific implementations or the http client.
157161
pub async fn create_client_with_custom_headers(
158162
&self,
159163
endpoint: Endpoint,
160164
custom_headers: Vec<(HeaderName, String)>,
165+
) -> Result<Box<dyn crate::Redfish>, RedfishError> {
166+
self.create_client_impl(endpoint, None, custom_headers)
167+
.await
168+
}
169+
170+
/// Creates a Redfish BMC client for a certain endpoint using
171+
/// the provided vendor instead of auto-detecting from the service
172+
/// root. This is needed for BMCs (e.g. Lite-On power shelves) whose
173+
/// service root does not expose vendor information, where we need
174+
/// a client that uses vendor-specific logic.
175+
pub async fn create_client_with_vendor(
176+
&self,
177+
endpoint: Endpoint,
178+
vendor: RedfishVendor,
179+
custom_headers: Vec<(HeaderName, String)>,
180+
) -> Result<Box<dyn crate::Redfish>, RedfishError> {
181+
self.create_client_impl(endpoint, Some(vendor), custom_headers)
182+
.await
183+
}
184+
185+
// Creates a complete "client" that takes the endpoint, an optional
186+
// vendor (which falls back to self-detection using the service root),
187+
// and an optional set of custom headers.
188+
//
189+
// If there's ever a need to expose this as pub, it's entirely
190+
// reasonable to do so (and rename it to something descriptive like
191+
// create_complete_client).
192+
async fn create_client_impl(
193+
&self,
194+
endpoint: Endpoint,
195+
vendor: Option<RedfishVendor>,
196+
custom_headers: Vec<(HeaderName, String)>,
161197
) -> Result<Box<dyn crate::Redfish>, RedfishError> {
162198
let client = RedfishHttpClient::new(self.http_client.clone(), endpoint, custom_headers);
163199
let mut s = RedfishStandard::new(client);
@@ -172,22 +208,28 @@ impl RedfishClientPool {
172208
})?;
173209
let chassis = s.get_chassis_all().await?;
174210

175-
s.set_system_id(system_id)?;
176211
// call set_system_id always before calling set_vendor
212+
s.set_system_id(system_id)?;
177213
s.set_manager_id(manager_id)?;
178214
s.set_service_root(service_root.clone())?;
179215

180-
let Some(mut vendor) = service_root.vendor() else {
181-
return Err(RedfishError::MissingVendor);
182-
};
183-
if vendor == RedfishVendor::P3809 {
184-
if chassis.contains(&"MGX_NVSwitch_0".to_string()) {
185-
vendor = RedfishVendor::NvidiaGBSwitch;
186-
} else {
187-
vendor = RedfishVendor::NvidiaGH200;
216+
let vendor = match vendor {
217+
Some(v) => v,
218+
None => {
219+
let Some(mut v) = service_root.vendor() else {
220+
return Err(RedfishError::MissingVendor);
221+
};
222+
if v == RedfishVendor::P3809 {
223+
if chassis.contains(&"MGX_NVSwitch_0".to_string()) {
224+
v = RedfishVendor::NvidiaGBSwitch;
225+
} else {
226+
v = RedfishVendor::NvidiaGH200;
227+
}
228+
}
229+
v
188230
}
189-
}
190-
// returns the vendor specific object
231+
};
232+
191233
s.set_vendor(vendor).await
192234
}
193235

0 commit comments

Comments
 (0)