OLD | NEW |
---|---|
1 # Copyright 2014 The Chromium Authors. All rights reserved. | 1 # Copyright 2014 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 import contextlib | 5 import contextlib |
6 import datetime | 6 import datetime |
7 import datetime_encoder | |
8 import json | 7 import json |
9 import logging | 8 import logging |
10 import urllib | 9 import urllib |
10 import utils | |
11 import webapp2 | 11 import webapp2 |
12 import zlib | 12 import zlib |
13 | 13 |
14 import cloudstorage as gcs | 14 import cloudstorage as gcs |
15 | 15 |
16 from google.appengine.api import app_identity | 16 from google.appengine.api import app_identity |
17 from google.appengine.api import memcache | 17 from google.appengine.api import memcache |
18 from google.appengine.api import modules | |
agable
2015/08/12 22:18:08
Unused import?
| |
18 from google.appengine.api import users | 19 from google.appengine.api import users |
19 from google.appengine.datastore import datastore_query | 20 from google.appengine.datastore import datastore_query |
20 from google.appengine.ext import ndb | 21 from google.appengine.ext import ndb |
21 | 22 |
22 LOGGER = logging.getLogger(__name__) | 23 LOGGER = logging.getLogger(__name__) |
23 | 24 |
24 | 25 |
25 class AlertsJSON(ndb.Model): | 26 class AlertsJSON(ndb.Model): |
26 type = ndb.StringProperty() | 27 type = ndb.StringProperty() |
27 json = ndb.BlobProperty(compressed=True) | 28 json = ndb.BlobProperty(compressed=True) |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
69 data['stale_alerts_json'] = True | 70 data['stale_alerts_json'] = True |
70 data['stale_alerts_thresh'] = self.MAX_STALENESS | 71 data['stale_alerts_thresh'] = self.MAX_STALENESS |
71 | 72 |
72 data = self.generate_json_dump(data) | 73 data = self.generate_json_dump(data) |
73 self.send_json_headers() | 74 self.send_json_headers() |
74 self.response.write(data) | 75 self.response.write(data) |
75 return True | 76 return True |
76 | 77 |
77 @staticmethod | 78 @staticmethod |
78 def generate_json_dump(alerts): | 79 def generate_json_dump(alerts): |
79 return json.dumps(alerts, cls=datetime_encoder.DateTimeEncoder, indent=1) | 80 return json.dumps(alerts, cls=utils.DateTimeEncoder, indent=1) |
80 | 81 |
81 @staticmethod | 82 @staticmethod |
82 def get_last_datastore(alerts_type): | 83 def get_last_datastore(alerts_type): |
83 #TODO(stip): rewrite to use hardcoded '-last' key to avoid race condition. | 84 #TODO(stip): rewrite to use hardcoded '-last' key to avoid race condition. |
84 last_query = AlertsJSON.query().filter(AlertsJSON.type == alerts_type) | 85 last_query = AlertsJSON.query().filter(AlertsJSON.type == alerts_type) |
85 return last_query.order(-AlertsJSON.date).get() | 86 return last_query.order(-AlertsJSON.date).get() |
86 | 87 |
87 @staticmethod | 88 @staticmethod |
88 def get_from_gcs(alerts_type, filename): | 89 def get_from_gcs(alerts_type, filename): |
89 with contextlib.closing(gcs.open( | 90 with contextlib.closing(gcs.open( |
(...skipping 27 matching lines...) Expand all Loading... | |
117 def get_from_memcache(self): | 118 def get_from_memcache(self): |
118 compressed = memcache.get(self.ALERT_TYPE) | 119 compressed = memcache.get(self.ALERT_TYPE) |
119 if compressed: | 120 if compressed: |
120 logging.info('Reading alerts from memcache') | 121 logging.info('Reading alerts from memcache') |
121 uncompressed = zlib.decompress(compressed) | 122 uncompressed = zlib.decompress(compressed) |
122 data = json.loads(uncompressed) | 123 data = json.loads(uncompressed) |
123 return data | 124 return data |
124 return False | 125 return False |
125 | 126 |
126 def get(self): | 127 def get(self): |
128 utils.increment_monarch('alerts') | |
127 data = self.get_from_memcache() or self.get_from_datastore() | 129 data = self.get_from_memcache() or self.get_from_datastore() |
128 if data: | 130 if data: |
129 self.send_json_data(data) | 131 self.send_json_data(data) |
130 else: | 132 else: |
131 self.response.write({}) | 133 self.response.write({}) |
132 | 134 |
133 def store_alerts(self, alerts): | 135 def store_alerts(self, alerts): |
134 last_entry = self.get_last_datastore(self.ALERT_TYPE) | 136 last_entry = self.get_last_datastore(self.ALERT_TYPE) |
135 last_alerts = {} | 137 last_alerts = {} |
136 if last_entry: | 138 if last_entry: |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
188 alerts.update({'date': datetime.datetime.utcnow()}) | 190 alerts.update({'date': datetime.datetime.utcnow()}) |
189 self.store_alerts(alerts) | 191 self.store_alerts(alerts) |
190 | 192 |
191 def post(self): | 193 def post(self): |
192 self.update_alerts() | 194 self.update_alerts() |
193 | 195 |
194 | 196 |
195 class NewAlertsHandler(AlertsHandler): | 197 class NewAlertsHandler(AlertsHandler): |
196 # pylint: disable=arguments-differ | 198 # pylint: disable=arguments-differ |
197 def get(self, tree): | 199 def get(self, tree): |
200 utils.increment_monarch('api/v1/alerts') | |
198 self.ALERT_TYPE = 'new-alerts/%s' % tree | 201 self.ALERT_TYPE = 'new-alerts/%s' % tree |
199 super(NewAlertsHandler, self).get() | 202 super(NewAlertsHandler, self).get() |
200 | 203 |
201 # pylint: disable=arguments-differ | 204 # pylint: disable=arguments-differ |
202 def post(self, tree): | 205 def post(self, tree): |
203 self.ALERT_TYPE = 'new-alerts/%s' % tree | 206 self.ALERT_TYPE = 'new-alerts/%s' % tree |
204 super(NewAlertsHandler, self).post() | 207 super(NewAlertsHandler, self).post() |
205 | 208 |
206 | 209 |
207 app = webapp2.WSGIApplication([ | 210 app = webapp2.WSGIApplication([ |
208 ('/alerts', AlertsHandler), | 211 ('/alerts', AlertsHandler), |
209 ('/api/v1/alerts/(.*)', NewAlertsHandler) | 212 ('/api/v1/alerts/(.*)', NewAlertsHandler) |
210 ]) | 213 ]) |
OLD | NEW |