Skip to content

Refactor BMC interface to support vendor-specific implementations#689

Merged
afritzler merged 6 commits intomainfrom
enh/bmc-refactoring
Mar 3, 2026
Merged

Refactor BMC interface to support vendor-specific implementations#689
afritzler merged 6 commits intomainfrom
enh/bmc-refactoring

Conversation

@afritzler
Copy link
Copy Markdown
Member

@afritzler afritzler commented Feb 18, 2026

Summary by CodeRabbit

  • Refactor
    • Reorganized BMC handling into a shared base with vendor-specific wrappers for Dell, HPE, Lenovo and Supermicro; consolidated firmware upgrade and attribute workflows for consistency and clearer not-supported fallbacks.
  • New Features
    • Unified, vendor-agnostic upgrade and BMC attribute helpers, improved task monitoring and error reporting.
    • Added vendor-aware password generation and a PXE-once boot action for Supermicro.

Fixes #688

@afritzler afritzler requested a review from a team as a code owner February 18, 2026 12:37
@github-actions github-actions Bot added size/XXL enhancement New feature or request labels Feb 18, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 18, 2026

Walkthrough

Refactors BMC/OEM handling: removes OEM-specific package interfaces, consolidates shared OEM helpers, renames RedfishBMC to RedfishBaseBMC, and introduces vendor-specific BMC types (Dell/HPE/Lenovo/Supermicro) that embed the base and override vendor behaviors. Factory now returns vendor-aware BMC implementations.

Changes

Cohort / File(s) Summary
API surface & OEM removals
bmc/bmc.go, bmc/common/helpers.go, bmc/oem/oem.go, bmc/oem/types.go, bmc/oem/hpe.go, bmc/oem/lenovo.go, bmc/oem/dell.go
Removed OEM factory functions, OEM interfaces/types, per-vendor OEM files and helper CheckAttribues; deleted exported constructors and many OEM-specific managers/methods.
Vendor-agnostic helpers (added)
bmc/oem_helpers.go
Added vendor-agnostic upgrade and HTTP-based BMC attribute helpers, pluggable vendor callbacks, validation (isSubMap/checkAttributes), and shared upgrade/task polling logic.
Base BMC refactor
bmc/redfish.go, bmc/redfish_kube.go, bmc/redfish_local.go, manifest_file, go.mod
Renamed RedfishBMC → RedfishBaseBMC, added newRedfishBaseBMCClient and factory NewRedfishBMCClient returning BMC interface, moved many method receivers to base, added password-generation utilities, and centralized manufacturer detection.
Dell vendor implementation
bmc/redfish_dell.go, bmc/redfish_dell_test.go
Added DellRedfishBMC embedding base, moved/renamed Dell OEM logic into Dell-specific methods (attribute registry, get/update flows, upgrade builders/parsers) and updated tests.
HPE vendor implementation
bmc/redfish_hpe.go
Added HPERedfishBMC embedding base with HPE-specific attribute handlers and firmware upgrade builders/parsers delegating to shared helpers.
Lenovo vendor implementation
bmc/redfish_lenovo.go
Added LenovoRedfishBMC embedding base with Lenovo-specific attribute handlers and upgrade flows including nested job parsing.
Supermicro vendor implementation
bmc/redfish_supermicro.go
Added SupermicroRedfishBMC embedding base and Supermicro-specific SetPXEBootOnce implementation (UEFI/PXE override).

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant RedfishBaseBMC as BaseBMC
    participant VendorBMC
    participant RedfishService as BMCService

    Client->>BaseBMC: NewRedfishBMCClient(ctx, options)
    BaseBMC->>RedfishService: connect & detect manufacturer
    RedfishService-->>BaseBMC: Manufacturer info
    BaseBMC-->>Client: return VendorBMC (embedded Base)

    Client->>VendorBMC: UpgradeBMCVersion(params)
    VendorBMC->>VendorBMC: build vendor-specific request (requestBodyFn)
    VendorBMC->>RedfishService: POST /UpdateService SimpleUpdate
    RedfishService-->>VendorBMC: 200/202 + Location/Body
    VendorBMC->>VendorBMC: extract task monitor URI (taskMonitorURIFn)
    VendorBMC->>RedfishService: GET taskURI (poll)
    RedfishService-->>VendorBMC: task response
    VendorBMC->>VendorBMC: parse task details (taskMonitorDetailsFn)
    VendorBMC-->>Client: return task info / completion status
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

