redfish接口新组件代码移植错误

问题描述

我在rackmount的代码里面开发redfish,收集日志定制化命令,我们新建了一个组件CTCC,现在在rackmount调通的代码移植到CTCC那边去,移动改动的部分,好像不行,plugin的函数,不能调用,让CtCC和rackmount保持一致,好像就可以,麻烦各位大佬看一下呢,rackmount部分代码如下:
/workspace/rackmount/interface_config/redfish/mapping_config/Managers/LogServices/LogServices.json

{

“Resources”: [

{

“Uri”: “/redfish/v1/Managers/:managerid/LogServices/CollectAllLogActionInfo”,

“Interfaces”: [

{

“Type”: “GET”,

“ResourceExist”: {

“${Statements/IsValidManagersId()}”: true

},

“Statements”: {

“IsValidManagersId”: {

“Steps”: [

{

“Type”: “Plugin”,

“Formula”: “ctcc_utils.is_valid_managers_id(Uri.managerid)”

}

]

}

},

“RspBody”: {

@odata.contextodata.context”: “/redfish/v1/$metadata#ActionInfo.Ac@odata.idionInfo”,

@odata.id”: “/redfish/v1/Managers/1/LogServices/Collect@odata.typellLogActionInfo”,

@odata.type”: “#ActionInfo.v1_0_0.ActionInfo”,

“Id”: “CollectAllLogActionInfo”,

“Name”: “Collect Log Action Info”,

“Parameters”: [

{

“Name”: “Type”,

“Required”: true,

“DataType”: “String”,

“AllowableValues”: [

“URI”

]

},

{

“Name”: “Content”,

“Required”: true,

“DataType”: “String”

}

]

}

}

]

},

{

“Uri”: “/redfish/v1/Managers/:managerid/LogServices/:logtype/Actions/Oem/{{OemIdentifier}}/LogService.ExportLog”,

“Interfaces”: [

{

“Type”: “POST”,

“LockdownAllow”: true,

“ResourceExist”: {

“${Statements/IsValidManagersId()}”: true,

“${Statements/IsValidLogType()}”: true

},

“ReqBody”: {

“Type”: “object”,

“Required”: true,

“Properties”: {

“Type”: {

“Type”: “string”,

“Required”: true,

“Validator”: [

{

“Type”: “Regex”,

“Formula”: “^(text|URI)$”

}

]

},

“Content”: {

“Type”: “string”,

“Required”: true,

“Sensitive”: true

}

}

},

“Statements”: {

“IsValidManagersId”: {

“Steps”: [

{

“Type”: “Plugin”,

“Formula”: “ctcc_utils.is_valid_managers_id(Uri.managerid)”

}

]

},

“IsValidLogType”: {

“Steps”: [

{

“Type”: “Script”,

“Formula”: “if string.lower(Uri.logtype) == ‘operatelog’ or string.lower(Uri.logtype) == ‘runlog’ or string.lower(Uri.logtype) == ‘securitylog’ then return true end return false”

}

]

},

“LogType”: {

“Steps”: [

{

“Type”: “Script”,

“Formula”: “Managers/LogServices/get_log_type.lua”

}

]

}

},

“ProcessingFlow”: [

{

“Type”: “Task”,

“Path”: “/bmc/kepler/Managers/1/LogServices/${Statements/LogType()}”,

“Interface”: “bmc.kepler.Managers.LogService”,

“Name”: “ExportLog”,

“Params”: [

“${ReqBody/Content}”,

“”

],

“Destination”: {

“TaskId”: “TaskId”

},

“PostTaskProcess”: [

{

“Type”: “ChangeOwner”,

“Params”: [

“${ReqBody/Content}”

]

}

]

}

]

}

]

},

{

“Uri”: “/redfish/v1/Managers/:managerid/LogServices/:logtype/ExportLogActionInfo”,

“Interfaces”: [

{

“Type”: “GET”,

“ResourceExist”: {

“${Statements/IsValidManagersId()}”: true,

“${Statements/IsValidLogType()}”: true

},

“Statements”: {

“IsValidManagersId”: {

“Steps”: [

{

“Type”: “Plugin”,

“Formula”: “ctcc_utils.is_valid_managers_id(Uri.managerid)”

}

]

},

“IsValidLogType”: {

“Steps”: [

{

“Type”: “Script”,

“Formula”: “if string.lower(Uri.logtype) == ‘operatelog’ or string.lower(Uri.logtype) == ‘runlog’ or string.lower(Uri.logtype) == ‘securitylog’ then return true end return false”

}

]

},

“LogType”: {

“Steps”: [

{

“Type”: “Script”,

“Formula”: “Managers/LogServices/get_lo@odata.context_type.lua”

}

]

}

},

“RspB@odata.contextdy”: {

@odata.id@odata.context”: “/redfish/v1/$metadata#ActionInfo.Actio@odata.idInfo”,

@odata.id”: “/redfish/v1/Managers/@odata.type/LogServices/${Statements/LogType()}/ExportLogActio@odata.typeInfo”,

@odata.type”: “#ActionInfo.v1_0_0.ActionInfo”,

“Id”: “ExportLogActionInfo”,

“Name”: “Export Log Action Info”,

“Parameters”: [

{

“Name”: “Type”,

“Required”: true,

“DataType”: “String”,

“AllowableValues”: [

“URI”

]

},

{

“Name”: “Content”,

“Required”: true,

“DataType”: “String”

}

],

“Oem”: {}

}

}

]

},

{

“Uri”: “/redfish/v1/Managers/:managerid/LogServices/Actions/Oem/{{OemIdentifier}}/CollectAllLog”,

“Interfaces”: [

{

“Type”: “POST”,

“Statements”: {

“IsValidManagersId”: {

“Steps”: [

{

“Type”: “Plugin”,

“Formula”: “ctcc_utils.is_valid_managers_id(Uri.managerid)”

}

]

}

},

“ResourceExist”: {

“${Statements/IsValidManagersId()}”: true

},

“ReqBody”: {

“Type”: “object”,

“Required”: true,

“Properties”: {

“Type”: {

“Type”: “string”,

“Required”: true,

“Validator”: [

{

“Type”: “Regex”,

“Formula”: “^(text|URI)$”

}

]

},

“Content”: {

“Type”: “string”,

“Required”: true,

“Sensitive”: true

}

}

},

“ProcessingFlow”: [

{

“Type”: “Task”,

“Path”: “/bmc/kepler/Managers/${Uri/managerid}/LogServices”,

“Interface”: “bmc.kepler.Managers.LogServices”,

“Name”: “Dump”,

“Params”: [

0,

“${ReqBody/Content}”

],

“Destination”: {

“TaskId”: “TaskId”

},

“PostTaskProcess”: [

{

“Type”: “ChangeOwner”,

“Params”: [

“${ReqBody/Content}”

]

}

]

}

]

}

]

},

{

“Uri”: “/redfish/v1/Managers/:managerid/LogServices/Actions/Oem/{{OemIdentifier}}/CollectAllLog.Status”,

“Interfaces”: [

{

“Type”: “GET”,

“Statements”: {

“IsValidManagersId”: {

“Steps”: [

{

“Type”: “Plugin”,

“Formula”: “ctcc_utils.is_valid_managers_id(Uri.managerid)”

}

]

},

“TaskStatusCode”: {

“Input”: “${Statements/CollectAllLogState()}”,

“Steps”: [

{

“Type”: “Switch”,

“Formula”: [

{

“Case”: “New”,

“To”: 2

},

{

“Case”: “Starting”,

“To”: 1

},

{

“Case”: “Running”,

“To”: 1

},

{

“Case”: “Suspended”,

“To”: 1

},

{

“Case”: “Interrupted”,

“To”: 1

},

{

“Case”: “Pending”,

“To”: 1

},

{

“Case”: “Stopping”,

“To”: 1

},

{

“Case”: “Completed”,

“To”: 0

},

{

“Case”: “Killed”,

“To”: 3

},

{

“Case”: “Exception”,

“To”: 3

},

{

“Case”: “Service”,

“To”: 1

},

{

“Case”: “UN”,

“To”: 2

},

{

“To”: 2

}

]

}

]

},

“StatusDescription”: {

“Input”: “${Statements/TaskStatusCode()}”,

“Steps”: [

{

“Type”: “Switch”,

“Formula”: [

{

“Case”: 0,

“To”: “succeeded”

},

{

“Case”: 1,

“To”: “running”

},

{

“Case”: 2,

“To”: “unstart”

},

{

“Case”: 3,

“To”: “failed”

},

{

“To”: “unknown”

}

]

}

]

},

“GetCollectionProgress”: {

“Input”: “${ProcessingFlow[1]/Destination/TaskIdList}”,

“Steps”: [

{

“Type”: “Expand”

},

{

“Type”: “Plugin”,

“Formula”: “ctcc_utils.get_log_collection_progress(Input)”

}

]

},

“CollectAllLogProgress”:{

“Input”: “${Statements/GetCollectionProgress()}”,

“Steps”: [

{

“Type”: “Script”,

“Formula”: “return Input.Progress”

}

]

},

“CollectAllLogState”: {

“Input”: “${Statements/GetCollectionProgress()}”,

“Steps”: [

{

“Type”: “Script”,

“Formula”: “return Input.State”

}

]

},

“CollectAllLogStartTime”: {

“Input”: “${Statements/GetCollectionProgress()}”,

“Steps”: [

{

“Type”: “Script”,

“Formula”: “return Input.StartTime”

}

]

}

},

“ResourceExist”: {

“${Statements/IsValidManagersId()}”: true

},

“ProcessingFlow”: [

{

“Type”: “List”,

“Path”: “/bmc/kepler/Managers/${Uri/managerid}/LogServices/TaskService/Tasks”,

“P@odata.idrams”: [1],

“Destination”: {

“Members”: “TaskIdList”

}

}

@odata.id],

“RspBody”: {

@odata.id”: “/redfish/v1/Ma@odata.typeagers/${Uri/managerid}/LogServices/Actions/Oem/{{OemIdentifier}}/Colle@odata.typetAllLog.Status”,

@odata.type”: “#ActionInfo.v1_0_0.ActionInfo”,

“Id”: “CollectAllLog.Status”,

“Name”: “Export Dump File Task”,

“StartTime”:“${Statements/CollectAllLogStartTime()}”,

“Oem”: {

“{{OemIdentifier}}”:{

“TaskPercentage”:“${Statements/CollectAllLogProgress()}”,

“Status”@odata.context“${Statements/TaskStatusCode()}”,

“StatusDescription”:“${Statements/S@odata.contextatusDescription()}”

}

},

@odata.context”: “/redfish/v1/$metadata#TaskService/Tasks/Members/$entity”,

“TaskState”:“${Statements/CollectAllLogState()}”

}

}

]

},

{

“Uri”: “/bmc/kepler/Managers/1/LogServices/TaskService/Tasks/:id”,

“Interfaces”: [

{

“Type”: “GET”,

“RspBody”: {

“Progress”: “${ProcessingFlow[1]/Destination/Progress}”,

“StartTime”: “${ProcessingFlow[1]/Destination/StartTime}”,

“State”: “${ProcessingFlow[1]/Destination/State}”,

“Name”: “${ProcessingFlow[1]/Destination/Name}”

},

“ProcessingFlow”: [

{

“Type”: “Property”,

“Path”: “/bmc/kepler/Managers/1/LogServices/TaskService/Tasks/${Uri/id}”,

“Interface”: “bmc.kepler.TaskService.Task”,

“Destination”: {

“Progress”: “Progress”,

“StartTime”: “StartTime”,

“State”: “State”,

“Name”: “Name”

}

}

]

}

]

}

]

}
/workspace/rackmount/interface_config/redfish/plugins/utils.lua

