Merge lp:~mpontillo/maas/add-logging-for-bug-1627362 into lp:~maas-committers/maas/trunk

Proposed by Mike Pontillo
Status: Rejected
Rejected by: Mike Pontillo
Proposed branch: lp:~mpontillo/maas/add-logging-for-bug-1627362
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 92 lines (+68/-0)
1 file modified
src/maasserver/monkey.py (+68/-0)
To merge this branch: bzr merge lp:~mpontillo/maas/add-logging-for-bug-1627362
Reviewer Review Type Date Requested Status
Gavin Panella (community) Approve
Review via email: mp+307574@code.launchpad.net

Commit message

Add logging for bug #1627362, so we can attempt to determine the root cause.

To post a comment you must log in.
5431. By Mike Pontillo

Fix lint.

Revision history for this message
Gavin Panella (allenap) wrote :

Looks good. Some comments but no blockers.

review: Approve
Revision history for this message
Mike Pontillo (mpontillo) :
Revision history for this message
Mike Pontillo (mpontillo) wrote :

We may want to come back to this if we have trouble finding the root cause, but for now it won't be needed. The problem seems to be in the websocket handler's batch handling.

Unmerged revisions

5432. By Mike Pontillo

Add debug logging.

5431. By Mike Pontillo

Fix lint.

5430. By Mike Pontillo

Add logging for bug #1627362.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/maasserver/monkey.py'
2--- src/maasserver/monkey.py 2016-08-19 10:22:29 +0000
3+++ src/maasserver/monkey.py 2016-10-04 14:12:19 +0000
4@@ -7,14 +7,69 @@
5
6 __all__ = [
7 "add_patches_to_django",
8+ "orig_parse_datetime"
9 ]
10
11+import datetime
12 import re
13
14+from provisioningserver.logger import get_maas_logger
15+
16+
17+maaslog = get_maas_logger("maassever.monkey")
18
19 fixed_re = re.compile(r"^([a-z0-9.-]+|\[[a-f0-9]*:[a-f0-9:\.]+\])(:\d+)?$")
20
21
22+def _parse_datetime_init(value, *args, **kwargs):
23+ """Initializer for the orig_parse_datetime global.
24+
25+ This is just in case this method somehow gets called before it's
26+ initialized, which should never happen.
27+ """
28+ raise NotImplementedError("Not patched yet.")
29+
30+# Global variable which will be assigned to the original Django parse_datetime.
31+orig_parse_datetime = _parse_datetime_init
32+
33+
34+def maas_parse_datetime(value, *args, **kwargs):
35+ """Patch for bug #1627362.
36+
37+ Also logs the error so we can attempt to determine the root cause.
38+ """
39+ try:
40+ orig_parse_datetime(value, args, kwargs)
41+ except TypeError as e:
42+ # Check if this is the known-problematic TypeError.
43+ if str(e) == "expected string or bytes-like object":
44+ maaslog.warning(
45+ "[Bug #1627362] Django parse_datetime expected bytes/str; got "
46+ "'%s': %r. (If you see this message, please leave a comment "
47+ "at https://launchpad.net/bugs/1627362 if it has not yet been "
48+ "resolved.)" % (str(type(value), value)))
49+ # This may or may not work around the issue, but it's going to be
50+ # better than crashing. In MAAS, DateTimeField is use for created
51+ # and updated values (on EVERY model), commissioning results
52+ # timestamps, the Django `auth_user` model (date_joined,
53+ # last_login), and the Discovery model (last_seen and first_seen).
54+ # Although None is a valid return value for this function, other
55+ # code expects these values to be NOT NULL. Setting this to 1970 so
56+ # that users who encounter this bug may notice something strange,
57+ # but will not necessarily crash their MAAS.
58+ return datetime.datetime(1970, 1, 1, 1, 0)
59+ else:
60+ # If TypeError occurred for some other reason, just return None
61+ # here so we can investigate the crash. This is actually a
62+ # different bug.
63+ maaslog.warning(
64+ "[Bug #1627362] TypeError (%s); got '%s': %r. (If you see this"
65+ "message, please leave a comment at "
66+ "https://launchpad.net/bugs/1627362 if it has not yet been "
67+ "resolved.)" % (str(type(value), value)))
68+ return None
69+
70+
71 def fix_django_http_request():
72 """Add support for ipv6-formatted ipv4 addresses to django requests.
73
74@@ -25,5 +80,18 @@
75 django.http.request.host_validation_re = fixed_re
76
77
78+def fix_django_parse_datetime():
79+ import django.utils.dateparse
80+ try:
81+ django.utils.dateparse.parse_datetime(None)
82+ except TypeError:
83+ # The API indicates that None should be returned in the event of an
84+ # error. (A TypeError here is incorrect.)
85+ global orig_parse_datetime
86+ orig_parse_datetime = django.utils.dateparse.parse_datetime
87+ django.utils.dateparse.parse_datetime = maas_parse_datetime
88+
89+
90 def add_patches_to_django():
91 fix_django_http_request()
92+ fix_django_parse_datetime()