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