xref: /openbmc/openbmc-test-automation/lib/pldm_utils.py (revision 41e5ad25eb9d16be3f823222f94204b71fac8274)
1 #!/usr/bin/env python3
2 
3 r"""
4 PLDM functions.
5 """
6 
7 import json
8 import random
9 import re
10 import string
11 
12 import bmc_ssh_utils as bsu
13 import func_args as fa
14 import var_funcs as vf
15 from robot.api import logger
16 
17 
18 def pldmtool(option_string, **bsu_options):
19     r"""
20     Run pldmtool on the BMC with the caller's option string and return the result.
21 
22     Example:
23 
24     ${pldm_results}=  Pldmtool  base GetPLDMTypes
25     Rprint Vars  pldm_results
26 
27     pldm_results:
28       pldmtool base GetPLDMVersion -t 0
29       {
30           "Response": "1.0.0"
31       }
32 
33     Description of argument(s):
34     option_string         A string of options which are to be processed by the
35                           pldmtool command.
36     parse_results         Parse the pldmtool results and return a dictionary
37                           rather than the raw
38                           pldmtool output.
39     bsu_options           Options to be passed directly to bmc_execute_command.
40                           See its prolog for details.
41     """
42 
43     # This allows callers to specify arguments in python style
44     # (e.g. print_out=1 vs. print_out=${1}).
45     bsu_options = fa.args_to_objects(bsu_options)
46 
47     stdout, stderr, rc = bsu.bmc_execute_command(
48         "pldmtool " + option_string, **bsu_options, ignore_err=1
49     )
50     if stderr:
51         return stderr
52     try:
53         return json.loads(stdout)
54     except ValueError:
55         return stdout
56 
57 
58 def GetBIOSEnumAttributeOptionalValues(attr_val_table_data):
59     """
60     From pldmtool GetBIOSTable of type AttributeValueTable get the dict of
61     attribute handle and its optional values for BIOS Enumeration type.
62 
63     Description of argument(s):
64     attr_val_table_data     pldmtool output from GetBIOSTable table type AttributeValueTable
65                             e.g.
66                             [{
67                                   "AttributeHandle": 20,
68                                   "AttributeNameHandle": "23(pvm-pcie-error-inject)",
69                                   "AttributeType": "BIOSEnumeration",
70                                   "NumberOfPossibleValues": 2,
71                                   "PossibleValueStringHandle[0]": "3(Disabled)",
72                                   "PossibleValueStringHandle[1]": "4(Enabled)",
73                                   "NumberOfDefaultValues": 1,
74                                   "DefaultValueStringHandleIndex[0]": 1,
75                                   "StringHandle": "4(Enabled)"
76                              }]
77     @return                  Dictionary of BIOS attribute and its value.
78                              e.g. {'pvm_pcie_error_inject': ['Disabled', 'Enabled']}
79     """
80 
81     attr_val_data_dict = {}
82     for item in attr_val_table_data:
83         for attr in item:
84             if attr == "NumberOfPossibleValues":
85                 value_list = []
86                 for i in range(0, int(item[attr])):
87                     attr_values = item[
88                         "PossibleValueStringHandle[" + str(i) + "]"
89                     ]
90                     value = re.search(r"\((.*?)\)", attr_values).group(1)
91                     if value:
92                         # Example:
93                         # value = '"Power Off"'
94                         if " " in value:
95                             value = '"' + value + '"'
96                         value_list.append(value)
97                     else:
98                         value_list.append("")
99 
100                 attr_handle = re.findall(
101                     r"\(.*?\)", item["AttributeNameHandle"]
102                 )
103                 attr_val_data_dict[attr_handle[0][1:-1]] = value_list
104     return attr_val_data_dict
105 
106 
107 def GetBIOSStrAndIntAttributeHandles(attr_type, attr_val_table_data):
108     """
109     From pldmtool GetBIOSTable of type AttributeValueTable get the dict of
110     attribute handle and its values based on the attribute type.
111 
112     Description of argument(s):
113     attr_type               "BIOSInteger" or "BIOSString".
114     attr_val_table_data     pldmtool output from GetBIOSTable table type AttributeValueTable.
115 
116     @return                 Dict of BIOS attribute and its value based on attribute type.
117 
118     """
119     attr_val_int_dict = {}
120     attr_val_str_dict = {}
121     for item in attr_val_table_data:
122         value_dict = {}
123         attr_handle = re.findall(r"\(.*?\)", item["AttributeNameHandle"])
124         # Example:
125         # {'vmi_if0_ipv4_prefix_length': {'UpperBound': 32, 'LowerBound': 0}
126         if item["AttributeType"] == "BIOSInteger":
127             value_dict["LowerBound"] = item["LowerBound"]
128             value_dict["UpperBound"] = item["UpperBound"]
129             attr_val_int_dict[attr_handle[0][1:-1]] = value_dict
130         # Example:
131         # {'vmi_if1_ipv4_ipaddr': {'MaximumStringLength': 15, 'MinimumStringLength': 7}}
132         elif item["AttributeType"] == "BIOSString":
133             value_dict["MinimumStringLength"] = item["MinimumStringLength"]
134             value_dict["MaximumStringLength"] = item["MaximumStringLength"]
135             attr_val_str_dict[attr_handle[0][1:-1]] = value_dict
136 
137     if attr_type == "BIOSInteger":
138         return attr_val_int_dict
139     if attr_type == "BIOSString":
140         return attr_val_str_dict
141 
142     return None
143 
144 
145 def GetRandomBIOSIntAndStrValues(attr_name, count):
146     """
147     Get random integer or string values for BIOS attribute values based on the count.
148 
149     Description of argument(s):
150     attr_name               Attribute name of BIOS attribute type Integer or string.
151     count                   Max length for BIOS attribute type Integer or string.
152 
153     @return                 Random attribute value based on BIOS attribute type Integer
154                             or string.
155 
156     """
157     attr_random_value = ""
158 
159     # Example
160     # 12.13.14.15
161     if "gateway" in attr_name:
162         attr_random_value = ".".join(
163             map(str, (random.randint(0, 255) for _ in range(4)))
164         )
165     # Example
166     # 11.11.11.11
167     elif "ipaddr" in attr_name:
168         attr_random_value = ".".join(
169             map(str, (random.randint(0, 255) for _ in range(4)))
170         )
171     # Example
172     # E5YWEDWJJ
173     elif "name" in attr_name:
174         data = string.ascii_uppercase + string.digits
175         attr_random_value = "".join(
176             random.choice(data) for _ in range(int(count))
177         )
178 
179     elif "mfg_flags" in attr_name:
180         data = string.ascii_uppercase + string.digits
181         attr_random_value = "".join(
182             random.choice(data) for _ in range(int(count))
183         )
184 
185     elif "hb_lid_ids" in attr_name:
186         attr_random_value = str(random.randint(0, int(count)))
187 
188     else:
189         attr_random_value = random.randint(0, int(count))
190     return attr_random_value
191 
192 
193 def GetBIOSAttrOriginalValues(attr_val_table_data):
194     """
195     From pldmtool GetBIOSTable of type AttributeValueTable get the dict of
196     attribute handle and its values.
197 
198     Description of argument(s):
199     attr_val_table_data     pldmtool output from GetBIOSTable table type AttributeValueTable.
200 
201     @return                 Dict of BIOS attribute and its value.
202 
203     """
204     attr_val_data_dict = {}
205     for item in attr_val_table_data:
206         attr_handle = re.findall(r"\(.*?\)", item["AttributeNameHandle"])
207         attr_name = attr_handle[0][1:-1]
208 
209         # Exclude BIOS attribute which are ReadOnly.
210         if "ReadOnly" not in item["AttributeType"]:
211             command = (
212                 "bios GetBIOSAttributeCurrentValueByHandle -a " + attr_name
213             )
214             value = pldmtool(command)
215             if "error" in value:
216                 print("Ignore BIOS attribute which throws error...")
217                 pass
218             elif not value["CurrentValue"]:
219                 if "name" in attr_name:
220                     attr_val_data_dict[attr_name] = '""'
221                 elif "hb_lid_ids" in attr_name:
222                     attr_val_data_dict[attr_name] = '""'
223             else:
224                 attr_val_data_dict[attr_name] = value["CurrentValue"]
225 
226     return attr_val_data_dict
227 
228 
229 def GetBIOSAttrDefaultValues(attr_val_table_data):
230     """
231     From pldmtool GetBIOSTable of type AttributeValueTable get the dict of
232     attribute handle and its default attribute values.
233 
234     Description of argument(s):
235     attr_val_table_data     pldmtool output from GetBIOSTable table type AttributeValueTable.
236 
237     @return                 Dict of BIOS attribute and its default attribute value.
238 
239     """
240     attr_val_data_dict = {}
241     for item in attr_val_table_data:
242         attr_handle = re.findall(r"\(.*?\)", item["AttributeNameHandle"])
243         attr_name = attr_handle[0][1:-1]
244 
245         if "DefaultString" in item:
246             attr_val_data_dict[attr_name] = item["DefaultString"]
247             if not item["DefaultString"]:
248                 if "name" in attr_name:
249                     attr_val_data_dict[attr_name] = '""'
250                 elif "hb_lid_ids" in attr_name:
251                     attr_val_data_dict[attr_name] = '""'
252         elif "DefaultValue" in item:
253             attr_val_data_dict[attr_name] = item["DefaultValue"]
254         elif "StringHandle" in item:
255             attr_default_value = re.findall(r"\(.*?\)", item["StringHandle"])
256             attr_val_data_dict[attr_name] = attr_default_value[0][1:-1]
257 
258     return attr_val_data_dict
259 
260 
261 def GetNewValuesForAllBIOSAttrs(attr_table_data):
262     """
263     Get a new set of values for all attributes in Attribute Table.
264 
265     Description of argument(s):
266     attr_table_data         pldmtool output from GetBIOSTable table type AttributeValueTable.
267 
268     @return                 Dict of BIOS attribute and new attribute value.
269 
270     """
271     existing_data = GetBIOSAttrOriginalValues(attr_table_data)
272     logger.info(existing_data)
273     string_attr_data = GetBIOSStrAndIntAttributeHandles(
274         "BIOSString", attr_table_data
275     )
276     logger.info(string_attr_data)
277     int_attr_data = GetBIOSStrAndIntAttributeHandles(
278         "BIOSInteger", attr_table_data
279     )
280     logger.info(int_attr_data)
281     enum_attr_data = GetBIOSEnumAttributeOptionalValues(attr_table_data)
282     logger.info(enum_attr_data)
283 
284     attr_random_data = {}
285     temp_list = enum_attr_data.copy()
286     for attr in enum_attr_data:
287         try:
288             temp_list[attr].remove(existing_data[attr])
289         except ValueError:
290             try:
291                 # The data values have a double quote in them.
292                 data = '"' + str(existing_data[attr]) + '"'
293                 temp_list[attr].remove(data)
294             except ValueError:
295                 logger.info(
296                     "Unable to remove the existing value "
297                     + str(data)
298                     + " from list "
299                     + str(temp_list[attr])
300                 )
301         valid_values = temp_list[attr][:]
302         value = random.choice(valid_values)
303         attr_random_data[attr] = value.strip('"')
304     logger.info("Values generated for enumeration type attributes")
305 
306     for attr in string_attr_data:
307         # Iterating to make sure we have a different value
308         # other than the existing value.
309         for iter in range(5):
310             random_val = GetRandomBIOSIntAndStrValues(
311                 attr, string_attr_data[attr]["MaximumStringLength"]
312             )
313             if random_val != existing_data[attr]:
314                 break
315         if isinstance(random_val, str):
316             attr_random_data[attr] = random_val.strip('"')
317     logger.info("Values generated for string type attributes")
318 
319     for attr in int_attr_data:
320         for iter in range(5):
321             random_val = GetRandomBIOSIntAndStrValues(
322                 attr, int_attr_data[attr]["UpperBound"]
323             )
324             if random_val != existing_data[attr]:
325                 break
326         attr_random_data[attr] = random_val
327     logger.info("Values generated for integer type attributes")
328 
329     return attr_random_data
330