api-change

Suggested reviewers

  • xkonni
  • stefanhipfel
  • nagadeesh-nagaraja
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is minimal and incomplete. It only contains 'Fixes #688' without explaining the actual changes, implementation approach, or impact summary required by the template. Expand the description to include 'Proposed Changes' section with bullet points covering the refactoring strategy, key files modified, and any breaking changes or migration notes.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Refactor BMC interface to support vendor-specific implementations' clearly and concisely summarizes the main change—moving from a monolithic RedfishBMC to vendor-specific implementations with a shared base.
Linked Issues check ✅ Passed The PR implementation successfully fulfills all primary objectives from issue #688: RedfishBMC refactored to RedfishBaseBMC with vendor-specific implementations (Dell, HPE, Lenovo, Supermicro), manufacturer detection in factory, shared OEM helpers (oem_helpers.go), and base/kube clients adapted to new structure.
Out of Scope Changes check ✅ Passed All changes are directly related to the stated refactoring objectives. Removals of OEM package abstractions (oem.go, dell.go, hpe.go, lenovo.go, helpers.go) and helper functions are part of the consolidation into vendor files as intended by the issue.
Docstring Coverage ✅ Passed Docstring coverage is 90.91% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch enh/bmc-refactoring

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
bmc/redfish.go (1)

890-903: ⚠️ Potential issue | 🟡 Minor

Dell special characters contain doubled %% — likely a typo.

Line 892: "!#$%%&()*.?-@[]^_{}|~+="contains%%which produces two%characters in the charset. This doubles the probability of selecting%during password generation. If a single%` was intended, remove the duplicate.

🔧 Proposed fix (if single `%` was intended)
 	ManufacturerDell: {
-		SpecialChars: "!#$%%&()*.?-@[]^_`{}|~+=",
+		SpecialChars: "!#$%&()*.?-@[]^_`{}|~+=",
 	},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bmc/redfish.go` around lines 890 - 903, The Dell entry in
manufacturerPasswordConfigs (key ManufacturerDell) has a duplicated percent sign
in its SpecialChars string ("!#$%%&()*.?-@[]^_`{}|~+="), which will bias
password generation toward '%'—remove the extra '%' so the SpecialChars contains
a single '%' character; update the ManufacturerDell value in the
manufacturerPasswordConfigs map (the ManufacturerDell/ManufacturerPasswordConfig
entry) accordingly.
🧹 Nitpick comments (6)
bmc/redfish_lenovo.go (1)

83-142: Complex task-to-job parsing — consider extracting shared logic.

The lenovoParseTaskDetails and hpeParseTaskDetails (in redfish_hpe.go) share significant structural overlap: read body → unmarshal task → check/transform task state. The Lenovo-specific part (OperationTransitionedToJob handling) is unique, but the boilerplate read-unmarshal-return pattern could be extracted into a shared helper to reduce duplication across vendors.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bmc/redfish_lenovo.go` around lines 83 - 142, Extract the common "read body →
unmarshal into *redfish.Task → basic post-unmarshal checks" logic used by
lenovoParseTaskDetails and hpeParseTaskDetails into a shared helper (e.g.,
readAndUnmarshalTask(ctx, resp *http.Response) (*redfish.Task, []byte, error) or
parseTaskBody) that returns the parsed *redfish.Task and the raw body for
vendor-specific handling; then refactor LenovoRedfishBMC.lenovoParseTaskDetails
to call that helper, keep only the vendor-specific OperationTransitionedToJob
handling (the GET of msg.MessageArgs[0], job unmarshalling and mapping fields
into a redfish.Task) and return the resulting task, and update
hpeParseTaskDetails to use the same helper so the duplicated boilerplate is
removed.
bmc/redfish_kube.go (1)

322-329: Two different checkAttributes functions coexist — potential confusion.

Line 193 calls r.checkAttributes(attrs, filtered) (method on RedfishBaseBMC, accepting map[string]RegistryEntryAttributes for BIOS), while Line 328 calls the package-level checkAttributes(attrs, filtered) (accepting map[string]redfish.Attribute for BMC). Both are correct, but the naming overlap could cause confusion during future maintenance. Consider renaming the package-level function (e.g., checkBMCAttributes) to distinguish it from the BIOS variant.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bmc/redfish_kube.go` around lines 322 - 329, The package-level function
checkAttributes that accepts map[string]redfish.Attribute should be renamed to
checkBMCAttributes to avoid confusion with the RedfishBaseBMC.checkAttributes
method; update its definition and all call sites (including
RedfishKubeBMC.CheckBMCAttributes which currently calls checkAttributes and any
other callers), and ensure imports/signatures remain the same (refer to
RedfishKubeBMC.CheckBMCAttributes, getFilteredBMCRegistryAttributes, and the
RedfishBaseBMC.checkAttributes method to locate the related code paths).
bmc/redfish_dell.go (4)

