Skip to content
Merged
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
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ repository = "https://github.com/NVIDIA/infra-controller"

[workspace.dependencies]
clap = { version = "4", features = ["derive", "env"] }
libredfish = { git = "https://github.com/NVIDIA/libredfish.git", tag = "v0.46.1" }
libredfish = { git = "https://github.com/NVIDIA/libredfish.git", tag = "v0.46.2" }
librms = { git = "https://github.com/NVIDIA/nv-rms-client.git", tag = "v0.10.0" }
ansi-to-html = "0.2.2"

Expand Down
2 changes: 1 addition & 1 deletion crates/admin-cli/src/redfish/cmds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -842,7 +842,7 @@ fn convert_ports_to_nice_table(
.as_ref()
.and_then(|ethernet| ethernet.mtu_size)
.unwrap_or(0),
port.current_speed_gbps.unwrap_or(0),
port.current_speed_gbps.unwrap_or(0.0),
]);
}
}
Expand Down
73 changes: 64 additions & 9 deletions crates/redfish/src/libredfish/test_support.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ struct RedfishSimState {
/// is password-redacted, and to exercise the quarantine-and-return-to-Ready
/// path in host UEFI rotation.
uefi_password_change_error: Option<String>,
/// Optional ComputerSystem identifier used to drive platform classification.
system_id: Option<String>,
/// Physical-port MAC addresses exposed through the adapter Ports collection.
network_adapter_port_mac_addresses: Vec<MacAddress>,
}

/// Build the `HTTPErrorCode` a real BMC would return for a rejected request, so
Expand Down Expand Up @@ -409,6 +413,22 @@ impl RedfishSim {
self.state.lock().unwrap().chassis_manufacturer = manufacturer;
}

/// Override the ComputerSystem identifier returned by the simulator. Site
/// Explorer classifies identifiers containing `bluefield` as DPUs.
pub fn set_system_id(&self, system_id: impl Into<String>) {
self.state.lock().unwrap().system_id = Some(system_id.into());
}

/// Configure the physical-port MAC addresses returned by the simulated
/// `Chassis/.../NetworkAdapters/.../Ports` collection. A non-empty value
/// also advertises the parent `NetworkAdapters` link on `Card1`.
pub fn set_network_adapter_port_mac_addresses(&self, mac_addresses: Vec<MacAddress>) {
self.state
.lock()
.unwrap()
.network_adapter_port_mac_addresses = mac_addresses;
}

/// Seed a credential into the sim's credential store -- the same store
/// [`Self::credential_reader`] exposes. Controllers that resolve a credential
/// through `redfish_client_pool.credential_reader()` (e.g. UEFI setup, which
Expand Down Expand Up @@ -1029,20 +1049,23 @@ impl Redfish for RedfishSimClient {

fn get_chassis<'a>(
&'a self,
_id: &'a str,
id: &'a str,
) -> libredfish::RedfishFuture<'a, Result<Chassis, RedfishError>> {
Box::pin(async move {
let manufacturer = self
.state
.lock()
.unwrap()
let state = self.state.lock().unwrap();
let manufacturer = state
.chassis_manufacturer
.clone()
.unwrap_or_else(|| "Nvidia".to_string());
Ok(Chassis {
manufacturer: Some(manufacturer),
model: Some("Bluefield 3 SmartNIC Main Card".to_string()),
name: Some("Card1".to_string()),
network_adapters: (id == "Card1"
&& !state.network_adapter_port_mac_addresses.is_empty())
.then(|| ODataId {
odata_id: "/redfish/v1/Chassis/Card1/NetworkAdapters".to_string(),
}),
..Default::default()
})
})
Expand Down Expand Up @@ -1144,8 +1167,15 @@ impl Redfish for RedfishSimClient {
) -> libredfish::RedfishFuture<'a, Result<libredfish::model::ComputerSystem, RedfishError>>
{
Box::pin(async move {
let id = self
.state
.lock()
.unwrap()
.system_id
.clone()
.unwrap_or_else(|| "Bluefield".to_string());
Ok(libredfish::model::ComputerSystem {
id: "Bluefield".to_string(),
id,
boot_progress: Some(libredfish::model::BootProgress {
last_state: Some(libredfish::model::BootProgressTypes::OSRunning),
last_state_time: Some(Utc::now().to_string()),
Expand Down Expand Up @@ -1235,25 +1265,50 @@ impl Redfish for RedfishSimClient {
_chassis_id: &'a str,
_network_adapter: &'a str,
) -> libredfish::RedfishFuture<'a, Result<Vec<std::string::String>, RedfishError>> {
Box::pin(async move { Ok(Vec::new()) })
Box::pin(async move {
let count = self
.state
.lock()
.unwrap()
.network_adapter_port_mac_addresses
.len();
Ok((0..count).map(|index| index.to_string()).collect())
})
}

fn get_port<'a>(
&'a self,
_chassis_id: &'a str,
_network_adapter: &'a str,
_id: &'a str,
id: &'a str,
) -> libredfish::RedfishFuture<'a, Result<libredfish::model::port::NetworkPort, RedfishError>>
{
Box::pin(async move {
let index = id
.parse::<usize>()
.map_err(|error| RedfishError::GenericError {
error: format!("invalid simulated network adapter port ID {id}: {error}"),
})?;
let state = self.state.lock().unwrap();
let mac_address = state
.network_adapter_port_mac_addresses
.get(index)
.copied()
.ok_or_else(|| RedfishError::GenericError {
error: format!("unknown simulated network adapter port ID {id}"),
})?;
Ok(libredfish::model::port::NetworkPort {
odata: None,
description: None,
id: None,
id: Some(id.to_string()),
name: None,
link_status: None,
link_network_technology: None,
current_speed_gbps: None,
ethernet: Some(libredfish::model::port::PortEthernet {
associated_mac_addresses: vec![mac_address.to_string()],
}),
oem: None,
})
})
}
Expand Down
Loading
Loading