autoupdate.py: Deprecate autoupdate.py

This mechanism is not used in the lab anymore and has been replaced by
gs_cache/nebraska_wrapper.py in crrev.com/c/2258234.

BUG=chromium:1078188
TEST=./devserver_integration_test.py

Change-Id: Ifa007df983aab49c808360df6ba0b62b7031221c
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/dev-util/+/2486466
Tested-by: Amin Hassani <ahassani@chromium.org>
Commit-Queue: Amin Hassani <ahassani@chromium.org>
Reviewed-by: Jae Hoon Kim <kimjae@chromium.org>
diff --git a/Makefile b/Makefile
index e584dcc..fe2f97c 100644
--- a/Makefile
+++ b/Makefile
@@ -14,7 +14,6 @@
 	install -m 0755 host/start_devserver "${DESTDIR}/usr/bin"
 	install -m 0755 devserver.py strip_package.py "${DESTDIR}/usr/lib/devserver"
 	install -m 0644  \
-		autoupdate.py \
 		builder.py \
 		cherrypy_ext.py \
 		health_checker.py \
diff --git a/autoupdate.py b/autoupdate.py
deleted file mode 100644
index 88def64..0000000
--- a/autoupdate.py
+++ /dev/null
@@ -1,207 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Devserver module for handling update client requests."""
-
-from __future__ import print_function
-
-import os
-
-from six.moves import urllib
-
-import cherrypy  # pylint: disable=import-error
-
-# TODO(crbug.com/872441): We try to import nebraska from different places
-# because when we install the devserver, we copy the nebraska.py into the main
-# directory. Once this bug is resolved, we can always import from nebraska
-# directory.
-try:
-  from nebraska import nebraska
-except ImportError:
-  import nebraska
-
-import setup_chromite  # pylint: disable=unused-import
-from chromite.lib.xbuddy import cherrypy_log_util
-from chromite.lib.xbuddy import devserver_constants as constants
-
-
-# Module-local log function.
-def _Log(message, *args):
-  return cherrypy_log_util.LogWithTag('UPDATE', message, *args)
-
-class AutoupdateError(Exception):
-  """Exception classes used by this module."""
-  pass
-
-
-def _ChangeUrlPort(url, new_port):
-  """Return the URL passed in with a different port"""
-  scheme, netloc, path, query, fragment = urllib.parse.urlsplit(url)
-  host_port = netloc.split(':')
-
-  if len(host_port) == 1:
-    host_port.append(new_port)
-  else:
-    host_port[1] = new_port
-
-  print(host_port)
-  netloc = '%s:%s' % tuple(host_port)
-
-  # pylint: disable=too-many-function-args
-  return urllib.parse.urlunsplit((scheme, netloc, path, query, fragment))
-
-def _NonePathJoin(*args):
-  """os.path.join that filters None's from the argument list."""
-  return os.path.join(*[x for x in args if x is not None])
-
-
-class Autoupdate(object):
-  """Class that contains functionality that handles Chrome OS update pings."""
-
-  def __init__(self, xbuddy, static_dir=None):
-    """Initializes the class.
-
-    Args:
-      xbuddy: The xbuddy path.
-      static_dir: The path to the devserver static directory.
-    """
-    self.xbuddy = xbuddy
-    self.static_dir = static_dir
-
-  def GetUpdateForLabel(self, label):
-    """Given a label, get an update from the directory.
-
-    Args:
-      label: the relative directory inside the static dir
-
-    Returns:
-      A relative path to the directory with the update payload.
-      This is the label if an update did not need to be generated, but can
-      be label/cache/hashed_dir_for_update.
-
-    Raises:
-      AutoupdateError: If client version is higher than available update found
-        at the directory given by the label.
-    """
-    _Log('Update label: %s', label)
-    static_update_path = _NonePathJoin(self.static_dir, label,
-                                       constants.UPDATE_FILE)
-
-    if label and os.path.exists(static_update_path):
-      # An update payload was found for the given label, return it.
-      return label
-
-    # The label didn't resolve.
-    _Log('Did not found any update payload for label %s.', label)
-    return None
-
-  def GetDevserverUrl(self):
-    """Returns the devserver url base."""
-    x_forwarded_host = cherrypy.request.headers.get('X-Forwarded-Host')
-    if x_forwarded_host:
-      # Select the left most <ip>:<port> value so that the request is
-      # forwarded correctly.
-      x_forwarded_host = [x.strip() for x in x_forwarded_host.split(',')][0]
-      hostname = 'http://' + x_forwarded_host
-    else:
-      hostname = cherrypy.request.base
-
-    return hostname
-
-  def GetStaticUrl(self):
-    """Returns the static url base that should prefix all payload responses."""
-    hostname = self.GetDevserverUrl()
-    _Log('Handling update ping as %s', hostname)
-
-    static_urlbase = '%s/static' % hostname
-    _Log('Using static url base %s', static_urlbase)
-    return static_urlbase
-
-  def GetPathToPayload(self, label, board):
-    """Find a payload locally.
-
-    See devserver's update rpc for documentation.
-
-    Args:
-      label: from update request
-      board: from update request
-
-    Returns:
-      The relative path to an update from the static_dir
-
-    Raises:
-      AutoupdateError: If the update could not be found.
-    """
-    label = label or ''
-    label_list = label.split('/')
-    # Suppose that the path follows old protocol of indexing straight
-    # into static_dir with board/version label.
-    # Attempt to get the update in that directory, generating if necc.
-    path_to_payload = self.GetUpdateForLabel(label)
-    if path_to_payload is None:
-      # There was no update found in the directory. Let XBuddy find the
-      # payloads.
-      if label_list[0] == 'xbuddy':
-        # If path explicitly calls xbuddy, pop off the tag.
-        label_list.pop()
-      x_label, _ = self.xbuddy.Translate(label_list, board=board)
-      # Path has been resolved, try to get the payload.
-      path_to_payload = self.GetUpdateForLabel(x_label)
-      if path_to_payload is None:
-        # No update payload found after translation. Try to get an update to
-        # a test image from GS using the label.
-        path_to_payload, _image_name = self.xbuddy.Get(
-            ['remote', label, 'full_payload'])
-
-    # One of the above options should have gotten us a relative path.
-    if path_to_payload is None:
-      raise AutoupdateError('Failed to get an update for: %s' % label)
-
-    return path_to_payload
-
-  def HandleUpdatePing(self, data, label='', **kwargs):
-    """Handles an update ping from an update client.
-
-    Args:
-      data: XML blob from client.
-      label: optional label for the update.
-      kwargs: The map of query strings passed to the /update API.
-
-    Returns:
-      Update payload message for client.
-    """
-    # Get the static url base that will form that base of our update url e.g.
-    # http://hostname:8080/static/update.gz.
-    static_urlbase = self.GetStaticUrl()
-    # Change the URL's string query dictionary provided by cherrypy to a valid
-    # dictionary that has proper values for its keys. e.g. True instead of
-    # 'True'.
-    kwargs = nebraska.QueryDictToDict(kwargs)
-
-    # Process attributes of the update check.
-    request = nebraska.Request(data)
-    if request.request_type == nebraska.Request.RequestType.EVENT:
-      _Log('A non-update event notification received. Returning an ack.')
-      return nebraska.Nebraska().GetResponseToRequest(
-          request, response_props=nebraska.ResponseProperties(**kwargs))
-
-    _Log('Update Check Received.')
-
-    try:
-      path_to_payload = self.GetPathToPayload(label, request.board)
-      base_url = _NonePathJoin(static_urlbase, path_to_payload)
-      local_payload_dir = _NonePathJoin(self.static_dir, path_to_payload)
-    except AutoupdateError as e:
-      # Raised if we fail to generate an update payload.
-      _Log('Failed to process an update request, but we will defer to '
-           'nebraska to respond with no-update. The error was %s', e)
-
-    _Log('Responding to client to use url %s to get image', base_url)
-    nebraska_props = nebraska.NebraskaProperties(
-        update_payloads_address=base_url,
-        update_metadata_dir=local_payload_dir)
-    nebraska_obj = nebraska.Nebraska(nebraska_props=nebraska_props)
-    return nebraska_obj.GetResponseToRequest(
-        request, response_props=nebraska.ResponseProperties(**kwargs))
diff --git a/autoupdate_unittest.py b/autoupdate_unittest.py
deleted file mode 100755
index 648ef7c..0000000
--- a/autoupdate_unittest.py
+++ /dev/null
@@ -1,115 +0,0 @@
-#!/usr/bin/env python2
-# -*- coding: utf-8 -*-
-# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Unit tests for autoupdate.py."""
-
-from __future__ import print_function
-
-import json
-import shutil
-import socket
-import tempfile
-import unittest
-
-import mock
-import cherrypy  # pylint: disable=import-error
-
-import autoupdate
-
-import setup_chromite  # pylint: disable=unused-import
-from chromite.lib.xbuddy import common_util
-from chromite.lib.xbuddy import xbuddy
-
-
-_TEST_REQUEST = """<?xml version="1.0" encoding="UTF-8"?>
-<request protocol="3.0" updater="ChromeOSUpdateEngine" updaterversion="0.1.0.0">
-  <app appid="test-appid" version="%(version)s" track="%(track)s"
-       board="%(board)s" hardware_class="%(hwclass)s">
-    <updatecheck />
-  </app>
-</request>"""
-
-class AutoupdateTest(unittest.TestCase):
-  """Tests for the autoupdate.Autoupdate class."""
-
-  def setUp(self):
-    self.port = 8080
-    self.test_board = 'test-board'
-    self.build_root = tempfile.mkdtemp('autoupdate_build_root')
-    self.tempdir = tempfile.mkdtemp('tempdir')
-    self.latest_dir = '12345_af_12-a1'
-    self.latest_verision = '12345_af_12'
-    self.static_image_dir = tempfile.mkdtemp('autoupdate_static_dir')
-    self.hostname = '%s:%s' % (socket.gethostname(), self.port)
-    self.test_dict = {
-        'version': 'ForcedUpdate',
-        'track': 'test-channel',
-        'board': self.test_board,
-        'hwclass': 'test-hardware-class',
-    }
-    self.test_data = _TEST_REQUEST % self.test_dict
-    self.payload = 'My payload'
-    cherrypy.request.base = 'http://%s' % self.hostname
-    common_util.MkDirP(self.static_image_dir)
-    self._xbuddy = xbuddy.XBuddy(False,
-                                 static_dir=self.static_image_dir)
-    mock.patch.object(xbuddy.XBuddy, '_GetArtifact')
-
-  def tearDown(self):
-    shutil.rmtree(self.build_root)
-    shutil.rmtree(self.tempdir)
-    shutil.rmtree(self.static_image_dir)
-
-  def _DummyAutoupdateConstructor(self, **kwargs):
-    """Creates a dummy autoupdater.  Used to avoid using constructor."""
-    dummy = autoupdate.Autoupdate(self._xbuddy,
-                                  static_dir=self.static_image_dir,
-                                  **kwargs)
-    return dummy
-
-  def testChangeUrlPort(self):
-    # pylint: disable=protected-access
-    r = autoupdate._ChangeUrlPort('http://fuzzy:8080/static', 8085)
-    self.assertEqual(r, 'http://fuzzy:8085/static')
-
-    r = autoupdate._ChangeUrlPort('http://fuzzy/static', 8085)
-    self.assertEqual(r, 'http://fuzzy:8085/static')
-
-    r = autoupdate._ChangeUrlPort('ftp://fuzzy/static', 8085)
-    self.assertEqual(r, 'ftp://fuzzy:8085/static')
-
-    r = autoupdate._ChangeUrlPort('ftp://fuzzy', 8085)
-    self.assertEqual(r, 'ftp://fuzzy:8085')
-
-  def testHandleHostInfoPing(self):
-    au_mock = self._DummyAutoupdateConstructor()
-    self.assertRaises(AssertionError, au_mock.HandleHostInfoPing, None)
-
-    # Setup fake host_infos entry and ensure it comes back to us in one piece.
-    test_ip = '1.2.3.4'
-    au_mock.host_infos.GetInitHostInfo(test_ip).attrs = self.test_dict
-    self.assertEqual(
-        json.loads(au_mock.HandleHostInfoPing(test_ip)), self.test_dict)
-
-  @mock.patch.object(autoupdate.Autoupdate, 'GetPathToPayload')
-  def testHandleUpdatePing(self, path_to_payload_mock):
-    """Tests HandleUpdatePing"""
-    au_mock = self._DummyAutoupdateConstructor()
-    path_to_payload_mock.return_value = self.tempdir
-    request = """<?xml version="1.0" encoding="UTF-8"?>
-<request protocol="3.0">
-  <os version="Indy" platform="Chrome OS" sp="10323.52.0_x86_64"></os>
-  <app appid="platform" version="1.0.0" delta_okay="true"
-       track="stable-channel" board="eve">
-    <ping active="1" a="1" r="1"></ping>
-    <updatecheck targetversionprefix=""></updatecheck>
-  </app>
-</request>"""
-
-    self.assertIn('error-unknownApplication', au_mock.HandleUpdatePing(request))
-
-if __name__ == '__main__':
-  unittest.main()
diff --git a/devserver.py b/devserver.py
index c25191c..f7d6707 100755
--- a/devserver.py
+++ b/devserver.py
@@ -4,22 +4,14 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-"""Chromium OS development server that can be used for all forms of update.
+"""Chromium OS development server that can be used for caching files.
 
