fix(webui): trust IPMI FRU readback over ipmitool's exit code
`ipmitool fru edit` frequently exits non-zero after a field resize (shrinking/growing a string shifts every later offset in the FRU record) even though the write itself landed correctly on the BMC - the failure is in ipmitool's own post-write re-parse, not the write. bee was treating that exit code as authoritative and marking the task failed even when the field was actually written. runIPMIFRUWriteTask now re-reads the FRU on a non-zero exit and compares the target field's actual value before deciding the task failed, logging which path it took either way. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
198567dffe
commit
7aa276320b
@@ -210,8 +210,37 @@ func runIPMIFRUWriteTask(ctx context.Context, j *jobState, exportDir string, p t
|
||||
j.append(fmt.Sprintf("Setting %s (%s %d) = %q", c.Name, c.Area, c.Index, c.Value))
|
||||
cmd := exec.CommandContext(ctx, "ipmitool", "fru", "edit", "0", "field", c.Area, fmt.Sprintf("%d", c.Index), c.Value)
|
||||
if err := streamCmdJob(j, cmd); err != nil {
|
||||
return fmt.Errorf("fru edit %s %d: %w", c.Area, c.Index, err)
|
||||
// ipmitool's `fru edit` frequently exits non-zero after a field
|
||||
// resize (shrinking/growing a string shifts every later offset in
|
||||
// the FRU record) even though the write itself landed correctly -
|
||||
// the failure is in ipmitool's own post-write re-parse, not the
|
||||
// BMC write. Read the FRU back and trust the BMC's own data over
|
||||
// ipmitool's exit code before declaring the task failed.
|
||||
ok, verifyErr := verifyFRUField(ctx, c.Area, c.Index, c.Value)
|
||||
if verifyErr != nil {
|
||||
j.append("Readback verification failed: " + verifyErr.Error())
|
||||
return fmt.Errorf("fru edit %s %d: %w", c.Area, c.Index, err)
|
||||
}
|
||||
if !ok {
|
||||
return fmt.Errorf("fru edit %s %d: %w", c.Area, c.Index, err)
|
||||
}
|
||||
j.append(fmt.Sprintf("ipmitool exited with an error, but readback confirms %s %d was written correctly - continuing", c.Area, c.Index))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// verifyFRUField re-reads the FRU and checks whether the field at area/index
|
||||
// already holds want, independent of any exit code from a prior edit.
|
||||
func verifyFRUField(ctx context.Context, area string, index int, want string) (bool, error) {
|
||||
out, err := exec.CommandContext(ctx, "ipmitool", "fru", "print", "0").CombinedOutput()
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("fru print: %w", err)
|
||||
}
|
||||
for _, f := range parseFRUOutput(string(out)) {
|
||||
if f.Area == area && f.Index == index {
|
||||
return f.Value == want, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user