1e7e9171eSGeorge Keishing#!/usr/bin/env python3
24d488571SRahul Maheshwari
34d488571SRahul Maheshwarir"""
44d488571SRahul MaheshwariPLDM functions.
54d488571SRahul Maheshwari"""
64d488571SRahul Maheshwari
7961050baSSridevi Rameshimport json
82ab3d388SSridevi Rameshimport random
920f38712SPatrick Williamsimport re
102ab3d388SSridevi Rameshimport string
1120f38712SPatrick Williams
1220f38712SPatrick Williamsimport bmc_ssh_utils as bsu
1320f38712SPatrick Williamsimport func_args as fa
1420f38712SPatrick Williamsimport var_funcs as vf
15ba3cb8c0SAnusha Dathatrifrom robot.api import logger
164d488571SRahul Maheshwari
174d488571SRahul Maheshwari
18961050baSSridevi Rameshdef pldmtool(option_string, **bsu_options):
194d488571SRahul Maheshwari    r"""
204d488571SRahul Maheshwari    Run pldmtool on the BMC with the caller's option string and return the result.
214d488571SRahul Maheshwari
224d488571SRahul Maheshwari    Example:
234d488571SRahul Maheshwari
244d488571SRahul Maheshwari    ${pldm_results}=  Pldmtool  base GetPLDMTypes
254d488571SRahul Maheshwari    Rprint Vars  pldm_results
264d488571SRahul Maheshwari
274d488571SRahul Maheshwari    pldm_results:
28961050baSSridevi Ramesh      pldmtool base GetPLDMVersion -t 0
29961050baSSridevi Ramesh      {
30961050baSSridevi Ramesh          "Response": "1.0.0"
31961050baSSridevi Ramesh      }
32961050baSSridevi Ramesh
334d488571SRahul Maheshwari    Description of argument(s):
34b9080fc5SGeorge Keishing    option_string         A string of options which are to be processed by the
35b9080fc5SGeorge Keishing                          pldmtool command.
36b9080fc5SGeorge Keishing    parse_results         Parse the pldmtool results and return a dictionary
37b9080fc5SGeorge Keishing                          rather than the raw
384d488571SRahul Maheshwari                          pldmtool output.
39b9080fc5SGeorge Keishing    bsu_options           Options to be passed directly to bmc_execute_command.
40b9080fc5SGeorge Keishing                          See its prolog for details.
414d488571SRahul Maheshwari    """
424d488571SRahul Maheshwari
43b9080fc5SGeorge Keishing    # This allows callers to specify arguments in python style
44b9080fc5SGeorge Keishing    # (e.g. print_out=1 vs. print_out=${1}).
454d488571SRahul Maheshwari    bsu_options = fa.args_to_objects(bsu_options)
464d488571SRahul Maheshwari
4720f38712SPatrick Williams    stdout, stderr, rc = bsu.bmc_execute_command(
48*a4ab9f33SSridevi Ramesh        "pldmtool " + option_string, **bsu_options, ignore_err=1
4920f38712SPatrick Williams    )
502ab3d388SSridevi Ramesh    if stderr:
512ab3d388SSridevi Ramesh        return stderr
522ab3d388SSridevi Ramesh    try:
53961050baSSridevi Ramesh        return json.loads(stdout)
542ab3d388SSridevi Ramesh    except ValueError:
552ab3d388SSridevi Ramesh        return stdout
5657537452SSridevi Ramesh
5757537452SSridevi Ramesh
582ab3d388SSridevi Rameshdef GetBIOSEnumAttributeOptionalValues(attr_val_table_data):
5957537452SSridevi Ramesh    """
602ab3d388SSridevi Ramesh    From pldmtool GetBIOSTable of type AttributeValueTable get the dict of
612ab3d388SSridevi Ramesh    attribute handle and its optional values for BIOS Enumeration type.
6257537452SSridevi Ramesh
6357537452SSridevi Ramesh    Description of argument(s):
6457537452SSridevi Ramesh    attr_val_table_data     pldmtool output from GetBIOSTable table type AttributeValueTable
6557537452SSridevi Ramesh                            e.g.
6657537452SSridevi Ramesh                            [{
6757537452SSridevi Ramesh                                  "AttributeHandle": 20,
6857537452SSridevi Ramesh                                  "AttributeNameHandle": "23(pvm-pcie-error-inject)",
6957537452SSridevi Ramesh                                  "AttributeType": "BIOSEnumeration",
7057537452SSridevi Ramesh                                  "NumberOfPossibleValues": 2,
7157537452SSridevi Ramesh                                  "PossibleValueStringHandle[0]": "3(Disabled)",
7257537452SSridevi Ramesh                                  "PossibleValueStringHandle[1]": "4(Enabled)",
7357537452SSridevi Ramesh                                  "NumberOfDefaultValues": 1,
7457537452SSridevi Ramesh                                  "DefaultValueStringHandleIndex[0]": 1,
7557537452SSridevi Ramesh                                  "StringHandle": "4(Enabled)"
7657537452SSridevi Ramesh                             }]
7757537452SSridevi Ramesh    @return                  Dictionary of BIOS attribute and its value.
782ab3d388SSridevi Ramesh                             e.g. {'pvm_pcie_error_inject': ['Disabled', 'Enabled']}
7957537452SSridevi Ramesh    """
8057537452SSridevi Ramesh
8157537452SSridevi Ramesh    attr_val_data_dict = {}
8257537452SSridevi Ramesh    for item in attr_val_table_data:
8357537452SSridevi Ramesh        for attr in item:
8420f38712SPatrick Williams            if attr == "NumberOfPossibleValues":
8557537452SSridevi Ramesh                value_list = []
8657537452SSridevi Ramesh                for i in range(0, int(item[attr])):
8720f38712SPatrick Williams                    attr_values = item[
8820f38712SPatrick Williams                        "PossibleValueStringHandle[" + str(i) + "]"
8920f38712SPatrick Williams                    ]
9020f38712SPatrick Williams                    value = re.search(r"\((.*?)\)", attr_values).group(1)
9157537452SSridevi Ramesh                    if value:
9257537452SSridevi Ramesh                        # Example:
9357537452SSridevi Ramesh                        # value = '"Power Off"'
9420f38712SPatrick Williams                        if " " in value:
9557537452SSridevi Ramesh                            value = '"' + value + '"'
9657537452SSridevi Ramesh                        value_list.append(value)
9757537452SSridevi Ramesh                    else:
9820f38712SPatrick Williams                        value_list.append("")
9957537452SSridevi Ramesh
10020f38712SPatrick Williams                attr_handle = re.findall(
10120f38712SPatrick Williams                    r"\(.*?\)", item["AttributeNameHandle"]
10220f38712SPatrick Williams                )
10357537452SSridevi Ramesh                attr_val_data_dict[attr_handle[0][1:-1]] = value_list
10457537452SSridevi Ramesh    return attr_val_data_dict
1052ab3d388SSridevi Ramesh
1062ab3d388SSridevi Ramesh
1072ab3d388SSridevi Rameshdef GetBIOSStrAndIntAttributeHandles(attr_type, attr_val_table_data):
1082ab3d388SSridevi Ramesh    """
1092ab3d388SSridevi Ramesh    From pldmtool GetBIOSTable of type AttributeValueTable get the dict of
1102ab3d388SSridevi Ramesh    attribute handle and its values based on the attribute type.
1112ab3d388SSridevi Ramesh
1122ab3d388SSridevi Ramesh    Description of argument(s):
1132ab3d388SSridevi Ramesh    attr_type               "BIOSInteger" or "BIOSString".
1142ab3d388SSridevi Ramesh    attr_val_table_data     pldmtool output from GetBIOSTable table type AttributeValueTable.
1152ab3d388SSridevi Ramesh
1162ab3d388SSridevi Ramesh    @return                 Dict of BIOS attribute and its value based on attribute type.
1172ab3d388SSridevi Ramesh
1182ab3d388SSridevi Ramesh    """
1192ab3d388SSridevi Ramesh    attr_val_int_dict = {}
1202ab3d388SSridevi Ramesh    attr_val_str_dict = {}
1212ab3d388SSridevi Ramesh    for item in attr_val_table_data:
1222ab3d388SSridevi Ramesh        value_dict = {}
12320f38712SPatrick Williams        attr_handle = re.findall(r"\(.*?\)", item["AttributeNameHandle"])
1242ab3d388SSridevi Ramesh        # Example:
1252ab3d388SSridevi Ramesh        # {'vmi_if0_ipv4_prefix_length': {'UpperBound': 32, 'LowerBound': 0}
12620f38712SPatrick Williams        if item["AttributeType"] == "BIOSInteger":
1272ab3d388SSridevi Ramesh            value_dict["LowerBound"] = item["LowerBound"]
1282ab3d388SSridevi Ramesh            value_dict["UpperBound"] = item["UpperBound"]
1292ab3d388SSridevi Ramesh            attr_val_int_dict[attr_handle[0][1:-1]] = value_dict
1302ab3d388SSridevi Ramesh        # Example:
1312ab3d388SSridevi Ramesh        # {'vmi_if1_ipv4_ipaddr': {'MaximumStringLength': 15, 'MinimumStringLength': 7}}
13220f38712SPatrick Williams        elif item["AttributeType"] == "BIOSString":
1332ab3d388SSridevi Ramesh            value_dict["MinimumStringLength"] = item["MinimumStringLength"]
1342ab3d388SSridevi Ramesh            value_dict["MaximumStringLength"] = item["MaximumStringLength"]
1352ab3d388SSridevi Ramesh            attr_val_str_dict[attr_handle[0][1:-1]] = value_dict
1362ab3d388SSridevi Ramesh
13720f38712SPatrick Williams    if attr_type == "BIOSInteger":
1382ab3d388SSridevi Ramesh        return attr_val_int_dict
139b9080fc5SGeorge Keishing    if attr_type == "BIOSString":
1402ab3d388SSridevi Ramesh        return attr_val_str_dict
1412ab3d388SSridevi Ramesh
142b9080fc5SGeorge Keishing    return None
143b9080fc5SGeorge Keishing
1442ab3d388SSridevi Ramesh
1452ab3d388SSridevi Rameshdef GetRandomBIOSIntAndStrValues(attr_name, count):
1462ab3d388SSridevi Ramesh    """
1472ab3d388SSridevi Ramesh    Get random integer or string values for BIOS attribute values based on the count.
1482ab3d388SSridevi Ramesh
1492ab3d388SSridevi Ramesh    Description of argument(s):
1502ab3d388SSridevi Ramesh    attr_name               Attribute name of BIOS attribute type Integer or string.
1512ab3d388SSridevi Ramesh    count                   Max length for BIOS attribute type Integer or string.
1522ab3d388SSridevi Ramesh
1532ab3d388SSridevi Ramesh    @return                 Random attribute value based on BIOS attribute type Integer
1542ab3d388SSridevi Ramesh                            or string.
1552ab3d388SSridevi Ramesh
1562ab3d388SSridevi Ramesh    """
15720f38712SPatrick Williams    attr_random_value = ""
1582ab3d388SSridevi Ramesh
1592ab3d388SSridevi Ramesh    # Example
1602ab3d388SSridevi Ramesh    # 12.13.14.15
16120f38712SPatrick Williams    if "gateway" in attr_name:
16220f38712SPatrick Williams        attr_random_value = ".".join(
16320f38712SPatrick Williams            map(str, (random.randint(0, 255) for _ in range(4)))
16420f38712SPatrick Williams        )
1652ab3d388SSridevi Ramesh    # Example
1662ab3d388SSridevi Ramesh    # 11.11.11.11
16720f38712SPatrick Williams    elif "ipaddr" in attr_name:
16820f38712SPatrick Williams        attr_random_value = ".".join(
16920f38712SPatrick Williams            map(str, (random.randint(0, 255) for _ in range(4)))
17020f38712SPatrick Williams        )
1712ab3d388SSridevi Ramesh    # Example
1722ab3d388SSridevi Ramesh    # E5YWEDWJJ
17320f38712SPatrick Williams    elif "name" in attr_name:
1742ab3d388SSridevi Ramesh        data = string.ascii_uppercase + string.digits
17520f38712SPatrick Williams        attr_random_value = "".join(
17620f38712SPatrick Williams            random.choice(data) for _ in range(int(count))
17720f38712SPatrick Williams        )
1782ab3d388SSridevi Ramesh
17920f38712SPatrick Williams    elif "mfg_flags" in attr_name:
18074291d46SSridevi Ramesh        data = string.ascii_uppercase + string.digits
18120f38712SPatrick Williams        attr_random_value = "".join(
18220f38712SPatrick Williams            random.choice(data) for _ in range(int(count))
18320f38712SPatrick Williams        )
18474291d46SSridevi Ramesh
18520f38712SPatrick Williams    elif "hb_lid_ids" in attr_name:
18648615cd9SSridevi Ramesh        attr_random_value = str(random.randint(0, int(count)))
18748615cd9SSridevi Ramesh
1882ab3d388SSridevi Ramesh    else:
1892ab3d388SSridevi Ramesh        attr_random_value = random.randint(0, int(count))
1902ab3d388SSridevi Ramesh    return attr_random_value
1912ab3d388SSridevi Ramesh
1922ab3d388SSridevi Ramesh
1932ab3d388SSridevi Rameshdef GetBIOSAttrOriginalValues(attr_val_table_data):
1942ab3d388SSridevi Ramesh    """
1952ab3d388SSridevi Ramesh    From pldmtool GetBIOSTable of type AttributeValueTable get the dict of
1962ab3d388SSridevi Ramesh    attribute handle and its values.
1972ab3d388SSridevi Ramesh
1982ab3d388SSridevi Ramesh    Description of argument(s):
1992ab3d388SSridevi Ramesh    attr_val_table_data     pldmtool output from GetBIOSTable table type AttributeValueTable.
2002ab3d388SSridevi Ramesh
2012ab3d388SSridevi Ramesh    @return                 Dict of BIOS attribute and its value.
2022ab3d388SSridevi Ramesh
2032ab3d388SSridevi Ramesh    """
2042ab3d388SSridevi Ramesh    attr_val_data_dict = {}
2052ab3d388SSridevi Ramesh    for item in attr_val_table_data:
20620f38712SPatrick Williams        attr_handle = re.findall(r"\(.*?\)", item["AttributeNameHandle"])
2072ab3d388SSridevi Ramesh        attr_name = attr_handle[0][1:-1]
2082ab3d388SSridevi Ramesh
209*a4ab9f33SSridevi Ramesh        # Exclude BIOS attribute which are ReadOnly.
210*a4ab9f33SSridevi Ramesh        if "ReadOnly" not in item["AttributeType"]:
211*a4ab9f33SSridevi Ramesh            command = (
212*a4ab9f33SSridevi Ramesh                "bios GetBIOSAttributeCurrentValueByHandle -a " + attr_name
213*a4ab9f33SSridevi Ramesh            )
2142ab3d388SSridevi Ramesh            value = pldmtool(command)
215*a4ab9f33SSridevi Ramesh            if "error" in value:
216*a4ab9f33SSridevi Ramesh                print("Ignore BIOS attribute which throws error...")
217*a4ab9f33SSridevi Ramesh                pass
218*a4ab9f33SSridevi Ramesh            elif not value["CurrentValue"]:
21920f38712SPatrick Williams                if "name" in attr_name:
2202ab3d388SSridevi Ramesh                    attr_val_data_dict[attr_name] = '""'
22120f38712SPatrick Williams                elif "hb_lid_ids" in attr_name:
22248615cd9SSridevi Ramesh                    attr_val_data_dict[attr_name] = '""'
223*a4ab9f33SSridevi Ramesh            else:
224*a4ab9f33SSridevi Ramesh                attr_val_data_dict[attr_name] = value["CurrentValue"]
2252ab3d388SSridevi Ramesh
2262ab3d388SSridevi Ramesh    return attr_val_data_dict
2272ab3d388SSridevi Ramesh
2282ab3d388SSridevi Ramesh
2292ab3d388SSridevi Rameshdef GetBIOSAttrDefaultValues(attr_val_table_data):
2302ab3d388SSridevi Ramesh    """
2312ab3d388SSridevi Ramesh    From pldmtool GetBIOSTable of type AttributeValueTable get the dict of
2322ab3d388SSridevi Ramesh    attribute handle and its default attribute values.
2332ab3d388SSridevi Ramesh
2342ab3d388SSridevi Ramesh    Description of argument(s):
2352ab3d388SSridevi Ramesh    attr_val_table_data     pldmtool output from GetBIOSTable table type AttributeValueTable.
2362ab3d388SSridevi Ramesh
2372ab3d388SSridevi Ramesh    @return                 Dict of BIOS attribute and its default attribute value.
2382ab3d388SSridevi Ramesh
2392ab3d388SSridevi Ramesh    """
2402ab3d388SSridevi Ramesh    attr_val_data_dict = {}
2412ab3d388SSridevi Ramesh    for item in attr_val_table_data:
24220f38712SPatrick Williams        attr_handle = re.findall(r"\(.*?\)", item["AttributeNameHandle"])
2432ab3d388SSridevi Ramesh        attr_name = attr_handle[0][1:-1]
2442ab3d388SSridevi Ramesh
2452ab3d388SSridevi Ramesh        if "DefaultString" in item:
2462ab3d388SSridevi Ramesh            attr_val_data_dict[attr_name] = item["DefaultString"]
2472ab3d388SSridevi Ramesh            if not item["DefaultString"]:
24820f38712SPatrick Williams                if "name" in attr_name:
2492ab3d388SSridevi Ramesh                    attr_val_data_dict[attr_name] = '""'
25020f38712SPatrick Williams                elif "hb_lid_ids" in attr_name:
25148615cd9SSridevi Ramesh                    attr_val_data_dict[attr_name] = '""'
2522ab3d388SSridevi Ramesh        elif "DefaultValue" in item:
2532ab3d388SSridevi Ramesh            attr_val_data_dict[attr_name] = item["DefaultValue"]
2542ab3d388SSridevi Ramesh        elif "StringHandle" in item:
25520f38712SPatrick Williams            attr_default_value = re.findall(r"\(.*?\)", item["StringHandle"])
2562ab3d388SSridevi Ramesh            attr_val_data_dict[attr_name] = attr_default_value[0][1:-1]
2572ab3d388SSridevi Ramesh
2582ab3d388SSridevi Ramesh    return attr_val_data_dict
259ba3cb8c0SAnusha Dathatri
260ba3cb8c0SAnusha Dathatri
261ba3cb8c0SAnusha Dathatridef GetNewValuesForAllBIOSAttrs(attr_table_data):
262ba3cb8c0SAnusha Dathatri    """
263ba3cb8c0SAnusha Dathatri    Get a new set of values for all attributes in Attribute Table.
264ba3cb8c0SAnusha Dathatri
265ba3cb8c0SAnusha Dathatri    Description of argument(s):
266ba3cb8c0SAnusha Dathatri    attr_table_data         pldmtool output from GetBIOSTable table type AttributeValueTable.
267ba3cb8c0SAnusha Dathatri
268ba3cb8c0SAnusha Dathatri    @return                 Dict of BIOS attribute and new attribute value.
269ba3cb8c0SAnusha Dathatri
270ba3cb8c0SAnusha Dathatri    """
271ba3cb8c0SAnusha Dathatri    existing_data = GetBIOSAttrOriginalValues(attr_table_data)
272ba3cb8c0SAnusha Dathatri    logger.info(existing_data)
27320f38712SPatrick Williams    string_attr_data = GetBIOSStrAndIntAttributeHandles(
27420f38712SPatrick Williams        "BIOSString", attr_table_data
27520f38712SPatrick Williams    )
276ba3cb8c0SAnusha Dathatri    logger.info(string_attr_data)
27720f38712SPatrick Williams    int_attr_data = GetBIOSStrAndIntAttributeHandles(
27820f38712SPatrick Williams        "BIOSInteger", attr_table_data
27920f38712SPatrick Williams    )
280ba3cb8c0SAnusha Dathatri    logger.info(int_attr_data)
281ba3cb8c0SAnusha Dathatri    enum_attr_data = GetBIOSEnumAttributeOptionalValues(attr_table_data)
282ba3cb8c0SAnusha Dathatri    logger.info(enum_attr_data)
283ba3cb8c0SAnusha Dathatri
284ba3cb8c0SAnusha Dathatri    attr_random_data = {}
285ba3cb8c0SAnusha Dathatri    temp_list = enum_attr_data.copy()
286ba3cb8c0SAnusha Dathatri    for attr in enum_attr_data:
287ba3cb8c0SAnusha Dathatri        try:
288ba3cb8c0SAnusha Dathatri            temp_list[attr].remove(existing_data[attr])
289ba3cb8c0SAnusha Dathatri        except ValueError:
290ba3cb8c0SAnusha Dathatri            try:
291ba3cb8c0SAnusha Dathatri                # The data values have a double quote in them.
292ba3cb8c0SAnusha Dathatri                data = '"' + str(existing_data[attr]) + '"'
293ba3cb8c0SAnusha Dathatri                temp_list[attr].remove(data)
294ba3cb8c0SAnusha Dathatri            except ValueError:
29520f38712SPatrick Williams                logger.info(
29620f38712SPatrick Williams                    "Unable to remove the existing value "
29720f38712SPatrick Williams                    + str(data)
29820f38712SPatrick Williams                    + " from list "
29920f38712SPatrick Williams                    + str(temp_list[attr])
30020f38712SPatrick Williams                )
301ba3cb8c0SAnusha Dathatri        valid_values = temp_list[attr][:]
302ba3cb8c0SAnusha Dathatri        value = random.choice(valid_values)
303ba3cb8c0SAnusha Dathatri        attr_random_data[attr] = value.strip('"')
304ba3cb8c0SAnusha Dathatri    logger.info("Values generated for enumeration type attributes")
305ba3cb8c0SAnusha Dathatri
306ba3cb8c0SAnusha Dathatri    for attr in string_attr_data:
307ba3cb8c0SAnusha Dathatri        # Iterating to make sure we have a different value
308ba3cb8c0SAnusha Dathatri        # other than the existing value.
309ba3cb8c0SAnusha Dathatri        for iter in range(5):
31020f38712SPatrick Williams            random_val = GetRandomBIOSIntAndStrValues(
31120f38712SPatrick Williams                attr, string_attr_data[attr]["MaximumStringLength"]
31220f38712SPatrick Williams            )
313ba3cb8c0SAnusha Dathatri            if random_val != existing_data[attr]:
314ba3cb8c0SAnusha Dathatri                break
315*a4ab9f33SSridevi Ramesh        if isinstance(random_val, str):
316ba3cb8c0SAnusha Dathatri            attr_random_data[attr] = random_val.strip('"')
317ba3cb8c0SAnusha Dathatri    logger.info("Values generated for string type attributes")
318ba3cb8c0SAnusha Dathatri
319ba3cb8c0SAnusha Dathatri    for attr in int_attr_data:
320ba3cb8c0SAnusha Dathatri        for iter in range(5):
32120f38712SPatrick Williams            random_val = GetRandomBIOSIntAndStrValues(
32220f38712SPatrick Williams                attr, int_attr_data[attr]["UpperBound"]
32320f38712SPatrick Williams            )
324ba3cb8c0SAnusha Dathatri            if random_val != existing_data[attr]:
325ba3cb8c0SAnusha Dathatri                break
326ba3cb8c0SAnusha Dathatri        attr_random_data[attr] = random_val
327ba3cb8c0SAnusha Dathatri    logger.info("Values generated for integer type attributes")
328ba3cb8c0SAnusha Dathatri
329ba3cb8c0SAnusha Dathatri    return attr_random_data
330