Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(26)

Side by Side Diff: appengine/chrome_infra_mon_proxy/main.py

Issue 928043005: Monitoring proxy for time series data (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: More fine-tuning Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 # Copyright 2015 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5 import logging
6 import random
7 import os
8 import time
9 import sys
10 import webapp2
11
12 from protorpc import messages
13 from protorpc import message_types
14 from protorpc import remote
15
16 from google.appengine.api import app_identity, taskqueue
17
18 import admin_handler
19 import common
20
21 BASE_DIR = os.path.dirname(os.path.abspath(__file__))
22 sys.path.insert(0, os.path.join(BASE_DIR, 'components', 'third_party'))
23
24 from components import auth
25
26 VM_MODULES = ['vm1', 'vm2', 'vm3']
ghost stip (do not use) 2015/04/14 00:36:42 oppan dijkstra style: VM_MODULE_COUNT = 3 VM_MODU
Sergey Berezin (google) 2015/04/16 04:39:07 I feel the temptation :-) But this suggests the nu
27
28
29 def is_group_member(group_name):
30 """Skip authorization for dev appserver."""
31 if common.is_development_server():
32 auth_decorator = auth.public
33 else:
34 auth_decorator = auth.require( # pragma: no branch
35 lambda: auth.is_group_member(group_name))
36
37 def decorator(fn):
38 return auth_decorator(fn)
39 return decorator
40
41
42 class NoBackendException(Exception):
43 pass
44
45
46 class LoadBalancer(object):
47 """Balance the load among VM modules.
48
49 TODO(sergeyberezin): take into account health checks on the
50 corresponding NAT boxes. Specifically, fetch the health status
51 from the datastore in __init__(), and update it periodically as needed.
52 """
53 def __init__(self):
54 # dict: module name -> bool: whether module is healthy.
55 self._health = {module: True for module in VM_MODULES}
56 # Seconds since UNIX epoch when last health check was made.
ghost stip (do not use) 2015/04/14 00:36:42 probably want to remove now until we figure out ho
Sergey Berezin (google) 2015/04/16 04:39:07 Done.
57 self._last_health_check = 0
58
59 def _healthy_modules(self):
60 """Return the list of names of all healthy modules."""
61 # TODO(sergeyberezin): perform health checks and update the
62 # datastore once in a while.
63 return [module for module in VM_MODULES if self._health[module]]
64
65 def choose_module(self):
66 """Select a module to send the data to."""
67 modules = self._healthy_modules()
68 if not modules:
69 raise NoBackendException('Error: no healthy backends are available')
70 return random.randint(0, len(modules)-1)
ghost stip (do not use) 2015/04/14 00:36:42 return random.choice(modules)
Sergey Berezin (google) 2015/04/16 04:39:06 Done. Nice, thanks!
71
72
73 def forward_data(data):
74 """Forwards the raw data to the backend."""
75 # logging.debug('Forwarding data: %s', common.payload_stats(data))
ghost stip (do not use) 2015/04/14 00:36:42 why commented out? seems legit
Sergey Berezin (google) 2015/04/16 04:39:06 It computes md5, and now that I debugged the heade
76 # Task queue should work correctly both in dev and prod server.
77 lb = LoadBalancer()
78 queue_name = VM_MODULES[lb.choose_module()]
ghost stip (do not use) 2015/04/14 00:36:42 queue_name = lb.choose_module()
Sergey Berezin (google) 2015/04/16 04:39:07 Done.
79 logging.info('Selected queue: %s', queue_name)
80 taskqueue.add(url='/vm', payload=data, queue_name=queue_name)
81
82
83 class MonacqHandler(auth.AuthenticatingHandler):
84 # Disable XSRF in local dev appserver; otherwise requests will fail.
85 if common.is_development_server():
86 xsrf_token_enforce_on = [] # pragma: no cover
ghost stip (do not use) 2015/04/14 00:36:43 nit: two spaces before comment
Sergey Berezin (google) 2015/04/16 04:39:07 Done.
87
88 @is_group_member('service-account-monitoring-proxy')
89 def get(self):
90 self.response.headers.add_header('Content-Type', 'text/plain')
91 self.response.write('GET requests are not allowed.')
ghost stip (do not use) 2015/04/14 00:36:42 I think if you don't provide a get function to beg
Sergey Berezin (google) 2015/04/16 04:39:06 Indeed - removed.
92 self.response.set_status(403)
ghost stip (do not use) 2015/04/14 00:36:42 at least make it 405
Sergey Berezin (google) 2015/04/16 04:39:07 N/A - removed def get().
93 return
94
95 @is_group_member('service-account-monitoring-proxy')
96 def post(self):
97 # logging.info('Received POST /monacq: %s',
98 # common.payload_stats(self.request.body))
99 forward_data(self.request.body)
100
101
102 class MainHandler(webapp2.RequestHandler):
103 def get(self):
104 # TODO(sergeyberezin): create a meaningful welcome page with some
105 # documentation.
106 msg = 'There is nothing here yet.\n'
ghost stip (do not use) 2015/04/14 00:36:42 make this a little more friendly! msg = 'Welcome
Sergey Berezin (google) 2015/04/16 04:39:06 Done - created an actual page with some useful con
107 self.response.headers['Content-Type'] = 'text/plain'
ghost stip (do not use) 2015/04/14 00:36:42 is this needed?
Sergey Berezin (google) 2015/04/16 04:39:07 Nope - it's all gone now.
108 self.response.out.write(msg)
109
110
111
112 logging.basicConfig(level=logging.DEBUG)
113
114 main_handlers = [
115 (r'/', MainHandler),
116 (r'/monacq', MonacqHandler),
117 (r'/admin/(.*)', admin_handler.AdminDispatch),
118 ]
119
120 app = webapp2.WSGIApplication(main_handlers, debug=True)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698