blob: af0e5a3e054ec550aa37ef46f6469c6d4f75b73a [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
Michael Walshf4098fb2018-02-28 10:54:46 -06007import re
Michael Walsh4481b932018-02-08 11:45:15 -06008import gen_print as gp
Michael Walshed5b46e2017-05-24 11:49:14 -05009import gen_misc as gm
Michael Walsh94811f62018-09-05 14:55:12 -050010import gen_cmd as gc
Michael Walshed5b46e2017-05-24 11:49:14 -050011import gen_robot_keyword as grk
12import gen_robot_utils as gru
Michael Walsh4481b932018-02-08 11:45:15 -060013import bmc_ssh_utils as bsu
14import var_funcs as vf
Michael Walsh19e70c82019-01-23 11:07:15 -060015import ipmi_client as ic
Michael Walshed5b46e2017-05-24 11:49:14 -050016import tempfile
17gru.my_import_resource("ipmi_client.robot")
Michael Walsh4481b932018-02-08 11:45:15 -060018from robot.libraries.BuiltIn import BuiltIn
Tony Lee9bca44b2019-12-13 09:34:26 +080019import json
Michael Walshed5b46e2017-05-24 11:49:14 -050020
21
Michael Walshed5b46e2017-05-24 11:49:14 -050022def get_sol_info():
Michael Walshed5b46e2017-05-24 11:49:14 -050023 r"""
24 Get all SOL info and return it as a dictionary.
25
26 Example use:
27
28 Robot code:
29 ${sol_info}= get_sol_info
30 Rpvars sol_info
31
32 Output:
33 sol_info:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -050034 sol_info[Info]: SOL parameter 'Payload Channel (7)'
35 not supported - defaulting to 0x0e
Michael Walshed5b46e2017-05-24 11:49:14 -050036 sol_info[Character Send Threshold]: 1
37 sol_info[Force Authentication]: true
38 sol_info[Privilege Level]: USER
39 sol_info[Set in progress]: set-complete
40 sol_info[Retry Interval (ms)]: 100
41 sol_info[Non-Volatile Bit Rate (kbps)]: IPMI-Over-Serial-Setting
42 sol_info[Character Accumulate Level (ms)]: 100
43 sol_info[Enabled]: true
44 sol_info[Volatile Bit Rate (kbps)]: IPMI-Over-Serial-Setting
45 sol_info[Payload Channel]: 14 (0x0e)
46 sol_info[Payload Port]: 623
47 sol_info[Force Encryption]: true
48 sol_info[Retry Count]: 7
49 """
50
51 status, ret_values = grk.run_key_u("Run IPMI Standard Command sol info")
52
53 # Create temp file path.
54 temp = tempfile.NamedTemporaryFile()
55 temp_file_path = temp.name
56
57 # Write sol info to temp file path.
58 text_file = open(temp_file_path, "w")
59 text_file.write(ret_values)
60 text_file.close()
61
62 # Use my_parm_file to interpret data.
63 sol_info = gm.my_parm_file(temp_file_path)
64
65 return sol_info
66
Rahul Maheshwarid629b5c2017-05-23 08:06:28 -050067
Rahul Maheshwarid629b5c2017-05-23 08:06:28 -050068def set_sol_setting(setting_name, setting_value):
Rahul Maheshwarid629b5c2017-05-23 08:06:28 -050069 r"""
70 Set SOL setting with given value.
71
72 # Description of argument(s):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -050073 # setting_name SOL setting which needs to be set (e.g.
74 # "retry-count").
75 # setting_value Value which needs to be set (e.g. "7").
Rahul Maheshwarid629b5c2017-05-23 08:06:28 -050076 """
77
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -050078 status, ret_values = grk.run_key_u("Run IPMI Standard Command sol set "
79 + setting_name + " " + setting_value)
Rahul Maheshwarid629b5c2017-05-23 08:06:28 -050080
81 return status
82
Rahul Maheshwarid629b5c2017-05-23 08:06:28 -050083
Michael Walsh94811f62018-09-05 14:55:12 -050084def execute_ipmi_cmd(cmd_string,
85 ipmi_cmd_type='inband',
86 print_output=1,
Michael Walsh19e70c82019-01-23 11:07:15 -060087 ignore_err=0,
88 **options):
Michael Walsh94811f62018-09-05 14:55:12 -050089 r"""
90 Run the given command string as an IPMI command and return the stdout,
91 stderr and the return code.
92
93 Description of argument(s):
94 cmd_string The command string to be run as an IPMI
95 command.
96 ipmi_cmd_type 'inband' or 'external'.
97 print_output If this is set, this function will print
98 the stdout/stderr generated by
99 the IPMI command.
100 ignore_err Ignore error means that a failure
101 encountered by running the command
102 string will not be raised as a python
103 exception.
Michael Walsh19e70c82019-01-23 11:07:15 -0600104 options These are passed directly to the
105 create_ipmi_ext_command_string function.
106 See that function's prolog for details.
Michael Walsh94811f62018-09-05 14:55:12 -0500107 """
108
109 if ipmi_cmd_type == 'inband':
110 IPMI_INBAND_CMD = BuiltIn().get_variable_value("${IPMI_INBAND_CMD}")
111 cmd_buf = IPMI_INBAND_CMD + " " + cmd_string
112 return bsu.os_execute_command(cmd_buf,
113 print_out=print_output,
114 ignore_err=ignore_err)
115
116 if ipmi_cmd_type == 'external':
Michael Walsh19e70c82019-01-23 11:07:15 -0600117 cmd_buf = ic.create_ipmi_ext_command_string(cmd_string, **options)
Michael Walsh94811f62018-09-05 14:55:12 -0500118 rc, stdout, stderr = gc.shell_cmd(cmd_buf,
119 print_output=print_output,
120 ignore_err=ignore_err,
121 return_stderr=1)
122 return stdout, stderr, rc
123
124
Tony Leeea741302019-11-08 11:01:58 +0800125def get_lan_print_dict(channel_number='', ipmi_cmd_type='external'):
Michael Walsh4481b932018-02-08 11:45:15 -0600126 r"""
127 Get IPMI 'lan print' output and return it as a dictionary.
128
129 Here is an example of the IPMI lan print output:
130
131 Set in Progress : Set Complete
132 Auth Type Support : MD5
133 Auth Type Enable : Callback : MD5
134 : User : MD5
135 : Operator : MD5
136 : Admin : MD5
137 : OEM : MD5
138 IP Address Source : Static Address
139 IP Address : x.x.x.x
140 Subnet Mask : x.x.x.x
141 MAC Address : xx:xx:xx:xx:xx:xx
142 Default Gateway IP : x.x.x.x
143 802.1q VLAN ID : Disabled
144 Cipher Suite Priv Max : Not Available
145 Bad Password Threshold : Not Available
146
147 Given that data, this function will return the following dictionary.
148
149 lan_print_dict:
150 [Set in Progress]: Set Complete
151 [Auth Type Support]: MD5
152 [Auth Type Enable]:
153 [Callback]: MD5
154 [User]: MD5
155 [Operator]: MD5
156 [Admin]: MD5
157 [OEM]: MD5
158 [IP Address Source]: Static Address
159 [IP Address]: x.x.x.x
160 [Subnet Mask]: x.x.x.x
161 [MAC Address]: xx:xx:xx:xx:xx:xx
162 [Default Gateway IP]: x.x.x.x
163 [802.1q VLAN ID]: Disabled
164 [Cipher Suite Priv Max]: Not Available
165 [Bad Password Threshold]: Not Available
166
Michael Walsh94811f62018-09-05 14:55:12 -0500167 Description of argument(s):
168 ipmi_cmd_type The type of ipmi command to use (e.g.
169 'inband', 'external').
Michael Walsh4481b932018-02-08 11:45:15 -0600170 """
171
Tony Leeea741302019-11-08 11:01:58 +0800172 channel_number = str(channel_number)
Michael Walsh4481b932018-02-08 11:45:15 -0600173 # Notice in the example of data above that 'Auth Type Enable' needs some
174 # special processing. We essentially want to isolate its data and remove
175 # the 'Auth Type Enable' string so that key_value_outbuf_to_dict can
176 # process it as a sub-dictionary.
Tony Leeea741302019-11-08 11:01:58 +0800177 cmd_buf = "lan print " + channel_number + " | grep -E '^(Auth Type Enable)" +\
Michael Walsh4481b932018-02-08 11:45:15 -0600178 "?[ ]+: ' | sed -re 's/^(Auth Type Enable)?[ ]+: //g'"
Michael Walsh94811f62018-09-05 14:55:12 -0500179 stdout1, stderr, rc = execute_ipmi_cmd(cmd_buf, ipmi_cmd_type,
180 print_output=0)
Michael Walsh4481b932018-02-08 11:45:15 -0600181
182 # Now get the remainder of the data and exclude the lines with no field
183 # names (i.e. the 'Auth Type Enable' sub-fields).
Tony Leeea741302019-11-08 11:01:58 +0800184 cmd_buf = "lan print " + channel_number + " | grep -E -v '^[ ]+: '"
Michael Walsh94811f62018-09-05 14:55:12 -0500185 stdout2, stderr, rc = execute_ipmi_cmd(cmd_buf, ipmi_cmd_type,
186 print_output=0)
Michael Walsh4481b932018-02-08 11:45:15 -0600187
188 # Make auth_type_enable_dict sub-dictionary...
189 auth_type_enable_dict = vf.key_value_outbuf_to_dict(stdout1, to_lower=0,
190 underscores=0)
191
192 # Create the lan_print_dict...
193 lan_print_dict = vf.key_value_outbuf_to_dict(stdout2, to_lower=0,
194 underscores=0)
195 # Re-assign 'Auth Type Enable' to contain the auth_type_enable_dict.
196 lan_print_dict['Auth Type Enable'] = auth_type_enable_dict
197
198 return lan_print_dict
Michael Walshd59ed7c2018-02-15 10:19:38 -0600199
200
Michael Walshf4098fb2018-02-28 10:54:46 -0600201def get_ipmi_power_reading(strip_watts=1):
Michael Walshd59ed7c2018-02-15 10:19:38 -0600202 r"""
203 Get IPMI power reading data and return it as a dictionary.
204
205 The data is obtained by issuing the IPMI "power reading" command. An
206 example is shown below:
207
208 Instantaneous power reading: 234 Watts
209 Minimum during sampling period: 234 Watts
210 Maximum during sampling period: 234 Watts
211 Average power reading over sample period: 234 Watts
212 IPMI timestamp: Thu Jan 1 00:00:00 1970
213 Sampling period: 00000000 Seconds.
214 Power reading state is: deactivated
215
216 For the data shown above, the following dictionary will be returned.
217
218 result:
219 [instantaneous_power_reading]: 238 Watts
220 [minimum_during_sampling_period]: 238 Watts
221 [maximum_during_sampling_period]: 238 Watts
222 [average_power_reading_over_sample_period]: 238 Watts
223 [ipmi_timestamp]: Thu Jan 1 00:00:00 1970
224 [sampling_period]: 00000000 Seconds.
225 [power_reading_state_is]: deactivated
Michael Walshf4098fb2018-02-28 10:54:46 -0600226
227 Description of argument(s):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500228 strip_watts Strip all dictionary values of the
229 trailing " Watts" substring.
Michael Walshd59ed7c2018-02-15 10:19:38 -0600230 """
231
232 status, ret_values = \
233 grk.run_key_u("Run IPMI Standard Command dcmi power reading")
234 result = vf.key_value_outbuf_to_dict(ret_values)
235
Michael Walshf4098fb2018-02-28 10:54:46 -0600236 if strip_watts:
237 result.update((k, re.sub(' Watts$', '', v)) for k, v in result.items())
238
Michael Walshd59ed7c2018-02-15 10:19:38 -0600239 return result
Michael Walshaf5607e2018-02-19 17:37:20 -0600240
241
242def get_mc_info():
Michael Walshaf5607e2018-02-19 17:37:20 -0600243 r"""
244 Get IPMI mc info data and return it as a dictionary.
245
246 The data is obtained by issuing the IPMI "mc info" command. An
247 example is shown below:
248
249 Device ID : 0
250 Device Revision : 0
251 Firmware Revision : 2.01
252 IPMI Version : 2.0
253 Manufacturer ID : 42817
254 Manufacturer Name : Unknown (0xA741)
255 Product ID : 16975 (0x424f)
256 Product Name : Unknown (0x424F)
257 Device Available : yes
258 Provides Device SDRs : yes
259 Additional Device Support :
260 Sensor Device
261 SEL Device
262 FRU Inventory Device
263 Chassis Device
264 Aux Firmware Rev Info :
265 0x00
266 0x00
267 0x00
268 0x00
269
270 For the data shown above, the following dictionary will be returned.
271 mc_info:
272 [device_id]: 0
273 [device_revision]: 0
274 [firmware_revision]: 2.01
275 [ipmi_version]: 2.0
276 [manufacturer_id]: 42817
277 [manufacturer_name]: Unknown (0xA741)
278 [product_id]: 16975 (0x424f)
279 [product_name]: Unknown (0x424F)
280 [device_available]: yes
281 [provides_device_sdrs]: yes
282 [additional_device_support]:
283 [additional_device_support][0]: Sensor Device
284 [additional_device_support][1]: SEL Device
285 [additional_device_support][2]: FRU Inventory Device
286 [additional_device_support][3]: Chassis Device
287 [aux_firmware_rev_info]:
288 [aux_firmware_rev_info][0]: 0x00
289 [aux_firmware_rev_info][1]: 0x00
290 [aux_firmware_rev_info][2]: 0x00
291 [aux_firmware_rev_info][3]: 0x00
292 """
293
294 status, ret_values = \
295 grk.run_key_u("Run IPMI Standard Command mc info")
296 result = vf.key_value_outbuf_to_dict(ret_values, process_indent=1)
297
298 return result
Rahul Maheshwaridc6a32c2018-03-15 05:21:55 -0500299
300
301def get_sdr_info():
Rahul Maheshwaridc6a32c2018-03-15 05:21:55 -0500302 r"""
303 Get IPMI sdr info data and return it as a dictionary.
304
305 The data is obtained by issuing the IPMI "sdr info" command. An
306 example is shown below:
307
308 SDR Version : 0x51
309 Record Count : 216
310 Free Space : unspecified
311 Most recent Addition :
312 Most recent Erase :
313 SDR overflow : no
314 SDR Repository Update Support : unspecified
315 Delete SDR supported : no
316 Partial Add SDR supported : no
317 Reserve SDR repository supported : no
318 SDR Repository Alloc info supported : no
319
320 For the data shown above, the following dictionary will be returned.
321 mc_info:
322
323 [sdr_version]: 0x51
324 [record_Count]: 216
325 [free_space]: unspecified
326 [most_recent_addition]:
327 [most_recent_erase]:
328 [sdr_overflow]: no
329 [sdr_repository_update_support]: unspecified
330 [delete_sdr_supported]: no
331 [partial_add_sdr_supported]: no
332 [reserve_sdr_repository_supported]: no
333 [sdr_repository_alloc_info_supported]: no
334 """
335
336 status, ret_values = \
337 grk.run_key_u("Run IPMI Standard Command sdr info")
338 result = vf.key_value_outbuf_to_dict(ret_values, process_indent=1)
339
340 return result
George Keishing3511a3f2018-04-19 10:38:30 -0500341
342
343def get_aux_version(version_id):
344 r"""
345 Get IPMI Aux version info data and return it.
346
347 Description of argument(s):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500348 version_id The data is obtained by from BMC
349 /etc/os-release
350 (e.g. "xxx-v2.1-438-g0030304-r3-gfea8585").
George Keishing3511a3f2018-04-19 10:38:30 -0500351
352 In the prior example, the 3rd field is "438" is the commit version and
353 the 5th field is "r3" and value "3" is the release version.
354
355 Aux version return from this function 4380003.
356 """
357
358 # Commit version.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500359 count = re.findall("-(\\d{1,4})-", version_id)
George Keishing3511a3f2018-04-19 10:38:30 -0500360
361 # Release version.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500362 release = re.findall("-r(\\d{1,4})", version_id)
George Keishing3511a3f2018-04-19 10:38:30 -0500363 if release:
364 aux_version = count[0] + "{0:0>4}".format(release[0])
365 else:
366 aux_version = count[0] + "0000"
367
368 return aux_version
Michael Walsh27b14a62018-05-24 11:05:07 -0500369
370
371def get_fru_info():
372 r"""
373 Get fru info and return it as a list of dictionaries.
374
375 The data is obtained by issuing the IPMI "fru print -N 50" command. An
376 example is shown below:
377
378 FRU Device Description : Builtin FRU Device (ID 0)
379 Device not present (Unspecified error)
380
381 FRU Device Description : cpu0 (ID 1)
382 Board Mfg Date : Sun Dec 31 18:00:00 1995
George Keishinge0a81282018-06-08 10:02:30 -0500383 Board Mfg : <Manufacturer Name>
Michael Walsh27b14a62018-05-24 11:05:07 -0500384 Board Product : PROCESSOR MODULE
385 Board Serial : YA1934315964
386 Board Part Number : 02CY209
387
388 FRU Device Description : cpu1 (ID 2)
389 Board Mfg Date : Sun Dec 31 18:00:00 1995
George Keishinge0a81282018-06-08 10:02:30 -0500390 Board Mfg : <Manufacturer Name>
Michael Walsh27b14a62018-05-24 11:05:07 -0500391 Board Product : PROCESSOR MODULE
392 Board Serial : YA1934315965
393 Board Part Number : 02CY209
394
395 For the data shown above, the following list of dictionaries will be
396 returned.
397
398 fru_obj:
399 fru_obj[0]:
400 [fru_device_description]: Builtin FRU Device (ID 0)
401 [state]: Device not present (Unspecified error)
402 fru_obj[1]:
403 [fru_device_description]: cpu0 (ID 1)
404 [board_mfg_date]: Sun Dec 31 18:00:00 1995
George Keishinge0a81282018-06-08 10:02:30 -0500405 [board_mfg]: <Manufacturer Name>
Michael Walsh27b14a62018-05-24 11:05:07 -0500406 [board_product]: PROCESSOR MODULE
407 [board_serial]: YA1934315964
408 [board_part_number]: 02CY209
409 fru_obj[2]:
410 [fru_device_description]: cpu1 (ID 2)
411 [board_mfg_date]: Sun Dec 31 18:00:00 1995
George Keishinge0a81282018-06-08 10:02:30 -0500412 [board_mfg]: <Manufacturer Name>
Michael Walsh27b14a62018-05-24 11:05:07 -0500413 [board_product]: PROCESSOR MODULE
414 [board_serial]: YA1934315965
415 [board_part_number]: 02CY209
416 """
417
418 status, ret_values = \
419 grk.run_key_u("Run IPMI Standard Command fru print -N 50")
420
421 # Manipulate the "Device not present" line to create a "state" key.
422 ret_values = re.sub("Device not present", "state : Device not present",
423 ret_values)
424
425 return [vf.key_value_outbuf_to_dict(x) for x in re.split("\n\n",
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500426 ret_values)]
Michael Walsh61224e62018-05-30 17:58:42 -0500427
428
Michael Walsha95e4ef2018-06-06 17:53:04 -0500429def get_component_fru_info(component='cpu',
430 fru_objs=None):
Michael Walsh61224e62018-05-30 17:58:42 -0500431 r"""
432 Get fru info for the given component and return it as a list of
433 dictionaries.
434
435 This function calls upon get_fru_info and then filters out the unwanted
436 entries. See get_fru_info's prolog for a layout of the data.
437
438 Description of argument(s):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500439 component The component (e.g. "cpu", "dimm", etc.).
440 fru_objs A fru_objs list such as the one returned
441 by get_fru_info. If this is None, then
442 this function will call get_fru_info to
443 obtain such a list.
444 Supplying this argument may improve
445 performance if this function is to be
446 called multiple times.
Michael Walsh61224e62018-05-30 17:58:42 -0500447 """
448
Michael Walsha95e4ef2018-06-06 17:53:04 -0500449 if fru_objs is None:
450 fru_objs = get_fru_info()
Michael Walsh61224e62018-05-30 17:58:42 -0500451 return\
452 [x for x in fru_objs
453 if re.match(component + '([0-9]+)? ', x['fru_device_description'])]
Rahul Maheshwari24e0e792019-02-12 22:40:23 -0600454
455
456def get_user_info(userid, channel_number=1):
457 r"""
458 Get user info using channel command and return it as a dictionary.
459
460 Description of argument(s):
461 userid The userid (e.g. "1", "2", etc.).
462 channel_number The user's channel number (e.g. "1").
463
Michael Walshe733b262019-12-09 11:45:24 -0600464 Note: If userid is blank, this function will return a list of dictionaries. Each list entry represents
465 one userid record.
466
Rahul Maheshwari24e0e792019-02-12 22:40:23 -0600467 The data is obtained by issuing the IPMI "channel getaccess" command. An
468 example is shown below for user id 1 and channel number 1.
469
470 Maximum User IDs : 15
471 Enabled User IDs : 1
472 User ID : 1
473 User Name : root
474 Fixed Name : No
475 Access Available : callback
476 Link Authentication : enabled
477 IPMI Messaging : enabled
478 Privilege Level : ADMINISTRATOR
479 Enable Status : enabled
480
481 For the data shown above, the following dictionary will be returned.
482
483 user_info:
484 [maximum_userids]: 15
485 [enabled_userids: 1
486 [userid] 1
487 [user_name] root
488 [fixed_name] No
489 [access_available] callback
490 [link_authentication] enabled
491 [ipmi_messaging] enabled
492 [privilege_level] ADMINISTRATOR
493 [enable_status] enabled
Rahul Maheshwari24e0e792019-02-12 22:40:23 -0600494 """
495
496 status, ret_values = grk.run_key_u("Run IPMI Standard Command channel getaccess "
497 + str(channel_number) + " " + str(userid))
498
Michael Walshe733b262019-12-09 11:45:24 -0600499 if userid == "":
500 return vf.key_value_outbuf_to_dicts(ret_values, process_indent=1)
501 else:
502 return vf.key_value_outbuf_to_dict(ret_values, process_indent=1)
George Keishing45511e82019-10-15 01:26:55 -0500503
504
505def channel_getciphers_ipmi():
506
507 r"""
508 Run 'channel getciphers ipmi' command and return the result as a list of dictionaries.
509
510 Example robot code:
511 ${ipmi_channel_ciphers}= Channel Getciphers IPMI
512 Rprint Vars ipmi_channel_ciphers
513
514 Example output:
515 ipmi_channel_ciphers:
516 [0]:
517 [id]: 3
518 [iana]: N/A
519 [auth_alg]: hmac_sha1
520 [integrity_alg]: hmac_sha1_96
521 [confidentiality_alg]: aes_cbc_128
522 [1]:
523 [id]: 17
524 [iana]: N/A
525 [auth_alg]: hmac_sha256
526 [integrity_alg]: sha256_128
527 [confidentiality_alg]: aes_cbc_128
528 """
529
530 cmd_buf = "channel getciphers ipmi | sed -re 's/ Alg/_Alg/g'"
531 stdout, stderr, rc = execute_ipmi_cmd(cmd_buf, "external", print_output=0)
532 return vf.outbuf_to_report(stdout)
Tony Lee9bca44b2019-12-13 09:34:26 +0800533
534
535def get_device_id_config():
536 r"""
537 Get the device id config data and return as a dictionary.
538
539 Example:
540
541 dev_id_config = get_device_id_config()
542 print_vars(dev_id_config)
543
544 dev_id_config:
545 [manuf_id]: 7244
546 [addn_dev_support]: 141
547 [prod_id]: 16976
548 [aux]: 0
549 [id]: 32
550 [revision]: 129
551 [device_revision]: 1
552 """
553 stdout, stderr, rc = bsu.bmc_execute_command("cat /usr/share/ipmi-providers/dev_id.json")
554
555 result = json.loads(stdout)
556
557 # Create device revision field for the user.
558 # Reference IPMI specification v2.0 "Get Device ID Command"
559 # [7] 1 = device provides Device SDRs
560 # 0 = device does not provide Device SDRs
561 # [6:4] reserved. Return as 0.
562 # [3:0] Device Revision, binary encoded.
563
564 result['device_revision'] = result['revision'] & 0x0F
565
566 return result
Rahul Maheshwari02ea62c2020-02-21 05:06:13 -0600567
568
569def get_chassis_status():
570 r"""
571 Get IPMI chassis status data and return it as a dictionary.
572
573 The data is obtained by issuing the IPMI "chassis status" command. An
574 example is shown below:
575
576 System Power : off
577 Power Overload : false
578 Power Interlock : inactive
579 Main Power Fault : false
580 Power Control Fault : false
581 Power Restore Policy : previous
582 Last Power Event :
583 Chassis Intrusion : inactive
584 Front-Panel Lockout : inactive
585 Drive Fault : false
586 Cooling/Fan Fault : false
587 Sleep Button Disable : not allowed
588 Diag Button Disable : not allowed
589 Reset Button Disable : not allowed
590 Power Button Disable : allowed
591 Sleep Button Disabled : false
592 Diag Button Disabled : false
593 Reset Button Disabled : false
594 Power Button Disabled : false
595
596 For the data shown above, the following dictionary will be returned.
597
598 chassis_status:
599 [system_power]: off
600 [power_overload]: false
601 [power_interlock]: inactive
602 [main_power_fault]: false
603 [power_control_fault]: false
604 [power_restore_policy]: previous
605 [last_power_event]:
606 [chassis_intrusion]: inactive
607 [front-panel_lockout]: inactive
608 [drive_fault]: false
609 [cooling/fan_fault]: false
610 [sleep_button_disable]: not allowed
611 [diag_button_disable]: not allowed
612 [reset_button_disable]: not allowed
613 [power_button_disable]: allowed
614 [sleep_button_disabled]: false
615 [diag_button_disabled]: false
616 [reset_button_disabled]: false
617 [power_button_disabled]: false
618 """
619
620 status, ret_values = \
621 grk.run_key_u("Run IPMI Standard Command chassis status")
622 result = vf.key_value_outbuf_to_dict(ret_values, process_indent=1)
623
624 return result
Tony Lee18c6f9a2020-02-18 17:00:20 +0800625
626
627def get_channel_info(channel_number=1):
628 r"""
629 Get the channel info and return as a dictionary.
630 Example:
631
632 channel_info:
633 [channel_0x2_info]:
634 [channel_medium_type]: 802.3 LAN
635 [channel_protocol_type]: IPMB-1.0
636 [session_support]: multi-session
637 [active_session_count]: 0
638 [protocol_vendor_id]: 7154
Tony Lee87c9cb92020-03-04 14:47:09 +0800639 [volatile(active)_settings]:
Tony Lee18c6f9a2020-02-18 17:00:20 +0800640 [alerting]: enabled
641 [per-message_auth]: enabled
642 [user_level_auth]: enabled
643 [access_mode]: always available
Tony Lee87c9cb92020-03-04 14:47:09 +0800644 [non-volatile_settings]:
Tony Lee18c6f9a2020-02-18 17:00:20 +0800645 [alerting]: enabled
646 [per-message_auth]: enabled
647 [user_level_auth]: enabled
648 [access_mode]: always available
649 """
650
651 status, ret_values = \
652 grk.run_key_u("Run IPMI Standard Command channel info " + str(channel_number))
Tony Lee87c9cb92020-03-04 14:47:09 +0800653 key_var_list = list(filter(None, ret_values.split("\n")))
654 # To match the dict format, add a colon after 'Volatile(active) Settings' and 'Non-Volatile Settings'
655 # respectively.
656 key_var_list[6] = 'Volatile(active) Settings:'
657 key_var_list[11] = 'Non-Volatile Settings:'
658 result = vf.key_value_list_to_dict(key_var_list, process_indent=1)
Tony Lee18c6f9a2020-02-18 17:00:20 +0800659 return result
Tony Lee3d351ee2020-02-19 10:21:04 +0800660
661
662def get_user_access_ipmi(channel_number=1):
663
664 r"""
665 Run 'user list [<channel number>]' command and return the result as a list of dictionaries.
666
667 Example robot code:
668 ${users_access}= user list 1
669 Rprint Vars users_access
670
671 Example output:
672 users:
673 [0]:
674 [id]: 1
675 [name]: root
676 [callin]: false
677 [link]: true
678 [auth]: true
679 [ipmi]: ADMINISTRATOR
680 [1]:
681 [id]: 2
682 [name]: axzIDwnz
683 [callin]: true
684 [link]: false
685 [auth]: true
686 [ipmi]: ADMINISTRATOR
687 """
688
689 cmd_buf = "user list " + str(channel_number)
690 stdout, stderr, rc = execute_ipmi_cmd(cmd_buf, "external", print_output=0)
691 return vf.outbuf_to_report(stdout)
Tony Lee0754c5f2020-03-13 19:38:24 +0800692
693
694def get_channel_auth_capabilities(channel_number=1):
695 r"""
696 Get the channel authentication capabilities and return as a dictionary.
697
698 Example:
699
700 channel_auth_cap:
701 [channel_number]: 2
702 [ipmi_v1.5__auth_types]:
703 [kg_status]: default (all zeroes)
704 [per_message_authentication]: enabled
705 [user_level_authentication]: enabled
706 [non-null_user_names_exist]: yes
707 [null_user_names_exist]: no
708 [anonymous_login_enabled]: no
709 [channel_supports_ipmi_v1.5]: no
710 [channel_supports_ipmi_v2.0]: yes
711 """
712
713 status, ret_values = \
714 grk.run_key_u("Run IPMI Standard Command channel authcap " + str(channel_number) + " 4")
715 result = vf.key_value_outbuf_to_dict(ret_values, process_indent=1)
716
717 return result
chithrag0a8c8782022-03-01 12:35:00 +0000718
719
720def fetch_date(date):
721 r"""
722 Removes prefix 0 in a date in given date
723
724 Example : 08/12/2021 then returns 8/12/2021
725 """
726
727 date = date.lstrip("0")
728 return date
729
730
731def fetch_added_sel_date(entry):
732 r"""
733 Split sel entry string with with | and join only the date with space
734
735 Example : If entry given is, "a | 02/14/2020 | 01:16:58 | Sensor_type #0x17 | | Asserted"
736 Then the result will be "02/14/2020 01:16:58"
737 """
738
739 temp = entry.split(" | ")
740 date = temp[1] + " " + temp[2]
741 print(date)
742 return date
743
744
745def prefix_bytes(listx):
746 r"""
747 prefixes byte strings in list
748
749 Example:
750 ${listx} = ['01', '02', '03']
751 ${listx}= Prefix Bytes ${listx}
752 then,
753 ${listx}= ['0x01', '0x02', '0x03']
754
755 """
756
757 listy = []
758 for item in listx:
759 item = "0x" + item
760 listy.append(item)
761 return listy
chithragff43db92022-03-01 13:13:48 +0000762
763
chithrag6b279b32022-05-05 08:28:05 +0000764def modify_and_fetch_threshold(old_threshold, threshold_list):
chithragff43db92022-03-01 13:13:48 +0000765 r"""
chithragff43db92022-03-01 13:13:48 +0000766 Description of argument(s):
767
chithrag6b279b32022-05-05 08:28:05 +0000768 old_threshold List of threshold values of sensor,
chithragff43db92022-03-01 13:13:48 +0000769 threshold_list List of higher and lower of critical and non-critical values.
chithrag6b279b32022-05-05 08:28:05 +0000770 i,e [ "lcr", "lnc", "unc", "ucr" ]
771
772 Gets old threshold values from sensor and threshold levels,
773 then returns the list of new threshold and the dict of threshold levels
chithragff43db92022-03-01 13:13:48 +0000774
775 For example :
chithrag6b279b32022-05-05 08:28:05 +0000776 1. If old_threshold list is [ 1, 2, 3, 4] then the newthreshold_list will be [ 101, 102, 103, 104 ].
777 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 +0000778
chithrag6b279b32022-05-05 08:28:05 +0000779 2. The newthreshold_list will be zipped to dictionary with threshold_list levels,
780 Example : threshold_dict = { 'lcr': 101, 'lnc': 102, 'unc': 103, 'ucr': 104 }
781
chithragff43db92022-03-01 13:13:48 +0000782 """
783
chithrag6b279b32022-05-05 08:28:05 +0000784 # Adding the difference of 100 as less than this value,
785 # may not have greater impact as the sensor considered is a fan sensor.
786 # The set threshold may round off for certain values below 100.
chithragff43db92022-03-01 13:13:48 +0000787 n = 100
788 newthreshold_list = []
789 for th in old_threshold:
790 th = th.strip()
791 if th == 'na':
792 newthreshold_list.append('na')
793 else:
794 x = int(float(th)) + n
795 newthreshold_list.append(x)
796 n = n + 100
797 threshold_dict = dict(zip(threshold_list, newthreshold_list))
798 return newthreshold_list, threshold_dict