blob: 5d1598c60ede229197fdbcd669731bc94228d934 [file] [log] [blame]
George Keishinge7e91712021-09-03 11:28:44 -05001#!/usr/bin/env python3
Michael Walshed5b46e2017-05-24 11:49:14 -05002
3r"""
4Provide useful ipmi functions.
5"""
6
Patrick Williams20f38712022-12-08 06:18:26 -06007import json
Michael Walshf4098fb2018-02-28 10:54:46 -06008import re
Patrick Williams20f38712022-12-08 06:18:26 -06009import tempfile
10
11import bmc_ssh_utils as bsu
George Keishinge635ddc2022-12-08 07:38:02 -060012import gen_cmd as gc
Patrick Williams20f38712022-12-08 06:18:26 -060013import gen_misc as gm
14import gen_print as gp
Michael Walshed5b46e2017-05-24 11:49:14 -050015import gen_robot_keyword as grk
16import gen_robot_utils as gru
George Keishinge635ddc2022-12-08 07:38:02 -060017import ipmi_client as ic
Patrick Williams20f38712022-12-08 06:18:26 -060018import var_funcs as vf
19from robot.libraries.BuiltIn import BuiltIn
20
George Keishing09679892022-12-08 08:21:52 -060021gru.my_import_resource("ipmi_client.robot")
Michael Walshed5b46e2017-05-24 11:49:14 -050022
23
Michael Walshed5b46e2017-05-24 11:49:14 -050024def get_sol_info():
Michael Walshed5b46e2017-05-24 11:49:14 -050025 r"""
26 Get all SOL info and return it as a dictionary.
27
28 Example use:
29
30 Robot code:
31 ${sol_info}= get_sol_info
32 Rpvars sol_info
33
34 Output:
35 sol_info:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -050036 sol_info[Info]: SOL parameter 'Payload Channel (7)'
37 not supported - defaulting to 0x0e
Michael Walshed5b46e2017-05-24 11:49:14 -050038 sol_info[Character Send Threshold]: 1
39 sol_info[Force Authentication]: true
40 sol_info[Privilege Level]: USER
41 sol_info[Set in progress]: set-complete
42 sol_info[Retry Interval (ms)]: 100
43 sol_info[Non-Volatile Bit Rate (kbps)]: IPMI-Over-Serial-Setting
44 sol_info[Character Accumulate Level (ms)]: 100
45 sol_info[Enabled]: true
46 sol_info[Volatile Bit Rate (kbps)]: IPMI-Over-Serial-Setting
47 sol_info[Payload Channel]: 14 (0x0e)
48 sol_info[Payload Port]: 623
49 sol_info[Force Encryption]: true
50 sol_info[Retry Count]: 7
51 """
52
53 status, ret_values = grk.run_key_u("Run IPMI Standard Command sol info")
54
55 # Create temp file path.
56 temp = tempfile.NamedTemporaryFile()
57 temp_file_path = temp.name
58
59 # Write sol info to temp file path.
60 text_file = open(temp_file_path, "w")
61 text_file.write(ret_values)
62 text_file.close()
63
64 # Use my_parm_file to interpret data.
65 sol_info = gm.my_parm_file(temp_file_path)
66
67 return sol_info
68
Rahul Maheshwarid629b5c2017-05-23 08:06:28 -050069
Rahul Maheshwarid629b5c2017-05-23 08:06:28 -050070def set_sol_setting(setting_name, setting_value):
Rahul Maheshwarid629b5c2017-05-23 08:06:28 -050071 r"""
72 Set SOL setting with given value.
73
74 # Description of argument(s):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -050075 # setting_name SOL setting which needs to be set (e.g.
76 # "retry-count").
77 # setting_value Value which needs to be set (e.g. "7").
Rahul Maheshwarid629b5c2017-05-23 08:06:28 -050078 """
79
Patrick Williams20f38712022-12-08 06:18:26 -060080 status, ret_values = grk.run_key_u(
81 "Run IPMI Standard Command sol set "
82 + setting_name
83 + " "
84 + setting_value
85 )
Rahul Maheshwarid629b5c2017-05-23 08:06:28 -050086
87 return status
88
Rahul Maheshwarid629b5c2017-05-23 08:06:28 -050089
Patrick Williams20f38712022-12-08 06:18:26 -060090def execute_ipmi_cmd(
91 cmd_string, ipmi_cmd_type="inband", print_output=1, ignore_err=0, **options
92):
Michael Walsh94811f62018-09-05 14:55:12 -050093 r"""
94 Run the given command string as an IPMI command and return the stdout,
95 stderr and the return code.
96
97 Description of argument(s):
98 cmd_string The command string to be run as an IPMI
99 command.
100 ipmi_cmd_type 'inband' or 'external'.
101 print_output If this is set, this function will print
102 the stdout/stderr generated by
103 the IPMI command.
104 ignore_err Ignore error means that a failure
105 encountered by running the command
106 string will not be raised as a python
107 exception.
Michael Walsh19e70c82019-01-23 11:07:15 -0600108 options These are passed directly to the
109 create_ipmi_ext_command_string function.
110 See that function's prolog for details.
Michael Walsh94811f62018-09-05 14:55:12 -0500111 """
112
Patrick Williams20f38712022-12-08 06:18:26 -0600113 if ipmi_cmd_type == "inband":
Michael Walsh94811f62018-09-05 14:55:12 -0500114 IPMI_INBAND_CMD = BuiltIn().get_variable_value("${IPMI_INBAND_CMD}")
115 cmd_buf = IPMI_INBAND_CMD + " " + cmd_string
Patrick Williams20f38712022-12-08 06:18:26 -0600116 return bsu.os_execute_command(
117 cmd_buf, print_out=print_output, ignore_err=ignore_err
118 )
Michael Walsh94811f62018-09-05 14:55:12 -0500119
Patrick Williams20f38712022-12-08 06:18:26 -0600120 if ipmi_cmd_type == "external":
Michael Walsh19e70c82019-01-23 11:07:15 -0600121 cmd_buf = ic.create_ipmi_ext_command_string(cmd_string, **options)
Patrick Williams20f38712022-12-08 06:18:26 -0600122 rc, stdout, stderr = gc.shell_cmd(
123 cmd_buf,
124 print_output=print_output,
125 ignore_err=ignore_err,
126 return_stderr=1,
127 )
Michael Walsh94811f62018-09-05 14:55:12 -0500128 return stdout, stderr, rc
129
130
Patrick Williams20f38712022-12-08 06:18:26 -0600131def get_lan_print_dict(channel_number="", ipmi_cmd_type="external"):
Michael Walsh4481b932018-02-08 11:45:15 -0600132 r"""
133 Get IPMI 'lan print' output and return it as a dictionary.
134
135 Here is an example of the IPMI lan print output:
136
137 Set in Progress : Set Complete
138 Auth Type Support : MD5
139 Auth Type Enable : Callback : MD5
140 : User : MD5
141 : Operator : MD5
142 : Admin : MD5
143 : OEM : MD5
144 IP Address Source : Static Address
145 IP Address : x.x.x.x
146 Subnet Mask : x.x.x.x
147 MAC Address : xx:xx:xx:xx:xx:xx
148 Default Gateway IP : x.x.x.x
149 802.1q VLAN ID : Disabled
150 Cipher Suite Priv Max : Not Available
151 Bad Password Threshold : Not Available
152
153 Given that data, this function will return the following dictionary.
154
155 lan_print_dict:
156 [Set in Progress]: Set Complete
157 [Auth Type Support]: MD5
158 [Auth Type Enable]:
159 [Callback]: MD5
160 [User]: MD5
161 [Operator]: MD5
162 [Admin]: MD5
163 [OEM]: MD5
164 [IP Address Source]: Static Address
165 [IP Address]: x.x.x.x
166 [Subnet Mask]: x.x.x.x
167 [MAC Address]: xx:xx:xx:xx:xx:xx
168 [Default Gateway IP]: x.x.x.x
169 [802.1q VLAN ID]: Disabled
170 [Cipher Suite Priv Max]: Not Available
171 [Bad Password Threshold]: Not Available
172
Michael Walsh94811f62018-09-05 14:55:12 -0500173 Description of argument(s):
174 ipmi_cmd_type The type of ipmi command to use (e.g.
175 'inband', 'external').
Michael Walsh4481b932018-02-08 11:45:15 -0600176 """
177
Tony Leeea741302019-11-08 11:01:58 +0800178 channel_number = str(channel_number)
Michael Walsh4481b932018-02-08 11:45:15 -0600179 # Notice in the example of data above that 'Auth Type Enable' needs some
180 # special processing. We essentially want to isolate its data and remove
181 # the 'Auth Type Enable' string so that key_value_outbuf_to_dict can
182 # process it as a sub-dictionary.
Patrick Williams20f38712022-12-08 06:18:26 -0600183 cmd_buf = (
184 "lan print "
185 + channel_number
186 + " | grep -E '^(Auth Type Enable)"
187 + "?[ ]+: ' | sed -re 's/^(Auth Type Enable)?[ ]+: //g'"
188 )
189 stdout1, stderr, rc = execute_ipmi_cmd(
190 cmd_buf, ipmi_cmd_type, print_output=0
191 )
Michael Walsh4481b932018-02-08 11:45:15 -0600192
193 # Now get the remainder of the data and exclude the lines with no field
194 # names (i.e. the 'Auth Type Enable' sub-fields).
Tony Leeea741302019-11-08 11:01:58 +0800195 cmd_buf = "lan print " + channel_number + " | grep -E -v '^[ ]+: '"
Patrick Williams20f38712022-12-08 06:18:26 -0600196 stdout2, stderr, rc = execute_ipmi_cmd(
197 cmd_buf, ipmi_cmd_type, print_output=0
198 )
Michael Walsh4481b932018-02-08 11:45:15 -0600199
200 # Make auth_type_enable_dict sub-dictionary...
Patrick Williams20f38712022-12-08 06:18:26 -0600201 auth_type_enable_dict = vf.key_value_outbuf_to_dict(
202 stdout1, to_lower=0, underscores=0
203 )
Michael Walsh4481b932018-02-08 11:45:15 -0600204
205 # Create the lan_print_dict...
Patrick Williams20f38712022-12-08 06:18:26 -0600206 lan_print_dict = vf.key_value_outbuf_to_dict(
207 stdout2, to_lower=0, underscores=0
208 )
Michael Walsh4481b932018-02-08 11:45:15 -0600209 # Re-assign 'Auth Type Enable' to contain the auth_type_enable_dict.
Patrick Williams20f38712022-12-08 06:18:26 -0600210 lan_print_dict["Auth Type Enable"] = auth_type_enable_dict
Michael Walsh4481b932018-02-08 11:45:15 -0600211
212 return lan_print_dict
Michael Walshd59ed7c2018-02-15 10:19:38 -0600213
214
Michael Walshf4098fb2018-02-28 10:54:46 -0600215def get_ipmi_power_reading(strip_watts=1):
Michael Walshd59ed7c2018-02-15 10:19:38 -0600216 r"""
217 Get IPMI power reading data and return it as a dictionary.
218
219 The data is obtained by issuing the IPMI "power reading" command. An
220 example is shown below:
221
222 Instantaneous power reading: 234 Watts
223 Minimum during sampling period: 234 Watts
224 Maximum during sampling period: 234 Watts
225 Average power reading over sample period: 234 Watts
226 IPMI timestamp: Thu Jan 1 00:00:00 1970
227 Sampling period: 00000000 Seconds.
228 Power reading state is: deactivated
229
230 For the data shown above, the following dictionary will be returned.
231
232 result:
233 [instantaneous_power_reading]: 238 Watts
234 [minimum_during_sampling_period]: 238 Watts
235 [maximum_during_sampling_period]: 238 Watts
236 [average_power_reading_over_sample_period]: 238 Watts
237 [ipmi_timestamp]: Thu Jan 1 00:00:00 1970
238 [sampling_period]: 00000000 Seconds.
239 [power_reading_state_is]: deactivated
Michael Walshf4098fb2018-02-28 10:54:46 -0600240
241 Description of argument(s):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500242 strip_watts Strip all dictionary values of the
243 trailing " Watts" substring.
Michael Walshd59ed7c2018-02-15 10:19:38 -0600244 """
245
Patrick Williams20f38712022-12-08 06:18:26 -0600246 status, ret_values = grk.run_key_u(
247 "Run IPMI Standard Command dcmi power reading"
248 )
Michael Walshd59ed7c2018-02-15 10:19:38 -0600249 result = vf.key_value_outbuf_to_dict(ret_values)
250
Michael Walshf4098fb2018-02-28 10:54:46 -0600251 if strip_watts:
Patrick Williams20f38712022-12-08 06:18:26 -0600252 result.update((k, re.sub(" Watts$", "", v)) for k, v in result.items())
Michael Walshf4098fb2018-02-28 10:54:46 -0600253
Michael Walshd59ed7c2018-02-15 10:19:38 -0600254 return result
Michael Walshaf5607e2018-02-19 17:37:20 -0600255
256
257def get_mc_info():
Michael Walshaf5607e2018-02-19 17:37:20 -0600258 r"""
259 Get IPMI mc info data and return it as a dictionary.
260
261 The data is obtained by issuing the IPMI "mc info" command. An
262 example is shown below:
263
264 Device ID : 0
265 Device Revision : 0
266 Firmware Revision : 2.01
267 IPMI Version : 2.0
268 Manufacturer ID : 42817
269 Manufacturer Name : Unknown (0xA741)
270 Product ID : 16975 (0x424f)
271 Product Name : Unknown (0x424F)
272 Device Available : yes
273 Provides Device SDRs : yes
274 Additional Device Support :
275 Sensor Device
276 SEL Device
277 FRU Inventory Device
278 Chassis Device
279 Aux Firmware Rev Info :
280 0x00
281 0x00
282 0x00
283 0x00
284
285 For the data shown above, the following dictionary will be returned.
286 mc_info:
287 [device_id]: 0
288 [device_revision]: 0
289 [firmware_revision]: 2.01
290 [ipmi_version]: 2.0
291 [manufacturer_id]: 42817
292 [manufacturer_name]: Unknown (0xA741)
293 [product_id]: 16975 (0x424f)
294 [product_name]: Unknown (0x424F)
295 [device_available]: yes
296 [provides_device_sdrs]: yes
297 [additional_device_support]:
298 [additional_device_support][0]: Sensor Device
299 [additional_device_support][1]: SEL Device
300 [additional_device_support][2]: FRU Inventory Device
301 [additional_device_support][3]: Chassis Device
302 [aux_firmware_rev_info]:
303 [aux_firmware_rev_info][0]: 0x00
304 [aux_firmware_rev_info][1]: 0x00
305 [aux_firmware_rev_info][2]: 0x00
306 [aux_firmware_rev_info][3]: 0x00
307 """
308
Patrick Williams20f38712022-12-08 06:18:26 -0600309 status, ret_values = grk.run_key_u("Run IPMI Standard Command mc info")
Michael Walshaf5607e2018-02-19 17:37:20 -0600310 result = vf.key_value_outbuf_to_dict(ret_values, process_indent=1)
311
312 return result
Rahul Maheshwaridc6a32c2018-03-15 05:21:55 -0500313
314
315def get_sdr_info():
Rahul Maheshwaridc6a32c2018-03-15 05:21:55 -0500316 r"""
317 Get IPMI sdr info data and return it as a dictionary.
318
319 The data is obtained by issuing the IPMI "sdr info" command. An
320 example is shown below:
321
322 SDR Version : 0x51
323 Record Count : 216
324 Free Space : unspecified
325 Most recent Addition :
326 Most recent Erase :
327 SDR overflow : no
328 SDR Repository Update Support : unspecified
329 Delete SDR supported : no
330 Partial Add SDR supported : no
331 Reserve SDR repository supported : no
332 SDR Repository Alloc info supported : no
333
334 For the data shown above, the following dictionary will be returned.
335 mc_info:
336
337 [sdr_version]: 0x51
338 [record_Count]: 216
339 [free_space]: unspecified
340 [most_recent_addition]:
341 [most_recent_erase]:
342 [sdr_overflow]: no
343 [sdr_repository_update_support]: unspecified
344 [delete_sdr_supported]: no
345 [partial_add_sdr_supported]: no
346 [reserve_sdr_repository_supported]: no
347 [sdr_repository_alloc_info_supported]: no
348 """
349
Patrick Williams20f38712022-12-08 06:18:26 -0600350 status, ret_values = grk.run_key_u("Run IPMI Standard Command sdr info")
Rahul Maheshwaridc6a32c2018-03-15 05:21:55 -0500351 result = vf.key_value_outbuf_to_dict(ret_values, process_indent=1)
352
353 return result
George Keishing3511a3f2018-04-19 10:38:30 -0500354
355
356def get_aux_version(version_id):
357 r"""
358 Get IPMI Aux version info data and return it.
359
360 Description of argument(s):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500361 version_id The data is obtained by from BMC
362 /etc/os-release
363 (e.g. "xxx-v2.1-438-g0030304-r3-gfea8585").
George Keishing3511a3f2018-04-19 10:38:30 -0500364
365 In the prior example, the 3rd field is "438" is the commit version and
366 the 5th field is "r3" and value "3" is the release version.
367
368 Aux version return from this function 4380003.
369 """
370
371 # Commit version.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500372 count = re.findall("-(\\d{1,4})-", version_id)
George Keishing3511a3f2018-04-19 10:38:30 -0500373
374 # Release version.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500375 release = re.findall("-r(\\d{1,4})", version_id)
George Keishing3511a3f2018-04-19 10:38:30 -0500376 if release:
377 aux_version = count[0] + "{0:0>4}".format(release[0])
378 else:
379 aux_version = count[0] + "0000"
380
381 return aux_version
Michael Walsh27b14a62018-05-24 11:05:07 -0500382
383
384def get_fru_info():
385 r"""
386 Get fru info and return it as a list of dictionaries.
387
388 The data is obtained by issuing the IPMI "fru print -N 50" command. An
389 example is shown below:
390
391 FRU Device Description : Builtin FRU Device (ID 0)
392 Device not present (Unspecified error)
393
394 FRU Device Description : cpu0 (ID 1)
395 Board Mfg Date : Sun Dec 31 18:00:00 1995
George Keishinge0a81282018-06-08 10:02:30 -0500396 Board Mfg : <Manufacturer Name>
Michael Walsh27b14a62018-05-24 11:05:07 -0500397 Board Product : PROCESSOR MODULE
398 Board Serial : YA1934315964
399 Board Part Number : 02CY209
400
401 FRU Device Description : cpu1 (ID 2)
402 Board Mfg Date : Sun Dec 31 18:00:00 1995
George Keishinge0a81282018-06-08 10:02:30 -0500403 Board Mfg : <Manufacturer Name>
Michael Walsh27b14a62018-05-24 11:05:07 -0500404 Board Product : PROCESSOR MODULE
405 Board Serial : YA1934315965
406 Board Part Number : 02CY209
407
408 For the data shown above, the following list of dictionaries will be
409 returned.
410
411 fru_obj:
412 fru_obj[0]:
413 [fru_device_description]: Builtin FRU Device (ID 0)
414 [state]: Device not present (Unspecified error)
415 fru_obj[1]:
416 [fru_device_description]: cpu0 (ID 1)
417 [board_mfg_date]: Sun Dec 31 18:00:00 1995
George Keishinge0a81282018-06-08 10:02:30 -0500418 [board_mfg]: <Manufacturer Name>
Michael Walsh27b14a62018-05-24 11:05:07 -0500419 [board_product]: PROCESSOR MODULE
420 [board_serial]: YA1934315964
421 [board_part_number]: 02CY209
422 fru_obj[2]:
423 [fru_device_description]: cpu1 (ID 2)
424 [board_mfg_date]: Sun Dec 31 18:00:00 1995
George Keishinge0a81282018-06-08 10:02:30 -0500425 [board_mfg]: <Manufacturer Name>
Michael Walsh27b14a62018-05-24 11:05:07 -0500426 [board_product]: PROCESSOR MODULE
427 [board_serial]: YA1934315965
428 [board_part_number]: 02CY209
429 """
430
Patrick Williams20f38712022-12-08 06:18:26 -0600431 status, ret_values = grk.run_key_u(
432 "Run IPMI Standard Command fru print -N 50"
433 )
Michael Walsh27b14a62018-05-24 11:05:07 -0500434
435 # Manipulate the "Device not present" line to create a "state" key.
Patrick Williams20f38712022-12-08 06:18:26 -0600436 ret_values = re.sub(
437 "Device not present", "state : Device not present", ret_values
438 )
Michael Walsh27b14a62018-05-24 11:05:07 -0500439
Patrick Williams20f38712022-12-08 06:18:26 -0600440 return [
441 vf.key_value_outbuf_to_dict(x) for x in re.split("\n\n", ret_values)
442 ]
Michael Walsh61224e62018-05-30 17:58:42 -0500443
444
Patrick Williams20f38712022-12-08 06:18:26 -0600445def get_component_fru_info(component="cpu", fru_objs=None):
Michael Walsh61224e62018-05-30 17:58:42 -0500446 r"""
447 Get fru info for the given component and return it as a list of
448 dictionaries.
449
450 This function calls upon get_fru_info and then filters out the unwanted
451 entries. See get_fru_info's prolog for a layout of the data.
452
453 Description of argument(s):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500454 component The component (e.g. "cpu", "dimm", etc.).
455 fru_objs A fru_objs list such as the one returned
456 by get_fru_info. If this is None, then
457 this function will call get_fru_info to
458 obtain such a list.
459 Supplying this argument may improve
460 performance if this function is to be
461 called multiple times.
Michael Walsh61224e62018-05-30 17:58:42 -0500462 """
463
Michael Walsha95e4ef2018-06-06 17:53:04 -0500464 if fru_objs is None:
465 fru_objs = get_fru_info()
Patrick Williams20f38712022-12-08 06:18:26 -0600466 return [
467 x
468 for x in fru_objs
469 if re.match(component + "([0-9]+)? ", x["fru_device_description"])
470 ]
Rahul Maheshwari24e0e792019-02-12 22:40:23 -0600471
472
473def get_user_info(userid, channel_number=1):
474 r"""
475 Get user info using channel command and return it as a dictionary.
476
477 Description of argument(s):
478 userid The userid (e.g. "1", "2", etc.).
479 channel_number The user's channel number (e.g. "1").
480
Michael Walshe733b262019-12-09 11:45:24 -0600481 Note: If userid is blank, this function will return a list of dictionaries. Each list entry represents
482 one userid record.
483
Rahul Maheshwari24e0e792019-02-12 22:40:23 -0600484 The data is obtained by issuing the IPMI "channel getaccess" command. An
485 example is shown below for user id 1 and channel number 1.
486
487 Maximum User IDs : 15
488 Enabled User IDs : 1
489 User ID : 1
490 User Name : root
491 Fixed Name : No
492 Access Available : callback
493 Link Authentication : enabled
494 IPMI Messaging : enabled
495 Privilege Level : ADMINISTRATOR
496 Enable Status : enabled
497
498 For the data shown above, the following dictionary will be returned.
499
500 user_info:
501 [maximum_userids]: 15
502 [enabled_userids: 1
503 [userid] 1
504 [user_name] root
505 [fixed_name] No
506 [access_available] callback
507 [link_authentication] enabled
508 [ipmi_messaging] enabled
509 [privilege_level] ADMINISTRATOR
510 [enable_status] enabled
Rahul Maheshwari24e0e792019-02-12 22:40:23 -0600511 """
512
Patrick Williams20f38712022-12-08 06:18:26 -0600513 status, ret_values = grk.run_key_u(
514 "Run IPMI Standard Command channel getaccess "
515 + str(channel_number)
516 + " "
517 + str(userid)
518 )
Rahul Maheshwari24e0e792019-02-12 22:40:23 -0600519
Michael Walshe733b262019-12-09 11:45:24 -0600520 if userid == "":
521 return vf.key_value_outbuf_to_dicts(ret_values, process_indent=1)
522 else:
523 return vf.key_value_outbuf_to_dict(ret_values, process_indent=1)
George Keishing45511e82019-10-15 01:26:55 -0500524
525
526def channel_getciphers_ipmi():
George Keishing45511e82019-10-15 01:26:55 -0500527 r"""
528 Run 'channel getciphers ipmi' command and return the result as a list of dictionaries.
529
530 Example robot code:
531 ${ipmi_channel_ciphers}= Channel Getciphers IPMI
532 Rprint Vars ipmi_channel_ciphers
533
534 Example output:
535 ipmi_channel_ciphers:
536 [0]:
537 [id]: 3
538 [iana]: N/A
539 [auth_alg]: hmac_sha1
540 [integrity_alg]: hmac_sha1_96
541 [confidentiality_alg]: aes_cbc_128
542 [1]:
543 [id]: 17
544 [iana]: N/A
545 [auth_alg]: hmac_sha256
546 [integrity_alg]: sha256_128
547 [confidentiality_alg]: aes_cbc_128
548 """
549
550 cmd_buf = "channel getciphers ipmi | sed -re 's/ Alg/_Alg/g'"
551 stdout, stderr, rc = execute_ipmi_cmd(cmd_buf, "external", print_output=0)
552 return vf.outbuf_to_report(stdout)
Tony Lee9bca44b2019-12-13 09:34:26 +0800553
554
555def get_device_id_config():
556 r"""
557 Get the device id config data and return as a dictionary.
558
559 Example:
560
561 dev_id_config = get_device_id_config()
562 print_vars(dev_id_config)
563
564 dev_id_config:
565 [manuf_id]: 7244
566 [addn_dev_support]: 141
567 [prod_id]: 16976
568 [aux]: 0
569 [id]: 32
570 [revision]: 129
571 [device_revision]: 1
572 """
Patrick Williams20f38712022-12-08 06:18:26 -0600573 stdout, stderr, rc = bsu.bmc_execute_command(
574 "cat /usr/share/ipmi-providers/dev_id.json"
575 )
Tony Lee9bca44b2019-12-13 09:34:26 +0800576
577 result = json.loads(stdout)
578
579 # Create device revision field for the user.
580 # Reference IPMI specification v2.0 "Get Device ID Command"
581 # [7] 1 = device provides Device SDRs
582 # 0 = device does not provide Device SDRs
583 # [6:4] reserved. Return as 0.
584 # [3:0] Device Revision, binary encoded.
585
Patrick Williams20f38712022-12-08 06:18:26 -0600586 result["device_revision"] = result["revision"] & 0x0F
Tony Lee9bca44b2019-12-13 09:34:26 +0800587
588 return result
Rahul Maheshwari02ea62c2020-02-21 05:06:13 -0600589
590
591def get_chassis_status():
592 r"""
593 Get IPMI chassis status data and return it as a dictionary.
594
595 The data is obtained by issuing the IPMI "chassis status" command. An
596 example is shown below:
597
598 System Power : off
599 Power Overload : false
600 Power Interlock : inactive
601 Main Power Fault : false
602 Power Control Fault : false
603 Power Restore Policy : previous
604 Last Power Event :
605 Chassis Intrusion : inactive
606 Front-Panel Lockout : inactive
607 Drive Fault : false
608 Cooling/Fan Fault : false
609 Sleep Button Disable : not allowed
610 Diag Button Disable : not allowed
611 Reset Button Disable : not allowed
612 Power Button Disable : allowed
613 Sleep Button Disabled : false
614 Diag Button Disabled : false
615 Reset Button Disabled : false
616 Power Button Disabled : false
617
618 For the data shown above, the following dictionary will be returned.
619
620 chassis_status:
621 [system_power]: off
622 [power_overload]: false
623 [power_interlock]: inactive
624 [main_power_fault]: false
625 [power_control_fault]: false
626 [power_restore_policy]: previous
627 [last_power_event]:
628 [chassis_intrusion]: inactive
629 [front-panel_lockout]: inactive
630 [drive_fault]: false
631 [cooling/fan_fault]: false
632 [sleep_button_disable]: not allowed
633 [diag_button_disable]: not allowed
634 [reset_button_disable]: not allowed
635 [power_button_disable]: allowed
636 [sleep_button_disabled]: false
637 [diag_button_disabled]: false
638 [reset_button_disabled]: false
639 [power_button_disabled]: false
640 """
641
Patrick Williams20f38712022-12-08 06:18:26 -0600642 status, ret_values = grk.run_key_u(
643 "Run IPMI Standard Command chassis status"
644 )
Rahul Maheshwari02ea62c2020-02-21 05:06:13 -0600645 result = vf.key_value_outbuf_to_dict(ret_values, process_indent=1)
646
647 return result
Tony Lee18c6f9a2020-02-18 17:00:20 +0800648
649
650def get_channel_info(channel_number=1):
651 r"""
652 Get the channel info and return as a dictionary.
653 Example:
654
655 channel_info:
656 [channel_0x2_info]:
657 [channel_medium_type]: 802.3 LAN
658 [channel_protocol_type]: IPMB-1.0
659 [session_support]: multi-session
660 [active_session_count]: 0
661 [protocol_vendor_id]: 7154
Tony Lee87c9cb92020-03-04 14:47:09 +0800662 [volatile(active)_settings]:
Tony Lee18c6f9a2020-02-18 17:00:20 +0800663 [alerting]: enabled
664 [per-message_auth]: enabled
665 [user_level_auth]: enabled
666 [access_mode]: always available
Tony Lee87c9cb92020-03-04 14:47:09 +0800667 [non-volatile_settings]:
Tony Lee18c6f9a2020-02-18 17:00:20 +0800668 [alerting]: enabled
669 [per-message_auth]: enabled
670 [user_level_auth]: enabled
671 [access_mode]: always available
672 """
673
Patrick Williams20f38712022-12-08 06:18:26 -0600674 status, ret_values = grk.run_key_u(
675 "Run IPMI Standard Command channel info " + str(channel_number)
676 )
Tony Lee87c9cb92020-03-04 14:47:09 +0800677 key_var_list = list(filter(None, ret_values.split("\n")))
678 # To match the dict format, add a colon after 'Volatile(active) Settings' and 'Non-Volatile Settings'
679 # respectively.
Patrick Williams20f38712022-12-08 06:18:26 -0600680 key_var_list[6] = "Volatile(active) Settings:"
681 key_var_list[11] = "Non-Volatile Settings:"
Tony Lee87c9cb92020-03-04 14:47:09 +0800682 result = vf.key_value_list_to_dict(key_var_list, process_indent=1)
Tony Lee18c6f9a2020-02-18 17:00:20 +0800683 return result
Tony Lee3d351ee2020-02-19 10:21:04 +0800684
685
686def get_user_access_ipmi(channel_number=1):
Tony Lee3d351ee2020-02-19 10:21:04 +0800687 r"""
688 Run 'user list [<channel number>]' command and return the result as a list of dictionaries.
689
690 Example robot code:
691 ${users_access}= user list 1
692 Rprint Vars users_access
693
694 Example output:
695 users:
696 [0]:
697 [id]: 1
698 [name]: root
699 [callin]: false
700 [link]: true
701 [auth]: true
702 [ipmi]: ADMINISTRATOR
703 [1]:
704 [id]: 2
705 [name]: axzIDwnz
706 [callin]: true
707 [link]: false
708 [auth]: true
709 [ipmi]: ADMINISTRATOR
710 """
711
712 cmd_buf = "user list " + str(channel_number)
713 stdout, stderr, rc = execute_ipmi_cmd(cmd_buf, "external", print_output=0)
714 return vf.outbuf_to_report(stdout)
Tony Lee0754c5f2020-03-13 19:38:24 +0800715
716
nagarjunb2298450742022-04-19 12:00:02 +0530717def get_channel_auth_capabilities(channel_number=1, privilege_level=4):
Tony Lee0754c5f2020-03-13 19:38:24 +0800718 r"""
719 Get the channel authentication capabilities and return as a dictionary.
720
721 Example:
722
723 channel_auth_cap:
724 [channel_number]: 2
725 [ipmi_v1.5__auth_types]:
726 [kg_status]: default (all zeroes)
727 [per_message_authentication]: enabled
728 [user_level_authentication]: enabled
729 [non-null_user_names_exist]: yes
730 [null_user_names_exist]: no
731 [anonymous_login_enabled]: no
732 [channel_supports_ipmi_v1.5]: no
733 [channel_supports_ipmi_v2.0]: yes
734 """
735
Patrick Williams20f38712022-12-08 06:18:26 -0600736 status, ret_values = grk.run_key_u(
737 "Run IPMI Standard Command channel authcap "
738 + str(channel_number)
739 + " "
740 + str(privilege_level)
741 )
Tony Lee0754c5f2020-03-13 19:38:24 +0800742 result = vf.key_value_outbuf_to_dict(ret_values, process_indent=1)
743
744 return result
chithrag0a8c8782022-03-01 12:35:00 +0000745
746
747def fetch_date(date):
748 r"""
749 Removes prefix 0 in a date in given date
750
751 Example : 08/12/2021 then returns 8/12/2021
752 """
753
754 date = date.lstrip("0")
755 return date
756
757
758def fetch_added_sel_date(entry):
759 r"""
760 Split sel entry string with with | and join only the date with space
761
762 Example : If entry given is, "a | 02/14/2020 | 01:16:58 | Sensor_type #0x17 | | Asserted"
763 Then the result will be "02/14/2020 01:16:58"
764 """
765
766 temp = entry.split(" | ")
767 date = temp[1] + " " + temp[2]
768 print(date)
769 return date
770
771
772def prefix_bytes(listx):
773 r"""
774 prefixes byte strings in list
775
776 Example:
777 ${listx} = ['01', '02', '03']
778 ${listx}= Prefix Bytes ${listx}
779 then,
780 ${listx}= ['0x01', '0x02', '0x03']
781
782 """
783
784 listy = []
785 for item in listx:
786 item = "0x" + item
787 listy.append(item)
788 return listy
chithragff43db92022-03-01 13:13:48 +0000789
790
chithrag6b279b32022-05-05 08:28:05 +0000791def modify_and_fetch_threshold(old_threshold, threshold_list):
chithragff43db92022-03-01 13:13:48 +0000792 r"""
chithragff43db92022-03-01 13:13:48 +0000793 Description of argument(s):
794
chithrag6b279b32022-05-05 08:28:05 +0000795 old_threshold List of threshold values of sensor,
chithragff43db92022-03-01 13:13:48 +0000796 threshold_list List of higher and lower of critical and non-critical values.
chithrag6b279b32022-05-05 08:28:05 +0000797 i,e [ "lcr", "lnc", "unc", "ucr" ]
798
799 Gets old threshold values from sensor and threshold levels,
800 then returns the list of new threshold and the dict of threshold levels
chithragff43db92022-03-01 13:13:48 +0000801
802 For example :
chithrag6b279b32022-05-05 08:28:05 +0000803 1. If old_threshold list is [ 1, 2, 3, 4] then the newthreshold_list will be [ 101, 102, 103, 104 ].
804 If old_threshold has 'na' the same will be appended to new list, eg: [ 101, 102, 103, 104, 'na'].
chithragff43db92022-03-01 13:13:48 +0000805
chithrag6b279b32022-05-05 08:28:05 +0000806 2. The newthreshold_list will be zipped to dictionary with threshold_list levels,
807 Example : threshold_dict = { 'lcr': 101, 'lnc': 102, 'unc': 103, 'ucr': 104 }
808
chithragff43db92022-03-01 13:13:48 +0000809 """
810
chithrag6b279b32022-05-05 08:28:05 +0000811 # Adding the difference of 100 as less than this value,
812 # may not have greater impact as the sensor considered is a fan sensor.
813 # The set threshold may round off for certain values below 100.
chithragff43db92022-03-01 13:13:48 +0000814 n = 100
815 newthreshold_list = []
816 for th in old_threshold:
817 th = th.strip()
Patrick Williams20f38712022-12-08 06:18:26 -0600818 if th == "na":
819 newthreshold_list.append("na")
chithragff43db92022-03-01 13:13:48 +0000820 else:
821 x = int(float(th)) + n
822 newthreshold_list.append(x)
823 n = n + 100
824 threshold_dict = dict(zip(threshold_list, newthreshold_list))
825 return newthreshold_list, threshold_dict