已开启
cli适配libroute_mapper切换service #9
HuangJiayi创建于 8月23日
cli适配libroute_mapper切换service #9
已开启
HuangJiayi创建于 8月23日
共 24 个文件变更+598-118
@@ -0,0 +1,170 @@
1+-- Copyright (c) 2026 Huawei Technologies Co., Ltd.
2+-- openUBMC is licensed under Mulan PSL v2.
3+-- You can use this software according to the terms and conditions of the Mulan PSL v2.
4+-- You may obtain a copy of Mulan PSL v2 at:
5+-- http://license.coscl.org.cn/MulanPSL2
6+-- THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
7+-- EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
8+-- MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
9+-- See the Mulan PSL v2 for more details.
10+ 
11+local mapper_package_path = package.path
12+local mapper_package_cpath = package.cpath
13+local mapper_global_mc = rawget(_G, 'mc')
14+local mapper_preserved_modules = {}
15+local mapper_preserved_module_names = { 'mc', 'mc.class', 'mc.logging', 'mc.context', 'mc.error' }
16+for _, module_name in ipairs(mapper_preserved_module_names) do
17+ if package.loaded[module_name] ~= nil then
18+ mapper_preserved_modules[module_name] = package.loaded[module_name]
19+ end
20+end
21+ 
22+local routemapper = require('routemapper.sync')
23+assert(package.path == mapper_package_path and package.cpath == mapper_package_cpath,
24+ 'route mapper changed the CLI Lua module search path')
25+assert(rawget(_G, 'mc') == mapper_global_mc, 'route mapper replaced the CLI _G.mc value')
26+for module_name, preserved in pairs(mapper_preserved_modules) do
27+ assert(package.loaded[module_name] == preserved,
28+ 'route mapper replaced the CLI module ' .. module_name)
29+end
30+ 
31+local mapper = {}
32+local mapper_mt = { __index = mapper }
33+ 
34+local function request_context(params)
35+ -- CLI identity tables use ClientIp, while mcengine request contexts use ClientAddr.
36+ local user = params.context or params.user or {}
37+ local result = {}
38+ for key, value in pairs(user) do
39+ if key ~= 'ClientIp' then
40+ result[key] = value
41+ end
42+ end
43+ if result.ClientAddr == nil then
44+ result.ClientAddr = user.ClientIp
45+ end
46+ return result
47+end
48+ 
49+local function request_arguments(params)
50+ params = params or {}
51+ return params.body or {}, params.header or {}, request_context(params), params.query or {}
52+end
53+ 
54+local function has_type(parameter, expected)
55+ for _, value in ipairs(parameter.Types or {}) do
56+ if string.lower(value) == expected then
57+ return true
58+ end
59+ end
60+ return false
61+end
62+ 
63+local function convert_scalar(value, parameter)
64+ if type(value) ~= 'string' then
65+ return value
66+ end
67+ if has_type(parameter, 'integer') then
68+ local number = tonumber(value)
69+ if number and math.type(number) == 'integer' then
70+ return number
71+ end
72+ end
73+ if has_type(parameter, 'number') then
74+ local number = tonumber(value)
75+ if number then
76+ return number
77+ end
78+ end
79+ if has_type(parameter, 'boolean') then
80+ local lower = string.lower(value)
81+ if lower == 'true' then
82+ return true
83+ elseif lower == 'false' then
84+ return false
85+ end
86+ end
87+ return value
88+end
89+ 
90+local function request_body(description, values)
91+ values = values or {}
92+ local value_count = 0
93+ for key in pairs(values) do
94+ if type(key) ~= 'number' then
95+ return values
96+ end
97+ value_count = math.max(value_count, key)
98+ end
99+ 
100+ local result = {}
101+ local parameters = description.Parameters or {}
102+ local selected = {}
103+ for index, parameter in ipairs(parameters) do
104+ if parameter.Required then
105+ selected[#selected + 1] = { index = index, parameter = parameter }
106+ end
107+ end
108+ local optional_count = math.max(0, value_count - #selected)
109+ for index, parameter in ipairs(parameters) do
110+ if not parameter.Required and optional_count > 0 then
111+ selected[#selected + 1] = { index = index, parameter = parameter }
112+ optional_count = optional_count - 1
113+ end
114+ end
115+ table.sort(selected, function(left, right)
116+ return left.index < right.index
117+ end)
118+ for index, item in ipairs(selected) do
119+ if values[index] ~= nil then
120+ result[item.parameter.Name] = convert_scalar(values[index], item.parameter)
121+ end
122+ end
123+ return result
124+end
125+ 
126+function mapper.new(config_root, bus)
127+ return setmetatable({
128+ runtime = routemapper.load(config_root, bus, nil, true, 'cli'),
129+ }, mapper_mt)
130+end
131+ 
132+function mapper:execute(uri, method, params)
133+ local body, headers, user, query = request_arguments(params)
134+ return self.runtime:execute(string.upper(method), uri, body, headers, user, query)
135+end
136+ 
137+function mapper:describe(uri, method, params)
138+ local body, headers, user, query = request_arguments(params)
139+ return self.runtime:describe(string.upper(method), uri, body, headers, user, query)
140+end
141+ 
142+function mapper:discover(uri, method, params)
143+ local body, headers, user, query = request_arguments(params)
144+ return self.runtime:discover(string.upper(method), uri, body, headers, user, query)
145+end
146+ 
147+function mapper:authenticate(uri, method, params)
148+ params = params or {}
149+ local user = request_context(params)
150+ return self.runtime:authenticate(string.upper(method), uri, params.header or {}, user, params.required)
151+end
152+ 
153+function mapper:prepare(discovery, method, params)
154+ params = params or {}
155+ local uri = discovery.ResolvedPath or discovery.InputPath
156+ local body = request_body(discovery.Endpoint, params.body)
157+ local description = self:describe(uri, method, {
158+ body = body,
159+ header = params.header,
160+ user = params.context or params.user,
161+ query = params.query,
162+ })
163+ return description, body, uri
164+end
165+ 
166+function mapper:customer()
167+ return self.runtime:customer()
168+end
169+ 
170+return mapper
@@ -15,7 +15,6 @@ local utils_file = require('utils.file')
15local cjson = require('cjson')15local cjson = require('cjson')
16local tmpl = require('template')16local tmpl = require('template')
17local config = require('config')17local config = require('config')
18-local mapper_intf = require('route_mapper.interface')
19 18 
20local safe_close = mc_utils.safe_close_file19local safe_close = mc_utils.safe_close_file
21local is_file = utils_core.is_file20local is_file = utils_core.is_file
@@ -39,7 +38,7 @@ end
39 38 
40function base:get_echo_path(echo_file_name)39function base:get_echo_path(echo_file_name)
41 local default = config.ECHO_FILE_PATH .. echo_file_name40 local default = config.ECHO_FILE_PATH .. echo_file_name
42- local customer_name = mapper_intf.get_package_customer(self.bus)41+ local customer_name = self.mapper and self.mapper:customer() or ''
43 if not customer_name or customer_name == '' then42 if not customer_name or customer_name == '' then
44 return default43 return default
45 end44 end
@@ -17,14 +17,14 @@ local ordinary = class(base)
17function ordinary:ctor() end17function ordinary:ctor() end
18 18 
19function ordinary:call(details, reminder, method, header, value)19function ordinary:call(details, reminder, method, header, value)
20- local errs, rsp_body, extra_info =20+ local result =
21- self.mapper:match(details.Uri, method, { header = header, body = value, user = common.get_user_info() })21+ self.mapper:execute(details.Uri, method, { header = header, body = value, user = common.get_user_info() })
22- if errs and #errs ~= 0 then22+ if result.errors and #result.errors ~= 0 then
23- common.print_errs_message(errs, true)23+ common.print_errs_message(result.errors, true)
24 return24 return
25 end25 end
26 26 
27- self:print_echo_content(extra_info and extra_info.Echoes[1], rsp_body)27+ self:print_echo_content(details.Echoes and details.Echoes[1], result.body)
28end28end
29 29 
30return ordinary30return ordinary
@@ -12,7 +12,6 @@ local class = require('mc.class')
12local log = require('mc.logging')12local log = require('mc.logging')
13local base = require('command.base')13local base = require('command.base')
14local common = require('common')14local common = require('common')
15-local mapper_intf = require('route_mapper.interface')
16 15 
17local paging = class(base)16local paging = class(base)
18 17 
@@ -21,14 +20,13 @@ function paging:ctor() end
21function paging:get_items_count(uri, method, value)20function paging:get_items_count(uri, method, value)
22 local query = { ['$skip'] = 0, ['$top'] = 0 }21 local query = { ['$skip'] = 0, ['$top'] = 0 }
23 22 
24- local errs, rsp_body =23+ local result = self.mapper:execute(uri, method, { body = value, query = query, user = common.get_user_info() })
25- self.mapper:match(uri, method, { body = value, query = query, user = common.get_user_info() })24+ if result.errors and #result.errors ~= 0 then
26- if errs and #errs ~= 0 then25+ common.print_errs_message(result.errors, true)
27- common.print_errs_message(errs, true)
28 return nil26 return nil
29 end27 end
30 28 
31- return rsp_body.Count or 029+ return result.body.Count or 0
32end30end
33 31 
34function paging:call(details, reminder, method, header, value)32function paging:call(details, reminder, method, header, value)
@@ -53,25 +51,26 @@ function paging:call(details, reminder, method, header, value)
53 query['$skip'] = math.max(skip, remain - top)51 query['$skip'] = math.max(skip, remain - top)
54 query['$top'] = math.min(top, remain)52 query['$top'] = math.min(top, remain)
55 53 
56- local errs, rsp_body, extra_info = self.mapper:match(54+ local result = self.mapper:execute(
57 details.Uri,55 details.Uri,
58 method,56 method,
59 { header = header, body = value, query = query, user = common.get_user_info() }57 { header = header, body = value, query = query, user = common.get_user_info() }
60 )58 )
61- if errs and #errs ~= 0 then59+ if result.errors and #result.errors ~= 0 then
62- common.print_errs_message(errs, true)60+ common.print_errs_message(result.errors, true)
63 break61 break
64 end62 end
65 63 
64+ local rsp_body = result.body
66 rsp_body.Count = count65 rsp_body.Count = count
67- self:print_echo_content(extra_info and extra_info.Echoes[1], rsp_body)66+ self:print_echo_content(details.Echoes and details.Echoes[1], rsp_body)
68 67 
69 if query['$skip'] == skip then68 if query['$skip'] == skip then
70 break69 break
71 end70 end
72 71 
73 -- 以Q或q开头的字符串72 -- 以Q或q开头的字符串
74- local status, char = mapper_intf.get_user_input(self.bus, 'Input \'q\' to quit:')73+ local status, char = common.get_user_input('Input \'q\' to quit:')
75 if status ~= 0 then74 if status ~= 0 then
76 break75 break
77 end76 end
@@ -15,7 +15,7 @@ local mc_utils = require('mc.utils')
15local cjson = require('cjson')15local cjson = require('cjson')
16 16 
17local cli_utils = require('cli.utils')17local cli_utils = require('cli.utils')
18-local mdb_access = require('route_mapper.mdb_access')18+local mdb_access = require('mc.mdb')
19local base = require('command.base')19local base = require('command.base')
20local common = require('common')20local common = require('common')
21 21 
@@ -108,7 +108,7 @@ function task:wait_for_task(task_path, extra_info, rsp_body)
108 108 
109 if info.progress == 100 or info.state == 'Completed' then109 if info.progress == 100 or info.state == 'Completed' then
110 local task_info = extra_info.TaskInfo110 local task_info = extra_info.TaskInfo
111- if task_info and task_info.PostTaskProcess then111+ if task_info and type(task_info.PostTaskProcess) == 'table' then
112 excute_post_process(self.bus, task_info.PostTaskProcess, task_info.Context)112 excute_post_process(self.bus, task_info.PostTaskProcess, task_info.Context)
113 end113 end
114 114 
@@ -126,26 +126,34 @@ function task:wait_for_task(task_path, extra_info, rsp_body)
126end126end
127 127 
128function task:call(details, reminder, method, header, value)128function task:call(details, reminder, method, header, value)
129- local errs, rsp_body, extra_info =129+ local result =
130- self.mapper:match(details.Uri, method, { header = header, body = value, user = common.get_user_info() })130+ self.mapper:execute(details.Uri, method, { header = header, body = value, user = common.get_user_info() })
131- if errs and #errs ~= 0 then131+ if result.errors and #result.errors ~= 0 then
132- common.print_errs_message(errs, true)132+ common.print_errs_message(result.errors, true)
133 return133 return
134 end134 end
135 135 
136+ local rsp_body = result.body
137+ local task_info = result.effects and result.effects.Tasks and result.effects.Tasks[1]
138+ local extra_info = {
139+ Echoes = details.Echoes,
140+ TaskInfo = task_info,
141+ }
142+ 
136 -- 在获取任务信息失败的时候,直接打印回显143 -- 在获取任务信息失败的时候,直接打印回显
137- if not extra_info.TaskInfo then144+ if not task_info then
138 self:print_echo_content(extra_info and extra_info.Echoes[1], rsp_body)145 self:print_echo_content(extra_info and extra_info.Echoes[1], rsp_body)
139 return146 return
140 end147 end
141 148 
142- local task_path = extra_info.TaskInfo.Path .. '/TaskService/Tasks/' .. extra_info.TaskInfo.TaskId149+ local task_path = task_info.Path .. '/TaskService/Tasks/' .. task_info.TaskId
143 150 
144 rsp_body.State = 'New'151 rsp_body.State = 'New'
145 self:print_echo_content(extra_info and extra_info.Echoes[1], rsp_body)152 self:print_echo_content(extra_info and extra_info.Echoes[1], rsp_body)
146 cli_utils.redirect_start_print('0%')153 cli_utils.redirect_start_print('0%')
147 154 
148- self:wait_for_task(task_path, extra_info, cjson.json_object_to_table(rsp_body))155+ local task_body = cjson.json_object_is_object(rsp_body) and cjson.json_object_to_table(rsp_body) or rsp_body
156+ self:wait_for_task(task_path, extra_info, task_body)
149end157end
150 158 
151return task159return task
@@ -13,7 +13,7 @@ local utils = require('mc.utils')
13local cjson = require('cjson')13local cjson = require('cjson')
14local cli_utils = require('cli.utils')14local cli_utils = require('cli.utils')
15local message = require('mc.message')15local message = require('mc.message')
16-local mdb_access = require('route_mapper.mdb_access')16+local mdb_access = require('mc.mdb')
17 17 
18local AVAILABLE = 118local AVAILABLE = 1
19local SOL_COM <const> = 'SOL COM'19local SOL_COM <const> = 'SOL COM'
@@ -26,6 +26,21 @@ local SOL_SESSION2_PATH = '/bmc/kepler/Managers/1/SOL/Session/2'
26local SOL_SESSION_INTERFACE = 'bmc.kepler.Managers.SOL.Session'26local SOL_SESSION_INTERFACE = 'bmc.kepler.Managers.SOL.Session'
27local common = {}27local common = {}
28 28 
29+function common.get_user_input(prompt)
30+ io.write(prompt or '')
31+ io.flush()
32+ local input = io.read('*l')
33+ if type(input) ~= 'string' then
34+ return -1, ''
35+ end
36+ return 0, string.sub(input, 1, 1)
37+end
38+ 
39+function common.check_the_input_operation(prompt)
40+ local status, input = common.get_user_input(prompt)
41+ return status == 0 and (input == 'y' or input == 'Y')
42+end
43+ 
29function common.print_errs_message(errs, is_print_failed)44function common.print_errs_message(errs, is_print_failed)
30 local errs_message = {}45 local errs_message = {}
31 local is_success = true46 local is_success = true
@@ -34,11 +49,12 @@ function common.print_errs_message(errs, is_print_failed)
34 is_success = false49 is_success = false
35 end50 end
36 51 
37- errs_message[err.Message] = true52+ local err_message = err.Message or err.Code or 'Request failed.'
53+ errs_message[err_message] = true
38 54 
39- if err.MessageName == 'PasswordChangeRequired' then55+ if err.MessageName == 'PasswordChangeRequired' or err.Code == 'PasswordChangeRequired' then
40 -- 首次登录场景,直接抛出此错误56 -- 首次登录场景,直接抛出此错误
41- print(err.Message)57+ print(err_message)
42 print('Request failed.')58 print('Request failed.')
43 return59 return
44 end60 end
@@ -84,10 +100,12 @@ function common.print_command_reminder(reminder)
84 print(reminder.Brief)100 print(reminder.Brief)
85 end101 end
86 102 
87- if reminder['-v'] ~= nil and reminder['-v'] ~= cjson.null then103+ local parameters = reminder['-v'] or reminder.Parameters
88- for index = 1, #reminder['-v'] do104+ if parameters ~= nil and parameters ~= cjson.null then
89- if is_valid_parameter(reminder['-v'][index].Description) then105+ for index = 1, #parameters do
90- print(reminder['-v'][index].Command .. ': ' .. reminder['-v'][index].Description)106+ if is_valid_parameter(parameters[index].Description) then
107+ local command = parameters[index].Command or parameters[index].Name
108+ print(command .. ': ' .. parameters[index].Description)
91 end109 end
92 end110 end
93 end111 end
@@ -12,9 +12,8 @@ local common = require('common')
12local command = require('command.command')12local command = require('command.command')
13local cli_utils = require('cli.utils')13local cli_utils = require('cli.utils')
14local traces = require('telemetry.trace')14local traces = require('telemetry.trace')
15-local mdb_access = require('route_mapper.mdb_access')15+local mdb_access = require('mc.mdb')
16local argparse = require('argparse')16local argparse = require('argparse')
17-local mapper_intf = require('route_mapper.interface')
18local tracer = traces.get_tracer('cli')17local tracer = traces.get_tracer('cli')
19local telemetry = require('telemetry')18local telemetry = require('telemetry')
20local log = require('mc.logging')19local log = require('mc.logging')
@@ -24,7 +23,7 @@ local mc_error = require('mc.error')
24 23 
25local file_sec = require('utils.file')24local file_sec = require('utils.file')
26local context = require('mc.context')25local context = require('mc.context')
27-local mapper = require('route_mapper.route_mapper')26+local mapper = require('cli_mapper')
28 27 
29local OBSERVABILITY_PATH = '/bmc/kepler/Dashboard'28local OBSERVABILITY_PATH = '/bmc/kepler/Dashboard'
30local OBSERVABILITY_INTERFACE = 'bmc.kepler.Dashboard.Observability'29local OBSERVABILITY_INTERFACE = 'bmc.kepler.Dashboard.Observability'
@@ -39,9 +38,6 @@ local MULTI_HOST_TYPE = 'MultiHost'
39 38 
40local safe_call = mc_error.safe_call39local safe_call = mc_error.safe_call
41 40 
42-local MATCHED = 0
43-local URI_MATCHED = 1
44-local UN_MATCHED = 2
45local PRINT_ALL = 041local PRINT_ALL = 0
46 42 
47local cli = class()43local cli = class()
@@ -171,13 +167,13 @@ local function print_target_dataitem_reminder(reminder, method, bus)
171 end167 end
172end168end
173 169 
174-local function command_confirm(bus, confirm)170+local function command_confirm(confirm)
175 -- 判断是否需要进行Y/N确认171 -- 判断是否需要进行Y/N确认
176 if type(confirm) ~= 'table' or confirm.Condition ~= true then172 if type(confirm) ~= 'table' or confirm.Condition ~= true then
177 return true173 return true
178 end174 end
179 175 
180- return mapper_intf.check_the_input_operation(bus, confirm.Description)176+ return common.check_the_input_operation(confirm.Description)
181end177end
182 178 
183local function command_authentication(bus, authentication)179local function command_authentication(bus, authentication)
@@ -219,22 +215,35 @@ local function command_authentication(bus, authentication)
219 return true215 return true
220end216end
221 217 
222-function cli:execute_command_request(details, reminder, method, header, value)218+local function install_authenticated_context(auth_result)
219+ if type(auth_result.context) ~= 'table' then
220+ return
221+ end
222+ 
223+ local authenticated = context.new()
224+ for key, value in pairs(auth_result.context) do
225+ authenticated[key] = value
226+ end
227+ context.set_context(authenticated)
228+end
229+ 
230+function cli:execute_command_request(details, reminder, method, header, value, raw_value)
223 if not details or not details.Mapper then231 if not details or not details.Mapper then
224 log:error('The route mapper response is abnormal(details data)')232 log:error('The route mapper response is abnormal(details data)')
225 print('Invalid Command')233 print('Invalid Command')
234+ return
226 end235 end
227 236 
228 -- -v后接参数内容检验异常237 -- -v后接参数内容检验异常
229- if details.ReqErrs and #details.ReqErrs ~= 0 then238+ if details.RequestErrors and #details.RequestErrors ~= 0 then
230- common.print_errs_message(details.ReqErrs, false)239+ common.print_errs_message(details.RequestErrors, false)
231 print('')240 print('')
232 common.print_command_reminder(reminder)241 common.print_command_reminder(reminder)
233 return242 return
234 end243 end
235 244 
236 if245 if
237- not command_confirm(self.bus, details.Confirm)246+ not command_confirm(details.Confirm)
238 or not command_authentication(self.bus, details.Authentication)247 or not command_authentication(self.bus, details.Authentication)
239 then248 then
240 return249 return
@@ -242,6 +251,18 @@ function cli:execute_command_request(details, reminder, method, header, value)
242 251 
243 local is_sol_activate = common.check_is_sol_activate_or_deactivate(details.Uri)252 local is_sol_activate = common.check_is_sol_activate_or_deactivate(details.Uri)
244 if is_sol_activate == true then253 if is_sol_activate == true then
254+ local auth_result = self.mapper:authenticate(details.Uri, method, {
255+ header = header,
256+ user = common.get_user_info(),
257+ required = false,
258+ })
259+ if not auth_result.accepted then
260+ print(auth_result.message)
261+ print('Request failed.')
262+ return
263+ end
264+ install_authenticated_context(auth_result)
265+ 
245 local route_file = '/opt/bmc/apps/cli/lualib/route/ipmcset/sol_activate.lua'266 local route_file = '/opt/bmc/apps/cli/lualib/route/ipmcset/sol_activate.lua'
246 local ret = file_sec.check_realpath_before_open_s(route_file)267 local ret = file_sec.check_realpath_before_open_s(route_file)
247 if ret ~= 0 then268 if ret ~= 0 then
@@ -250,7 +271,7 @@ function cli:execute_command_request(details, reminder, method, header, value)
250 end271 end
251 272 
252 local route_func = dofile(route_file)273 local route_func = dofile(route_file)
253- route_func(self.bus, value, header)274+ route_func(self.bus, raw_value or value, header)
254 return275 return
255 end276 end
256 277 
@@ -265,6 +286,21 @@ function cli:execute_command_request(details, reminder, method, header, value)
265 cmd_type:call(details, reminder, method, header, value)286 cmd_type:call(details, reminder, method, header, value)
266end287end
267 288 
289+local function discovery_reminder(discovery)
290+ local reminder = {}
291+ for _, candidate in ipairs(discovery.Candidates or {}) do
292+ local target, dataitem = string.match(candidate.Path or '', '^/cli/v1/([^/]+)/?([^/]*)')
293+ local option = dataitem == '' and '-t' or '-d'
294+ local command = dataitem == '' and target or dataitem
295+ reminder[option] = reminder[option] or {}
296+ reminder[option][#reminder[option] + 1] = {
297+ Command = command,
298+ Description = candidate.Description or '',
299+ }
300+ end
301+ return reminder
302+end
303+ 
268local function get_index(arr, v)304local function get_index(arr, v)
269 for index, value in ipairs(arr) do305 for index, value in ipairs(arr) do
270 if value == v then306 if value == v then
@@ -611,19 +647,42 @@ function cli:command_request(method, params)
611 end647 end
612 end648 end
613 649 
614- local probe_ret = self.mapper:probe(self.bus, uri, method, header, value)650+ local discovery = self.mapper:discover(uri, method, {
615- -- 如果header的中的SystemId为空表,默认获取所有id651+ header = header,
616- if header and header['SystemId'] and next(header['SystemId']) == nil and probe_ret.Details.ReqHeader then652+ body = {},
617- header = probe_ret.Details.ReqHeader653+ user = common.get_user_info(),
618- end654+ })
619- if probe_ret.MatchStatus == UN_MATCHED then655+ local has_candidates = type(discovery.Candidates) == 'table' and #discovery.Candidates > 0
620- print_target_dataitem_reminder(probe_ret.Reminder, method, self.bus)656+ if
621- elseif probe_ret.MatchStatus == URI_MATCHED or value_err then657+ type(discovery.Endpoint) == 'table'
622- self:print_uri_matched_or_value_err_help_info(probe_ret.Details.Uri, probe_ret.Reminder)658+ and (discovery.Status == 'Matched' or discovery.Status == 'Completed')
623- elseif probe_ret.MatchStatus == MATCHED then659+ and not has_candidates
624- self:execute_command_request(probe_ret.Details, probe_ret.Reminder, method, header, value)660+ then
661+ local raw_value = value
662+ local details
663+ details, value, uri = self.mapper:prepare(discovery, method, {
664+ header = header,
665+ body = value,
666+ user = common.get_user_info(),
667+ })
668+ details.Uri = uri
669+ if header and header['SystemId'] and next(header['SystemId']) == nil and details.ReqHeader then
670+ header = details.ReqHeader
671+ end
672+ if (details.RequestErrors and #details.RequestErrors ~= 0) or value_err then
673+ self:print_uri_matched_or_value_err_help_info(details.Uri, details)
674+ else
675+ self:execute_command_request(details, details, method, header, value, raw_value)
676+ end
677+ elseif
678+ has_candidates
679+ or discovery.Status == 'Partial'
680+ or discovery.Status == 'Ambiguous'
681+ or discovery.Status == 'Unmatched'
682+ then
683+ print_target_dataitem_reminder(discovery_reminder(discovery), method, self.bus)
625 else684 else
626- log:error('The route mapper response is abnormal(not MatchStatus)')685+ log:error('The route mapper discovery response is abnormal(status: %s)', tostring(discovery.Status))
627 print('Invalid Command')686 print('Invalid Command')
628 end687 end
629 span:add_event('cli command request finished')688 span:add_event('cli command request finished')
@@ -14,12 +14,11 @@ local mc_error = require('mc.error')
14local context = require('mc.context')14local context = require('mc.context')
15local mc_privilege = require('mc.privilege')15local mc_privilege = require('mc.privilege')
16local file_sec = require('utils.file')16local file_sec = require('utils.file')
17-local mapper = require('route_mapper.route_mapper')17+local mapper = require('cli_mapper')
18local command = require('command.command')18local command = require('command.command')
19local common = require('common')19local common = require('common')
20local cli_utils = require('cli.utils')20local cli_utils = require('cli.utils')
21-local mdb_access = require('route_mapper.mdb_access')21+local mdb_access = require('mc.mdb')
22-local mapper_intf = require('route_mapper.interface')
23local argparse = require('argparse')22local argparse = require('argparse')
24local traces = require('telemetry.trace')23local traces = require('telemetry.trace')
25local tracer = traces.get_tracer('cli')24local tracer = traces.get_tracer('cli')
@@ -38,9 +37,6 @@ local TRACES_INTERFACE = 'bmc.kepler.Dashboard.Observability.Traces'
38 37 
39local safe_call = mc_error.safe_call38local safe_call = mc_error.safe_call
40 39 
41-local MATCHED = 0
42-local URI_MATCHED = 1
43-local UN_MATCHED = 2
44local PRINT_ALL = 040local PRINT_ALL = 0
45 41 
46local cli = class()42local cli = class()
@@ -48,7 +44,6 @@ local cli = class()
48function cli:ctor(conf_path, bus)44function cli:ctor(conf_path, bus)
49 self.bus = bus45 self.bus = bus
50 self.mapper = mapper.new(conf_path, bus)46 self.mapper = mapper.new(conf_path, bus)
51- self.mapper:set_cli_l_supported(true)
52end47end
53 48 
54local function parse_parameter_value(params, offset)49local function parse_parameter_value(params, offset)
@@ -199,13 +194,13 @@ local function print_target_dataitem_reminder(reminder, method, bus)
199 end194 end
200end195end
201 196 
202-local function command_confirm(bus, confirm)197+local function command_confirm(confirm)
203 -- 判断是否需要进行Y/N确认198 -- 判断是否需要进行Y/N确认
204 if type(confirm) ~= 'table' or confirm.Condition ~= true then199 if type(confirm) ~= 'table' or confirm.Condition ~= true then
205 return true200 return true
206 end201 end
207 202 
208- return mapper_intf.check_the_input_operation(bus, confirm.Description)203+ return common.check_the_input_operation(confirm.Description)
209end204end
210 205 
211local function command_authentication(bus, authentication)206local function command_authentication(bus, authentication)
@@ -247,22 +242,35 @@ local function command_authentication(bus, authentication)
247 return true242 return true
248end243end
249 244 
250-function cli:execute_command_request(details, reminder, method, header, value)245+local function install_authenticated_context(auth_result)
246+ if type(auth_result.context) ~= 'table' then
247+ return
248+ end
249+ 
250+ local authenticated = context.new()
251+ for key, value in pairs(auth_result.context) do
252+ authenticated[key] = value
253+ end
254+ context.set_context(authenticated)
255+end
256+ 
257+function cli:execute_command_request(details, reminder, method, header, value, raw_value)
251 if not details or not details.Mapper then258 if not details or not details.Mapper then
252 log:error('The route mapper response is abnormal(details data)')259 log:error('The route mapper response is abnormal(details data)')
253 print('Invalid Command')260 print('Invalid Command')
261+ return
254 end262 end
255 263 
256 -- -v后接参数内容检验异常264 -- -v后接参数内容检验异常
257- if details.ReqErrs and #details.ReqErrs ~= 0 then265+ if details.RequestErrors and #details.RequestErrors ~= 0 then
258- common.print_errs_message(details.ReqErrs, false)266+ common.print_errs_message(details.RequestErrors, false)
259 print('')267 print('')
260 common.print_command_reminder(reminder)268 common.print_command_reminder(reminder)
261 return269 return
262 end270 end
263 271 
264 if272 if
265- not command_confirm(self.bus, details.Confirm)273+ not command_confirm(details.Confirm)
266 or not command_authentication(self.bus, details.Authentication)274 or not command_authentication(self.bus, details.Authentication)
267 then275 then
268 return276 return
@@ -270,6 +278,18 @@ function cli:execute_command_request(details, reminder, method, header, value)
270 278 
271 local is_sol_activate = common.check_is_sol_activate_or_deactivate(details.Uri)279 local is_sol_activate = common.check_is_sol_activate_or_deactivate(details.Uri)
272 if is_sol_activate == true then280 if is_sol_activate == true then
281+ local auth_result = self.mapper:authenticate(details.Uri, method, {
282+ header = header,
283+ user = common.get_user_info(),
284+ required = false,
285+ })
286+ if not auth_result.accepted then
287+ print(auth_result.message)
288+ print('Request failed.')
289+ return
290+ end
291+ install_authenticated_context(auth_result)
292+ 
273 local route_file = '/opt/bmc/apps/cli/lualib/route/ipmcset/sol_activate.lua'293 local route_file = '/opt/bmc/apps/cli/lualib/route/ipmcset/sol_activate.lua'
274 local ret = file_sec.check_realpath_before_open_s(route_file)294 local ret = file_sec.check_realpath_before_open_s(route_file)
275 if ret ~= 0 then295 if ret ~= 0 then
@@ -278,7 +298,7 @@ function cli:execute_command_request(details, reminder, method, header, value)
278 end298 end
279 299 
280 local route_func = dofile(route_file)300 local route_func = dofile(route_file)
281- route_func(self.bus, value, header)301+ route_func(self.bus, raw_value or value, header)
282 return302 return
283 end303 end
284 304 
@@ -293,6 +313,31 @@ function cli:execute_command_request(details, reminder, method, header, value)
293 cmd_type:call(details, reminder, method, header, value)313 cmd_type:call(details, reminder, method, header, value)
294end314end
295 315 
316+local function discovery_reminder(discovery)
317+ local reminder = {}
318+ for _, candidate in ipairs(discovery.Candidates or {}) do
319+ local location, target, dataitem = string.match(candidate.Path or '', '^/cli/v1/([^/]+)/?([^/]*)/?([^/]*)')
320+ local option
321+ local command
322+ if target == '' then
323+ option = '-l'
324+ command = location
325+ elseif dataitem == '' then
326+ option = '-t'
327+ command = target
328+ else
329+ option = '-d'
330+ command = dataitem
331+ end
332+ reminder[option] = reminder[option] or {}
333+ reminder[option][#reminder[option] + 1] = {
334+ Command = command,
335+ Description = candidate.Description or '',
336+ }
337+ end
338+ return reminder
339+end
340+ 
296local function get_index(arr, v)341local function get_index(arr, v)
297 for index, value in ipairs(arr) do342 for index, value in ipairs(arr) do
298 if value == v then343 if value == v then
@@ -548,9 +593,9 @@ local function parse_ldconfig(value)
548end593end
549 594 
550-- 如果命令行传入的header字段为空,则从映射器配置获取默认参数595-- 如果命令行传入的header字段为空,则从映射器配置获取默认参数
551-local function get_default_header(header, probe_ret)596+local function get_default_header(header, details)
552- if header['SystemId'] and next(header['SystemId']) == nil and probe_ret.Details.ReqHeader['SystemId'] then597+ if header['SystemId'] and next(header['SystemId']) == nil and details.ReqHeader['SystemId'] then
553- header['SystemId'] = probe_ret.Details.ReqHeader['SystemId']598+ header['SystemId'] = details.ReqHeader['SystemId']
554 end599 end
555end600end
556 601 
@@ -630,19 +675,42 @@ function cli:command_request(method, params)
630 end675 end
631 end676 end
632 677 
633- local probe_ret = self.mapper:probe(self.bus, uri, method, header, value)678+ local discovery = self.mapper:discover(uri, method, {
634- if header and probe_ret.Details.ReqHeader then679+ header = header,
635- get_default_header(header, probe_ret)680+ body = {},
636- end681+ user = common.get_user_info(),
637- 682+ })
638- if probe_ret.MatchStatus == UN_MATCHED then683+ local has_candidates = type(discovery.Candidates) == 'table' and #discovery.Candidates > 0
639- print_target_dataitem_reminder(probe_ret.Reminder, method, self.bus)684+ if
640- elseif probe_ret.MatchStatus == URI_MATCHED or value_err then685+ type(discovery.Endpoint) == 'table'
641- self:print_uri_matched_or_value_err_help_info(probe_ret.Details.Uri, probe_ret.Reminder)686+ and (discovery.Status == 'Matched' or discovery.Status == 'Completed')
642- elseif probe_ret.MatchStatus == MATCHED then687+ and not has_candidates
643- self:execute_command_request(probe_ret.Details, probe_ret.Reminder, method, header, value)688+ then
689+ local raw_value = value
690+ local details
691+ details, value, uri = self.mapper:prepare(discovery, method, {
692+ header = header,
693+ body = value,
694+ user = common.get_user_info(),
695+ })
696+ details.Uri = uri
697+ if header and details.ReqHeader then
698+ get_default_header(header, details)
699+ end
700+ if (details.RequestErrors and #details.RequestErrors ~= 0) or value_err then
701+ self:print_uri_matched_or_value_err_help_info(details.Uri, details)
702+ else
703+ self:execute_command_request(details, details, method, header, value, raw_value)
704+ end
705+ elseif
706+ has_candidates
707+ or discovery.Status == 'Partial'
708+ or discovery.Status == 'Ambiguous'
709+ or discovery.Status == 'Unmatched'
710+ then
711+ print_target_dataitem_reminder(discovery_reminder(discovery), method, self.bus)
644 else712 else
645- log:error('The route mapper response is abnormal(not MatchStatus)')713+ log:error('The route mapper discovery response is abnormal(status: %s)', tostring(discovery.Status))
646 print('Invalid Command')714 print('Invalid Command')
647 end715 end
648 span:add_event('cli command request finished')716 span:add_event('cli command request finished')
@@ -12,8 +12,7 @@ local comm = require('cli.sol')
12local common = require('common')12local common = require('common')
13local utils_core = require('utils.core')13local utils_core = require('utils.core')
14local initiator = require('mc.initiator')14local initiator = require('mc.initiator')
15-local mdb_access = require('route_mapper.mdb_access')15+local mdb_access = require('mc.mdb')
16-local account = require('route_mapper.account')
17local bs = require('mc.bitstring')16local bs = require('mc.bitstring')
18local class = require('mc.class')17local class = require('mc.class')
19local log = require('mc.logging')18local log = require('mc.logging')
@@ -119,7 +118,6 @@ function sol_client:ctor(option, mode, sol_obj, bus, header)
119 local user = common.get_user_info()118 local user = common.get_user_info()
120 self.user_name = user.UserName119 self.user_name = user.UserName
121 self.ip_addr = user.ClientIp120 self.ip_addr = user.ClientIp
122- account.init_user_context(bus, user)
123 self.parser = parser.new() -- 协议处理模块121 self.parser = parser.new() -- 协议处理模块
124 self.is_connect = true122 self.is_connect = true
125 self.escape_pending = 0 -- 记录esc键 1 上次按键esc 0 上次按键非esc123 self.escape_pending = 0 -- 记录esc键 1 上次按键esc 0 上次按键非esc
@@ -14,4 +14,6 @@ return {
14 PROJECT_DIR = PROJECT_DIR,14 PROJECT_DIR = PROJECT_DIR,
15 ECHO_FILE_PATH = PROJECT_DIR .. '/test/unit/data/interface_config/echoes/',15 ECHO_FILE_PATH = PROJECT_DIR .. '/test/unit/data/interface_config/echoes/',
16 CUSTOMER_PATH = PROJECT_DIR .. '/test/unit/data/interface_config/customer/',16 CUSTOMER_PATH = PROJECT_DIR .. '/test/unit/data/interface_config/customer/',
17+ IPMCGET_PATH = PROJECT_DIR .. '/test/unit/data/interface_config/ipmcget',
18+ IPMCSET_PATH = PROJECT_DIR .. '/test/unit/data/interface_config/ipmcset',
17}19}
Rtest/unit/data/interface_config/ipmcget/system.json→test/unit/data/interface_config/ipmcget/mapping_config/system.json+0-0
文件重命名但无更改。
Rtest/unit/data/interface_config/ipmcget/target.json→test/unit/data/interface_config/ipmcget/mapping_config/target.json+0-0
文件重命名但无更改。
Rtest/unit/data/interface_config/ipmcset/sol.json→test/unit/data/interface_config/ipmcset/mapping_config/sol.json+0-0
文件重命名但无更改。
Rtest/unit/data/interface_config/ipmcset/system.json→test/unit/data/interface_config/ipmcset/mapping_config/system.json+0-0
文件重命名但无更改。
Rtest/unit/data/interface_config/ipmcset/user.json→test/unit/data/interface_config/ipmcset/mapping_config/user.json+0-0
文件重命名但无更改。
@@ -14,6 +14,7 @@ package.path = os.getenv('PROJECT_DIR') .. '/src/?.lua;' .. package.path
14local lu = require('luaunit')14local lu = require('luaunit')
15 15 
16require('test_cli')16require('test_cli')
17+require('test_cli_mapper')
17require('test_common')18require('test_common')
18require('test_template')19require('test_template')
19require('test_template_util')20require('test_template_util')
@@ -0,0 +1,111 @@
1+-- Copyright (c) 2026 Huawei Technologies Co., Ltd.
2+-- openUBMC is licensed under Mulan PSL v2.
3+-- You can use this software according to the terms and conditions of the Mulan PSL v2.
4+-- You may obtain a copy of Mulan PSL v2 at:
5+-- http://license.coscl.org.cn/MulanPSL2
6+-- THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
7+-- EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
8+-- MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
9+-- See the Mulan PSL v2 for more details.
10+ 
11+local lu = require('luaunit')
12+local cli_mapper = require('cli_mapper')
13+ 
14+TestCliMapper = {}
15+ 
16+function TestCliMapper:test_prepare_converts_ordered_cli_values()
17+ local observed_body
18+ local mapper = setmetatable({
19+ describe = function(_, _, _, params)
20+ observed_body = params.body
21+ return { Mapper = { Type = 'Ordinary' } }
22+ end,
23+ }, { __index = cli_mapper })
24+ local discovery = {
25+ ResolvedPath = '/cli/v1/system/example',
26+ Endpoint = {
27+ Parameters = {
28+ { Name = 'Optional', Types = { 'string' }, Required = false },
29+ { Name = 'Count', Types = { 'integer' }, Required = true },
30+ { Name = 'Enabled', Types = { 'boolean' }, Required = false },
31+ },
32+ },
33+ }
34+ 
35+ local _, body, uri = mapper:prepare(discovery, 'Patch', { body = { 'name', '7', 'true' } })
36+ 
37+ lu.assertEquals(uri, '/cli/v1/system/example')
38+ lu.assertEquals(body, { Optional = 'name', Count = 7, Enabled = true })
39+ lu.assertEquals(observed_body, body)
40+end
41+ 
42+function TestCliMapper:test_prepare_preserves_structured_request_body()
43+ local mapper = setmetatable({
44+ describe = function(_, _, _, params)
45+ return params.body
46+ end,
47+ }, { __index = cli_mapper })
48+ local discovery = {
49+ InputPath = '/cli/v1/system/example',
50+ Endpoint = { Parameters = {} },
51+ }
52+ local input = { Name = 'node-1' }
53+ 
54+ local description, body = mapper:prepare(discovery, 'Patch', { body = input })
55+ 
56+ lu.assertEquals(body, input)
57+ lu.assertEquals(description, input)
58+end
59+ 
60+function TestCliMapper:test_execute_normalizes_client_ip_for_route_mapper_context()
61+ local observed_context
62+ local mapper = setmetatable({
63+ runtime = {
64+ execute = function(_, _, _, _, _, context)
65+ observed_context = context
66+ return {}
67+ end,
68+ },
69+ }, { __index = cli_mapper })
70+ local user = {
71+ Interface = 'CLI',
72+ UserName = 'operator',
73+ ClientIp = '192.0.2.1:2200',
74+ }
75+ 
76+ mapper:execute('/cli/v1/_/version', 'Get', { user = user })
77+ 
78+ lu.assertEquals(observed_context, {
79+ Interface = 'CLI',
80+ UserName = 'operator',
81+ ClientAddr = '192.0.2.1:2200',
82+ })
83+ lu.assertEquals(user.ClientIp, '192.0.2.1:2200')
84+end
85+ 
86+function TestCliMapper:test_authenticate_preserves_explicit_client_addr()
87+ local observed_context
88+ local mapper = setmetatable({
89+ runtime = {
90+ authenticate = function(_, _, _, _, context)
91+ observed_context = context
92+ return { accepted = true }
93+ end,
94+ },
95+ }, { __index = cli_mapper })
96+ 
97+ mapper:authenticate('/cli/v1/_/version', 'Get', {
98+ context = {
99+ Interface = 'CLI',
100+ UserName = 'operator',
101+ ClientIp = '192.0.2.1:2200',
102+ ClientAddr = '198.51.100.8:22',
103+ },
104+ })
105+ 
106+ lu.assertEquals(observed_context, {
107+ Interface = 'CLI',
108+ UserName = 'operator',
109+ ClientAddr = '198.51.100.8:22',
110+ })
111+end
@@ -10,19 +10,18 @@
10 10 
11local lu = require('luaunit')11local lu = require('luaunit')
12local command_base = require('command.base')12local command_base = require('command.base')
13-local account = require('route_mapper.account')
14local config = require('config')13local config = require('config')
15 14 
16local customer_path = config.CUSTOMER_PATH .. 'abc/'15local customer_path = config.CUSTOMER_PATH .. 'abc/'
17 16 
18-account.get_package_customer = function()
19- return 'abc'
20-end
21- 
22TestCommandBase = {}17TestCommandBase = {}
23 18 
24function TestCommandBase:test_get_echo_path()19function TestCommandBase:test_get_echo_path()
25- local base = command_base.new()20+ local base = command_base.new(nil, {
21+ customer = function()
22+ return 'abc'
23+ end,
24+ })
26 25 
27 lu.assertEquals(customer_path .. 'echoes/ipmcget/_time', base:get_echo_path('ipmcget/_time'))26 lu.assertEquals(customer_path .. 'echoes/ipmcget/_time', base:get_echo_path('ipmcget/_time'))
28end27end
@@ -14,7 +14,7 @@ local src_config = require('lualib.config')
14TestConfig = {}14TestConfig = {}
15function TestConfig:test_config()15function TestConfig:test_config()
16 lu.assertEquals(src_config.ECHO_FILE_PATH, '/opt/bmc/apps/cli/interface_config/echoes/')16 lu.assertEquals(src_config.ECHO_FILE_PATH, '/opt/bmc/apps/cli/interface_config/echoes/')
17- lu.assertEquals(src_config.IPMCSET_PATH, '/opt/bmc/apps/cli/interface_config/ipmcset')
18 lu.assertEquals(src_config.CUSTOMER_PATH, '/opt/bmc/apps/cli/interface_config/customer/')17 lu.assertEquals(src_config.CUSTOMER_PATH, '/opt/bmc/apps/cli/interface_config/customer/')
19 lu.assertEquals(src_config.IPMCGET_PATH, '/opt/bmc/apps/cli/interface_config/ipmcget')18 lu.assertEquals(src_config.IPMCGET_PATH, '/opt/bmc/apps/cli/interface_config/ipmcget')
19+ lu.assertEquals(src_config.IPMCSET_PATH, '/opt/bmc/apps/cli/interface_config/ipmcset')
20end20end
@@ -12,11 +12,16 @@ local lu = require('luaunit')
12local ipmc = require('ipmc')12local ipmc = require('ipmc')
13local common = require('common')13local common = require('common')
14local config = require('config')14local config = require('config')
15+local context = require('mc.context')
15 16 
16TestIpmc = {}17TestIpmc = {}
17 18 
18function TestIpmc:setUp()19function TestIpmc:setUp()
19- self.ipmc = ipmc.new(config.PROJECT_DIR .. '/test/unit/data/interface_config/ipmcget')20+ self.ipmc = ipmc.new(config.IPMCGET_PATH, {
21+ timeout_call = function()
22+ error('unexpected route mapper bus call')
23+ end,
24+ })
20end25end
21 26 
22function TestIpmc:tearDown() end27function TestIpmc:tearDown() end
@@ -24,7 +29,7 @@ function TestIpmc:tearDown() end
24function TestIpmc:test_execute_command_request()29function TestIpmc:test_execute_command_request()
25 local ok, ret30 local ok, ret
26 local details = {31 local details = {
27- ReqErrs = { { Severity = 'OK', Message = 'InternalError' } },32+ RequestErrors = { { Severity = 'OK', Message = 'InternalError' } },
28 }33 }
29 34 
30 ok, ret = pcall(function()35 ok, ret = pcall(function()
@@ -33,7 +38,7 @@ function TestIpmc:test_execute_command_request()
33 lu.assertEquals(ok, true)38 lu.assertEquals(ok, true)
34 lu.assertIsNil(ret)39 lu.assertIsNil(ret)
35 40 
36- details = { ReqErrs = {}, Mapper = { Type = 123 } }41+ details = { RequestErrors = {}, Mapper = { Type = 123 } }
37 42 
38 ok, ret = pcall(function()43 ok, ret = pcall(function()
39 return self.ipmc:execute_command_request(details)44 return self.ipmc:execute_command_request(details)
@@ -42,17 +47,30 @@ function TestIpmc:test_execute_command_request()
42 lu.assertIsNil(ret)47 lu.assertIsNil(ret)
43 48 
44 local check_is_sol_activate_or_deactivate = common.check_is_sol_activate_or_deactivate49 local check_is_sol_activate_or_deactivate = common.check_is_sol_activate_or_deactivate
50+ local authenticate = self.ipmc.mapper.authenticate
51+ local set_context = context.set_context
52+ local installed_context
45 common.check_is_sol_activate_or_deactivate = function()53 common.check_is_sol_activate_or_deactivate = function()
46 return true54 return true
47 end55 end
56+ self.ipmc.mapper.authenticate = function()
57+ return { accepted = true, context = { UserName = 'cli-user', Privilege = 1 } }
58+ end
59+ context.set_context = function(value)
60+ installed_context = value
61+ end
48 62 
49 ok, ret = pcall(function()63 ok, ret = pcall(function()
50 return self.ipmc:execute_command_request(details)64 return self.ipmc:execute_command_request(details)
51 end)65 end)
52 lu.assertEquals(ok, true)66 lu.assertEquals(ok, true)
53 lu.assertIsNil(ret)67 lu.assertIsNil(ret)
68+ lu.assertEquals(installed_context.UserName, 'cli-user')
69+ lu.assertEquals(installed_context.Privilege, 1)
54 70 
55 common.check_is_sol_activate_or_deactivate = check_is_sol_activate_or_deactivate71 common.check_is_sol_activate_or_deactivate = check_is_sol_activate_or_deactivate
72+ self.ipmc.mapper.authenticate = authenticate
73+ context.set_context = set_context
56end74end
57 75 
58function TestIpmc:test_command_request()76function TestIpmc:test_command_request()
@@ -60,8 +78,11 @@ function TestIpmc:test_command_request()
60 pcall = function()78 pcall = function()
61 return -179 return -1
62 end,80 end,
81+ timeout_call = function()
82+ error('unexpected route mapper bus call')
83+ end,
63 }84 }
64- local ipmc_new = ipmc.new(config.PROJECT_DIR .. '/test/unit/data/interface_config/ipmcget', test_bus)85+ local ipmc_new = ipmc.new(config.IPMCGET_PATH, test_bus)
65 local ok, ret, method, params86 local ok, ret, method, params
66 method = 'Patch'87 method = 'Patch'
67 params = { '-t', 'storage', '-d', 'addld', '-v', '111' }88 params = { '-t', 'storage', '-d', 'addld', '-v', '111' }
@@ -12,11 +12,16 @@ local lu = require('luaunit')
12local ipmc_location = require('ipmc_location_supported')12local ipmc_location = require('ipmc_location_supported')
13local common = require('common')13local common = require('common')
14local config = require('config')14local config = require('config')
15+local context = require('mc.context')
15 16 
16TestIpmcLocationSupported = {}17TestIpmcLocationSupported = {}
17 18 
18function TestIpmcLocationSupported:setUp()19function TestIpmcLocationSupported:setUp()
19- self.ipmc_location = ipmc_location.new(config.PROJECT_DIR .. '/test/unit/data/interface_config/ipmcget')20+ self.ipmc_location = ipmc_location.new(config.IPMCGET_PATH, {
21+ timeout_call = function()
22+ error('unexpected route mapper bus call')
23+ end,
24+ })
20end25end
21 26 
22function TestIpmcLocationSupported:tearDown() end27function TestIpmcLocationSupported:tearDown() end
@@ -24,7 +29,7 @@ function TestIpmcLocationSupported:tearDown() end
24function TestIpmcLocationSupported:test_execute_command_request()29function TestIpmcLocationSupported:test_execute_command_request()
25 local ok, ret30 local ok, ret
26 local details = {31 local details = {
27- ReqErrs = { { Severity = 'OK', Message = 'InternalError' } },32+ RequestErrors = { { Severity = 'OK', Message = 'InternalError' } },
28 }33 }
29 34 
30 ok, ret = pcall(function()35 ok, ret = pcall(function()
@@ -33,7 +38,7 @@ function TestIpmcLocationSupported:test_execute_command_request()
33 lu.assertEquals(ok, true)38 lu.assertEquals(ok, true)
34 lu.assertIsNil(ret)39 lu.assertIsNil(ret)
35 40 
36- details = { ReqErrs = {}, Mapper = { Type = 123 } }41+ details = { RequestErrors = {}, Mapper = { Type = 123 } }
37 42 
38 ok, ret = pcall(function()43 ok, ret = pcall(function()
39 return self.ipmc_location:execute_command_request(details)44 return self.ipmc_location:execute_command_request(details)
@@ -42,17 +47,30 @@ function TestIpmcLocationSupported:test_execute_command_request()
42 lu.assertIsNil(ret)47 lu.assertIsNil(ret)
43 48 
44 local check_is_sol_activate_or_deactivate = common.check_is_sol_activate_or_deactivate49 local check_is_sol_activate_or_deactivate = common.check_is_sol_activate_or_deactivate
50+ local authenticate = self.ipmc_location.mapper.authenticate
51+ local set_context = context.set_context
52+ local installed_context
45 common.check_is_sol_activate_or_deactivate = function()53 common.check_is_sol_activate_or_deactivate = function()
46 return true54 return true
47 end55 end
56+ self.ipmc_location.mapper.authenticate = function()
57+ return { accepted = true, context = { UserName = 'cli-user', Privilege = 1 } }
58+ end
59+ context.set_context = function(value)
60+ installed_context = value
61+ end
48 62 
49 ok, ret = pcall(function()63 ok, ret = pcall(function()
50 return self.ipmc_location:execute_command_request(details)64 return self.ipmc_location:execute_command_request(details)
51 end)65 end)
52 lu.assertEquals(ok, true)66 lu.assertEquals(ok, true)
53 lu.assertIsNil(ret)67 lu.assertIsNil(ret)
68+ lu.assertEquals(installed_context.UserName, 'cli-user')
69+ lu.assertEquals(installed_context.Privilege, 1)
54 70 
55 common.check_is_sol_activate_or_deactivate = check_is_sol_activate_or_deactivate71 common.check_is_sol_activate_or_deactivate = check_is_sol_activate_or_deactivate
72+ self.ipmc_location.mapper.authenticate = authenticate
73+ context.set_context = set_context
56end74end
57 75 
58function TestIpmcLocationSupported:test_command_request()76function TestIpmcLocationSupported:test_command_request()
@@ -60,8 +78,11 @@ function TestIpmcLocationSupported:test_command_request()
60 pcall = function()78 pcall = function()
61 return -179 return -1
62 end,80 end,
81+ timeout_call = function()
82+ error('unexpected route mapper bus call')
83+ end,
63 }84 }
64- local ipmc_new = ipmc_location.new(config.PROJECT_DIR .. '/test/unit/data/interface_config/ipmcget', test_bus)85+ local ipmc_new = ipmc_location.new(config.IPMCGET_PATH, test_bus)
65 local ok, ret, method, params86 local ok, ret, method, params
66 method = 'Patch'87 method = 'Patch'
67 params = { '-t', 'storage', '-d', 'addld', '-v', '111' }88 params = { '-t', 'storage', '-d', 'addld', '-v', '111' }
@@ -16,7 +16,7 @@ local utils_file = require('utils.file')
16local cli_utils = require('cli.utils')16local cli_utils = require('cli.utils')
17local cli = require('ipmc')17local cli = require('ipmc')
18local sd_bus = require('sd_bus')18local sd_bus = require('sd_bus')
19-local libroutemapper_utils = require('libroutemapper.utils')19+local common = require('common')
20 20 
21TestIpmcget = {}21TestIpmcget = {}
22 22 
@@ -45,9 +45,12 @@ function TestIpmcget:setUp()
45 pcall = function()45 pcall = function()
46 return -146 return -1
47 end,47 end,
48+ timeout_call = function()
49+ error('unexpected route mapper bus call')
50+ end,
48 }51 }
49 self.temp_cli_new = cli.new52 self.temp_cli_new = cli.new
50- self.cli_obj = self.cli_obj or cli.new(config.PROJECT_DIR .. '/test/unit/data/interface_config/ipmcget', self.bus)53+ self.cli_obj = self.cli_obj or cli.new(config.IPMCGET_PATH, self.bus)
51 cli.new = function()54 cli.new = function()
52 return self.cli_obj55 return self.cli_obj
53 end56 end
@@ -77,9 +80,9 @@ function TestIpmcget:test_ipmcget_operatelog()
77 lu.assertEquals(get_file_content(config.PROJECT_DIR .. '/test/unit/rsp_info/ipmcget_operatelog'), output)80 lu.assertEquals(get_file_content(config.PROJECT_DIR .. '/test/unit/rsp_info/ipmcget_operatelog'), output)
78 end81 end
79 82 
80- local temp_get_user_input = libroutemapper_utils.get_user_input83+ local temp_get_user_input = common.get_user_input
81 local count = 084 local count = 0
82- libroutemapper_utils.get_user_input = function(prompt, timeout)85+ common.get_user_input = function(prompt)
83 if count == 0 then86 if count == 0 then
84 print(prompt)87 print(prompt)
85 count = count + 188 count = count + 1
@@ -89,7 +92,7 @@ function TestIpmcget:test_ipmcget_operatelog()
89 return 0, 'q'92 return 0, 'q'
90 end93 end
91 loadfile(config.PROJECT_DIR .. '/src/service/ipmcget.lua')('-d', 'o')94 loadfile(config.PROJECT_DIR .. '/src/service/ipmcget.lua')('-d', 'o')
92- libroutemapper_utils.get_user_input = temp_get_user_input95+ common.get_user_input = temp_get_user_input
93end96end
94 97 
95function TestIpmcget:test_ipmcget_diaginfo()98function TestIpmcget:test_ipmcget_diaginfo()
@@ -16,7 +16,7 @@ local utils_file = require('utils.file')
16local cli_utils = require('cli.utils')16local cli_utils = require('cli.utils')
17local cli = require('ipmc')17local cli = require('ipmc')
18local sd_bus = require('sd_bus')18local sd_bus = require('sd_bus')
19-local libroutemapper_utils = require('libroutemapper.utils')19+local common = require('common')
20 20 
21TestIpmcset = {}21TestIpmcset = {}
22 22 
@@ -45,9 +45,12 @@ function TestIpmcset:setUp()
45 pcall = function()45 pcall = function()
46 return -146 return -1
47 end,47 end,
48+ timeout_call = function()
49+ error('unexpected route mapper bus call')
50+ end,
48 }51 }
49 self.temp_cli_new = cli.new52 self.temp_cli_new = cli.new
50- self.cli_obj = self.cli_obj or cli.new(config.PROJECT_DIR .. '/test/unit/data/interface_config/ipmcset', self.bus)53+ self.cli_obj = self.cli_obj or cli.new(config.IPMCSET_PATH, self.bus)
51 cli.new = function()54 cli.new = function()
52 return self.cli_obj55 return self.cli_obj
53 end56 end
@@ -85,13 +88,13 @@ function TestIpmcset:test_ipmcset_reset()
85 lu.assertEquals(get_file_content(config.PROJECT_DIR .. '/test/unit/rsp_info/ipmcset_reset'), output)88 lu.assertEquals(get_file_content(config.PROJECT_DIR .. '/test/unit/rsp_info/ipmcset_reset'), output)
86 end89 end
87 90 
88- local temp_get_user_input = libroutemapper_utils.get_user_input91+ local temp_get_user_input = common.get_user_input
89- libroutemapper_utils.get_user_input = function(prompt, timeout)92+ common.get_user_input = function(prompt)
90 print(prompt .. 'yes')93 print(prompt .. 'yes')
91 return 0, 'y'94 return 0, 'y'
92 end95 end
93 loadfile(config.PROJECT_DIR .. '/src/service/ipmcset.lua')('-d', 'reset')96 loadfile(config.PROJECT_DIR .. '/src/service/ipmcset.lua')('-d', 'reset')
94- libroutemapper_utils.get_user_input = temp_get_user_input97+ common.get_user_input = temp_get_user_input
95end98end
96 99 
97function TestIpmcset:test_ipmcset_user_unlock()100function TestIpmcset:test_ipmcset_user_unlock()
@@ -15,7 +15,7 @@ local log = require('mc.logging')
15local utils = require('mc.utils')15local utils = require('mc.utils')
16local utils_core = require('utils.core')16local utils_core = require('utils.core')
17local utils_file = require('utils.file')17local utils_file = require('utils.file')
18-local mdb_access = require('route_mapper.mdb_access')18+local mdb_access = require('mc.mdb')
19local cli_utils = require('cli.utils')19local cli_utils = require('cli.utils')
20local comm = require('cli.sol')20local comm = require('cli.sol')
21local common = require('common')21local common = require('common')