Northbound Interface Mapper Adaptation Guide
更新时间: 2025/11/06
在Gitcode上查看源码

Northbound Interface Mapper Adaptation Guide

Understanding the Northbound Interface Mapper Model

Model Design Goals

Northbound interfaces are standardized management interfaces provided by the BMC. Their core design goal is to implement abstraction and service-oriented hardware resources, and support flexible docking with upper-layer management protocols and ecosystem partners. The northbound interface mapper is a rackmount module that maps internal BMC data to the standardized interfaces provided by the BMC for external systems.

Main Content

The northbound interface mapper provides northbound interfaces such as Redfish, web, CLI, SNMP and IPMI.

Visit rackmount to obtain the code.

Configuring Northbound Interfaces

To configure a new interface, you need to obtain the code corresponding to the current version. First, find the rackmount library of the node used by the current product in manifest.yaml and download the corresponding node code.

New Configuration for the Redfish Interface

The Redfish interface is located in rackmount\interface_config\redfish.

Example: To add a query interface for the WelcomeMessage property of my_app (an existing community example), assume that the following D-Bus exists and contains the WelcomeMessage property:

text
~ ~ $  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    -              -

If the expected new path is /redfish/v1/Chassis/1/Myapp, perform the following steps:

  1. Search for ThresholdSensors in the existing interface_config/redfish/mapping_config/Chassis/Chassis.json file, and add the following nearby:

    json
        "MyApp": {
            "@odata.id": "/redfish/v1/Chassis/${Uri/chassisid}/MyApp"
        },

    The purpose is to display the MyApp link when the /redfish/v1/Chassis/1 path is accessed.

  2. Search for ThresholdSensors in the interface_config\redfish\mapping_config\AccountService\PrivilegeMap\PrivilegeMap.json file, and add the following nearby:

    json
    {
        "Entity": "MyApp",
        "OperationMap": {
            "GET": [
                {
                    "Privilege": [
                        "Login"
                    ]
                }
            ]
        }
    },

    If this is not added, a compilation error occurs: PrivilegeMap: GET interface: /redfish/v1/Chassis/{id}/MyApp, type: MyApp PrivilegeMap is not configured.

  3. Add the interface_config\redfish\mapping_config\Chassis\MyApp.json file with the following content:

    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"
                                }
                            }
                        ]
                    }
                ]
            }
        ]
    }

    When the /redfish/v1/Chassis/1/MyApp interface is called, the content in RspBody is returned. The value of the WelcomeMessage property is obtained according to the D-Bus property in ProcessingFlow. The source of the WelcomeMessage property is the WelcomeMessage property in bmc.demo.OpenUBMC.Community. The @odata related properties here are new and require new configuration. Refer to the next steps for the configuration method.

  4. In the interface_config\redfish\static_resource\redfish\v1\jsonschemas\ path, add a myapp folder and create a index.json file:

    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"
            }
        ]
    }

    To compile MyApp.json, the corresponding @odata static resource file needs to be found. The Uri path here must be configured correctly. Although the name of the final corresponding JSON file is entirely in lowercase, the system can handle this case discrepancy without issue.

  5. In the interface_config\redfish\static_resource\redfish\v1\schemastore\en\ directory, add a myapp.json file:

    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."
    }

    The WelcomeMessage property must match the property of the source interface. Fill in the corresponding source interface URI in uris.

  6. In the interface_config\redfish\static_resource\redfish\v1\schemastore\en\oem\huawei_chassis.json file, search for ThresholdSensors, and add the following nearby:

    json
    "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."
    },

    The Chassis.json file is associated with huawei_chassis.json. Therefore, you also need to add the file here. Otherwise, an error will be reported during compilation.

  7. Compile and run the code on the device, and access https://ip/redfish/v1/Chassis/1/MyApp to get the results.

    json
    {
        "@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"
    }
    • When you access the /redfish/v1/Chassis/1 path, the /redfish/v1/Chassis/1/MyApp link is displayed.
    json
    {
        "@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"
                },
        ...
            },
        ...
    }

New Configuration for the Web Interface

The web interface is located in the rackmount\interface_config\web_backend path.

For example, to add a query interface for the WelcomeMessage property of my_app (an existing community example) to the System path (the expected path is /UI/Rest/System/Myapp), perform the following steps:

  1. Add the MyApp.json file to the interface_config\web_backend\mapping_config\System directory.

    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"
                                }
                            }
                        ]
                    }
                ]
            }
        ]
    }

    The WelcomeMessage in RspBody matches the WelcomeMessage value found by running busctl --user introspect bmc.kepler.my_app /bmc/demo/MyMDSModel/1 | cat.

  2. WebUI verification: Use Postman to access https://ip/UI/Rest/System/MyApp. When using Postman, you need to add the cookie parameter under the key column in the header page, and fill in the cookie value in the value column. You can press F12 in the browser to open DevTools and find the cookie for the corresponding interface. Verify if the results are normal.

    json
    {
    "WelcomeMessage": "Hello"
    }