413-427: UpgradeBiosVersion and UpgradeBMCVersion have identical implementations (same for the task getters).

This appears intentional for Dell iDRAC where BIOS and BMC upgrades follow the same Redfish path. A brief inline comment would help future maintainers understand this is by design and not a copy-paste oversight.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bmc/redfish_dell.go` around lines 413 - 427,
UpgradeBiosVersion/UpgradeBMCVersion and their task getters currently call the
same helpers with identical implementations, which looks like accidental
duplication; add a concise inline comment in each of the methods
UpgradeBiosVersion, UpgradeBMCVersion, GetBiosUpgradeTask, and GetBMCUpgradeTask
indicating that the duplication is intentional because Dell iDRAC uses the same
Redfish path/flow for BIOS and BMC updates, so they deliberately share the same
helpers (upgradeVersion/getUpgradeTask with dellBuildRequestBody,
dellExtractTaskMonitorURI, dellParseTaskDetails) to prevent future maintainers
from refactoring them away.

128-136: Attribute appended even on fetch failure — harmless but misleading.

When getObjFromUri fails (line 130-131), the partially-initialized bmcDellAttribute is still appended on line 135. This is ultimately discarded (lines 137-139 return nil on error), but a continue after appending the error would make the intent clearer.

♻️ Suggested improvement
 		bmcDellAttribute := &dellAttributes{}
 		eTag, err := r.getObjFromUri(data.String(), bmcDellAttribute)
 		if err != nil {
 			errs = append(errs, err)
+			continue
 		}
 		bmcDellAttribute.Etag = eTag
 		bmcDellAttributes = append(bmcDellAttributes, *bmcDellAttribute)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bmc/redfish_dell.go` around lines 128 - 136, In the loop over
tempData.DellOEMData.DellLinkAttributes, avoid appending a partially-initialized
bmcDellAttribute when r.getObjFromUri returns an error: after you append err to
errs in the error branch (the block handling err from getObjFromUri), add a
continue so bmcDellAttributes is only appended on successful fetch; reference
the variables and functions bmcDellAttribute, getObjFromUri, errs and
bmcDellAttributes to locate the change.

76-76: Go naming convention: UriURI.

