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 traceback | 5 import traceback |
6 | 6 |
7 from app_yaml_helper import AppYamlHelper | 7 from app_yaml_helper import AppYamlHelper |
8 from appengine_wrappers import IsDeadlineExceededError, logservice | 8 from appengine_wrappers import IsDeadlineExceededError, logservice, taskqueue |
9 from branch_utility import BranchUtility | 9 from branch_utility import BranchUtility |
| 10 from commit_tracker import CommitTracker |
10 from compiled_file_system import CompiledFileSystem | 11 from compiled_file_system import CompiledFileSystem |
11 from custom_logger import CustomLogger | 12 from custom_logger import CustomLogger |
12 from data_source_registry import CreateDataSource | 13 from data_source_registry import CreateDataSource |
13 from environment import GetAppVersion | 14 from environment import GetAppVersion |
14 from file_system import IsFileSystemThrottledError | 15 from file_system import IsFileSystemThrottledError |
15 from future import Future | 16 from future import Future |
16 from gcs_file_system_provider import CloudStorageFileSystemProvider | 17 from gcs_file_system_provider import CloudStorageFileSystemProvider |
17 from github_file_system_provider import GithubFileSystemProvider | 18 from github_file_system_provider import GithubFileSystemProvider |
18 from host_file_system_provider import HostFileSystemProvider | 19 from host_file_system_provider import HostFileSystemProvider |
19 from object_store_creator import ObjectStoreCreator | 20 from object_store_creator import ObjectStoreCreator |
| 21 from refresh_tracker import RefreshTracker |
20 from server_instance import ServerInstance | 22 from server_instance import ServerInstance |
21 from servlet import Servlet, Request, Response | 23 from servlet import Servlet, Request, Response |
22 from timer import Timer, TimerClosure | 24 from timer import Timer, TimerClosure |
23 | 25 |
24 | 26 |
| 27 _log = CustomLogger('refresh') |
25 | 28 |
26 _log = CustomLogger('refresh') | 29 |
| 30 def _UpdateMasterCommit(object_store_creator, commit): |
| 31 commit_tracker = CommitTracker(object_store_creator) |
| 32 return commit_tracker.Set('master', commit) |
27 | 33 |
28 | 34 |
29 class RefreshServlet(Servlet): | 35 class RefreshServlet(Servlet): |
30 '''Servlet which refreshes a single data source. | 36 '''Servlet which refreshes a single data source. |
31 ''' | 37 ''' |
32 def __init__(self, request, delegate_for_test=None): | 38 def __init__(self, request, delegate_for_test=None): |
33 Servlet.__init__(self, request) | 39 Servlet.__init__(self, request) |
34 self._delegate = delegate_for_test or RefreshServlet.Delegate() | 40 self._delegate = delegate_for_test or RefreshServlet.Delegate() |
35 | 41 |
36 class Delegate(object): | 42 class Delegate(object): |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
79 (source_name, '' if source_path is None else '[%s]' % source_path)) | 85 (source_name, '' if source_path is None else '[%s]' % source_path)) |
80 | 86 |
81 if 'commit' in self._request.arguments: | 87 if 'commit' in self._request.arguments: |
82 commit = self._request.arguments['commit'] | 88 commit = self._request.arguments['commit'] |
83 else: | 89 else: |
84 _log.warning('No commit given; refreshing from master. ' | 90 _log.warning('No commit given; refreshing from master. ' |
85 'This is probably NOT what you want.') | 91 'This is probably NOT what you want.') |
86 commit = None | 92 commit = None |
87 | 93 |
88 server_instance = self._CreateServerInstance(commit) | 94 server_instance = self._CreateServerInstance(commit) |
| 95 refresh_tracker = RefreshTracker(server_instance.object_store_creator) |
| 96 |
89 success = True | 97 success = True |
| 98 success_message = 'Success' |
90 try: | 99 try: |
91 if source_name == 'platform_bundle': | 100 if source_name == 'platform_bundle': |
92 data_source = server_instance.platform_bundle | 101 data_source = server_instance.platform_bundle |
93 elif source_name == 'content_providers': | 102 elif source_name == 'content_providers': |
94 data_source = server_instance.content_providers | 103 data_source = server_instance.content_providers |
| 104 elif source_name == 'instance_master': |
| 105 data_source = _InstanceMasterCommitUpdater(commit) |
95 else: | 106 else: |
96 data_source = CreateDataSource(source_name, server_instance) | 107 data_source = CreateDataSource(source_name, server_instance) |
97 | 108 |
| 109 # If the data source defines subtasks and none was provided, do the nice |
| 110 # thing and queue up the defined subtasks instead of just failing. |
| 111 if source_path is None: |
| 112 refresh_paths = data_source.GetRefreshPaths() |
| 113 if len(refresh_paths) > 1: |
| 114 queue = taskqueue.Queue() |
| 115 tasks = ['/_refresh/%s/%s' % (source_name, path) |
| 116 for path in refresh_paths] |
| 117 for task in tasks: |
| 118 queue.add(taskqueue.Task(url=task, params={'commit': commit})) |
| 119 success_message = 'Enqueued tasks: %s' % tasks |
| 120 # The finally clause really handles the return. |
| 121 return |
| 122 |
98 class_name = data_source.__class__.__name__ | 123 class_name = data_source.__class__.__name__ |
99 refresh_future = data_source.Refresh(source_path) | 124 refresh_future = data_source.Refresh(source_path) |
100 assert isinstance(refresh_future, Future), ( | 125 assert isinstance(refresh_future, Future), ( |
101 '%s.Refresh() did not return a Future' % class_name) | 126 '%s.Refresh() did not return a Future' % class_name) |
102 timer = Timer() | 127 timer = Timer() |
103 try: | 128 try: |
104 refresh_future.Get() | 129 refresh_future.Get() |
| 130 |
| 131 def resolve(refresh_complete): |
| 132 if refresh_complete: |
| 133 return _UpdateMasterCommit( |
| 134 server_instance.object_store_creator, commit) |
| 135 return None |
| 136 refresh_tracker.MarkTaskComplete(commit, '_refresh/%s/%s' % ( |
| 137 source_name, path)).Get() |
| 138 refresh_tracker.GetRefreshComplete(commit).Then(resolve).Get() |
105 except Exception as e: | 139 except Exception as e: |
106 _log.error('%s: error %s' % (class_name, traceback.format_exc())) | 140 _log.error('%s: error %s' % (class_name, traceback.format_exc())) |
107 success = False | 141 success = False |
108 if IsFileSystemThrottledError(e): | 142 if IsFileSystemThrottledError(e): |
109 return Response.ThrottledError('Throttled') | 143 return Response.ThrottledError('Throttled') |
110 raise | 144 raise |
111 finally: | 145 finally: |
112 _log.info('Refreshing %s took %s' % | 146 _log.info('Refreshing %s took %s' % |
113 (class_name, timer.Stop().FormatElapsed())) | 147 (class_name, timer.Stop().FormatElapsed())) |
114 | 148 |
115 except: | 149 except: |
116 success = False | 150 success = False |
117 # This should never actually happen. | 151 # This should never actually happen. |
118 _log.error('uncaught error: %s' % traceback.format_exc()) | 152 _log.error('uncaught error: %s' % traceback.format_exc()) |
119 raise | 153 raise |
120 finally: | 154 finally: |
121 _log.info('finished (%s)', 'success' if success else 'FAILED') | 155 _log.info('finished (%s)', 'success' if success else 'FAILED') |
122 return (Response.Ok('Success') if success else | 156 return (Response.Ok(success_message) if success else |
123 Response.InternalError('Failure')) | 157 Response.InternalError('Failure')) |
124 | 158 |
125 def _CreateServerInstance(self, commit): | 159 def _CreateServerInstance(self, commit): |
126 '''Creates a ServerInstance pinned to |commit|, or HEAD if None. | 160 '''Creates a ServerInstance pinned to |commit|, or HEAD if None. |
127 NOTE: If passed None it's likely that during the cron run patches will be | 161 NOTE: If passed None it's likely that during the cron run patches will be |
128 submitted at HEAD, which may change data underneath the cron run. | 162 submitted at HEAD, which may change data underneath the cron run. |
129 ''' | 163 ''' |
130 object_store_creator = ObjectStoreCreator(start_empty=True) | 164 object_store_creator = ObjectStoreCreator(start_empty=True) |
131 branch_utility = self._delegate.CreateBranchUtility(object_store_creator) | 165 branch_utility = self._delegate.CreateBranchUtility(object_store_creator) |
132 host_file_system_provider = self._delegate.CreateHostFileSystemProvider( | 166 host_file_system_provider = self._delegate.CreateHostFileSystemProvider( |
133 object_store_creator, pinned_commit=commit) | 167 object_store_creator, pinned_commit=commit) |
134 github_file_system_provider = self._delegate.CreateGithubFileSystemProvider( | 168 github_file_system_provider = self._delegate.CreateGithubFileSystemProvider( |
135 object_store_creator) | 169 object_store_creator) |
136 gcs_file_system_provider = self._delegate.CreateGCSFileSystemProvider( | 170 gcs_file_system_provider = self._delegate.CreateGCSFileSystemProvider( |
137 object_store_creator) | 171 object_store_creator) |
138 return ServerInstance(object_store_creator, | 172 return ServerInstance(object_store_creator, |
139 CompiledFileSystem.Factory(object_store_creator), | 173 CompiledFileSystem.Factory(object_store_creator), |
140 branch_utility, | 174 branch_utility, |
141 host_file_system_provider, | 175 host_file_system_provider, |
142 github_file_system_provider, | 176 github_file_system_provider, |
143 gcs_file_system_provider) | 177 gcs_file_system_provider) |
OLD | NEW |