autoupdate: Install stateful_update from the right location
stateful_update can be locally stored at 2 locations:
/usr/sbin/stateful_update installed by package chromeos-base/devserver,
or by python modules: either during unit test or by build_externals.py on
the labserver.
BUG=chromium:689105
TEST=Unit test. Test stateful_update is executable.
Check powerwash machines are updating properly.
Change-Id: Ib43552651b7b1bae594254253b0d623f5e72f8a5
Signed-off-by: Gwendal Grignou <gwendal@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/527422
Reviewed-by: Richard Barnette <jrbarnette@google.com>
diff --git a/client/common_lib/cros/autoupdater.py b/client/common_lib/cros/autoupdater.py
index 3a36557..510091c 100644
--- a/client/common_lib/cros/autoupdater.py
+++ b/client/common_lib/cros/autoupdater.py
@@ -20,9 +20,14 @@
except ImportError:
metrics = utils.metrics_mock
+try:
+ import devserver
+ STATEFUL_UPDATE_PATH = devserver.__path__[0]
+except ImportError:
+ STATEFUL_UPDATE_PATH = '/usr/bin'
+
# Local stateful update path is relative to the CrOS source directory.
-LOCAL_STATEFUL_UPDATE_PATH = 'src/platform/dev/stateful_update'
-LOCAL_CHROOT_STATEFUL_UPDATE_PATH = '/usr/bin/stateful_update'
+STATEFUL_UPDATE_SCRIPT = 'stateful_update'
UPDATER_IDLE = 'UPDATE_STATUS_IDLE'
UPDATER_NEED_REBOOT = 'UPDATE_STATUS_UPDATED_NEED_REBOOT'
# A list of update engine client states that occur after an update is triggered.
@@ -325,9 +330,11 @@
class ChromiumOSUpdater(BaseUpdater):
"""Helper class used to update DUT with image of desired version."""
- REMOTE_STATEUL_UPDATE_PATH = '/usr/local/bin/stateful_update'
+ REMOTE_STATEFUL_UPDATE_PATH = os.path.join(
+ '/usr/local/bin', STATEFUL_UPDATE_SCRIPT)
+ REMOTE_TMP_STATEFUL_UPDATE = os.path.join(
+ '/tmp', STATEFUL_UPDATE_SCRIPT)
UPDATER_BIN = '/usr/bin/update_engine_client'
- STATEFUL_UPDATE = '/tmp/stateful_update'
UPDATED_MARKER = '/var/run/update_engine_autoupdate_completed'
UPDATER_LOGS = ['/var/log/messages', '/var/log/update_engine']
@@ -418,34 +425,31 @@
def get_stateful_update_script(self):
- """Returns the path to the stateful update script on the target."""
- # We attempt to load the local stateful update path in 3 different
- # ways. First we use the location specified in the autotest global
- # config. If this doesn't exist, we attempt to use the Chromium OS
- # Chroot path to the installed script. If all else fails, we use the
- # stateful update script on the host.
- stateful_update_path = os.path.join(
- global_config.global_config.get_config_value(
- 'CROS', 'source_tree', default=''),
- LOCAL_STATEFUL_UPDATE_PATH)
+ """Returns the path to the stateful update script on the target.
- if not os.path.exists(stateful_update_path):
- logging.warning('Could not find Chrome OS source location for '
- 'stateful_update script at %s, falling back to '
- 'chroot copy.', stateful_update_path)
- stateful_update_path = LOCAL_CHROOT_STATEFUL_UPDATE_PATH
+ When runnning test_that, stateful_update is in chroot /usr/sbin,
+ as installed by chromeos-base/devserver packages.
+ In the lab, it is installed with the python module devserver, by
+ build_externals.py command.
- if not os.path.exists(stateful_update_path):
- logging.warning('Could not chroot stateful_update script, falling '
- 'back on client copy.')
- statefuldev_script = self.REMOTE_STATEUL_UPDATE_PATH
- else:
+ If we can find it, we hope it exists already on the DUT, we assert
+ otherwise.
+ """
+ stateful_update_file = os.path.join(STATEFUL_UPDATE_PATH,
+ STATEFUL_UPDATE_SCRIPT)
+ if os.path.exists(stateful_update_file):
self.host.send_file(
- stateful_update_path, self.STATEFUL_UPDATE,
+ stateful_update_file, self.REMOTE_TMP_STATEFUL_UPDATE,
delete_dest=True)
- statefuldev_script = self.STATEFUL_UPDATE
+ return self.REMOTE_TMP_STATEFUL_UPDATE
- return statefuldev_script
+ if self.host.path_exists(self.REMOTE_STATEFUL_UPDATE_PATH):
+ logging.warning('Could not chroot %s script, falling back on %s',
+ STATEFUL_UPDATE_SCRIPT, self.REMOTE_STATEFUL_UPDATE_PATH)
+ return self.REMOTE_STATEFUL_UPDATE_PATH
+ else:
+ raise ChromiumOSError('Could not locate %s',
+ STATEFUL_UPDATE_SCRIPT)
def reset_stateful_partition(self):
diff --git a/client/common_lib/cros/autoupdater_unittest.py b/client/common_lib/cros/autoupdater_unittest.py
index 65bb520..d29dffd 100755
--- a/client/common_lib/cros/autoupdater_unittest.py
+++ b/client/common_lib/cros/autoupdater_unittest.py
@@ -4,6 +4,7 @@
# found in the LICENSE file.
import mox
+import os
import unittest
import common
@@ -11,6 +12,7 @@
import autoupdater
from autotest_lib.client.common_lib import error
+from autotest_lib.client.common_lib.test_utils import mock
class TestAutoUpdater(mox.MoxTestBase):
"""Test autoupdater module."""
@@ -517,12 +519,12 @@
# Test with clobber=False.
autoupdater.ChromiumOSUpdater.get_stateful_update_script().AndReturn(
- autoupdater.ChromiumOSUpdater.REMOTE_STATEUL_UPDATE_PATH)
+ autoupdater.ChromiumOSUpdater.REMOTE_STATEFUL_UPDATE_PATH)
autoupdater.ChromiumOSUpdater._run(
mox.And(
mox.StrContains(
autoupdater.ChromiumOSUpdater.
- REMOTE_STATEUL_UPDATE_PATH),
+ REMOTE_STATEFUL_UPDATE_PATH),
mox.StrContains(static_update_url),
mox.Not(mox.StrContains('--stateful_change=clean'))),
timeout=mox.IgnoreArg())
@@ -535,12 +537,12 @@
# Test with clobber=True.
self.mox.ResetAll()
autoupdater.ChromiumOSUpdater.get_stateful_update_script().AndReturn(
- autoupdater.ChromiumOSUpdater.REMOTE_STATEUL_UPDATE_PATH)
+ autoupdater.ChromiumOSUpdater.REMOTE_STATEFUL_UPDATE_PATH)
autoupdater.ChromiumOSUpdater._run(
mox.And(
mox.StrContains(
autoupdater.ChromiumOSUpdater.
- REMOTE_STATEUL_UPDATE_PATH),
+ REMOTE_STATEFUL_UPDATE_PATH),
mox.StrContains(static_update_url),
mox.StrContains('--stateful_change=clean')),
timeout=mox.IgnoreArg())
@@ -550,6 +552,44 @@
self.mox.VerifyAll()
+ def testGetStatefulUpdateScript(self):
+ """ Test that get_stateful_update_script look for stateful_update.
+
+ Check get_stateful_update_script is trying hard to find
+ stateful_update and assert if it can't.
+
+ """
+ update_url = ('http://172.22.50.205:8082/update/lumpy-chrome-perf/'
+ 'R28-4444.0.0-b2996')
+ script_loc = os.path.join(autoupdater.STATEFUL_UPDATE_PATH,
+ autoupdater.STATEFUL_UPDATE_SCRIPT)
+ self.god = mock.mock_god()
+ self.god.stub_function(os.path, 'exists')
+ host = self.mox.CreateMockAnything()
+ updater = autoupdater.ChromiumOSUpdater(update_url, host=host)
+ os.path.exists.expect_call(script_loc).and_return(False)
+ host.path_exists('/usr/local/bin/stateful_update').AndReturn(False)
+
+ self.mox.ReplayAll()
+ # No existing files, no URL, we should assert.
+ self.assertRaises(
+ autoupdater.ChromiumOSError,
+ updater.get_stateful_update_script)
+ self.mox.VerifyAll()
+
+ # No existing files, but stateful URL, we will try.
+ self.mox.ResetAll()
+ os.path.exists.expect_call(script_loc).and_return(True)
+ host.send_file(
+ script_loc,
+ '/tmp/stateful_update', delete_dest=True).AndReturn(True)
+ self.mox.ReplayAll()
+ self.assertEqual(
+ updater.get_stateful_update_script(),
+ '/tmp/stateful_update')
+ self.mox.VerifyAll()
+
+
def testRollbackRootfs(self):
"""Tests that we correctly rollback the rootfs when requested."""
self.mox.StubOutWithMock(autoupdater.ChromiumOSUpdater, '_run')