blob: 99f54fb70be23e73dc15137dce2a9aa862b6514d [file] [log] [blame]
# 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.
from autotest_lib.client.bin import utils
from autotest_lib.client.common_lib import global_config
from autotest_lib.client.common_lib.cros import autoupdater
from autotest_lib.server import autoserv_parser
from autotest_lib.server import site_remote_power
from autotest_lib.server.hosts import base_classes
parser = autoserv_parser.autoserv_parser
# Time to wait for new kernel to be marked successful.
_KERNEL_UPDATE_TIMEOUT = 60
# Ephemeral file to indicate that an update has just occurred.
_JUST_UPDATED_FLAG = '/tmp/just_updated'
class ChromiumOSHost(base_classes.Host):
"""ChromiumOSHost is a special subclass of SSHHost that supports
additional install methods.
"""
def __initialize(self, hostname, *args, **dargs):
"""
Construct a ChromiumOSHost object
Args:
hostname: network hostname or address of remote machine
"""
super(ChromiumOSHost, self)._initialize(hostname, *args, **dargs)
def machine_install(self, update_url=None, force_update=False):
if parser.options.image:
update_url = parser.options.image
elif not update_url:
raise autoupdater.ChromiumOSError(
'Update failed. No update URL provided.')
# Attempt to update the system.
updater = autoupdater.ChromiumOSUpdater(update_url, host=self)
if updater.run_update(force_update):
# Figure out active and inactive kernel.
active_kernel, inactive_kernel = updater.get_kernel_state()
# Ensure inactive kernel has higher priority than active.
if (updater.get_kernel_priority(inactive_kernel)
< updater.get_kernel_priority(active_kernel)):
raise autoupdater.ChromiumOSError(
'Update failed. The priority of the inactive kernel'
' partition is less than that of the active kernel'
' partition.')
# Updater has returned, successfully, reboot the host.
self.reboot(timeout=60, wait=True)
# Following the reboot, verify the correct version.
updater.check_version()
# Figure out newly active kernel.
new_active_kernel, _ = updater.get_kernel_state()
# Ensure that previously inactive kernel is now the active kernel.
if new_active_kernel != inactive_kernel:
raise autoupdater.ChromiumOSError(
'Update failed. New kernel partition is not active after'
' boot.')
# Wait until tries == 0 and success, or until timeout.
utils.poll_for_condition(
lambda: (updater.get_kernel_tries(new_active_kernel) == 0
and updater.get_kernel_success(new_active_kernel)),
exception=autoupdater.ChromiumOSError(
'Update failed. Timed out waiting for system to mark'
' new kernel as successful.'),
timeout=_KERNEL_UPDATE_TIMEOUT, sleep_interval=5)
# TODO(dalecurtis): Hack for R12 builds to make sure BVT runs of
# platform_Shutdown pass correctly.
if updater.update_version.startswith('0.12'):
self.reboot(timeout=60, wait=True)
# Mark host as recently updated. Hosts are rebooted at the end of
# every test cycle which will remove the file.
self.run('touch %s' % _JUST_UPDATED_FLAG)
# Clean up any old autotest directories which may be lying around.
for path in global_config.global_config.get_config_value(
'AUTOSERV', 'client_autodir_paths', type=list):
self.run('rm -rf ' + path)
def has_just_updated(self):
"""Indicates whether the host was updated within this boot."""
# Check for the existence of the just updated flag file.
return self.run(
'[ -f %s ] && echo T || echo F'
% _JUST_UPDATED_FLAG).stdout.strip() == 'T'
def cleanup(self):
"""Special cleanup method to make sure hosts always get power back."""
super(ChromiumOSHost, self).cleanup()
remote_power = site_remote_power.RemotePower(self.hostname)
if remote_power:
remote_power.set_power_on()
def verify(self):
"""Override to ensure only our version of verify_software() is run."""
self.verify_hardware()
self.verify_connectivity()
self.__verify_software()
def __verify_software(self):
"""Ensure the stateful partition has space for Autotest and updates.
Similar to what is done by AbstractSSH, except instead of checking the
Autotest installation path, just check the stateful partition.
Checking the stateful partition is preferable in case it has been wiped,
resulting in an Autotest installation path which doesn't exist and isn't
writable. We still want to pass verify in this state since the partition
will be recovered with the next install.
"""
super(ChromiumOSHost, self).verify_software()
self.check_diskspace(
'/mnt/stateful_partition',
global_config.global_config.get_config_value(
'SERVER', 'gb_diskspace_required', type=int,
default=20))