blob: 4e0a838a8bcb86ce177e0508688297bed8aa7436 [file] [log] [blame]
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import json
import logging
from appengine_wrappers import memcache
from commit_tracker import CommitTracker
from environment import IsDevServer
from environment_wrappers import CreateUrlFetcher
from future import All
from object_store_creator import ObjectStoreCreator
from servlet import Servlet, Response
# This is the service account ID associated with the chrome-apps-doc project in
# the Google Developers Console.
_SERVICE_ACCOUNT_NAME = '636061184119-compute@developer.gserviceaccount.com'
# This is Google's OAuth2 service for retrieving user information from an access
# token. It is used to authenticate an incoming access token in the metadata
# flush servlet, ensuring that only requests from the above service account are
# fulfilled.
_ACCOUNT_INFO_URL = ('https://www.googleapis.com/oauth2/v1/userinfo?'
'access_token=%s')
class QueryCommitServlet(Servlet):
'''Provides read access to the commit ID cache within the server. For example:
/_query_commit/master
will return the commit ID stored under the commit key "master" within the
commit cache. Currently "master" is the only named commit we cache, and it
corresponds to the commit ID whose data currently populates the data cache
used by live instances.
'''
def __init__(self, request):
Servlet.__init__(self, request)
def Get(self):
object_store_creator = ObjectStoreCreator(start_empty=False)
commit_tracker = CommitTracker(object_store_creator)
def generate_response(result):
commit_id, history = result
history_log = ''.join('%s: %s<br>' % (entry.datetime, entry.commit_id)
for entry in reversed(history))
response = 'Current commit: %s<br><br>Most recent commits:<br>%s' % (
commit_id, history_log)
return response
commit_name = self._request.path
id_future = commit_tracker.Get(commit_name)
history_future = commit_tracker.GetHistory(commit_name)
return Response.Ok(
All((id_future, history_future)).Then(generate_response).Get())
class FlushMemcacheServlet(Servlet):
'''Flushes the entire memcache.
This requires an access token for the project's main service account. Without
said token, the request is considered invalid.
'''
class Delegate(object):
def IsAuthorized(self, access_token):
'''Verifies that a given access_token represents the main service account.
'''
fetcher = CreateUrlFetcher()
response = fetcher.Fetch(_ACCOUNT_INFO_URL % access_token)
if response.status_code != 200:
return False
try:
info = json.loads(response.content)
except:
return False
return info['email'] == _SERVICE_ACCOUNT_NAME
def __init__(self, request, delegate=Delegate()):
Servlet.__init__(self, request)
self._delegate = delegate
def GetAccessToken(self):
auth_header = self._request.headers.get('Authorization')
if not auth_header:
return None
try:
method, token = auth_header.split(' ', 1)
except:
return None
if method != 'Bearer':
return None
return token
def Get(self):
access_token = self.GetAccessToken()
if not access_token:
return Response.Unauthorized('Unauthorized', 'Bearer', 'update')
if not self._delegate.IsAuthorized(access_token):
return Response.Forbidden('Forbidden')
result = memcache.flush_all()
return Response.Ok('Flushed: %s' % result)
class UpdateCacheServlet(Servlet):
'''Devserver-only servlet for pushing local file data into the datastore.
This is useful if you've used update_cache.py to build a local datastore
for testing. Query:
/_update_cache/FOO_DATA
to make the devserver read FOO_DATA from its pwd and push all the data into
datastore.
'''
def __init__(self, request):
Servlet.__init__(self, request)
def Get(self):
if not IsDevServer():
return Response.BadRequest('')
import cPickle
from persistent_object_store_appengine import PersistentObjectStoreAppengine
with open(self._request.path, 'r') as f:
data = cPickle.load(f)
for namespace, contents in data.iteritems():
store = PersistentObjectStoreAppengine(namespace)
for k, v in cPickle.loads(contents).iteritems():
try:
store.Set(k, v).Get()
except:
logging.warn('Skipping entry %s because of errors.' % k)
return Response.Ok('Data pushed!')