Home | History | Annotate | Download | only in server2
      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.
      4 
      5 import traceback
      6 
      7 from app_yaml_helper import AppYamlHelper
      8 from appengine_wrappers import IsDeadlineExceededError, logservice
      9 from branch_utility import BranchUtility
     10 from compiled_file_system import CompiledFileSystem
     11 from custom_logger import CustomLogger
     12 from data_source_registry import CreateDataSource
     13 from environment import GetAppVersion
     14 from file_system import IsFileSystemThrottledError
     15 from future import Future
     16 from gcs_file_system_provider import CloudStorageFileSystemProvider
     17 from github_file_system_provider import GithubFileSystemProvider
     18 from host_file_system_provider import HostFileSystemProvider
     19 from object_store_creator import ObjectStoreCreator
     20 from server_instance import ServerInstance
     21 from servlet import Servlet, Request, Response
     22 from timer import Timer, TimerClosure
     23 
     24 
     25 
     26 _log = CustomLogger('refresh')
     27 
     28 
     29 class RefreshServlet(Servlet):
     30   '''Servlet which refreshes a single data source.
     31   '''
     32   def __init__(self, request, delegate_for_test=None):
     33     Servlet.__init__(self, request)
     34     self._delegate = delegate_for_test or RefreshServlet.Delegate()
     35 
     36   class Delegate(object):
     37     '''RefreshServlet's runtime dependencies. Override for testing.
     38     '''
     39     def CreateBranchUtility(self, object_store_creator):
     40       return BranchUtility.Create(object_store_creator)
     41 
     42     def CreateHostFileSystemProvider(self,
     43                                      object_store_creator,
     44                                      pinned_commit=None):
     45       return HostFileSystemProvider(object_store_creator,
     46                                     pinned_commit=pinned_commit)
     47 
     48     def CreateGithubFileSystemProvider(self, object_store_creator):
     49       return GithubFileSystemProvider(object_store_creator)
     50 
     51     def CreateGCSFileSystemProvider(self, object_store_creator):
     52       return CloudStorageFileSystemProvider(object_store_creator)
     53 
     54     def GetAppVersion(self):
     55       return GetAppVersion()
     56 
     57   def Get(self):
     58     # Manually flush logs at the end of the run. However, sometimes
     59     # even that isn't enough, which is why in this file we use the
     60     # custom logger and make it flush the log every time its used.
     61     logservice.AUTOFLUSH_ENABLED = False
     62     try:
     63       return self._GetImpl()
     64     except BaseException:
     65       _log.error('Caught top-level exception! %s', traceback.format_exc())
     66     finally:
     67       logservice.flush()
     68 
     69   def _GetImpl(self):
     70     path = self._request.path.strip('/')
     71     parts = self._request.path.split('/', 1)
     72     source_name = parts[0]
     73     if len(parts) == 2:
     74       source_path = parts[1]
     75     else:
     76       source_path = None
     77 
     78     _log.info('starting refresh of %s DataSource %s' %
     79         (source_name, '' if source_path is None else '[%s]' % source_path))
     80 
     81     if 'commit' in self._request.arguments:
     82       commit = self._request.arguments['commit']
     83     else:
     84       _log.warning('No commit given; refreshing from master. '
     85                    'This is probably NOT what you want.')
     86       commit = None
     87 
     88     server_instance = self._CreateServerInstance(commit)
     89     success = True
     90     try:
     91       if source_name == 'platform_bundle':
     92         data_source = server_instance.platform_bundle
     93       elif source_name == 'content_providers':
     94         data_source = server_instance.content_providers
     95       else:
     96         data_source = CreateDataSource(source_name, server_instance)
     97 
     98       class_name = data_source.__class__.__name__
     99       refresh_future = data_source.Refresh(source_path)
    100       assert isinstance(refresh_future, Future), (
    101           '%s.Refresh() did not return a Future' % class_name)
    102       timer = Timer()
    103       try:
    104         refresh_future.Get()
    105       except Exception as e:
    106         _log.error('%s: error %s' % (class_name, traceback.format_exc()))
    107         success = False
    108         if IsFileSystemThrottledError(e):
    109           return Response.ThrottledError('Throttled')
    110         raise
    111       finally:
    112         _log.info('Refreshing %s took %s' %
    113             (class_name, timer.Stop().FormatElapsed()))
    114 
    115     except:
    116       success = False
    117       # This should never actually happen.
    118       _log.error('uncaught error: %s' % traceback.format_exc())
    119       raise
    120     finally:
    121       _log.info('finished (%s)', 'success' if success else 'FAILED')
    122       return (Response.Ok('Success') if success else
    123               Response.InternalError('Failure'))
    124 
    125   def _CreateServerInstance(self, commit):
    126     '''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
    128     submitted at HEAD, which may change data underneath the cron run.
    129     '''
    130     object_store_creator = ObjectStoreCreator(start_empty=True)
    131     branch_utility = self._delegate.CreateBranchUtility(object_store_creator)
    132     host_file_system_provider = self._delegate.CreateHostFileSystemProvider(
    133         object_store_creator, pinned_commit=commit)
    134     github_file_system_provider = self._delegate.CreateGithubFileSystemProvider(
    135         object_store_creator)
    136     gcs_file_system_provider = self._delegate.CreateGCSFileSystemProvider(
    137         object_store_creator)
    138     return ServerInstance(object_store_creator,
    139                           CompiledFileSystem.Factory(object_store_creator),
    140                           branch_utility,
    141                           host_file_system_provider,
    142                           github_file_system_provider,
    143                           gcs_file_system_provider)
    144