【教学培训篇】新增组件

前言

在前期的学习中,我们从一开始对openUBMC懵懵懂懂,到学会如何构建openUBMC产品,想必现在的你很想以openUBMC为基底,在上面打造属于你独一无二的产品吧!

也许你很早之前就已经在openUBMC社区深入学习过新增一个组件组件开发,并且也在自己终端实际操作过。但由于缺少相关服务器环境,无法观测它如何用于产品,无法感知自己产品的整体情况.

在这里,我们将结合openUBMC社区文档中心,一步步告诉你如何构建属于自己的组件,并如何在产品上查看它。

新增组件

组件初始化

新增组件命令:bingo new -n Hello_openUBMC -t application -l lua

image

查看新增的组件:ls -l Hello_openUBMC

在新增的组件里面初始git操作,方便后面维护:

cd Hello_openUBMC
git init .
git branch -m main

新增组件业务

想必,您肯定希望在自己组件中实现自己的“奇思妙想”,openUBMC社区提供了一键式的模型生成体系,您只需要遵循其规则添加自己的想法即可。

新增MDS资源对象定义

进入新建的HelloOpenUBMC项目中,打开mds/model.json。在这里添加您想创建的对象(HelloOpenUBMC),以及这个对象挂载的路径(/bmc/kepler/HelloOpenUBMC/${id})、它提供给外界调用的接口(interfaces)、私有属性(properties),更加详细的信息可以参考MDS

{
    "HelloOpenUBMC": {
        "path": "/bmc/kepler/HelloOpenUBMC/",
        "interfaces": {
            "bmc.kepler.OpenUBMC.Community": {
                "properties":{
                    "WelcometoOpenUBMC": {}
                }
            }
        },
        "properties": {
            "Health": {
                "baseType": "U32"
            }
        }
    }
}

模型代码自动生成

充满好奇心的你肯定会问只是在model.json添加自己的资源协作对象的接口和属性就可以直接使用了吗?应该在哪调用呢?
openUBMC社区提供一套基于MDS模型生成的辅助代码,更加的详细信息参考代码自动生成

如果你这边只是在model.json里面添加内容,在自动生成代码过程中,就会遇到这个问题:

FileNotFoundError: [Errno 2] No such file or directory: '/root/lwm/Hello_openUBMC/temp/lua_codegen/../../temp/opt/bmc/apps/mdb_interface//path/mdb//bmc/kepler/HelloOpenUBMC////HelloOpenUBMC.json'


原因:当组件的MDS对象需要新增interface接口时,需要mdb_interface定义这个interface接口以及属性。
我们可以从两个方面来验证上述的原因:

  • 新增的MDS对象只保留私有属性
{
    "HelloOpenUBMC": {
        "properties": {
            "Health": {
                "baseType": "U32"
            }
        }
    }
}

执行 bingo gen,此时可以看到是没有报错的,而且也能顺利生成对应自动生成代码


  • 在mdb_interface组件中新增Hello_OpenUBMC的对外接口
  1. 从社区拉起mdb_interface组件
    git clone git@gitcode.com:openUBMC/mdb_interface.git

根据openUBMC社区的资源协作接口的说明:开发者需要在mdb_interface组件仓的json/path/路径下新增对象定义文件,根据上述新增的Hello_OpenUBMC组件的MDS对象,需要在mdb_interface做如下修改:

1. 新增json/path/mdb/bmc/kepler/HelloOpenUBMC/HelloOpenUBMC.json对象定义文件

对象定义文件的路径和MDS对象定义的path属性要一致,即json/path/mdb + MDS对象的path

