Configuration Import and Export Adaptation Guide
Key Components for Configuration Import and Export: profile_schema, oms, and Components for Export
The code of profile_schema can be found at profile_schema.
Introduction
For some internal BMC configuration items, a config.json file can be generated and downloaded locally using the configuration export function. Customers can modify some properties and import the configuration file into the local BMC or into the BMC of other devices of the same model for the configuration to take effect. This ensures configuration consistency and saves time when multiple devices with the same property values are configured.
Implementation Principles of Configuration Export
When learning this function, you can refer to the configuration of \profile_schema\schema\account.json to get familiar with the format of configuration items. Analyze the exported configuration, compare the configuration items with the current configuration, and understand the format of the exported data. The exported data can be imported back. In the code of the component to be exported, search for mc.mdb.micro_component.config_manage to find the entry for the import and export code.
Services Capable of Exporting Data
Configuration import and export are carried through the oms component. You can see some logs in the app.log file. During export, the system first obtains all component names from the maca service. Then, it calls the relevant export interface in the corresponding service to collect data and generate the exported config.json file.
busctl --user --verbose call bmc.kepler.maca /bmc/kepler/MdbService bmc.kepler.Mdb GetServiceNames a{ss} 0 | cat
MESSAGE "as" {
ARRAY "s" {
STRING "bmc.kepler.network_adapter";
STRING "bmc.kepler.usb_entry";
......
STRING "bmc.kepler.power_mgmt";
};
};Adding Data Import and Export to Existing Services
For example, the existing my_app module contains the WelcomeMessage property. Implement its export and import functions.
Add the my_app.json file to \profile_schema\schema with the following content:
{
"type": "object",
"properties": {
"Description": {
"const": "Configurations of my_app"
},
"ConfigData": {
"type": "object",
"properties": {
"MY_APP": {
"type": "object",
"properties": {
"WelcomeMessage": {
"type": "string",
"AttributeType": "ImportAndExport"
}
}
}
}
}
}
}The preceding configuration indicates that the content to be exported is WelcomeMessage, the type is string, and the name of the custom data collection of the exported item is MY_APP.
Add dependency-related code to the my_app/src/lualib/my_app_app.lua module of my_app:
local json = require 'cjson'
local mdb_config_manage = require 'mc.mdb.micro_component.config_manage'mdb_config_manage defined here indicates dependency on mc.mdb.micro_component.config_manage to register the on_export and on_import functions. The export function can be invoked only after the registration. The json library is added for data processing using json.encode and json.decode.
Add initialization code inside the app:init() function:
mdb_config_manage.on_import(function(...)
return self:import(...)
end)
mdb_config_manage.on_export(function(...)
return self:export(...)
end)
log:notice("mdb_config_manage on_export end")The on_export and on_import registered to mdb_config_manage are implemented by functions of the oms component when the configuration import or export command is executed.
Adding Export Implementation
Add export-related code to my_app/src/lualib/my_app_app.lua of the my_app module:
function app:configuration_export()
local my_app_obj = self.my_mds_model
local data = {}
if not my_app_obj then
log:error('get my_app_obj failed.')
return data
end
local configuration_config = {}
configuration_config.WelcomeMessage = my_app_obj.WelcomeMessage
data.MY_APP = configuration_config
log:notice('export configuration config successfully.')
return data
end
function app:custom_export()
local data = {}
local customize_config = {}
customize_config.WelcomeMessage = ''
log:notice("app:custom_export")
data.CustomSettings = customize_config
log:notice('export custom config successfully.')
return data
end
function app:export(ctx, export_type)
local data = {}
if export_type == 'configuration' then
data = self:configuration_export()
elseif export_type == 'custom' then
data = self:custom_export()
end
log:notice("app:export end")
return json.encode({ ConfigData = data })
endThe second parameter of export is export_type, which can be configuration or custom. Currently, configuration is used. If a custom function is used, use the custom branch (not used in this example). data.MY_APP indicates that the data set name of the component in the exported data is MY_APP.
The content in the exported JSON file is as follows:
"my_app": {
"ConfigData": {
"MY_APP": {
"WelcomeMessage": {
"Value": "WelcomeMessage!",
"AttributeType": "ImportAndExport",
"Import": true
}
}
},
"Description": "Configurations of my_app"
},If the configuration JSON file specifies ExportOnly, the content in the exported file is as follows:
"my_app": {
"ConfigData": {
"MY_APP": {
"WelcomeMessage": {
"Value": "WelcomeMessage! haha!",
"AttributeType": "ExportOnly",
"Import": false
}
}
},
"Description": "Configurations of ums"
},Adding Import Implementation
Add import-related code to my_app/src/lualib/my_app_app.lua of the my_app module:
function app:configuration_import(configuration_config, my_app_obj, ctx)
for key, value in pairs(configuration_config) do
if not value or not value.Import then
log:notice('my_app property [%s] import not supported.', key)
return
end
-- Obtaining the value based on the actual data structure
local config_value
if type(value) == "table" and value.Value then
config_value = value.Value
else
config_value = value
end
log:notice('Setting key: ' .. key .. ' to value: ', tostring(config_value))
-- Setting the property
my_app_obj[key] = config_value
log:notice('Successfully set ' .. key)
end
end
function app:custom_import(custom_config, my_app_obj, ctx)
log:notice("custom_import")
end
-- Configuration import interface
function app:import(ctx, datas, import_type)
log:notice("app:import start")
if not datas then
log:error('app: import data is nil.')
return
end
-- Printing raw data
log:notice('Raw import data: ' .. tostring(datas))
-- Parsing JSON data
local data = json.decode(datas)
if not data then
log:error('JSON decode returned nil')
return
end
log:notice('Decoded data type: ' .. type(data))
if type(data) == "table" then
for k, v in pairs(data) do
log:notice('data[' .. tostring(k) .. '] type: ' .. type(v))
end
else
log:error('Decoded data is not a table')
return
end
local config = data.ConfigData
if not config or type(config) ~= 'table' then
log:error('import data ConfigData is invalid.')
return
end
local my_app_obj = self.my_mds_model
if not my_app_obj then
log:error('get my_mds_model failed.')
return
end
if import_type == 'configuration' then
self:configuration_import(config.MY_APP, my_app_obj, ctx)
elseif import_type == 'custom' then
self:custom_import(config.CustomSettings, my_app_obj, ctx)
else
log:error('unknown import type(%s)', import_type)
end
log:notice('app:import successfully')
endThe preceding function handles the import process. Similarly, it processes import_type first. When configuration_import is called, the config.MY_APP object needs to be transferred. Finally, the properties to be imported are set to the memory object.
For example, if you change the WelcomeMessage property in the config.json import file to:
"my_app": {
"ConfigData": {
"MY_APP": {
"WelcomeMessage": {
"Value": "WelcomeMessage! haha!",
"AttributeType": "ImportAndExport",
"Import": true
}
}
},
"Description": "Configurations of my_app"
},After the import, query the relevant property on the device:
~ ~ $ 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 "WelcomeMessage! haha!" emits-change writable
bmc.kepler.Object.Properties interface - - -During the import, the system prints the logs recorded in the code to app.log to facilitate troubleshooting:
Raw import data: {"ConfigData":{"MY_APP":{"WelcomeMessage":{"Value":"WelcomeMessage! haha!","Import":true}}},"Description":"Configurations of my_app"}Equipment Customization Items
Search for CustomSettings in the corresponding service in profile_schema to see equipment customization items. Pay attention to the CustomDefault property, which indicates the default value of the configuration data.
Common Issues
Errors in JSON Import Configuration
The web page also displays an error message: Failed to import the configuration file. Check and modify the configuration file and import it again. For more information, see the operation logs.
Errors in Profile Configuration
The compiler may not report errors during compilation, but the web page displays error messages. Search for relevant error logs according to the prompts. Failed to import the configuration file. Check and modify the configuration file and import it again. For more information, see the operation logs.
You can check app.log for logs similar to the following:
validate.lua(88): Attribute(MY_APP) import value invalid
oms ERROR: validate.lua(88): Attribute(ConfigData) import value invalid
oms ERROR: validate.lua(118): Validate import value failed
oms ERROR: import.lua(144): Service(my_app) config is invalid, error info: /MY_APP/WelcomeMessageImported Data Does Not Take Effect
For example, if the Import property in the configured config.json is false, it will be filtered out by the following validation code:
if not value or not value.Import then
log:notice('my_app property [%s] import not supported.', key)
return
endCorresponding validation log in app.log:
my_app property [WelcomeMessage] import not supported.