-This devserver can be used to perform system-wide autoupdate and update
-of specific portage packages on devices running Chromium OS derived operating
-systems.
-
-The devserver is configured to stage and
-serve artifacts from Google Storage using the credentials provided to it before
-it is run. The easiest way to understand this is that the devserver is
-functioning as a local cache for artifacts produced and uploaded by build
-servers. Users of this form of devserver can either download the artifacts
-from the devservers static directory OR use the update RPC to perform a
-system-wide autoupdate. Archive mode is always active.
-
-For autoupdates, there are many more advanced options that can help specify
-how to update and which payload to give to a requester.
+The devserver is configured to stage and serve artifacts from Google Storage
+using the credentials provided to it before it is run. The easiest way to
+understand this is that the devserver is functioning as a local cache for
+artifacts produced and uploaded by build servers. Users of this form of
+devserver can download the artifacts from the devservers static directory.
+Archive mode is always active.
 """
 
 from __future__ import print_function
@@ -45,7 +37,6 @@
 from cherrypy.process import plugins
 # pylint: enable=no-name-in-module, import-error
 
-import autoupdate
 import cherrypy_ext
 import health_checker
 
@@ -74,9 +65,6 @@
                   'dep-chrome_test.tar.bz2',
                   'dep-perf_data_dep.tar.bz2']
 
-# Sets up global to share between classes.
-updater = None
-
 # Log rotation parameters.  These settings correspond to twice a day once
 # devserver is started, with about two weeks (28 backup files) of old logs
 # kept for backup.
@@ -139,19 +127,23 @@
     raise DevServerError('Must specify an archive_url in the request')
 
 
-def _canonicalize_local_path(local_path):
+def _canonicalize_local_path(local_path, static_dir):
   """Canonicalizes |local_path| strings.
 
