MDS Model Plugin Mechanism
更新时间: 2025/03/03
在Gitcode上查看源码

Introduction

In openUBMC, the plugin mechanism can override the public method of the resource collaboration interface of a component or the private method of a service component without intrusive modifications to the component code, thereby enabling extension of differentiated scenarios.

The plugin mechanism applies to the following scenarios:

  1. The plugin mechanism is used to override the public or private methods of the resource collaboration interface of open components to implement open component customization function.
  2. The plugin mechanism is used to override the public or private methods of the resource collaboration interface of open source components. This prevents management inconvenience caused by the creation of multiple branches due to differentiated product function implementations and provides other ways for differentiated customization of different products.

Configuration Procedure

To configure an extensible plugin in openUBMC, perform the following operations:

  1. Configure the featureTag keyword in the model.json file of the corresponding component to describe the feature to which the plugin method belongs, for example, Feature1.

  2. Run the bingo gen command.

  3. Implement the customization function in the plugin/Feature1/init.lua file.

MDS Syntax

When configuring an extensible plugin in openUBMC, you need to configure the featureTag keyword. The following describes how to add the featureTag property in model.json with the examples of overriding the public method or the private method of the resource collaboration interface of open components.

Examples

  • Public methods of the resource collaboration interface
json
{
    "ClassA": {
        "path": "/bmc/kepler/xxx/${Id}",
        "interfaces": {
            "bmc.kepler.Interface1": {
                "methods": {
                    "Method1": {
                        "featureTag": "Feature1",
                        ...
                    }
                }
            }
        }
    }
}
  • Private methods
json
{
    "private": {
        "methods": {
            "Method1": {
                "featureTag": "Feature1",
                ...
            }
        }
    }
}
  1. featureTag is used to describe the feature to which the plugin method belongs. Ensure that a plugin method has at most one feature tag to prevent plugin implementation conflicts when multiple component (feature) plugins take effect.

    Incorrect example

    json
    {
        "private": {
            "methods": {
                "Method1": {
                    "featureTag": ["Feature1", "Feature2"],
                    ...
                }
            }
        }
    }
  2. If a plugin method has multiple feature tags, its granularity may be too large. In this case, consider splitting it into multiple methods.

    Changed the incorrect example in (1) to

    json
    {
        "private": {
            "methods": {
                "Method1": {
                    "featureTag": "Feature1",
                    ...
                },
                "Method2": {
                    "featrueTag": "Feature2",
                    ...
                }
            }
        }
    }
  3. Different plugin methods in the same component may share the same featureTag type.

    Example

    json
    {
        "ClassA": {
            "path": "/bmc/kepler/xxx/${Id}",
            "interfaces": {
                "bmc.kepler.Interface1": {
                    "methods": {
                        "Method1": {
                            "featureTag": "Feature1",
                            ...
                        }
                    }
                }
            }
        },
        "private": {
            "methods": {
                "Method1": {
                    "featureTag": "Feature1",
                    ...
                }
            }
        }
    }
  4. Difference between public and private plugin methods of the resource collaboration interface

    a. A plugin implemented based on the public plugin method can be used by other components that implement interface specifications. For details, see the public plugin method of the resource collaboration interface.

    b. A private plugin method serves as the interface constraint of a component. It is an interface specification that must be implemented by the component and is requested and called for service handling. A private plugin method is a service constraint that is decomposed and extracted by the component based on the service process and logic, and has no constraint on other components. For details, see the private plugin method.

For details about the MDS object, see MDS.

Example

Below describes how to add a private plugin method. The usage of public and private plugin methods is basically consistent.

Private Plugin Method

MDS Syntax

Add the private plugin method to ../mds/model.json.

json
{
    "private": {
        "methods": {
            "PrivateProcess": {
                "featureTag": "Feature1",
                "description": "Private plugin method,"
                "req": {
                    "request1": {
                        "baseType": "String"
                    },
                    "request2": {
                        "baseType": "String"
                    }
                },
                "rsp": {
                    "Status": {
                        "baseType": "U8"
                    }
                }
            }
        }
    }
}

Automatic Code Generation

  1. After the private plugin method is added to model.json, run the bingo gen command to automatically generate the corresponding code.
    shell
    bingo gen

In this case, two parts of code are automatically generated: component plugin service interface and component plugin template interface.

  1. Component plugin service interface

    The implementation and calling methods of the private method are generated in ../gen/sensor/service.lua.

    lua
    -- Calling method
    function sensor_service:ImplPrivateProcess(cb)
        model.ImplPrivateProcess(cb)
    end
    
    -- Implementation method
    function sensor_service:PrivateProcess(...)
        model.PrivateProcess(...)
    end
  2. Component plugin template interface

The plugin code is generated in temp/plugin and needs to be moved to the plugin directory of the app: ../plugin/Feature1/init.lua.

In init.lua, three methods are reserved for function customization:

```lua
-- PreProcess is executed before the plugin runs (optional). It can verify or convert input parameters, and passes the processed parameters to the plugin's Process method.
local function PrivateProcessPreProcess(...)
    --todo
    return ...
end

-- Process is used for plugin running (optional). If the plugin's Process method is not implemented, the default method will be used.
local function PrivateProcessProcess(...)
    --todo
    return ...
end

-- Postprocess is used to process and return the output parameters of the Process method or default implementation after the plugin finishes running. (optional)
local function PrivateProcessPostprocess(...)
    --todo
    return ...
end

-- The input parameters are the callback result of the PreProcess, Process, and Postprocess methods. After the callback is implemented, enter the method name. nil indicates that no processing is performed.
Feature1:ImplPrivateProcess(nil, nil, nil)
```

For more information about automatic code generation, see Automatic Code Generation.

Plugin Function Implementation

The following uses log information printing as an example to describe the differences between the component's default method and plugin method.

  1. Implementation of the component's default method

    The default method implementation means that the method in ./gen/sensor/service.lua is directly called in the service function code.

    The following example describes how to implement log information printing in ../src/lualib/sample.lua. Note: The path for storing the service function code needs to be customized.

    lua
    local RET<const> = 0
    
    base_service:ImplPrivateProcess(function(request1, request2)
        log:notice('default: request1 is %s and request2 is %s', request1, request2)
        return RET
    end)
  2. Implementation of the plugin method The plugin method implementation needs to add the log information printing function to the Process method in ../plugin/Feature1/init.lua, thereby achieve plugin customization.

    lua
    -- The PreProcess method is not overwritten. No processing is required.
    local function PrivateProcessPreProcess(...)
        --todo
        return ...
    end
    
    -- The Process method is overridden.
    local RET<const> = 0
    
    local function PrivateProcessProcess(...)
        return function(request1, request2)
            log:notice('plugin: request1 is %s and request2 is %s', request1, request2)
            return RET
    end
    
    -- The Postprocess method is not overwritten. No processing is required.
    local function PrivateProcessPostprocess(...)
        --todo
        return ...
    end
    
    -- The Process method is overridden and needs to be passed to the calling method. The PreProcess and Postprocess methods are not overridden, so nil is passed.
    Feature1:ImplPrivateProcess(nil, PrivateProcessProcess, nil)

Developer Testing

After the plugin mechanism is implemented for a component, add the app component name to ../src/service/main.lua to run the developer tests.

For example, to test the sensor component:

lua
-- Path: ../src/service/main.lua
APP_NAME = 'sensor'
...