{
    "HelloOpenUBMC": {
        "path": "/bmc/kepler/HelloOpenUBMC/",
}

在这个路径创建的文件名和类名一致:“HelloOpenUBMC”

总之,在mdb_interface组件仓中新增json/path/mdb/bmc/kepler/HelloOpenUBMC/HelloOpenUBMC.json对象定义文件,内容如下:

{
    "HelloOpenUBMC": {
        "path": "/bmc/kepler/HelloOpenUBMC/",
        "interfaces": [
            "bmc.kepler.OpenUBMC.Community"
        ]
    }
}

2. 新增json/intf/mdb/bmc/kepler/OpenUBMC/Community.json接口定义文件

根据openUBMC社区的资源写作接口说明:新增接口的定义存放在mdb_interface组件的json/intf/路径下,主要存放接口的具体方法和属性等信息。接口定义文件的路径要和挂载接口一致:json/intf/ + 新增接口命名转化为路径,如bmc.kepler.OpenUBMC.Community转化为/bmc/kepler/OpenUBMC/Community.json

{
    "bmc.kepler.OpenUBMC.Community": {
        "properties":{
            "WelcometoOpenUBMC": {
                "baseType": "String",
                "description": "欢迎加入openUBMC社区!"
            }
        }
    }
}

聪明的你肯定会想:那我们是如何将mdb_interface和Hello_OpenUBMC组件相结合,即Hello_OpenUBMC是如何感知mdb_interface的修改呢?
细心的你会发现报错的信息有这么一段话:

'/root/lwm/Hello_openUBMC/temp/lua_codegen/../../temp/opt/bmc/apps/mdb_interface//path/mdb//bmc/kepler/HelloOpenUBMC////HelloOpenUBMC.json'


也就是每次我们自动生成的时候,都会从寻找本地或远程mdb_interface组件的conan包,如何将其存放在temp/opt/bmc/apps/路径下。
那么,Hello_OpenUBMC组件是怎么感知自己要去拉取mdb_interface组件的呢?
原来在我们是用bingo new -n Hello_openUBMC -t application -l lua生成新组件时会自动把依赖组件添加在service.json

{
    "name": "Hello_openUBMC",
    "type": "application",
    "deployConfig": "",
    "version": "0.0.1",
    "license": "",
    "codegen_policy": {
        "version": "18"
    },
    "description": "",
    "dependencies": {
        "test": [
        ],
        "build": [
            {
                "conan": "libmc4lua/[>=0.0.1]"
            },
            {
                "conan": "mdb_interface/[>=0.0.1]"
            }
        ]
    },
    "required": []
}

我们可以看到dependencies里面的build下面具有"conan": "mdb_interface/[>=0.0.1]"这个依赖,也就是在构建/自动生成的时候会默认依赖mdb_interface。

总之,我们需要进行下面三个步骤操作,就可以自动生成代码了:

1. 在mdb_interface组件中构建出包
bingo bulld

2. 将生成的mdb_interface组件的版本号替换Hello_OpenUBMC组件的mdb_interface/[>=0.0.1]
```service.json
{
    "name": "Hello_openUBMC",
    "type": "application",
    "deployConfig": "",
    "version": "0.0.1",
    "license": "",
    "description": "",
    "dependencies": {
        "test": [
        ],
        "build": [
            {
                "conan": "libmc4lua/[>=0.0.1]"
            },
            {
                "conan": "mdb_interface/1.90.78@openUBMC.dev/dev"
            }
        ]
    },
    "required": []
}

3. 在'Hello_OpenUBMC'组件仓中自动生成代码bingo gen


自动生成代码仅仅生成了管理代码,但并没有真正的创建实例。需要在组件的代码中去创建实例对象。

在src/lualib/Hello_openUBMC_app.lua代码中创建实例

local class = require 'mc.class'
local service = require 'Hello_openUBMC.service'

local Hello_openUBMC = class(service)

function Hello_openUBMC:ctor()

end

function Hello_openUBMC:init()
    self.super.init(self)
    self.hello_openUBMC = self:CreateHelloOpenUBMC(1,function(object)
        object.ObjectName = "HelloOpenUBMC_1"
        object.WelcometoOpenUBMC = "Welcome to openUBMC"
        object.Health = 1
    end)
end

return Hello_openUBMC

说明:在这里,我们创建了HelloOpenUBMC_instance这个实例,并对其MDS属性进行赋值。从现在开始,你可以书写属于自己的业务内容。

组件出包

在Hello_OpenUBMC组件中采用bingo build构建出包

bingo build

产品出包

当我们成功完成了组件出包,您会思考我们应该如何将其融入到openUBMC产品呢?看过我们前期两篇教学培训:体验openUBMC构建openUBMC包的朋友会自然而然地想到openUBMC的manifest仓。是的,您想的没错!和产品相关的内容都是在manifest仓进行的

1. 下载openUBMC社区的manifest(已经有manifest仓的朋友可以跳过)
git clone git@gitcode.com:openUBMC/manifest.git

2. 在build/subsys/rc/hardware.yml(可以放在其他yml里面)添加Hello_OpenUBMC组件
  - conan: "Hello_openUBMC/0.0.1@openUBMC.dev/dev"
还需要把mdb_interface的版本也添加进去


3. 在build/product/BMC/openUBMC/manifest.yml中dependency中添加Hello_OpenUBMC组件

4. 构建出包: bingo build -sc qemu


5. 使用python3 build/works/packet/qemu_shells/vemake_1711.py运行qemu
6. ssh登录终端,采用cat /etc/package_info | grep Hello_openUBMC有没有这个组件

image

7. 查看Hello_openUBMC的资源树
busctl --user tree bmc.kepler.Hello_openUBMC

8. 使用mdbctl查看起来的组件
发现Hello_openUBMC也在里面

但很奇怪的是:你会发现在终端中出现一个Hello_openUBMC组件起不来的刷屏日志
image
这需要进一步探究啦~

使用xshell以telnet进去
telnet 127.0.0.1 -p 10023
运行:cat /var/log/app.log | grep Hello

发现报错:
Hello_openUBMC start failed, err: ./opt/bmc/libmc/lualib/mc/mdb/object_manage.lua:102: attempt to call local ‘prop_setting_cb’ (a number value)


然后进一步查看代码,发现Hello_openUBMC_service:CreateHelloOpenUBMC里面只需要传入回调函数

将src/lualib/Hello_openUBMC_app.lua的代码改为:

function Hello_openUBMC:init()
    logging:notice("Hello_openUBMC:init start")
    self.super.init(self)
    self.hello_openUBMC = self:CreateHelloOpenUBMC(function(object)
        object.ObjectName = "HelloOpenUBMC_1"
        object.WelcometoOpenUBMC = "Welcome to openUBMC"
        object.Health = 1
    end)
    logging:notice("Hello_openUBMC: init end")
end

更加详细的信息可以参考社区文档中的新增一个组件组件开发MDS代码自动生成
也可以继续关注教学培训篇,后续我们将会讲解和实践更深入的内容!

conan2

2 个赞

可以,我照着步骤走一遍,学习下,这个教学挺新颖

欢迎指正和批评,若有疑问可以直接评论,感谢!
目前新增组件的教学培训篇还没有写完,预估计这两天完成。

按照步骤执行之后的出错如下,如何解决?还有如何看entry_class_factory.lua的内容?麻烦帮忙看看

可以在src/lualib/Hello_openUBMC_app.lua中将内容替换为:

local class = require 'mc.class'
local service = require 'Hello_openUBMC.service'
local logging = require 'mc.logging'

local Hello_openUBMC = class(service)

function Hello_openUBMC:ctor()

end

function Hello_openUBMC:init()
    logging:notice("Hello_openUBMC:init start")
    self.super.init(self)
    self.hello_openUBMC = self:CreateHelloOpenUBMC(function(object)
        object.ObjectName = "HelloOpenUBMC_1"
        object.WelcometoOpenUBMC = "Welcome to openUBMC"
        object.Health = 1
    end)
    logging:notice("Hello_openUBMC: init end")
end

return Hello_openUBMC

也就是self:CreateHelloOpenUBMC里面只需要传入回调函数即可

entry_class_factory.lua是属于闭源二进制组件提供的,它应该是在调用create_object函数中会被调用的文件,理论上修改好Hello_openUBMC_app.lua应该就可以了,您这边可以在Hello_openUBMC_app.lua添加更多的日志,例如:

local class = require 'mc.class'
local service = require 'Hello_openUBMC.service'
local logging = require 'mc.logging'

local Hello_openUBMC = class(service)

function Hello_openUBMC:ctor()

end

function Hello_openUBMC:init()
    logging:notice("Hello_openUBMC:init start")
    self.super.init(self)
    logging.notice("111111111111")
    self.hello_openUBMC = self:CreateHelloOpenUBMC(function(object)
        object.ObjectName = "HelloOpenUBMC_1"
        object.WelcometoOpenUBMC = "Welcome to openUBMC"
        object.Health = 1
    end)
    logging:notice("Hello_openUBMC: init end")
end

return Hello_openUBMC

如果还是有问题,请问可以提供一下代码截图和日志,或者代码私仓给我看看吗?

按照修改后的代码改完之后还是不行,出错的打印跟之前是一样的,有个怀疑点:我这gen自动生成的service.lua跟您这个截图不一样,没有CreatHelloOpenUBMC,这是为啥?

bingo gen的时候看一下temp目录下的mdb_interface中是否有HelloOpenUBMC.json文件没。如果没有的话,检查一下service.json中mdb_interface的版本是否正确

还有个问题,运行qemu之后,网页登录失败,只有第一次运行可以,再次运行都登不上,重启也不行,帮忙看看,谢谢

端口10443监听正常

文件没有问题,有,编译没有问题

这看起来是web还没加载起来的问题,可以看一下终端,有没有notify security core that bmc has successfully started这个句话,如果有的话,可以去登录web了。

还有一个可能是manifest的output里面的data的问题,可以手动删除一下,然后重新在manifest启动qemu

您这边的新增组件问题,我这边重新弄一下,试一下有没有这个问题,有可能是gen出现bug了,晚点给您答复哈

目前根因在于构建工具更新,需要在service.json里面添加自动生成代码的版本:

{
    "name": "Hello_openUBMC",
    "type": "application",
    "deployConfig": "",
    "version": "0.0.1",
    "license": "",
    "codegen_policy": {
        "version": "18"
    },
    "description": "",
    "dependencies": {
        "test": [
        ],
        "build": [
            {
                "conan": "libmc4lua/[>=0.0.1]"
            },
            {
                "conan": "mdb_interface/1.90.108@openUBMC.release/dev"
            }
        ]
    },
    "required": []
}

1 个赞

删掉data之后重新编译,启动qemu,web可以打开了,多谢

1 个赞

按照步骤在组件出包时出现了如下问题,请问该如何解决呢?


下面是/root/.bmcgo_log/bingo.log中的内容

能不能看一下您这边bingo版本和conan版本呢?

bingo --version

conan --version

如果是conan2的话,需要在conanfile.py和Cmakelist.txt进行如下操作

conanfile.py

from conanbase import ConanBase, copy
import os

required_conan_version = ">=1.60.0"
class AppConan(ConanBase):

  def package(self):
        super().package()
        copy(self, "permissions.ini", src=os.path.join(self.source_folder, "dist"), dst=self.package_folder)

  def package_info(self):
        pass
cmake_minimum_required(VERSION 3.14)

project(Hello_openUBMC)
find_package(PkgConfig REQUIRED)
pkg_search_module(GLIB REQUIRED glib-2.0)
pkg_search_module(GMODULE REQUIRED gmodule-2.0)

set(TARGET_LIB ${PROJECT_NAME})
set(BUILD_DIR temp)

if (EXISTS "${CMAKE_BINARY_DIR}/conanbuildinfo.cmake")
    include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
    conan_basic_setup()
endif()

set(APP_INSTALL_DIR opt/bmc/apps/${PROJECT_NAME})
set(LUACLIB_INSTALL_DIR ${APP_INSTALL_DIR}/luaclib)

install(DIRECTORY src/lualib DESTINATION ${APP_INSTALL_DIR} OPTIONAL)
install(DIRECTORY include/ DESTINATION opt/bmc/lualib OPTIONAL)
install(DIRECTORY src/service DESTINATION ${APP_INSTALL_DIR} OPTIONAL)
if (NOT ${CMAKE_BUILD_TYPE} STREQUAL Release)
    install(DIRECTORY gen/debug/ DESTINATION ${APP_INSTALL_DIR}/debug OPTIONAL)
    install(DIRECTORY src/debug/lualib DESTINATION ${APP_INSTALL_DIR} OPTIONAL)
endif()
install(DIRECTORY gen/${PROJECT_NAME}/ DESTINATION ${APP_INSTALL_DIR} OPTIONAL)
install(DIRECTORY gen/class DESTINATION ${APP_INSTALL_DIR} OPTIONAL)
install(FILES mds/schema.json DESTINATION ${APP_INSTALL_DIR}/mds OPTIONAL)
install(FILES mds/service.json DESTINATION ${APP_INSTALL_DIR}/mds OPTIONAL)
install(DIRECTORY user_conf/rootfs/ DESTINATION . USE_SOURCE_PERMISSIONS OPTIONAL)
install(FILES config.cfg DESTINATION ${APP_INSTALL_DIR} OPTIONAL)

根据你提供的报错信息看,是conan包名中带了多余的‘/’,你编译的组件Hello_openUBMC的包名看着是没有问题的,请检查下是否有依赖组件的包名不规范。可以查找“requirements”关键字来排查依赖组件名字。

想在新增组件中实现Eeprom的读写,但是日志显示addObject failed,请帮忙看一下这个问题,多谢

以下是model.json和root.sr的修改:

  1. model.json增加,bingo gen,bingo build

bingo 版本为: 0.6.33
bmc-studio 版本为: 1.2.0

Conan version 1.62.0

  1. vpd/vendor/Huawei/Server/Kunpeng/openUBMC/root.sr

bingo build --stage=rc

  1. manifest,将上述构建的vpd和Hello_openUBMC版本包更新到hardware.yml,构建仿真,仿真日志打印

是不是没有在service.json添加依赖呢,具体可以参考network_adapter组件哦

“required”: [

    {

        "path": "\*",

        "interface": "bmc.kepler.Chip.BlockIO",

        "properties": {}

    }

]

在service.json的required中增加以下BlockIO和Accessor,重新bingo gen,bingo build,报同样的错误invalid interface:bmc.kepler.Chip.BlockIO,src/lualib/Hello_openUBMC_app.lua需要增加什么修改么?

我这边准备把您这边全流程跑一遍,到时候一起讨论商量哈~

好的,非常感谢