+  Args:
+    local_path: The input path.
+    static_dir: Devserver's static cache directory.
+
   Raises:
     DevserverError: if |local_path| is not set.
   """
   # Restrict staging of local content to only files within the static
   # directory.
   local_path = os.path.abspath(local_path)
-  if not local_path.startswith(updater.static_dir):
+  if not local_path.startswith(static_dir):
     raise DevServerError(
         'Local path %s must be a subdirectory of the static'
-        ' directory: %s' % (local_path, updater.static_dir))
+        ' directory: %s' % (local_path, static_dir))
 
   return local_path.rstrip('/')
 
@@ -190,20 +182,21 @@
   return os_type == 'android'
 
 
-def _get_downloader(kwargs):
+def _get_downloader(static_dir, kwargs):
   """Returns the downloader based on passed in arguments.
 
   Args:
+    static_dir: Devserver's static cache directory.
     kwargs: Keyword arguments for the request.
   """
   local_path = kwargs.get('local_path')
   if local_path:
-    local_path = _canonicalize_local_path(local_path)
+    local_path = _canonicalize_local_path(local_path, static_dir)
 
   dl = None
   if local_path:
     delete_source = _parse_boolean_arg(kwargs, 'delete_source')
-    dl = downloader.LocalDownloader(updater.static_dir, local_path,
+    dl = downloader.LocalDownloader(static_dir, local_path,
                                     delete_source=delete_source)
 
   if not _is_android_build_request(kwargs):
@@ -217,7 +210,7 @@
     if not dl:
       archive_url = _canonicalize_archive_url(archive_url)
       dl = downloader.GoogleStorageDownloader(
-          updater.static_dir, archive_url,
+          static_dir, archive_url,
           downloader.GoogleStorageDownloader.GetBuildIdFromArchiveURL(
               archive_url))
   elif not dl:
@@ -227,20 +220,21 @@
     if not target or not branch or not build_id:
       raise DevServerError('target, branch, build ID must all be specified for '
                            'downloading Android build.')
-    dl = downloader.AndroidBuildDownloader(updater.static_dir, branch, build_id,
+    dl = downloader.AndroidBuildDownloader(static_dir, branch, build_id,
                                            target)
 
   return dl
 
 
-def _get_downloader_and_factory(kwargs):
+def _get_downloader_and_factory(static_dir, kwargs):
   """Returns the downloader and artifact factory based on passed in arguments.
 
   Args:
+    static_dir: Devserver's static cache directory.
     kwargs: Keyword arguments for the request.
   """
   artifacts, files = _get_artifacts(kwargs)
-  dl = _get_downloader(kwargs)
+  dl = _get_downloader(static_dir, kwargs)
 
   if (isinstance(dl, (downloader.GoogleStorageDownloader,
                       downloader.LocalDownloader))):
@@ -344,11 +338,6 @@
       '/build': {
           'response.timeout': 100000,
       },
-      '/update': {
-          # Gets rid of cherrypy parsing post file for args.
-          'request.process_request_body': False,
-          'response.timeout': 10000,
-      },
       # Sets up the static dir for file hosting.
       '/static': {
           'tools.staticdir.dir': options.static_dir,
@@ -519,10 +508,11 @@
   # Lock used to lock increasing/decreasing count.
   _staging_thread_count_lock = threading.Lock()
 
-  def __init__(self, _xbuddy):
+  def __init__(self, _xbuddy, static_dir):
     self._builder = None
     self._telemetry_lock_dict = common_util.LockDict()
     self._xbuddy = _xbuddy
+    self._static_dir = static_dir
 
   @property
   def staging_thread_count(self):
@@ -561,7 +551,7 @@
     Returns:
       True of all artifacts are staged.
     """
