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
3 # found in the LICENSE file.
8 from appengine_wrappers
import memcache
9 from commit_tracker
import CommitTracker
10 from environment
import IsDevServer
11 from environment_wrappers
import CreateUrlFetcher
12 from future
import All
13 from object_store_creator
import ObjectStoreCreator
14 from servlet
import Servlet
, Response
17 # This is the service account ID associated with the chrome-apps-doc project in
18 # the Google Developers Console.
19 _SERVICE_ACCOUNT_NAME
= '636061184119-compute@developer.gserviceaccount.com'
21 # This is Google's OAuth2 service for retrieving user information from an access
22 # token. It is used to authenticate an incoming access token in the metadata
23 # flush servlet, ensuring that only requests from the above service account are
25 _ACCOUNT_INFO_URL
= ('https://www.googleapis.com/oauth2/v1/userinfo?'
29 class QueryCommitServlet(Servlet
):
30 '''Provides read access to the commit ID cache within the server. For example:
34 will return the commit ID stored under the commit key "master" within the
35 commit cache. Currently "master" is the only named commit we cache, and it
36 corresponds to the commit ID whose data currently populates the data cache
37 used by live instances.
39 def __init__(self
, request
):
40 Servlet
.__init
__(self
, request
)
43 object_store_creator
= ObjectStoreCreator(start_empty
=False)
44 commit_tracker
= CommitTracker(object_store_creator
)
46 def generate_response(result
):
47 commit_id
, history
= result
48 history_log
= ''.join('%s: %s<br>' % (entry
.datetime
, entry
.commit_id
)
49 for entry
in reversed(history
))
50 response
= 'Current commit: %s<br><br>Most recent commits:<br>%s' % (
51 commit_id
, history_log
)
54 commit_name
= self
._request
.path
55 id_future
= commit_tracker
.Get(commit_name
)
56 history_future
= commit_tracker
.GetHistory(commit_name
)
58 All((id_future
, history_future
)).Then(generate_response
).Get())
61 class FlushMemcacheServlet(Servlet
):
62 '''Flushes the entire memcache.
64 This requires an access token for the project's main service account. Without
65 said token, the request is considered invalid.
68 class Delegate(object):
69 def IsAuthorized(self
, access_token
):
70 '''Verifies that a given access_token represents the main service account.
72 fetcher
= CreateUrlFetcher()
73 response
= fetcher
.Fetch(_ACCOUNT_INFO_URL
% access_token
)
74 if response
.status_code
!= 200:
77 info
= json
.loads(response
.content
)
80 return info
['email'] == _SERVICE_ACCOUNT_NAME
82 def __init__(self
, request
, delegate
=Delegate()):
83 Servlet
.__init
__(self
, request
)
84 self
._delegate
= delegate
86 def GetAccessToken(self
):
87 auth_header
= self
._request
.headers
.get('Authorization')
91 method
, token
= auth_header
.split(' ', 1)
94 if method
!= 'Bearer':
99 access_token
= self
.GetAccessToken()
101 return Response
.Unauthorized('Unauthorized', 'Bearer', 'update')
102 if not self
._delegate
.IsAuthorized(access_token
):
103 return Response
.Forbidden('Forbidden')
104 result
= memcache
.flush_all()
105 return Response
.Ok('Flushed: %s' % result
)
108 class UpdateCacheServlet(Servlet
):
109 '''Devserver-only servlet for pushing local file data into the datastore.
110 This is useful if you've used update_cache.py to build a local datastore
113 /_update_cache/FOO_DATA
115 to make the devserver read FOO_DATA from its pwd and push all the data into
118 def __init__(self
, request
):
119 Servlet
.__init
__(self
, request
)
122 if not IsDevServer():
123 return Response
.BadRequest('')
125 from persistent_object_store_appengine
import PersistentObjectStoreAppengine
126 with
open(self
._request
.path
, 'r') as f
:
127 data
= cPickle
.load(f
)
128 for namespace
, contents
in data
.iteritems():
129 store
= PersistentObjectStoreAppengine(namespace
)
130 for k
, v
in cPickle
.loads(contents
).iteritems():
132 store
.Set(k
, v
).Get()
134 logging
.warn('Skipping entry %s because of errors.' % k
)
135 return Response
.Ok('Data pushed!')