Per Go conventions, acronyms in identifiers should be all-caps. Consider renaming getObjFromUri to getObjFromURI.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bmc/redfish_dell.go` at line 76, Rename the method getObjFromUri to use the
Go acronym convention getObjFromURI on the DellRedfishBMC type, update the
function signature and all internal references/call sites to call getObjFromURI,
and ensure any interface implementations or tests referencing getObjFromUri are
updated as well; search for the symbol getObjFromUri and replace with
getObjFromURI (keeping the receiver DellRedfishBMC and parameter/return types
unchanged).

99-108: getManagerForOEM is fetched redundantly in some flows.

For instance, SetBMCAttributesImmediately calls getCurrentBMCSettingAttribute() (which calls getManagerForOEM() internally) and then calls getManagerForOEM() again on line 290. Consider caching or passing the manager to avoid repeated remote calls for the same data within a single operation.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bmc/redfish_dell.go` around lines 99 - 108, getManagerForOEM is being called
multiple times in a single operation (e.g., SetBMCAttributesImmediately calls
getCurrentBMCSettingAttribute which calls getManagerForOEM, then calls
getManagerForOEM again), causing redundant remote calls; refactor to obtain the
Manager once and reuse it by either (a) changing getCurrentBMCSettingAttribute
to accept a *redfish.Manager parameter so callers like
SetBMCAttributesImmediately can pass the already-fetched manager, or (b) add a
short-lived cached field on DellRedfishBMC (e.g., lastManager with a
nonce/timestamp) used within the scope of the operation to return the same
manager instance for subsequent getManagerForOEM calls; update
SetBMCAttributesImmediately, getCurrentBMCSettingAttribute, and getManagerForOEM
accordingly to accept/return and use the shared manager to eliminate the
duplicate remote call.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@bmc/oem_helpers.go`:
- Around line 190-195: In the loop over attrs in the function that parses
HTTP-style attributes (the for attr, value := range attrs block), you append an
error when parts := strings.Fields(attr) yields len(parts) != 2 but then still
access parts[1], causing a panic on malformed input; fix this by adding a
continue immediately after appending the error so the iteration skips accessing
parts[1] (same pattern as must be applied to the httpBasedGetBMCSettingAttribute
handling of attrs).
- Around line 137-142: The loop over attributes splits keys into parts and
appends an error when len(parts) != 2, but execution falls through and still
calls c.Get(parts[1]) causing an index-out-of-range panic; in the loop that
iterates "for key, data := range attributes" (where parts := strings.Fields(key)
is computed and c.Get(parts[1]) is later called), add an early continue
immediately after appending the validation error so the code skips using parts
when the format is invalid.
- Around line 196-201: The code unsafely asserts value.(string) before
json.Unmarshal, which will panic for non-string attribute values; update the
block around value, valueMap and json.Unmarshal to first use the comma-ok form
to detect whether value is a string (e.g., vStr, ok := value.(string)); if it is
a string, unmarshal vStr as before, otherwise convert non-string values to a
JSON string safely (e.g., marshal the value into bytes) and then unmarshal or
handle accordingly; ensure errors appended to errs (the fmt.Errorf call) include
the original value and keep the same context (parts[1]) so no panics occur for
ints/bools/maps.
- Around line 152-157: In httpBasedGetBMCSettingAttribute the resp.Body.Close()
is deferred inside the loop which delays closing until function exit; change
this to close the body immediately after reading it with io.ReadAll (i.e., call
resp.Body.Close() right after respRawBody is obtained and before any
continue/processing), remove the in-loop defer, and ensure resp is still
referenced only after the body is closed to avoid resource leaks.

In `@bmc/redfish_dell.go`:
- Around line 150-157: In the loop over registries in the function containing
the ManagerAttributeRegistry handling, avoid indexing into registry.Location
without checking length: before using registry.Location[0].URI (the access
inside the getObjFromUri call), ensure len(registry.Location) > 0 and handle the
empty-case (e.g., skip this registry or return a descriptive error) so the code
no longer panics when Location is empty; update the block that references
registry.Location[0].URI accordingly.
- Around line 243-259: The tBMCSetting variable is declared once and reused
across iterations of the loop over bmcAttrValues, causing its Attributes map to
persist and leak data between iterations; to fix, remove the outer declaration
of tBMCSetting and instead declare a fresh local tBMCSetting (same struct type
with Attributes redfish.SettingsAttributes) inside the for _, bmcAttrValue :=
range bmcAttrValues loop immediately before calling r.getObjFromUri so each
iteration unmarshals into a new struct, preventing stale map entries and
eliminating false duplicate detections when merging into
mergedPendingBMCAttributes.
- Line 212: The comparison at the enumeration check in redfish_dell.go
incorrectly lowercases entry.Type then compares to
redfish.EnumerationAttributeType, so it never matches; change the comparison to
a case-insensitive equality (use strings.EqualFold) when checking entry.Type
against redfish.EnumerationAttributeType (the code around the if that currently
reads strings.ToLower(string(entry.Type)) ==
string(redfish.EnumerationAttributeType)), so enumeration attributes hit the
enumeration branch and use the enumeration lookup logic for entry.Type and
related handling.

In `@bmc/redfish_hpe.go`:
- Around line 96-107: The current code in the redfish_hpe.go path unmarshals
into tTask and then accesses tTask.Error.ExtendedInfo[0]["MessageId"] directly
which can panic if Error is nil or ExtendedInfo is empty; update the
post-unmarshal logic in the block after json.Unmarshal so it first checks that
tTask.Error is non-nil, len(tTask.Error.ExtendedInfo) > 0 and that the map
contains the "MessageId" key (and is a string) before inspecting it, and if
those checks fail return a clear error (instead of indexing) — modify the
conditional around the ExtendedInfo access (the check that sets
task.TaskState/PercentComplete/TaskStatus and returns task,nil) to use these
guards and fall back to the existing error return when missing.

---

Outside diff comments:
In `@bmc/redfish.go`:
- Around line 890-903: The Dell entry in manufacturerPasswordConfigs (key
ManufacturerDell) has a duplicated percent sign in its SpecialChars string
("!#$%%&()*.?-@[]^_`{}|~+="), which will bias password generation toward
'%'—remove the extra '%' so the SpecialChars contains a single '%' character;
update the ManufacturerDell value in the manufacturerPasswordConfigs map (the
ManufacturerDell/ManufacturerPasswordConfig entry) accordingly.