-    dl, factory = _get_downloader_and_factory(kwargs)
+    dl, factory = _get_downloader_and_factory(self._static_dir, kwargs)
     response = str(dl.IsStaged(factory))
     _Log('Responding to is_staged %s request with %r', kwargs, response)
     return response
@@ -581,7 +571,7 @@
     Returns:
       A string with information about the contents of the image directory.
     """
-    dl = _get_downloader(kwargs)
+    dl = _get_downloader(self._static_dir, kwargs)
     try:
       image_dir_contents = dl.ListBuildDir()
     except build_artifact.ArtifactDownloadError as e:
@@ -643,7 +633,7 @@
         custom post-processing.
       clean: True to remove any previously staged artifacts first.
     """
-    dl, factory = _get_downloader_and_factory(kwargs)
+    dl, factory = _get_downloader_and_factory(self._static_dir, kwargs)
 
     with DevServerRoot._staging_thread_count_lock:
       DevServerRoot._staging_thread_count += 1
@@ -680,7 +670,7 @@
     if is_deprecated_server():
       raise DeprecatedRPCError('locate_file')
 
-    dl, _ = _get_downloader_and_factory(kwargs)
+    dl, _ = _get_downloader_and_factory(self._static_dir, kwargs)
     try:
       file_name = kwargs['file_name']
       artifacts = kwargs['artifacts']
