instance_servlet.py revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
1# Copyright 2013 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
5from branch_utility import BranchUtility
6from compiled_file_system import CompiledFileSystem
7from environment import IsDevServer
8from github_file_system_provider import GithubFileSystemProvider
9from host_file_system_provider import HostFileSystemProvider
10from third_party.json_schema_compiler.memoize import memoize
11from render_servlet import RenderServlet
12from object_store_creator import ObjectStoreCreator
13from server_instance import ServerInstance
14from gcs_file_system_provider import CloudStorageFileSystemProvider
15
16class InstanceServletRenderServletDelegate(RenderServlet.Delegate):
17  '''AppEngine instances should never need to call out to SVN. That should only
18  ever be done by the cronjobs, which then write the result into DataStore,
19  which is as far as instances look. To enable this, crons can pass a custom
20  (presumably online) ServerInstance into Get().
21
22  Why? SVN is slow and a bit flaky. Cronjobs failing is annoying but temporary.
23  Instances failing affects users, and is really bad.
24
25  Anyway - to enforce this, we actually don't give instances access to SVN.  If
26  anything is missing from datastore, it'll be a 404. If the cronjobs don't
27  manage to catch everything - uhoh. On the other hand, we'll figure it out
28  pretty soon, and it also means that legitimate 404s are caught before a round
29  trip to SVN.
30  '''
31  def __init__(self, delegate):
32    self._delegate = delegate
33
34  @memoize
35  def CreateServerInstance(self):
36    object_store_creator = ObjectStoreCreator(start_empty=False)
37    branch_utility = self._delegate.CreateBranchUtility(object_store_creator)
38    # In production have offline=True so that we can catch cron errors.  In
39    # development it's annoying to have to run the cron job, so offline=False.
40    host_file_system_provider = self._delegate.CreateHostFileSystemProvider(
41        object_store_creator,
42        offline=not IsDevServer())
43    github_file_system_provider = self._delegate.CreateGithubFileSystemProvider(
44        object_store_creator)
45    return ServerInstance(object_store_creator,
46                          CompiledFileSystem.Factory(object_store_creator),
47                          branch_utility,
48                          host_file_system_provider,
49                          github_file_system_provider,
50                          CloudStorageFileSystemProvider(object_store_creator))
51
52class InstanceServlet(object):
53  '''Servlet for running on normal AppEngine instances.
54  Create this via GetConstructor() so that cache state can be shared amongst
55  them via the memoizing Delegate.
56  '''
57  class Delegate(object):
58    '''Allow runtime dependencies to be overriden for testing.
59    '''
60    def CreateBranchUtility(self, object_store_creator):
61      return BranchUtility.Create(object_store_creator)
62
63    def CreateHostFileSystemProvider(self, object_store_creator, **optargs):
64      return HostFileSystemProvider(object_store_creator, **optargs)
65
66    def CreateGithubFileSystemProvider(self, object_store_creator):
67      return GithubFileSystemProvider(object_store_creator)
68
69  @staticmethod
70  def GetConstructor(delegate_for_test=None):
71    render_servlet_delegate = InstanceServletRenderServletDelegate(
72        delegate_for_test or InstanceServlet.Delegate())
73    return lambda request: RenderServlet(request, render_servlet_delegate)
74
75  # NOTE: if this were a real Servlet it would implement a Get() method, but
76  # GetConstructor returns an appropriate lambda function (Request -> Servlet).
77