blob: 633091284c550bb5097683688e4432d2197676c0 [file] [log] [blame]
Matt Spinler3048ecc2018-03-28 10:15:12 -05001#!/usr/bin/env python
2
3'''Generates 2 reports about OpenBMC error logs:
4
5 1) Dumps every error defined in the errors.yaml files passed in
6 into a single JSON file that looks like:
7
8 {
9 "desc":"Callout IIC device",
10 "error":"xyz.openbmc_project.Common.Callout.Error.IIC",
11 "file":"xyz/openbmc_project/Common/Callout.errors.yaml",
12 "metadata":[
13 "CALLOUT_IIC_BUS",
14 "CALLOUT_IIC_ADDR",
15 "Inherits xyz.openbmc_project.Common.Callout.Error.Device"
16 ]
17 }
18
19 2) Crosschecks this generated JSON with the IBM error policy table,
20 showing if any errors are in one file but not the other.
21
22'''
23
24import argparse
25import os
26import json
27import yaml
28
29
30def get_errors(yaml_dirs):
31 '''Finds all of the errors in all of the error YAML files in
32 the directories passed in.'''
33
34 all_errors = []
35 for yaml_dir in yaml_dirs:
36 error_data = []
37 yaml_files = get_yaml(yaml_dir)
38
39 for yaml_file in yaml_files:
40 all_errors += read_error_yaml(yaml_dir, yaml_file)
41
42 return all_errors
43
44
45def read_error_yaml(yaml_dir, yaml_file):
46 '''Returns a list of dictionary objects reflecting the error YAML.'''
47
48 all_errors = []
49
50 #xyz/openbmc_project/x.errors.yaml -> xyz.openbmc_project.x.Error
51 error_base = yaml_file.replace(os.sep, '.')
52 error_base = error_base.replace('.errors.yaml', '')
53 error_base += '.Error.'
54
55 #Also needs to look up the metadata from the .metadata.yaml files
56 metadata_file = yaml_file.replace('errors.yaml', 'metadata.yaml')
57 metadata = []
58
59 if os.path.exists(os.path.join(yaml_dir, metadata_file)):
60 with open(os.path.join(yaml_dir, metadata_file)) as mfd:
61 metadata = yaml.safe_load(mfd.read())
62
63 with open(os.path.join(yaml_dir, yaml_file)) as fd:
64 data = yaml.safe_load(fd.read())
65
66 for e in data:
67 error = {}
68 error['error'] = error_base + e['name']
69 error['desc'] = e['description']
70 error['metadata'] = get_metadata(e['name'], metadata)
71 error['file'] = yaml_file
72 all_errors.append(error)
73
74 return all_errors
75
76
Matt Spinlera5ae51c2018-03-28 10:22:18 -050077def add_error(val):
78 '''Adds the '.Error' before the last segment of an error string.'''
79 dot = val.rfind('.')
80 return val[:dot] + '.Error' + val[dot:]
81
82
Matt Spinler3048ecc2018-03-28 10:15:12 -050083def get_metadata(name, metadata):
Matt Spinlera5ae51c2018-03-28 10:22:18 -050084 '''Finds metadata entries for the error in the metadata
85 dictionary parsed out of the *.metadata.yaml files.
86
87 The metadata YAML looks something like:
88 - name: SlaveDetectionFailure
89 meta:
90 - str: "ERRNO=%d"
91 type: int32
92 inherits:
93 - xyz.openbmc_project.Callout
94 '''
95
Matt Spinler3048ecc2018-03-28 10:15:12 -050096 data = []
Matt Spinlera5ae51c2018-03-28 10:22:18 -050097 for m in metadata:
98 if m['name'] == name:
99 if 'meta' in m:
100 for entry in m['meta']:
101 #Get the name from name=value
102 n = entry['str'].split('=')[0]
103 data.append(n)
104
105 #inherits is a list, return it comma separated
106 if 'inherits' in m:
107 vals = list(map(add_error, m['inherits']))
108 i = ','.join(vals)
109 data.append("Inherits %s" % i)
110
Matt Spinler3048ecc2018-03-28 10:15:12 -0500111 return data
112
113
114def get_yaml(yaml_dir):
115 '''Finds all of the *.errors.yaml files in the directory passed in.
116 Returns a list of entries like xyz/openbmc_project/Common.Errors.yaml.
117 '''
118
119 err_files = []
120 metadata_files = []
121 if os.path.exists(yaml_dir):
122 for directory, _, files in os.walk(yaml_dir):
123 if not files:
124 continue
125
126 err_files += map(
127 lambda f: os.path.relpath(
128 os.path.join(directory, f),
129 yaml_dir),
130 filter(lambda f: f.endswith('.errors.yaml'), files))
131
132 return err_files
133
134
135if __name__ == '__main__':
136
137 parser = argparse.ArgumentParser(description='Error log policy reports')
138
139 parser.add_argument('-y', '--yaml_dirs',
140 dest='yaml_dirs',
141 default='.',
142 help='Comma separated list of error YAML dirs')
143 parser.add_argument('-e', '--error_file',
144 dest='error_file',
145 default='obmc-errors.json',
146 help='Output Error report file')
147 parser.add_argument('-p', '--policy',
148 dest='policy_file',
149 default='condensed.json',
150 help='Condensed policy in JSON')
151
152 args = parser.parse_args()
153
154 dirs = args.yaml_dirs.split(',')
155 errors = get_errors(dirs)
156
157 with open(args.error_file, 'w') as outfile:
158 json.dump(errors, outfile, sort_keys=True,
159 indent=2, separators=(',', ':'))
160
161 #TODO: crosschecking