---

Nitpick comments:
In `@bmc/redfish_dell.go`:
- Around line 413-427: UpgradeBiosVersion/UpgradeBMCVersion and their task
getters currently call the same helpers with identical implementations, which
looks like accidental duplication; add a concise inline comment in each of the
methods UpgradeBiosVersion, UpgradeBMCVersion, GetBiosUpgradeTask, and
GetBMCUpgradeTask indicating that the duplication is intentional because Dell
iDRAC uses the same Redfish path/flow for BIOS and BMC updates, so they
deliberately share the same helpers (upgradeVersion/getUpgradeTask with
dellBuildRequestBody, dellExtractTaskMonitorURI, dellParseTaskDetails) to
prevent future maintainers from refactoring them away.
- Around line 128-136: In the loop over tempData.DellOEMData.DellLinkAttributes,
avoid appending a partially-initialized bmcDellAttribute when r.getObjFromUri
returns an error: after you append err to errs in the error branch (the block
handling err from getObjFromUri), add a continue so bmcDellAttributes is only
appended on successful fetch; reference the variables and functions
bmcDellAttribute, getObjFromUri, errs and bmcDellAttributes to locate the
change.
- Line 76: Rename the method getObjFromUri to use the Go acronym convention
getObjFromURI on the DellRedfishBMC type, update the function signature and all
internal references/call sites to call getObjFromURI, and ensure any interface
implementations or tests referencing getObjFromUri are updated as well; search
for the symbol getObjFromUri and replace with getObjFromURI (keeping the
receiver DellRedfishBMC and parameter/return types unchanged).
- Around line 99-108: getManagerForOEM is being called multiple times in a
single operation (e.g., SetBMCAttributesImmediately calls
getCurrentBMCSettingAttribute which calls getManagerForOEM, then calls
getManagerForOEM again), causing redundant remote calls; refactor to obtain the
Manager once and reuse it by either (a) changing getCurrentBMCSettingAttribute
to accept a *redfish.Manager parameter so callers like
SetBMCAttributesImmediately can pass the already-fetched manager, or (b) add a
short-lived cached field on DellRedfishBMC (e.g., lastManager with a
nonce/timestamp) used within the scope of the operation to return the same
manager instance for subsequent getManagerForOEM calls; update
SetBMCAttributesImmediately, getCurrentBMCSettingAttribute, and getManagerForOEM
accordingly to accept/return and use the shared manager to eliminate the
duplicate remote call.

In `@bmc/redfish_kube.go`:
- Around line 322-329: The package-level function checkAttributes that accepts
map[string]redfish.Attribute should be renamed to checkBMCAttributes to avoid
confusion with the RedfishBaseBMC.checkAttributes method; update its definition
and all call sites (including RedfishKubeBMC.CheckBMCAttributes which currently
calls checkAttributes and any other callers), and ensure imports/signatures
remain the same (refer to RedfishKubeBMC.CheckBMCAttributes,
getFilteredBMCRegistryAttributes, and the RedfishBaseBMC.checkAttributes method
to locate the related code paths).