function m.is_valid_managers_id(id)

local path = ‘/bmc/kepler/Managers/’ .. id

local ok, rsp = pcall(mdb_service.is_valid_path, bus, path)

if not ok then

log:error(‘is_valid_managers_id failed, err(%s)’, rsp.message)

error(rsp)

end

return rsp.Result

end

-- Convert ISO 8601 datetime string to UTC timestamp

-- Input: “2024-01-18T08:00:00+08:00”

-- Output: Unix timestamp (seconds since epoch)

function m.parse_iso8601_to_timestamp(datetime_str)

– Validate input

if not datetime_str or datetime_str == “” then

log:debug(“parse_iso8601_to_timestamp: empty input, return 0”)

return 0

end

– Parse ISO 8601 format

local y, mo, d, h, mi, s, tz_sign, tz_h, tz_m =

datetime_str:match(“^(%d+)-(%d+)-(%d+)T(%d+):(%d+):(%d+)([%+%-])(%d+):(%d+)$”)

if not y then

log:error(“parse_iso8601_to_timestamp: invalid format ‘%s’”, datetime_str)

return 0

end

log:debug(“parse_iso8601_to_timestamp: input=‘%s’”, datetime_str)

– Convert to numbers

y, mo, d = tonumber(y), tonumber(mo), tonumber(d)

