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 row = [value for key, value in report.items() if host[0:28] in key][0] 266 267 return row 268 269 270def list_to_set(fru_list=""): 271 r""" 272 Pack the list into a set tuple and return. 273 274 It may seem that this function is rather trivial. However, it simplifies 275 the code and improves robot program readability and achieve the result 276 required. 277 278 Example result: 279 280 set(['Version', 'PartNumber', 'SerialNumber', 'FieldReplaceable', 281 'BuildDate', 'Present', 'Manufacturer', 'PrettyName', 'Cached', 'Model']) 282 283 # Description of arguments. 284 fru_list List of FRU's elements. 285 """ 286 return set(fru_list) 287 288 289def min_list_value(value_list): 290 r""" 291 Returns the element from the list with minimum value. 292 """ 293 return min(value_list) 294 295 296def convert_lsb_to_msb(string): 297 r""" 298 Reverse given string (From LSB first to MSB first) and converts to HEX. 299 300 Input string 0a 00 301 Return string 0a 302 """ 303 datalist = string.split(" ") 304 new_list = datalist[::-1] 305 new_string = "".join([str(element) for element in new_list]) 306 return int(new_string, 16) 307 308 309def add_prefix_to_string(string, prefix): 310 r""" 311 Add given prefix to the string and return string. 312 313 Input string 0a 01 314 Return string 0x0a 0x01 315 """ 316 prefix_string = "" 317 data_list = string.strip().split(" ") 318 for item in data_list: 319 prefix_string += prefix + item + " " 320 return prefix_string.strip() 321 322 323def get_value_from_nested_dict(key, nested_dict): 324 r""" 325 Returns the key value from the nested dictionary. 326 327 key Key value of the dictionary to look up. 328 nested_dict Dictionary data. 329 """ 330 result = [] 331 for k, v in nested_dict.items(): 332 if k == key: 333 result.append(v) 334 elif isinstance(v, dict) and k != key: 335 result += get_value_from_nested_dict(key, v) 336 337 return result 338