devserver: support for serving remotely hosted payloads
This feature is aimed to allow one instance of a devserver to respond to
an update check with a link to a payload that's hosted (statically
staged) on another devserver. Specifically, we plan on using it in the
test lab to spawn test-private devserver instances that will direct DUTs
to obtain their payloads from a central devserver. To use this feature,
the test-private instance should be invoked with the following switches:
--archive_dir=static/ (avoids payload generation, value insignificant)
--urlbase=http://<central-devserver-hostname>:<port>
--payload=static/<path>/<to>/<payload>/<file>
--remote_payload (triggers proper handling of the remote payload)
Note that the --payload value is optional, and is only used if the
update check issued by the client does not contain a payload URL, for
example: .../update/static/<path>/<to>/<payload>/<file>
* Adds a new option --remote_payload for triggering special handling of
remotely hosted payload files. This is hard to infer based on existing
options (such as --urlbase) and disambiguates the behavior.
* Added functionality for retrieving necessary attributes of the remote
payload file, such as size and hashes, which need to be send back to
the DUT in the update response.
* The payload file name is assumed to be a devserver constant
(update.gz).
* The remote payload URL is assumed to have a /static prefix to it. This
invariant must be preserved by both the client (request) and the
backend devserver (provisioning).
* Added unit test to cover remote payload logic.
BUG=chromium-os:33762
TEST=Devserver responds with remote payload data; passes unit tests.
Change-Id: Ief34bbd18d9046460f2b2a7a6c88b465d65426e8
Reviewed-on: https://gerrit.chromium.org/gerrit/34499
Reviewed-by: Chris Sosa <sosa@chromium.org>
Reviewed-by: Scott Zawalski <scottz@chromium.org>
Commit-Ready: Gilad Arnold <garnold@chromium.org>
Tested-by: Gilad Arnold <garnold@chromium.org>
diff --git a/autoupdate_unittest.py b/autoupdate_unittest.py
index 2fd88a7..f06b981 100755
--- a/autoupdate_unittest.py
+++ b/autoupdate_unittest.py
@@ -34,6 +34,7 @@
self.mox.StubOutWithMock(common_util, 'GetFileSha256')
self.mox.StubOutWithMock(autoupdate.Autoupdate, 'GetUpdatePayload')
self.mox.StubOutWithMock(autoupdate.Autoupdate, '_GetLatestImageDir')
+ self.mox.StubOutWithMock(autoupdate.Autoupdate, '_GetRemotePayloadAttrs')
self.port = 8080
self.test_board = 'test-board'
self.build_root = '/src_path/build/images'
@@ -51,18 +52,18 @@
}
self.test_data = _TEST_REQUEST % self.test_dict
self.forced_image_path = '/path_to_force/chromiumos_image.bin'
- self.hash = 12345
+ self.sha1 = 12345
self.size = 54321
self.url = 'http://%s/static/update.gz' % self.hostname
self.payload = 'My payload'
self.sha256 = 'SHA LA LA'
cherrypy.request.base = 'http://%s' % self.hostname
- def _DummyAutoupdateConstructor(self):
+ def _DummyAutoupdateConstructor(self, **kwargs):
"""Creates a dummy autoupdater. Used to avoid using constructor."""
dummy = autoupdate.Autoupdate(root_dir=None,
static_dir=self.static_image_dir,
- port=self.port)
+ **kwargs)
return dummy
def testGetRightSignedDeltaPayloadDir(self):
@@ -115,13 +116,13 @@
self.forced_image_path,
static_image_dir=self.static_image_dir).AndReturn('update.gz')
common_util.GetFileSha1(os.path.join(
- self.static_image_dir, 'update.gz')).AndReturn(self.hash)
+ self.static_image_dir, 'update.gz')).AndReturn(self.sha1)
common_util.GetFileSha256(os.path.join(
self.static_image_dir, 'update.gz')).AndReturn(self.sha256)
common_util.GetFileSize(os.path.join(
self.static_image_dir, 'update.gz')).AndReturn(self.size)
autoupdate.Autoupdate.GetUpdatePayload(
- self.hash, self.sha256, self.size, self.url, False).AndReturn(
+ self.sha1, self.sha256, self.size, self.url, False).AndReturn(
self.payload)
self.mox.ReplayAll()
@@ -139,13 +140,13 @@
self.test_board, 'ForcedUpdate', self.static_image_dir).AndReturn(
'update.gz')
common_util.GetFileSha1(os.path.join(
- self.static_image_dir, 'update.gz')).AndReturn(self.hash)
+ self.static_image_dir, 'update.gz')).AndReturn(self.sha1)
common_util.GetFileSha256(os.path.join(
self.static_image_dir, 'update.gz')).AndReturn(self.sha256)
common_util.GetFileSize(os.path.join(
self.static_image_dir, 'update.gz')).AndReturn(self.size)
autoupdate.Autoupdate.GetUpdatePayload(
- self.hash, self.sha256, self.size, self.url, False).AndReturn(
+ self.sha1, self.sha256, self.size, self.url, False).AndReturn(
self.payload)
self.mox.ReplayAll()
@@ -211,13 +212,13 @@
self.test_board, 'ForcedUpdate', new_image_dir).AndReturn(
'update.gz')
common_util.GetFileSha1(os.path.join(
- new_image_dir, 'update.gz')).AndReturn(self.hash)
+ new_image_dir, 'update.gz')).AndReturn(self.sha1)
common_util.GetFileSha256(os.path.join(
new_image_dir, 'update.gz')).AndReturn(self.sha256)
common_util.GetFileSize(os.path.join(
new_image_dir, 'update.gz')).AndReturn(self.size)
autoupdate.Autoupdate.GetUpdatePayload(
- self.hash, self.sha256, self.size, new_url, False).AndReturn(
+ self.sha1, self.sha256, self.size, new_url, False).AndReturn(
self.payload)
self.mox.ReplayAll()
@@ -270,6 +271,26 @@
self.assertTrue(au._CanUpdate('0.16.892.0', '0.16.892.1'))
self.assertFalse(au._CanUpdate('0.16.892.0', '0.16.892.0'))
+ def testHandleUpdatePingRemotePayload(self):
+ remote_urlbase = 'http://remotehost:6666'
+ remote_payload_path = 'static/path/to/update.gz'
+ remote_url = '/'.join([remote_urlbase, remote_payload_path, 'update.gz'])
+
+ test_data = _TEST_REQUEST % self.test_dict
+
+ autoupdate.Autoupdate._GetRemotePayloadAttrs(remote_url).AndReturn(
+ (self.sha1, self.sha256, self.size, False))
+ autoupdate.Autoupdate.GetUpdatePayload(
+ self.sha1, self.sha256, self.size, remote_url, False).AndReturn(
+ self.payload)
+
+ self.mox.ReplayAll()
+ au_mock = self._DummyAutoupdateConstructor(urlbase=remote_urlbase,
+ payload_path=remote_payload_path,
+ remote_payload=True)
+ self.assertEqual(au_mock.HandleUpdatePing(test_data), self.payload)
+ self.mox.VerifyAll()
+
if __name__ == '__main__':
unittest.main()