devserver: stage images using image archive uploaded to Google Storage

This adds a devserver feature that'll download an stage individual
images from the builders' Google Storage archive
(gs://chromeos-image-archive).

- Defines a new CherryPy URL (stage_images) and hooks it to the staging
  code.

- Implements a downloader for the image archive zipfile (image.zip),
  which will fetch it to a temporary directory and unzip the desired
  images to the target (staging) directory.

- Uses a flag file for recording the set of images that have already
  been staged for a given build.

BUG=chromium-os:33762
TEST=devserver stages requested image files, which can be served in
subsequent requests.

Change-Id: I339bd0edb1511c68cca36378c189551511ad1639
Reviewed-on: https://gerrit.chromium.org/gerrit/33140
Commit-Ready: Gilad Arnold <[email protected]>
Reviewed-by: Gilad Arnold <[email protected]>
Tested-by: Gilad Arnold <[email protected]>
diff --git a/devserver.py b/devserver.py
index 2ad13b8..7d0ae96 100755
--- a/devserver.py
+++ b/devserver.py
@@ -426,6 +426,30 @@
                                            params['control_path'])
 
   @cherrypy.expose
+  def stage_images(self, **kwargs):
+    """Downloads and stages a Chrome OS image from Google Storage.
+
+    This method downloads a zipped archive from a specified GS location, then
+    extracts and stages the specified list of images and stages them under
+    static/images/BOARD/BUILD/. Download is synchronous.
+
+    Args:
+      archive_url: Google Storage URL for the build.
+      image_types: comma-separated list of images to download, may include
+                   'test', 'recovery', and 'base'
+
+    Example URL:
+      http://myhost/stage_images?archive_url=gs://chromeos-image-archive/
+      x86-generic/R17-1208.0.0-a1-b338&image_types=test,base
+    """
+    # TODO(garnold) This needs to turn into an async operation, to avoid
+    # unnecessary failure of concurrent secondary requests (chromium-os:34661).
+    archive_url = self._canonicalize_archive_url(kwargs.get('archive_url'))
+    image_types = kwargs.get('image_types').split(',')
+    return (downloader.ImagesDownloader(
+        updater.static_dir).Download(archive_url, image_types))
+
+  @cherrypy.expose
   def index(self):
     return 'Welcome to the Dev Server!'