上篇章节我们学习了如何新增一个组件,并通过资源协作接口将对象和属性接入了openUBMC系统中。然而在部分场景下,我们需要将属性呈现给bmc系统外部的用户。本章节将学习如何通过bmc的对外接口将数据传递出去。
IMPORTANT
本章的学习需要基于《新增一个组件》章节创建的my_app
,请确保已完成该章节的动作。
新增IPMI命令
IPMI(智能平台管理接口),Intelligent Platform Management Interface 的缩写,是常用的服务器带外管理协议之一。
IPMI模型定义
openUBMC中提供了一套描述IPMI模型的方式,也属于MDS模型的一部分,因此仅需在MDS中定义IPMI命令,便可自动生成IPMI命令的封装解析帮助函数代码。
NOTE
详细的IPMI模型定义,请参考《MDS》
打开mds/ipmi.json
(如果没有该文件,请新建),粘贴下面的代码
{
"package": "MyAppIpmiCmds",
"cmds": {
"GetSecretNumber": {
"netfn": "0x30",
"cmd": "0x90",
"priority": "OEM",
"role": "Operator",
"privilege": ["BasicSetting"],
"req": [
{"data": "SubCommand", "baseType": "U8", "len": "1B", "value": "0x88"},
{"data": "ManufactureId", "baseType": "U32", "len": "3B", "value": "0x0007db"},
{"data": "Action", "baseType": "U8", "len": "1B", "value": "0x00"}
],
"rsp": [
{"data": "CompletionCode", "baseType": "U8", "len": "1B"},
{"data": "SecretNumber", "baseType": "U32", "len": "3B"}
]
},
"SetSecretNumber": {
"netfn": "0x30",
"cmd": "0x90",
"priority": "OEM",
"role": "Operator",
"privilege": ["BasicSetting"],
"req": [
{"data": "SubCommand", "baseType": "U8", "len": "1B", "value": "0x88"},
{"data": "ManufactureId", "baseType": "U32", "len": "3B", "value": "0x0007db"},
{"data": "Action", "baseType": "U8", "len": "1B", "value": "0x01"},
{"data": "Data", "baseType": "U32", "len": "3B"}
],
"rsp": [
{"data": "CompletionCode", "baseType": "U8", "len": "1B"}
]
}
}
}
这里我们创建了两个IPMI命令,都是NetFn 0x30, CMD 0x90
0x30 0x90 0x88 0xdb 0x07 0x00 0x00
此命令用于查询SecretNumber
0x30 0x90 0x88 0xdb 0x07 0x00 0x01
此命令用于设置SecretNumber
定义完后,我们需要使用自动生成代码进行代码生成。
bingo gen
代码编写
通过自动生成代码,我们获得了IPMI命令解析、封装和路由的能力,但我们仍需编写IPMI命令的业务部分,即将数据返回出去,或者将传入的数据设置在内存中。
打开my_app_app.lua
,
首先要在头部加载生成的IPMI文件
local class = require 'mc.class' -- lua开发框架提供的增强类型系统
local c_service = require 'my_app.service' -- 自动生成代码生成的组件基类
-- 新增ipmi相关文件
local ipmi_struct = require 'my_app.ipmi.ipmi'
local ipmi_msg = require 'my_app.ipmi.ipmi_message'
local ipmi = require 'ipmi'
然后在app:init()
中,注册对应IPMI的回调函数
function app:init() -- 组件的初始化函数
app.super.init(self) -- 先调用基类的初始化函数
self.my_mds_model = self:CreateMyMDSModel(1, function(object) -- 创建一个mds对象实例
object.ObjectName = "MyMDSModel_1" -- 在回调函数中进行对象的属性赋值
object.WelcomeMessage = "Hello OpenUBMC!"
object.SecretNumber = 330
end)
self:register_ipmi()
end
function app:register_ipmi()
self:register_ipmi_cmd(ipmi_struct.GetSecretNumber, function(req, ctx, ...)
return ipmi_msg.GetSecretNumberRsp.new(ipmi.types.Cc.Success, self.my_mds_model.SecretNumber)
end)
self:register_ipmi_cmd(ipmi_struct.SetSecretNumber, function(req, ctx, ...)
if req.Data > 630 then
return ipmi_msg.GetSecretNumberRsp.new(ipmi.types.Cc.InvalidFieldRequest)
end
self.my_mds_model.SecretNumber = req.Data
return ipmi_msg.GetSecretNumberRsp.new(ipmi.types.Cc.Success)
end)
end
当查询IPMI命令来的时候,我们返回MyMDSModel
中存储的SecretNumber
当设置IPMI命令来的时候,我们先判断数值是否有效,如果有效,则修改对应的内存数据,并返回成功。
组件构建
代码写完后,我们需要测试一下我们写的代码。首先先进行组件构建。
因为我们对组件的功能进行了修改,因此我们可以通过递增组件的版本用于区分。
首先打开mds/service.json
,修改version
字段,从0.0.1
修改至0.0.2
bingo build --stage=rc
构建完成后我们可以通过日志发现,我们构建了一个构建标签为my_app/0.0.2@openUBMC.release/rc
的版本。我们之前的my_app/0.0.1@openUBMC.release/rc
版本仍存在,且不受影响。如果需要使用之前的版本,仍可以通过依赖my_app/0.0.1@openUBMC.release/rc
标签进行使用。
整包构建
之前的版本我们使用的是my_app/0.0.1
版本,现在我们需要将版本改至my_app/0.0.2
,然后再进行整包构建。
bingo build
构建完成后,便可在manifest/output
中查看构建包。
整包测试
整包升级后,我们再次查看一下my_app
的资源
source /etc/profile
busctl --user tree bmc.kepler.my_app
└─/bmc
|─/bmc/demo
| └─/bmc/demo/MyMDSModel
| └─/bmc/demo/MyMDSModel/1
|─/bmc/kepler
|─/bmc/kepler/IpmiCmds
| └─/bmc/kepler/IpmiCmds/30
| └─/bmc/kepler/IpmiCmds/30/90
| |─/bmc/kepler/IpmiCmds/30/90/GetSecretNumber
| └─/bmc/kepler/IpmiCmds/30/90/SetSecretNumber
└─/bmc/kepler/my_app
└─/bmc/kepler/my_app/MicroComponent
这里多了一些ipmi的资源,证明我们成功的将IPMI注册到了我们组件上面,SDK在启动阶段会通过遍历这些资源,更新系统整体IPMI路由表。
通过ipmitool
,我们可以快速测试ipmi命令是否可以访问。
> ./ipmitool.exe -H ip -I lanplus -p 623 -U TestUser -P OpenUBMC@123 -C 17 raw 0x30 0x90 0x88 0xdb 0x07 0x00 0x00
> 00 30 03
命令返回330,正是我们在代码中定义的SecretNumber
再次通过设置命令,将SecretNumber
设置成630
。ipmitool
需要输入十六进制,也就是0x000276
# SetSecretNumber
> ./ipmitool.exe -H ip -I lanplus -p 623 -U TestUser -P OpenUBMC@123 -C 17 raw 0x30 0x90 0x88 0xdb 0x07 0x00 0x01 0x76 0x02 0x00
>
# 当命令成功时,成功码不会显示,返回显示为空行
# GetSecretNumber
> ./ipmitool.exe -H ip -I lanplus -p 623 -U TestUser -P OpenUBMC@123 -C 17 raw 0x30 0x90 0x88 0xdb 0x07 0x00 0x00
> 76 02 00
设置成功,并再次下发查询命令,得到630,与我们设置的数值一致。
redfish接口
openUBMC的SDK已经提供了完备的Redfish协议管理能力,并提供了强大的映射配置器,简化北向接口的适配工作量。
NOTE
具体关于接口映射配置的介绍,请参考《接口映射配置》
映射配置增加
首先先获取当前Redfish相关接口的映射配置仓,获取目录如下:
git clone git@gitcode.com:openUBMC/rackmount.git
打开rackmount文件夹后,我们可以发现,在interface_config/redfish/mapping_config
下,每一个文件对应着一个Redfish的路径。
我们希望扩展一个Redfish接口,路径为:/redfish/v1/OpenUBMC
首先在interface_config/redfish/mapping_config
下创建文件:OpenUBMC.json
,并粘贴以下代码
{
"Resources": [
{
"Uri": "/redfish/v1/OpenUBMC",
"Interfaces": [
{
"Type": "GET",
"RspBody": {
"@odata.id": "/redfish/v1/OpenUBMC",
"Id": "OpenUBMC",
"Name": "OpenUBMC",
"WelcomeMessage": "${ProcessingFlow[1]/Destination/WelcomeMessage}"
},
"ProcessingFlow": [
{
"Type": "Property",
"Path": "/bmc/demo/MyMDSModel/1",
"Interface": "bmc.demo.OpenUBMC.Community",
"Destination": {
"WelcomeMessage": "WelcomeMessage"
}
}
]
}
]
}
]
}
这里我们通过接口映射配置,不仅将Redfish的uri
资源进行了具体的定义,并将redfish的uri
资源与openUBMC资源协作接口关联了起来,开发者无需再编写Redfish的接口代码逻辑。
组件构建
由于修改了rackmount
仓库,因此我们需要对rackmount
仓库进行重新构建。
为了和之前版本进行区分,我们需要将service.json
中的version
字段进行更新
bingo build --stage=rc
整包构建
在manifest中找到rackmount
声明位置,将版本改至对应的构建版本,然后再进行整包构建
bingo build
整包测试
整包升级后,我们可以对Redfish接口进行访问。
curl -u username:password 'https://ip/redfish/v1/OpenUBMC' -k
接口返回的WelcomeMessage
与资源协作接口返回的数值一致。
{"@odata.id":"\/redfish\/v1\/OpenUBMC","Id":"OpenUBMC","Name":"OpenUBMC","WelcomeMessage":"Hello OpenUBMC!"}