New Configuration for the CLI Interface

Example: To add a query interface for the WelcomeMessage property of my_app (an existing community example), under the ipmcget -d version command, perform the following steps:

  1. In the interface_config\cli\ipmcget\system.json file, search for "Uri": "/cli/v1/_/version":

    • Add the WelcomeMessage field in RspBody.
    json
    "WelcomeMessage": "${ProcessingFlow[13]/Destination/WelcomeMessage}",
    • Add the corresponding property mapping in ProcessingFlow.
    json
    {
        "Type": "Property",
        "Path": "/bmc/demo/MyMDSModel/1",
        "Interface": "bmc.demo.OpenUBMC.Community",
        "Destination": {
            "WelcomeMessage": "WelcomeMessage"
        }
    }
  2. In the interface_config\cli\echoes\ipmcget_version file, search for FirmwareInfo.ActiveBMCSDK.Version, and add the following below it:

    json
    MYAPP INFO      Version:         {* WelcomeMessage *}
  3. In SSH, run the ipmcget -d version command. The new information is displayed under Active BMCSDK.

    json
    MYAPP INFO      Version:         Hello

Common Issues and Solutions

Zone.Identifier Temporary File Issue

When files are copied to in a directory, a Zone.Identifier temporary file is often generated. This file also participates in compilation and causes a compilation error.

The error information is similar to the following:

text
ERROR: rackmount/1.90.222@openubmc/rc: Error in build() method, line 37
    MapperCheck.check()
    JSONDecodeError: Expecting value: line 1 column 2 (char 1)

The solution is to delete the relevant Zone.Identifier files. You can use the git status command to check if there are redundant Zone.Identifier files in Untracked files.

JSON File Debugging

If you modify multiple JSON files and are unsure which one causes an error, you can add debugging information to the mapper_check\MapperCheck.py file to help locate the error JSON file. The following is the git diff result for reference.

text
-    with open(path, 'r', encoding='utf-8') as fp:
-        return json.load(fp)
+    try:
+        print(f"Reading JSON file: {path}")
+        with open(path, 'r', encoding='utf-8') as fp:
+            data = json.load(fp)
+        print(f"✅ Successfully read: {path}")
+        return data
+    except Exception as e:
+        print(f"❌ Failed to read JSON file: {path}")
+        print(f"❌ Error message: {e}")
+        # Check if the file exists.
+        if not os.path.exists(path):
+            print(f"❌ File does not exist: {path}")
+        else:
+            # Check the file content.
+            with open(path, 'r', encoding='utf-8') as fp:
+                content = fp.read()
+                print(f"File content: {content}")
+        raise

Property Acquisition Processing Method: ProcessingFlow

If the Type under ProcessingFlow for a normally added property is Property, use List if multiple objects are obtained, and use Method if a method is used. A ProcessingFlow can contain multiple objects, each with an index starting from 1.

json
{
    "Type": "Method",
    "Path": "/bmc/kepler/MdbService",
    "Interface": "bmc.kepler.Mdb",
    "Name": "GetPath",
    "Params": [
        "bmc.kepler.Systems.FruData.Overview",
        {
            "FruId": 0
        },
        false
    ],
    "Destination": {
        "Path": "Path"
    }
},

Property Acquisition Processing Method: Statements

If data on D-Bus needs to be processed, use Statements, which can contain ProcessingFlow.

json
"Steps": [
    {
        "Type": "Plugin",
        "Formula": "orchestrator.bios.get_registry_version(Uri.systemid)"
    }

The content of Formula is a Lua script that can implement any service logic processing with complex logic. It supports input parameters, which can use data sources such as ReqBody.

Plugin can implement service processing with complex logic (not recommended for use with other processing types).

Taking Redfish as an example, the current storage directory for Redfish plugins is /opt/bmc/apps/redfish/interface_config/plugins. The preceding configuration requires the orchestrator\bios.lua file to exist in the storage directory and contain the get_registry_version function.

Redfish URI Configuration Issue

When configuring the Redfish interface, you may encounter a URI error. This is actually due to incorrect configurations in @odata.context, @odata.id, or @odata.type. Check and modify them.

Conclusion

Reference documents: