blob: 34fd701e4398bbc0056d75a47bfa7e384a58470a [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
manimozhikdd321652023-11-08 10:22:06 +0000356def fetch_sdr_count(sdr_data):
357 r"""
358 Get IPMI SDR list and return the SDR OEM count.
359
360 The data is obtained by issuing the IPMI "sdr elist -vvv" command. An
361 example is shown below:
362
363 SDR record ID : 0x00cb
364 SDR record ID : 0x00cc
365 SDR record type : 0xc0
366 SDR record next : 0xffff
367 SDR record bytes: 11
368 Getting 11 bytes from SDR at offset 5
369
370 For the data shown above, the SDR record type with 0xc0 count will be returned.
371 """
372
373 data = sdr_data.split("\n")
374 sdr_list = []
375 for i, j in enumerate(data):
376 a = j.split(":")
377 if a[0].strip() == "SDR record type":
378 sdr_list.append(a[1].strip())
379 return sdr_list.count("0xc0")
380
381
George Keishing3511a3f2018-04-19 10:38:30 -0500382def get_aux_version(version_id):
383 r"""
384 Get IPMI Aux version info data and return it.
385
386 Description of argument(s):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500387 version_id The data is obtained by from BMC
388 /etc/os-release
389 (e.g. "xxx-v2.1-438-g0030304-r3-gfea8585").
George Keishing3511a3f2018-04-19 10:38:30 -0500390
391 In the prior example, the 3rd field is "438" is the commit version and
392 the 5th field is "r3" and value "3" is the release version.
393
394 Aux version return from this function 4380003.
395 """
396
397 # Commit version.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500398 count = re.findall("-(\\d{1,4})-", version_id)
George Keishing3511a3f2018-04-19 10:38:30 -0500399
400 # Release version.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500401 release = re.findall("-r(\\d{1,4})", version_id)
George Keishing3511a3f2018-04-19 10:38:30 -0500402 if release:
403 aux_version = count[0] + "{0:0>4}".format(release[0])
404 else:
405 aux_version = count[0] + "0000"
406
407 return aux_version
Michael Walsh27b14a62018-05-24 11:05:07 -0500408
409
410def get_fru_info():
411 r"""
412 Get fru info and return it as a list of dictionaries.
413
414 The data is obtained by issuing the IPMI "fru print -N 50" command. An
415 example is shown below:
416
417 FRU Device Description : Builtin FRU Device (ID 0)
418 Device not present (Unspecified error)
419
420 FRU Device Description : cpu0 (ID 1)
421 Board Mfg Date : Sun Dec 31 18:00:00 1995
George Keishinge0a81282018-06-08 10:02:30 -0500422 Board Mfg : <Manufacturer Name>
Michael Walsh27b14a62018-05-24 11:05:07 -0500423 Board Product : PROCESSOR MODULE
424 Board Serial : YA1934315964
425 Board Part Number : 02CY209
426
427 FRU Device Description : cpu1 (ID 2)
428 Board Mfg Date : Sun Dec 31 18:00:00 1995
George Keishinge0a81282018-06-08 10:02:30 -0500429 Board Mfg : <Manufacturer Name>
Michael Walsh27b14a62018-05-24 11:05:07 -0500430 Board Product : PROCESSOR MODULE
431 Board Serial : YA1934315965
432 Board Part Number : 02CY209
433
434 For the data shown above, the following list of dictionaries will be
435 returned.
436
437 fru_obj:
438 fru_obj[0]:
439 [fru_device_description]: Builtin FRU Device (ID 0)
440 [state]: Device not present (Unspecified error)
441 fru_obj[1]:
442 [fru_device_description]: cpu0 (ID 1)
443 [board_mfg_date]: Sun Dec 31 18:00:00 1995
George Keishinge0a81282018-06-08 10:02:30 -0500444 [board_mfg]: <Manufacturer Name>
Michael Walsh27b14a62018-05-24 11:05:07 -0500445 [board_product]: PROCESSOR MODULE
446 [board_serial]: YA1934315964
447 [board_part_number]: 02CY209
448 fru_obj[2]:
449 [fru_device_description]: cpu1 (ID 2)
450 [board_mfg_date]: Sun Dec 31 18:00:00 1995
George Keishinge0a81282018-06-08 10:02:30 -0500451 [board_mfg]: <Manufacturer Name>
Michael Walsh27b14a62018-05-24 11:05:07 -0500452 [board_product]: PROCESSOR MODULE
453 [board_serial]: YA1934315965
454 [board_part_number]: 02CY209
455 """
456
Patrick Williams20f38712022-12-08 06:18:26 -0600457 status, ret_values = grk.run_key_u(
458 "Run IPMI Standard Command fru print -N 50"
459 )
Michael Walsh27b14a62018-05-24 11:05:07 -0500460
461 # Manipulate the "Device not present" line to create a "state" key.
Patrick Williams20f38712022-12-08 06:18:26 -0600462 ret_values = re.sub(
463 "Device not present", "state : Device not present", ret_values
464 )
Michael Walsh27b14a62018-05-24 11:05:07 -0500465
Patrick Williams20f38712022-12-08 06:18:26 -0600466 return [
467 vf.key_value_outbuf_to_dict(x) for x in re.split("\n\n", ret_values)
468 ]
Michael Walsh61224e62018-05-30 17:58:42 -0500469
470
Patrick Williams20f38712022-12-08 06:18:26 -0600471def get_component_fru_info(component="cpu", fru_objs=None):
Michael Walsh61224e62018-05-30 17:58:42 -0500472 r"""
473 Get fru info for the given component and return it as a list of
474 dictionaries.
475
476 This function calls upon get_fru_info and then filters out the unwanted
477 entries. See get_fru_info's prolog for a layout of the data.
478
479 Description of argument(s):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500480 component The component (e.g. "cpu", "dimm", etc.).
481 fru_objs A fru_objs list such as the one returned
482 by get_fru_info. If this is None, then
483 this function will call get_fru_info to
484 obtain such a list.
485 Supplying this argument may improve
486 performance if this function is to be
487 called multiple times.
Michael Walsh61224e62018-05-30 17:58:42 -0500488 """
489
Michael Walsha95e4ef2018-06-06 17:53:04 -0500490 if fru_objs is None:
491 fru_objs = get_fru_info()
Patrick Williams20f38712022-12-08 06:18:26 -0600492 return [
493 x
494 for x in fru_objs
495 if re.match(component + "([0-9]+)? ", x["fru_device_description"])
496 ]
Rahul Maheshwari24e0e792019-02-12 22:40:23 -0600497
498
499def get_user_info(userid, channel_number=1):
500 r"""
501 Get user info using channel command and return it as a dictionary.
502
503 Description of argument(s):
504 userid The userid (e.g. "1", "2", etc.).
505 channel_number The user's channel number (e.g. "1").
506
Michael Walshe733b262019-12-09 11:45:24 -0600507 Note: If userid is blank, this function will return a list of dictionaries. Each list entry represents
508 one userid record.
509
Rahul Maheshwari24e0e792019-02-12 22:40:23 -0600510 The data is obtained by issuing the IPMI "channel getaccess" command. An
511 example is shown below for user id 1 and channel number 1.
512
513 Maximum User IDs : 15
514 Enabled User IDs : 1
515 User ID : 1
516 User Name : root
517 Fixed Name : No
518 Access Available : callback
519 Link Authentication : enabled
520 IPMI Messaging : enabled
521 Privilege Level : ADMINISTRATOR
522 Enable Status : enabled
523
524 For the data shown above, the following dictionary will be returned.
525
526 user_info:
527 [maximum_userids]: 15
528 [enabled_userids: 1
529 [userid] 1
530 [user_name] root
531 [fixed_name] No
532 [access_available] callback
533 [link_authentication] enabled
534 [ipmi_messaging] enabled
535 [privilege_level] ADMINISTRATOR
536 [enable_status] enabled
Rahul Maheshwari24e0e792019-02-12 22:40:23 -0600537 """
538
Patrick Williams20f38712022-12-08 06:18:26 -0600539 status, ret_values = grk.run_key_u(
540 "Run IPMI Standard Command channel getaccess "
541 + str(channel_number)
542 + " "
543 + str(userid)
544 )
Rahul Maheshwari24e0e792019-02-12 22:40:23 -0600545
Michael Walshe733b262019-12-09 11:45:24 -0600546 if userid == "":
547 return vf.key_value_outbuf_to_dicts(ret_values, process_indent=1)
548 else:
549 return vf.key_value_outbuf_to_dict(ret_values, process_indent=1)
George Keishing45511e82019-10-15 01:26:55 -0500550
551
552def channel_getciphers_ipmi():
George Keishing45511e82019-10-15 01:26:55 -0500553 r"""
554 Run 'channel getciphers ipmi' command and return the result as a list of dictionaries.
555
556 Example robot code:
557 ${ipmi_channel_ciphers}= Channel Getciphers IPMI
558 Rprint Vars ipmi_channel_ciphers
559
560 Example output:
561 ipmi_channel_ciphers:
562 [0]:
563 [id]: 3
564 [iana]: N/A
565 [auth_alg]: hmac_sha1
566 [integrity_alg]: hmac_sha1_96
567 [confidentiality_alg]: aes_cbc_128
568 [1]:
569 [id]: 17
570 [iana]: N/A
571 [auth_alg]: hmac_sha256
572 [integrity_alg]: sha256_128
573 [confidentiality_alg]: aes_cbc_128
574 """
575
576 cmd_buf = "channel getciphers ipmi | sed -re 's/ Alg/_Alg/g'"
577 stdout, stderr, rc = execute_ipmi_cmd(cmd_buf, "external", print_output=0)
578 return vf.outbuf_to_report(stdout)
Tony Lee9bca44b2019-12-13 09:34:26 +0800579
580
581def get_device_id_config():
582 r"""
583 Get the device id config data and return as a dictionary.
584
585 Example:
586
587 dev_id_config = get_device_id_config()
588 print_vars(dev_id_config)
589
590 dev_id_config:
591 [manuf_id]: 7244
592 [addn_dev_support]: 141
593 [prod_id]: 16976
594 [aux]: 0
595 [id]: 32
596 [revision]: 129
597 [device_revision]: 1
598 """
Patrick Williams20f38712022-12-08 06:18:26 -0600599 stdout, stderr, rc = bsu.bmc_execute_command(
600 "cat /usr/share/ipmi-providers/dev_id.json"
601 )
Tony Lee9bca44b2019-12-13 09:34:26 +0800602
603 result = json.loads(stdout)
604
605 # Create device revision field for the user.
606 # Reference IPMI specification v2.0 "Get Device ID Command"
607 # [7] 1 = device provides Device SDRs
608 # 0 = device does not provide Device SDRs
609 # [6:4] reserved. Return as 0.
610 # [3:0] Device Revision, binary encoded.
611
Patrick Williams20f38712022-12-08 06:18:26 -0600612 result["device_revision"] = result["revision"] & 0x0F
Tony Lee9bca44b2019-12-13 09:34:26 +0800613
614 return result
Rahul Maheshwari02ea62c2020-02-21 05:06:13 -0600615
616
617def get_chassis_status():
618 r"""
619 Get IPMI chassis status data and return it as a dictionary.
620
621 The data is obtained by issuing the IPMI "chassis status" command. An
622 example is shown below:
623
624 System Power : off
625 Power Overload : false
626 Power Interlock : inactive
627 Main Power Fault : false
628 Power Control Fault : false
629 Power Restore Policy : previous
630 Last Power Event :
631 Chassis Intrusion : inactive
632 Front-Panel Lockout : inactive
633 Drive Fault : false
634 Cooling/Fan Fault : false
635 Sleep Button Disable : not allowed
636 Diag Button Disable : not allowed
637 Reset Button Disable : not allowed
638 Power Button Disable : allowed
639 Sleep Button Disabled : false
640 Diag Button Disabled : false
641 Reset Button Disabled : false
642 Power Button Disabled : false
643
644 For the data shown above, the following dictionary will be returned.
645
646 chassis_status:
647 [system_power]: off
648 [power_overload]: false
649 [power_interlock]: inactive
650 [main_power_fault]: false
651 [power_control_fault]: false
652 [power_restore_policy]: previous
653 [last_power_event]:
654 [chassis_intrusion]: inactive
655 [front-panel_lockout]: inactive
656 [drive_fault]: false
657 [cooling/fan_fault]: false
658 [sleep_button_disable]: not allowed
659 [diag_button_disable]: not allowed
660 [reset_button_disable]: not allowed
661 [power_button_disable]: allowed
662 [sleep_button_disabled]: false
663 [diag_button_disabled]: false
664 [reset_button_disabled]: false
665 [power_button_disabled]: false
666 """
667
Patrick Williams20f38712022-12-08 06:18:26 -0600668 status, ret_values = grk.run_key_u(
669 "Run IPMI Standard Command chassis status"
670 )
Rahul Maheshwari02ea62c2020-02-21 05:06:13 -0600671 result = vf.key_value_outbuf_to_dict(ret_values, process_indent=1)
672
673 return result
Tony Lee18c6f9a2020-02-18 17:00:20 +0800674
675
676def get_channel_info(channel_number=1):
677 r"""
678 Get the channel info and return as a dictionary.
679 Example:
680
681 channel_info:
682 [channel_0x2_info]:
683 [channel_medium_type]: 802.3 LAN
684 [channel_protocol_type]: IPMB-1.0
685 [session_support]: multi-session
686 [active_session_count]: 0
687 [protocol_vendor_id]: 7154
Tony Lee87c9cb92020-03-04 14:47:09 +0800688 [volatile(active)_settings]:
Tony Lee18c6f9a2020-02-18 17:00:20 +0800689 [alerting]: enabled
690 [per-message_auth]: enabled
691 [user_level_auth]: enabled
692 [access_mode]: always available
Tony Lee87c9cb92020-03-04 14:47:09 +0800693 [non-volatile_settings]:
Tony Lee18c6f9a2020-02-18 17:00:20 +0800694 [alerting]: enabled
695 [per-message_auth]: enabled
696 [user_level_auth]: enabled
697 [access_mode]: always available
698 """
699
Patrick Williams20f38712022-12-08 06:18:26 -0600700 status, ret_values = grk.run_key_u(
701 "Run IPMI Standard Command channel info " + str(channel_number)
702 )
Tony Lee87c9cb92020-03-04 14:47:09 +0800703 key_var_list = list(filter(None, ret_values.split("\n")))
704 # To match the dict format, add a colon after 'Volatile(active) Settings' and 'Non-Volatile Settings'
705 # respectively.
Patrick Williams20f38712022-12-08 06:18:26 -0600706 key_var_list[6] = "Volatile(active) Settings:"
707 key_var_list[11] = "Non-Volatile Settings:"
Tony Lee87c9cb92020-03-04 14:47:09 +0800708 result = vf.key_value_list_to_dict(key_var_list, process_indent=1)
Tony Lee18c6f9a2020-02-18 17:00:20 +0800709 return result
Tony Lee3d351ee2020-02-19 10:21:04 +0800710
711
712def get_user_access_ipmi(channel_number=1):
Tony Lee3d351ee2020-02-19 10:21:04 +0800713 r"""
714 Run 'user list [<channel number>]' command and return the result as a list of dictionaries.
715
716 Example robot code:
717 ${users_access}= user list 1
718 Rprint Vars users_access
719
720 Example output:
721 users:
722 [0]:
723 [id]: 1
724 [name]: root
725 [callin]: false
726 [link]: true
727 [auth]: true
728 [ipmi]: ADMINISTRATOR
729 [1]:
730 [id]: 2
731 [name]: axzIDwnz
732 [callin]: true
733 [link]: false
734 [auth]: true
735 [ipmi]: ADMINISTRATOR
736 """
737
738 cmd_buf = "user list " + str(channel_number)
739 stdout, stderr, rc = execute_ipmi_cmd(cmd_buf, "external", print_output=0)
740 return vf.outbuf_to_report(stdout)
Tony Lee0754c5f2020-03-13 19:38:24 +0800741
742
nagarjunb2298450742022-04-19 12:00:02 +0530743def get_channel_auth_capabilities(channel_number=1, privilege_level=4):
Tony Lee0754c5f2020-03-13 19:38:24 +0800744 r"""
745 Get the channel authentication capabilities and return as a dictionary.
746
747 Example:
748
749 channel_auth_cap:
750 [channel_number]: 2
751 [ipmi_v1.5__auth_types]:
752 [kg_status]: default (all zeroes)
753 [per_message_authentication]: enabled
754 [user_level_authentication]: enabled
755 [non-null_user_names_exist]: yes
756 [null_user_names_exist]: no
757 [anonymous_login_enabled]: no
758 [channel_supports_ipmi_v1.5]: no
759 [channel_supports_ipmi_v2.0]: yes
760 """
761
Patrick Williams20f38712022-12-08 06:18:26 -0600762 status, ret_values = grk.run_key_u(
763 "Run IPMI Standard Command channel authcap "
764 + str(channel_number)
765 + " "
766 + str(privilege_level)
767 )
Tony Lee0754c5f2020-03-13 19:38:24 +0800768 result = vf.key_value_outbuf_to_dict(ret_values, process_indent=1)
769
770 return result
chithrag0a8c8782022-03-01 12:35:00 +0000771
772
773def fetch_date(date):
774 r"""
775 Removes prefix 0 in a date in given date
776
777 Example : 08/12/2021 then returns 8/12/2021
778 """
779
780 date = date.lstrip("0")
781 return date
782
783
784def fetch_added_sel_date(entry):
785 r"""
786 Split sel entry string with with | and join only the date with space
787
788 Example : If entry given is, "a | 02/14/2020 | 01:16:58 | Sensor_type #0x17 | | Asserted"
789 Then the result will be "02/14/2020 01:16:58"
790 """
791
792 temp = entry.split(" | ")
793 date = temp[1] + " " + temp[2]
794 print(date)
795 return date
796
797
798def prefix_bytes(listx):
799 r"""
800 prefixes byte strings in list
801
802 Example:
803 ${listx} = ['01', '02', '03']
804 ${listx}= Prefix Bytes ${listx}
805 then,
806 ${listx}= ['0x01', '0x02', '0x03']
807
808 """
809
810 listy = []
811 for item in listx:
812 item = "0x" + item
813 listy.append(item)
814 return listy
chithragff43db92022-03-01 13:13:48 +0000815
816
chithrag6b279b32022-05-05 08:28:05 +0000817def modify_and_fetch_threshold(old_threshold, threshold_list):
chithragff43db92022-03-01 13:13:48 +0000818 r"""
chithragff43db92022-03-01 13:13:48 +0000819 Description of argument(s):
820
chithrag6b279b32022-05-05 08:28:05 +0000821 old_threshold List of threshold values of sensor,
chithragff43db92022-03-01 13:13:48 +0000822 threshold_list List of higher and lower of critical and non-critical values.
chithrag6b279b32022-05-05 08:28:05 +0000823 i,e [ "lcr", "lnc", "unc", "ucr" ]
824
825 Gets old threshold values from sensor and threshold levels,
826 then returns the list of new threshold and the dict of threshold levels
chithragff43db92022-03-01 13:13:48 +0000827
828 For example :
chithrag6b279b32022-05-05 08:28:05 +0000829 1. If old_threshold list is [ 1, 2, 3, 4] then the newthreshold_list will be [ 101, 102, 103, 104 ].
830 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 +0000831
chithrag6b279b32022-05-05 08:28:05 +0000832 2. The newthreshold_list will be zipped to dictionary with threshold_list levels,
833 Example : threshold_dict = { 'lcr': 101, 'lnc': 102, 'unc': 103, 'ucr': 104 }
834
chithragff43db92022-03-01 13:13:48 +0000835 """
836
chithrag6b279b32022-05-05 08:28:05 +0000837 # Adding the difference of 100 as less than this value,
838 # may not have greater impact as the sensor considered is a fan sensor.
839 # The set threshold may round off for certain values below 100.
chithragff43db92022-03-01 13:13:48 +0000840 n = 100
841 newthreshold_list = []
842 for th in old_threshold:
843 th = th.strip()
Patrick Williams20f38712022-12-08 06:18:26 -0600844 if th == "na":
845 newthreshold_list.append("na")
chithragff43db92022-03-01 13:13:48 +0000846 else:
847 x = int(float(th)) + n
848 newthreshold_list.append(x)
849 n = n + 100
850 threshold_dict = dict(zip(threshold_list, newthreshold_list))
851 return newthreshold_list, threshold_dict