扩展对外接口
更新时间:2025/2/19
在Gitcode上查看源码

上篇章节我们学习了如何新增一个组件,并通过资源协作接口将对象和属性接入了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(如果没有该文件,请新建),粘贴下面的代码

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

定义完后,我们需要使用自动生成代码进行代码生成。

bash
bingo gen

代码编写

通过自动生成代码,我们获得了IPMI命令解析、封装和路由的能力,但我们仍需编写IPMI命令的业务部分,即将数据返回出去,或者将传入的数据设置在内存中。

打开my_app_app.lua

首先要在头部加载生成的IPMI文件

lua
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的回调函数

lua
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

bash
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,然后再进行整包构建。

bash
bingo build

构建完成后,便可在manifest/output中查看构建包。

整包测试

整包升级后,我们再次查看一下my_app的资源

bash
source /etc/profile
busctl --user tree bmc.kepler.my_app
bash
└─/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命令是否可以访问。

powershell
> ./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设置成630ipmitool需要输入十六进制,也就是0x000276

powershell
# 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相关接口的映射配置仓,获取目录如下:

bash
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,并粘贴以下代码

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字段进行更新

bash
bingo build --stage=rc

整包构建

在manifest中找到rackmount声明位置,将版本改至对应的构建版本,然后再进行整包构建

bash
bingo build

整包测试

整包升级后,我们可以对Redfish接口进行访问。

bash
curl -u username:password 'https://ip/redfish/v1/OpenUBMC' -k

接口返回的WelcomeMessage与资源协作接口返回的数值一致。

bash
{"@odata.id":"\/redfish\/v1\/OpenUBMC","Id":"OpenUBMC","Name":"OpenUBMC","WelcomeMessage":"Hello OpenUBMC!"}