blob: b2a1b2b7821874ea422814f1b4ea07889dfb973f [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
Patrick Williams57318182022-12-08 06:18:26 -06008import gen_print as gp
George Keishinge635ddc2022-12-08 07:38:02 -06009import gen_misc as gm
10import gen_cmd as gc
Michael Walshed5b46e2017-05-24 11:49:14 -050011import gen_robot_keyword as grk
12import gen_robot_utils as gru
George Keishinge635ddc2022-12-08 07:38:02 -060013import bmc_ssh_utils as bsu
Patrick Williams57318182022-12-08 06:18:26 -060014import var_funcs as vf
George Keishinge635ddc2022-12-08 07:38:02 -060015import ipmi_client as ic
16import tempfile
17import json
Sridevi Ramesh47375aa2022-12-08 05:05:31 -060018from robot.libraries.BuiltIn import BuiltIn
19
20gru.my_import_resource("ipmi_client.robot")
Michael Walshed5b46e2017-05-24 11:49:14 -050021
22
Michael Walshed5b46e2017-05-24 11:49:14 -050023def get_sol_info():
Michael Walshed5b46e2017-05-24 11:49:14 -050024 r"""
25 Get all SOL info and return it as a dictionary.
26
27 Example use:
28
29 Robot code:
30 ${sol_info}= get_sol_info
31 Rpvars sol_info
32
33 Output:
34 sol_info:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -050035 sol_info[Info]: SOL parameter 'Payload Channel (7)'
36 not supported - defaulting to 0x0e
Michael Walshed5b46e2017-05-24 11:49:14 -050037 sol_info[Character Send Threshold]: 1
38 sol_info[Force Authentication]: true
39 sol_info[Privilege Level]: USER
40 sol_info[Set in progress]: set-complete
41 sol_info[Retry Interval (ms)]: 100
42 sol_info[Non-Volatile Bit Rate (kbps)]: IPMI-Over-Serial-Setting
43 sol_info[Character Accumulate Level (ms)]: 100
44 sol_info[Enabled]: true
45 sol_info[Volatile Bit Rate (kbps)]: IPMI-Over-Serial-Setting
46 sol_info[Payload Channel]: 14 (0x0e)
47 sol_info[Payload Port]: 623
48 sol_info[Force Encryption]: true
49 sol_info[Retry Count]: 7
50 """
51
52 status, ret_values = grk.run_key_u("Run IPMI Standard Command sol info")
53
54 # Create temp file path.
55 temp = tempfile.NamedTemporaryFile()
56 temp_file_path = temp.name
57
58 # Write sol info to temp file path.
59 text_file = open(temp_file_path, "w")
60 text_file.write(ret_values)
61 text_file.close()
62
63 # Use my_parm_file to interpret data.
64 sol_info = gm.my_parm_file(temp_file_path)
65
66 return sol_info
67
Rahul Maheshwarid629b5c2017-05-23 08:06:28 -050068
Rahul Maheshwarid629b5c2017-05-23 08:06:28 -050069def set_sol_setting(setting_name, setting_value):
Rahul Maheshwarid629b5c2017-05-23 08:06:28 -050070 r"""
71 Set SOL setting with given value.
72
73 # Description of argument(s):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -050074 # setting_name SOL setting which needs to be set (e.g.
75 # "retry-count").
76 # setting_value Value which needs to be set (e.g. "7").
Rahul Maheshwarid629b5c2017-05-23 08:06:28 -050077 """
78
George Keishinge635ddc2022-12-08 07:38:02 -060079 status, ret_values = grk.run_key_u("Run IPMI Standard Command sol set "
80 + setting_name + " " + setting_value)
Rahul Maheshwarid629b5c2017-05-23 08:06:28 -050081
82 return status
83
Rahul Maheshwarid629b5c2017-05-23 08:06:28 -050084
George Keishinge635ddc2022-12-08 07:38:02 -060085def execute_ipmi_cmd(cmd_string,
86 ipmi_cmd_type='inband',
87 print_output=1,
88 ignore_err=0,
89 **options):
Michael Walsh94811f62018-09-05 14:55:12 -050090 r"""
91 Run the given command string as an IPMI command and return the stdout,
92 stderr and the return code.
93
94 Description of argument(s):
95 cmd_string The command string to be run as an IPMI
96 command.
97 ipmi_cmd_type 'inband' or 'external'.
98 print_output If this is set, this function will print
99 the stdout/stderr generated by
100 the IPMI command.
101 ignore_err Ignore error means that a failure
102 encountered by running the command
103 string will not be raised as a python
104 exception.
Michael Walsh19e70c82019-01-23 11:07:15 -0600105 options These are passed directly to the
106 create_ipmi_ext_command_string function.
107 See that function's prolog for details.
Michael Walsh94811f62018-09-05 14:55:12 -0500108 """
109
George Keishinge635ddc2022-12-08 07:38:02 -0600110 if ipmi_cmd_type == 'inband':
Michael Walsh94811f62018-09-05 14:55:12 -0500111 IPMI_INBAND_CMD = BuiltIn().get_variable_value("${IPMI_INBAND_CMD}")
112 cmd_buf = IPMI_INBAND_CMD + " " + cmd_string
George Keishinge635ddc2022-12-08 07:38:02 -0600113 return bsu.os_execute_command(cmd_buf,
114 print_out=print_output,
115 ignore_err=ignore_err)
Michael Walsh94811f62018-09-05 14:55:12 -0500116
George Keishinge635ddc2022-12-08 07:38:02 -0600117 if ipmi_cmd_type == 'external':
Michael Walsh19e70c82019-01-23 11:07:15 -0600118 cmd_buf = ic.create_ipmi_ext_command_string(cmd_string, **options)
George Keishinge635ddc2022-12-08 07:38:02 -0600119 rc, stdout, stderr = gc.shell_cmd(cmd_buf,
120 print_output=print_output,
121 ignore_err=ignore_err,
122 return_stderr=1)
Michael Walsh94811f62018-09-05 14:55:12 -0500123 return stdout, stderr, rc
124
125
George Keishinge635ddc2022-12-08 07:38:02 -0600126def get_lan_print_dict(channel_number='', ipmi_cmd_type='external'):
Michael Walsh4481b932018-02-08 11:45:15 -0600127 r"""
128 Get IPMI 'lan print' output and return it as a dictionary.
129
130 Here is an example of the IPMI lan print output:
131
132 Set in Progress : Set Complete
133 Auth Type Support : MD5
134 Auth Type Enable : Callback : MD5
135 : User : MD5
136 : Operator : MD5
137 : Admin : MD5
138 : OEM : MD5
139 IP Address Source : Static Address
140 IP Address : x.x.x.x
141 Subnet Mask : x.x.x.x
142 MAC Address : xx:xx:xx:xx:xx:xx
143 Default Gateway IP : x.x.x.x
144 802.1q VLAN ID : Disabled
145 Cipher Suite Priv Max : Not Available
146 Bad Password Threshold : Not Available
147
148 Given that data, this function will return the following dictionary.
149
150 lan_print_dict:
151 [Set in Progress]: Set Complete
152 [Auth Type Support]: MD5
153 [Auth Type Enable]:
154 [Callback]: MD5
155 [User]: MD5
156 [Operator]: MD5
157 [Admin]: MD5
158 [OEM]: MD5
159 [IP Address Source]: Static Address
160 [IP Address]: x.x.x.x
161 [Subnet Mask]: x.x.x.x
162 [MAC Address]: xx:xx:xx:xx:xx:xx
163 [Default Gateway IP]: x.x.x.x
164 [802.1q VLAN ID]: Disabled
165 [Cipher Suite Priv Max]: Not Available
166 [Bad Password Threshold]: Not Available
167
Michael Walsh94811f62018-09-05 14:55:12 -0500168 Description of argument(s):
169 ipmi_cmd_type The type of ipmi command to use (e.g.
170 'inband', 'external').
Michael Walsh4481b932018-02-08 11:45:15 -0600171 """
172
Tony Leeea741302019-11-08 11:01:58 +0800173 channel_number = str(channel_number)
Michael Walsh4481b932018-02-08 11:45:15 -0600174 # Notice in the example of data above that 'Auth Type Enable' needs some
175 # special processing. We essentially want to isolate its data and remove
176 # the 'Auth Type Enable' string so that key_value_outbuf_to_dict can
177 # process it as a sub-dictionary.
George Keishinge635ddc2022-12-08 07:38:02 -0600178 cmd_buf = "lan print " + channel_number + " | grep -E '^(Auth Type Enable)" +\
179 "?[ ]+: ' | sed -re 's/^(Auth Type Enable)?[ ]+: //g'"
180 stdout1, stderr, rc = execute_ipmi_cmd(cmd_buf, ipmi_cmd_type,
181 print_output=0)
Michael Walsh4481b932018-02-08 11:45:15 -0600182
183 # Now get the remainder of the data and exclude the lines with no field
184 # names (i.e. the 'Auth Type Enable' sub-fields).
Tony Leeea741302019-11-08 11:01:58 +0800185 cmd_buf = "lan print " + channel_number + " | grep -E -v '^[ ]+: '"
George Keishinge635ddc2022-12-08 07:38:02 -0600186 stdout2, stderr, rc = execute_ipmi_cmd(cmd_buf, ipmi_cmd_type,
187 print_output=0)
Michael Walsh4481b932018-02-08 11:45:15 -0600188
189 # Make auth_type_enable_dict sub-dictionary...
George Keishinge635ddc2022-12-08 07:38:02 -0600190 auth_type_enable_dict = vf.key_value_outbuf_to_dict(stdout1, to_lower=0,
191 underscores=0)
Michael Walsh4481b932018-02-08 11:45:15 -0600192
193 # Create the lan_print_dict...
George Keishinge635ddc2022-12-08 07:38:02 -0600194 lan_print_dict = vf.key_value_outbuf_to_dict(stdout2, to_lower=0,
195 underscores=0)
Michael Walsh4481b932018-02-08 11:45:15 -0600196 # Re-assign 'Auth Type Enable' to contain the auth_type_enable_dict.
George Keishinge635ddc2022-12-08 07:38:02 -0600197 lan_print_dict['Auth Type Enable'] = auth_type_enable_dict
Michael Walsh4481b932018-02-08 11:45:15 -0600198
199 return lan_print_dict
Michael Walshd59ed7c2018-02-15 10:19:38 -0600200
201
Michael Walshf4098fb2018-02-28 10:54:46 -0600202def get_ipmi_power_reading(strip_watts=1):
Michael Walshd59ed7c2018-02-15 10:19:38 -0600203 r"""
204 Get IPMI power reading data and return it as a dictionary.
205
206 The data is obtained by issuing the IPMI "power reading" command. An
207 example is shown below:
208
209 Instantaneous power reading: 234 Watts
210 Minimum during sampling period: 234 Watts
211 Maximum during sampling period: 234 Watts
212 Average power reading over sample period: 234 Watts
213 IPMI timestamp: Thu Jan 1 00:00:00 1970
214 Sampling period: 00000000 Seconds.
215 Power reading state is: deactivated
216
217 For the data shown above, the following dictionary will be returned.
218
219 result:
220 [instantaneous_power_reading]: 238 Watts
221 [minimum_during_sampling_period]: 238 Watts
222 [maximum_during_sampling_period]: 238 Watts
223 [average_power_reading_over_sample_period]: 238 Watts
224 [ipmi_timestamp]: Thu Jan 1 00:00:00 1970
225 [sampling_period]: 00000000 Seconds.
226 [power_reading_state_is]: deactivated
Michael Walshf4098fb2018-02-28 10:54:46 -0600227
228 Description of argument(s):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500229 strip_watts Strip all dictionary values of the
230 trailing " Watts" substring.
Michael Walshd59ed7c2018-02-15 10:19:38 -0600231 """
232
George Keishinge635ddc2022-12-08 07:38:02 -0600233 status, ret_values = \
234 grk.run_key_u("Run IPMI Standard Command dcmi power reading")
Michael Walshd59ed7c2018-02-15 10:19:38 -0600235 result = vf.key_value_outbuf_to_dict(ret_values)
236
Michael Walshf4098fb2018-02-28 10:54:46 -0600237 if strip_watts:
George Keishinge635ddc2022-12-08 07:38:02 -0600238 result.update((k, re.sub(' Watts$', '', v)) for k, v in result.items())
Michael Walshf4098fb2018-02-28 10:54:46 -0600239
Michael Walshd59ed7c2018-02-15 10:19:38 -0600240 return result
Michael Walshaf5607e2018-02-19 17:37:20 -0600241
242
243def get_mc_info():
Michael Walshaf5607e2018-02-19 17:37:20 -0600244 r"""
245 Get IPMI mc info data and return it as a dictionary.
246
247 The data is obtained by issuing the IPMI "mc info" command. An
248 example is shown below:
249
250 Device ID : 0
251 Device Revision : 0
252 Firmware Revision : 2.01
253 IPMI Version : 2.0
254 Manufacturer ID : 42817
255 Manufacturer Name : Unknown (0xA741)
256 Product ID : 16975 (0x424f)
257 Product Name : Unknown (0x424F)
258 Device Available : yes
259 Provides Device SDRs : yes
260 Additional Device Support :
261 Sensor Device
262 SEL Device
263 FRU Inventory Device
264 Chassis Device
265 Aux Firmware Rev Info :
266 0x00
267 0x00
268 0x00
269 0x00
270
271 For the data shown above, the following dictionary will be returned.
272 mc_info:
273 [device_id]: 0
274 [device_revision]: 0
275 [firmware_revision]: 2.01
276 [ipmi_version]: 2.0
277 [manufacturer_id]: 42817
278 [manufacturer_name]: Unknown (0xA741)
279 [product_id]: 16975 (0x424f)
280 [product_name]: Unknown (0x424F)
281 [device_available]: yes
282 [provides_device_sdrs]: yes
283 [additional_device_support]:
284 [additional_device_support][0]: Sensor Device
285 [additional_device_support][1]: SEL Device
286 [additional_device_support][2]: FRU Inventory Device
287 [additional_device_support][3]: Chassis Device
288 [aux_firmware_rev_info]:
289 [aux_firmware_rev_info][0]: 0x00
290 [aux_firmware_rev_info][1]: 0x00
291 [aux_firmware_rev_info][2]: 0x00
292 [aux_firmware_rev_info][3]: 0x00
293 """
294
George Keishinge635ddc2022-12-08 07:38:02 -0600295 status, ret_values = \
296 grk.run_key_u("Run IPMI Standard Command mc info")
Michael Walshaf5607e2018-02-19 17:37:20 -0600297 result = vf.key_value_outbuf_to_dict(ret_values, process_indent=1)
298
299 return result
Rahul Maheshwaridc6a32c2018-03-15 05:21:55 -0500300
301
302def get_sdr_info():
Rahul Maheshwaridc6a32c2018-03-15 05:21:55 -0500303 r"""
304 Get IPMI sdr info data and return it as a dictionary.
305
306 The data is obtained by issuing the IPMI "sdr info" command. An
307 example is shown below:
308
309 SDR Version : 0x51
310 Record Count : 216
311 Free Space : unspecified
312 Most recent Addition :
313 Most recent Erase :
314 SDR overflow : no
315 SDR Repository Update Support : unspecified
316 Delete SDR supported : no
317 Partial Add SDR supported : no
318 Reserve SDR repository supported : no
319 SDR Repository Alloc info supported : no
320
321 For the data shown above, the following dictionary will be returned.
322 mc_info:
323
324 [sdr_version]: 0x51
325 [record_Count]: 216
326 [free_space]: unspecified
327 [most_recent_addition]:
328 [most_recent_erase]:
329 [sdr_overflow]: no
330 [sdr_repository_update_support]: unspecified
331 [delete_sdr_supported]: no
332 [partial_add_sdr_supported]: no
333 [reserve_sdr_repository_supported]: no
334 [sdr_repository_alloc_info_supported]: no
335 """
336
George Keishinge635ddc2022-12-08 07:38:02 -0600337 status, ret_values = \
338 grk.run_key_u("Run IPMI Standard Command sdr info")
Rahul Maheshwaridc6a32c2018-03-15 05:21:55 -0500339 result = vf.key_value_outbuf_to_dict(ret_values, process_indent=1)
340
341 return result
George Keishing3511a3f2018-04-19 10:38:30 -0500342
343
344def get_aux_version(version_id):
345 r"""
346 Get IPMI Aux version info data and return it.
347
348 Description of argument(s):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500349 version_id The data is obtained by from BMC
350 /etc/os-release
351 (e.g. "xxx-v2.1-438-g0030304-r3-gfea8585").
George Keishing3511a3f2018-04-19 10:38:30 -0500352
353 In the prior example, the 3rd field is "438" is the commit version and
354 the 5th field is "r3" and value "3" is the release version.
355
356 Aux version return from this function 4380003.
357 """
358
359 # Commit version.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500360 count = re.findall("-(\\d{1,4})-", version_id)
George Keishing3511a3f2018-04-19 10:38:30 -0500361
362 # Release version.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500363 release = re.findall("-r(\\d{1,4})", version_id)
George Keishing3511a3f2018-04-19 10:38:30 -0500364 if release:
365 aux_version = count[0] + "{0:0>4}".format(release[0])
366 else:
367 aux_version = count[0] + "0000"
368
369 return aux_version
Michael Walsh27b14a62018-05-24 11:05:07 -0500370
371
372def get_fru_info():
373 r"""
374 Get fru info and return it as a list of dictionaries.
375
376 The data is obtained by issuing the IPMI "fru print -N 50" command. An
377 example is shown below:
378
379 FRU Device Description : Builtin FRU Device (ID 0)
380 Device not present (Unspecified error)
381
382 FRU Device Description : cpu0 (ID 1)
383 Board Mfg Date : Sun Dec 31 18:00:00 1995
George Keishinge0a81282018-06-08 10:02:30 -0500384 Board Mfg : <Manufacturer Name>
Michael Walsh27b14a62018-05-24 11:05:07 -0500385 Board Product : PROCESSOR MODULE
386 Board Serial : YA1934315964
387 Board Part Number : 02CY209
388
389 FRU Device Description : cpu1 (ID 2)
390 Board Mfg Date : Sun Dec 31 18:00:00 1995
George Keishinge0a81282018-06-08 10:02:30 -0500391 Board Mfg : <Manufacturer Name>
Michael Walsh27b14a62018-05-24 11:05:07 -0500392 Board Product : PROCESSOR MODULE
393 Board Serial : YA1934315965
394 Board Part Number : 02CY209
395
396 For the data shown above, the following list of dictionaries will be
397 returned.
398
399 fru_obj:
400 fru_obj[0]:
401 [fru_device_description]: Builtin FRU Device (ID 0)
402 [state]: Device not present (Unspecified error)
403 fru_obj[1]:
404 [fru_device_description]: cpu0 (ID 1)
405 [board_mfg_date]: Sun Dec 31 18:00:00 1995
George Keishinge0a81282018-06-08 10:02:30 -0500406 [board_mfg]: <Manufacturer Name>
Michael Walsh27b14a62018-05-24 11:05:07 -0500407 [board_product]: PROCESSOR MODULE
408 [board_serial]: YA1934315964
409 [board_part_number]: 02CY209
410 fru_obj[2]:
411 [fru_device_description]: cpu1 (ID 2)
412 [board_mfg_date]: Sun Dec 31 18:00:00 1995
George Keishinge0a81282018-06-08 10:02:30 -0500413 [board_mfg]: <Manufacturer Name>
Michael Walsh27b14a62018-05-24 11:05:07 -0500414 [board_product]: PROCESSOR MODULE
415 [board_serial]: YA1934315965
416 [board_part_number]: 02CY209
417 """
418
George Keishinge635ddc2022-12-08 07:38:02 -0600419 status, ret_values = \
420 grk.run_key_u("Run IPMI Standard Command fru print -N 50")
Michael Walsh27b14a62018-05-24 11:05:07 -0500421
422 # Manipulate the "Device not present" line to create a "state" key.
George Keishinge635ddc2022-12-08 07:38:02 -0600423 ret_values = re.sub("Device not present", "state : Device not present",
424 ret_values)
Michael Walsh27b14a62018-05-24 11:05:07 -0500425
George Keishinge635ddc2022-12-08 07:38:02 -0600426 return [vf.key_value_outbuf_to_dict(x) for x in re.split("\n\n",
427 ret_values)]
Michael Walsh61224e62018-05-30 17:58:42 -0500428
429
George Keishinge635ddc2022-12-08 07:38:02 -0600430def get_component_fru_info(component='cpu',
431 fru_objs=None):
Michael Walsh61224e62018-05-30 17:58:42 -0500432 r"""
433 Get fru info for the given component and return it as a list of
434 dictionaries.
435
436 This function calls upon get_fru_info and then filters out the unwanted
437 entries. See get_fru_info's prolog for a layout of the data.
438
439 Description of argument(s):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500440 component The component (e.g. "cpu", "dimm", etc.).
441 fru_objs A fru_objs list such as the one returned
442 by get_fru_info. If this is None, then
443 this function will call get_fru_info to
444 obtain such a list.
445 Supplying this argument may improve
446 performance if this function is to be
447 called multiple times.
Michael Walsh61224e62018-05-30 17:58:42 -0500448 """
449
Michael Walsha95e4ef2018-06-06 17:53:04 -0500450 if fru_objs is None:
451 fru_objs = get_fru_info()
George Keishinge635ddc2022-12-08 07:38:02 -0600452 return\
453 [x for x in fru_objs
454 if re.match(component + '([0-9]+)? ', x['fru_device_description'])]
Rahul Maheshwari24e0e792019-02-12 22:40:23 -0600455
456
457def get_user_info(userid, channel_number=1):
458 r"""
459 Get user info using channel command and return it as a dictionary.
460
461 Description of argument(s):
462 userid The userid (e.g. "1", "2", etc.).
463 channel_number The user's channel number (e.g. "1").
464
Michael Walshe733b262019-12-09 11:45:24 -0600465 Note: If userid is blank, this function will return a list of dictionaries. Each list entry represents
466 one userid record.
467
Rahul Maheshwari24e0e792019-02-12 22:40:23 -0600468 The data is obtained by issuing the IPMI "channel getaccess" command. An
469 example is shown below for user id 1 and channel number 1.
470
471 Maximum User IDs : 15
472 Enabled User IDs : 1
473 User ID : 1
474 User Name : root
475 Fixed Name : No
476 Access Available : callback
477 Link Authentication : enabled
478 IPMI Messaging : enabled
479 Privilege Level : ADMINISTRATOR
480 Enable Status : enabled
481
482 For the data shown above, the following dictionary will be returned.
483
484 user_info:
485 [maximum_userids]: 15
486 [enabled_userids: 1
487 [userid] 1
488 [user_name] root
489 [fixed_name] No
490 [access_available] callback
491 [link_authentication] enabled
492 [ipmi_messaging] enabled
493 [privilege_level] ADMINISTRATOR
494 [enable_status] enabled
Rahul Maheshwari24e0e792019-02-12 22:40:23 -0600495 """
496
George Keishinge635ddc2022-12-08 07:38:02 -0600497 status, ret_values = grk.run_key_u("Run IPMI Standard Command channel getaccess "
498 + str(channel_number) + " " + str(userid))
Rahul Maheshwari24e0e792019-02-12 22:40:23 -0600499
Michael Walshe733b262019-12-09 11:45:24 -0600500 if userid == "":
501 return vf.key_value_outbuf_to_dicts(ret_values, process_indent=1)
502 else:
503 return vf.key_value_outbuf_to_dict(ret_values, process_indent=1)
George Keishing45511e82019-10-15 01:26:55 -0500504
505
506def channel_getciphers_ipmi():
George Keishinge635ddc2022-12-08 07:38:02 -0600507
George Keishing45511e82019-10-15 01:26:55 -0500508 r"""
509 Run 'channel getciphers ipmi' command and return the result as a list of dictionaries.
510
511 Example robot code:
512 ${ipmi_channel_ciphers}= Channel Getciphers IPMI
513 Rprint Vars ipmi_channel_ciphers
514
515 Example output:
516 ipmi_channel_ciphers:
517 [0]:
518 [id]: 3
519 [iana]: N/A
520 [auth_alg]: hmac_sha1
521 [integrity_alg]: hmac_sha1_96
522 [confidentiality_alg]: aes_cbc_128
523 [1]:
524 [id]: 17
525 [iana]: N/A
526 [auth_alg]: hmac_sha256
527 [integrity_alg]: sha256_128
528 [confidentiality_alg]: aes_cbc_128
529 """
530
531 cmd_buf = "channel getciphers ipmi | sed -re 's/ Alg/_Alg/g'"
532 stdout, stderr, rc = execute_ipmi_cmd(cmd_buf, "external", print_output=0)
533 return vf.outbuf_to_report(stdout)
Tony Lee9bca44b2019-12-13 09:34:26 +0800534
535
536def get_device_id_config():
537 r"""
538 Get the device id config data and return as a dictionary.
539
540 Example:
541
542 dev_id_config = get_device_id_config()
543 print_vars(dev_id_config)
544
545 dev_id_config:
546 [manuf_id]: 7244
547 [addn_dev_support]: 141
548 [prod_id]: 16976
549 [aux]: 0
550 [id]: 32
551 [revision]: 129
552 [device_revision]: 1
553 """
George Keishinge635ddc2022-12-08 07:38:02 -0600554 stdout, stderr, rc = bsu.bmc_execute_command("cat /usr/share/ipmi-providers/dev_id.json")
Tony Lee9bca44b2019-12-13 09:34:26 +0800555
556 result = json.loads(stdout)
557
558 # Create device revision field for the user.
559 # Reference IPMI specification v2.0 "Get Device ID Command"
560 # [7] 1 = device provides Device SDRs
561 # 0 = device does not provide Device SDRs
562 # [6:4] reserved. Return as 0.
563 # [3:0] Device Revision, binary encoded.
564
George Keishinge635ddc2022-12-08 07:38:02 -0600565 result['device_revision'] = result['revision'] & 0x0F
Tony Lee9bca44b2019-12-13 09:34:26 +0800566
567 return result
Rahul Maheshwari02ea62c2020-02-21 05:06:13 -0600568
569
570def get_chassis_status():
571 r"""
572 Get IPMI chassis status data and return it as a dictionary.
573
574 The data is obtained by issuing the IPMI "chassis status" command. An
575 example is shown below:
576
577 System Power : off
578 Power Overload : false
579 Power Interlock : inactive
580 Main Power Fault : false
581 Power Control Fault : false
582 Power Restore Policy : previous
583 Last Power Event :
584 Chassis Intrusion : inactive
585 Front-Panel Lockout : inactive
586 Drive Fault : false
587 Cooling/Fan Fault : false
588 Sleep Button Disable : not allowed
589 Diag Button Disable : not allowed
590 Reset Button Disable : not allowed
591 Power Button Disable : allowed
592 Sleep Button Disabled : false
593 Diag Button Disabled : false
594 Reset Button Disabled : false
595 Power Button Disabled : false
596
597 For the data shown above, the following dictionary will be returned.
598
599 chassis_status:
600 [system_power]: off
601 [power_overload]: false
602 [power_interlock]: inactive
603 [main_power_fault]: false
604 [power_control_fault]: false
605 [power_restore_policy]: previous
606 [last_power_event]:
607 [chassis_intrusion]: inactive
608 [front-panel_lockout]: inactive
609 [drive_fault]: false
610 [cooling/fan_fault]: false
611 [sleep_button_disable]: not allowed
612 [diag_button_disable]: not allowed
613 [reset_button_disable]: not allowed
614 [power_button_disable]: allowed
615 [sleep_button_disabled]: false
616 [diag_button_disabled]: false
617 [reset_button_disabled]: false
618 [power_button_disabled]: false
619 """
620
George Keishinge635ddc2022-12-08 07:38:02 -0600621 status, ret_values = \
622 grk.run_key_u("Run IPMI Standard Command chassis status")
Rahul Maheshwari02ea62c2020-02-21 05:06:13 -0600623 result = vf.key_value_outbuf_to_dict(ret_values, process_indent=1)
624
625 return result
Tony Lee18c6f9a2020-02-18 17:00:20 +0800626
627
628def get_channel_info(channel_number=1):
629 r"""
630 Get the channel info and return as a dictionary.
631 Example:
632
633 channel_info:
634 [channel_0x2_info]:
635 [channel_medium_type]: 802.3 LAN
636 [channel_protocol_type]: IPMB-1.0
637 [session_support]: multi-session
638 [active_session_count]: 0
639 [protocol_vendor_id]: 7154
Tony Lee87c9cb92020-03-04 14:47:09 +0800640 [volatile(active)_settings]:
Tony Lee18c6f9a2020-02-18 17:00:20 +0800641 [alerting]: enabled
642 [per-message_auth]: enabled
643 [user_level_auth]: enabled
644 [access_mode]: always available
Tony Lee87c9cb92020-03-04 14:47:09 +0800645 [non-volatile_settings]:
Tony Lee18c6f9a2020-02-18 17:00:20 +0800646 [alerting]: enabled
647 [per-message_auth]: enabled
648 [user_level_auth]: enabled
649 [access_mode]: always available
650 """
651
George Keishinge635ddc2022-12-08 07:38:02 -0600652 status, ret_values = \
653 grk.run_key_u("Run IPMI Standard Command channel info " + str(channel_number))
Tony Lee87c9cb92020-03-04 14:47:09 +0800654 key_var_list = list(filter(None, ret_values.split("\n")))
655 # To match the dict format, add a colon after 'Volatile(active) Settings' and 'Non-Volatile Settings'
656 # respectively.
George Keishinge635ddc2022-12-08 07:38:02 -0600657 key_var_list[6] = 'Volatile(active) Settings:'
658 key_var_list[11] = 'Non-Volatile Settings:'
Tony Lee87c9cb92020-03-04 14:47:09 +0800659 result = vf.key_value_list_to_dict(key_var_list, process_indent=1)
Tony Lee18c6f9a2020-02-18 17:00:20 +0800660 return result
Tony Lee3d351ee2020-02-19 10:21:04 +0800661
662
663def get_user_access_ipmi(channel_number=1):
George Keishinge635ddc2022-12-08 07:38:02 -0600664
Tony Lee3d351ee2020-02-19 10:21:04 +0800665 r"""
666 Run 'user list [<channel number>]' command and return the result as a list of dictionaries.
667
668 Example robot code:
669 ${users_access}= user list 1
670 Rprint Vars users_access
671
672 Example output:
673 users:
674 [0]:
675 [id]: 1
676 [name]: root
677 [callin]: false
678 [link]: true
679 [auth]: true
680 [ipmi]: ADMINISTRATOR
681 [1]:
682 [id]: 2
683 [name]: axzIDwnz
684 [callin]: true
685 [link]: false
686 [auth]: true
687 [ipmi]: ADMINISTRATOR
688 """
689
690 cmd_buf = "user list " + str(channel_number)
691 stdout, stderr, rc = execute_ipmi_cmd(cmd_buf, "external", print_output=0)
692 return vf.outbuf_to_report(stdout)
Tony Lee0754c5f2020-03-13 19:38:24 +0800693
694
nagarjunb2298450742022-04-19 12:00:02 +0530695def get_channel_auth_capabilities(channel_number=1, privilege_level=4):
Tony Lee0754c5f2020-03-13 19:38:24 +0800696 r"""
697 Get the channel authentication capabilities and return as a dictionary.
698
699 Example:
700
701 channel_auth_cap:
702 [channel_number]: 2
703 [ipmi_v1.5__auth_types]:
704 [kg_status]: default (all zeroes)
705 [per_message_authentication]: enabled
706 [user_level_authentication]: enabled
707 [non-null_user_names_exist]: yes
708 [null_user_names_exist]: no
709 [anonymous_login_enabled]: no
710 [channel_supports_ipmi_v1.5]: no
711 [channel_supports_ipmi_v2.0]: yes
712 """
713
George Keishinge635ddc2022-12-08 07:38:02 -0600714 status, ret_values = \
715 grk.run_key_u("Run IPMI Standard Command channel authcap " + str(channel_number) + " "
716 + str(privilege_level))
Tony Lee0754c5f2020-03-13 19:38:24 +0800717 result = vf.key_value_outbuf_to_dict(ret_values, process_indent=1)
718
719 return result
chithrag0a8c8782022-03-01 12:35:00 +0000720
721
722def fetch_date(date):
723 r"""
724 Removes prefix 0 in a date in given date
725
726 Example : 08/12/2021 then returns 8/12/2021
727 """
728
729 date = date.lstrip("0")
730 return date
731
732
733def fetch_added_sel_date(entry):
734 r"""
735 Split sel entry string with with | and join only the date with space
736
737 Example : If entry given is, "a | 02/14/2020 | 01:16:58 | Sensor_type #0x17 | | Asserted"
738 Then the result will be "02/14/2020 01:16:58"
739 """
740
741 temp = entry.split(" | ")
742 date = temp[1] + " " + temp[2]
743 print(date)
744 return date
745
746
747def prefix_bytes(listx):
748 r"""
749 prefixes byte strings in list
750
751 Example:
752 ${listx} = ['01', '02', '03']
753 ${listx}= Prefix Bytes ${listx}
754 then,
755 ${listx}= ['0x01', '0x02', '0x03']
756
757 """
758
759 listy = []
760 for item in listx:
761 item = "0x" + item
762 listy.append(item)
763 return listy
chithragff43db92022-03-01 13:13:48 +0000764
765
chithrag6b279b32022-05-05 08:28:05 +0000766def modify_and_fetch_threshold(old_threshold, threshold_list):
chithragff43db92022-03-01 13:13:48 +0000767 r"""
chithragff43db92022-03-01 13:13:48 +0000768 Description of argument(s):
769
chithrag6b279b32022-05-05 08:28:05 +0000770 old_threshold List of threshold values of sensor,
chithragff43db92022-03-01 13:13:48 +0000771 threshold_list List of higher and lower of critical and non-critical values.
chithrag6b279b32022-05-05 08:28:05 +0000772 i,e [ "lcr", "lnc", "unc", "ucr" ]
773
774 Gets old threshold values from sensor and threshold levels,
775 then returns the list of new threshold and the dict of threshold levels
chithragff43db92022-03-01 13:13:48 +0000776
777 For example :
chithrag6b279b32022-05-05 08:28:05 +0000778 1. If old_threshold list is [ 1, 2, 3, 4] then the newthreshold_list will be [ 101, 102, 103, 104 ].
779 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 +0000780
chithrag6b279b32022-05-05 08:28:05 +0000781 2. The newthreshold_list will be zipped to dictionary with threshold_list levels,
782 Example : threshold_dict = { 'lcr': 101, 'lnc': 102, 'unc': 103, 'ucr': 104 }
783
chithragff43db92022-03-01 13:13:48 +0000784 """
785
chithrag6b279b32022-05-05 08:28:05 +0000786 # Adding the difference of 100 as less than this value,
787 # may not have greater impact as the sensor considered is a fan sensor.
788 # The set threshold may round off for certain values below 100.
chithragff43db92022-03-01 13:13:48 +0000789 n = 100
790 newthreshold_list = []
791 for th in old_threshold:
792 th = th.strip()
George Keishinge635ddc2022-12-08 07:38:02 -0600793 if th == 'na':
794 newthreshold_list.append('na')
chithragff43db92022-03-01 13:13:48 +0000795 else:
796 x = int(float(th)) + n
797 newthreshold_list.append(x)
798 n = n + 100
799 threshold_dict = dict(zip(threshold_list, newthreshold_list))
800 return newthreshold_list, threshold_dict