In `@bmc/redfish_lenovo.go`:
- Around line 83-142: Extract the common "read body → unmarshal into
*redfish.Task → basic post-unmarshal checks" logic used by
lenovoParseTaskDetails and hpeParseTaskDetails into a shared helper (e.g.,
readAndUnmarshalTask(ctx, resp *http.Response) (*redfish.Task, []byte, error) or
parseTaskBody) that returns the parsed *redfish.Task and the raw body for
vendor-specific handling; then refactor LenovoRedfishBMC.lenovoParseTaskDetails
to call that helper, keep only the vendor-specific OperationTransitionedToJob
handling (the GET of msg.MessageArgs[0], job unmarshalling and mapping fields
into a redfish.Task) and return the resulting task, and update
hpeParseTaskDetails to use the same helper so the duplicated boilerplate is
removed.

Comment thread bmc/oem_helpers.go
Comment thread bmc/oem_helpers.go Outdated
Comment thread bmc/oem_helpers.go
Comment thread bmc/oem_helpers.go
Comment thread bmc/redfish_dell.go
Comment thread bmc/redfish_dell.go Outdated
Comment thread bmc/redfish_dell.go Outdated
Comment thread bmc/redfish_hpe.go
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
bmc/redfish.go (2)

888-901: ⚠️ Potential issue | 🟡 Minor

%% in Dell's SpecialChars results in two % characters in the password pool.

In a Go string literal %% is two literal percent signs, not an escape sequence. This gives % twice the probability of being chosen during random fill compared to all other special characters. Dell likely intends a single %.

🐛 Proposed fix
-	ManufacturerDell: {
-		SpecialChars: "!#$%%&()*.?-@[]^_`{}|~+=",
-	},
+	ManufacturerDell: {
+		SpecialChars: "!#$%&()*.?-@[]^_`{}|~+=",
+	},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bmc/redfish.go` around lines 888 - 901, The Dell entry in
manufacturerPasswordConfigs uses "%%" in the SpecialChars string which yields
two '%' characters in the character pool; update the ManufacturerDell
SpecialChars value in the manufacturerPasswordConfigs map (the ManufacturerDell
key / ManufacturerPasswordConfig.SpecialChars) to use a single '%' instead of
"%%" so '%' has the same probability as other special characters.

512-517: ⚠️ Potential issue | 🔴 Critical

Potential panic: registry.Location[0] accessed without bounds check.

If a BiosAttributeRegistry entry has an empty Location slice, line 514 will panic with an index-out-of-range error. This is the same class of bug previously fixed in bmc/redfish_dell.go.

🐛 Proposed fix
 	for _, registry := range registries {
 		if strings.Contains(registry.ID, "BiosAttributeRegistry") {
+			if len(registry.Location) == 0 {
+				return nil, fmt.Errorf("BiosAttributeRegistry %q has no Location entries", registry.ID)
+			}
 			if err := registry.Get(r.client, registry.Location[0].URI, biosRegistry); err != nil {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bmc/redfish.go` around lines 512 - 517, The loop over registries accesses
registry.Location[0].URI without checking that registry.Location has at least
one element; update the loop in the registries iteration (the block that checks
if strings.Contains(registry.ID, "BiosAttributeRegistry")) to first verify
len(registry.Location) > 0 (or that registry.Location != nil and len(...)>0)
before using registry.Location[0].URI, and handle the empty-case by either
skipping that registry or returning a clear error; ensure the Get(r.client,
registry.Location[0].URI, biosRegistry) call only executes when the location is
present.
🧹 Nitpick comments (1)
bmc/redfish.go (1)

124-129: Consider logging a warning when manufacturer detection fails and falls back to base.

When getSystemManufacturer errors, base.manufacturer is "". Subsequent "not supported" errors will show manufacturer "", which makes debugging harder. An optional structured log warning at fallback would improve observability.

