北向接口映射器适配指导
认识北向接口映射器模型
模型设计目标
北向接口是BMC对外提供的标准化管理接口,其核心设计目标是实现硬件资源的抽象化服务化,并支撑上层管理协议与生态伙伴的灵活对接 北向接口映射器是把 BMC 内部的数据映射成BMC对外提供的标准化接口的rackmount模块
主要内容
北向接口映射器提供的北向接口包括:redfish、web-backend、cli、snmp、ipmi 等
代码获取方式:rackmount
配置北向接口方法
配置新接口,需要先获取当前版本对应的代码,首先需要在 manifest.yaml 中找到当前产品使用的是哪个节点的 rackmount 库,下载相应节点代码。
Redfish 接口新增配置方法
Redfish 接口在 rackmount\interface_config\redfish 路径下
举例:需要新增一个社区已有例子 my_app 的 WelcomeMessage 属性的查询接口,当前已包含如下dbus,里面有 WelcomeMessage 属性
~ ~ $ busctl --user introspect bmc.kepler.my_app /bmc/demo/MyMDSModel/1 | cat
NAME TYPE SIGNATURE RESULT/VALUE FLAGS
bmc.demo.OpenUBMC.Community interface - - -
.GetRepoURL method a{ss}u s -
.WelcomeMessage property s "hello" emits-change writable
bmc.kepler.Object.Properties interface - - -
...
org.freedesktop.DBus.Introspectable interface - - -
.Introspect method - s -
org.freedesktop.DBus.ObjectManager interface - - -
.GetManagedObjects method - a{oa{sa{sv}}} -
org.freedesktop.DBus.Peer interface - - -
.GetMachineId method - s -
.Ping method - - -
org.freedesktop.DBus.Properties interface - - -
.Get method ss v -
.GetAll method s a{sv} -
.Set method ssv - -
.PropertiesChanged signal sa{sv}as - -期待的新增路径是 /redfish/v1/Chassis/1/Myapp,需要做如下步骤:
1: 在已有的interface_config/redfish/mapping_config/Chassis/Chassis.json文件中搜索ThresholdSensors,在附近增加
"MyApp": {
"@odata.id": "/redfish/v1/Chassis/${Uri/chassisid}/MyApp"
},目的是在访问 /redfish/v1/Chassis/1 路径时,会显示 MyApp 的链接
2: 在 interface_config\redfish\mapping_config\AccountService\PrivilegeMap\PrivilegeMap.json 文件中搜索 ThresholdSensors,在附近增加
{
"Entity": "MyApp",
"OperationMap": {
"GET": [
{
"Privilege": [
"Login"
]
}
]
}
},不增加编译时会报错:PrivilegeMap:GET 接口:/redfish/v1/Chassis/{id}/MyApp,类型:MyApp 未配置 PrivilegeMap
3: 新增 interface_config\redfish\mapping_config\Chassis\MyApp.json文件,内容如下
{
"Resources": [
{
"Uri": "/redfish/v1/Chassis/:chassisid/MyApp",
"Interfaces": [
{
"Type": "GET",
"ResourceExist": {
"${Statements/IsValidChassisId()}": true
},
"RspBody": {
"@odata.context": "/redfish/v1/$metadata#MyApp.MyApp",
"@odata.id": "/redfish/v1/Chassis/${Uri/chassisid}/MyApp",
"@odata.type": "#MyApp.MyApp",
"Id": "MyApp",
"Name": "New MyApp Interface",
"WelcomeMessage": "${ProcessingFlow[1]/Destination/WelcomeMessage}"
},
"Statements": {
"IsValidChassisId": {
"Steps": [
{
"Type": "Plugin",
"Formula": "utils.is_valid_chassis_id(Uri.chassisid)"
}
]
}
},
"ProcessingFlow": [
{
"Type": "Property",
"Path": "/bmc/demo/MyMDSModel/1",
"Interface": "bmc.demo.OpenUBMC.Community",
"Destination": {
"WelcomeMessage": "WelcomeMessage"
}
}
]
}
]
}
]
}在调用到 /redfish/v1/Chassis/1/MyApp 接口时,会返回 RspBody 里面的内容,根据 ProcessingFlow 里面的 dbus 属性获取 WelcomeMessage 属性的值 其中的 WelcomeMessage 属性的获取来源是 bmc.demo.OpenUBMC.Community 里面的 WelcomeMessage 属性 此处的 @odata 的相关属性是新的,需要新增配置,配置方法见下面步骤
4: 在 interface_config\redfish\static_resource\redfish\v1\jsonschemas\ 路径下,新增 myapp 文件夹,新建 index.json 文件
{
"@odata.context": "/redfish/v1/$metadata#JsonSchemaFile.JsonSchemaFile",
"@odata.id": "/redfish/v1/JSONSchemas/MyApp",
"@odata.type": "#JsonSchemaFile.v1_0_2.JsonSchemaFile",
"Id": "MyApp",
"Description": "MyApp Schema File Location",
"Name": "MyApp",
"Languages": [
"en"
],
"Schema": "#MyApp.MyApp",
"Location": [
{
"Language": "en",
"Uri": "/redfish/v1/SchemaStore/en/MyApp.json"
}
]
}编译MyApp.json时需要找到对应 odata 的静态资源文件,此处的Uri路径要配正确,最后的文件对应的json都是小写的,这里不影响
5: 在 interface_config\redfish\static_resource\redfish\v1\schemastore\en\ 路径下,新增 myapp.json 文件
{
"$schema": "http://redfish.dmtf.org/schemas/v1/redfish-schema.v1_1_0.json",
"title": "#MyApp.MyApp",
"$ref": "#/definitions/MyApp",
"definitions": {
"MyApp": {
"anyOf": [
{
"$ref": "http://redfish.dmtf.org/schemas/v1/odata.4.0.0.json#/definitions/idRef"
},
{
"type": "object",
"patternProperties": {
"^([a-zA-Z_][a-zA-Z0-9_]*)?@(odata|Redfish|Message|Privileges)\\.[a-zA-Z_][a-zA-Z0-9_.]+$": {
"type": [
"array",
"boolean",
"number",
"null",
"object",
"string"
],
"description": "This property shall specify a valid odata or Redfish property."
}
},
"additionalProperties": false,
"properties": {
"@odata.context": {
"$ref": "http://redfish.dmtf.org/schemas/v1/odata.4.0.0.json#/definitions/context"
},
"@odata.id": {
"$ref": "http://redfish.dmtf.org/schemas/v1/odata.4.0.0.json#/definitions/id"
},
"@odata.type": {
"$ref": "http://redfish.dmtf.org/schemas/v1/odata.4.0.0.json#/definitions/type"
},
"Description": {
"anyOf": [
{
"$ref": "http://redfish.dmtf.org/schemas/v1/Resource.json#/definitions/Description"
},
{
"type": "null"
}
],
"readonly": true
},
"Name": {
"$ref": "http://redfish.dmtf.org/schemas/v1/Resource.json#/definitions/Name",
"readonly": true
},
"WelcomeMessage": {
"type": [
"string",
"null"
],
"readonly": true,
"description": "The value of this property shall be the name of WelcomeMessage."
}
}
}
],
"updatable": false,
"insertable": false,
"deletable": false,
"uris": [
"/redfish/v1/Chassis/:chassisid/MyApp"
],
"description": "This is myapp resource."
}
},
"copyright": "Copyright © xxx Technologies Co., Ltd. 2018. All rights reserved."
}WelcomeMessage 属性需要和源接口的属性一致 uris 里面需要填上对应的源接口的 uri
6: 在 interface_config\redfish\static_resource\redfish\v1\schemastore\en\oem\huawei_chassis.json 文件中搜索 ThresholdSensors,在附近增加
"MyApp": {
"$ref": "http://redfish.dmtf.org/schemas/v1/MyApp.json#/definitions/MyApp",
"readonly": true,
"description": "A list of MyApp objects.",
"longDescription": "Show all of the MyApp objects."
},Chassis.json 文件会关联到 huawei_chassis.json,所以这里也需要添加,否则编译会报错。
7: 编译,在设备上运行后,访问https://ip/redfish/v1/Chassis/1/MyApp就可以得到结果了
{
"@odata.context": "/redfish/v1/$metadata#MyApp.MyApp",
"@odata.id": "/redfish/v1/Chassis/1/MyApp",
"@odata.type": "#MyApp.MyApp",
"Id": "MyApp",
"Name": "New MyApp Interface",
"WelcomeMessage": "hello"
}- 在访问 /redfish/v1/Chassis/1 路径时,会显示 /redfish/v1/Chassis/1/MyApp 的链接
{
"@odata.context": "/redfish/v1/$metadata#Chassis.Chassis",
"@odata.id": "/redfish/v1/Chassis/1",
"@odata.type": "#Chassis.v1_15_7.Chassis",
"Id": "1",
"Name": "Computer System Chassis",
...
"Oem": {
"openUBMC": {
"ChassisID": null,
...
"ThresholdSensors": {
"@odata.id": "/redfish/v1/Chassis/1/ThresholdSensors"
},
"MyApp": {
"@odata.id": "/redfish/v1/Chassis/1/MyApp"
},
"DiscreteSensors": {
"@odata.id": "/redfish/v1/Chassis/1/DiscreteSensors"
},
...
},
...
}Web 接口新增配置方法
Web 接口在 rackmount\interface_config\web_backend 路径下
举例:需要新增一个社区已有的 my_app 的 WelcomeMessage 属性的查询接口,在 System 路径下,期待路径是 /UI/Rest/System/Myapp,需要做如下步骤:
1: 在 interface_config\web_backend\mapping_config\System 目录下,增加 MyApp.json 文件
{
"Resources": [
{
"Uri": "/UI/Rest/System/MyApp",
"Interfaces": [
{
"Type": "GET",
"Authentication": {
"Condition": false
},
"RspBody": {
"WelcomeMessage": "${ProcessingFlow[1]/Destination/WelcomeMessage}"
},
"ProcessingFlow": [
{
"Type": "Property",
"Path": "/bmc/demo/MyMDSModel/1",
"Interface": "bmc.demo.OpenUBMC.Community",
"Destination": {
"WelcomeMessage": "WelcomeMessage"
}
}
]
}
]
}
]
}RspBody 中的 WelcomeMessage 和 busctl --user introspect bmc.kepler.my_app /bmc/demo/MyMDSModel/1 | cat 中查询到的 WelcomeMessage 值一致
2: WebUI 验证,使用 postman 访问https://ip/UI/Rest/System/MyApp,使用postman访问时,需要在header页面下添加参数key列下面添加 cookie,对应的value 列填写 cookie 值,这里的cookie 值可以通过浏览器的F12工具查看对应的接口获取, 可以得到正常的结果
{
"WelcomeMessage": "Hello"
}CLI 接口新增配置方法
举例:需要新增一个社区例子里面 my_app 的 WelcomeMessage 属性的查询接口,在 ipmcget -d version 命令下,需要做如下步骤:
1: 在 interface_config\cli\ipmcget\system.json 文件中,搜索 "Uri": "/cli/v1/_/version"
- 在 RspBody 中增加 WelcomeMessage 字段
"WelcomeMessage": "${ProcessingFlow[13]/Destination/WelcomeMessage}",- 在 ProcessingFlow 中增加对应的属性映射
{
"Type": "Property",
"Path": "/bmc/demo/MyMDSModel/1",
"Interface": "bmc.demo.OpenUBMC.Community",
"Destination": {
"WelcomeMessage": "WelcomeMessage"
}
}2: 在 interface_config\cli\echoes\ipmcget_version 文件中,搜索 FirmwareInfo.ActiveBMCSDK.Version,在下方增加
MYAPP INFO Version: {* WelcomeMessage *}3: 在 SSH 中,使用 ipmcget -d version,即可看到新增的信息在 Active BMCSDK 下方
MYAPP INFO Version: Hello常见问题及解决方案
Zone.Identifier 临时文件问题
当一个目录拷贝文件的时候,经常会生成一个 Zone.Identifier 的临时文件,这个文件也会参与编译,编译时会报错
报错内容类似下方报错:
ERROR: rackmount/1.90.222@openubmc/rc: Error in build() method, line 37
MapperCheck.check()
JSONDecodeError: Expecting value: line 1 column 2 (char 1)解决办法是,删除相关的 Zone.Identifier 文件,可以使用 git status 命令,看 Untracked files 里面是否有多余的 Zone.Identifier 文件。
JSON 文件调试方法
如果修改多个 JSON 后不清楚哪个 JSON 报错,可以在 mapper_check\MapperCheck.py 文件中增加调试信息,方便找到哪个 JSON 文件报错,下面是git diff结果,请参考修改
- with open(path, 'r', encoding='utf-8') as fp:
- return json.load(fp)
+ try:
+ print(f"正在读取JSON文件: {path}")
+ with open(path, 'r', encoding='utf-8') as fp:
+ data = json.load(fp)
+ print(f"✅ 成功读取: {path}")
+ return data
+ except Exception as e:
+ print(f"❌ 读取JSON文件失败: {path}")
+ print(f"❌ 错误信息: {e}")
+ # 检查文件是否存在
+ if not os.path.exists(path):
+ print(f"❌ 文件不存在: {path}")
+ else:
+ # 检查文件内容
+ with open(path, 'r', encoding='utf-8') as fp:
+ content = fp.read()
+ print(f"文件内容: {content}")
+ raise属性获取处理方法ProcessingFlow
如果正常增加的属性 ProcessingFlow 下面的 Type 是 "Property",如果获取的是多个对象,要使用 "List",使用的是方法,要使用 "Method",一个 ProcessingFlow 可以包含多个对象,每个对象有一个下标,下标是从 1 开始的
{
"Type": "Method",
"Path": "/bmc/kepler/MdbService",
"Interface": "bmc.kepler.Mdb",
"Name": "GetPath",
"Params": [
"bmc.kepler.Systems.FruData.Overview",
{
"FruId": 0
},
false
],
"Destination": {
"Path": "Path"
}
},属性获取处理方法Statements,里面可以再包含
如果 D-Bus 上的数据需要处理,需要使用 Statements,里面可以再包含 ProcessingFlow
"Steps": [
{
"Type": "Plugin",
"Formula": "orchestrator.bios.get_registry_version(Uri.systemid)"
}Formula 的内容是一段 Lua 脚本,可实现任何复杂逻辑的处理,支持入参,入参可使用 ReqBody 等数据来源。
Plugin 可实现复杂逻辑的业务处理(不推荐与其他处理类型叠加使用)。
以 Redfish 为例,当前 Redfish 插件的存放目录为 /opt/bmc/apps/redfish/interface_config/plugins,那么上述配置要求,在存放目录下有文件 orchestrator\bios.lua,并且文件有函数 get_registry_version。
Redfish URI 配置问题
配置 Redfish 接口时,会遇到 URI 报错,实际上是 "@odata.context","@odata.id","@odata.type" 这几个配置的有问题,需检查修改
结语
参考文档: