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