Add NETVIRT-1270 to whitelist
[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/NEUTRON-157",
118      "id": "ConflictingModificationAppliedException",
119      "context": [
120          "Optimistic lock failed for path /(urn:opendaylight:neutron?revision=2015-07-12)" +
121          "neutron/networks/network/network[{(urn:opendaylight:neutron?revision=2015-07-12)uuid=",
122          "Conflicting modification for path /(urn:opendaylight:neutron?revision=2015-07-12)" +
123          "neutron/networks/network/network[{(urn:opendaylight:neutron?revision=2015-07-12)uuid="
124      ]},
125     {"issue": "https://jira.opendaylight.org/browse/NEUTRON-157",
126      "id": "OptimisticLockFailedException",
127      "context": [
128          "Got OptimisticLockFailedException",
129          "AbstractTranscriberInterface"
130      ]},
131     {"issue": "https://jira.opendaylight.org/browse/NEUTRON-157",
132      "id": "ConflictingModificationAppliedException",
133      "context": [
134          "Optimistic lock failed for path /(urn:opendaylight:neutron?revision=2015-07-12)neutron"
135      ]},
136     # oxygen
137     {"issue": "https://jira.opendaylight.org/browse/NEUTRON-157",
138      "id": "ConflictingModificationAppliedException",
139      "context": [
140          "OptimisticLockFailedException: Optimistic lock failed.",
141          "Conflicting modification for path /(urn:opendaylight:neutron?revision=2015-07-12)" +
142          "neutron/networks/network/network[{(urn:opendaylight:neutron?revision=2015-07-12)uuid=",
143      ]},
144     {"issue": "https://jira.opendaylight.org/browse/OPNFLWPLUG-917",
145      "id": "IllegalStateException",
146      "context": [
147          "java.lang.IllegalStateException: Deserializer for key: msgVersion: 4 objectClass: " +
148          "org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entries.grouping.MatchEntry " +
149          "msgType: 1 oxm_field: 33 experimenterID: null was not found " +
150          "- please verify that all needed deserializers ale loaded correctly"
151      ]}
152 ]
153
154 _re_ts = re.compile(r"^[0-9]{4}(-[0-9]{2}){2}T([0-9]{2}:){2}[0-9]{2},[0-9]{3}")
155 _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  \| )")
156 _re_ex = re.compile(r"(?i)exception")
157 _ex_map = collections.OrderedDict()
158 _ts_list = []
159 _fail = []
160
161
162 def get_exceptions(lines):
163     """
164     Create a map of exceptions that also has a list of warnings and errors preceeding
165     the exception to use as context.
166
167     The lines are parsed to create a list where all lines related to a timestamp
168     are aggregated. Timestamped lines with exception (case insensitive) are copied
169     to the exception map keyed to the index of the timestamp line. Each exception value
170     also has a list containing WARN and ERROR lines proceeding the exception.
171
172     :param list lines:
173     :return OrderedDict _ex_map: map of exceptions
174     """
175     global _ex_map
176     _ex_map = collections.OrderedDict()
177     global _ts_list
178     _ts_list = []
179     cur_list = []
180     warnerr_deq = collections.deque(maxlen=5)
181
182     for line in lines:
183         ts = _re_ts.search(line)
184
185         # Check if this is the start or continuation of a timestamp line
186         if ts:
187             cur_list = [line]
188             _ts_list.append(cur_list)
189             ts_we = _re_ts_we.search(line)
190             # Track WARN and ERROR lines
191             if ts_we:
192                 warn_err_index = len(_ts_list) - 1
193                 warnerr_deq.append(warn_err_index)
194         # Append to current timestamp line since this is not a timestamp line
195         else:
196             cur_list.append(line)
197
198         # Add the timestamp line to the exception map if it has an exception
199         ex = _re_ex.search(line)
200         if ex:
201             index = len(_ts_list) - 1
202             if index not in _ex_map:
203                 _ex_map[index] = {"warnerr_list": list(warnerr_deq), 'lines': cur_list}
204                 warnerr_deq.clear()  # reset the deque to only track new ERROR and WARN lines
205
206     return _ex_map
207
208
209 def check_exceptions():
210     """
211     Return a list of exceptions that were not in the whitelist.
212
213     Each exception found is compared against all the patterns
214     in the whitelist.
215
216     :return list _fail: list of exceptions not in the whitelist
217     """
218     global _fail
219     _fail = []
220     _match = []
221     for ex_idx, ex in _ex_map.items():
222         ex_str = "__".join(ex.get("lines"))
223         for whitelist in _whitelist:
224             # skip the current whitelist exception if not in the current exception
225             if whitelist.get("id") not in ex_str:
226                 continue
227             whitelist_contexts = whitelist.get("context")
228             num_context_matches = 0
229             for whitelist_context in whitelist_contexts:
230                 for exwe_index in reversed(ex.get("warnerr_list")):
231                     exwe_str = "__".join(_ts_list[exwe_index])
232                     if whitelist_context in exwe_str:
233                         num_context_matches += 1
234             # Mark this exception as a known issue if all the context's matched
235             if num_context_matches >= len(whitelist_contexts):
236                 ex["issue"] = whitelist.get("issue")
237                 _match.append(ex)
238                 logging.info("known exception was seen: {}".format(ex["issue"]))
239                 break
240         # A new exception when it isn't marked with a known issue.
241         if "issue" not in ex:
242             _fail.append(ex)
243     return _fail, _match
244
245
246 def verify_exceptions(lines):
247     """
248     Return a list of exceptions not in the whitelist for the given lines.
249
250     :param list lines: list of lines from a log
251     :return list, list: one list of exceptions not in the whitelist, and a second with matching issues
252     """
253     if not lines:
254         return
255     get_exceptions(lines)
256     return check_exceptions()
257
258
259 def write_exceptions_map_to_file(testname, filename, mode="a+"):
260     """
261     Write the exceptions map to a file under the testname header. The output
262     will include all lines in the exception itself as well as any previous
263     contextual warning or error lines. The output will be appended or overwritten
264     depending on the mode parameter. It is assumed that the caller has called
265     verify_exceptions() earlier to populate the exceptions map, otherwise only
266     the testname and header will be printed to the file.
267
268     :param str testname: The name of the test
269     :param str filename: The file to open for writing
270     :param str mode: Append (a+) or overwrite (w+)
271     """
272     try:
273         os.makedirs(os.path.dirname(filename))
274     except OSError as exception:
275         if exception.errno != errno.EEXIST:
276             raise
277
278     with open(filename, mode) as fp:
279         fp.write("{}\n".format("=" * 60))
280         fp.write("Starting test: {}\n".format(testname))
281         for ex_idx, ex in _ex_map.items():
282             fp.write("{}\n".format("-" * 40))
283             if "issue" in ex:
284                 fp.write("Exception was matched to: {}\n".format(ex.get("issue")))
285             else:
286                 fp.write("Exception is new\n")
287             for exwe_index in ex.get("warnerr_list")[:-1]:
288                 for line in _ts_list[exwe_index]:
289                     fp.write("{}\n".format(line))
290             fp.writelines(ex.get("lines"))
291             fp.write("\n")