@@ -714,7 +704,7 @@
     Returns:
       Path to the source folder for the telemetry codebase once it is staged.
     """
-    dl = _get_downloader(kwargs)
+    dl = _get_downloader(self._static_dir, kwargs)
 
     build_path = dl.GetBuildDir()
     deps_path = os.path.join(build_path, 'autotest/packages')
@@ -774,7 +764,7 @@
     # Try debug.tar.xz first, then debug.tgz
     for artifact in (artifact_info.SYMBOLS_ONLY, artifact_info.SYMBOLS):
       kwargs['artifacts'] = artifact
-      dl = _get_downloader(kwargs)
+      dl = _get_downloader(self._static_dir, kwargs)
 
       try:
         if self.stage(**kwargs) == 'Success':
@@ -845,7 +835,7 @@
 
     try:
       return common_util.GetLatestBuildVersion(
-          updater.static_dir, kwargs['target'],
+          self._static_dir, kwargs['target'],
           milestone=kwargs.get('milestone'))
     except common_util.CommonUtilError as errmsg:
       raise DevServerHTTPError(http_client.INTERNAL_SERVER_ERROR,
@@ -883,13 +873,13 @@
 
     control_file_list = [
         line.rstrip() for line in common_util.GetControlFileListForSuite(
-            updater.static_dir, kwargs['build'],
+            self._static_dir, kwargs['build'],
             kwargs['suite_name']).splitlines()]
 
     control_file_content_dict = {}
     for control_path in control_file_list:
       control_file_content_dict[control_path] = (common_util.GetControlFile(
-          updater.static_dir, kwargs['build'], control_path))
+          self._static_dir, kwargs['build'], control_path))
 
     return json.dumps(control_file_content_dict)
 
@@ -932,13 +922,13 @@
     if 'control_path' not in kwargs:
       if 'suite_name' in kwargs and kwargs['suite_name']:
         return common_util.GetControlFileListForSuite(
-            updater.static_dir, kwargs['build'], kwargs['suite_name'])
+            self._static_dir, kwargs['build'], kwargs['suite_name'])
       else:
         return common_util.GetControlFileList(
-            updater.static_dir, kwargs['build'])
+            self._static_dir, kwargs['build'])
     else:
       return common_util.GetControlFile(
-          updater.static_dir, kwargs['build'], kwargs['control_path'])
+          self._static_dir, kwargs['build'], kwargs['control_path'])
 
   @cherrypy.expose
   def xbuddy_translate(self, *args, **kwargs):
@@ -1073,7 +1063,7 @@
     """Shows the documentation for available methods / URLs.
 
     Examples:
-      http://myhost/doc/update
+      http://myhost/doc/xbuddy
     """
     if is_deprecated_server():
       raise DeprecatedRPCError('doc')
@@ -1086,51 +1076,6 @@
       raise DevServerError("No documentation for exposed method `%s'" % name)
     return '<pre>\n%s</pre>' % method.__doc__
 
-  @cherrypy.expose
-  def update(self, *args, **kwargs):
-    """Handles an update check from a Chrome OS client.
-
-    The HTTP request should contain the standard Omaha-style XML blob. The URL
-    line may contain an additional intermediate path to the update payload.
-
-    This request can be handled in one of 4 ways, depending on the devsever
-    settings and intermediate path.
-
-    1. No intermediate path. DEPRECATED
-
-    2. Path explicitly invokes XBuddy
-    If there is a path given, it can explicitly invoke xbuddy by prefixing it
-    with 'xbuddy'. This path is then used to acquire an image binary for the
-    devserver to generate an update payload from. Devserver then serves this
-    payload.
-
-    3. Path is left for the devserver to interpret.
-    If the path given doesn't explicitly invoke xbuddy, devserver will attempt
-    to generate a payload from the test image in that directory and serve it.
-
-    Examples:
-      2. Explicitly invoke xbuddy
-      update_engine_client --omaha_url=
-      http://myhost/update/xbuddy/remote/board/version/dev
-      This would go to GS to download the dev image for the board, from which
-      the devserver would generate a payload to serve.
-
-      3. Give a path for devserver to interpret
-      update_engine_client --omaha_url=http://myhost/update/some/random/path
-      This would attempt, in order to:
-        a) Generate an update from a test image binary if found in
-           static_dir/some/random/path.
-        b) Serve an update payload found in static_dir/some/random/path.
-        c) Hope that some/random/path takes the form "board/version" and
-           and attempt to download an update payload for that board/version
-           from GS.
-    """
-    label = '/'.join(args)
-    body_length = int(cherrypy.request.headers.get('Content-Length', 0))
-    data = cherrypy.request.rfile.read(body_length)
-
-    return updater.HandleUpdatePing(data, label, **kwargs)
-
 
 def _CleanCache(cache_dir, wipe):
   """Wipes any excess cached items in the cache_dir.
@@ -1278,15 +1223,10 @@
   if options.clear_cache and options.xbuddy_manage_builds:
     _xbuddy.CleanCache()
 
-  # We allow global use here to share with cherrypy classes.
-  # pylint: disable=W0603
-  global updater
-  updater = autoupdate.Autoupdate(_xbuddy, static_dir=options.static_dir)
-
   if options.exit:
     return
 
-  dev_server = DevServerRoot(_xbuddy)
+  dev_server = DevServerRoot(_xbuddy, options.static_dir)
   health_checker_app = health_checker.Root(dev_server, options.static_dir)
 
   if options.pidfile:
diff --git a/devserver_integration_test.py b/devserver_integration_test.py
index 64a492f..89c5d19 100755
--- a/devserver_integration_test.py
+++ b/devserver_integration_test.py
@@ -26,12 +26,8 @@
 
 from string import Template
 
-from xml.dom import minidom
-
 import requests
 
-from six.moves import urllib
-
 import psutil  # pylint: disable=import-error
 
 import setup_chromite  # pylint: disable=unused-import
@@ -215,64 +211,6 @@
     self.pid = None
     self.devserver = None
 
-
-  def VerifyHandleUpdate(self, label, use_test_payload=True,
-                         appid='{DEV-BUILD}'):
-    """Verifies that we can send an update request to the devserver.
-
-    This method verifies (using a fake update_request blob) that the devserver
-    can interpret the payload and give us back the right payload.
-
-    Args:
-      label: Label that update is served from e.g. <board>-release/<version>
-      use_test_payload: If set to true, expects to serve payload under
-        testdata/ and does extra checks i.e. compares hash and content of
-        payload.
-      appid: The APP ID of the board.
-
-    Returns:
-      url of the update payload if we verified the update.
-    """
-    update_label = '/'.join([UPDATE, label])
-    response = self._MakeRPC(
-        update_label, data=UPDATE_REQUEST.substitute({'appid': appid}),
-        critical_update=True)
-    self.assertNotEqual('', response)
-    self.assertIn('deadline="now"', response)
-
-    # Parse the response and check if it contains the right result.
-    dom = minidom.parseString(response)
-    update = dom.getElementsByTagName('updatecheck')[0]
-    expected_static_url = '/'.join([self.devserver_url, STATIC, label])
-    url = self.VerifyV3Response(update, expected_static_url)
-
-    # Verify the image we download is correct since we already know what it is.
-    if use_test_payload:
-      connection = urllib.request.urlopen(url)
-      contents = connection.read().decode('utf-8')
-      connection.close()
-      self.assertEqual('Developers, developers, developers!\n', contents)
-
-    return url
-
-  def VerifyV3Response(self, update, expected_static_url):
-    """Verifies the update DOM from a v3 response and returns the url."""
-    # Parse the response and check if it contains the right result.
-    urls = update.getElementsByTagName('urls')[0]
-    url = urls.getElementsByTagName('url')[0]
-
-    static_url = url.getAttribute('codebase')
-    # Static url's end in /.
-    self.assertEqual(expected_static_url + '/', static_url)
-
-    manifest = update.getElementsByTagName('manifest')[0]
-    packages = manifest.getElementsByTagName('packages')[0]
-    package = packages.getElementsByTagName('package')[0]
-    filename = package.getAttribute('name')
-    self.assertEqual(TEST_UPDATE_PAYLOAD_NAME, filename)
-
-    return os.path.join(static_url, filename)
-
   def _MakeRPC(self, rpc, data=None, timeout=None, **kwargs):
     """Makes an RPC call to the devserver.
 
@@ -338,9 +276,6 @@
   they are lumped with the remote tests here.
   """
 
