| # Copyright 2016 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. |
| |
| import logging |
| |
| from autotest_lib.client.common_lib import error |
| from autotest_lib.client.common_lib import global_config |
| from autotest_lib.server import afe_utils |
| from autotest_lib.server import test |
| from autotest_lib.server.hosts import testbed |
| |
| |
| _CONFIG = global_config.global_config |
| # pylint: disable-msg=E1120 |
| _IMAGE_URL_PATTERN = _CONFIG.get_config_value( |
| 'ANDROID', 'image_url_pattern', type=str) |
| |
| |
| class provision_AndroidUpdate(test.test): |
| """A test that can provision a machine to the correct Android version.""" |
| version = 1 |
| |
| def initialize(self, host, value, force=False, is_test_na=False, |
| repair=False): |
| """Initialize. |
| |
| @param host: The host object to update to |value|. |
| @param value: String of the image we want to install on the host. |
| @param force: not used by initialize. |
| @param is_test_na: boolean, if True, will simply skip the test |
| and emit TestNAError. The control file |
| determines whether the test should be skipped |
| and passes the decision via this argument. Note |
| we can't raise TestNAError in control file as it won't |
| be caught and handled properly. |
| @param repair: not used by initialize. |
| """ |
| if is_test_na: |
| raise error.TestNAError('Provisioning not applicable.') |
| # We check value in initialize so that it fails faster. |
| if not (value or repair): |
| raise error.TestFail('No build version specified.') |
| |
| |
| def run_once(self, host, value=None, force=False, repair=False, board=None, |
| os=None): |
| """The method called by the control file to start the test. |
| |
| @param host: The host object to update to |value|. |
| @param value: The host object to provision with a build corresponding |
| to |value|. |
| @param force: True iff we should re-provision the machine regardless of |
| the current image version. If False and the image |
| version matches our expected image version, no |
| provisioning will be done. |
| @param repair: If True, we are doing a repair provision, therefore the |
| build to provision is looked up from the AFE's |
| get_stable_version RPC. |
| @param board: Board name of the device. For host created in testbed, |
| it does not have host labels and attributes. Therefore, |
| the board name needs to be passed in from the testbed |
| repair call. |
| @param os: OS of the device. For host created in testbed, it does not |
| have host labels and attributes. Therefore, the OS needs to |
| be passed in from the testbed repair call. |
| |
| """ |
| logging.debug('Start provisioning %s to %s', host, value) |
| |
| if not value and not repair: |
| raise error.TestFail('No build provided and this is not a repair ' |
| ' job.') |
| |
| info = host.host_info_store.get() |
| # If the host is already on the correct build, we have nothing to do. |
| if not force and info.build == value: |
| # We can't raise a TestNA, as would make sense, as that makes |
| # job.run_test return False as if the job failed. However, it'd |
| # still be nice to get this into the status.log, so we manually |
| # emit an INFO line instead. |
| self.job.record('INFO', None, None, |
| 'Host already running %s' % value) |
| return |
| |
| board = board or info.board |
| os = os or info.os |
| logging.debug('Host %s is board type: %s, OS type: %s', host, board, os) |
| if repair: |
| # TODO(kevcheng): remove the board.split() line when all android |
| # devices have their board label updated to have no android in |
| # there. |
| board = board.split('-')[-1] |
| value = afe_utils.get_stable_android_version(board) |
| if not value: |
| raise error.TestFail('No stable version assigned for board: ' |
| '%s' % board) |
| logging.debug('Stable version found for board %s: %s', board, value) |
| |
| if not isinstance(host, testbed.TestBed): |
| url, _ = host.stage_build_for_install(value, os_type=os) |
| logging.debug('Installing image from: %s', url) |
| args = {'build_url': url, 'os_type': os} |
| else: |
| logging.debug('Installing image: %s', value) |
| args = {'image': value} |
| try: |
| afe_utils.machine_install_and_update_labels( |
| host, **args) |
| except error.InstallError as e: |
| logging.error(e) |
| raise error.TestFail(str(e)) |
| logging.debug('Finished provisioning %s to %s', host, value) |