h, mi, s = tonumber(h), tonumber(mi), tonumber(s)

tz_h, tz_m = tonumber(tz_h), tonumber(tz_m)

– Calculate timezone offset in seconds

local tz_offset = tz_h * 3600 + tz_m * 60

if tz_sign == ‘-’ then

tz_offset = -tz_offset

end

– Get timestamp and adjust for timezone

local timestamp = utils.get_timestamp(y, mo, d, h, mi, s)

local utc_timestamp = timestamp - tz_offset

log:debug(“parse_iso8601_to_timestamp: %s%02d:%02d → UTC timestamp %d”,

tz_sign, tz_h, tz_m, utc_timestamp)

return utc_timestamp

end

-- Find the latest “Export Dump File Task” by comparing UTC timestamps

function m.get_log_collection_progress(Input)

log:debug(“get_log_collection_progress: start (input type: %s)”, type(Input))

– Default empty result

local default_result = {

Progress = 0,

StartTime = “”,

State = “”,

Name = “”

}

– Validate input

if Input == cjson.null then

log:debug(“get_log_collection_progress: input is null”)

return default_result

end

– Find latest task by UTC timestamp

local latest_task = nil

local latest_timestamp = 0

for _, task in pairs(Input) do

– Filter by task name

if task.Name == “Export Dump File Task” and task.StartTime and task.StartTime ~= “” then

