blob: a9bebd764bf7628b9ccff69d9afab526cf284542 [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
ishwaryamathim372cd862023-11-14 18:12:23 +000053 status, ret_values = grk.run_key_u(
54 "Run External IPMI Standard Command sol info"
55 )
Michael Walshed5b46e2017-05-24 11:49:14 -050056
57 # Create temp file path.
58 temp = tempfile.NamedTemporaryFile()
59 temp_file_path = temp.name
60
61 # Write sol info to temp file path.
62 text_file = open(temp_file_path, "w")
63 text_file.write(ret_values)
64 text_file.close()
65
66 # Use my_parm_file to interpret data.
67 sol_info = gm.my_parm_file(temp_file_path)
68
69 return sol_info
70
Rahul Maheshwarid629b5c2017-05-23 08:06:28 -050071
Rahul Maheshwarid629b5c2017-05-23 08:06:28 -050072def set_sol_setting(setting_name, setting_value):
Rahul Maheshwarid629b5c2017-05-23 08:06:28 -050073 r"""
74 Set SOL setting with given value.
75
76 # Description of argument(s):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -050077 # setting_name SOL setting which needs to be set (e.g.
78 # "retry-count").
79 # setting_value Value which needs to be set (e.g. "7").
Rahul Maheshwarid629b5c2017-05-23 08:06:28 -050080 """
81
Patrick Williams20f38712022-12-08 06:18:26 -060082 status, ret_values = grk.run_key_u(
ishwaryamathim372cd862023-11-14 18:12:23 +000083 "Run External IPMI Standard Command sol set "
Patrick Williams20f38712022-12-08 06:18:26 -060084 + setting_name
85 + " "
86 + setting_value
87 )
Rahul Maheshwarid629b5c2017-05-23 08:06:28 -050088
89 return status
90
Rahul Maheshwarid629b5c2017-05-23 08:06:28 -050091
Patrick Williams20f38712022-12-08 06:18:26 -060092def execute_ipmi_cmd(
93 cmd_string, ipmi_cmd_type="inband", print_output=1, ignore_err=0, **options
94):
Michael Walsh94811f62018-09-05 14:55:12 -050095 r"""
96 Run the given command string as an IPMI command and return the stdout,
97 stderr and the return code.
98
99 Description of argument(s):
100 cmd_string The command string to be run as an IPMI
101 command.
102 ipmi_cmd_type 'inband' or 'external'.
103 print_output If this is set, this function will print
104 the stdout/stderr generated by
105 the IPMI command.
106 ignore_err Ignore error means that a failure
107 encountered by running the command
108 string will not be raised as a python
109 exception.
Michael Walsh19e70c82019-01-23 11:07:15 -0600110 options These are passed directly to the
111 create_ipmi_ext_command_string function.
112 See that function's prolog for details.
Michael Walsh94811f62018-09-05 14:55:12 -0500113 """
114
Patrick Williams20f38712022-12-08 06:18:26 -0600115 if ipmi_cmd_type == "inband":
Michael Walsh94811f62018-09-05 14:55:12 -0500116 IPMI_INBAND_CMD = BuiltIn().get_variable_value("${IPMI_INBAND_CMD}")
117 cmd_buf = IPMI_INBAND_CMD + " " + cmd_string
Patrick Williams20f38712022-12-08 06:18:26 -0600118 return bsu.os_execute_command(
119 cmd_buf, print_out=print_output, ignore_err=ignore_err
120 )
Michael Walsh94811f62018-09-05 14:55:12 -0500121
Patrick Williams20f38712022-12-08 06:18:26 -0600122 if ipmi_cmd_type == "external":
Michael Walsh19e70c82019-01-23 11:07:15 -0600123 cmd_buf = ic.create_ipmi_ext_command_string(cmd_string, **options)
Patrick Williams20f38712022-12-08 06:18:26 -0600124 rc, stdout, stderr = gc.shell_cmd(
125 cmd_buf,
126 print_output=print_output,
127 ignore_err=ignore_err,
128 return_stderr=1,
129 )
Michael Walsh94811f62018-09-05 14:55:12 -0500130 return stdout, stderr, rc
131
132
Patrick Williams20f38712022-12-08 06:18:26 -0600133def get_lan_print_dict(channel_number="", ipmi_cmd_type="external"):
Michael Walsh4481b932018-02-08 11:45:15 -0600134 r"""
135 Get IPMI 'lan print' output and return it as a dictionary.
136
137 Here is an example of the IPMI lan print output:
138
139 Set in Progress : Set Complete
140 Auth Type Support : MD5
141 Auth Type Enable : Callback : MD5
142 : User : MD5
143 : Operator : MD5
144 : Admin : MD5
145 : OEM : MD5
146 IP Address Source : Static Address
147 IP Address : x.x.x.x
148 Subnet Mask : x.x.x.x
149 MAC Address : xx:xx:xx:xx:xx:xx
150 Default Gateway IP : x.x.x.x
151 802.1q VLAN ID : Disabled
152 Cipher Suite Priv Max : Not Available
153 Bad Password Threshold : Not Available
154
155 Given that data, this function will return the following dictionary.
156
157 lan_print_dict:
158 [Set in Progress]: Set Complete
159 [Auth Type Support]: MD5
160 [Auth Type Enable]:
161 [Callback]: MD5
162 [User]: MD5
163 [Operator]: MD5
164 [Admin]: MD5
165 [OEM]: MD5
166 [IP Address Source]: Static Address
167 [IP Address]: x.x.x.x
168 [Subnet Mask]: x.x.x.x
169 [MAC Address]: xx:xx:xx:xx:xx:xx
170 [Default Gateway IP]: x.x.x.x
171 [802.1q VLAN ID]: Disabled
172 [Cipher Suite Priv Max]: Not Available
173 [Bad Password Threshold]: Not Available
174
Michael Walsh94811f62018-09-05 14:55:12 -0500175 Description of argument(s):
176 ipmi_cmd_type The type of ipmi command to use (e.g.
177 'inband', 'external').
Michael Walsh4481b932018-02-08 11:45:15 -0600178 """
179
Tony Leeea741302019-11-08 11:01:58 +0800180 channel_number = str(channel_number)
Michael Walsh4481b932018-02-08 11:45:15 -0600181 # Notice in the example of data above that 'Auth Type Enable' needs some
182 # special processing. We essentially want to isolate its data and remove
183 # the 'Auth Type Enable' string so that key_value_outbuf_to_dict can
184 # process it as a sub-dictionary.
Patrick Williams20f38712022-12-08 06:18:26 -0600185 cmd_buf = (
186 "lan print "
187 + channel_number
188 + " | grep -E '^(Auth Type Enable)"
189 + "?[ ]+: ' | sed -re 's/^(Auth Type Enable)?[ ]+: //g'"
190 )
191 stdout1, stderr, rc = execute_ipmi_cmd(
192 cmd_buf, ipmi_cmd_type, print_output=0
193 )
Michael Walsh4481b932018-02-08 11:45:15 -0600194
195 # Now get the remainder of the data and exclude the lines with no field
196 # names (i.e. the 'Auth Type Enable' sub-fields).
Tony Leeea741302019-11-08 11:01:58 +0800197 cmd_buf = "lan print " + channel_number + " | grep -E -v '^[ ]+: '"
Patrick Williams20f38712022-12-08 06:18:26 -0600198 stdout2, stderr, rc = execute_ipmi_cmd(
199 cmd_buf, ipmi_cmd_type, print_output=0
200 )
Michael Walsh4481b932018-02-08 11:45:15 -0600201
202 # Make auth_type_enable_dict sub-dictionary...
Patrick Williams20f38712022-12-08 06:18:26 -0600203 auth_type_enable_dict = vf.key_value_outbuf_to_dict(
204 stdout1, to_lower=0, underscores=0
205 )
Michael Walsh4481b932018-02-08 11:45:15 -0600206
207 # Create the lan_print_dict...
Patrick Williams20f38712022-12-08 06:18:26 -0600208 lan_print_dict = vf.key_value_outbuf_to_dict(
209 stdout2, to_lower=0, underscores=0
210 )
Michael Walsh4481b932018-02-08 11:45:15 -0600211 # Re-assign 'Auth Type Enable' to contain the auth_type_enable_dict.
Patrick Williams20f38712022-12-08 06:18:26 -0600212 lan_print_dict["Auth Type Enable"] = auth_type_enable_dict
Michael Walsh4481b932018-02-08 11:45:15 -0600213
214 return lan_print_dict
Michael Walshd59ed7c2018-02-15 10:19:38 -0600215
216
Michael Walshf4098fb2018-02-28 10:54:46 -0600217def get_ipmi_power_reading(strip_watts=1):
Michael Walshd59ed7c2018-02-15 10:19:38 -0600218 r"""
219 Get IPMI power reading data and return it as a dictionary.
220
221 The data is obtained by issuing the IPMI "power reading" command. An
222 example is shown below:
223
224 Instantaneous power reading: 234 Watts
225 Minimum during sampling period: 234 Watts
226 Maximum during sampling period: 234 Watts
227 Average power reading over sample period: 234 Watts
228 IPMI timestamp: Thu Jan 1 00:00:00 1970
229 Sampling period: 00000000 Seconds.
230 Power reading state is: deactivated
231
232 For the data shown above, the following dictionary will be returned.
233
234 result:
235 [instantaneous_power_reading]: 238 Watts
236 [minimum_during_sampling_period]: 238 Watts
237 [maximum_during_sampling_period]: 238 Watts
238 [average_power_reading_over_sample_period]: 238 Watts
239 [ipmi_timestamp]: Thu Jan 1 00:00:00 1970
240 [sampling_period]: 00000000 Seconds.
241 [power_reading_state_is]: deactivated
Michael Walshf4098fb2018-02-28 10:54:46 -0600242
243 Description of argument(s):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500244 strip_watts Strip all dictionary values of the
245 trailing " Watts" substring.
Michael Walshd59ed7c2018-02-15 10:19:38 -0600246 """
247
Patrick Williams20f38712022-12-08 06:18:26 -0600248 status, ret_values = grk.run_key_u(
249 "Run IPMI Standard Command dcmi power reading"
250 )
Michael Walshd59ed7c2018-02-15 10:19:38 -0600251 result = vf.key_value_outbuf_to_dict(ret_values)
252
Michael Walshf4098fb2018-02-28 10:54:46 -0600253 if strip_watts:
Patrick Williams20f38712022-12-08 06:18:26 -0600254 result.update((k, re.sub(" Watts$", "", v)) for k, v in result.items())
Michael Walshf4098fb2018-02-28 10:54:46 -0600255
Michael Walshd59ed7c2018-02-15 10:19:38 -0600256 return result
Michael Walshaf5607e2018-02-19 17:37:20 -0600257
258
259def get_mc_info():
Michael Walshaf5607e2018-02-19 17:37:20 -0600260 r"""
261 Get IPMI mc info data and return it as a dictionary.
262
263 The data is obtained by issuing the IPMI "mc info" command. An
264 example is shown below:
265
266 Device ID : 0
267 Device Revision : 0
268 Firmware Revision : 2.01
269 IPMI Version : 2.0
270 Manufacturer ID : 42817
271 Manufacturer Name : Unknown (0xA741)
272 Product ID : 16975 (0x424f)
273 Product Name : Unknown (0x424F)
274 Device Available : yes
275 Provides Device SDRs : yes
276 Additional Device Support :
277 Sensor Device
278 SEL Device
279 FRU Inventory Device
280 Chassis Device
281 Aux Firmware Rev Info :
282 0x00
283 0x00
284 0x00
285 0x00
286
287 For the data shown above, the following dictionary will be returned.
288 mc_info:
289 [device_id]: 0
290 [device_revision]: 0
291 [firmware_revision]: 2.01
292 [ipmi_version]: 2.0
293 [manufacturer_id]: 42817
294 [manufacturer_name]: Unknown (0xA741)
295 [product_id]: 16975 (0x424f)
296 [product_name]: Unknown (0x424F)
297 [device_available]: yes
298 [provides_device_sdrs]: yes
299 [additional_device_support]:
300 [additional_device_support][0]: Sensor Device
301 [additional_device_support][1]: SEL Device
302 [additional_device_support][2]: FRU Inventory Device
303 [additional_device_support][3]: Chassis Device
304 [aux_firmware_rev_info]:
305 [aux_firmware_rev_info][0]: 0x00
306 [aux_firmware_rev_info][1]: 0x00
307 [aux_firmware_rev_info][2]: 0x00
308 [aux_firmware_rev_info][3]: 0x00
309 """
310
Patrick Williams20f38712022-12-08 06:18:26 -0600311 status, ret_values = grk.run_key_u("Run IPMI Standard Command mc info")
Michael Walshaf5607e2018-02-19 17:37:20 -0600312 result = vf.key_value_outbuf_to_dict(ret_values, process_indent=1)
313
314 return result
Rahul Maheshwaridc6a32c2018-03-15 05:21:55 -0500315
316
317def get_sdr_info():
Rahul Maheshwaridc6a32c2018-03-15 05:21:55 -0500318 r"""
319 Get IPMI sdr info data and return it as a dictionary.
320
321 The data is obtained by issuing the IPMI "sdr info" command. An
322 example is shown below:
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 For the data shown above, the following dictionary will be returned.
337 mc_info:
338
339 [sdr_version]: 0x51
340 [record_Count]: 216
341 [free_space]: unspecified
342 [most_recent_addition]:
343 [most_recent_erase]:
344 [sdr_overflow]: no
345 [sdr_repository_update_support]: unspecified
346 [delete_sdr_supported]: no
347 [partial_add_sdr_supported]: no
348 [reserve_sdr_repository_supported]: no
349 [sdr_repository_alloc_info_supported]: no
350 """
351
Patrick Williams20f38712022-12-08 06:18:26 -0600352 status, ret_values = grk.run_key_u("Run IPMI Standard Command sdr info")
Rahul Maheshwaridc6a32c2018-03-15 05:21:55 -0500353 result = vf.key_value_outbuf_to_dict(ret_values, process_indent=1)
354
355 return result
George Keishing3511a3f2018-04-19 10:38:30 -0500356
357
manimozhikdd321652023-11-08 10:22:06 +0000358def fetch_sdr_count(sdr_data):
359 r"""
360 Get IPMI SDR list and return the SDR OEM count.
361
362 The data is obtained by issuing the IPMI "sdr elist -vvv" command. An
363 example is shown below:
364
365 SDR record ID : 0x00cb
366 SDR record ID : 0x00cc
367 SDR record type : 0xc0
368 SDR record next : 0xffff
369 SDR record bytes: 11
370 Getting 11 bytes from SDR at offset 5
371
372 For the data shown above, the SDR record type with 0xc0 count will be returned.
373 """
374
375 data = sdr_data.split("\n")
376 sdr_list = []
377 for i, j in enumerate(data):
378 a = j.split(":")
379 if a[0].strip() == "SDR record type":
380 sdr_list.append(a[1].strip())
381 return sdr_list.count("0xc0")
382
383
George Keishing3511a3f2018-04-19 10:38:30 -0500384def get_aux_version(version_id):
385 r"""
386 Get IPMI Aux version info data and return it.
387
388 Description of argument(s):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500389 version_id The data is obtained by from BMC
390 /etc/os-release
391 (e.g. "xxx-v2.1-438-g0030304-r3-gfea8585").
George Keishing3511a3f2018-04-19 10:38:30 -0500392
393 In the prior example, the 3rd field is "438" is the commit version and
394 the 5th field is "r3" and value "3" is the release version.
395
396 Aux version return from this function 4380003.
397 """
398
399 # Commit version.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500400 count = re.findall("-(\\d{1,4})-", version_id)
George Keishing3511a3f2018-04-19 10:38:30 -0500401
402 # Release version.
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500403 release = re.findall("-r(\\d{1,4})", version_id)
George Keishing3511a3f2018-04-19 10:38:30 -0500404 if release:
405 aux_version = count[0] + "{0:0>4}".format(release[0])
406 else:
407 aux_version = count[0] + "0000"
408
409 return aux_version
Michael Walsh27b14a62018-05-24 11:05:07 -0500410
411
412def get_fru_info():
413 r"""
414 Get fru info and return it as a list of dictionaries.
415
416 The data is obtained by issuing the IPMI "fru print -N 50" command. An
417 example is shown below:
418
419 FRU Device Description : Builtin FRU Device (ID 0)
420 Device not present (Unspecified error)
421
422 FRU Device Description : cpu0 (ID 1)
423 Board Mfg Date : Sun Dec 31 18:00:00 1995
George Keishinge0a81282018-06-08 10:02:30 -0500424 Board Mfg : <Manufacturer Name>
Michael Walsh27b14a62018-05-24 11:05:07 -0500425 Board Product : PROCESSOR MODULE
426 Board Serial : YA1934315964
427 Board Part Number : 02CY209
428
429 FRU Device Description : cpu1 (ID 2)
430 Board Mfg Date : Sun Dec 31 18:00:00 1995
George Keishinge0a81282018-06-08 10:02:30 -0500431 Board Mfg : <Manufacturer Name>
Michael Walsh27b14a62018-05-24 11:05:07 -0500432 Board Product : PROCESSOR MODULE
433 Board Serial : YA1934315965
434 Board Part Number : 02CY209
435
436 For the data shown above, the following list of dictionaries will be
437 returned.
438
439 fru_obj:
440 fru_obj[0]:
441 [fru_device_description]: Builtin FRU Device (ID 0)
442 [state]: Device not present (Unspecified error)
443 fru_obj[1]:
444 [fru_device_description]: cpu0 (ID 1)
445 [board_mfg_date]: Sun Dec 31 18:00:00 1995
George Keishinge0a81282018-06-08 10:02:30 -0500446 [board_mfg]: <Manufacturer Name>
Michael Walsh27b14a62018-05-24 11:05:07 -0500447 [board_product]: PROCESSOR MODULE
448 [board_serial]: YA1934315964
449 [board_part_number]: 02CY209
450 fru_obj[2]:
451 [fru_device_description]: cpu1 (ID 2)
452 [board_mfg_date]: Sun Dec 31 18:00:00 1995
George Keishinge0a81282018-06-08 10:02:30 -0500453 [board_mfg]: <Manufacturer Name>
Michael Walsh27b14a62018-05-24 11:05:07 -0500454 [board_product]: PROCESSOR MODULE
455 [board_serial]: YA1934315965
456 [board_part_number]: 02CY209
457 """
458
Patrick Williams20f38712022-12-08 06:18:26 -0600459 status, ret_values = grk.run_key_u(
460 "Run IPMI Standard Command fru print -N 50"
461 )
Michael Walsh27b14a62018-05-24 11:05:07 -0500462
463 # Manipulate the "Device not present" line to create a "state" key.
Patrick Williams20f38712022-12-08 06:18:26 -0600464 ret_values = re.sub(
465 "Device not present", "state : Device not present", ret_values
466 )
Michael Walsh27b14a62018-05-24 11:05:07 -0500467
Patrick Williams20f38712022-12-08 06:18:26 -0600468 return [
469 vf.key_value_outbuf_to_dict(x) for x in re.split("\n\n", ret_values)
470 ]
Michael Walsh61224e62018-05-30 17:58:42 -0500471
472
Patrick Williams20f38712022-12-08 06:18:26 -0600473def get_component_fru_info(component="cpu", fru_objs=None):
Michael Walsh61224e62018-05-30 17:58:42 -0500474 r"""
475 Get fru info for the given component and return it as a list of
476 dictionaries.
477
478 This function calls upon get_fru_info and then filters out the unwanted
479 entries. See get_fru_info's prolog for a layout of the data.
480
481 Description of argument(s):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500482 component The component (e.g. "cpu", "dimm", etc.).
483 fru_objs A fru_objs list such as the one returned
484 by get_fru_info. If this is None, then
485 this function will call get_fru_info to
486 obtain such a list.
487 Supplying this argument may improve
488 performance if this function is to be
489 called multiple times.
Michael Walsh61224e62018-05-30 17:58:42 -0500490 """
491
Michael Walsha95e4ef2018-06-06 17:53:04 -0500492 if fru_objs is None:
493 fru_objs = get_fru_info()
Patrick Williams20f38712022-12-08 06:18:26 -0600494 return [
495 x
496 for x in fru_objs
497 if re.match(component + "([0-9]+)? ", x["fru_device_description"])
498 ]
Rahul Maheshwari24e0e792019-02-12 22:40:23 -0600499
500
501def get_user_info(userid, channel_number=1):
502 r"""
503 Get user info using channel command and return it as a dictionary.
504
505 Description of argument(s):
506 userid The userid (e.g. "1", "2", etc.).
507 channel_number The user's channel number (e.g. "1").
508
Michael Walshe733b262019-12-09 11:45:24 -0600509 Note: If userid is blank, this function will return a list of dictionaries. Each list entry represents
510 one userid record.
511
Rahul Maheshwari24e0e792019-02-12 22:40:23 -0600512 The data is obtained by issuing the IPMI "channel getaccess" command. An
513 example is shown below for user id 1 and channel number 1.
514
515 Maximum User IDs : 15
516 Enabled User IDs : 1
517 User ID : 1
518 User Name : root
519 Fixed Name : No
520 Access Available : callback
521 Link Authentication : enabled
522 IPMI Messaging : enabled
523 Privilege Level : ADMINISTRATOR
524 Enable Status : enabled
525
526 For the data shown above, the following dictionary will be returned.
527
528 user_info:
529 [maximum_userids]: 15
530 [enabled_userids: 1
531 [userid] 1
532 [user_name] root
533 [fixed_name] No
534 [access_available] callback
535 [link_authentication] enabled
536 [ipmi_messaging] enabled
537 [privilege_level] ADMINISTRATOR
538 [enable_status] enabled
Rahul Maheshwari24e0e792019-02-12 22:40:23 -0600539 """
540
Patrick Williams20f38712022-12-08 06:18:26 -0600541 status, ret_values = grk.run_key_u(
542 "Run IPMI Standard Command channel getaccess "
543 + str(channel_number)
544 + " "
545 + str(userid)
546 )
Rahul Maheshwari24e0e792019-02-12 22:40:23 -0600547
Michael Walshe733b262019-12-09 11:45:24 -0600548 if userid == "":
549 return vf.key_value_outbuf_to_dicts(ret_values, process_indent=1)
550 else:
551 return vf.key_value_outbuf_to_dict(ret_values, process_indent=1)
George Keishing45511e82019-10-15 01:26:55 -0500552
553
554def channel_getciphers_ipmi():
George Keishing45511e82019-10-15 01:26:55 -0500555 r"""
556 Run 'channel getciphers ipmi' command and return the result as a list of dictionaries.
557
558 Example robot code:
559 ${ipmi_channel_ciphers}= Channel Getciphers IPMI
560 Rprint Vars ipmi_channel_ciphers
561
562 Example output:
563 ipmi_channel_ciphers:
564 [0]:
565 [id]: 3
566 [iana]: N/A
567 [auth_alg]: hmac_sha1
568 [integrity_alg]: hmac_sha1_96
569 [confidentiality_alg]: aes_cbc_128
570 [1]:
571 [id]: 17
572 [iana]: N/A
573 [auth_alg]: hmac_sha256
574 [integrity_alg]: sha256_128
575 [confidentiality_alg]: aes_cbc_128
576 """
577
578 cmd_buf = "channel getciphers ipmi | sed -re 's/ Alg/_Alg/g'"
579 stdout, stderr, rc = execute_ipmi_cmd(cmd_buf, "external", print_output=0)
580 return vf.outbuf_to_report(stdout)
Tony Lee9bca44b2019-12-13 09:34:26 +0800581
582
583def get_device_id_config():
584 r"""
585 Get the device id config data and return as a dictionary.
586
587 Example:
588
589 dev_id_config = get_device_id_config()
590 print_vars(dev_id_config)
591
592 dev_id_config:
593 [manuf_id]: 7244
594 [addn_dev_support]: 141
595 [prod_id]: 16976
596 [aux]: 0
597 [id]: 32
598 [revision]: 129
599 [device_revision]: 1
600 """
Patrick Williams20f38712022-12-08 06:18:26 -0600601 stdout, stderr, rc = bsu.bmc_execute_command(
602 "cat /usr/share/ipmi-providers/dev_id.json"
603 )
Tony Lee9bca44b2019-12-13 09:34:26 +0800604
605 result = json.loads(stdout)
606
607 # Create device revision field for the user.
608 # Reference IPMI specification v2.0 "Get Device ID Command"
609 # [7] 1 = device provides Device SDRs
610 # 0 = device does not provide Device SDRs
611 # [6:4] reserved. Return as 0.
612 # [3:0] Device Revision, binary encoded.
613
Patrick Williams20f38712022-12-08 06:18:26 -0600614 result["device_revision"] = result["revision"] & 0x0F
Tony Lee9bca44b2019-12-13 09:34:26 +0800615
616 return result
Rahul Maheshwari02ea62c2020-02-21 05:06:13 -0600617
618
619def get_chassis_status():
620 r"""
621 Get IPMI chassis status data and return it as a dictionary.
622
623 The data is obtained by issuing the IPMI "chassis status" command. An
624 example is shown below:
625
626 System Power : off
627 Power Overload : false
628 Power Interlock : inactive
629 Main Power Fault : false
630 Power Control Fault : false
631 Power Restore Policy : previous
632 Last Power Event :
633 Chassis Intrusion : inactive
634 Front-Panel Lockout : inactive
635 Drive Fault : false
636 Cooling/Fan Fault : false
637 Sleep Button Disable : not allowed
638 Diag Button Disable : not allowed
639 Reset Button Disable : not allowed
640 Power Button Disable : allowed
641 Sleep Button Disabled : false
642 Diag Button Disabled : false
643 Reset Button Disabled : false
644 Power Button Disabled : false
645
646 For the data shown above, the following dictionary will be returned.
647
648 chassis_status:
649 [system_power]: off
650 [power_overload]: false
651 [power_interlock]: inactive
652 [main_power_fault]: false
653 [power_control_fault]: false
654 [power_restore_policy]: previous
655 [last_power_event]:
656 [chassis_intrusion]: inactive
657 [front-panel_lockout]: inactive
658 [drive_fault]: false
659 [cooling/fan_fault]: false
660 [sleep_button_disable]: not allowed
661 [diag_button_disable]: not allowed
662 [reset_button_disable]: not allowed
663 [power_button_disable]: allowed
664 [sleep_button_disabled]: false
665 [diag_button_disabled]: false
666 [reset_button_disabled]: false
667 [power_button_disabled]: false
668 """
669
Patrick Williams20f38712022-12-08 06:18:26 -0600670 status, ret_values = grk.run_key_u(
ishwaryamathim372cd862023-11-14 18:12:23 +0000671 "Run External IPMI Standard Command chassis status"
Patrick Williams20f38712022-12-08 06:18:26 -0600672 )
Rahul Maheshwari02ea62c2020-02-21 05:06:13 -0600673 result = vf.key_value_outbuf_to_dict(ret_values, process_indent=1)
674
675 return result
Tony Lee18c6f9a2020-02-18 17:00:20 +0800676
677
678def get_channel_info(channel_number=1):
679 r"""
680 Get the channel info and return as a dictionary.
681 Example:
682
683 channel_info:
684 [channel_0x2_info]:
685 [channel_medium_type]: 802.3 LAN
686 [channel_protocol_type]: IPMB-1.0
687 [session_support]: multi-session
688 [active_session_count]: 0
689 [protocol_vendor_id]: 7154
Tony Lee87c9cb92020-03-04 14:47:09 +0800690 [volatile(active)_settings]:
Tony Lee18c6f9a2020-02-18 17:00:20 +0800691 [alerting]: enabled
692 [per-message_auth]: enabled
693 [user_level_auth]: enabled
694 [access_mode]: always available
Tony Lee87c9cb92020-03-04 14:47:09 +0800695 [non-volatile_settings]:
Tony Lee18c6f9a2020-02-18 17:00:20 +0800696 [alerting]: enabled
697 [per-message_auth]: enabled
698 [user_level_auth]: enabled
699 [access_mode]: always available
700 """
701
Patrick Williams20f38712022-12-08 06:18:26 -0600702 status, ret_values = grk.run_key_u(
703 "Run IPMI Standard Command channel info " + str(channel_number)
704 )
Tony Lee87c9cb92020-03-04 14:47:09 +0800705 key_var_list = list(filter(None, ret_values.split("\n")))
706 # To match the dict format, add a colon after 'Volatile(active) Settings' and 'Non-Volatile Settings'
707 # respectively.
Patrick Williams20f38712022-12-08 06:18:26 -0600708 key_var_list[6] = "Volatile(active) Settings:"
709 key_var_list[11] = "Non-Volatile Settings:"
Tony Lee87c9cb92020-03-04 14:47:09 +0800710 result = vf.key_value_list_to_dict(key_var_list, process_indent=1)
Tony Lee18c6f9a2020-02-18 17:00:20 +0800711 return result
Tony Lee3d351ee2020-02-19 10:21:04 +0800712
713
714def get_user_access_ipmi(channel_number=1):
Tony Lee3d351ee2020-02-19 10:21:04 +0800715 r"""
716 Run 'user list [<channel number>]' command and return the result as a list of dictionaries.
717
718 Example robot code:
719 ${users_access}= user list 1
720 Rprint Vars users_access
721
722 Example output:
723 users:
724 [0]:
725 [id]: 1
726 [name]: root
727 [callin]: false
728 [link]: true
729 [auth]: true
730 [ipmi]: ADMINISTRATOR
731 [1]:
732 [id]: 2
733 [name]: axzIDwnz
734 [callin]: true
735 [link]: false
736 [auth]: true
737 [ipmi]: ADMINISTRATOR
738 """
739
740 cmd_buf = "user list " + str(channel_number)
741 stdout, stderr, rc = execute_ipmi_cmd(cmd_buf, "external", print_output=0)
742 return vf.outbuf_to_report(stdout)
Tony Lee0754c5f2020-03-13 19:38:24 +0800743
744
nagarjunb2298450742022-04-19 12:00:02 +0530745def get_channel_auth_capabilities(channel_number=1, privilege_level=4):
Tony Lee0754c5f2020-03-13 19:38:24 +0800746 r"""
747 Get the channel authentication capabilities and return as a dictionary.
748
749 Example:
750
751 channel_auth_cap:
752 [channel_number]: 2
753 [ipmi_v1.5__auth_types]:
754 [kg_status]: default (all zeroes)
755 [per_message_authentication]: enabled
756 [user_level_authentication]: enabled
757 [non-null_user_names_exist]: yes
758 [null_user_names_exist]: no
759 [anonymous_login_enabled]: no
760 [channel_supports_ipmi_v1.5]: no
761 [channel_supports_ipmi_v2.0]: yes
762 """
763
Patrick Williams20f38712022-12-08 06:18:26 -0600764 status, ret_values = grk.run_key_u(
765 "Run IPMI Standard Command channel authcap "
766 + str(channel_number)
767 + " "
768 + str(privilege_level)
769 )
Tony Lee0754c5f2020-03-13 19:38:24 +0800770 result = vf.key_value_outbuf_to_dict(ret_values, process_indent=1)
771
772 return result
chithrag0a8c8782022-03-01 12:35:00 +0000773
774
775def fetch_date(date):
776 r"""
777 Removes prefix 0 in a date in given date
778
779 Example : 08/12/2021 then returns 8/12/2021
780 """
781
782 date = date.lstrip("0")
783 return date
784
785
786def fetch_added_sel_date(entry):
787 r"""
788 Split sel entry string with with | and join only the date with space
789
790 Example : If entry given is, "a | 02/14/2020 | 01:16:58 | Sensor_type #0x17 | | Asserted"
791 Then the result will be "02/14/2020 01:16:58"
792 """
793
794 temp = entry.split(" | ")
795 date = temp[1] + " " + temp[2]
796 print(date)
797 return date
798
799
800def prefix_bytes(listx):
801 r"""
802 prefixes byte strings in list
803
804 Example:
805 ${listx} = ['01', '02', '03']
806 ${listx}= Prefix Bytes ${listx}
807 then,
808 ${listx}= ['0x01', '0x02', '0x03']
809
810 """
811
812 listy = []
813 for item in listx:
814 item = "0x" + item
815 listy.append(item)
816 return listy
chithragff43db92022-03-01 13:13:48 +0000817
818
chithrag6b279b32022-05-05 08:28:05 +0000819def modify_and_fetch_threshold(old_threshold, threshold_list):
chithragff43db92022-03-01 13:13:48 +0000820 r"""
chithragff43db92022-03-01 13:13:48 +0000821 Description of argument(s):
822
chithrag6b279b32022-05-05 08:28:05 +0000823 old_threshold List of threshold values of sensor,
chithragff43db92022-03-01 13:13:48 +0000824 threshold_list List of higher and lower of critical and non-critical values.
chithrag6b279b32022-05-05 08:28:05 +0000825 i,e [ "lcr", "lnc", "unc", "ucr" ]
826
827 Gets old threshold values from sensor and threshold levels,
828 then returns the list of new threshold and the dict of threshold levels
chithragff43db92022-03-01 13:13:48 +0000829
830 For example :
chithrag6b279b32022-05-05 08:28:05 +0000831 1. If old_threshold list is [ 1, 2, 3, 4] then the newthreshold_list will be [ 101, 102, 103, 104 ].
832 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 +0000833
chithrag6b279b32022-05-05 08:28:05 +0000834 2. The newthreshold_list will be zipped to dictionary with threshold_list levels,
835 Example : threshold_dict = { 'lcr': 101, 'lnc': 102, 'unc': 103, 'ucr': 104 }
836
chithragff43db92022-03-01 13:13:48 +0000837 """
838
chithrag6b279b32022-05-05 08:28:05 +0000839 # Adding the difference of 100 as less than this value,
840 # may not have greater impact as the sensor considered is a fan sensor.
841 # The set threshold may round off for certain values below 100.
chithragff43db92022-03-01 13:13:48 +0000842 n = 100
843 newthreshold_list = []
844 for th in old_threshold:
845 th = th.strip()
Patrick Williams20f38712022-12-08 06:18:26 -0600846 if th == "na":
847 newthreshold_list.append("na")
chithragff43db92022-03-01 13:13:48 +0000848 else:
849 x = int(float(th)) + n
850 newthreshold_list.append(x)
851 n = n + 100
852 threshold_dict = dict(zip(threshold_list, newthreshold_list))
853 return newthreshold_list, threshold_dict