-
Notifications
You must be signed in to change notification settings - Fork 162
fix: more changes to support lenovo GB300s #2809
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1188,21 +1188,53 @@ impl SiteExplorer { | |
| } | ||
| } | ||
|
|
||
| // A DPU can show up as a chassis network adapter instead of a PCIe | ||
| // device on some BMCs; fall back to those only if the PCIe scan found none. | ||
| // A DPU can show up as a chassis instead of a PCIe device on some | ||
| // BMCs; fall back to the chassis inventory only if the PCIe scan | ||
| // found none. | ||
| if dpu_exploration.expected_managed_total() == 0 { | ||
| for chassis in ep.report.chassis.iter() { | ||
| for network_adapter in chassis.network_adapters.iter() { | ||
| // Some BMCs (e.g. the AMI/Lenovo GB300 host BMC) report the | ||
| // BlueField as the chassis object itself -- model, part_number | ||
| // and serial_number live on the chassis, while its nested | ||
| // network adapter carries an empty serial. Match on the | ||
| // chassis identity in that case; otherwise fall back to the | ||
| // chassis's network adapters (other vendors put the DPU | ||
| // serial there). Matching only one of the two per chassis | ||
| // keeps a single DPU from being counted twice. | ||
| let chassis_is_bluefield = chassis | ||
| .part_number | ||
| .as_deref() | ||
| .map(str::trim) | ||
| .is_some_and(is_bluefield_model); | ||
| let chassis_has_serial = chassis | ||
| .serial_number | ||
| .as_deref() | ||
| .map(str::trim) | ||
| .is_some_and(|serial| !serial.is_empty()); | ||
| if chassis_is_bluefield && chassis_has_serial { | ||
| self.record_host_dpu_device( | ||
| network_adapter.part_number.as_deref(), | ||
| network_adapter.serial_number.as_deref(), | ||
| chassis.part_number.as_deref(), | ||
| chassis.serial_number.as_deref(), | ||
| &dpu_sn_to_endpoint, | ||
| host_dpu_mode, | ||
| &ep, | ||
| &mut dpu_exploration, | ||
| metrics, | ||
| ) | ||
| .await; | ||
| } else { | ||
| for network_adapter in chassis.network_adapters.iter() { | ||
|
Comment on lines
+1214
to
+1226
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win Do not skip adapter serials unless the chassis serial can actually pair. Line 1214 selects the chassis path for any non-empty BlueField chassis serial, but Proposed fix- let chassis_has_serial = chassis
+ let chassis_serial = chassis
.serial_number
.as_deref()
.map(str::trim)
- .is_some_and(|serial| !serial.is_empty());
- if chassis_is_bluefield && chassis_has_serial {
+ .filter(|serial| !serial.is_empty());
+ let chassis_serial_matches_discovered_dpu = chassis_serial
+ .is_some_and(|serial| dpu_sn_to_endpoint.contains_key(serial));
+ if chassis_is_bluefield && chassis_serial_matches_discovered_dpu {
self.record_host_dpu_device(
chassis.part_number.as_deref(),
- chassis.serial_number.as_deref(),
+ chassis_serial,
&dpu_sn_to_endpoint,
host_dpu_mode,
&ep,🤖 Prompt for AI Agents |
||
| self.record_host_dpu_device( | ||
| network_adapter.part_number.as_deref(), | ||
| network_adapter.serial_number.as_deref(), | ||
| &dpu_sn_to_endpoint, | ||
| host_dpu_mode, | ||
| &ep, | ||
| &mut dpu_exploration, | ||
| metrics, | ||
| ) | ||
| .await; | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -232,22 +232,33 @@ impl RedfishClient { | |
| .map_err(|err| redact_password(err, curr_password.as_str())) | ||
| .map_err(map_redfish_error)?; | ||
| } | ||
| // Vikings and Lenovo GB300s. GB300s are detected as AMI at this | ||
| // point (vendor isn't refined to LenovoGB300 until later), but both | ||
| // rotate via the same admin account, so handle them together. | ||
| // Vikings and Lenovo GB300s (both still detected as AMI here). | ||
| // Resolve the admin account by username, and fall back to the conventional | ||
| // id "2" only when reads are blocked by `PasswordChangeRequired` (Viking factory state). | ||
| // Any other error propagates. | ||
| // | ||
| // https://docs.nvidia.com/dgx/dgxh100-user-guide/redfish-api-supp.html | ||
| RedfishVendor::AMI | RedfishVendor::LenovoGB300 => { | ||
| /* | ||
| https://docs.nvidia.com/dgx/dgxh100-user-guide/redfish-api-supp.html | ||
|
|
||
| You should set the password after the first boot. The following curl command changes the password for the admin user. | ||
| curl -k -u <bmc-user>:<password> --request PATCH 'https://<bmc-ip-address>/redfish/v1/AccountService/Accounts/2' --header 'If-Match: *' --header 'Content-Type: application/json' --data-raw '{ "Password" : "<password>" }' | ||
| */ | ||
| client | ||
| .change_password_by_id("2", new_password.as_str()) | ||
| match client | ||
| .change_password(curr_user.as_str(), new_password.as_str()) | ||
| .await | ||
| .map_err(|err| redact_password(err, new_password.as_str())) | ||
| .map_err(|err| redact_password(err, curr_password.as_str())) | ||
| .map_err(map_redfish_error)?; | ||
| { | ||
| Ok(()) => {} | ||
| Err(libredfish::RedfishError::PasswordChangeRequired) => { | ||
| client | ||
| .change_password_by_id("2", new_password.as_str()) | ||
| .await | ||
|
Comment on lines
+247
to
+250
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win Do not apply the AMI This branch includes Split the As per path instructions, BMC-facing code should account for “credential handling” and “vendor differences.” 🤖 Prompt for AI AgentsSource: Path instructions |
||
| .map_err(|err| redact_password(err, new_password.as_str())) | ||
| .map_err(|err| redact_password(err, curr_password.as_str())) | ||
| .map_err(map_redfish_error)?; | ||
| } | ||
| Err(err) => { | ||
| return Err(map_redfish_error(redact_password( | ||
| redact_password(err, new_password.as_str()), | ||
| curr_password.as_str(), | ||
| ))); | ||
| } | ||
| } | ||
| } | ||
| RedfishVendor::LenovoAMI | ||
| | RedfishVendor::Supermicro | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
Add comprehensive test coverage for the regex parsing change.
This modification to
PCI_ROOT_REGEXalters parsing behavior to accommodate GB300/Grace device paths with vendor/MMIO prefixes, yet no tests were added to verify correctness. According to the style guide, parsing functions are ideal candidates for table-driven tests usingcarbide-test-support.The following scenarios should be covered:
VenHw(...)/MemoryMapped(...)/PciRoot(0x16)/Pci(0x0,0x0)PciRoot(0x8)/Pci(0x2,0xa)/Pci(0x0,0x0)/MAC(...)suffixWithout test coverage, we cannot verify the fix works as intended or prevent regressions in this critical hardware discovery path. As per path instructions and STYLE_GUIDE.md testing guidance, add table-driven tests before merging.
📋 Example test structure using carbide-test-support
🤖 Prompt for AI Agents
Sources: Coding guidelines, Path instructions