local timestamp = m.parse_iso8601_to_timestamp(task.StartTime)

– Update if this is the latest

if timestamp > latest_timestamp then

latest_timestamp = timestamp

latest_task = {

Progress = task.Progress,

StartTime = task.StartTime,

State = task.State,

Name = task.Name

}

log:debug(“get_log_collection_progress: new latest task at UTC=%d”, timestamp)

end

end

end

return latest_task or default_result

end

CTCC配置
/workspace/CTCC/interface_config/redfish/config.json

然后我把rackmount的LogServices.json复制到了/workspace/CTCC/interface_config/redfish/Managers/Oem/LogServices/LogServices.json
把utils.lua复制到/workspace/CTCC/interface_config/redfish/plugins/ctcc_utils.lua

注:我都只复制的修改部分,没有完全复制

答案内容由AI生成,仅供参考:

关于CTCC组件移植Redfish日志定制命令失败的问题分析与解决方案

根据您提供的详细信息,您在将 rackmount 项目中已调试通过的 Redfish日志收集与导出功能 移植到新组件 CTCC 时,出现了 Plugin函数无法调用 的问题。以下是基于现有文档、知识图谱和配置逻辑的全面分析与解决方案。


:magnifying_glass_tilted_left: 问题核心:Plugin函数调用失败

错误表现ctcc_utils.is_valid_managers_id(Uri.managerid)ctcc_utils.get_log_collection_progress(Input) 无法执行,导致接口返回异常或 500 错误。

这表明在 CTCC 环境中,虽然您已复制了 .lua 文件和 JSON 配置文件,但 Plugin机制未被正确加载或解析,从而导致 Lua 函数不可见。


