blob: 50244bb9c7154ab4c18078065002fee909ba0f7c [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
207def get_sbe():
George Keishing6f407b92018-01-16 02:21:47 -0600208 r"""
209 Return CFAM value which contains such things as SBE side bit.
210 """
211
212 cmd_buf = "pdbg -d p9w -p0 getcfam 0x2808 | sed -re 's/.* = //g'"
213 out_buf, stderr, rc = bsu.bmc_execute_command(cmd_buf)
214
215 return int(out_buf, 16)
216
George Keishingbf724772018-02-21 08:57:16 -0600217
Gunnar Mills096cd562018-03-26 10:19:12 -0500218def compare_mac_address(sys_mac_addr, user_mac_addr):
George Keishingbf724772018-02-21 08:57:16 -0600219 r"""
Patrick Williams20f38712022-12-08 06:18:26 -0600220 Return 1 if the MAC value matched, otherwise 0.
George Keishingbf724772018-02-21 08:57:16 -0600221
Patrick Williams20f38712022-12-08 06:18:26 -0600222 . Description of argument(s):
223 sys_mac_addr A valid system MAC string (e.g. "70:e2:84:14:2a:08")
224 user_mac_addr A user provided MAC string (e.g. "70:e2:84:14:2a:08")
George Keishingbf724772018-02-21 08:57:16 -0600225 """
226
227 index = 0
228 # Example: ['70', 'e2', '84', '14', '2a', '08']
229 mac_list = user_mac_addr.split(":")
230 for item in sys_mac_addr.split(":"):
231 if int(item, 16) == int(mac_list[index], 16):
232 index = index + 1
233 continue
234 return 0
235
236 return 1
Michael Walsh7847ece2018-04-12 11:37:45 -0500237
238
239def get_os_ethtool(interface_name):
240 r"""
241 Get OS 'ethtool' output for the given interface_name and return it as a
242 dictionary.
243
244 Settings for enP52p1s0f0:
245 Supported ports: [ TP ]
246 Supported link modes: 10baseT/Half 10baseT/Full
247 100baseT/Half 100baseT/Full
248 1000baseT/Half 1000baseT/Full
249 Supported pause frame use: No
250 Supports auto-negotiation: Yes
251 Supported FEC modes: Not reported
252 Advertised link modes: 10baseT/Half 10baseT/Full
253 100baseT/Half 100baseT/Full
254 1000baseT/Half 1000baseT/Full
255 Advertised pause frame use: Symmetric
256 Advertised auto-negotiation: Yes
257 Advertised FEC modes: Not reported
258 Speed: Unknown!
259 Duplex: Unknown! (255)
260 Port: Twisted Pair
261 PHYAD: 1
262 Transceiver: internal
263 Auto-negotiation: on
264 MDI-X: Unknown
265 Supports Wake-on: g
266 Wake-on: g
267 Current message level: 0x000000ff (255)
268 drv probe link timer ifdown ifup rx_err tx_err
269 Link detected: no
270
271 Given that data, this function will return the following dictionary.
272
273 ethtool_dict:
274 [supported_ports]: [ TP ]
275 [supported_link_modes]:
276 [supported_link_modes][0]: 10baseT/Half 10baseT/Full
277 [supported_link_modes][1]: 100baseT/Half 100baseT/Full
278 [supported_link_modes][2]: 1000baseT/Half 1000baseT/Full
279 [supported_pause_frame_use]: No
280 [supports_auto-negotiation]: Yes
281 [supported_fec_modes]: Not reported
282 [advertised_link_modes]:
283 [advertised_link_modes][0]: 10baseT/Half 10baseT/Full
284 [advertised_link_modes][1]: 100baseT/Half 100baseT/Full
285 [advertised_link_modes][2]: 1000baseT/Half 1000baseT/Full
286 [advertised_pause_frame_use]: Symmetric
287 [advertised_auto-negotiation]: Yes
288 [advertised_fec_modes]: Not reported
289 [speed]: Unknown!
290 [duplex]: Unknown! (255)
291 [port]: Twisted Pair
292 [phyad]: 1
293 [transceiver]: internal
294 [auto-negotiation]: on
295 [mdi-x]: Unknown
296 [supports_wake-on]: g
297 [wake-on]: g
298 [current_message_level]: 0x000000ff (255)
299 [drv_probe_link_timer_ifdown_ifup_rx_err_tx_err]:<blank>
300 [link_detected]: no
301 """
302
303 # Using sed and tail to massage the data a bit before running
304 # key_value_outbuf_to_dict.
Patrick Williams20f38712022-12-08 06:18:26 -0600305 cmd_buf = (
306 "ethtool "
307 + interface_name
308 + " | sed -re 's/(.* link modes:)(.*)/\\1\\n\\2/g' | tail -n +2"
309 )
Michael Walsh7847ece2018-04-12 11:37:45 -0500310 stdout, stderr, rc = bsu.os_execute_command(cmd_buf)
311 result = vf.key_value_outbuf_to_dict(stdout, process_indent=1, strip=" \t")
312
313 return result
Michael Walsh75575102018-10-04 15:10:44 -0500314
315
316def to_json_ordered(json_str):
317 r"""
318 Parse the JSON string data and return an ordered JSON dictionary object.
319
320 Description of argument(s):
321 json_str The string containing the JSON data.
322 """
323
George Keishing36efbc02018-12-12 10:18:23 -0600324 try:
325 return json.loads(json_str, object_pairs_hook=DotDict)
326 except TypeError:
327 return json.loads(json_str.decode("utf-8"), object_pairs_hook=DotDict)
Michael Walsh35d78f22020-01-14 15:01:57 -0600328
329
330def get_bmc_release_info():
331 r"""
332 Get release info from the BMC and return as a dictionary.
333
334 Example:
335
336 ${release_info}= Get BMC Release Info
337 Rprint Vars release_info
338
339 Output:
340
341 release_info:
George Keishingc7cc02b2022-08-12 09:09:52 -0500342 [id]: openbmc-phosphor
343 [name]: Phosphor OpenBMC (Phosphor OpenBMC Project Reference...
344 [version]: 2.8.0-dev
345 [version_id]: 2.8.0-dev-1083-g8954c3505
346 [pretty_name]: Phosphor OpenBMC (Phosphor OpenBMC Project Reference...
347 [build_id]: 2.8.0-dev
348 [openbmc_target_machine]: witherspoon
Michael Walsh35d78f22020-01-14 15:01:57 -0600349 """
350
Patrick Williams20f38712022-12-08 06:18:26 -0600351 out_buf, stderr, rc = bsu.bmc_execute_command("cat /etc/os-release")
Michael Walsh35d78f22020-01-14 15:01:57 -0600352 return vf.key_value_outbuf_to_dict(out_buf, delim="=", strip='"')
353
354
355def get_os_release_info():
356 r"""
357 Get release info from the OS and return as a dictionary.
358
359 Example:
360
361 ${release_info}= Get OS Release Info
362 Rprint Vars release_info
363
364 Output:
365 release_info:
366 [name]: Red Hat Enterprise Linux Server
367 [version]: 7.6 (Maipo)
368 [id]: rhel
369 [id_like]: fedora
370 [variant]: Server
371 [variant_id]: server
372 [version_id]: 7.6
373 [pretty_name]: Red Hat Enterprise Linux Server 7.6 (Maipo)
374 [ansi_color]: 0;31
375 [cpe_name]: cpe:/o:redhat:enterprise_linux:7.6:GA:server
376 [home_url]: https://www.redhat.com/
377 [bug_report_url]: https://bugzilla.redhat.com/
378 [redhat_bugzilla_product]: Red Hat Enterprise Linux 7
379 [redhat_bugzilla_product_version]: 7.6
380 [redhat_support_product]: Red Hat Enterprise Linux
381 [redhat_support_product_version]: 7.6
382 """
383
Patrick Williams20f38712022-12-08 06:18:26 -0600384 out_buf, stderr, rc = bsu.os_execute_command("cat /etc/os-release")
Michael Walsh35d78f22020-01-14 15:01:57 -0600385 return vf.key_value_outbuf_to_dict(out_buf, delim="=", strip='"')
Sridevi Ramesh9617ebd2019-11-25 10:57:21 -0600386
387
388def pdbg(option_string, **bsu_options):
389 r"""
390 Run pdbg on the BMC with the caller's option string and return the output.
391
392 Description of argument(s):
George Keishingc7cc02b2022-08-12 09:09:52 -0500393 option_string A string of options which are to be processed by the pdbg command.
394 bsu_options Options to be passed directly to bmc_execute_command. See its prolog for
395 details.
Sridevi Ramesh9617ebd2019-11-25 10:57:21 -0600396 """
397
398 # Default print_out to 1.
Patrick Williams20f38712022-12-08 06:18:26 -0600399 if "print_out" not in bsu_options:
400 bsu_options["print_out"] = 1
Sridevi Ramesh9617ebd2019-11-25 10:57:21 -0600401
Patrick Williams20f38712022-12-08 06:18:26 -0600402 stdout, stderr, rc = bsu.bmc_execute_command(
403 "pdbg " + option_string, **bsu_options
404 )
Sridevi Ramesh9617ebd2019-11-25 10:57:21 -0600405 return stdout
Sridevi Ramesheb5a1622020-03-19 05:50:46 -0500406
407
408def ecmd(option_string, **bsu_options):
409 r"""
410 Run ecmd command on the BMC with the caller's option string and return the output.
411
412 Description of argument(s):
George Keishingc7cc02b2022-08-12 09:09:52 -0500413 option_string A string of options which are to be executed on BMC.
414 (e.g. getscom pu 20010a40 -all,
415 putscom pu 20010a40 4000000000000000 -p0).
416 bsu_options Options to be passed directly to bmc_execute_command. See its prolog for
417 details.
Sridevi Ramesheb5a1622020-03-19 05:50:46 -0500418 """
419
420 # Default print_out to 1.
Patrick Williams20f38712022-12-08 06:18:26 -0600421 if "print_out" not in bsu_options:
422 bsu_options["print_out"] = 1
Sridevi Ramesheb5a1622020-03-19 05:50:46 -0500423
424 stdout, stderr, rc = bsu.bmc_execute_command(option_string, **bsu_options)
425 return stdout
chithrag0a8c8782022-03-01 12:35:00 +0000426
427
428def split_string_with_index(stri, n):
429 r"""
430 To split every n characters and forms an element for every nth index
431
432 Example : Given ${stri} = "abcdef", then the function call,
433 ${data}= Split List With Index ${stri} 2
434 then, result will be data = ['ab', 'cd', 'ef']
435 """
436
437 n = int(n)
Patrick Williams20f38712022-12-08 06:18:26 -0600438 data = [stri[index : index + n] for index in range(0, len(stri), n)]
chithrag0a8c8782022-03-01 12:35:00 +0000439 return data
440
441
442def remove_whitespace(instring):
443 r"""
444 Removes the white spaces around the string
445
446 Example: instring = " xxx ", then returns instring = "xxx"
447 """
448
449 return instring.strip()
450
451
452def zfill_data(data, num):
453 r"""
George Keishingc7cc02b2022-08-12 09:09:52 -0500454 zfill() method adds zeros (0) at the beginning of the string, until it
455 reaches the specified length.
chithrag0a8c8782022-03-01 12:35:00 +0000456
457 Usage : ${anystr}= Zfill Data ${data} num
458
459 Example : Binary of one Byte has 8 bits - xxxx xxxx
460
461 Consider ${binary} has only 3 bits after converting from Hexadecimal/decimal to Binary
462 Say ${binary} = 110 then,
463 ${binary}= Zfill Data ${binary} 8
464 Now ${binary} will be 0000 0110
465 """
466
467 return data.zfill(int(num))
ganesanbc288aff2022-05-19 19:55:47 +0530468
469
470def get_subsequent_value_from_list(list, value):
471 r"""
472 returns first index of the element occurrence.
473 """
474
475 index = [list.index(i) for i in list if value in i]
476 return index
477
478
479def return_decoded_string(input):
480 r"""
481 returns decoded string of encoded byte.
482 """
483
Patrick Williams20f38712022-12-08 06:18:26 -0600484 encoded_string = input.encode("ascii", "ignore")
ganesanbc288aff2022-05-19 19:55:47 +0530485 decoded_string = encoded_string.decode()
486 return decoded_string
ganesanb07958e12023-04-26 05:38:22 -0700487
488
489def remove_unicode_from_uri(uri):
490 r"""
491 returns dbus uri without unicode in prefix
492 """
493
494 return re.sub("`-|\\|-", "", uri)
ganesanbbd187d22023-05-03 11:00:18 +0000495
496
497def get_bmc_major_minor_version(version):
498 r"""
499 returns major version and minor version
500 from cat /etc/os-release command.
501 For example,
502 xyz23.01 --> [23, 01]
503 xyz.0-112 --> [0, 112]
504 ZERzzYY-23.04-1-xx3 --> [23, 04, 1, 3]
505 """
506
507 return re.findall(r"\d+", re.sub("[A-Z]|[a-z]", "", version))
ganesanb5502e3e2022-12-13 11:07:43 +0000508
509
510def convert_name_into_bytes_with_prefix(name):
511 r"""
512 Convert name into bytes with prefix 0x
513 """
514
515 bytes_list = []
516
517 for letter in name:
518 bytes_list.append(hex(ord(letter)))
519
520 return bytes_list
521
522
523def convert_name_into_bytes_without_prefix(name):
524 r"""
525 Convert name into bytes
526 """
527
528 tmp_lst = []
529
530 for letter in name:
531 value = convert_to_hex_value_without_prefix(letter)
532 tmp_lst.append(value)
533
534 return tmp_lst
535
536
537def convert_to_hex_value_without_prefix(letter):
538 r"""
539 Convert into hex
540 """
541
542 value = hex(ord(letter))
543 if value[:2] == "0x":
544 value = value[2:]
545
546 return value
547
548
549def convert_prefix_hex_list_to_non_prefix_hex_list(list):
550 r"""
551 Convert into list of hex with prefix to list of hex without prefix.
552 """
553
554 tmp_list = []
555
556 for value in list:
557 if value[:2] == "0x":
558 tmp_list.append(value[2:])
559
560 return tmp_list