blob: b969a829958a4a088d06f5c2ba21f0686d0197bf [file] [log] [blame]
Matt Spinlerd9c2fea2020-03-05 16:53:41 -06001#!/usr/bin/env python3
Andrew Geisslerc830e0f2016-10-18 12:51:29 -05002
3r"""
Deepak Kodihalli160d3e02017-01-17 04:25:22 -06004This script will parse error log yaml file(s) and generate
Andrew Geisslerc830e0f2016-10-18 12:51:29 -05005a header file which will then be used by the error logging client and
6server to collect and validate the error information generated by the
7openbmc software components.
8
9This code uses a mako template to provide the basic template of the header
10file we're going to generate. We then call it with information from the
11yaml to generate the header file.
Andrew Geisslerc830e0f2016-10-18 12:51:29 -050012"""
13
14from mako.template import Template
15from optparse import OptionParser
16import yaml
17import sys
18import os
19
Andrew Geissler184690d2016-11-03 08:06:31 -050020
Deepak Kodihalli5d1aace2017-01-18 00:17:39 -060021def order_inherited_errors(i_errors, i_parents):
22 # the ordered list of errors
23 errors = list()
24 has_inheritance = False
25 for error in i_errors:
Patrick Williamse6555f52022-08-04 13:56:17 -050026 if i_parents[error] is not None:
Deepak Kodihalli5d1aace2017-01-18 00:17:39 -060027 has_inheritance = True
28 break
29
Patrick Williamse6555f52022-08-04 13:56:17 -050030 if has_inheritance:
Deepak Kodihalli5d1aace2017-01-18 00:17:39 -060031 # Order the error codes list such that an error is never placed
32 # before it's parent. This way generated code can ensure parent
Gunnar Millsdeae3ca2017-10-25 17:22:22 -050033 # definitions precede child error definitions.
Patrick Williamse6555f52022-08-04 13:56:17 -050034 while len(errors) < len(i_errors):
Deepak Kodihalli5d1aace2017-01-18 00:17:39 -060035 for error in i_errors:
Patrick Williamse6555f52022-08-04 13:56:17 -050036 if error in errors:
Deepak Kodihalli5d1aace2017-01-18 00:17:39 -060037 # already ordererd
38 continue
Patrick Williamse6555f52022-08-04 13:56:17 -050039 if (not i_parents[error]) or (i_parents[error] in errors):
Deepak Kodihalli5d1aace2017-01-18 00:17:39 -060040 # parent present, or has no parent, either way this error
41 # can be added
42 errors.append(error)
43 else:
44 # no inherited errors
45 errors = i_errors
46
47 return errors
48
49
Deepak Kodihallicbd12c82017-01-17 08:50:55 -060050def check_error_inheritance(i_errors, i_parents):
Deepak Kodihalli5d1aace2017-01-18 00:17:39 -060051 for error in i_errors:
Patrick Williamse6555f52022-08-04 13:56:17 -050052 if i_parents[error] and (i_parents[error] not in i_errors):
53 print(
54 error
55 + " inherits "
56 + i_parents[error]
57 + " but the latter is not defined"
58 )
Deepak Kodihallicbd12c82017-01-17 08:50:55 -060059 return False
60 return True
61
62
Adriana Kobylak465aaec2017-02-20 11:58:03 -060063# Return the yaml files with their directory structure plus the file name
64# without the yaml extension, which will be used to set the namespaces.
65# Ex: file xyz/openbmc_project/Error/Callout/Device.errors.yaml
66# will have namespce xyz/openbmc_project/Error/Callout/Device
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -060067def get_error_yaml_files(i_yaml_dir, i_test_dir):
Adriana Kobylak371a38b2017-02-19 13:45:42 -060068 yaml_files = dict()
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -060069 if i_yaml_dir != "None":
70 for root, dirs, files in os.walk(i_yaml_dir):
Patrick Williamse6555f52022-08-04 13:56:17 -050071 for files in [
72 file for file in files if file.endswith(".errors.yaml")
73 ]:
Adriana Kobylak465aaec2017-02-20 11:58:03 -060074 splitdir = root.split(i_yaml_dir)[1] + "/" + files[:-12]
75 if splitdir.startswith("/"):
76 splitdir = splitdir[1:]
Adriana Kobylak371a38b2017-02-19 13:45:42 -060077 yaml_files[(os.path.join(root, files))] = splitdir
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -060078 for root, dirs, files in os.walk(i_test_dir):
Patrick Williamse6555f52022-08-04 13:56:17 -050079 for files in [file for file in files if file.endswith(".errors.yaml")]:
Adriana Kobylak465aaec2017-02-20 11:58:03 -060080 splitdir = root.split(i_test_dir)[1] + "/" + files[:-12]
Adriana Kobylak371a38b2017-02-19 13:45:42 -060081 yaml_files[(os.path.join(root, files))] = splitdir
Deepak Kodihalli160d3e02017-01-17 04:25:22 -060082 return yaml_files
83
84
85def get_meta_yaml_file(i_error_yaml_file):
86 # the meta data will be defined in file name where we replace
87 # <Interface>.errors.yaml with <Interface>.metadata.yaml
88 meta_yaml = i_error_yaml_file.replace("errors", "metadata")
89 return meta_yaml
90
91
Deepak Kodihalli99161192017-01-16 04:00:07 -060092def get_cpp_type(i_type):
93 typeMap = {
Patrick Williamse6555f52022-08-04 13:56:17 -050094 "boolean": "bool",
95 "int8": "int8_t",
96 "int16": "int16_t",
97 "int32": "int32_t",
98 "int64": "int64_t",
99 "uint8": "uint8_t",
100 "uint16": "uint16_t",
101 "uint32": "uint32_t",
102 "uint64": "uint64_t",
103 "double": "double",
Deepak Kodihalli99161192017-01-16 04:00:07 -0600104 # const char* aids usage of constexpr
Patrick Williamse6555f52022-08-04 13:56:17 -0500105 "string": "const char*",
106 }
Deepak Kodihalli99161192017-01-16 04:00:07 -0600107
108 return typeMap[i_type]
109
110
Patrick Williamse6555f52022-08-04 13:56:17 -0500111def gen_elog_hpp(
112 i_yaml_dir, i_test_dir, i_output_hpp, i_template_dir, i_elog_mako
113):
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500114 r"""
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600115 Read yaml file(s) under input yaml dir, grab the relevant data and call
116 the mako template to generate the output header file.
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500117
118 Description of arguments:
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -0600119 i_yaml_dir directory containing base error yaml files
120 i_test_dir directory containing test error yaml files
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600121 i_output_hpp name of the to be generated output hpp
122 i_template_dir directory containing error mako templates
123 i_elog_mako error mako template to render
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500124 """
125
126 # Input parameters to mako template
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600127 errors = list() # Main error codes
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500128 error_msg = dict() # Error msg that corresponds to error code
129 error_lvl = dict() # Error code log level (debug, info, error, ...)
Deepak Kodihalli5d1aace2017-01-18 00:17:39 -0600130 meta = dict() # The meta data names associated (ERRNO, FILE_NAME, ...)
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500131 meta_data = dict() # The meta data info (type, format)
Deepak Kodihalli5d1aace2017-01-18 00:17:39 -0600132 parents = dict()
Deepak Kodihalli38f69742017-02-28 02:18:09 -0600133 metadata_process = dict() # metadata that have the 'process' keyword set
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500134
Patrick Williams7dc8c3b2021-04-17 07:22:48 -0500135 # Verify the input mako file
136 template_path = os.path.join(i_template_dir, i_elog_mako)
Patrick Williamse6555f52022-08-04 13:56:17 -0500137 if not (os.path.isfile(template_path)):
Patrick Williams7dc8c3b2021-04-17 07:22:48 -0500138 print("Cannot find input template file " + template_path)
139 exit(1)
140 template_path = os.path.abspath(template_path)
141
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -0600142 error_yamls = get_error_yaml_files(i_yaml_dir, i_test_dir)
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600143
144 for error_yaml in error_yamls:
145 # Verify the error yaml file
Patrick Williamse6555f52022-08-04 13:56:17 -0500146 if not (os.path.isfile(error_yaml)):
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500147 print("Cannot find input yaml file " + error_yaml)
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600148 exit(1)
149
150 # Verify the metadata yaml file
151 meta_yaml = get_meta_yaml_file(error_yaml)
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600152
Patrick Williamse6555f52022-08-04 13:56:17 -0500153 get_elog_data(
154 error_yaml,
155 meta_yaml,
156 error_yamls[error_yaml],
157 # Last arg is a tuple
158 (
159 errors,
160 error_msg,
161 error_lvl,
162 meta,
163 meta_data,
164 parents,
165 metadata_process,
166 ),
167 )
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600168
Patrick Williamse6555f52022-08-04 13:56:17 -0500169 if not check_error_inheritance(errors, parents):
Patrick Williams6f299132017-02-16 13:27:39 -0600170 print("Error - failed to validate error inheritance")
Deepak Kodihallicbd12c82017-01-17 08:50:55 -0600171 exit(1)
172
Deepak Kodihalli5d1aace2017-01-18 00:17:39 -0600173 errors = order_inherited_errors(errors, parents)
174
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600175 # Load the mako template and call it with the required data
176 yaml_dir = i_yaml_dir.strip("./")
177 yaml_dir = yaml_dir.strip("../")
178 template = Template(filename=template_path)
Patrick Williamse6555f52022-08-04 13:56:17 -0500179 f = open(i_output_hpp, "w")
180 f.write(
181 template.render(
Deepak Kodihalli38f69742017-02-28 02:18:09 -0600182 errors=errors,
183 error_msg=error_msg,
184 error_lvl=error_lvl,
185 meta=meta,
Adriana Kobylak465aaec2017-02-20 11:58:03 -0600186 meta_data=meta_data,
Deepak Kodihalli38f69742017-02-28 02:18:09 -0600187 parents=parents,
Patrick Williamse6555f52022-08-04 13:56:17 -0500188 metadata_process=metadata_process,
189 )
190 )
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600191 f.close()
192
Patrick Williamsbb6af862021-04-16 13:58:01 -0500193
Patrick Williamse6555f52022-08-04 13:56:17 -0500194def get_elog_data(i_elog_yaml, i_elog_meta_yaml, i_namespace, o_elog_data):
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600195 r"""
196 Parse the error and metadata yaml files in order to pull out
197 error metadata.
198
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500199 Use default values if metadata yaml file is not found.
200
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600201 Description of arguments:
202 i_elog_yaml error yaml file
203 i_elog_meta_yaml metadata yaml file
Adriana Kobylak371a38b2017-02-19 13:45:42 -0600204 i_namespace namespace data
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600205 o_elog_data error metadata
206 """
Patrick Williamse6555f52022-08-04 13:56:17 -0500207 (
208 errors,
209 error_msg,
210 error_lvl,
211 meta,
212 meta_data,
213 parents,
214 metadata_process,
215 ) = o_elog_data
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600216 ifile = yaml.safe_load(open(i_elog_yaml))
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500217
Patrick Williamsbb6af862021-04-16 13:58:01 -0500218 # for all the errors in error yaml file
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500219 for error in ifile:
Patrick Williamse6555f52022-08-04 13:56:17 -0500220 if "name" not in error:
221 print(
222 "Error - Did not find name in entry %s in file %s "
223 % (str(error), i_elog_yaml)
224 )
Andrew Geisslere8596302016-11-21 16:06:53 -0600225 exit(1)
Patrick Williamse6555f52022-08-04 13:56:17 -0500226 fullname = i_namespace.replace("/", ".") + (".") + error["name"]
Adriana Kobylak465aaec2017-02-20 11:58:03 -0600227 errors.append(fullname)
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500228
Patrick Williamse6555f52022-08-04 13:56:17 -0500229 if "description" in error:
230 error_msg[fullname] = error["description"].strip()
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500231
Patrick Williamsbb6af862021-04-16 13:58:01 -0500232 # set default values
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500233 error_lvl[fullname] = "ERR"
234 parents[fullname] = None
235
Patrick Williamsbb6af862021-04-16 13:58:01 -0500236 # check if meta data yaml file is found
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500237 if not os.path.isfile(i_elog_meta_yaml):
238 continue
239 mfile = yaml.safe_load(open(i_elog_meta_yaml))
240
241 # Find the meta data entry
242 match = None
243 for meta_entry in mfile:
Patrick Williamse6555f52022-08-04 13:56:17 -0500244 if meta_entry["name"] == error["name"]:
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500245 match = meta_entry
246 break
247
248 if match is None:
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500249 continue
250
Patrick Williamse6555f52022-08-04 13:56:17 -0500251 error_lvl[fullname] = match.get("level", "ERR")
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500252
253 # Get 0th inherited error (current support - single inheritance)
Patrick Williamse6555f52022-08-04 13:56:17 -0500254 if "inherits" in match:
255 parents[fullname] = match["inherits"][0]
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500256
Lei YU80aa4762018-07-19 10:29:56 +0800257 # Put all errors in meta[] even the meta is empty
258 # so that child errors could inherits such error without meta
259 tmp_meta = []
Patrick Williamse6555f52022-08-04 13:56:17 -0500260 if "meta" in match:
Marri Devender Raodf7cb5c2017-05-14 08:30:40 -0500261 # grab all the meta data fields and info
Patrick Williamse6555f52022-08-04 13:56:17 -0500262 for i in match["meta"]:
263 str_short = i["str"].split("=")[0]
Deepak Kodihalli7924b172017-03-08 00:04:33 -0600264 tmp_meta.append(str_short)
265 meta_data[str_short] = {}
Patrick Williamse6555f52022-08-04 13:56:17 -0500266 meta_data[str_short]["str"] = i["str"]
267 meta_data[str_short]["str_short"] = str_short
268 meta_data[str_short]["type"] = get_cpp_type(i["type"])
269 if ("process" in i) and (i["process"] is True):
Deepak Kodihalli38f69742017-02-28 02:18:09 -0600270 metadata_process[str_short] = fullname + "." + str_short
Lei YU80aa4762018-07-19 10:29:56 +0800271 meta[fullname] = tmp_meta
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500272
273 # Debug
Andrew Geissler184690d2016-11-03 08:06:31 -0500274 # for i in errors:
Andrew Geisslerdf048c12016-11-10 16:50:35 -0600275 # print "ERROR: " + errors[i]
276 # print " MSG: " + error_msg[errors[i]]
277 # print " LVL: " + error_lvl[errors[i]]
278 # print " META: "
279 # print meta[i]
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500280
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500281
282def main(i_args):
283 parser = OptionParser()
284
Patrick Williamse6555f52022-08-04 13:56:17 -0500285 parser.add_option(
286 "-m",
287 "--mako",
288 dest="elog_mako",
289 default="elog-gen-template.mako.hpp",
290 help="input mako template file to use",
291 )
Andrew Geissler184690d2016-11-03 08:06:31 -0500292
Patrick Williamse6555f52022-08-04 13:56:17 -0500293 parser.add_option(
294 "-o",
295 "--output",
296 dest="output_hpp",
297 default="elog-errors.hpp",
298 help="output hpp to generate, elog-errors.hpp default",
299 )
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500300
Patrick Williamse6555f52022-08-04 13:56:17 -0500301 parser.add_option(
302 "-y",
303 "--yamldir",
304 dest="yamldir",
305 default="None",
306 help="Base directory of yaml files to process",
307 )
Andrew Geisslerf1f2cfa2016-11-21 15:16:45 -0600308
Patrick Williamse6555f52022-08-04 13:56:17 -0500309 parser.add_option(
310 "-u",
311 "--testdir",
312 dest="testdir",
313 default="./tools/example/",
314 help="Unit test directory of yaml files to process",
315 )
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -0600316
Patrick Williamse6555f52022-08-04 13:56:17 -0500317 parser.add_option(
318 "-t",
319 "--templatedir",
320 dest="templatedir",
321 default="phosphor-logging/templates/",
322 help="Base directory of files to process",
323 )
Andrew Geisslerf1f2cfa2016-11-21 15:16:45 -0600324
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500325 (options, args) = parser.parse_args(i_args)
326
Patrick Williamse6555f52022-08-04 13:56:17 -0500327 gen_elog_hpp(
328 options.yamldir,
329 options.testdir,
330 options.output_hpp,
331 options.templatedir,
332 options.elog_mako,
333 )
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500334
Patrick Williamsbb6af862021-04-16 13:58:01 -0500335
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500336# Only run if it's a script
Patrick Williamse6555f52022-08-04 13:56:17 -0500337if __name__ == "__main__":
Andrew Geissler184690d2016-11-03 08:06:31 -0500338 main(sys.argv[1:])