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    out_buf = out_buf.decode("utf-8")
203
204    # Split the output by line.
205    rows = out_buf.rstrip("\n").split("\n")
206
207    # Initialize report dictionary.
208    report = DotDict()
209    for row in rows:
210        # Process each row of mtr output.
211        # Create a list of fields by splitting on space delimiter.
212        row_list = row.split(" ")
213        # Create dictionary for the row.
214        row = DotDict()
215        row["row_num"] = row_list[0].rstrip(".")
216        row["host"] = row_list[1]
217        row["loss"] = row_list[2].rstrip("%")
218        row["snt"] = row_list[3]
219        row["last"] = row_list[4]
220        row["avg"] = row_list[5]
221        row["best"] = row_list[6]
222        row["wrst"] = row_list[7]
223        row["stdev"] = row_list[8]
224        report[row["host"]] = row
225
226    # Return the full report as dictionary of dictionaries.
227    return report
228
229
230def get_mtr_row(host=""):
231    r"""
232    Run an mtr report and get a specified row and return it as a dictionary.
233
234    Example result:
235
236    row:
237      row[row_num]:              2
238      row[host]:                 bmc-dummy-dnsname.com
239      row[loss]:                 0.0
240      row[snt]:                  10
241      row[last]:                 0.5
242      row[avg]:                  0.5
243      row[best]:                 0.4
244      row[wrst]:                 0.7
245      row[stdev]:                0.1
246
247    Description of arguments:
248    host   The DNS name or IP address to be passed to the mtr command as
249           well as the indicating which row of the report to return.
250    """
251
252    report = get_mtr_report(host)
253
254    # The max length of host in output is 28 chars.
255    row = [value for key, value in report.items() if host[0:28] in key][0]
256
257    return row
258
259
260def list_to_set(fru_list=""):
261    r"""
262    Pack the list into a set tuple and return.
263
264    It may seem that this function is rather trivial. However, it simplifies
265    the code and improves robot program readability and achieve the result
266    required.
267
268    Example result:
269
270    set(['Version', 'PartNumber', 'SerialNumber', 'FieldReplaceable',
271    'BuildDate', 'Present', 'Manufacturer', 'PrettyName', 'Cached', 'Model'])
272
273    # Description of arguments.
274    fru_list   List of FRU's elements.
275    """
276    return set(fru_list)
277
278
279def min_list_value(value_list):
280    r"""
281    Returns the element from the list with minimum value.
282    """
283    return min(value_list)
284
285
286def convert_lsb_to_msb(string):
287    r"""
288    Reverse given string (From LSB first to MSB first) and converts to HEX.
289
290    Input string     0a 00
291    Return string    0a
292    """
293    datalist = string.split(" ")
294    new_list = datalist[::-1]
295    new_string = "".join([str(element) for element in new_list])
296    return int(new_string, 16)
297
298
299def add_prefix_to_string(string, prefix):
300    r"""
301    Add given prefix to the string and return string.
302
303    Input string      0a 01
304    Return string     0x0a 0x01
305    """
306    prefix_string = ""
307    data_list = string.strip().split(" ")
308    for item in data_list:
309        prefix_string += prefix + item + " "
310    return prefix_string.strip()
311
312
313def get_value_from_nested_dict(key, nested_dict):
314    r"""
315    Returns the key value from the nested dictionary.
316
317    key               Key value of the dictionary to look up.
318    nested_dict       Dictionary data.
319    """
320    result = []
321    for k, v in nested_dict.items():
322        if k == key:
323            result.append(v)
324        elif isinstance(v, dict) and k != key:
325            result += get_value_from_nested_dict(key, v)
326
327    return result
328