blob: d9d39a302edd1f29ef2fccaafcfa7d71058361e0 [file] [log] [blame]
George Keishinge7e91712021-09-03 11:28:44 -05001#!/usr/bin/env python3
Michael Walshfdc5ced2017-08-17 13:15:15 -05002
3r"""
4Companion file to utils.robot.
5"""
6
George Keishinge635ddc2022-12-08 07:38:02 -06007import collections
Patrick Williams20f38712022-12-08 06:18:26 -06008import json
9import os
10
11import bmc_ssh_utils as bsu
Michael Walshfdc5ced2017-08-17 13:15:15 -050012import gen_print as gp
13import gen_robot_keyword as grk
Michael Walshf880ac62017-11-10 11:29:37 -060014import var_funcs as vf
George Keishinge635ddc2022-12-08 07:38:02 -060015from robot.libraries import DateTime
Patrick Williams20f38712022-12-08 06:18:26 -060016from robot.libraries.BuiltIn import BuiltIn
17
Michael Walshf880ac62017-11-10 11:29:37 -060018try:
19 from robot.utils import DotDict
20except ImportError:
21 pass
ganesanb07958e12023-04-26 05:38:22 -070022import re
Michael Walshfdc5ced2017-08-17 13:15:15 -050023
Sushil Singh6624ce52020-01-22 00:53:41 -060024# The code base directory will be one level up from the directory containing this module.
25code_base_dir_path = os.path.dirname(os.path.dirname(__file__)) + os.sep
26
27
28def get_code_base_dir_path():
29 r"""
30 Return the dir path of our code base.
31 """
32
33 return code_base_dir_path
34
35
Michael Walshfdc5ced2017-08-17 13:15:15 -050036def set_power_policy_method():
Michael Walshfdc5ced2017-08-17 13:15:15 -050037 r"""
38 Set the global bmc_power_policy_method to either 'Old' or 'New'.
39
40 The power policy data has moved from an 'org' location to an 'xyz'
41 location. This keyword will determine whether the new method of getting
42 the power policy is valid and will set the global bmc_power_policy_method
43 variable accordingly. If power_policy_setup is already set (by a prior
44 call to this function), this keyword will simply return.
45
46 If bmc_power_policy_method is "Old", this function will adjust the global
47 policy variables from data/variables.py: RESTORE_LAST_STATE,
48 ALWAYS_POWER_ON, ALWAYS_POWER_OFF.
49 """
50
51 # Retrieve global variables.
Patrick Williams20f38712022-12-08 06:18:26 -060052 power_policy_setup = int(
53 BuiltIn().get_variable_value("${power_policy_setup}", default=0)
54 )
55 bmc_power_policy_method = BuiltIn().get_variable_value(
56 "${bmc_power_policy_method}", default=0
57 )
Michael Walshfdc5ced2017-08-17 13:15:15 -050058 gp.dpvar(power_policy_setup)
59
60 # If this function has already been run once, we need not continue.
61 if power_policy_setup:
62 return
63
64 gp.dpvar(bmc_power_policy_method, 1)
65
66 # The user has not set bmc_power_policy_method via a -v parm so we will
67 # determine what it should be.
68 if bmc_power_policy_method == "":
69 status, ret_values = grk.run_key_u("New Get Power Policy", ignore=1)
Patrick Williams20f38712022-12-08 06:18:26 -060070 if status == "PASS":
71 bmc_power_policy_method = "New"
Michael Walshfdc5ced2017-08-17 13:15:15 -050072 else:
Patrick Williams20f38712022-12-08 06:18:26 -060073 bmc_power_policy_method = "Old"
Michael Walshfdc5ced2017-08-17 13:15:15 -050074
75 gp.qpvar(bmc_power_policy_method)
76 # For old style, we will rewrite these global variable settings to old
77 # values.
78 if bmc_power_policy_method == "Old":
Patrick Williams20f38712022-12-08 06:18:26 -060079 BuiltIn().set_global_variable(
80 "${RESTORE_LAST_STATE}", "RESTORE_LAST_STATE"
81 )
82 BuiltIn().set_global_variable("${ALWAYS_POWER_ON}", "ALWAYS_POWER_ON")
83 BuiltIn().set_global_variable(
84 "${ALWAYS_POWER_OFF}", "ALWAYS_POWER_OFF"
85 )
Michael Walshfdc5ced2017-08-17 13:15:15 -050086
87 # Set global variables to control subsequent calls to this function.
Patrick Williams20f38712022-12-08 06:18:26 -060088 BuiltIn().set_global_variable(
89 "${bmc_power_policy_method}", bmc_power_policy_method
90 )
Michael Walshfdc5ced2017-08-17 13:15:15 -050091 BuiltIn().set_global_variable("${power_policy_setup}", 1)
92
93
Michael Walshfdc5ced2017-08-17 13:15:15 -050094def translate_power_policy_value(policy):
Michael Walshfdc5ced2017-08-17 13:15:15 -050095 r"""
96 Translate the policy value and return the result.
97
98 Using old style functions, callers might call like this with a hard-
99 code value for policy:
100
George Keishingefc3ff22017-12-12 11:49:25 -0600101 Set BMC Power Policy ALWAYS_POWER_OFF
Michael Walshfdc5ced2017-08-17 13:15:15 -0500102
103 This function will get the value of the corresponding global variable (if
104 it exists) and return it.
105
106 This will allow the old style call to still work on systems using the new
107 method of storing the policy value.
108 """
109
Patrick Williams20f38712022-12-08 06:18:26 -0600110 valid_power_policy_vars = BuiltIn().get_variable_value(
111 "${valid_power_policy_vars}"
112 )
Michael Walshfdc5ced2017-08-17 13:15:15 -0500113
114 if policy not in valid_power_policy_vars:
115 return policy
116
Patrick Williams20f38712022-12-08 06:18:26 -0600117 status, ret_values = grk.run_key_u(
118 "Get Variable Value ${" + policy + "}", quiet=1
119 )
Michael Walshfdc5ced2017-08-17 13:15:15 -0500120 return ret_values
121
Michael Walshf880ac62017-11-10 11:29:37 -0600122
Michael Walshf880ac62017-11-10 11:29:37 -0600123def get_bmc_date_time():
Michael Walshf880ac62017-11-10 11:29:37 -0600124 r"""
125 Get date/time info from BMC and return as a dictionary.
126
127 Example of dictionary data returned by this keyword.
128 time_dict:
129 [local_time]: Fri 2017-11-03 152756 UTC
130 [local_time_seconds]: 1509740876
131 [universal_time]: Fri 2017-11-03 152756 UTC
132 [universal_time_seconds]: 1509740876
133 [rtc_time]: Fri 2016-05-20 163403
134 [rtc_time_seconds]: 1463780043
135 [time_zone]: n/a (UTC, +0000)
136 [network_time_on]: yes
137 [ntp_synchronized]: no
138 [rtc_in_local_tz]: no
139 """
140
Patrick Williams20f38712022-12-08 06:18:26 -0600141 out_buf, stderr, rc = bsu.bmc_execute_command("timedatectl")
Michael Walshf880ac62017-11-10 11:29:37 -0600142 # Example of output returned by call to timedatectl:
143 # Local time: Fri 2017-11-03 15:27:56 UTC
144 # Universal time: Fri 2017-11-03 15:27:56 UTC
145 # RTC time: Fri 2016-05-20 16:34:03
146 # Time zone: n/a (UTC, +0000)
147 # Network time on: yes
148 # NTP synchronized: no
149 # RTC in local TZ: no
150
151 # Convert the out_buf to a dictionary.
152 initial_time_dict = vf.key_value_outbuf_to_dict(out_buf)
153
154 # For each "_time" entry in the dictionary, we will create a corresponding
155 # "_time_seconds" entry. We create a new dictionary so that the entries
156 # are kept in a nice order for printing.
157 try:
158 result_time_dict = collections.OrderedDict()
159 except AttributeError:
160 result_time_dict = DotDict()
161
162 for key, value in initial_time_dict.items():
163 result_time_dict[key] = value
164 if not key.endswith("_time"):
165 continue
Patrick Williams20f38712022-12-08 06:18:26 -0600166 result_time_dict[key + "_seconds"] = int(
167 DateTime.convert_date(value, result_format="epoch")
168 )
Michael Walshf880ac62017-11-10 11:29:37 -0600169
170 return result_time_dict
171
Michael Walsh193743e2017-11-20 16:43:31 -0600172
173def get_bmc_df(df_parm_string=""):
Michael Walsh193743e2017-11-20 16:43:31 -0600174 r"""
Patrick Williams20f38712022-12-08 06:18:26 -0600175 Get df report from BMC and return as a report "object".
Michael Walsh193743e2017-11-20 16:43:31 -0600176
Patrick Williams20f38712022-12-08 06:18:26 -0600177 A df report object is a list where each entry is a dictionary whose keys
178 are the field names from the first entry in report_list.
Michael Walsh193743e2017-11-20 16:43:31 -0600179
Patrick Williams20f38712022-12-08 06:18:26 -0600180 Example df report object:
Michael Walsh193743e2017-11-20 16:43:31 -0600181
Patrick Williams20f38712022-12-08 06:18:26 -0600182 df_report:
183 df_report[0]:
184 [filesystem]: dev
185 [1k-blocks]: 247120
186 [used]: 0
187 [available]: 247120
188 [use%]: 0%
189 [mounted]: /dev
190 df_report[1]:
191 [filesystem]: dev
192 [1k-blocks]: 247120
193 [used]: 0
194 [available]: 247120
195 [use%]: 0%
196 [mounted]: /dev
Michael Walsh193743e2017-11-20 16:43:31 -0600197
Patrick Williams20f38712022-12-08 06:18:26 -0600198 . Description of argument(s):
199 df_parm_string A string containing valid df command parms (e.g.
200 "-h /var").
Michael Walsh193743e2017-11-20 16:43:31 -0600201 """
202
203 out_buf, stderr, rc = bsu.bmc_execute_command("df " + df_parm_string)
204 return vf.outbuf_to_report(out_buf)
George Keishing6f407b92018-01-16 02:21:47 -0600205
206
Sridevi Ramesha618f672025-03-27 08:10:11 -0500207def get_sbe(cfam_addrs):
George Keishing6f407b92018-01-16 02:21:47 -0600208 r"""
209 Return CFAM value which contains such things as SBE side bit.
Sridevi Ramesha618f672025-03-27 08:10:11 -0500210
211 Description of argument(s):
212 cfam_addrs Provide the CFAM address
George Keishing6f407b92018-01-16 02:21:47 -0600213 """
214
Sridevi Ramesha618f672025-03-27 08:10:11 -0500215 cmd_buf = (
216 "pdbg -d p9w -p0 getcfam " + cfam_addrs + " | sed -re 's/.* = //g'"
217 )
George Keishing6f407b92018-01-16 02:21:47 -0600218 out_buf, stderr, rc = bsu.bmc_execute_command(cmd_buf)
219
220 return int(out_buf, 16)
221
George Keishingbf724772018-02-21 08:57:16 -0600222
Gunnar Mills096cd562018-03-26 10:19:12 -0500223def compare_mac_address(sys_mac_addr, user_mac_addr):
George Keishingbf724772018-02-21 08:57:16 -0600224 r"""
Patrick Williams20f38712022-12-08 06:18:26 -0600225 Return 1 if the MAC value matched, otherwise 0.
George Keishingbf724772018-02-21 08:57:16 -0600226
Patrick Williams20f38712022-12-08 06:18:26 -0600227 . Description of argument(s):
228 sys_mac_addr A valid system MAC string (e.g. "70:e2:84:14:2a:08")
229 user_mac_addr A user provided MAC string (e.g. "70:e2:84:14:2a:08")
George Keishingbf724772018-02-21 08:57:16 -0600230 """
231
232 index = 0
233 # Example: ['70', 'e2', '84', '14', '2a', '08']
234 mac_list = user_mac_addr.split(":")
235 for item in sys_mac_addr.split(":"):
236 if int(item, 16) == int(mac_list[index], 16):
237 index = index + 1
238 continue
239 return 0
240
241 return 1
Michael Walsh7847ece2018-04-12 11:37:45 -0500242
243
244def get_os_ethtool(interface_name):
245 r"""
246 Get OS 'ethtool' output for the given interface_name and return it as a
247 dictionary.
248
249 Settings for enP52p1s0f0:
250 Supported ports: [ TP ]
251 Supported link modes: 10baseT/Half 10baseT/Full
252 100baseT/Half 100baseT/Full
253 1000baseT/Half 1000baseT/Full
254 Supported pause frame use: No
255 Supports auto-negotiation: Yes
256 Supported FEC modes: Not reported
257 Advertised link modes: 10baseT/Half 10baseT/Full
258 100baseT/Half 100baseT/Full
259 1000baseT/Half 1000baseT/Full
260 Advertised pause frame use: Symmetric
261 Advertised auto-negotiation: Yes
262 Advertised FEC modes: Not reported
263 Speed: Unknown!
264 Duplex: Unknown! (255)
265 Port: Twisted Pair
266 PHYAD: 1
267 Transceiver: internal
268 Auto-negotiation: on
269 MDI-X: Unknown
270 Supports Wake-on: g
271 Wake-on: g
272 Current message level: 0x000000ff (255)
273 drv probe link timer ifdown ifup rx_err tx_err
274 Link detected: no
275
276 Given that data, this function will return the following dictionary.
277
278 ethtool_dict:
279 [supported_ports]: [ TP ]
280 [supported_link_modes]:
281 [supported_link_modes][0]: 10baseT/Half 10baseT/Full
282 [supported_link_modes][1]: 100baseT/Half 100baseT/Full
283 [supported_link_modes][2]: 1000baseT/Half 1000baseT/Full
284 [supported_pause_frame_use]: No
285 [supports_auto-negotiation]: Yes
286 [supported_fec_modes]: Not reported
287 [advertised_link_modes]:
288 [advertised_link_modes][0]: 10baseT/Half 10baseT/Full
289 [advertised_link_modes][1]: 100baseT/Half 100baseT/Full
290 [advertised_link_modes][2]: 1000baseT/Half 1000baseT/Full
291 [advertised_pause_frame_use]: Symmetric
292 [advertised_auto-negotiation]: Yes
293 [advertised_fec_modes]: Not reported
294 [speed]: Unknown!
295 [duplex]: Unknown! (255)
296 [port]: Twisted Pair
297 [phyad]: 1
298 [transceiver]: internal
299 [auto-negotiation]: on
300 [mdi-x]: Unknown
301 [supports_wake-on]: g
302 [wake-on]: g
303 [current_message_level]: 0x000000ff (255)
304 [drv_probe_link_timer_ifdown_ifup_rx_err_tx_err]:<blank>
305 [link_detected]: no
306 """
307
308 # Using sed and tail to massage the data a bit before running
309 # key_value_outbuf_to_dict.
Patrick Williams20f38712022-12-08 06:18:26 -0600310 cmd_buf = (
311 "ethtool "
312 + interface_name
313 + " | sed -re 's/(.* link modes:)(.*)/\\1\\n\\2/g' | tail -n +2"
314 )
Michael Walsh7847ece2018-04-12 11:37:45 -0500315 stdout, stderr, rc = bsu.os_execute_command(cmd_buf)
316 result = vf.key_value_outbuf_to_dict(stdout, process_indent=1, strip=" \t")
317
318 return result
Michael Walsh75575102018-10-04 15:10:44 -0500319
320
321def to_json_ordered(json_str):
322 r"""
323 Parse the JSON string data and return an ordered JSON dictionary object.
324
325 Description of argument(s):
326 json_str The string containing the JSON data.
327 """
328
George Keishing36efbc02018-12-12 10:18:23 -0600329 try:
330 return json.loads(json_str, object_pairs_hook=DotDict)
331 except TypeError:
332 return json.loads(json_str.decode("utf-8"), object_pairs_hook=DotDict)
Michael Walsh35d78f22020-01-14 15:01:57 -0600333
334
335def get_bmc_release_info():
336 r"""
337 Get release info from the BMC and return as a dictionary.
338
339 Example:
340
341 ${release_info}= Get BMC Release Info
342 Rprint Vars release_info
343
344 Output:
345
346 release_info:
George Keishingc7cc02b2022-08-12 09:09:52 -0500347 [id]: openbmc-phosphor
348 [name]: Phosphor OpenBMC (Phosphor OpenBMC Project Reference...
349 [version]: 2.8.0-dev
350 [version_id]: 2.8.0-dev-1083-g8954c3505
351 [pretty_name]: Phosphor OpenBMC (Phosphor OpenBMC Project Reference...
352 [build_id]: 2.8.0-dev
353 [openbmc_target_machine]: witherspoon
Michael Walsh35d78f22020-01-14 15:01:57 -0600354 """
355
Patrick Williams20f38712022-12-08 06:18:26 -0600356 out_buf, stderr, rc = bsu.bmc_execute_command("cat /etc/os-release")
Michael Walsh35d78f22020-01-14 15:01:57 -0600357 return vf.key_value_outbuf_to_dict(out_buf, delim="=", strip='"')
358
359
360def get_os_release_info():
361 r"""
362 Get release info from the OS and return as a dictionary.
363
364 Example:
365
366 ${release_info}= Get OS Release Info
367 Rprint Vars release_info
368
369 Output:
370 release_info:
371 [name]: Red Hat Enterprise Linux Server
372 [version]: 7.6 (Maipo)
373 [id]: rhel
374 [id_like]: fedora
375 [variant]: Server
376 [variant_id]: server
377 [version_id]: 7.6
378 [pretty_name]: Red Hat Enterprise Linux Server 7.6 (Maipo)
379 [ansi_color]: 0;31
380 [cpe_name]: cpe:/o:redhat:enterprise_linux:7.6:GA:server
381 [home_url]: https://www.redhat.com/
382 [bug_report_url]: https://bugzilla.redhat.com/
383 [redhat_bugzilla_product]: Red Hat Enterprise Linux 7
384 [redhat_bugzilla_product_version]: 7.6
385 [redhat_support_product]: Red Hat Enterprise Linux
386 [redhat_support_product_version]: 7.6
387 """
388
Patrick Williams20f38712022-12-08 06:18:26 -0600389 out_buf, stderr, rc = bsu.os_execute_command("cat /etc/os-release")
Michael Walsh35d78f22020-01-14 15:01:57 -0600390 return vf.key_value_outbuf_to_dict(out_buf, delim="=", strip='"')
Sridevi Ramesh9617ebd2019-11-25 10:57:21 -0600391
392
393def pdbg(option_string, **bsu_options):
394 r"""
395 Run pdbg on the BMC with the caller's option string and return the output.
396
397 Description of argument(s):
George Keishingc7cc02b2022-08-12 09:09:52 -0500398 option_string A string of options which are to be processed by the pdbg command.
399 bsu_options Options to be passed directly to bmc_execute_command. See its prolog for
400 details.
Sridevi Ramesh9617ebd2019-11-25 10:57:21 -0600401 """
402
403 # Default print_out to 1.
Patrick Williams20f38712022-12-08 06:18:26 -0600404 if "print_out" not in bsu_options:
405 bsu_options["print_out"] = 1
Sridevi Ramesh9617ebd2019-11-25 10:57:21 -0600406
Patrick Williams20f38712022-12-08 06:18:26 -0600407 stdout, stderr, rc = bsu.bmc_execute_command(
408 "pdbg " + option_string, **bsu_options
409 )
Sridevi Ramesh9617ebd2019-11-25 10:57:21 -0600410 return stdout
Sridevi Ramesheb5a1622020-03-19 05:50:46 -0500411
412
413def ecmd(option_string, **bsu_options):
414 r"""
415 Run ecmd command on the BMC with the caller's option string and return the output.
416
417 Description of argument(s):
George Keishingc7cc02b2022-08-12 09:09:52 -0500418 option_string A string of options which are to be executed on BMC.
419 (e.g. getscom pu 20010a40 -all,
420 putscom pu 20010a40 4000000000000000 -p0).
421 bsu_options Options to be passed directly to bmc_execute_command. See its prolog for
422 details.
Sridevi Ramesheb5a1622020-03-19 05:50:46 -0500423 """
424
425 # Default print_out to 1.
Patrick Williams20f38712022-12-08 06:18:26 -0600426 if "print_out" not in bsu_options:
427 bsu_options["print_out"] = 1
Sridevi Ramesheb5a1622020-03-19 05:50:46 -0500428
429 stdout, stderr, rc = bsu.bmc_execute_command(option_string, **bsu_options)
430 return stdout
chithrag0a8c8782022-03-01 12:35:00 +0000431
432
433def split_string_with_index(stri, n):
434 r"""
435 To split every n characters and forms an element for every nth index
436
437 Example : Given ${stri} = "abcdef", then the function call,
438 ${data}= Split List With Index ${stri} 2
439 then, result will be data = ['ab', 'cd', 'ef']
440 """
441
442 n = int(n)
Patrick Williams20f38712022-12-08 06:18:26 -0600443 data = [stri[index : index + n] for index in range(0, len(stri), n)]
chithrag0a8c8782022-03-01 12:35:00 +0000444 return data
445
446
447def remove_whitespace(instring):
448 r"""
449 Removes the white spaces around the string
450
451 Example: instring = " xxx ", then returns instring = "xxx"
452 """
453
454 return instring.strip()
455
456
457def zfill_data(data, num):
458 r"""
George Keishingc7cc02b2022-08-12 09:09:52 -0500459 zfill() method adds zeros (0) at the beginning of the string, until it
460 reaches the specified length.
chithrag0a8c8782022-03-01 12:35:00 +0000461
462 Usage : ${anystr}= Zfill Data ${data} num
463
464 Example : Binary of one Byte has 8 bits - xxxx xxxx
465
466 Consider ${binary} has only 3 bits after converting from Hexadecimal/decimal to Binary
467 Say ${binary} = 110 then,
468 ${binary}= Zfill Data ${binary} 8
469 Now ${binary} will be 0000 0110
470 """
471
472 return data.zfill(int(num))
ganesanbc288aff2022-05-19 19:55:47 +0530473
474
475def get_subsequent_value_from_list(list, value):
476 r"""
477 returns first index of the element occurrence.
478 """
479
480 index = [list.index(i) for i in list if value in i]
481 return index
482
483
484def return_decoded_string(input):
485 r"""
486 returns decoded string of encoded byte.
487 """
488
Patrick Williams20f38712022-12-08 06:18:26 -0600489 encoded_string = input.encode("ascii", "ignore")
ganesanbc288aff2022-05-19 19:55:47 +0530490 decoded_string = encoded_string.decode()
491 return decoded_string
ganesanb07958e12023-04-26 05:38:22 -0700492
493
494def remove_unicode_from_uri(uri):
495 r"""
496 returns dbus uri without unicode in prefix
497 """
498
499 return re.sub("`-|\\|-", "", uri)
ganesanbbd187d22023-05-03 11:00:18 +0000500
501
502def get_bmc_major_minor_version(version):
503 r"""
504 returns major version and minor version
505 from cat /etc/os-release command.
506 For example,
507 xyz23.01 --> [23, 01]
508 xyz.0-112 --> [0, 112]
509 ZERzzYY-23.04-1-xx3 --> [23, 04, 1, 3]
510 """
511
512 return re.findall(r"\d+", re.sub("[A-Z]|[a-z]", "", version))
ganesanb5502e3e2022-12-13 11:07:43 +0000513
514
515def convert_name_into_bytes_with_prefix(name):
516 r"""
517 Convert name into bytes with prefix 0x
518 """
519
520 bytes_list = []
521
522 for letter in name:
523 bytes_list.append(hex(ord(letter)))
524
525 return bytes_list
526
527
528def convert_name_into_bytes_without_prefix(name):
529 r"""
530 Convert name into bytes
531 """
532
533 tmp_lst = []
534
535 for letter in name:
536 value = convert_to_hex_value_without_prefix(letter)
537 tmp_lst.append(value)
538
539 return tmp_lst
540
541
542def convert_to_hex_value_without_prefix(letter):
543 r"""
544 Convert into hex
545 """
546
547 value = hex(ord(letter))
548 if value[:2] == "0x":
549 value = value[2:]
550
551 return value
552
553
554def convert_prefix_hex_list_to_non_prefix_hex_list(list):
555 r"""
556 Convert into list of hex with prefix to list of hex without prefix.
557 """
558
559 tmp_list = []
560
561 for value in list:
562 if value[:2] == "0x":
563 tmp_list.append(value[2:])
564
565 return tmp_list