Chromium Code Reviews| 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 from appengine_wrappers import taskqueue | 5 import json |
| 6 import logging | |
| 7 | |
| 8 from appengine_wrappers import memcache | |
| 6 from commit_tracker import CommitTracker | 9 from commit_tracker import CommitTracker |
| 10 from environment import IsDevServer | |
| 11 from environment_wrappers import CreateUrlFetcher | |
| 7 from future import All | 12 from future import All |
| 8 from object_store_creator import ObjectStoreCreator | 13 from object_store_creator import ObjectStoreCreator |
| 9 from refresh_tracker import RefreshTracker | |
| 10 from servlet import Servlet, Response | 14 from servlet import Servlet, Response |
| 11 | 15 |
| 12 | 16 |
| 13 class EnqueueServlet(Servlet): | 17 _SERVICE_ACCOUNT_NAME = '636061184119-compute@developer.gserviceaccount.com' |
| 14 '''This Servlet can be used to manually enqueue tasks on the default | 18 _ACCOUNT_INFO_URL = ('https://www.googleapis.com/oauth2/v1/userinfo?' |
| 15 taskqueue. Useful for when an admin wants to manually force a specific | 19 'access_token=%s') |
| 16 DataSource refresh, but the refresh operation takes longer than the 60 sec | |
| 17 timeout of a non-taskqueue request. For example, you might query | |
| 18 | |
| 19 /_enqueue/_refresh/content_providers/cr-native-client?commit=123ff65468dcafff0 | |
| 20 | |
| 21 which will enqueue a task (/_refresh/content_providers/cr-native-client) to | |
| 22 refresh the NaCl documentation cache for commit 123ff65468dcafff0. | |
| 23 | |
| 24 Access to this servlet should always be restricted to administrative users. | |
| 25 ''' | |
| 26 def __init__(self, request): | |
| 27 Servlet.__init__(self, request) | |
| 28 | |
| 29 def Get(self): | |
| 30 queue = taskqueue.Queue() | |
| 31 queue.add(taskqueue.Task(url='/%s' % self._request.path, | |
| 32 params=self._request.arguments)) | |
| 33 return Response.Ok('Task enqueued.') | |
| 34 | 20 |
| 35 | 21 |
| 36 class QueryCommitServlet(Servlet): | 22 class QueryCommitServlet(Servlet): |
| 37 '''Provides read access to the commit ID cache within the server. For example: | 23 '''Provides read access to the commit ID cache within the server. For example: |
| 38 | 24 |
| 39 /_query_commit/master | 25 /_query_commit/master |
| 40 | 26 |
| 41 will return the commit ID stored under the commit key "master" within the | 27 will return the commit ID stored under the commit key "master" within the |
| 42 commit cache. Currently "master" is the only named commit we cache, and it | 28 commit cache. Currently "master" is the only named commit we cache, and it |
| 43 corresponds to the commit ID whose data currently populates the data cache | 29 corresponds to the commit ID whose data currently populates the data cache |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 58 commit_id, history_log) | 44 commit_id, history_log) |
| 59 return response | 45 return response |
| 60 | 46 |
| 61 commit_name = self._request.path | 47 commit_name = self._request.path |
| 62 id_future = commit_tracker.Get(commit_name) | 48 id_future = commit_tracker.Get(commit_name) |
| 63 history_future = commit_tracker.GetHistory(commit_name) | 49 history_future = commit_tracker.GetHistory(commit_name) |
| 64 return Response.Ok( | 50 return Response.Ok( |
| 65 All((id_future, history_future)).Then(generate_response).Get()) | 51 All((id_future, history_future)).Then(generate_response).Get()) |
| 66 | 52 |
| 67 | 53 |
| 68 class DumpRefreshServlet(Servlet): | 54 class FlushMemcacheServlet(Servlet): |
|
Ken Rockot(use gerrit already)
2015/05/26 00:26:22
This is necessary since we're pushing stuff into t
| |
| 69 def __init__(self, request): | 55 '''Flushes the entire memcache. |
| 70 Servlet.__init__(self, request) | |
| 71 | 56 |
| 72 def Get(self): | 57 This requires an access token for the project's main service account. Without |
| 73 object_store_creator = ObjectStoreCreator(start_empty=False) | 58 said token, the request is considered invalid. |
| 74 refresh_tracker = RefreshTracker(object_store_creator) | |
| 75 commit_id = self._request.path | |
| 76 work_order = refresh_tracker._GetWorkOrder(commit_id).Get() | |
| 77 task_names = ['%s@%s' % (commit_id, task) for task in work_order.tasks] | |
| 78 completions = refresh_tracker._task_completions.GetMulti(task_names).Get() | |
| 79 missing = [] | |
| 80 for task in task_names: | |
| 81 if task not in completions: | |
| 82 missing.append(task) | |
| 83 response = 'Missing:<br>%s' % ''.join('%s<br>' % task for task in missing) | |
| 84 return Response.Ok(response) | |
| 85 | |
| 86 class ResetCommitServlet(Servlet): | |
| 87 '''Writes a new commit ID to the commit cache. For example: | |
| 88 | |
| 89 /_reset_commit/master/123456 | |
| 90 | |
| 91 will reset the 'master' commit ID to '123456'. The provided commit MUST be | |
| 92 in the named commit's recent history or it will be ignored. | |
| 93 ''' | 59 ''' |
| 94 | 60 |
| 95 class Delegate(object): | 61 class Delegate(object): |
| 96 def CreateCommitTracker(self): | 62 def IsAuthorized(self, access_token): |
| 97 return CommitTracker(ObjectStoreCreator(start_empty=False)) | 63 '''Verifies that a given access_token represents the main service account. |
| 64 ''' | |
| 65 fetcher = CreateUrlFetcher() | |
| 66 response = fetcher.Fetch(_ACCOUNT_INFO_URL % access_token) | |
| 67 if response.status_code != 200: | |
| 68 return False | |
| 69 try: | |
| 70 info = json.loads(response.content) | |
| 71 except: | |
| 72 return False | |
| 73 return info['email'] == _SERVICE_ACCOUNT_NAME | |
| 98 | 74 |
| 99 def __init__(self, request, delegate=Delegate()): | 75 def __init__(self, request, delegate=Delegate()): |
| 100 Servlet.__init__(self, request) | 76 Servlet.__init__(self, request) |
| 101 self._delegate = delegate | 77 self._delegate = delegate |
| 102 | 78 |
| 79 def GetAccessToken(self): | |
| 80 auth_header = self._request.headers.get('Authorization') | |
| 81 if not auth_header: | |
| 82 return None | |
| 83 try: | |
| 84 method, token = auth_header.split(' ', 1) | |
| 85 except: | |
| 86 return None | |
| 87 if method != 'Bearer': | |
| 88 return None | |
| 89 return token | |
| 90 | |
| 103 def Get(self): | 91 def Get(self): |
| 104 commit_tracker = self._delegate.CreateCommitTracker() | 92 access_token = self.GetAccessToken() |
| 105 commit_name, commit_id = self._request.path.split('/', 1) | 93 if not access_token: |
| 106 history = commit_tracker.GetHistory(commit_name).Get() | 94 return Response.Unauthorized('Unauthorized', 'Bearer', 'update') |
| 107 if not any(entry.commit_id == commit_id for entry in history): | 95 if not self._delegate.IsAuthorized(access_token): |
| 108 return Response.BadRequest('Commit %s not cached.' % commit_id) | 96 return Response.Forbidden('Forbidden') |
| 109 commit_tracker.Set(commit_name, commit_id).Get() | 97 result = memcache.flush_all() |
| 110 return Response.Ok('Commit "%s" updated to %s' % (commit_name, commit_id)) | 98 return Response.Ok('Flushed: %s' % result) |
| 111 | 99 |
| 100 | |
| 101 class UpdateCacheServlet(Servlet): | |
| 102 '''Devserver-only servlet for pushing local file data into the datastore. | |
|
Ken Rockot(use gerrit already)
2015/05/26 00:26:22
Unfortunately the AppEngine sandbox, even on dev_s
| |
| 103 This is useful if you've used update_cache.py to build a local datastore | |
| 104 for testing. Query: | |
| 105 | |
| 106 /_update_cache/FOO_DATA | |
| 107 | |
| 108 to make the devserver read FOO_DATA from its pwd and push all the data into | |
| 109 datastore. | |
| 110 ''' | |
| 111 def __init__(self, request): | |
| 112 Servlet.__init__(self, request) | |
| 113 | |
| 114 def Get(self): | |
| 115 if not IsDevServer(): | |
| 116 return Response.BadRequest('') | |
| 117 import cPickle | |
| 118 from persistent_object_store_appengine import PersistentObjectStoreAppengine | |
| 119 with open(self._request.path, 'r') as f: | |
| 120 data = cPickle.load(f) | |
| 121 for namespace, contents in data.iteritems(): | |
| 122 store = PersistentObjectStoreAppengine(namespace) | |
| 123 for k, v in cPickle.loads(contents).iteritems(): | |
| 124 try: | |
| 125 store.Set(k, v).Get() | |
| 126 except: | |
| 127 logging.warn('Skipping entry %s because of errors.' % k) | |
| 128 return Response.Ok('Data pushed!') | |
| OLD | NEW |