-  def testHandleUpdateV3(self):
-    self.VerifyHandleUpdate(label=LABEL)
-
   def testXBuddyLocalAlias(self):
     """Extensive local image xbuddy unittest.
 
@@ -375,7 +310,7 @@
 
       xbuddy_path = '/'.join([build_id, item])
       logging.info('Testing xbuddy path %s', xbuddy_path)
-      response = self._MakeRPC('/'.join([XBUDDY, xbuddy_path]))
+      response = self._MakeRPC('/'.join([XBUDDY, xbuddy_path]), timeout=3)
       self.assertEqual(response, data)
 
       expected_dir = '/'.join([self.devserver_url, STATIC, build_id])
@@ -386,14 +321,6 @@
                                relative_path=True)
       self.assertEqual(response, build_id)
 
-    logging.info('Verifying the actual payload data')
-    url = self.VerifyHandleUpdate(build_id, use_test_payload=False)
-    logging.info('Verify the actual content of the update payload')
-    connection = urllib.request.urlopen(url)
-    contents = connection.read().decode('utf-8')
-    connection.close()
-    self.assertEqual(update_data, contents)
-
   def testPidFile(self):
     """Test that using a pidfile works correctly."""
     with open(self.pidfile, 'r') as f:
@@ -412,37 +339,6 @@
   2) time. These tests actually download the artifacts needed.
   """
 
-  def testStageAndUpdate(self):
-    """Tests core stage/update autotest workflow where with a test payload."""
-    build_id = 'eve-release/R78-12499.0.0'
-    archive_url = 'gs://chromeos-image-archive/%s' % build_id
-
-    response = self._MakeRPC(IS_STAGED, archive_url=archive_url,
-                             artifacts='full_payload,stateful')
-    self.assertEqual(response, 'False')
-
-    logging.info('Staging update artifacts')
-    self._MakeRPC(STAGE, archive_url=archive_url,
-                  artifacts='full_payload,stateful')
-    logging.info('Staging complete. '
-                 'Verifying files exist and are staged in the staging '
-                 'directory.')
-    response = self._MakeRPC(IS_STAGED, archive_url=archive_url,
-                             artifacts='full_payload,stateful')
-    self.assertEqual(response, 'True')
-    staged_dir = os.path.join(self.test_data_path, build_id)
-    self.assertTrue(os.path.isdir(staged_dir))
-    self.assertTrue(os.path.exists(
-        os.path.join(staged_dir, devserver_constants.UPDATE_FILE)))
-    self.assertTrue(os.path.exists(
-        os.path.join(staged_dir, devserver_constants.UPDATE_METADATA_FILE)))
-    self.assertTrue(os.path.exists(
-        os.path.join(staged_dir, devserver_constants.STATEFUL_FILE)))
-
-    logging.info('Verifying we can update using the stage update artifacts.')
-    self.VerifyHandleUpdate(build_id, use_test_payload=False,
-                            appid='{01906EA2-3EB2-41F1-8F62-F0B7120EFD2E}')
-
   @unittest.skip('crbug.com/640063 Broken test.')
   def testStageAutotestAndGetPackages(self):
     """Another stage/update autotest workflow test with a test payload."""