运维笔记

Redfish API 报错 400/500?手撕 iLO 和 iDRAC 的诡异错误码修复实录

Infrastructure 技术可视化

先说说这破事儿是怎么来的

上个月我们搞了个自动化运维脚本,用 Redfish API 批量给新到的 HPE Gen11 服务器做初始配置。结果翻车了。

两台 Gen11,一台 iLO 6 v1.53,一台 iLO 6 v1.66,配置一模一样。脚本跑过去,老的稳如老狗,新的疯狂报 HTTP 400 Bad Request。查了半天文档,Reddit 上也有兄弟在骂这事儿——“Redfish api drives return error” 那个帖子我翻了三遍。

后来发现不是脚本的问题,是 Redfish 规范里的一些坑,加上厂商实现上的微妙差异。今天就把我们踩过的坑、怎么定位的、最终怎么修的,全写出来。

症状描述:你大概率也会遇到

场景一:PATCH 请求改密码,报 HTTP 400

curl -X PATCH \
  -H "Content-Type: application/json" \
  -H "X-Auth-Token: $TOKEN" \
  -d '{"Password": "NewP@ss123"}' \
  https://bmc-ip/redfish/v1/AccountService/Accounts/1

返回:

{
  "error": {
    "code": "Base.1.13.GeneralError",
    "message": "A general error has occurred. See ExtendedInfo for more information.",
    "@Message.ExtendedInfo": [
      {
        "MessageId": "Base.1.13.PropertyValueNotInList",
        "Message": "The value 'NewP@ss123' for the property 'Password' is not in the list of acceptable values.",
        "Severity": "Warning"
      }
    ]
  }
}

场景二:GET 请求读网卡信息,报 HTTP 500

curl -s -H "X-Auth-Token: $TOKEN" \
  https://bmc-ip/redfish/v1/Chassis/1/NetworkAdapters

返回 500 Internal Server Error,没有任何 ExtendedInfo。这就是最恶心的那种——服务端直接炸了,连个错误码都不给。

场景三:设置一次性启动项为 PXE,报 HTTP 400

这个问题在 HPE ProLiant DL380 Gen10 上特别常见。Reddit 上有人发帖说 redfish_command 模块跑 PATCH 到 Boot 资源时,返回 HTTP Error 400

根因分析:到底谁在搞鬼

我们把这三个场景拆开看,背后的原因其实就几类:

1. 密码策略冲突(场景一)

这个最坑。Redfish 标准对 Password 属性没有强制校验规则,但 iLO 和 iDRAC 各自有密码复杂度要求。你传一个在标准看来合法的字符串,BMC 的密码策略校验器直接给拒了。

更坑的是错误信息。PropertyValueNotInList 这个 MessageId 意思是"值不在可接受列表中",但你传的是字符串,不是枚举值。这他妈是厂商把错误类型用错了——应该用 PropertyValueFormatError 或者 PropertyValueModified 才对。

2. 固件 BUG 导致 Internal Server Error(场景二)

HTTP 500 在 Redfish 里通常意味着 BMC 内部处理请求时崩了。我们抓包发现,对 /Chassis/1/NetworkAdapters 的 GET 请求,iDRAC 在序列化响应时,某个网卡的健康状态字段是 null,但 JSON 序列化器没做 null 检查,直接抛了 NPE(空指针异常)。

这就是典型的固件质量问题。DMTF 的 Redfish 规范里明确说了——服务端不应该返回 500,应该返回带 ExtendedInfo 的 4xx。但厂商不按规矩来,你能怎么办?

3. Boot 资源属性校验过于严格(场景三)

设置一次性启动项时,你传的 JSON body 里可能包含了 BootSourceOverrideTargetBootSourceOverrideEnabled。问题在于,某些 iLO 固件版本要求这两个属性必须同时出现,且 BootSourceOverrideEnabled 必须先于 BootSourceOverrideTarget 被处理。

如果你只传了 BootSourceOverrideTarget: "Pxe" 没传 BootSourceOverrideEnabled,或者顺序不对,iLO 直接返回 400。

修复步骤:从踩坑到填坑

第一步:开启 Redfish 调试日志(定位问题)

# 在 iDRAC 上启用 Redfish 调试
racadm set iDRAC.Redfish.DebugLevel 2
racadm set iDRAC.Redfish.LogToFile Enabled

# 在 iLO 上
# 通过 SSH 登录 iLO
ssh Administrator@bmc-ip
> set /map1/dump1/flag OemRHD_EnableDebugLogs 1
> set /map1/dump1/flag OemRHD_EnableVerboseLogging 1

然后重现问题,去 BMC 的日志里捞错误堆栈。我们就是在日志里看到了那个 NPE,才确定是固件 BUG。

第二步:修复密码修改的 PATCH 请求

不要直接传明文密码。Redfish 规范里有个更好的做法——使用 ChangePassword 动作(Action),而不是直接 PATCH 属性。

# 正确做法:使用 ChangePassword 动作
curl -X POST \
  -H "Content-Type: application/json" \
  -H "X-Auth-Token: $TOKEN" \
  -d '{
    "OldPassword": "oldPassword12",
    "NewPassword": "NewP@ss123!"
  }' \
  https://bmc-ip/redfish/v1/AccountService/Actions/AccountService.ChangePassword

如果厂商不支持 ChangePassword 动作(有些老固件确实没有),那就得先 GET 出密码策略,再构造合法的密码:

