1#!/usr/bin/env python 2 3r""" 4Provide useful ipmi functions. 5""" 6 7import re 8import gen_print as gp 9import gen_misc as gm 10import gen_robot_keyword as grk 11import gen_robot_utils as gru 12import bmc_ssh_utils as bsu 13import var_funcs as vf 14import tempfile 15gru.my_import_resource("ipmi_client.robot") 16from robot.libraries.BuiltIn import BuiltIn 17 18 19def get_sol_info(): 20 r""" 21 Get all SOL info and return it as a dictionary. 22 23 Example use: 24 25 Robot code: 26 ${sol_info}= get_sol_info 27 Rpvars sol_info 28 29 Output: 30 sol_info: 31 sol_info[Info]: SOL parameter 'Payload Channel (7)' 32 not supported - defaulting to 0x0e 33 sol_info[Character Send Threshold]: 1 34 sol_info[Force Authentication]: true 35 sol_info[Privilege Level]: USER 36 sol_info[Set in progress]: set-complete 37 sol_info[Retry Interval (ms)]: 100 38 sol_info[Non-Volatile Bit Rate (kbps)]: IPMI-Over-Serial-Setting 39 sol_info[Character Accumulate Level (ms)]: 100 40 sol_info[Enabled]: true 41 sol_info[Volatile Bit Rate (kbps)]: IPMI-Over-Serial-Setting 42 sol_info[Payload Channel]: 14 (0x0e) 43 sol_info[Payload Port]: 623 44 sol_info[Force Encryption]: true 45 sol_info[Retry Count]: 7 46 """ 47 48 status, ret_values = grk.run_key_u("Run IPMI Standard Command sol info") 49 50 # Create temp file path. 51 temp = tempfile.NamedTemporaryFile() 52 temp_file_path = temp.name 53 54 # Write sol info to temp file path. 55 text_file = open(temp_file_path, "w") 56 text_file.write(ret_values) 57 text_file.close() 58 59 # Use my_parm_file to interpret data. 60 sol_info = gm.my_parm_file(temp_file_path) 61 62 return sol_info 63 64 65def set_sol_setting(setting_name, setting_value): 66 r""" 67 Set SOL setting with given value. 68 69 # Description of argument(s): 70 # setting_name SOL setting which needs to be set (e.g. 71 # "retry-count"). 72 # setting_value Value which needs to be set (e.g. "7"). 73 """ 74 75 status, ret_values = grk.run_key_u("Run IPMI Standard Command sol set " 76 + setting_name + " " + setting_value) 77 78 return status 79 80 81def get_lan_print_dict(): 82 r""" 83 Get IPMI 'lan print' output and return it as a dictionary. 84 85 Here is an example of the IPMI lan print output: 86 87 Set in Progress : Set Complete 88 Auth Type Support : MD5 89 Auth Type Enable : Callback : MD5 90 : User : MD5 91 : Operator : MD5 92 : Admin : MD5 93 : OEM : MD5 94 IP Address Source : Static Address 95 IP Address : x.x.x.x 96 Subnet Mask : x.x.x.x 97 MAC Address : xx:xx:xx:xx:xx:xx 98 Default Gateway IP : x.x.x.x 99 802.1q VLAN ID : Disabled 100 Cipher Suite Priv Max : Not Available 101 Bad Password Threshold : Not Available 102 103 Given that data, this function will return the following dictionary. 104 105 lan_print_dict: 106 [Set in Progress]: Set Complete 107 [Auth Type Support]: MD5 108 [Auth Type Enable]: 109 [Callback]: MD5 110 [User]: MD5 111 [Operator]: MD5 112 [Admin]: MD5 113 [OEM]: MD5 114 [IP Address Source]: Static Address 115 [IP Address]: x.x.x.x 116 [Subnet Mask]: x.x.x.x 117 [MAC Address]: xx:xx:xx:xx:xx:xx 118 [Default Gateway IP]: x.x.x.x 119 [802.1q VLAN ID]: Disabled 120 [Cipher Suite Priv Max]: Not Available 121 [Bad Password Threshold]: Not Available 122 123 """ 124 125 IPMI_INBAND_CMD = BuiltIn().get_variable_value("${IPMI_INBAND_CMD}") 126 127 # Notice in the example of data above that 'Auth Type Enable' needs some 128 # special processing. We essentially want to isolate its data and remove 129 # the 'Auth Type Enable' string so that key_value_outbuf_to_dict can 130 # process it as a sub-dictionary. 131 cmd_buf = IPMI_INBAND_CMD + " lan print | grep -E '^(Auth Type Enable)" +\ 132 "?[ ]+: ' | sed -re 's/^(Auth Type Enable)?[ ]+: //g'" 133 stdout1, stderr, rc = bsu.os_execute_command(cmd_buf) 134 135 # Now get the remainder of the data and exclude the lines with no field 136 # names (i.e. the 'Auth Type Enable' sub-fields). 137 cmd_buf = IPMI_INBAND_CMD + " lan print | grep -E -v '^[ ]+: '" 138 stdout2, stderr, rc = bsu.os_execute_command(cmd_buf) 139 140 # Make auth_type_enable_dict sub-dictionary... 141 auth_type_enable_dict = vf.key_value_outbuf_to_dict(stdout1, to_lower=0, 142 underscores=0) 143 144 # Create the lan_print_dict... 145 lan_print_dict = vf.key_value_outbuf_to_dict(stdout2, to_lower=0, 146 underscores=0) 147 # Re-assign 'Auth Type Enable' to contain the auth_type_enable_dict. 148 lan_print_dict['Auth Type Enable'] = auth_type_enable_dict 149 150 return lan_print_dict 151 152 153def get_ipmi_power_reading(strip_watts=1): 154 r""" 155 Get IPMI power reading data and return it as a dictionary. 156 157 The data is obtained by issuing the IPMI "power reading" command. An 158 example is shown below: 159 160 Instantaneous power reading: 234 Watts 161 Minimum during sampling period: 234 Watts 162 Maximum during sampling period: 234 Watts 163 Average power reading over sample period: 234 Watts 164 IPMI timestamp: Thu Jan 1 00:00:00 1970 165 Sampling period: 00000000 Seconds. 166 Power reading state is: deactivated 167 168 For the data shown above, the following dictionary will be returned. 169 170 result: 171 [instantaneous_power_reading]: 238 Watts 172 [minimum_during_sampling_period]: 238 Watts 173 [maximum_during_sampling_period]: 238 Watts 174 [average_power_reading_over_sample_period]: 238 Watts 175 [ipmi_timestamp]: Thu Jan 1 00:00:00 1970 176 [sampling_period]: 00000000 Seconds. 177 [power_reading_state_is]: deactivated 178 179 Description of argument(s): 180 strip_watts Strip all dictionary values of the 181 trailing " Watts" substring. 182 """ 183 184 status, ret_values = \ 185 grk.run_key_u("Run IPMI Standard Command dcmi power reading") 186 result = vf.key_value_outbuf_to_dict(ret_values) 187 188 if strip_watts: 189 result.update((k, re.sub(' Watts$', '', v)) for k, v in result.items()) 190 191 return result 192 193 194def get_mc_info(): 195 r""" 196 Get IPMI mc info data and return it as a dictionary. 197 198 The data is obtained by issuing the IPMI "mc info" command. An 199 example is shown below: 200 201 Device ID : 0 202 Device Revision : 0 203 Firmware Revision : 2.01 204 IPMI Version : 2.0 205 Manufacturer ID : 42817 206 Manufacturer Name : Unknown (0xA741) 207 Product ID : 16975 (0x424f) 208 Product Name : Unknown (0x424F) 209 Device Available : yes 210 Provides Device SDRs : yes 211 Additional Device Support : 212 Sensor Device 213 SEL Device 214 FRU Inventory Device 215 Chassis Device 216 Aux Firmware Rev Info : 217 0x00 218 0x00 219 0x00 220 0x00 221 222 For the data shown above, the following dictionary will be returned. 223 mc_info: 224 [device_id]: 0 225 [device_revision]: 0 226 [firmware_revision]: 2.01 227 [ipmi_version]: 2.0 228 [manufacturer_id]: 42817 229 [manufacturer_name]: Unknown (0xA741) 230 [product_id]: 16975 (0x424f) 231 [product_name]: Unknown (0x424F) 232 [device_available]: yes 233 [provides_device_sdrs]: yes 234 [additional_device_support]: 235 [additional_device_support][0]: Sensor Device 236 [additional_device_support][1]: SEL Device 237 [additional_device_support][2]: FRU Inventory Device 238 [additional_device_support][3]: Chassis Device 239 [aux_firmware_rev_info]: 240 [aux_firmware_rev_info][0]: 0x00 241 [aux_firmware_rev_info][1]: 0x00 242 [aux_firmware_rev_info][2]: 0x00 243 [aux_firmware_rev_info][3]: 0x00 244 """ 245 246 status, ret_values = \ 247 grk.run_key_u("Run IPMI Standard Command mc info") 248 result = vf.key_value_outbuf_to_dict(ret_values, process_indent=1) 249 250 return result 251 252 253def get_sdr_info(): 254 r""" 255 Get IPMI sdr info data and return it as a dictionary. 256 257 The data is obtained by issuing the IPMI "sdr info" command. An 258 example is shown below: 259 260 SDR Version : 0x51 261 Record Count : 216 262 Free Space : unspecified 263 Most recent Addition : 264 Most recent Erase : 265 SDR overflow : no 266 SDR Repository Update Support : unspecified 267 Delete SDR supported : no 268 Partial Add SDR supported : no 269 Reserve SDR repository supported : no 270 SDR Repository Alloc info supported : no 271 272 For the data shown above, the following dictionary will be returned. 273 mc_info: 274 275 [sdr_version]: 0x51 276 [record_Count]: 216 277 [free_space]: unspecified 278 [most_recent_addition]: 279 [most_recent_erase]: 280 [sdr_overflow]: no 281 [sdr_repository_update_support]: unspecified 282 [delete_sdr_supported]: no 283 [partial_add_sdr_supported]: no 284 [reserve_sdr_repository_supported]: no 285 [sdr_repository_alloc_info_supported]: no 286 """ 287 288 status, ret_values = \ 289 grk.run_key_u("Run IPMI Standard Command sdr info") 290 result = vf.key_value_outbuf_to_dict(ret_values, process_indent=1) 291 292 return result 293 294 295def get_aux_version(version_id): 296 r""" 297 Get IPMI Aux version info data and return it. 298 299 Description of argument(s): 300 version_id The data is obtained by from BMC 301 /etc/os-release 302 (e.g. "xxx-v2.1-438-g0030304-r3-gfea8585"). 303 304 In the prior example, the 3rd field is "438" is the commit version and 305 the 5th field is "r3" and value "3" is the release version. 306 307 Aux version return from this function 4380003. 308 """ 309 310 # Commit version. 311 count = re.findall("-(\\d{1,4})-", version_id) 312 313 # Release version. 314 release = re.findall("-r(\\d{1,4})", version_id) 315 if release: 316 aux_version = count[0] + "{0:0>4}".format(release[0]) 317 else: 318 aux_version = count[0] + "0000" 319 320 return aux_version 321 322 323def get_fru_info(): 324 r""" 325 Get fru info and return it as a list of dictionaries. 326 327 The data is obtained by issuing the IPMI "fru print -N 50" command. An 328 example is shown below: 329 330 FRU Device Description : Builtin FRU Device (ID 0) 331 Device not present (Unspecified error) 332 333 FRU Device Description : cpu0 (ID 1) 334 Board Mfg Date : Sun Dec 31 18:00:00 1995 335 Board Mfg : <Manufacturer Name> 336 Board Product : PROCESSOR MODULE 337 Board Serial : YA1934315964 338 Board Part Number : 02CY209 339 340 FRU Device Description : cpu1 (ID 2) 341 Board Mfg Date : Sun Dec 31 18:00:00 1995 342 Board Mfg : <Manufacturer Name> 343 Board Product : PROCESSOR MODULE 344 Board Serial : YA1934315965 345 Board Part Number : 02CY209 346 347 For the data shown above, the following list of dictionaries will be 348 returned. 349 350 fru_obj: 351 fru_obj[0]: 352 [fru_device_description]: Builtin FRU Device (ID 0) 353 [state]: Device not present (Unspecified error) 354 fru_obj[1]: 355 [fru_device_description]: cpu0 (ID 1) 356 [board_mfg_date]: Sun Dec 31 18:00:00 1995 357 [board_mfg]: <Manufacturer Name> 358 [board_product]: PROCESSOR MODULE 359 [board_serial]: YA1934315964 360 [board_part_number]: 02CY209 361 fru_obj[2]: 362 [fru_device_description]: cpu1 (ID 2) 363 [board_mfg_date]: Sun Dec 31 18:00:00 1995 364 [board_mfg]: <Manufacturer Name> 365 [board_product]: PROCESSOR MODULE 366 [board_serial]: YA1934315965 367 [board_part_number]: 02CY209 368 """ 369 370 status, ret_values = \ 371 grk.run_key_u("Run IPMI Standard Command fru print -N 50") 372 373 # Manipulate the "Device not present" line to create a "state" key. 374 ret_values = re.sub("Device not present", "state : Device not present", 375 ret_values) 376 377 return [vf.key_value_outbuf_to_dict(x) for x in re.split("\n\n", 378 ret_values)] 379 380 381def get_component_fru_info(component='cpu', 382 fru_objs=None): 383 r""" 384 Get fru info for the given component and return it as a list of 385 dictionaries. 386 387 This function calls upon get_fru_info and then filters out the unwanted 388 entries. See get_fru_info's prolog for a layout of the data. 389 390 Description of argument(s): 391 component The component (e.g. "cpu", "dimm", etc.). 392 fru_objs A fru_objs list such as the one returned 393 by get_fru_info. If this is None, then 394 this function will call get_fru_info to 395 obtain such a list. 396 Supplying this argument may improve 397 performance if this function is to be 398 called multiple times. 399 """ 400 401 if fru_objs is None: 402 fru_objs = get_fru_info() 403 return\ 404 [x for x in fru_objs 405 if re.match(component + '([0-9]+)? ', x['fru_device_description'])] 406