blob: 59d63e33ebadbb1eb619b83809910474528f0788 [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
Sushil Singh6624ce52020-01-22 00:53:41 -06007import os
George Keishingc7cc02b2022-08-12 09:09:52 -05008import json
9import collections
Michael Walshfdc5ced2017-08-17 13:15:15 -050010import gen_print as gp
11import gen_robot_keyword as grk
Michael Walshf880ac62017-11-10 11:29:37 -060012import bmc_ssh_utils as bsu
13import var_funcs as vf
Michael Walshfdc5ced2017-08-17 13:15:15 -050014from robot.libraries.BuiltIn import BuiltIn
Michael Walshf880ac62017-11-10 11:29:37 -060015from robot.libraries import DateTime
16try:
17 from robot.utils import DotDict
18except ImportError:
19 pass
Michael Walshfdc5ced2017-08-17 13:15:15 -050020
21
Sushil Singh6624ce52020-01-22 00:53:41 -060022# The code base directory will be one level up from the directory containing this module.
23code_base_dir_path = os.path.dirname(os.path.dirname(__file__)) + os.sep
24
25
26def get_code_base_dir_path():
27 r"""
28 Return the dir path of our code base.
29 """
30
31 return code_base_dir_path
32
33
Michael Walshfdc5ced2017-08-17 13:15:15 -050034def set_power_policy_method():
Michael Walshfdc5ced2017-08-17 13:15:15 -050035 r"""
36 Set the global bmc_power_policy_method to either 'Old' or 'New'.
37
38 The power policy data has moved from an 'org' location to an 'xyz'
39 location. This keyword will determine whether the new method of getting
40 the power policy is valid and will set the global bmc_power_policy_method
41 variable accordingly. If power_policy_setup is already set (by a prior
42 call to this function), this keyword will simply return.
43
44 If bmc_power_policy_method is "Old", this function will adjust the global
45 policy variables from data/variables.py: RESTORE_LAST_STATE,
46 ALWAYS_POWER_ON, ALWAYS_POWER_OFF.
47 """
48
49 # Retrieve global variables.
50 power_policy_setup = \
51 int(BuiltIn().get_variable_value("${power_policy_setup}",
52 default=0))
53 bmc_power_policy_method = \
54 BuiltIn().get_variable_value("${bmc_power_policy_method}",
55 default=0)
56 gp.dpvar(power_policy_setup)
57
58 # If this function has already been run once, we need not continue.
59 if power_policy_setup:
60 return
61
62 gp.dpvar(bmc_power_policy_method, 1)
63
64 # The user has not set bmc_power_policy_method via a -v parm so we will
65 # determine what it should be.
66 if bmc_power_policy_method == "":
67 status, ret_values = grk.run_key_u("New Get Power Policy", ignore=1)
68 if status == 'PASS':
69 bmc_power_policy_method = 'New'
70 else:
71 bmc_power_policy_method = 'Old'
72
73 gp.qpvar(bmc_power_policy_method)
74 # For old style, we will rewrite these global variable settings to old
75 # values.
76 if bmc_power_policy_method == "Old":
77 BuiltIn().set_global_variable("${RESTORE_LAST_STATE}",
78 "RESTORE_LAST_STATE")
79 BuiltIn().set_global_variable("${ALWAYS_POWER_ON}",
80 "ALWAYS_POWER_ON")
81 BuiltIn().set_global_variable("${ALWAYS_POWER_OFF}",
82 "ALWAYS_POWER_OFF")
83
84 # Set global variables to control subsequent calls to this function.
85 BuiltIn().set_global_variable("${bmc_power_policy_method}",
86 bmc_power_policy_method)
87 BuiltIn().set_global_variable("${power_policy_setup}", 1)
88
89
Michael Walshfdc5ced2017-08-17 13:15:15 -050090def translate_power_policy_value(policy):
Michael Walshfdc5ced2017-08-17 13:15:15 -050091 r"""
92 Translate the policy value and return the result.
93
94 Using old style functions, callers might call like this with a hard-
95 code value for policy:
96
George Keishingefc3ff22017-12-12 11:49:25 -060097 Set BMC Power Policy ALWAYS_POWER_OFF
Michael Walshfdc5ced2017-08-17 13:15:15 -050098
99 This function will get the value of the corresponding global variable (if
100 it exists) and return it.
101
102 This will allow the old style call to still work on systems using the new
103 method of storing the policy value.
104 """
105
106 valid_power_policy_vars = \
107 BuiltIn().get_variable_value("${valid_power_policy_vars}")
108
109 if policy not in valid_power_policy_vars:
110 return policy
111
112 status, ret_values = grk.run_key_u("Get Variable Value ${" + policy + "}",
113 quiet=1)
114 return ret_values
115
Michael Walshf880ac62017-11-10 11:29:37 -0600116
Michael Walshf880ac62017-11-10 11:29:37 -0600117def get_bmc_date_time():
Michael Walshf880ac62017-11-10 11:29:37 -0600118 r"""
119 Get date/time info from BMC and return as a dictionary.
120
121 Example of dictionary data returned by this keyword.
122 time_dict:
123 [local_time]: Fri 2017-11-03 152756 UTC
124 [local_time_seconds]: 1509740876
125 [universal_time]: Fri 2017-11-03 152756 UTC
126 [universal_time_seconds]: 1509740876
127 [rtc_time]: Fri 2016-05-20 163403
128 [rtc_time_seconds]: 1463780043
129 [time_zone]: n/a (UTC, +0000)
130 [network_time_on]: yes
131 [ntp_synchronized]: no
132 [rtc_in_local_tz]: no
133 """
134
135 out_buf, stderr, rc = bsu.bmc_execute_command('timedatectl')
136 # Example of output returned by call to timedatectl:
137 # Local time: Fri 2017-11-03 15:27:56 UTC
138 # Universal time: Fri 2017-11-03 15:27:56 UTC
139 # RTC time: Fri 2016-05-20 16:34:03
140 # Time zone: n/a (UTC, +0000)
141 # Network time on: yes
142 # NTP synchronized: no
143 # RTC in local TZ: no
144
145 # Convert the out_buf to a dictionary.
146 initial_time_dict = vf.key_value_outbuf_to_dict(out_buf)
147
148 # For each "_time" entry in the dictionary, we will create a corresponding
149 # "_time_seconds" entry. We create a new dictionary so that the entries
150 # are kept in a nice order for printing.
151 try:
152 result_time_dict = collections.OrderedDict()
153 except AttributeError:
154 result_time_dict = DotDict()
155
156 for key, value in initial_time_dict.items():
157 result_time_dict[key] = value
158 if not key.endswith("_time"):
159 continue
160 result_time_dict[key + '_seconds'] = \
161 int(DateTime.convert_date(value, result_format='epoch'))
162
163 return result_time_dict
164
Michael Walsh193743e2017-11-20 16:43:31 -0600165
166def get_bmc_df(df_parm_string=""):
Michael Walsh193743e2017-11-20 16:43:31 -0600167 r"""
168 Get df report from BMC and return as a report "object".
169
170 A df report object is a list where each entry is a dictionary whose keys
171 are the field names from the first entry in report_list.
172
173 Example df report object:
174
175 df_report:
176 df_report[0]:
177 [filesystem]: dev
178 [1k-blocks]: 247120
179 [used]: 0
180 [available]: 247120
181 [use%]: 0%
182 [mounted]: /dev
183 df_report[1]:
184 [filesystem]: dev
185 [1k-blocks]: 247120
186 [used]: 0
187 [available]: 247120
188 [use%]: 0%
189 [mounted]: /dev
190
191. Description of argument(s):
192 df_parm_string A string containing valid df command parms (e.g.
193 "-h /var").
194 """
195
196 out_buf, stderr, rc = bsu.bmc_execute_command("df " + df_parm_string)
197 return vf.outbuf_to_report(out_buf)
George Keishing6f407b92018-01-16 02:21:47 -0600198
199
200def get_sbe():
George Keishing6f407b92018-01-16 02:21:47 -0600201 r"""
202 Return CFAM value which contains such things as SBE side bit.
203 """
204
205 cmd_buf = "pdbg -d p9w -p0 getcfam 0x2808 | sed -re 's/.* = //g'"
206 out_buf, stderr, rc = bsu.bmc_execute_command(cmd_buf)
207
208 return int(out_buf, 16)
209
George Keishingbf724772018-02-21 08:57:16 -0600210
Gunnar Mills096cd562018-03-26 10:19:12 -0500211def compare_mac_address(sys_mac_addr, user_mac_addr):
George Keishingbf724772018-02-21 08:57:16 -0600212 r"""
213 Return 1 if the MAC value matched, otherwise 0.
214
215. Description of argument(s):
216 sys_mac_addr A valid system MAC string (e.g. "70:e2:84:14:2a:08")
217 user_mac_addr A user provided MAC string (e.g. "70:e2:84:14:2a:08")
218 """
219
220 index = 0
221 # Example: ['70', 'e2', '84', '14', '2a', '08']
222 mac_list = user_mac_addr.split(":")
223 for item in sys_mac_addr.split(":"):
224 if int(item, 16) == int(mac_list[index], 16):
225 index = index + 1
226 continue
227 return 0
228
229 return 1
Michael Walsh7847ece2018-04-12 11:37:45 -0500230
231
232def get_os_ethtool(interface_name):
233 r"""
234 Get OS 'ethtool' output for the given interface_name and return it as a
235 dictionary.
236
237 Settings for enP52p1s0f0:
238 Supported ports: [ TP ]
239 Supported link modes: 10baseT/Half 10baseT/Full
240 100baseT/Half 100baseT/Full
241 1000baseT/Half 1000baseT/Full
242 Supported pause frame use: No
243 Supports auto-negotiation: Yes
244 Supported FEC modes: Not reported
245 Advertised link modes: 10baseT/Half 10baseT/Full
246 100baseT/Half 100baseT/Full
247 1000baseT/Half 1000baseT/Full
248 Advertised pause frame use: Symmetric
249 Advertised auto-negotiation: Yes
250 Advertised FEC modes: Not reported
251 Speed: Unknown!
252 Duplex: Unknown! (255)
253 Port: Twisted Pair
254 PHYAD: 1
255 Transceiver: internal
256 Auto-negotiation: on
257 MDI-X: Unknown
258 Supports Wake-on: g
259 Wake-on: g
260 Current message level: 0x000000ff (255)
261 drv probe link timer ifdown ifup rx_err tx_err
262 Link detected: no
263
264 Given that data, this function will return the following dictionary.
265
266 ethtool_dict:
267 [supported_ports]: [ TP ]
268 [supported_link_modes]:
269 [supported_link_modes][0]: 10baseT/Half 10baseT/Full
270 [supported_link_modes][1]: 100baseT/Half 100baseT/Full
271 [supported_link_modes][2]: 1000baseT/Half 1000baseT/Full
272 [supported_pause_frame_use]: No
273 [supports_auto-negotiation]: Yes
274 [supported_fec_modes]: Not reported
275 [advertised_link_modes]:
276 [advertised_link_modes][0]: 10baseT/Half 10baseT/Full
277 [advertised_link_modes][1]: 100baseT/Half 100baseT/Full
278 [advertised_link_modes][2]: 1000baseT/Half 1000baseT/Full
279 [advertised_pause_frame_use]: Symmetric
280 [advertised_auto-negotiation]: Yes
281 [advertised_fec_modes]: Not reported
282 [speed]: Unknown!
283 [duplex]: Unknown! (255)
284 [port]: Twisted Pair
285 [phyad]: 1
286 [transceiver]: internal
287 [auto-negotiation]: on
288 [mdi-x]: Unknown
289 [supports_wake-on]: g
290 [wake-on]: g
291 [current_message_level]: 0x000000ff (255)
292 [drv_probe_link_timer_ifdown_ifup_rx_err_tx_err]:<blank>
293 [link_detected]: no
294 """
295
296 # Using sed and tail to massage the data a bit before running
297 # key_value_outbuf_to_dict.
298 cmd_buf = "ethtool " + interface_name +\
299 " | sed -re 's/(.* link modes:)(.*)/\\1\\n\\2/g' | tail -n +2"
300 stdout, stderr, rc = bsu.os_execute_command(cmd_buf)
301 result = vf.key_value_outbuf_to_dict(stdout, process_indent=1, strip=" \t")
302
303 return result
Michael Walsh75575102018-10-04 15:10:44 -0500304
305
306def to_json_ordered(json_str):
307 r"""
308 Parse the JSON string data and return an ordered JSON dictionary object.
309
310 Description of argument(s):
311 json_str The string containing the JSON data.
312 """
313
George Keishing36efbc02018-12-12 10:18:23 -0600314 try:
315 return json.loads(json_str, object_pairs_hook=DotDict)
316 except TypeError:
317 return json.loads(json_str.decode("utf-8"), object_pairs_hook=DotDict)
Michael Walsh35d78f22020-01-14 15:01:57 -0600318
319
320def get_bmc_release_info():
321 r"""
322 Get release info from the BMC and return as a dictionary.
323
324 Example:
325
326 ${release_info}= Get BMC Release Info
327 Rprint Vars release_info
328
329 Output:
330
331 release_info:
George Keishingc7cc02b2022-08-12 09:09:52 -0500332 [id]: openbmc-phosphor
333 [name]: Phosphor OpenBMC (Phosphor OpenBMC Project Reference...
334 [version]: 2.8.0-dev
335 [version_id]: 2.8.0-dev-1083-g8954c3505
336 [pretty_name]: Phosphor OpenBMC (Phosphor OpenBMC Project Reference...
337 [build_id]: 2.8.0-dev
338 [openbmc_target_machine]: witherspoon
Michael Walsh35d78f22020-01-14 15:01:57 -0600339 """
340
341 out_buf, stderr, rc = bsu.bmc_execute_command('cat /etc/os-release')
342 return vf.key_value_outbuf_to_dict(out_buf, delim="=", strip='"')
343
344
345def get_os_release_info():
346 r"""
347 Get release info from the OS and return as a dictionary.
348
349 Example:
350
351 ${release_info}= Get OS Release Info
352 Rprint Vars release_info
353
354 Output:
355 release_info:
356 [name]: Red Hat Enterprise Linux Server
357 [version]: 7.6 (Maipo)
358 [id]: rhel
359 [id_like]: fedora
360 [variant]: Server
361 [variant_id]: server
362 [version_id]: 7.6
363 [pretty_name]: Red Hat Enterprise Linux Server 7.6 (Maipo)
364 [ansi_color]: 0;31
365 [cpe_name]: cpe:/o:redhat:enterprise_linux:7.6:GA:server
366 [home_url]: https://www.redhat.com/
367 [bug_report_url]: https://bugzilla.redhat.com/
368 [redhat_bugzilla_product]: Red Hat Enterprise Linux 7
369 [redhat_bugzilla_product_version]: 7.6
370 [redhat_support_product]: Red Hat Enterprise Linux
371 [redhat_support_product_version]: 7.6
372 """
373
374 out_buf, stderr, rc = bsu.os_execute_command('cat /etc/os-release')
375 return vf.key_value_outbuf_to_dict(out_buf, delim="=", strip='"')
Sridevi Ramesh9617ebd2019-11-25 10:57:21 -0600376
377
378def pdbg(option_string, **bsu_options):
379 r"""
380 Run pdbg on the BMC with the caller's option string and return the output.
381
382 Description of argument(s):
George Keishingc7cc02b2022-08-12 09:09:52 -0500383 option_string A string of options which are to be processed by the pdbg command.
384 bsu_options Options to be passed directly to bmc_execute_command. See its prolog for
385 details.
Sridevi Ramesh9617ebd2019-11-25 10:57:21 -0600386 """
387
388 # Default print_out to 1.
389 if 'print_out' not in bsu_options:
390 bsu_options['print_out'] = 1
391
392 stdout, stderr, rc = bsu.bmc_execute_command('pdbg ' + option_string, **bsu_options)
393 return stdout
Sridevi Ramesheb5a1622020-03-19 05:50:46 -0500394
395
396def ecmd(option_string, **bsu_options):
397 r"""
398 Run ecmd command on the BMC with the caller's option string and return the output.
399
400 Description of argument(s):
George Keishingc7cc02b2022-08-12 09:09:52 -0500401 option_string A string of options which are to be executed on BMC.
402 (e.g. getscom pu 20010a40 -all,
403 putscom pu 20010a40 4000000000000000 -p0).
404 bsu_options Options to be passed directly to bmc_execute_command. See its prolog for
405 details.
Sridevi Ramesheb5a1622020-03-19 05:50:46 -0500406 """
407
408 # Default print_out to 1.
409 if 'print_out' not in bsu_options:
410 bsu_options['print_out'] = 1
411
412 stdout, stderr, rc = bsu.bmc_execute_command(option_string, **bsu_options)
413 return stdout
chithrag0a8c8782022-03-01 12:35:00 +0000414
415
416def split_string_with_index(stri, n):
417 r"""
418 To split every n characters and forms an element for every nth index
419
420 Example : Given ${stri} = "abcdef", then the function call,
421 ${data}= Split List With Index ${stri} 2
422 then, result will be data = ['ab', 'cd', 'ef']
423 """
424
425 n = int(n)
426 data = [stri[index: index + n] for index in range(0, len(stri), n)]
427 return data
428
429
430def remove_whitespace(instring):
431 r"""
432 Removes the white spaces around the string
433
434 Example: instring = " xxx ", then returns instring = "xxx"
435 """
436
437 return instring.strip()
438
439
440def zfill_data(data, num):
441 r"""
George Keishingc7cc02b2022-08-12 09:09:52 -0500442 zfill() method adds zeros (0) at the beginning of the string, until it
443 reaches the specified length.
chithrag0a8c8782022-03-01 12:35:00 +0000444
445 Usage : ${anystr}= Zfill Data ${data} num
446
447 Example : Binary of one Byte has 8 bits - xxxx xxxx
448
449 Consider ${binary} has only 3 bits after converting from Hexadecimal/decimal to Binary
450 Say ${binary} = 110 then,
451 ${binary}= Zfill Data ${binary} 8
452 Now ${binary} will be 0000 0110
453 """
454
455 return data.zfill(int(num))
ganesanbc288aff2022-05-19 19:55:47 +0530456
457
458def get_subsequent_value_from_list(list, value):
459 r"""
460 returns first index of the element occurrence.
461 """
462
463 index = [list.index(i) for i in list if value in i]
464 return index
465
466
467def return_decoded_string(input):
468 r"""
469 returns decoded string of encoded byte.
470 """
471
472 encoded_string = input.encode('ascii', 'ignore')
473 decoded_string = encoded_string.decode()
474 return decoded_string