blob: 1a79139c70091f2399cc671fd01ed79fb3e6b74d [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 Kobylak6a9db6e2017-02-21 12:58:05 -060059def get_error_yaml_files(i_yaml_dir, i_test_dir):
Adriana Kobylak371a38b2017-02-19 13:45:42 -060060 yaml_files = dict()
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -060061 if i_yaml_dir != "None":
62 for root, dirs, files in os.walk(i_yaml_dir):
63 for files in filter(lambda file:
64 file.endswith('.errors.yaml'), files):
Adriana Kobylak371a38b2017-02-19 13:45:42 -060065 splitdir = root.split(i_yaml_dir)[1]
66 yaml_files[(os.path.join(root, files))] = splitdir
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -060067 for root, dirs, files in os.walk(i_test_dir):
Adriana Kobylakf4690732017-02-19 09:53:34 -060068 for files in filter(lambda file: file.endswith('.errors.yaml'), files):
Adriana Kobylak371a38b2017-02-19 13:45:42 -060069 splitdir = root.split(i_test_dir)[1]
70 yaml_files[(os.path.join(root, files))] = splitdir
Deepak Kodihalli160d3e02017-01-17 04:25:22 -060071 return yaml_files
72
73
74def get_meta_yaml_file(i_error_yaml_file):
75 # the meta data will be defined in file name where we replace
76 # <Interface>.errors.yaml with <Interface>.metadata.yaml
77 meta_yaml = i_error_yaml_file.replace("errors", "metadata")
78 return meta_yaml
79
80
Deepak Kodihalli99161192017-01-16 04:00:07 -060081def get_cpp_type(i_type):
82 typeMap = {
83 'int16': 'int16_t',
84 'int32': 'int32_t',
85 'int64': 'int64_t',
86 'uint16': 'uint16_t',
87 'uint32': 'uint32_t',
88 'uint64': 'uint64_t',
89 'double': 'double',
90 # const char* aids usage of constexpr
91 'string': 'const char*'}
92
93 return typeMap[i_type]
94
95
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -060096def gen_elog_hpp(i_yaml_dir, i_test_dir, i_output_hpp,
Adriana Kobylak371a38b2017-02-19 13:45:42 -060097 i_template_dir, i_elog_mako):
Andrew Geisslerc830e0f2016-10-18 12:51:29 -050098 r"""
Deepak Kodihalli160d3e02017-01-17 04:25:22 -060099 Read yaml file(s) under input yaml dir, grab the relevant data and call
100 the mako template to generate the output header file.
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500101
102 Description of arguments:
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -0600103 i_yaml_dir directory containing base error yaml files
104 i_test_dir directory containing test error yaml files
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600105 i_output_hpp name of the to be generated output hpp
106 i_template_dir directory containing error mako templates
107 i_elog_mako error mako template to render
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500108 """
109
110 # Input parameters to mako template
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600111 errors = list() # Main error codes
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500112 error_msg = dict() # Error msg that corresponds to error code
113 error_lvl = dict() # Error code log level (debug, info, error, ...)
Deepak Kodihalli5d1aace2017-01-18 00:17:39 -0600114 meta = dict() # The meta data names associated (ERRNO, FILE_NAME, ...)
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500115 meta_data = dict() # The meta data info (type, format)
Deepak Kodihalli5d1aace2017-01-18 00:17:39 -0600116 parents = dict()
Adriana Kobylak371a38b2017-02-19 13:45:42 -0600117 namespace = dict()
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500118
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -0600119 error_yamls = get_error_yaml_files(i_yaml_dir, i_test_dir)
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600120
121 for error_yaml in error_yamls:
122 # Verify the error yaml file
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600123 if (not (os.path.isfile(error_yaml))):
Patrick Williams6f299132017-02-16 13:27:39 -0600124 print("Can not find input yaml file " + error_yaml)
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600125 exit(1)
126
127 # Verify the metadata yaml file
128 meta_yaml = get_meta_yaml_file(error_yaml)
129 if (not (os.path.isfile(meta_yaml))):
Patrick Williams6f299132017-02-16 13:27:39 -0600130 print("Can not find meta yaml file " + meta_yaml)
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600131 exit(1)
132
133 # Verify the input mako file
134 template_path = "/".join((i_template_dir, i_elog_mako))
135 if (not (os.path.isfile(template_path))):
Patrick Williams6f299132017-02-16 13:27:39 -0600136 print("Can not find input template file " + template_path)
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600137 exit(1)
138
139 get_elog_data(error_yaml,
140 meta_yaml,
Adriana Kobylak371a38b2017-02-19 13:45:42 -0600141 error_yamls[error_yaml],
142 # Last arg is a tuple
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600143 (errors,
144 error_msg,
145 error_lvl,
146 meta,
Deepak Kodihalli82b7de72017-01-17 07:59:29 -0600147 meta_data,
Adriana Kobylak371a38b2017-02-19 13:45:42 -0600148 parents,
149 namespace))
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600150
Deepak Kodihallicbd12c82017-01-17 08:50:55 -0600151 if(not check_error_inheritance(errors, parents)):
Patrick Williams6f299132017-02-16 13:27:39 -0600152 print("Error - failed to validate error inheritance")
Deepak Kodihallicbd12c82017-01-17 08:50:55 -0600153 exit(1)
154
Deepak Kodihalli5d1aace2017-01-18 00:17:39 -0600155 errors = order_inherited_errors(errors, parents)
156
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600157 # Load the mako template and call it with the required data
158 yaml_dir = i_yaml_dir.strip("./")
159 yaml_dir = yaml_dir.strip("../")
160 template = Template(filename=template_path)
161 f = open(i_output_hpp, 'w')
162 f.write(template.render(
163 errors=errors, error_msg=error_msg,
164 error_lvl=error_lvl, meta=meta,
Adriana Kobylak371a38b2017-02-19 13:45:42 -0600165 meta_data=meta_data, error_namespace=namespace,
Deepak Kodihallif2462f02017-01-19 03:40:12 -0600166 parents=parents))
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600167 f.close()
168
169
170def get_elog_data(i_elog_yaml,
171 i_elog_meta_yaml,
Adriana Kobylak371a38b2017-02-19 13:45:42 -0600172 i_namespace,
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600173 o_elog_data):
174 r"""
175 Parse the error and metadata yaml files in order to pull out
176 error metadata.
177
178 Description of arguments:
179 i_elog_yaml error yaml file
180 i_elog_meta_yaml metadata yaml file
Adriana Kobylak371a38b2017-02-19 13:45:42 -0600181 i_namespace namespace data
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600182 o_elog_data error metadata
183 """
Adriana Kobylak371a38b2017-02-19 13:45:42 -0600184 errors, error_msg, error_lvl, meta, meta_data, parents, namespace = \
185 o_elog_data
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600186 ifile = yaml.safe_load(open(i_elog_yaml))
Andrew Geisslere8596302016-11-21 16:06:53 -0600187 mfile = yaml.safe_load(open(i_elog_meta_yaml))
Adriana Kobylak17944e12017-02-13 22:29:21 -0600188 for i in mfile:
Andrew Geisslere8596302016-11-21 16:06:53 -0600189 match = None
190 # Find the corresponding meta data for this entry
Adriana Kobylak17944e12017-02-13 22:29:21 -0600191 for j in ifile:
192 if j['name'] == i['name']:
193 match = j
Andrew Geisslere8596302016-11-21 16:06:53 -0600194 break
195 if (match is None):
Patrick Williams6f299132017-02-16 13:27:39 -0600196 print("Error - Did not find meta data for " + i['name'])
Andrew Geisslere8596302016-11-21 16:06:53 -0600197 exit(1)
Andrew Geisslerdf048c12016-11-10 16:50:35 -0600198 # Grab the main error and it's info
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600199 errors.append(i['name'])
Deepak Kodihalli82b7de72017-01-17 07:59:29 -0600200 parent = None
201 if('inherits' in i):
202 # xyz.openbmc.Foo, we need Foo
203 # Get 0th inherited error (current support - single inheritance)
204 parent = i['inherits'][0].split(".").pop()
Deepak Kodihalli5d1aace2017-01-18 00:17:39 -0600205 parents[i['name']] = parent
Adriana Kobylak17944e12017-02-13 22:29:21 -0600206 error_msg[i['name']] = match['description']
Adriana Kobylak8c3857c2017-02-19 13:56:41 -0600207 try:
208 error_lvl[i['name']] = i['level']
209 except:
210 print ("No level found for: " + i['name'] + ", using INFO")
211 error_lvl[i['name']] = "INFO"
Andrew Geissler184690d2016-11-03 08:06:31 -0500212 tmp_meta = []
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500213 # grab all the meta data fields and info
Adriana Kobylak17944e12017-02-13 22:29:21 -0600214 for j in i['meta']:
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500215 str_short = j['str'].split('=')[0]
216 tmp_meta.append(str_short)
217 meta_data[str_short] = {}
218 meta_data[str_short]['str'] = j['str']
219 meta_data[str_short]['str_short'] = str_short
Deepak Kodihalli99161192017-01-16 04:00:07 -0600220 meta_data[str_short]['type'] = get_cpp_type(j['type'])
Deepak Kodihalli5d1aace2017-01-18 00:17:39 -0600221 meta[i['name']] = tmp_meta
Adriana Kobylak371a38b2017-02-19 13:45:42 -0600222 namespace[i['name']] = i_namespace
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500223
224 # Debug
Andrew Geissler184690d2016-11-03 08:06:31 -0500225 # for i in errors:
Andrew Geisslerdf048c12016-11-10 16:50:35 -0600226 # print "ERROR: " + errors[i]
227 # print " MSG: " + error_msg[errors[i]]
228 # print " LVL: " + error_lvl[errors[i]]
229 # print " META: "
230 # print meta[i]
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500231
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500232
233def main(i_args):
234 parser = OptionParser()
235
Andrew Geissler184690d2016-11-03 08:06:31 -0500236 parser.add_option("-m", "--mako", dest="elog_mako",
237 default="elog-gen-template.mako.hpp",
Andrew Geisslerdf048c12016-11-10 16:50:35 -0600238 help="input mako template file to use")
Andrew Geissler184690d2016-11-03 08:06:31 -0500239
240 parser.add_option("-o", "--output", dest="output_hpp",
241 default="elog-gen.hpp",
Andrew Geisslerdf048c12016-11-10 16:50:35 -0600242 help="output hpp to generate, elog-gen.hpp is default")
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500243
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600244 parser.add_option("-y", "--yamldir", dest="yamldir",
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -0600245 default="None",
Andrew Geisslerf1f2cfa2016-11-21 15:16:45 -0600246 help="Base directory of yaml files to process")
247
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -0600248 parser.add_option("-u", "--testdir", dest="testdir",
249 default="./tools/example/",
250 help="Unit test directory of yaml files to process")
251
Andrew Geisslerf1f2cfa2016-11-21 15:16:45 -0600252 parser.add_option("-t", "--templatedir", dest="templatedir",
253 default="phosphor-logging/templates/",
254 help="Base directory of files to process")
255
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500256 (options, args) = parser.parse_args(i_args)
257
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600258 gen_elog_hpp(options.yamldir,
Adriana Kobylak6a9db6e2017-02-21 12:58:05 -0600259 options.testdir,
Deepak Kodihalli160d3e02017-01-17 04:25:22 -0600260 options.output_hpp,
261 options.templatedir,
Adriana Kobylak371a38b2017-02-19 13:45:42 -0600262 options.elog_mako)
Andrew Geisslerc830e0f2016-10-18 12:51:29 -0500263
264# Only run if it's a script
265if __name__ == '__main__':
Andrew Geissler184690d2016-11-03 08:06:31 -0500266 main(sys.argv[1:])