blob: 469248fe232a55dc101dc7f0a28957937bad3daa [file] [log] [blame]
Andrew Geisslerc830e0f2016-10-18 12:51:29 -05001#!/usr/bin/env python
2
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:
26 if(i_parents[error] is not None):
27 has_inheritance = True
28 break
29
30 if(has_inheritance):
31 # Order the error codes list such that an error is never placed
32 # before it's parent. This way generated code can ensure parent
33 # definitions preceed child error definitions.
34 while(len(errors) < len(i_errors)):
35 for error in i_errors:
36 if(error in errors):
37 # already ordererd
38 continue
39 if((not i_parents[error]) or (i_parents[error] in errors)):
40 # 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:
52 if(i_parents[error] and (i_parents[error] not in i_errors)):
Patrick Williams6f299132017-02-16 13:27:39 -060053 print(error + " inherits " + i_parents[error] +
54 " but the latter is not defined")
Deepak Kodihallicbd12c82017-01-17 08:50:55 -060055 return False
56 return True
57
58
Adriana Kobylak465aaec2017-02-20 11:58:03 -060059# Return the yaml files with their directory structure plus the file name
60# without the yaml extension, which will be used to set the namespaces.
61# Ex: file xyz/openbmc_project/Error/Callout/Device.errors.yaml
62# will have namespce xyz/openbmc_project/Error/Callout/Device
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -060063def get_error_yaml_files(i_yaml_dir, i_test_dir):
Adriana Kobylak371a38b2017-02-19 13:45:42 -060064 yaml_files = dict()
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -060065 if i_yaml_dir != "None":
66 for root, dirs, files in os.walk(i_yaml_dir):
67 for files in filter(lambda file:
68 file.endswith('.errors.yaml'), files):
Adriana Kobylak465aaec2017-02-20 11:58:03 -060069 splitdir = root.split(i_yaml_dir)[1] + "/" + files[:-12]
70 if splitdir.startswith("/"):
71 splitdir = splitdir[1:]
Adriana Kobylak371a38b2017-02-19 13:45:42 -060072 yaml_files[(os.path.join(root, files))] = splitdir
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -060073 for root, dirs, files in os.walk(i_test_dir):
Adriana Kobylakf4690732017-02-19 09:53:34 -060074 for files in filter(lambda file: file.endswith('.errors.yaml'), files):
Adriana Kobylak465aaec2017-02-20 11:58:03 -060075 splitdir = root.split(i_test_dir)[1] + "/" + files[:-12]
Adriana Kobylak371a38b2017-02-19 13:45:42 -060076 yaml_files[(os.path.join(root, files))] = splitdir
Deepak Kodihalli160d3e02017-01-17 04:25:22 -060077 return yaml_files
78
79
80def get_meta_yaml_file(i_error_yaml_file):
81 # the meta data will be defined in file name where we replace
82 # <Interface>.errors.yaml with <Interface>.metadata.yaml
83 meta_yaml = i_error_yaml_file.replace("errors", "metadata")
84 return meta_yaml
85
86
Deepak Kodihalli99161192017-01-16 04:00:07 -060087def get_cpp_type(i_type):
88 typeMap = {
89 'int16': 'int16_t',
90 'int32': 'int32_t',
91 'int64': 'int64_t',
92 'uint16': 'uint16_t',
93 'uint32': 'uint32_t',
94 'uint64': 'uint64_t',
95 'double': 'double',
96 # const char* aids usage of constexpr
97 'string': 'const char*'}
98
99 return typeMap[i_type]
100
101
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -0600102def gen_elog_hpp(i_yaml_dir, i_test_dir, i_output_hpp,
Adriana Kobylak371a38b2017-02-19 13:45:42 -0600103 i_template_dir, i_elog_mako):
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500104 r"""
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600105 Read yaml file(s) under input yaml dir, grab the relevant data and call
106 the mako template to generate the output header file.
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500107
108 Description of arguments:
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -0600109 i_yaml_dir directory containing base error yaml files
110 i_test_dir directory containing test error yaml files
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600111 i_output_hpp name of the to be generated output hpp
112 i_template_dir directory containing error mako templates
113 i_elog_mako error mako template to render
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500114 """
115
116 # Input parameters to mako template
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600117 errors = list() # Main error codes
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500118 error_msg = dict() # Error msg that corresponds to error code
119 error_lvl = dict() # Error code log level (debug, info, error, ...)
Deepak Kodihalli5d1aace2017-01-18 00:17:39 -0600120 meta = dict() # The meta data names associated (ERRNO, FILE_NAME, ...)
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500121 meta_data = dict() # The meta data info (type, format)
Deepak Kodihalli5d1aace2017-01-18 00:17:39 -0600122 parents = dict()
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500123
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -0600124 error_yamls = get_error_yaml_files(i_yaml_dir, i_test_dir)
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600125
126 for error_yaml in error_yamls:
127 # Verify the error yaml file
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600128 if (not (os.path.isfile(error_yaml))):
Patrick Williams6f299132017-02-16 13:27:39 -0600129 print("Can not find input yaml file " + error_yaml)
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600130 exit(1)
131
132 # Verify the metadata yaml file
133 meta_yaml = get_meta_yaml_file(error_yaml)
134 if (not (os.path.isfile(meta_yaml))):
Patrick Williams6f299132017-02-16 13:27:39 -0600135 print("Can not find meta yaml file " + meta_yaml)
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600136 exit(1)
137
138 # Verify the input mako file
139 template_path = "/".join((i_template_dir, i_elog_mako))
140 if (not (os.path.isfile(template_path))):
Patrick Williams6f299132017-02-16 13:27:39 -0600141 print("Can not find input template file " + template_path)
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600142 exit(1)
143
144 get_elog_data(error_yaml,
145 meta_yaml,
Adriana Kobylak371a38b2017-02-19 13:45:42 -0600146 error_yamls[error_yaml],
147 # Last arg is a tuple
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600148 (errors,
149 error_msg,
150 error_lvl,
151 meta,
Deepak Kodihalli82b7de72017-01-17 07:59:29 -0600152 meta_data,
Adriana Kobylak465aaec2017-02-20 11:58:03 -0600153 parents))
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600154
Deepak Kodihallicbd12c82017-01-17 08:50:55 -0600155 if(not check_error_inheritance(errors, parents)):
Patrick Williams6f299132017-02-16 13:27:39 -0600156 print("Error - failed to validate error inheritance")
Deepak Kodihallicbd12c82017-01-17 08:50:55 -0600157 exit(1)
158
Deepak Kodihalli5d1aace2017-01-18 00:17:39 -0600159 errors = order_inherited_errors(errors, parents)
160
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600161 # Load the mako template and call it with the required data
162 yaml_dir = i_yaml_dir.strip("./")
163 yaml_dir = yaml_dir.strip("../")
164 template = Template(filename=template_path)
165 f = open(i_output_hpp, 'w')
166 f.write(template.render(
167 errors=errors, error_msg=error_msg,
168 error_lvl=error_lvl, meta=meta,
Adriana Kobylak465aaec2017-02-20 11:58:03 -0600169 meta_data=meta_data,
Deepak Kodihallif2462f02017-01-19 03:40:12 -0600170 parents=parents))
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600171 f.close()
172
173
174def get_elog_data(i_elog_yaml,
175 i_elog_meta_yaml,
Adriana Kobylak371a38b2017-02-19 13:45:42 -0600176 i_namespace,
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600177 o_elog_data):
178 r"""
179 Parse the error and metadata yaml files in order to pull out
180 error metadata.
181
182 Description of arguments:
183 i_elog_yaml error yaml file
184 i_elog_meta_yaml metadata yaml file
Adriana Kobylak371a38b2017-02-19 13:45:42 -0600185 i_namespace namespace data
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600186 o_elog_data error metadata
187 """
Adriana Kobylak465aaec2017-02-20 11:58:03 -0600188 errors, error_msg, error_lvl, meta, meta_data, parents = o_elog_data
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600189 ifile = yaml.safe_load(open(i_elog_yaml))
Andrew Geisslere8596302016-11-21 16:06:53 -0600190 mfile = yaml.safe_load(open(i_elog_meta_yaml))
Adriana Kobylak17944e12017-02-13 22:29:21 -0600191 for i in mfile:
Andrew Geisslere8596302016-11-21 16:06:53 -0600192 match = None
193 # Find the corresponding meta data for this entry
Adriana Kobylak17944e12017-02-13 22:29:21 -0600194 for j in ifile:
195 if j['name'] == i['name']:
196 match = j
Andrew Geisslere8596302016-11-21 16:06:53 -0600197 break
198 if (match is None):
Patrick Williams6f299132017-02-16 13:27:39 -0600199 print("Error - Did not find meta data for " + i['name'])
Andrew Geisslere8596302016-11-21 16:06:53 -0600200 exit(1)
Andrew Geisslerdf048c12016-11-10 16:50:35 -0600201 # Grab the main error and it's info
Adriana Kobylak465aaec2017-02-20 11:58:03 -0600202 fullname = i_namespace.replace('/', '.') + ('.') + i['name']
203 errors.append(fullname)
Deepak Kodihalli82b7de72017-01-17 07:59:29 -0600204 parent = None
205 if('inherits' in i):
Deepak Kodihalli82b7de72017-01-17 07:59:29 -0600206 # Get 0th inherited error (current support - single inheritance)
Adriana Kobylak465aaec2017-02-20 11:58:03 -0600207 parent = i['inherits'][0]
208 parents[fullname] = parent
209 error_msg[fullname] = match['description']
Adriana Kobylak8c3857c2017-02-19 13:56:41 -0600210 try:
Adriana Kobylak465aaec2017-02-20 11:58:03 -0600211 error_lvl[fullname] = i['level']
Adriana Kobylak8c3857c2017-02-19 13:56:41 -0600212 except:
213 print ("No level found for: " + i['name'] + ", using INFO")
Adriana Kobylak465aaec2017-02-20 11:58:03 -0600214 error_lvl[fullname] = "INFO"
Andrew Geissler184690d2016-11-03 08:06:31 -0500215 tmp_meta = []
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500216 # grab all the meta data fields and info
Deepak Kodihalli7924b172017-03-08 00:04:33 -0600217 if('meta' in i):
218 for j in i['meta']:
219 str_short = j['str'].split('=')[0]
220 tmp_meta.append(str_short)
221 meta_data[str_short] = {}
222 meta_data[str_short]['str'] = j['str']
223 meta_data[str_short]['str_short'] = str_short
224 meta_data[str_short]['type'] = get_cpp_type(j['type'])
225 meta[fullname] = tmp_meta
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500226
227 # Debug
Andrew Geissler184690d2016-11-03 08:06:31 -0500228 # for i in errors:
Andrew Geisslerdf048c12016-11-10 16:50:35 -0600229 # print "ERROR: " + errors[i]
230 # print " MSG: " + error_msg[errors[i]]
231 # print " LVL: " + error_lvl[errors[i]]
232 # print " META: "
233 # print meta[i]
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500234
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500235
236def main(i_args):
237 parser = OptionParser()
238
Andrew Geissler184690d2016-11-03 08:06:31 -0500239 parser.add_option("-m", "--mako", dest="elog_mako",
240 default="elog-gen-template.mako.hpp",
Andrew Geisslerdf048c12016-11-10 16:50:35 -0600241 help="input mako template file to use")
Andrew Geissler184690d2016-11-03 08:06:31 -0500242
243 parser.add_option("-o", "--output", dest="output_hpp",
Adriana Kobylakebd59fa2017-02-06 20:55:39 -0600244 default="elog-errors.hpp",
245 help="output hpp to generate, elog-errors.hpp default")
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500246
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600247 parser.add_option("-y", "--yamldir", dest="yamldir",
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -0600248 default="None",
Andrew Geisslerf1f2cfa2016-11-21 15:16:45 -0600249 help="Base directory of yaml files to process")
250
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -0600251 parser.add_option("-u", "--testdir", dest="testdir",
252 default="./tools/example/",
253 help="Unit test directory of yaml files to process")
254
Andrew Geisslerf1f2cfa2016-11-21 15:16:45 -0600255 parser.add_option("-t", "--templatedir", dest="templatedir",
256 default="phosphor-logging/templates/",
257 help="Base directory of files to process")
258
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500259 (options, args) = parser.parse_args(i_args)
260
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600261 gen_elog_hpp(options.yamldir,
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -0600262 options.testdir,
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600263 options.output_hpp,
264 options.templatedir,
Adriana Kobylak371a38b2017-02-19 13:45:42 -0600265 options.elog_mako)
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500266
267# Only run if it's a script
268if __name__ == '__main__':
Andrew Geissler184690d2016-11-03 08:06:31 -0500269 main(sys.argv[1:])