Update whtielist
[integration/test.git] / csit / libraries / netvirt / excepts.py
1 import collections
2 import errno
3 import logging
4 import os
5 import re
6
7 # Make sure to have unique matches in different lines
8 # Order the list in alphabetical order based on the "issue" key
9 _whitelist = [
10     {"issue": "https://jira.opendaylight.org/browse/NETVIRT-972",
11      "id": "ConflictingModificationAppliedException",
12      "context": [
13          "Node was created by other transaction",
14          "Optimistic lock failed for path /(urn:opendaylight:inventory?revision=2013-08-19)nodes/node/node" +
15          "[{(urn:opendaylight:inventory?revision=2013-08-19)id=openflow",
16          "table/table[{(urn:opendaylight:flow:inventory?revision=2013-08-19)id=21}]/flow/flow" +
17          "[{(urn:opendaylight:flow:inventory?revision=2013-08-19)id=L3."
18      ]},
19     # oxygen
20     {"issue": "https://jira.opendaylight.org/browse/NETVIRT-972",
21      "id": "ConflictingModificationAppliedException",
22      "context": [
23          "Node was created by other transaction",
24          "OptimisticLockFailedException: Optimistic lock failed."
25          "Conflicting modification for path /(urn:opendaylight:inventory?revision=2013-08-19)nodes/node/node" +
26          "[{(urn:opendaylight:inventory?revision=2013-08-19)id=",
27          "table/table[{(urn:opendaylight:flow:inventory?revision=2013-08-19)id=21}]/flow/flow" +
28          "[{(urn:opendaylight:flow:inventory?revision=2013-08-19)id=L3.", ".21.", ".42."
29      ]},
30     {"issue": "https://jira.opendaylight.org/browse/NETVIRT-1135",
31      "id": "ConflictingModificationAppliedException",
32      "context": [
33          "Node was created by other transaction",
34          "Optimistic lock failed for path /(urn:opendaylight:inventory?revision=2013-08-19)nodes/node/node" +
35          "[{(urn:opendaylight:inventory?revision=2013-08-19)id=openflow:",
36      ]},
37     # oxygen
38     {"issue": "https://jira.opendaylight.org/browse/NETVIRT-1135",
39      "id": "ConflictingModificationAppliedException",
40      "context": [
41          "OptimisticLockFailedException: Optimistic lock failed."
42          "Conflicting modification for path /(urn:opendaylight:inventory?revision=2013-08-19)nodes/node/node" +
43          "[{(urn:opendaylight:inventory?revision=2013-08-19)id=openflow:",
44          "table/table[{(urn:opendaylight:flow:inventory?revision=2013-08-19)id=47}]/flow/flow" +
45          "[{(urn:opendaylight:flow:inventory?revision=2013-08-19)id=SNAT.", ".47."
46      ]},
47     {"issue": "https://jira.opendaylight.org/browse/NETVIRT-1136",
48      "id": "ConflictingModificationAppliedException",
49      "context": [
50          "Node was deleted by other transaction",
51          "Optimistic lock failed for path /(urn:opendaylight:netvirt:elan?revision=2015-06-02)elan-" +
52          "forwarding-tables/mac-table/mac-table[{(urn:opendaylight:netvirt:elan?revision=2015-06-02)" +
53          "elan-instance-name=",
54      ]},
55     # oxygen version of NETVIRT-1136
56     {"issue": "https://jira.opendaylight.org/browse/NETVIRT-1136",
57      "id": "ConflictingModificationAppliedException",
58      "context": [
59          "Node was deleted by other transaction",
60          "OptimisticLockFailedException: Optimistic lock failed.",
61          "Conflicting modification for path /(urn:opendaylight:netvirt:elan?revision=2015-06-02)elan-" +
62          "forwarding-tables/mac-table/mac-table[{(urn:opendaylight:netvirt:elan?revision=2015-06-02)" +
63          "elan-instance-name="
64      ]},
65     {"issue": "https://jira.opendaylight.org/browse/NETVIRT-1260",
66      "id": "ConflictingModificationAppliedException",
67      "context": [
68          "Optimistic lock failed for path /(urn:ietf:params:xml:ns:yang:ietf-interfaces?revision=2014-05-08)" +
69          "interfaces/interface/interface[{(urn:ietf:params:xml:ns:yang:ietf-interfaces?revision=2014-05-08)name=",
70      ]},
71     {"issue": "https://jira.opendaylight.org/browse/NETVIRT-1270",
72      "id": "ConflictingModificationAppliedException",
73      "context": [
74          "OptimisticLockFailedException",
75          "/(urn:opendaylight:netvirt:l3vpn?revision=2013-09-11)" +
76          "vpn-instance-op-data/vpn-instance-op-data-entry/vpn-instance-op-data-entry" +
77          "[{(urn:opendaylight:netvirt:l3vpn?revision=2013-09-11)vrf-id=",
78          "vrf-id=", "/vpn-to-dpn-list/vpn-to-dpn-list", "dpnId="
79      ]},
80     {"issue": "https://jira.opendaylight.org/browse/NETVIRT-1270",
81      "id": "ExecutionException",
82      "context": [
83          "OptimisticLockFailedException: Optimistic lock failed",
84          "removeOrUpdateVpnToDpnList: Error removing from dpnToVpnList for vpn "
85      ]},
86     {"issue": "https://jira.opendaylight.org/browse/NETVIRT-1270",
87      "id": "OptimisticLockFailedException",
88      "context": [
89          "OptimisticLockFailedException",
90          "VpnInterfaceOpListener",
91          "Direct Exception (not failed Future) when executing job, won't even retry: JobEntry{key='VPNINTERFACE-",
92          "vpn-instance-op-data/vpn-instance-op-data-entry/vpn-instance-op-data-entry" +
93          "[{(urn:opendaylight:netvirt:l3vpn?revision=2013-09-11)vrf-id=",
94          "vrf-id=", "/vpn-to-dpn-list/vpn-to-dpn-list", "dpnId="
95      ]},
96     {"issue": "https://jira.opendaylight.org/browse/NETVIRT-1281",
97      "id": "OptimisticLockFailedException",
98      "context": [
99          "OptimisticLockFailedException: Optimistic lock failed.",
100          "ConflictingModificationAppliedException: Node children was modified by other transaction",
101          "Direct Exception (not failed Future) when executing job, won't even retry: JobEntry{key='VPNINTERFACE-"
102      ]},
103     {"issue": "https://jira.opendaylight.org/browse/NETVIRT-1304",
104      "id": "ModifiedNodeDoesNotExistException",
105      "context": [
106          "ModifiedNodeDoesNotExistException",
107          "/(urn:opendaylight:netvirt:fibmanager?revision=2015-03-30)fibEntries/" +
108          "vrfTables/vrfTables[{(urn:opendaylight:netvirt:fibmanager?revision=2015-03-30)routeDistinguisher="
109      ]},
110     {"issue": "https://jira.opendaylight.org/browse/NETVIRT-1304",
111      "id": "TransactionCommitFailedException",
112      "context": [
113          "TransactionCommitFailedException",
114          "/(urn:opendaylight:netvirt:fibmanager?revision=2015-03-30)fibEntries/" +
115          "vrfTables/vrfTables[{(urn:opendaylight:netvirt:fibmanager?revision=2015-03-30)routeDistinguisher="
116      ]},
117     {"issue": "https://jira.opendaylight.org/browse/NETVIRT-1427",
118      "id": "ModifiedNodeDoesNotExistException",
119      "context": [
120          "/(urn:huawei:params:xml:ns:yang:l3vpn?revision=2014-08-15)vpn-interfaces/vpn-interface/vpn-interface" +
121          "[{(urn:huawei:params:xml:ns:yang:l3vpn?revision=2014-08-15)name=",
122          "AugmentationIdentifier{childNames=[(urn:opendaylight:netvirt:l3vpn?revision=2013-09-11)adjacency]}"
123      ]},
124     {"issue": "https://jira.opendaylight.org/browse/NETVIRT-1428",
125      "id": "ModifiedNodeDoesNotExistException",
126      "context": [
127          "/(urn:huawei:params:xml:ns:yang:l3vpn?revision=2014-08-15)vpn-interfaces/vpn-interface/vpn-interface" +
128          "[{(urn:huawei:params:xml:ns:yang:l3vpn?revision=2014-08-15)name=",
129      ]},
130     {"issue": "https://jira.opendaylight.org/browse/NEUTRON-157",
131      "id": "ConflictingModificationAppliedException",
132      "context": [
133          "Optimistic lock failed for path /(urn:opendaylight:neutron?revision=2015-07-12)" +
134          "neutron/networks/network/network[{(urn:opendaylight:neutron?revision=2015-07-12)uuid=",
135          "Conflicting modification for path /(urn:opendaylight:neutron?revision=2015-07-12)" +
136          "neutron/networks/network/network[{(urn:opendaylight:neutron?revision=2015-07-12)uuid="
137      ]},
138     {"issue": "https://jira.opendaylight.org/browse/NEUTRON-157",
139      "id": "OptimisticLockFailedException",
140      "context": [
141          "Got OptimisticLockFailedException",
142          "AbstractTranscriberInterface"
143      ]},
144     {"issue": "https://jira.opendaylight.org/browse/NEUTRON-157",
145      "id": "ConflictingModificationAppliedException",
146      "context": [
147          "Optimistic lock failed for path /(urn:opendaylight:neutron?revision=2015-07-12)neutron"
148      ]},
149     # oxygen
150     {"issue": "https://jira.opendaylight.org/browse/NEUTRON-157",
151      "id": "ConflictingModificationAppliedException",
152      "context": [
153          "OptimisticLockFailedException: Optimistic lock failed.",
154          "Conflicting modification for path /(urn:opendaylight:neutron?revision=2015-07-12)" +
155          "neutron/networks/network/network[{(urn:opendaylight:neutron?revision=2015-07-12)uuid=",
156      ]},
157     {"issue": "https://jira.opendaylight.org/browse/OPNFLWPLUG-917",
158      "id": "IllegalStateException",
159      "context": [
160          "java.lang.IllegalStateException: Deserializer for key: msgVersion: 4 objectClass: " +
161          "org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entries.grouping.MatchEntry " +
162          "msgType: 1 oxm_field: 33 experimenterID: null was not found " +
163          "- please verify that all needed deserializers ale loaded correctly"
164      ]}
165 ]
166
167 _re_ts = re.compile(r"^[0-9]{4}(-[0-9]{2}){2}T([0-9]{2}:){2}[0-9]{2},[0-9]{3}")
168 _re_ts_we = re.compile(r"^[0-9]{4}(-[0-9]{2}){2}T([0-9]{2}:){2}[0-9]{2},[0-9]{3}( \| ERROR \| | \| WARN  \| )")
169 _re_ex = re.compile(r"(?i)exception")
170 _ex_map = collections.OrderedDict()
171 _ts_list = []
172 _fail = []
173
174
175 def get_exceptions(lines):
176     """
177     Create a map of exceptions that also has a list of warnings and errors preceeding
178     the exception to use as context.
179
180     The lines are parsed to create a list where all lines related to a timestamp
181     are aggregated. Timestamped lines with exception (case insensitive) are copied
182     to the exception map keyed to the index of the timestamp line. Each exception value
183     also has a list containing WARN and ERROR lines proceeding the exception.
184
185     :param list lines:
186     :return OrderedDict _ex_map: map of exceptions
187     """
188     global _ex_map
189     _ex_map = collections.OrderedDict()
190     global _ts_list
191     _ts_list = []
192     cur_list = []
193     warnerr_deq = collections.deque(maxlen=5)
194
195     for line in lines:
196         ts = _re_ts.search(line)
197
198         # Check if this is the start or continuation of a timestamp line
199         if ts:
200             cur_list = [line]
201             _ts_list.append(cur_list)
202             ts_we = _re_ts_we.search(line)
203             # Track WARN and ERROR lines
204             if ts_we:
205                 warn_err_index = len(_ts_list) - 1
206                 warnerr_deq.append(warn_err_index)
207         # Append to current timestamp line since this is not a timestamp line
208         else:
209             cur_list.append(line)
210
211         # Add the timestamp line to the exception map if it has an exception
212         ex = _re_ex.search(line)
213         if ex:
214             index = len(_ts_list) - 1
215             if index not in _ex_map:
216                 _ex_map[index] = {"warnerr_list": list(warnerr_deq), 'lines': cur_list}
217                 warnerr_deq.clear()  # reset the deque to only track new ERROR and WARN lines
218
219     return _ex_map
220
221
222 def check_exceptions():
223     """
224     Return a list of exceptions that were not in the whitelist.
225
226     Each exception found is compared against all the patterns
227     in the whitelist.
228
229     :return list _fail: list of exceptions not in the whitelist
230     """
231     global _fail
232     _fail = []
233     _match = []
234     for ex_idx, ex in _ex_map.items():
235         ex_str = "__".join(ex.get("lines"))
236         for whitelist in _whitelist:
237             # skip the current whitelist exception if not in the current exception
238             if whitelist.get("id") not in ex_str:
239                 continue
240             whitelist_contexts = whitelist.get("context")
241             num_context_matches = 0
242             for whitelist_context in whitelist_contexts:
243                 for exwe_index in reversed(ex.get("warnerr_list")):
244                     exwe_str = "__".join(_ts_list[exwe_index])
245                     if whitelist_context in exwe_str:
246                         num_context_matches += 1
247             # Mark this exception as a known issue if all the context's matched
248             if num_context_matches >= len(whitelist_contexts):
249                 ex["issue"] = whitelist.get("issue")
250                 _match.append(ex)
251                 logging.info("known exception was seen: {}".format(ex["issue"]))
252                 break
253         # A new exception when it isn't marked with a known issue.
254         if "issue" not in ex:
255             _fail.append(ex)
256     return _fail, _match
257
258
259 def verify_exceptions(lines):
260     """
261     Return a list of exceptions not in the whitelist for the given lines.
262
263     :param list lines: list of lines from a log
264     :return list, list: one list of exceptions not in the whitelist, and a second with matching issues
265     """
266     if not lines:
267         return
268     get_exceptions(lines)
269     return check_exceptions()
270
271
272 def write_exceptions_map_to_file(testname, filename, mode="a+"):
273     """
274     Write the exceptions map to a file under the testname header. The output
275     will include all lines in the exception itself as well as any previous
276     contextual warning or error lines. The output will be appended or overwritten
277     depending on the mode parameter. It is assumed that the caller has called
278     verify_exceptions() earlier to populate the exceptions map, otherwise only
279     the testname and header will be printed to the file.
280
281     :param str testname: The name of the test
282     :param str filename: The file to open for writing
283     :param str mode: Append (a+) or overwrite (w+)
284     """
285     try:
286         os.makedirs(os.path.dirname(filename))
287     except OSError as exception:
288         if exception.errno != errno.EEXIST:
289             raise
290
291     with open(filename, mode) as fp:
292         fp.write("{}\n".format("=" * 60))
293         fp.write("Starting test: {}\n".format(testname))
294         for ex_idx, ex in _ex_map.items():
295             fp.write("{}\n".format("-" * 40))
296             if "issue" in ex:
297                 fp.write("Exception was matched to: {}\n".format(ex.get("issue")))
298             else:
299                 fp.write("Exception is new\n")
300             for exwe_index in ex.get("warnerr_list")[:-1]:
301                 for line in _ts_list[exwe_index]:
302                     fp.write("{}\n".format(line))
303             fp.writelines(ex.get("lines"))
304             fp.write("\n")