1#!/usr/bin/env python 2 3r""" 4Companion file to utils.robot. 5""" 6 7import gen_print as gp 8import gen_robot_keyword as grk 9import bmc_ssh_utils as bsu 10import var_funcs as vf 11from robot.libraries.BuiltIn import BuiltIn 12from robot.libraries import DateTime 13import json 14try: 15 from robot.utils import DotDict 16except ImportError: 17 pass 18import collections 19 20 21def set_power_policy_method(): 22 r""" 23 Set the global bmc_power_policy_method to either 'Old' or 'New'. 24 25 The power policy data has moved from an 'org' location to an 'xyz' 26 location. This keyword will determine whether the new method of getting 27 the power policy is valid and will set the global bmc_power_policy_method 28 variable accordingly. If power_policy_setup is already set (by a prior 29 call to this function), this keyword will simply return. 30 31 If bmc_power_policy_method is "Old", this function will adjust the global 32 policy variables from data/variables.py: RESTORE_LAST_STATE, 33 ALWAYS_POWER_ON, ALWAYS_POWER_OFF. 34 """ 35 36 # Retrieve global variables. 37 power_policy_setup = \ 38 int(BuiltIn().get_variable_value("${power_policy_setup}", 39 default=0)) 40 bmc_power_policy_method = \ 41 BuiltIn().get_variable_value("${bmc_power_policy_method}", 42 default=0) 43 gp.dpvar(power_policy_setup) 44 45 # If this function has already been run once, we need not continue. 46 if power_policy_setup: 47 return 48 49 gp.dpvar(bmc_power_policy_method, 1) 50 51 # The user has not set bmc_power_policy_method via a -v parm so we will 52 # determine what it should be. 53 if bmc_power_policy_method == "": 54 status, ret_values = grk.run_key_u("New Get Power Policy", ignore=1) 55 if status == 'PASS': 56 bmc_power_policy_method = 'New' 57 else: 58 bmc_power_policy_method = 'Old' 59 60 gp.qpvar(bmc_power_policy_method) 61 # For old style, we will rewrite these global variable settings to old 62 # values. 63 if bmc_power_policy_method == "Old": 64 BuiltIn().set_global_variable("${RESTORE_LAST_STATE}", 65 "RESTORE_LAST_STATE") 66 BuiltIn().set_global_variable("${ALWAYS_POWER_ON}", 67 "ALWAYS_POWER_ON") 68 BuiltIn().set_global_variable("${ALWAYS_POWER_OFF}", 69 "ALWAYS_POWER_OFF") 70 71 # Set global variables to control subsequent calls to this function. 72 BuiltIn().set_global_variable("${bmc_power_policy_method}", 73 bmc_power_policy_method) 74 BuiltIn().set_global_variable("${power_policy_setup}", 1) 75 76 77def translate_power_policy_value(policy): 78 r""" 79 Translate the policy value and return the result. 80 81 Using old style functions, callers might call like this with a hard- 82 code value for policy: 83 84 Set BMC Power Policy ALWAYS_POWER_OFF 85 86 This function will get the value of the corresponding global variable (if 87 it exists) and return it. 88 89 This will allow the old style call to still work on systems using the new 90 method of storing the policy value. 91 """ 92 93 valid_power_policy_vars = \ 94 BuiltIn().get_variable_value("${valid_power_policy_vars}") 95 96 if policy not in valid_power_policy_vars: 97 return policy 98 99 status, ret_values = grk.run_key_u("Get Variable Value ${" + policy + "}", 100 quiet=1) 101 return ret_values 102 103 104def get_bmc_date_time(): 105 r""" 106 Get date/time info from BMC and return as a dictionary. 107 108 Example of dictionary data returned by this keyword. 109 time_dict: 110 [local_time]: Fri 2017-11-03 152756 UTC 111 [local_time_seconds]: 1509740876 112 [universal_time]: Fri 2017-11-03 152756 UTC 113 [universal_time_seconds]: 1509740876 114 [rtc_time]: Fri 2016-05-20 163403 115 [rtc_time_seconds]: 1463780043 116 [time_zone]: n/a (UTC, +0000) 117 [network_time_on]: yes 118 [ntp_synchronized]: no 119 [rtc_in_local_tz]: no 120 """ 121 122 out_buf, stderr, rc = bsu.bmc_execute_command('timedatectl') 123 # Example of output returned by call to timedatectl: 124 # Local time: Fri 2017-11-03 15:27:56 UTC 125 # Universal time: Fri 2017-11-03 15:27:56 UTC 126 # RTC time: Fri 2016-05-20 16:34:03 127 # Time zone: n/a (UTC, +0000) 128 # Network time on: yes 129 # NTP synchronized: no 130 # RTC in local TZ: no 131 132 # Convert the out_buf to a dictionary. 133 initial_time_dict = vf.key_value_outbuf_to_dict(out_buf) 134 135 # For each "_time" entry in the dictionary, we will create a corresponding 136 # "_time_seconds" entry. We create a new dictionary so that the entries 137 # are kept in a nice order for printing. 138 try: 139 result_time_dict = collections.OrderedDict() 140 except AttributeError: 141 result_time_dict = DotDict() 142 143 for key, value in initial_time_dict.items(): 144 result_time_dict[key] = value 145 if not key.endswith("_time"): 146 continue 147 result_time_dict[key + '_seconds'] = \ 148 int(DateTime.convert_date(value, result_format='epoch')) 149 150 return result_time_dict 151 152 153def get_bmc_df(df_parm_string=""): 154 r""" 155 Get df report from BMC and return as a report "object". 156 157 A df report object is a list where each entry is a dictionary whose keys 158 are the field names from the first entry in report_list. 159 160 Example df report object: 161 162 df_report: 163 df_report[0]: 164 [filesystem]: dev 165 [1k-blocks]: 247120 166 [used]: 0 167 [available]: 247120 168 [use%]: 0% 169 [mounted]: /dev 170 df_report[1]: 171 [filesystem]: dev 172 [1k-blocks]: 247120 173 [used]: 0 174 [available]: 247120 175 [use%]: 0% 176 [mounted]: /dev 177 178. Description of argument(s): 179 df_parm_string A string containing valid df command parms (e.g. 180 "-h /var"). 181 """ 182 183 out_buf, stderr, rc = bsu.bmc_execute_command("df " + df_parm_string) 184 return vf.outbuf_to_report(out_buf) 185 186 187def get_sbe(): 188 r""" 189 Return CFAM value which contains such things as SBE side bit. 190 """ 191 192 cmd_buf = "pdbg -d p9w -p0 getcfam 0x2808 | sed -re 's/.* = //g'" 193 out_buf, stderr, rc = bsu.bmc_execute_command(cmd_buf) 194 195 return int(out_buf, 16) 196 197 198def compare_mac_address(sys_mac_addr, user_mac_addr): 199 r""" 200 Return 1 if the MAC value matched, otherwise 0. 201 202. Description of argument(s): 203 sys_mac_addr A valid system MAC string (e.g. "70:e2:84:14:2a:08") 204 user_mac_addr A user provided MAC string (e.g. "70:e2:84:14:2a:08") 205 """ 206 207 index = 0 208 # Example: ['70', 'e2', '84', '14', '2a', '08'] 209 mac_list = user_mac_addr.split(":") 210 for item in sys_mac_addr.split(":"): 211 if int(item, 16) == int(mac_list[index], 16): 212 index = index + 1 213 continue 214 return 0 215 216 return 1 217 218 219def get_os_ethtool(interface_name): 220 r""" 221 Get OS 'ethtool' output for the given interface_name and return it as a 222 dictionary. 223 224 Settings for enP52p1s0f0: 225 Supported ports: [ TP ] 226 Supported link modes: 10baseT/Half 10baseT/Full 227 100baseT/Half 100baseT/Full 228 1000baseT/Half 1000baseT/Full 229 Supported pause frame use: No 230 Supports auto-negotiation: Yes 231 Supported FEC modes: Not reported 232 Advertised link modes: 10baseT/Half 10baseT/Full 233 100baseT/Half 100baseT/Full 234 1000baseT/Half 1000baseT/Full 235 Advertised pause frame use: Symmetric 236 Advertised auto-negotiation: Yes 237 Advertised FEC modes: Not reported 238 Speed: Unknown! 239 Duplex: Unknown! (255) 240 Port: Twisted Pair 241 PHYAD: 1 242 Transceiver: internal 243 Auto-negotiation: on 244 MDI-X: Unknown 245 Supports Wake-on: g 246 Wake-on: g 247 Current message level: 0x000000ff (255) 248 drv probe link timer ifdown ifup rx_err tx_err 249 Link detected: no 250 251 Given that data, this function will return the following dictionary. 252 253 ethtool_dict: 254 [supported_ports]: [ TP ] 255 [supported_link_modes]: 256 [supported_link_modes][0]: 10baseT/Half 10baseT/Full 257 [supported_link_modes][1]: 100baseT/Half 100baseT/Full 258 [supported_link_modes][2]: 1000baseT/Half 1000baseT/Full 259 [supported_pause_frame_use]: No 260 [supports_auto-negotiation]: Yes 261 [supported_fec_modes]: Not reported 262 [advertised_link_modes]: 263 [advertised_link_modes][0]: 10baseT/Half 10baseT/Full 264 [advertised_link_modes][1]: 100baseT/Half 100baseT/Full 265 [advertised_link_modes][2]: 1000baseT/Half 1000baseT/Full 266 [advertised_pause_frame_use]: Symmetric 267 [advertised_auto-negotiation]: Yes 268 [advertised_fec_modes]: Not reported 269 [speed]: Unknown! 270 [duplex]: Unknown! (255) 271 [port]: Twisted Pair 272 [phyad]: 1 273 [transceiver]: internal 274 [auto-negotiation]: on 275 [mdi-x]: Unknown 276 [supports_wake-on]: g 277 [wake-on]: g 278 [current_message_level]: 0x000000ff (255) 279 [drv_probe_link_timer_ifdown_ifup_rx_err_tx_err]:<blank> 280 [link_detected]: no 281 """ 282 283 # Using sed and tail to massage the data a bit before running 284 # key_value_outbuf_to_dict. 285 cmd_buf = "ethtool " + interface_name +\ 286 " | sed -re 's/(.* link modes:)(.*)/\\1\\n\\2/g' | tail -n +2" 287 stdout, stderr, rc = bsu.os_execute_command(cmd_buf) 288 result = vf.key_value_outbuf_to_dict(stdout, process_indent=1, strip=" \t") 289 290 return result 291 292 293def to_json_ordered(json_str): 294 r""" 295 Parse the JSON string data and return an ordered JSON dictionary object. 296 297 Description of argument(s): 298 json_str The string containing the JSON data. 299 """ 300 301 try: 302 return json.loads(json_str, object_pairs_hook=DotDict) 303 except TypeError: 304 return json.loads(json_str.decode("utf-8"), object_pairs_hook=DotDict) 305