# 先获取密码策略
curl -s -H "X-Auth-Token: $TOKEN" \
  https://bmc-ip/redfish/v1/AccountService | jq '.Oem'

# 看返回里的 MinPasswordLength、PasswordPattern 等字段
# 然后根据规则生成密码

第三步:绕过 Internal Server Error(场景二)

对于固件 BUG 导致的 500,我们的方案是降级访问路径:

# 不要直接访问 /Chassis/1/NetworkAdapters
# 改走 /Systems/1/NetworkInterfaces
curl -s -H "X-Auth-Token: $TOKEN" \
  https://bmc-ip/redfish/v1/Systems/1/NetworkInterfaces | jq '.Members[] | .@odata.id'

或者用 OData 查询参数跳过有问题的属性:

# 只请求需要的字段,避开有问题的序列化路径
curl -s -H "X-Auth-Token: $TOKEN" \
  "https://bmc-ip/redfish/v1/Chassis/1/NetworkAdapters?\$select=Id,Name,Status"

我们最终给厂商提了 ticket,两周后新固件修了这个问题。但在那之前,这个 workaround 让我们能继续干活。

第四步:修复一次性启动项设置(场景三)

# 正确做法:同时传两个属性,且按顺序
curl -X PATCH \
  -H "Content-Type: application/json" \
  -H "X-Auth-Token: $TOKEN" \
  -d '{
    "BootSourceOverrideEnabled": "Once",
    "BootSourceOverrideTarget": "Pxe"
  }' \
  https://bmc-ip/redfish/v1/Systems/1/BootOptions/1

注意 BootSourceOverrideEnabled 在前,BootSourceOverrideTarget 在后。HPE iLO 对这个顺序敏感,Dell iDRAC 不敏感。这是厂商实现差异。

第五步:统一错误处理逻辑

在脚本里加一个通用的错误重试和降级逻辑:

def redfish_patch(url, payload, token, retries=3):
    for attempt in range(retries):
        resp = requests.patch(url, json=payload, headers={"X-Auth-Token": token})
        if resp.status_code == 200:
            return resp.json()
        elif resp.status_code == 400:
            # 解析 ExtendedInfo
            msgs = resp.json().get("error", {}).get("@Message.ExtendedInfo", [])
            for msg in msgs:
                mid = msg.get("MessageId", "")
                if "PropertyValueNotInList" in mid:
                    # 可能是密码策略问题,尝试获取策略后重试
                    policy = get_password_policy(url, token)
                    payload["Password"] = generate_valid_password(policy)
                elif "ActionNotSupported" in mid:
                    # 降级到 PATCH 属性
                    return fallback_patch(url, payload, token)
        elif resp.status_code == 500:
            # 固件 BUG,等待后重试或走备用路径
            time.sleep(5)
            url = find_alternative_endpoint(url)
    raise Exception("Redfish API 重试耗尽")

各厂商 Redfish 实现对比

特性HPE iLO 6Dell iDRAC 9Lenovo XClarity
PATCH 密码支持✅ 支持 ChangePassword 动作✅ 支持直接 PATCH✅ 支持 ChangePassword 动作
密码策略暴露通过 Oem.Hpe.PasswordRules通过 Oem.Dell.DellPasswordService通过 Oem.Lenovo.PasswordPolicy
Boot 属性顺序敏感✅ 是❌ 否❌ 否
500 错误频率低(固件 1.60+)中(特定端点)
ExtendedInfo 完整性中(有时缺失)
认证方式Session + TokenSession + Token + BasicSession + Token

FAQ

什么是 API 错误码?

HTTP 状态码。200 表示成功,4xx 是客户端问题(你传的数据不对),5xx 是服务端问题(BMC 炸了)。Redfish 的扩展信息在 @Message.ExtendedInfo 里,比裸 HTTP 状态码有用得多。

Redfish API 是什么?

DMTF 定义的管理接口标准。用 RESTful HTTP + JSON,替代了老掉牙的 IPMI。支持从服务器到机架级管理。说白了就是 BMC 的 REST API。

什么情况下会返回 500 Internal Server Error?

通常是 BMC 固件在处理请求时崩溃了。比如 JSON 序列化时遇到 null 字段没做保护,或者内部状态机走到了未预期的分支。我们的经验是——先升级固件到最新版,能解决 80% 的 500 错误。

如何启用 Redfish 服务?

  • iDRAC: 网页进 Overview > iDRAC Settings > Network > Services,勾选 Redfish 启用。
  • iLO: 网页进 Administration > Access Settings > Services,启用 Redfish REST API。
  • 命令行: racadm set iDRAC.Redfish.Enable 1(Dell)或 ssh iLO 执行 set /map1/config/RedfishEnabled 1(HPE)。

最后说两句

Redfish 是个好协议,但厂商实现参差不齐。我们踩的这些坑,说到底都是固件质量和规范遵守程度的问题。

如果你也在用 Redfish 做自动化,我建议:

  1. 永远先升级 BMC 固件到最新版。我们遇到的 500 错误在新固件里修了。
  2. 别信厂商的文档——抓包看实际交互才是真理。
  3. 对每个厂商做单独的适配层。一劳永逸的通用客户端?不存在的。

Reddit 上那个问 “Redfish api drives return error” 的哥们,最后也是升级固件解决的。所以第一件事永远是:升级固件