:books: 背景知识支持(来自知识库)

1. Plugin 的定位与加载路径

根据文档和知识图谱:

  • Plugin 存放路径为:
    /opt/bmc/apps/redfish/interface_config/plugins
    (如 search result #3#8 所述)
  • Formula 字段中调用方式为:PluginName.FunctionName(...),例如:
    "Formula": "ctcc_utils.is_valid_managers_id(Uri.managerid)"

2. Plugin 本质是可复用函数模块

关键说明

  • Plugin 是抽象函数供接口配置调用,属于代码实现而非纯配置。
  • 需要确保编译构建后,Lua 文件被部署到正确路径,并被 Redfish 插件系统识别。
  • 减少 Plugin 使用建议:仅用于复杂业务逻辑(见文档 chunk 4 和 8)。

:white_check_mark: 原因分析:为何“看似一致”的移植仍失败?

问题点 分析
:small_orange_diamond: 文件未通过构建系统部署 单纯手动复制文件到本地工作区不等于部署到运行环境。CTCC 必须重新构建并打包,使 ctcc_utils.lua 被复制到 /opt/bmc/apps/redfish/interface_config/plugins/
:small_orange_diamond: Plugin 目录未包含在构建范围 CTCC 的构建脚本未将 interface_config/redfish/plugins 加入镜像,则 Plugin 不会被加载。
:small_orange_diamond: 文件名/模块名不匹配 Lua 模块名必须与文件名一致。若文件名为 ctcc_utils.lua,则模块应返回 ctcc_utils 或全局注册同名 table。
:small_orange_diamond: 路径映射错误或未生效 CTCC/config.json 中,使用 SourceTarget 映射时,可能路径解析顺序有误或未触发实际文件复制。
:small_orange_diamond: 缺乏初始化或 require 机制 openUBMC 中 Plugin 是否需要在某处显式 require?若框架依赖特定命名/结构才能自动加载,则需遵循规范。

:white_check_mark: 解决方案步骤

步骤一:确认 Plugin 文件被正确构建与部署

:red_exclamation_mark: 必须确保 ctcc_utils.lua 在最终镜像中存在于以下路径:

/opt/bmc/apps/redfish/interface_config/plugins/ctcc_utils.lua

验证方法

  1. 构建并烧录 CTCC 镜像;
  2. 登录 BMC 终端;
  3. 执行:
ls /opt/bmc/apps/redfish/interface_config/plugins/

检查是否存在 ctcc_utils.lua

:cross_mark: 若不存在 → 检查 CTCC 的构建流程是否将 plugins/ 目录纳入拷贝范围。


步骤二:确保模块导出格式正确

ctcc_utils.lua 中,请确保模块以标准方式定义并返回:

local m = {}  -- 定义模块

function m.is_valid_managers_id(id)
    local path = '/bmc/kepler/Managers/' .. id
    local ok, rsp = pcall(mdb_service.is_valid_path, bus, path)
    if not ok then
        log:error('is_valid_managers_id failed, err(%s)', rsp.message)
        error(rsp)
    end
    return rsp.Result
end

function m.parse_iso8601_to_timestamp(datetime_str)
    -- 原有实现...
end

function m.get_log_collection_progress(Input)
    -- 原有实现...
end

return m  -- ⚠️ 必须返回模块

:warning: 注意:不要使用 module(...) 或全局变量定义,modern Lua practice 推荐 local m = {} return m


步骤三:检查 config.json 映射规则是否正确

当前配置示例中存在不一致问题:

:cross_mark: 问题1:大小写不一致

您的 LogServices.json 中 URI 引用了:

"/redfish/v1/Managers/:managerid/LogServices/Actions/Oem/{{OemIdentifier}}/CollectAllLog"

但在 CTCC/config.json 的 Modify 中写成了:

"#CollectAlllog"  ← 小写 log,与定义不符

:white_check_mark: 修复为

"#CollectAllLog"

保持大小写完全一致!

:cross_mark: 问题2:路径拼接错误

确认目标文件路径是否真的生成到了:

mapping_config/Managers/LogServices/LogServices.json

而不是被覆盖或忽略。

建议:

  • 使用完整路径映射;
  • 或改为直接替换整个 mapping_config 子目录。

步骤四:启用调试日志定位问题(关键手段)

参考文档 映射器接口定位指导 提供的方法:

开启 Redfish 调试日志

log_level redfish debug

然后访问相关接口,查看日志输出:

tail -f /var/log/redfish.log

:magnifying_glass_tilted_left: 关注以下关键字:

  • Plugin not found
  • cannot load module 'ctcc_utils'
  • no field package.preload['ctcc_utils']
  • Formula execution failed

这些错误直接揭示 Plugin 加载失败原因。


步骤五:验证 Plugin 是否被框架支持

:pushpin: 根据开放文档,某些 rackmount 功能仅在主仓生效,子组件如 CTCC 需显式启用 Plugin 支持

建议操作

  • 查看 CTCC/service.json 中是否声明依赖或启用了 Redfish Plugin 功能;
  • 检查 CTCCpackage.json 或构建配置中是否将 plugins 目录加入发布列表;
  • 参考 扩展对外接口 文档,确认是否执行了整包构建和版本更新。

:white_check_mark: 推荐正确移植流程

# 1. 克隆代码
git clone git@gitcode.com:openUBMC/CTCC.git

# 2. 复制必要文件
cp rackmount/interface_config/redfish/plugins/ctcc_utils.lua CTCC/interface_config/redfish/plugins/

cp rackmount/interface_config/redfish/mapping_config/Managers/LogServices/LogServices.json \
   CTCC/interface_config/redfish/mapping_config/Managers/LogServices/

# 3. 更新 service.json 版本号以触发构建
# "version": "1.2.3" → "1.2.4"

# 4. 构建组件
bingo build --stage=stable

# 5. 整包构建(更新 manifest 中 CTCC 版本后)
bingo build

# 6. 烧录并登录 BMC 验证文件存在
ls /opt/bmc/apps/redfish/interface_config/plugins/ctcc_utils.lua

:hammer_and_wrench: 附加调试建议

使用 curl 测试接口行为

curl -u admin:password https://<BMC_IP>/redfish/v1/Managers/1/LogServices/CollectAllLogActionInfo -k

观察返回是否包含 500 Internal Server Error 或具体 Lua 错误信息。

检查 Etag 或响应乱序问题(如文档提到)

PATCH 请求因响应体乱序导致 Etag 变化也可能引发问题(见文档 #3),但本例为 POST/GET,可暂排除。


:white_check_mark: 总结

项目 是否满足 建议
Plugin 文件存在? :cross_mark: 很可能未部署 构建后验证路径
模块导出正确? :warning: 需检查 使用 return m
函数命名一致? :warning: 大小写问题 修复 CollectAlllogCollectAllLog
构建流程完整? :cross_mark: 易遗漏 必须整包构建
调试日志开启? 推荐开启 查看 redfish.log

:white_check_mark: 最终结论

根本原因:您仅复制了源码文件,但未保证其经过正确构建、部署至运行路径、并在 Plugin 系统中可加载,导致 Lua 函数无法被 Formula 调用。

解决方法
确保 ctcc_utils.lua 经过完整构建流程,部署到 /opt/bmc/apps/redfish/interface_config/plugins/,且模块导出规范、大小写一致、调试日志开启验证。

一旦完成以上步骤,Plugin 函数将可正常调用,问题即可解决。

如有进一步日志输出,欢迎提供 redfish.log 中的错误片段以便精准排查。

相关链接:

  1. rackmount组件测试覆盖率失败
  2. 【BMC Studio】BMC Studio新特性介绍:基于Qemu进行代码调试与资源协作接口调试
  3. sata盘信息获取问题
  4. 【提问求助】BMC studio板卡适配后仿真启动报错问题
  5. rackmount | 文档中心 | openUBMC

客户定制仓的插件需要通过多层级定制添加后才能加载调用。参考:产品多层级接口定制 | 文档中心 | openUBMC