♻️ Proposed improvement
 	manufacturer, err := base.getSystemManufacturer()
 	if err != nil {
-		// If we can't determine the manufacturer (e.g. no systems yet during
-		// endpoint discovery), fall back to the base implementation.
+		ctrl.LoggerFrom(ctx).V(1).Info("Could not detect manufacturer, falling back to base BMC", "error", err)
 		return base, nil
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bmc/redfish.go` around lines 124 - 129, When base.getSystemManufacturer()
returns an error and you fall back to returning base (whose base.manufacturer
will be empty), emit a structured warning including the error and a note that
you're falling back so debugging shows why manufacturer is blank; update the
error path in the block that calls base.getSystemManufacturer() to log the error
(e.g., using the package's logger: log.Warnf/log.Warn or processLogger.Warn)
with the error and that base.manufacturer is empty, then return base, nil.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@bmc/redfish_hpe.go`:
- Around line 60-74: hpeExtractTaskMonitorURI currently returns an empty string
on success if the JSON lacks TaskMonitor and does not check the HTTP Location
header; update the function (hpeExtractTaskMonitorURI) so that after
unmarshalling you check if tResp.TaskMonitor is empty and if so attempt to
extract the URI from response.Header.Get("Location") (use that value if
non-empty), and if both are empty return a clear error instead of nil; keep
existing read/unmarshal error handling but ensure the final success path only
returns nil error when a non-empty monitor URI is found.
- Line 104: Replace the use of ptr.To when setting task.PercentComplete with
gofish.ToRef to match the project's pointer type convention: locate the
assignment to task.PercentComplete in the redfish_hpe.go code and change the
pointer creation from ptr.To(uint(100)) to gofish.ToRef(uint(100)) so the
resulting pointer type matches other mockup usage (see task.PercentComplete and
the gofish.ToRef helper).

In `@bmc/redfish_lenovo.go`:
- Around line 66-80: lenovoExtractTaskMonitorURI currently returns ("", nil)
when the response lacks the `@odata.id`, causing upgradeVersion (which only checks
err != nil) to treat an empty URI as success; modify lenovoExtractTaskMonitorURI
to validate tResp.TaskMonitor after unmarshalling and return a descriptive
non-nil error (e.g., "empty task monitor URI" or "missing `@odata.id` in
response") when it is empty so callers like upgradeVersion receive an error
instead of an empty string and can fail fast; keep the error message descriptive
and include context that this originated from lenovoExtractTaskMonitorURI.

---

Outside diff comments:
In `@bmc/redfish.go`:
- Around line 888-901: The Dell entry in manufacturerPasswordConfigs uses "%%"
in the SpecialChars string which yields two '%' characters in the character
pool; update the ManufacturerDell SpecialChars value in the
manufacturerPasswordConfigs map (the ManufacturerDell key /
ManufacturerPasswordConfig.SpecialChars) to use a single '%' instead of "%%" so
'%' has the same probability as other special characters.
- Around line 512-517: The loop over registries accesses
registry.Location[0].URI without checking that registry.Location has at least
one element; update the loop in the registries iteration (the block that checks
if strings.Contains(registry.ID, "BiosAttributeRegistry")) to first verify
len(registry.Location) > 0 (or that registry.Location != nil and len(...)>0)
before using registry.Location[0].URI, and handle the empty-case by either
skipping that registry or returning a clear error; ensure the Get(r.client,
registry.Location[0].URI, biosRegistry) call only executes when the location is
present.

---

Nitpick comments:
In `@bmc/redfish.go`:
- Around line 124-129: When base.getSystemManufacturer() returns an error and
you fall back to returning base (whose base.manufacturer will be empty), emit a
structured warning including the error and a note that you're falling back so
debugging shows why manufacturer is blank; update the error path in the block
that calls base.getSystemManufacturer() to log the error (e.g., using the
package's logger: log.Warnf/log.Warn or processLogger.Warn) with the error and
that base.manufacturer is empty, then return base, nil.

Comment thread bmc/redfish_hpe.go
Comment thread bmc/redfish_hpe.go Outdated
Comment thread bmc/redfish_lenovo.go
Comment thread bmc/redfish_kube.go
Comment thread bmc/redfish_local.go
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Refactor BMC interface to support vendor-specific implementations

3 participants