1#!/usr/bin/env python3 -u 2 3r""" 4Generic utility functions. 5""" 6 7import importlib.util 8import random 9import string 10import subprocess 11 12from robot.libraries.BuiltIn import BuiltIn 13from robot.utils import DotDict 14 15 16def load_source(name, module_path): 17 r""" 18 import util to replace deprecated imp.load_source 19 """ 20 spec = importlib.util.spec_from_file_location(name, module_path) 21 module = importlib.util.module_from_spec(spec) 22 spec.loader.exec_module(module) 23 return module 24 25 26def random_mac(): 27 r""" 28 Return random mac address in the following format. 29 Example: 00:01:6C:80:02:78 30 """ 31 return ":".join( 32 map( 33 lambda x: "%02x" % x, 34 (random.randint(0x00, 0xFF) for _ in range(6)), 35 ) 36 ) 37 38 39def random_ip(): 40 r""" 41 Return random ip address in the following format. 42 Example: 9.3.128.100 43 """ 44 return ".".join(map(str, (random.randint(0, 255) for _ in range(4)))) 45 46 47def get_sensor(module_name, value): 48 r""" 49 Return sensor matched ID name. 50 """ 51 m = load_source("module.name", module_name) 52 53 for i in m.ID_LOOKUP["SENSOR"]: 54 if m.ID_LOOKUP["SENSOR"][i] == value: 55 return i 56 57 return 0xFF 58 59 60def get_inventory_sensor(module_name, value): 61 r""" 62 Return sensor matched ID name from inventory. 63 """ 64 m = load_source("module.name", module_name) 65 66 value = string.replace(value, m.INVENTORY_ROOT, "<inventory_root>") 67 68 for i in m.ID_LOOKUP["SENSOR"]: 69 if m.ID_LOOKUP["SENSOR"][i] == value: 70 return i 71 72 return 0xFF 73 74 75################################################################ 76# This will return the URI's of the FRU type 77# 78# i.e. get_inventory_list('../data/Palmetto.py') 79# 80# [/org/openbmc/inventory/system/chassis/motherboard/cpu0/core0, 81# /org/openbmc/inventory/system/chassis/motherboard/dimm0] 82################################################################ 83def get_inventory_list(module_name): 84 r""" 85 Return all FRU URI(s) list available from inventory. 86 """ 87 88 inventory_list = [] 89 m = load_source("module.name", module_name) 90 91 for i in m.ID_LOOKUP["FRU"]: 92 s = m.ID_LOOKUP["FRU"][i] 93 s = s.replace("<inventory_root>", m.INVENTORY_ROOT) 94 inventory_list.append(s) 95 96 return inventory_list 97 98 99################################################################ 100# This will return the URI's of the FRU type 101# 102# i.e. get_inventory_fru_type_list('../data/Witherspoon.py', 'CPU') 103# 104# [/org/openbmc/inventory/system/chassis/motherboard/cpu0, 105# /org/openbmc/inventory/system/chassis/motherboard/cpu1] 106################################################################ 107def get_inventory_fru_type_list(module_name, fru): 108 r""" 109 Return FRU URI(s) list of a given type from inventory. 110 """ 111 inventory_list = [] 112 m = load_source("module.name", module_name) 113 114 for i in m.FRU_INSTANCES.keys(): 115 if m.FRU_INSTANCES[i]["fru_type"] == fru: 116 s = i.replace("<inventory_root>", m.INVENTORY_ROOT) 117 inventory_list.append(s) 118 119 return inventory_list 120 121 122################################################################ 123# This will return the URI's of the FRU type that contain VPD 124# 125# i.e. get_vpd_inventory_list('../data/Palmetto.py', 'DIMM') 126# 127# [/org/openbmc/inventory/system/chassis/motherboard/dimm0, 128# /org/openbmc/inventory/system/chassis/motherboard/dimm1] 129################################################################ 130def get_vpd_inventory_list(module_name, fru): 131 r""" 132 Return VPD URI(s) list of a FRU type from inventory. 133 """ 134 inventory_list = [] 135 m = load_source("module.name", module_name) 136 137 for i in m.ID_LOOKUP["FRU_STR"]: 138 x = m.ID_LOOKUP["FRU_STR"][i] 139 140 if m.FRU_INSTANCES[x]["fru_type"] == fru: 141 s = x.replace("<inventory_root>", m.INVENTORY_ROOT) 142 inventory_list.append(s) 143 144 return inventory_list 145 146 147def call_keyword(keyword): 148 r""" 149 Return result of the execute robot keyword. 150 """ 151 return BuiltIn().run_keyword(keyword) 152 153 154def main(): 155 r""" 156 Python main func call. 157 """ 158 print(get_vpd_inventory_list("../data/Palmetto.py", "DIMM")) 159 160 161if __name__ == "__main__": 162 main() 163 164 165def get_mtr_report(host=""): 166 r""" 167 Get an mtr report and return it as a dictionary of dictionaries. 168 169 The key for the top level dictionary will be the host DNS name. The key 170 for the next level dictionary will be the field of a given row of the 171 report. 172 173 Example result: 174 175 report: 176 report[host_dummy-dnsname.com]: 177 report[host_dummy-dnsname.com][row_num]: 1 178 report[host_dummy-dnsname.com][host]: host_dummy-dnsname.com 179 report[host_dummy-dnsname.com][loss]: 0.0 180 report[host_dummy-dnsname.com][snt]: 10 181 report[host_dummy-dnsname.com][last]: 0.2 182 report[host_dummy-dnsname.com][avg]: 3.5 183 report[host_dummy-dnsname.com][best]: 0.2 184 report[host_dummy-dnsname.com][wrst]: 32.5 185 report[host_dummy-dnsname.com][stdev]: 10.2 186 report[bmc-dummy-dnsname.com]: 187 report[bmc-dummy-dnsname.com][row_num]: 2 188 report[bmc-dummy-dnsname.com][host]: bmc-dummy-dnsname.com 189 report[bmc-dummy-dnsname.com][loss]: 0.0 190 report[bmc-dummy-dnsname.com][snt]: 10 191 report[bmc-dummy-dnsname.com][last]: 0.5 192 report[bmc-dummy-dnsname.com][avg]: 0.5 193 report[bmc-dummy-dnsname.com][best]: 0.5 194 report[bmc-dummy-dnsname.com][wrst]: 0.5 195 report[bmc-dummy-dnsname.com][stdev]: 0.0 196 197 Description of arguments: 198 host The DNS name or IP address to be passed to the mtr command. 199 """ 200 201 # Run the mtr command. Exclude the header line. Trim leading space from 202 # each line. Change all multiple spaces delims to single space delims. 203 cmd_buf = ( 204 "mtr --report " 205 + host 206 + " | tail -n +2 | sed -r -e 's/^[ ]+//g' -e 's/[ ]+/ /g'" 207 ) 208 sub_proc = subprocess.Popen( 209 cmd_buf, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT 210 ) 211 out_buf, err_buf = sub_proc.communicate() 212 shell_rc = sub_proc.returncode 213 out_buf = out_buf.decode("utf-8") 214 215 # Split the output by line. 216 rows = out_buf.rstrip("\n").split("\n") 217 218 # Initialize report dictionary. 219 report = DotDict() 220 for row in rows: 221 # Process each row of mtr output. 222 # Create a list of fields by splitting on space delimiter. 223 row_list = row.split(" ") 224 # Create dictionary for the row. 225 row = DotDict() 226 row["row_num"] = row_list[0].rstrip(".") 227 row["host"] = row_list[1] 228 row["loss"] = row_list[2].rstrip("%") 229 row["snt"] = row_list[3] 230 row["last"] = row_list[4] 231 row["avg"] = row_list[5] 232 row["best"] = row_list[6] 233 row["wrst"] = row_list[7] 234 row["stdev"] = row_list[8] 235 report[row["host"]] = row 236 237 # Return the full report as dictionary of dictionaries. 238 return report 239 240 241def get_mtr_row(host=""): 242 r""" 243 Run an mtr report and get a specified row and return it as a dictionary. 244 245 Example result: 246 247 row: 248 row[row_num]: 2 249 row[host]: bmc-dummy-dnsname.com 250 row[loss]: 0.0 251 row[snt]: 10 252 row[last]: 0.5 253 row[avg]: 0.5 254 row[best]: 0.4 255 row[wrst]: 0.7 256 row[stdev]: 0.1 257 258 Description of arguments: 259 host The DNS name or IP address to be passed to the mtr command as 260 well as the indicating which row of the report to return. 261 """ 262 263 report = get_mtr_report(host) 264 265 # The max length of host in output is 28 chars. 266 host_part = host[:28] 267 268 row = [ 269 value 270 for key, value in report.items() 271 if key in host or host_part in key 272 ][0] 273 274 return row 275 276 277def list_to_set(fru_list=""): 278 r""" 279 Pack the list into a set tuple and return. 280 281 It may seem that this function is rather trivial. However, it simplifies 282 the code and improves robot program readability and achieve the result 283 required. 284 285 Example result: 286 287 set(['Version', 'PartNumber', 'SerialNumber', 'FieldReplaceable', 288 'BuildDate', 'Present', 'Manufacturer', 'PrettyName', 'Cached', 'Model']) 289 290 # Description of arguments. 291 fru_list List of FRU's elements. 292 """ 293 return set(fru_list) 294 295 296def min_list_value(value_list): 297 r""" 298 Returns the element from the list with minimum value. 299 """ 300 return min(value_list) 301 302 303def convert_lsb_to_msb(string): 304 r""" 305 Reverse given string (From LSB first to MSB first) and converts to HEX. 306 307 Input string 0a 00 308 Return string 0a 309 """ 310 datalist = string.split(" ") 311 new_list = datalist[::-1] 312 new_string = "".join([str(element) for element in new_list]) 313 return int(new_string, 16) 314 315 316def add_prefix_to_string(string, prefix): 317 r""" 318 Add given prefix to the string and return string. 319 320 Input string 0a 01 321 Return string 0x0a 0x01 322 """ 323 prefix_string = "" 324 data_list = string.strip().split(" ") 325 for item in data_list: 326 prefix_string += prefix + item + " " 327 return prefix_string.strip() 328 329 330def get_value_from_nested_dict(key, nested_dict): 331 r""" 332 Returns the key value from the nested dictionary. 333 334 key Key value of the dictionary to look up. 335 nested_dict Dictionary data. 336 """ 337 result = [] 338 for k, v in nested_dict.items(): 339 if k == key: 340 result.append(v) 341 elif isinstance(v, dict) and k != key: 342 result += get_value_from_nested_dict(key, v) 343 344 return result 345