openUBMC中北向接口(Redfish、Web-backend、CLI、SNMP)的设计,针对接口格式与资源协作接口的对接,提出配置、映射的概念,进而引入了映射接口配置的机制,框架解析接口配置,将接口请求映射到资源协作接口,拼装对应格式的返回数据。映射接口配置机制特点如下:
- 简易定制:封装接口协议,使用标准的资源协作接口实现接口配置
- 高效扩展:抽象接口数据模型,建立映射规则,扩展接口仅需修改配置
- 业务解耦:解耦接口与功能逻辑,避免接口错误调用影响业务功能
本文介绍公共接口映射配置规则,部分规则只在单一接口使用,可见其对应的接口配置指南。
接口支持
接口 | 说明 |
---|---|
Redfish | 机机接口,用于与上层网管对接。 |
Web_backend | 为Web前端提供后端服务支持。 |
SNMP | 机机接口,多用于与早期网管系统对接,逐渐被Redfish替代。 |
CLI | 人机接口,供用户直接操作设备。 |
关键字
映射关键字
关键字 | 类型 | 适用范围 | 说明 |
---|---|---|---|
Resources | array | All | 资源合集,每个数组元素描述一个资源。 |
Resources.Uri | string | All | 1. Redfish/Web_backend保持原uri不变。 2. CLI的uri以 /cli/v1 开头,-t 和 -d 后的参数分别为路由的第3、4段,若不存在-t,则以 _ 代替。3. SNMP的uri以/snmp/v1开头,oid为第三段,命令名称为第4段,读写方式为第5段。 |
Resources.IgnoreEtags | array | Redfish | 不进行etag校验的属性集合。频繁变更属性需要使用该字段进行屏蔽,否则执行 PATCH 方法时会因属性变更而设置失败。 |
Resources.ResourceExist | object | All | 资源存在性校验流程配置,一般用于校验 Uri 中的动态字段是否合法。 Key为数据来源的定义,Value为校验的预期结果。 Value为 #WITH 时,预期为数据存在。Value为 #WITHOUT 时,预期为数据不存在。其余字段代表实际预期结果。 |
Resources.Sequence | array | SNMP | 序列字段配置,用于SNMP接口中对象场景的数据定义。 |
Sequence.Name | string | SNMP | 对象中某个属性的名称,属性名的取值和mib文件中定义的一致。 |
Sequence.Type | string | SNMP | 对象中某个属性的类型,和mib文件中定义的一致,取值包含:string 、number 、integer 、object 、array 、boolean 。 |
Sequence.Access | string | SNMP | 对象中某个属性的访问权限,和mib文件中定义的一致,取值包含:Readonly、Readwrite。 |
Sequence.Primary | boolean | SNMP | 对象中某个属性是否为主键,同一个对象中可能存在多个属性被设置为主键,此字段配置信息和mib文件保持一致。 |
Resources.Interfaces | array | All | 资源方法的集合,包含 GET/PATCH/POST/DELETE 四类方法,单个资源包含的方法映射类型按实际情况进行配置,单一资源中每类方法只能配置一个。 |
Interfaces.Type | string | All | 方法的类型,取值包含 GET 、PATCH 、POST 、DELETE 四类,不区分大小写,具体分类:1. Redfish/Web_backend包含 GET 、PATCH 、POST 、DELETE 四类。2. CLI包含 GET 和 PATCH ,其中 ipmcget 对应 GET , ipmcset 对应 PATCH 。3. SNMP包含 GET 和 PATCH ,分别对应获取和设置操作。 |
Interfaces.LockdownAllow | boolean | All | 系统锁定状态下是否允许执行设置类接口(PATCH/POST/DELETE)。系统锁定后,该配置值为 true 时允许操作,否则不能执行。 |
Interfaces.Usage | string | CLI | 当输入的CLI命令可以唯一匹配到指定命令,但是 -v 后的参数不匹配,需提示出该命令的具体使用方法,该字段用来描述命令的正确使用格式 |
Interfaces.Brief | string | CLI | 当输入的CLI命令可以唯一匹配到指定命令,但是 -v 后的参数不匹配,需提示出该命令的简要描述,该提示信息在此字段配置,未配置则不显示。 |
Interfaces.Examples | array | CLI | 当输入的CLI命令可以唯一匹配到指定命令,但是 -v 后的参数不匹配,需提示出该命令的使用样例,该提示信息在此字段配置,可配置多个样例,未配置则不显示。 |
Interfaces.Description | string | CLI | 当输入的CLI命令未精确匹配到指定命令,则提示最接近当前输入的所有命令列表,每个命令的描述信息来源于此字段。 |
Interfaces.Echoes | array | CLI | 回显到客户端数据的模板路径。 |
Interfaces.ReqBody | string | All | 方法的请求体定义,属性支持嵌套配置,用关键字 Properties 描述下一级属性。 |
ReqBody.Name | string | All | 请求消息体中描述某属性的属性名,与对外接口的定义保持一致。 |
ReqBody.Type | [string, array] | All | 请求消息体中描述某属性的属性类型,与对外接口的定义保持一致,该字段取值范围:string 、number 、integer 、object 、array 、boolean 、null 。若该字段为数组类型,则该属性的取值可为多种类型。 |
ReqBody.Items | [object, array] | All | 适用于请求消息体属性为数组的情况,用于定义数组内的元素。 List Validation模式数组(数组内元素定义一致)可采用object类型,该定义对数组内所有属性生效。 Tuple Validation模式数组(数组内元素有多种定义)可采用array类型,定义的索引与请求消息体属性中的索引一一对应。 |
ReqBody.maxItems | number | All | 适用于请求消息体属性为数组的情况,用于定义数组的最大元素数量。 |
ReqBody.minItems | number | All | 适用于请求消息体属性为数组的情况,用于定义数组的最小元素数量。 |
ReqBody.uniqueItems | boolean | All | 适用于请求消息体属性为数组的情况,用于定义数组内的每个元素均不相同,默认允许数组包含重复元素。 |
ReqBody.Properties | object | All | 请求消息体中,当前属性的下一级属性的集合。 |
ReqBody.LockdownAllow | boolean | All | 与 Interfaces.LockdownAllow 字段的功能一致,该字段用于修饰PATCH接口中的单个属性,而不是整个接口 |
ReqBody.Required | boolean | All | 请求消息体属性是否为必选属性。 |
ReqBody.Description | string | CLI | 当输入的CLI命令可以唯一匹配到指定命令,但是 -v 后的参数不匹配,需提示该命令 -v 后参数的描述信息,该提示信息在此字段配置,未配置则不显示。 |
ReqBody.Sensitive | boolean | All | 请求消息体属性是否为敏感信息,敏感信息在错误信息中将替换为 ****** 。 |
ReqBody.Validator | array | All | 请求消息体属性的校验规则,同时满足数组中所有的校验规则,该属性的取值才有效 |
Interfaces.Query | object | All | 用于配置默认查询参数。 Redfish的查询参数存在使用限制。 |
Interfaces.RspBody | object | All | 方法的响应体。 |
Interfaces.Statements | object | All | 语句定义,用于数据的加工处理。 |
Statements.x.Input | [string, array] | All | 待加工处理的数据来源定义。 |
Statements.x.Steps | array | All | 处理过程定义,按数组定义顺序有序执行,上一步的执行结果为下一步执行的输入。 |
Interfaces.ProcessingFlow | array | All | 资源协作接口入口,按数组定义的顺序有序执行。 |
ProcessingFlow.Path | string | All | 资源协作接口Path,支持动态参数。 |
ProcessingFlow.Interface | string | All | 资源协作接口Interface。 |
ProcessingFlow.Destination | object | All | 资源协作接口数据目的区,数据由资源协作接口存入暂存区。Key:资源协作接口的属性名,Value:数据暂存区属性名。 |
ProcessingFlow.Source | object | All | 资源协作接口数据来源区,数据从定义的来源存入资源协作接口。Key:资源协作接口的属性名,Value:数据来源定义。 |
ProcessingFlow.Name | string | All | 资源协作接口方法名称。 |
ProcessingFlow.Params | array | All | 资源协作接口方法入参,数组定义参数的顺序与资源协作接口方法入参顺序一致。 |
ProcessingFlow.CallIf | [object, string] | All | 动态决定ProcessingFlow执行模式,包含 object 与 string 两种形态。 1. object类型,Key为数据来源的定义,Value为校验的预期结果。Value为 #WITH 时,预期为数据存在。Value为 #WITHOUT 时,预期为数据不存在。其余字段代表实际预期结果。该形态使用方式与 Resources.ResourceExist 相同。2. string类型,使用预设执行模式,当前预设执行模式有: · CheckUri :在资源存在性校验时执行,为资源存在性校验提供暂存区数据。 |
ProcessingFlow.Foreach | string | All | 用于迭代数组,#INDEX 表示当此迭代次数。可以通过 ${<数组路径>[#INDEX]} 引用当前迭代的数组元素。 |
Interfaces.Authentication | object | CLI | 描述该命令是否需要鉴权。若配置了该关键字,则对应命令会提示用户输入密码,然后自动进行认证处理。 |
Interfaces.Confirm | object | CLI | 描述该命令是否需要二次确认。若配置了该关键字,则对应命令会提示用户进行确认。 |
Authentication.Description Confirm.Description | string | CLI | 用户交互的提示信息。 |
Authentication.Condition Confirm.Condition | string | CLI | 对 -v 后的参数做条件判断,若判断结果为 true,则进行交互行为,该字段默认为true。若配置该字段为false,优先使用 Confirm 关键字。 |
映射符号
关键字 | 说明 |
---|---|
${...} | 数据引用,全路径方式引用到某个变量,引用的数据来源包含 Uri 、ReqBody 、Statements 、ProcessingFlow[...]/Destination 、Foreach 。使用样例: · ${Uri/Id} · ${ReqBody/IpAddr} · ${Statements/GetId()} · ${ProcessingFlow[1]/Destination/Name} |
[...] | 数组引用,可对数组变量进行下标引用,若为 Foreach 场景,则用 #INDEX 表示当此迭代。使用样例: ${Statements/GetPath()[#INDEX]} |
() | 语句调用,在调用Statements时使用。 |
/ | 下级属性引用。 |
{{...}} | 全局数据引用,引用数据配置在接口的 config.json 文件中。使用样例: {{OemIdentifier}} |
#WITH | 资源存在,用于数据校验。 |
#WITHOUT | 资源不存在,用于数据校验。 |
Statements关键字
关键字 | 说明 |
---|---|
Prefix-Add | 增加 Formula 中配置的前缀。 |
Prefix-Trim | 删除 Formula 中配置的前缀。 |
Suffix-Add | 增加F Formula 中配置的后缀。 |
Suffix-Trim | 删除 Formula 中配置的后缀。 |
Count | 输入属性包含元素的个数。 |
Convert | 数据类型转换,转换形式在 Formula 中配置。转换形式:NumberToBool 、BoolToNumber 、NumberToString 、StringToNumber 、FloatToInteger 、ToHex 、Tohex |
DateFormat | 将时间戳转化为指定格式的日期类型,Formula 为数组类型,第一个参数为指定的日期格式,第二个参数为是否显示当地的时区。 |
L-Pair | 将数组类型数据与 Formula 作Pair处理,以 Formula 中的字符串为Key,数组元素为Value,拼装成对象。 |
Switch | 数据替换。Formula 中定义了替换规则数组,替换规则中 From 为匹配项,To 为替换项,没有匹配项的替换规则为默认规则(default规则)。若输入数据满足任意匹配项,则转化为该替换规则中替换项。不满足任何匹配项的数据视为满足默认规则,没有默认规则时该数据不做替换。 |
Expand | 将输入数据作为uri进行资源展开,输入uri可以为内部uri。Formula 为展开层数,当前openUBMC仅支持一层展开(即 Formula 为1)。 |
Script | 脚本自定义规则。一般用于代码比较简单、不与业务耦合的场景。Formula 为代码或代码所在文件路径。代码可使用的全局变量包含: string 、math 、type 、table 、ipairs 、pairs 、next 、error 、base_messages 、custom_messages 、tonumber 、tostring 、cjson 、null 、lua_nil 、Uri 、ReqBody 、Query 、Context 、ProcessingFlow 、Input 。 |
Plugin | 插件自定义规则。一般用于耦合业务、比较“重型”的场景。Formula 为 “FileName.FunctionName(...)” 的形式,其中 FileName 为插件文件名,FunctionName 为插件中定义的函数名,... 为函数入参。函数入参支持的关键字包含: Uri 、ReqBody 、Query 、Context 、ProcessingFlow 、Input 。插件代码可使用的全局变量包含: bus 、mdb 、require 、libroutemapper_utils 、mapper_interface 、string 、math 、type 、table 、ipairs 、pairs 、next 、pcall 、xpcall 、error 、base_messages 、custom_messages 、tonumber 、tostring 、cjson 、null 、lua_nil |
Validator关键字
关键字 | 说明 |
---|---|
Range | 用于 integer 和 number 类型。校验属性的取值范围,取值范围包含左右边界。 |
Length | 用于 string 类型。校验字符串的长度限制,长度限制包含左右边界。 |
Enum | 用于 integer 、number 和 string 类型。校验属性的枚举类型。 |
Nonempty | 用于 string 类型。校验属性为非空字符串。 |
IPFormat | 用于 string 类型。校验属性为IP格式 |
Regex | 用于 string 类型。校验属性满足正则匹配规则。 |
Script | 脚本自定义校验规则。 |
通用格式
接口映射配置的通用格式:
{
"Resources": [
{
"Uri": "xxxx",
"Interfaces": [
{
"Type": "GET/PATCH/POST/DELETE",
"ResourceExist": {xxxx},
"ReqBody": {xxxx},
"RspBody": {xxxx},
"RspHeader": {xxxx},
"Statements": {xxxx},
"ProcessingFlow": [xxxx]
}
]
}
]
}
Resources
: Uri配置对象数组Interfaces
:Uri所对应的多种Type
的请求配置数组Type
:请求方法,支持GET、PATCH、POST、DELETE
ResourceExist
: Uri有效性校验ReqBody
:请求体配置RspBody
:响应体配置RspHeader
: 响应头配置Statements
: 数据处理ProcessingFlow
:资源协作接口映射配置
Uri有效性校验
在Uri配置中,需要利用动态字段指明同类资源中的某个具体资源。因此需要根据资源存在与否,校验访问Uri的有效性,相当于接口的入参校验。 例如"Uri": "/redfish/v1/Managers/:managersid"
中:managersid
就是动态参数。对于机架机型,一般有效取值为1,外部需要访问Uri:/redfish/v1/Managers/1
进行正确的接口访问
"ResourceExist": {
"${Uri/managersid}": "1",
"${Statements/GetName()}": "#WITH",
"${ProcessingFlow[1]/Destination/Valid}": true
}
当ResourceExist
字段中配置每个键值对中key==value
的判断均成立时,入参校验成功,资源存在条件全部满足,Uri校验成功。 上述例子中,除了当Uri/managersid
取值为"1"这个判断固定结果的条件外,还有另外两个条件需要满足。 其中#WITH
和#WITHOUT
来表示属性是否为nil;true和false作为bool类型值的判定规则。
只有当Uri/managersid
取值为"1"、Statements/GetName()
不为nil、ProcessingFlow[1]/Destination/Valid
取值为true,所有条件都满足时Uri校验成功。(ProcessingFlow的配置被ResourceExist直接或间接引用时,需要加上配置"CallIf": "CheckUri") 注:由于PATCH
接口在处理前会会调用一次对应GET
接口,所以PATCH
无需再配置ResourceExis
。
ReqBody声明
用户在发送请求时可能会携带请求体,由于请求体是用户输入,在实际使用中未必能按照预期输入数据,例如属性类型要求是字符串类型,但是用户输入却是数字。所以需要一种语法来声明请求体的数据内容,对请求体格式做最基本的校验,这里使用ReqBody
来声明。(ReqBody
声明类似JSON Schema官方文档的语法规范)
以如下请求体为例(假设UserName
是必填属性,且只允许取值Administrator
或root
):
{
"UserName": "root"
}
其对应的ReqBody配置应该为
"ReqBody": {
"Type": "object",
"Required": true,
"Properties": {
"UserName": {
"Type": "string",
"Required": true,
"Validator": [
{
"Type": "Enum",
"Formula": ["Administrator", "root"]
}
]
}
}
}
下面将详细说明请求体校验的的规则配置
完整性校验
关键字Required
用于声明请求体属性是否为必填参数,取值true/false
,未配置时取默认值false
。
"ReqBody": {
"Type": "object",
"Required": true,
"Properties": {
"PropA": {
"Required": true
},
"PropB": {
"Required": false
},
"PropC": {
"Type": "object",
"Properties": {
"Prop1": {
"Required": true
}
}
}
}
}
例如上述声明,请求体为{"PropA": 1}
或者{"PropA": 1, "PropB": 2}
是符合要求的(PropC
对象不存在时,不需要对PropC/Prop1
做完整性校验);请求体为{"PropA": 1, "PropC": {}}
或者{"PropB": 2}
是不符合要求的,前者缺少PropC/Prop1
,后者缺少PropA
。
数据类型校验
Type
关键字是数据类型校验的基础,可以是一个字符串或数组:
- 字符串,指定数据类型,可能取值
array、boolean、integer、number、null、object、string
- 字符串数组,允许多种类型,其中每个字符串是其中一种基本类型的名称,每个元素都是唯一的。在这种情况下,请求体数据与任一元素类型匹配上即可。
"ReqBody": {
"Type": "object",
"Required": true,
"Properties": {
"PropA": {
"Type": "string"
},
"PropB": {
"Type": ["number", "boolean"]
}
}
}
例如上述声明,请求体{"PropA": "str", "PropB": 1}
符合要求,{"PropA": 1, "PropB": "str"}
不符合要求。PropA
必须是字符串类型,PropB
可以是数字或者布尔类型。
除了boolean、integer、number、null、string
这些易于理解的基础类型外,下面对复合类型object、array
进行说明
object对象类型
对象(object
)是 JSON 中的映射类型,将“键”映射到“值”。在 JSON 中,“键”必须始终是字符串。这些对中的每一组通常被称为“属性”。 对象的属性(键值对)是使用Properties
关键字定义的 。Properties
的值是一个对象数组,数组的每个元素用于声明属性的特性,其内部同样也可以使用Type、Required
等关键字配置数据类型和完整性校验。
array数组类型
数组用于有序元素。在 JSON 中,数组中的每个元素可能是不同的类型。 JSON 中数组的使用一般有两种方式:
列表验证:任意长度的序列,其中每个元素都匹配相同的模式。
元组验证:一个固定长度的序列,其中每个元素可能有不同的模式。
列表验证 列表包含
Items、minItems、maxItems和uniqueItems
等关键字。Items
: 定义列表的单个元素校验,可以使用Type
等关键字。maxItems
: 定义列表的最大元素个数。缺省情况下不校验列表参数的最大元素个数。minItems
: 定义列表的最小元素个数。缺省情况下不校验列表参数的最小元素个数。uniqueItems
: 定义是否需要保证每个数组元素不相同。配置为true
,数组中的每一个元素必须唯一,配置为false
,则允许数组包含重复元素。缺省情况下为false
。json"ReqBody": { "Type": "object", "Required": true, "Properties": { "PropA": { "Type": "array", "Items": { "Type": "number" }, "minItems": 2, "maxItems": 5, "uniqueItems": true } } }
上述配置中属性
PropA
是一个数组,数组的每个元素都是数字,最少包含2个元素,最多包含5个元素,且数组中每个元素都不相同。元组验证
当数组是一个元素的集合时,元组验证很有用,每个元素可能有不同的模式。例如一个三元组 [编号、用户名、是否锁定],这些字段中的每一个都将具有不同的模式:
Id
:编号,必须是数字UserName
: 用户名,必须是字符串Locked
:是否锁定,必须是布尔值true/falseItems关键字设置为一个数组,其中每个元素都是一个模式,对应于元组的每个索引。也就是说,一个数组,其中第一个元素验证输入数组的第一个元素,第二个元素验证输入数组的第二个元素,依此类推。
json"ReqBody": [ { "Name": "PropA", "Type": "array", "Items": [ { "Type": "number" }, { "Type": "string" }, { "Type": "boolean" } ] }, ]
上述例子中,当PropA
的取值为[10086, 10001, true]
是不符合要求的,第二个元素必须是字符串,而10001
是一个数字。[10086, "root", true]
时是符合要求的,[10086, "root"]
和[10086, "root", true, "str"]
也是符合要求的。
数据内容校验Validator
有时需要对请求体属性内容做一些简单的校验,例如字符串长度符合范围或者限制为一组固定的值,这里使用关键字Validator
来声明相关内容校验,其中校验的种类由Type
字段来表征,当前支持的Type
可见下述各小节
{
"Name": "Prop",
"Validator": [
{
"Type": xxx,
"Formula": xxx
}
]
}
Enum
{
"Type": "Enum",
"Formula": ["Administrator", "root", "Admin"]
}
枚举校验,Formula
配置符合范围的取值数组,其中每个元素都唯一。可用于boolean、integer、number、null、string
简单数据类型的检验。(也可配置object
或者array
复杂结构,不推荐使用,复杂结构也要进行对应声明)
Length
{
"Type": "Length",
"Formula": [1, 16]
}
校验字符串长度。Formula
指定长度上下限(闭合区间),若上限或下限无要求,可配置为null
。
Nonempty
{
"Type": "Nonempty"
}
字符串非空校验,取值""
是不符合要求的。
Range
{
"Type": "Range",
"Formula": [1, 16]
}
数字范围校验,可用于integer
和number
数据类型,Formula
指定范围上下限(闭合区间),若上限或下限无要求,可配置为null
Regex
{
"Type": "Regex",
"Formula": "^xx[0-9]"
}
正则匹配校验(标准正则,非Lua
正则),可用于string
数据类型。上述例子中,取值"xx1"
符合要求,取值"xxx"
不符合要求
IPFormat
{
"Type": "IPFormat",
}
IP格式校验,,可用于string
数据类型。
Script
{
"Type": "Script",
"Formula": "if Input % 5 == 0 then local err = base_messages.PropertyValueFormatError(Input, PropertyName) err.RelatedProperties = {'#/' .. PropertyName} error(err) end return true"
}
复用数据处理中的Script
,具体使用规则可见数据处理statements章节。校验失败则执行error
抛出错误(必须是BMC定义的通用错误)。校验通过返回true或nil
。 相比较数据处理的Script,环境变量变化如下:
Input
:校验的属性取值PropertyName
: 新增变量,表示校验的属性名,例如Oem/openubmc/PropA
ProcessingFlow
: 校验时并未进行资源协作接口访问,故删除此变量
敏感信息打码Sensitive
当请求体存在敏感数据,错误Message中应该将该字段的值打码为******
。引入Sensitive
关键字,用于表示需要将该属性的取值打码,避免敏感数据直接呈现在Message
信息中。 敏感信息必须显示配置"Sensitive": true
,openUBMC涉及的敏感信息包括但不限于:用户密码、会话token等。
"ReqBody": {
"Type": "object",
"Required": true,
"Properties": {
"Password": {
"Type": "string",
"Sensitive": true
}
}
}
当请求体取值{"Password": 111}
,类型校验失败,其拿到的错误信息为:
"MessageId": "Base.1.0.PropertyValueTypeError",
"Message": "The value ****** for the property Password is of a different type than the property can accept.",
"MessageArgs": [
"******",
"Password"
],
...
RspBody定义
RspBody为接口响应体格式配置关键字,拼接从资源协作接口或者数据处理后获取的属性值,返回给用户侧,作为接口调用回显。
例如如下的RspBody配置:
"RspBody": {
"@odata.context": "/redfish/v1/$metadata#AccountService/Accounts/Members/$entity",
"Name": "User Account",
"UserName": "${ProcessingFlow[1]/Destination/UserName}",
"Oem": {
"openubmc": {
"LoginRule": null
}
}
}
其中${ProcessingFlow[1]/Destination/UserName}
表示数据需要从资源协作接口获取,详细规则可见下一章节资源协作接口映射配置ProcessingFlow,当其获取的值为"Administrator"
时,用户侧收到的响应体如下:
{
"@odata.context": "/redfish/v1/$metadata#AccountService/Accounts/Members/$entity",
"Name": "User Account",
"UserName": "Administrator",
"Oem": {
"openubmc": {
"LoginRule": null
}
}
}
资源协作接口映射配置ProcessingFlow
一般格式为:
"ProcessingFlow": [
{
"Type": "Property/Method/List/Task/Paging"
"Path": "xx",
"Interface": "xxx",
"Name": "xxx",
"Params": [xxx],
"Destination": {xxx},
"Source": {xxx},
"CallIf": {xxx},
"Foreach": "xxx"
},
xxx
]
通用字段说明:
ProcessingFlow
:取值必须为对象数组,每个对象指明一个资源协作接口映射,对象的映射数据按序执行Type
: 映射类型,当前支持Property/Method/List/Task/Paging
,具体使用方式可下述各小节(Paging仅CLI接口使用)Path
:MDS对象Interface
: 资源协作接口Name
: 方法名Params
:方法参数Destination
:返回值配置Source
: 设置属性时使用CallIf
:资源协作接口是否调用,适用于所有映射类型,规则可见CallIfForeach
: 资源协作接口多次调用,适用于所有映射类型,规则可见Foreach
Property属性
获取属性
json{ "Type": "Property", "Path": "/bmc/kepler/Managers/1/EthernetInterfaces/Ipv4", "Interface": "bmc.kepler.Managers.EthernetInterfaces.Ipv4", "Destination": { "IpMode": "IpModeIpv4", "IpAddr": "IpAddrIpv4", "SubnetMask": "SubnetMask" } }, { "Type": "Property", "Path": "/bmc/kepler/Managers/1/EthernetInterfaces/Ipv6", "Interface": "bmc.kepler.Managers.EthernetInterfaces.Ipv6", "Destination": { "IpMode": "IpModeIpv6" } }
Destination
配置了一系列键值对,key
表示资源协作接口上的属性名,获取该属性,该将属性名称重名为value
。
因为不同资源协作接口可能存在相同的属性名,有重命名的存在,就可以避免命名冲突。如上例,${ProcessingFlow[1]/Destination/IpModeIpv4}
说明获取的是IPv4资源协作接口的IpMode属性;${ProcessingFlow[2]/Destination/IpModeIpv6}
说明获取的是IPv6资源协作接口的IpMode属性设置属性
json{ "Type": "Property", "Path": "/bmc/kepler/Managers/1", "Interface": "bmc.kepler.Managers.Ntp", "Source": { "Preferred": "${ReqBody/PreferredServer}" } }
与获取属性的结构类似,关键字改为
Source
。上述例子中将请求体中的PreferredServer
属性值设置到资源协作接口的属性Preferred
中
Method
{
"Type": "Method",
"Path": "/bmc/kepler/Systems/Events",
"Interface": "bmc.kepler.Systems.Events",
"Name": "GetSelInfo",
"Params": [
"123"
],
"ContextParams": {
"SystemId": "1"
},
"Destination": {
"Version": "Version",
"CurrentEventNumber": "CurrentEventNumber",
"MaxEventNumber": "MaxEventNumber"
}
}
Name
: 方法名Params
:方法参数,可缺省,表示没有参数(不包括上下文参数)ContextParams
: 上下文参数配置,对应资源协作接口中的方法调用所需的a{ss}上下文参数Destination
:与获取属性配置类似,左边的key对应方法返回值的变量名,右边的value对应开发者配置的变量名
以上述配置为例,在实际环境使用busctl调用方法,有如下返回:
> busctl --user call bmc.kepler.event /bmc/kepler/Systems/Events bmc.kepler.Systems.Events GetSelInfo a{ss} 0
suu "1.0.0" 0 10000
返回为suu "1.0.0" 0 10000
,suu
表示后接数据类型依次是String、U32、U32
。此处并未能看出Version、CurrentEventNumber、MaxEventNumber
字段。
查看GetSelInfo
的声明(在mdb_interface
仓中有关于资源协作接口返回字段的声明),rsp
包含对返回字段的声明
"GetSelInfo" :{
"req": {},
"rsp": {
"Version": {
"baseType": "String"
},
"CurrentEventNumber": {
"baseType": "U32"
},
"MaxEventNumber": {
"baseType": "U32"
}
}
}
使用代理对象调用method
时,会对返回值做结构化封装,例如GetSelInfo
方法的返回值应该为:
{
Version = "1.0.0",
CurrentEventNumber = 0,
MaxEventNumber = 1000
}
List
{
"Type": "List",
"Path": "/bmc/kepler/Managers/1/NetworkProtocol",
"Interface": "bmc.kepler.Managers.NetworkProtocol.Protocol",
"Params": [1],
"Destination": {
"Members": "service_table"
}
}
获取资源协作接口集合。
Interface
:未配置时获取MDS子对象所有资源协作接口,配置时获取包含Interface的资源协作接口。Params
:可按需配置。Params[1]表征获取深度,例如1表示MDS子对象,2表示MDS子子对象。Params未配置时默认表示深度1。
上述例子中/bmc/kepler/Managers/1/NetworkProtocol资源有如下MDS子对象(子对象的资源协作接口均有bmc.kepler.Managers.NetworkProtocol.Protocol)
> busctl --user tree bmc.kepler.nsm
└─/bmc
└─/bmc/kepler
└─/bmc/kepler/Managers
│ └─/bmc/kepler/Managers/1
│ └─/bmc/kepler/Managers/1/NetworkProtocol
│ ├─/bmc/kepler/Managers/1/NetworkProtocol/HTTP
│ ├─/bmc/kepler/Managers/1/NetworkProtocol/HTTPS
│ ├─/bmc/kepler/Managers/1/NetworkProtocol/KVMIP
那么配置的结果为,Destination增加了如下键值对
"service_table": [
"/bmc/kepler/Managers/1/NetworkProtocol/HTTP",
"/bmc/kepler/Managers/1/NetworkProtocol/HTTPS",
"/bmc/kepler/Managers/1/NetworkProtocol/KVMIP",
......
]
Task
{
"Type": "Task",
"Path": "/bmc/kepler/Managers/1/LogServices",
"Interface": "bmc.kepler.Managers.LogServices",
"Name": "Dump",
"Params": [
0
],
"Destination": {
"TaskId": "TaskId"
},
"PostTaskProcess": [
{
"Type": "ChangeOwner",
"Params": [
"/tmp/web/operate.log"
]
}
]
}
Task
是一种特殊的Method,用于异步执行的方法。
PostTaskProcess
, 任务后置操作,用于配置在task执行完毕后执行指定操作。Type指明操作类型,目前已支持在文件导出任务后执行修改文件属主和权限。ChangeOwner
: 修改文件属主为当前用户,修改文件权限为600,参数:本地文件绝对路径(不支持远程文件路径)
补充:一个ProcessingFlow
中可以配置多个Task
,但是只应该有一个生效。可以通过CallIf
条件来控制具体执行的Task
CallIf
"CallIf": {
"${ReqBody/PropA}": "#WITH"
"${ReqBody/PropB}": "#WITHOUT",
"${ReqBody/PropC}": "str1",
"${Uri/id}": 1
}
只有当每个属性判断均成立,CallIf条件才成立,对应的Methods等才有必要执行。引入#WITH
和#WITHOUT
来表示属性是否存在。 上述例子表明,只有当ReqBody/PropA
存在、ReqBody/PropB
不存在、ReqBody/PropC
取值为"str1"、Uri/id
取值为1,四个条件都满足时CallIf条件才成立。
Foreach
"ReqBody": {
"Type": "object",
"Required": true,
"Properties": {
"SnmpTrapNotification": {
"Type": "object",
"Properties": {
"TrapServer": {
"Type": "array",
"Items": {
"Type": "object",
"Properties": {
"TrapServerPort": {
"Type": "number"
}
}
}
}
}
}
}
},
"ProcessingFlow": [
{
"Type": "Property",
"Path": "/bmc/kepler/EventService/Subscriptions/Snmp/Nmses/${#INDEX}",
"Interface": "bmc.kepler.EventService.Subscriptions.Snmp.Nms",
"Source": {
"Port": "${ReqBody/SnmpTrapNotification/TrapServer[#INDEX]/TrapServerPort}"
},
"Foreach": "${ReqBody/SnmpTrapNotification/TrapServer}"
}
]
上述配置例子,请求体中SnmpTrapNotification/TrapServer是一个数组,需要根据数组大小多次设置bmc.kepler.EventService.Subscriptions.Snmp.Nms的属性。
{
"SnmpTrapNotification": {
"TrapServer": [
{
"TrapServerPort": 3162
},
{
"TrapServerPort": 3163
},
{
"TrapServerPort": 3164
},
{
"TrapServerPort": 3165
}
]
}
}
假设请求体为上述配置,SnmpTrapNotification/TrapServer数组大小配置为4,通过语句"Foreach": "${ReqBody/SnmpTrapNotification/TrapServer}"
可断定需要设置属性4次(Foreach也可直接配置数字)。第一次时,Path为/bmc/kepler/EventService/Subscriptions/Snmp/Nmses/1
,数据源为${ReqBody/SnmpTrapNotification/TrapServer[1]/TrapServerPort} (#INDEX和Foreach配套使用,#INDEX会被替换成迭代时的次数)。
数据引用
数据引用:某些位置(DEST)需要使用来自外部的数据(SRC),例如响应体需要使用资源协作接口集合上的数据。
为了简化引用数据,以相同的格式来获取SRC数据,定义规则:${var}表示var的取值来自于外部数据SRC,例如${ReqBody/xxx}
表示引用请求体ReqBody
中的xxx属性 数据引用得到的数据类型是JsonObject,即有序json
数据来源
对于接口映射配置来说,作为外部数据的有:
Uri
: URI包含的动态字段Query
:查询参数ReqBody
:请求体中的数据ReqBodyOriginal
:请求体中的原始数据;ReqBody在校验时会删除异常数据,执行ProcessingFlow配置时获取不到,此时可获取ReqBodyOriginalReaHeader
: 请求头中的数据Context
: 上下文信息,包含的字段如下:- cli:Interface(取值CLI)、UserName、ClientIp、Privilege
- redfish用户密码鉴权方式:Interface(取值Redfish)、UserName、ClientIp、Privilege、RoleId、AccountId
- redfish会话鉴权方式:除用户密码鉴权方式的字段外,还额外支持AuthType、Token、SessionId
- web_backend:Interface(取值WEB)、UserName、ClientIp、Privilege、AccountId、RoleId、AuthType、Token、SessionId
- snmp:Interface(取值SNMP)、UserName、ClientIp、Privilege
ProcessingFlow[].Destination
:从资源协作接口中获取的数据
引用位置配置方式
- 1、属性写死
(非数据引用)理想的状态下,大部分引用位置的取值应该都是写死,是一个纯数据。
"RspBody": {
"Prop": "redfish/v1/Systems/1"
}
- 2、简易方式
框架会把${var}替换成外部数据中var的取值。
例如var取值为1,Prop的取值则为"redfish/v1/Systems/1"
"RspBody": {
"Prop" : "redfish/v1/Systems/${var}"
}
- 3、Statements方式
很多时候,拿到外部数据之后,并不能直接使用,而是需要做某些操作之后才可以使用。
这里定义"${Statements/Prop()}"
表示数据配置在Statements.Prop
中(注意:Statements/Prop
后接一对括号)。Statements.Prop
配置的含义为:引用var
的数据,经过多个Steps
处理后的取值。Statements
支持多种类型的配置,具体可见数据处理章节
"RspBody": {
"Prop" : "${Statements/Prop()}"
},
"Statements": {
"Prop": {
"Input": "${var}"
"Steps": [ {xxxx} ]
}
}
数据处理Statements
数据处理:拿到资源协作接口中的数据之后,需要做一些加工操作,才能使用
"Statements": {
"Prop": {
"Input": "${var}"
"Steps": [
{
"Type": "xxxx",
"Formula": "xxxxx"
},
{
"Type": "xxxx",
"Formula": "xxxxx"
},
]
}
}
Input:处理的数据源,取值必须是引用外部数据
Steps:数组类型,可配置多个处理逻辑。Input是Steps[1]的输入,Steps[1]的输出为Steps[2]的输入,依次类推;Steps[n]的输出为最终处理结果
Steps[].Type:指明数据处理的类型,可参考下列各小节说明
Steps[].Formula:数据处理的公式、规则。可嵌套配置数据引用
Convert
{
"Type": "Convert",
"Formula": "StringToNumber"
}
数据类型转换,上述中将字符串转换为数字类型,例如输入"12"
,输出为12
Formula指明转换的类型,当前支持的取值有:
NumberToBool
:数字转换为布尔值(0转换为false,非0转换为true)BoolToNumber
: 布尔值转换为数字(false转换为0,true转换为1)NumberToString
:数字转换为字符串StringToNumber
:字符串转换为数字FloatToInteger
:浮点型整数转换为整数。小数点后不为0,转化为nil,例如输入3.1,输出nilToHex
:数字转为16进制字符串,字母为大写Tohex
:数字转为16进制字符串,字母为小写
若输入数据类型与Formula声明的转换前类型不匹配时,输出为nil
Count
{
"Type": "Count"
}
输入数据必须为数组类型,计算该数组大小,无需Formula字段。 例如输入为["1", "2", "3"]
时,输出为3
。
Expand
{
"Type": "Expand",
"Formula": "1"
}
输入数据必须为可访问的URI字符串,Formula默认取值"1"。
Expand的作用是将URI原地替换为该URI对应的响应体。
注意:如果Expand的并非预期单独可访问的URI,不要以/redfish或者/UI/Rest开头,推荐以/expand或者/bmc/kepler开头,这样此URI在访问时会被nginx直接拦截,不会重定向到接口层业务层。
假如/redfish/v1/AccountService/Accounts/2
的响应体为
{
"UserName": "Administrator",
"RoleId": "Administrator",
"Locked": false,
}
那么输入为/redfish/v1/AccountService/Accounts/2
时,输出与上述响应体一致。
输入数据也可以是字符串数组,每个字符串都必须是可访问的URI,Expand操作会将每个字符串都原地替换为该URI对应的响应体。 假如/redfish/v1/AccountService/Accounts/3
的响应体为
{
"UserName": "Admin",
"RoleId": "Administrator",
"Locked": false,
}
那么输入为 ["/redfish/v1/AccountService/Accounts/2", "/redfish/v1/AccountService/Accounts/3"]
时,输出为:
[
{
"UserName": "Administrator",
"RoleId": "Administrator",
"Locked": false,
},
{
"UserName": "Admin",
"RoleId": "Administrator",
"Locked": false,
}
]
如果是资源协作接口路径遍历处理,可以添加资源协作接口的Uri,来获取响应数据
{
"Uri": "/bmc/kepler/AccountService/Accounts/:id",
"Interfaces": [
{
"Type": "Get",
"RspBody": {
"UserName": "${ProcessingFlow[1]/Destination/Id}",
"RoleId": "${ProcessingFlow[1]/Destination/Source}",
"Locked": "${ProcessingFlow[1]/Destination/Destination}",
},
"ProcessingFlow": [
{
"Type": "Property",
"Path": "/bmc/kepler/AccountService/Accounts/${Uri/id}",
"Interface": "bmc.kepler.AccountService.ManagerAccount",
"Destination": {
"UserName": "UserName",
"RoleId": "RoleId",
"Locked": "Locked"
}
}
]
}
]
}
输入数据也可以是对象数组,每个对象只有一个键值对,键必须为@odata.id
, 值必须为可访问的URI字符串,Expand
操作会将每个对象都原地替换为该URI对应的响应体。
L-Pair
{
"Type": "L-Pair",
"Formula": "@odata.id"
}
输入必须为数组,Formula
可取任意字符串。L-Pair
是将Formula
作为key
,数组元素作为value
,拼装成对象,替换原来的元素。
例如输入为["/redfish/v1/System/Blade1", "/redfish/v1/System/Blade2", "/redfish/v1/System/Blade3"]
,Formula
为@odata.id
时,输出为:
[
{"@odata.id": "/redfish/v1/System/Blade1"},
{"@odata.id": "/redfish/v1/System/Blade2"},
{"@odata.id": "/redfish/v1/System/Blade3"}
]
Prefix-Add
{
"Type": "Prefix-Add",
"Formula": "/redfish/v1/"
}
Formula为待增加的前缀字符串
- 输入为字符串或者数字时,输出为Formula + 输入组合成的字符串
- 输入为数组时,则为数组每个元素都增加Formula前缀作为输出
以Formula
取值/redfish/v1/
为例; 输入为"System"
时,输出为"/redfish/v1/System"
输入为["System/Blade1", "System/Blade2"]
时,输出为["/redfish/v1/System/1", "/redfish/v1/System/Blade2"]
Prefix-Trim
{
"Type": "Prefix-Trim",
"Formula": "/bmc/kepler/"
}
Prefix-Trim为删除前缀,使用规则与Prefix-Add类似
Suffix-Add
{
"Type": "Suffix-Add",
"Formula": "/Function/1"
}
Suffix-Add
为增加后缀,Formula
为待增加的后缀字符串,以上述配置为例: 输入为"PCIeCard"
时,输出为"/PCIeCard/Function/1"
输入为["PCIeCard1", "PCIeCard2"]
时,输出为["/PCIeCard1/Function/1", "/PCIeCard2/Function/1"]
Suffix-Trim
{
"Type": "Suffix-Trim",
"Formula": "/Function/1"
}
Suffix-Trim
为删除后缀,使用规则与Suffix-Add
类似
Switch
{
"Type": "Switch",
"Formula": [
{
"Case": "Administrator",
"To": 1
},
{
"Case": "root",
"To": 2
},
{
"Case": null,
"To": 3
},
{
"To": 0
}
]
}
数据替换,类似C/Java的switch语句,Case
为分支,To
对应替换的数据(默认带break
);
仅有To
配置对应default
分支(可缺省,配置需放置在最后)。
以上述配置为例:
当输入为"Administrator"
,输出为1
;
当输入为"root"
,输出为2
;
当输入为null
或者nil(空数据)
,输出为3
;
当输入为"Admin"
,输出为0
DateFormat
{
"Type": "DateFormat",
"Formula": ["%Y-%m-%dT%H:%M:%S", true]
}
输入为时间戳(数字或者字符串数字),输出为时间字符串。Formula[1]
指定时间格式(可参考Lua
语言os.date
函数的format
参数格式),未配置时或者配置为null
时取默认值"%Y-%m-%dT%H:%M:%S"
;Formula[2]
表征是否显示时区,默认值为false
。
上述例子,当输入为1
,系统时区为+8区时,输出为"1970-01-01T08:00:01+08:00"
Script
{
"Type": "Script",
"Formula": "return ReqBody.Option == 'all'"
}
Formula
的内容是一段Lua
脚本,可实现任何复杂逻辑的处理(不推荐与其他处理类型叠加使用)。
上述例子,请求体ReqBody
的Option
为"all"
时,输出为true
,否则输出为false
。
若脚本的内容较长,放置在一行不方便阅读,可将脚本外置在文件中,Formula
配置文件名即可,例如取值get_operate_log.lua
,那么在配置文件的同级目录下需要有文件script/get_operate_log.lua
。
注:除少部分复杂逻辑无法配置,尽量减少Script
的使用。接口映射配置的本质是将接口以配置方式实现,而Script
事实上就是代码实现。
Plugin
{
"Type": "Plugin",
"Formula": "orchestrator.bios.get_registry_version(Uri.systemid)"
}
Formula
的内容是一个函数,支持入参,入参可使用ReqBody
等数据来源。Plugin
可实现复杂逻辑的业务处理(不推荐与其他处理类型叠加使用)。
以Redfish
为例,当前Redfish
插件的存放目录为/opt/bmc/apps/redfish/interface_config/plugins
,那么上述配置要求,在存放目录下有文件orchestrator/bios.lua
,并且文件有函数get_registry_version
注:减少Plugin
的使用,Plugin
的本质是抽象函数供接口配置调用,也是代码实现。
Script和Plugin的区别
Script用于纯逻辑上的处理,Formula
配置的是一段Lua
脚本或文件名,不可复用。 Plugin用于编写跟业务相关的逻辑,Formula
配置的是函数调用,需要有配套的函数实现,可复用。 Script
和Plugin
中可使用的数据变量如表格所示:
变量 | 含义 | Script环境变量 | Plugin函数入参 | Plugin环境变量 |
---|---|---|---|---|
bus | dbus总线 | ✔ | ||
mdb | mdb自省接口 | ✔ | ||
require | Lua内置函数 | ✔ | ||
libroutemapper_utils | 接口映射配置封装的C库 | ✔ | ||
mapper_interface | 接口映射配置封装的Lua库 | ✔ | ||
string | Lua标准库 | ✔ | ✔ | |
math | Lua标准库 | ✔ | ✔ | |
type | Lua内置函数 | ✔ | ✔ | |
table | Lua标准库 | ✔ | ✔ | |
ipairs | Lua内置函数 | ✔ | ✔ | |
pairs | Lua内置函数 | ✔ | ✔ | |
next | Lua内置函数 | ✔ | ✔ | |
pcall | Lua内置函数 | ✔ | ||
xpcall | Lua内置函数 | ✔ | ||
error | Lua内置函数 | ✔ | ✔ | |
base_messages | 基础消息定义 | ✔ | ✔ | |
custom_messages | 自定义的错误消息 | ✔ | ✔ | |
tonumber | Lua内置函数 | ✔ | ✔ | |
tostring | Lua内置函数 | ✔ | ✔ | |
cjson | cjson库 | ✔ | ✔ | |
null | cjson.null | ✔ | ✔ | |
lua_nil | Lua的nil取值。RspBody属性获取失败会转为null,如果属性不呈现可以用lua_nil | ✔ | ✔ | |
Uri | 数据来源 | ✔ | ✔ | |
ReqBody | 数据来源 | ✔ | ✔ | |
Query | 数据来源 | ✔ | ✔ | |
Context | 数据来源 | ✔ | ✔ | |
ProcessingFlow | 数据来源 | ✔ | ✔ | |
Input | Steps[ ]的输入 | ✔ | ✔ |
系统锁定校验LockdownAllow
LockdownAllow
用于配置系统锁定状态下操作是否允许的配置选项,值为true
代表操作允许,值为false
表示不允许。支持接口级和属性级的配置,支持内层覆盖外层的配置,未配置的默认值为false
。配置样例如下:
{
"Uri": "/redfish/v1/AccountService",
"Interfaces": [
{
"Type": "PATCH",
"LockdownAllow": false,
"Properties": {
"Oem": {
"Type": "object",
"Properties": {
"openubmc": {
"Type": "object",
"Properties": {
"SystemLockDownEnabled": {
"LockdownAllow": true,
},
"SecurityBannerEnabled": {
"Type": "boolean",
}
}
}
}
}
}
}
]
}