| # Copyright 2019 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. |
| |
| |
| """ The autotest performing Cr50 update to the TOT image.""" |
| |
| |
| import logging |
| import os |
| import re |
| |
| from autotest_lib.client.common_lib.cros import cr50_utils |
| from autotest_lib.client.common_lib import error |
| from autotest_lib.server import utils |
| from autotest_lib.server.cros import filesystem_util, gsutil_wrapper |
| from autotest_lib.server.cros.faft.firmware_test import FirmwareTest |
| |
| |
| # TOT cr50 images are built as part of the reef image builder. |
| BUILDER = 'reef' |
| GS_URL = 'gs://chromeos-releases/dev-channel/' + BUILDER |
| # Firmware artifacts are stored in files like this. |
| # ChromeOS-firmware-R79-12519.0.0-reef.tar.bz2 |
| FIRMWARE_NAME = 'ChromeOS-firmware-%s-%s.tar.bz2' |
| REMOTE_TMPDIR = '/tmp/cr50_tot_update' |
| CR50_IMAGE_PATH = 'cr50/ec.bin' |
| # Wait 10 seconds for the update to take effect. |
| class provision_Cr50TOT(FirmwareTest): |
| """Update cr50 to TOT. |
| |
| The reef builder builds cr50. Fetch the image from the latest reef build |
| and update cr50 to that image. This expects that the DUT is running node |
| locked RO. |
| """ |
| version = 1 |
| |
| def get_latest_builds(self, board='reef-release', |
| bucket='chromeos-image-archive', |
| num_builds=5): |
| """Gets the latest build for the given board. |
| |
| Args: |
| board: The board for which the latest build needs to be fetched. |
| bucket: The GS bucket name. |
| num_builds: Number of builds to return. |
| |
| Raises: |
| error.TestFail() if the List() method is unable to retrieve the |
| contents of the path gs://<bucket>/<board> for any reason. |
| """ |
| path = 'gs://%s/%s' % (bucket, board) |
| cmd = 'gsutil ls -- %s' % path |
| try: |
| contents = utils.system_output(cmd).splitlines() |
| latest_contents = contents[(num_builds * -1):] |
| latest_builds = [] |
| for content in latest_contents: |
| latest_builds.append(content.strip(path).strip('/')) |
| latest_builds.reverse() |
| logging.info('Checking latest builds %s', latest_builds) |
| return latest_builds |
| except Exception as e: |
| raise error.TestFail('Could not determine the latest build due ' |
| 'to exception: %s' % e) |
| |
| def get_cr50_build(self, latest_ver, remote_dir): |
| """Download the TOT cr50 image from the reef artifacts.""" |
| bucket = os.path.join(GS_URL, latest_ver.split('-')[-1]) |
| filename = FIRMWARE_NAME % (latest_ver, BUILDER) |
| logging.info('Using cr50 image from %s', latest_ver) |
| |
| # Download the firmware artifacts from google storage. |
| gsutil_wrapper.copy_private_bucket(host=self.host, |
| bucket=bucket, |
| filename=filename, |
| destination=remote_dir) |
| |
| # Extract the cr50 image. |
| dut_path = os.path.join(remote_dir, filename) |
| result = self.host.run('tar xfv %s -C %s' % (dut_path, remote_dir)) |
| return os.path.join(remote_dir, CR50_IMAGE_PATH) |
| |
| |
| def get_latest_cr50_build(self): |
| self.host.run('mkdir -p %s' % (REMOTE_TMPDIR)) |
| latest_builds = self.get_latest_builds() |
| for latest_build in latest_builds: |
| try: |
| return self.get_cr50_build(latest_build, REMOTE_TMPDIR) |
| except Exception as e: |
| logging.warn('Unable to find %s cr50 image %s', latest_build, e) |
| raise error.TestFail('Unable to find latest cr50 image in %s' % |
| latest_builds) |
| |
| |
| def get_bin_version(self, dut_path): |
| """Get the cr50 version from the image.""" |
| find_ver_cmd = 'grep -a cr50_v.*tpm2 %s' % dut_path |
| version_output = self.host.run(find_ver_cmd).stdout.strip() |
| return re.findall('cr50_v\S+\s', version_output)[0].strip() |
| |
| |
| def run_once(self, host, force=False): |
| """Update cr50 to the TOT image from the reef builder.""" |
| # TODO(mruthven): remove once the test is successfully scheduled. |
| logging.info('SUCCESSFULLY SCHEDULED PROVISION CR50 TOT UPDATE') |
| if not force: |
| logging.info('skipping update') |
| return |
| logging.info('cr50 version %s', host.servo.get('cr50_version')) |
| self.host = host |
| cr50_path = self.get_latest_cr50_build() |
| logging.info('cr50 image is at %s', cr50_path) |
| local_path = os.path.join(self.resultsdir, 'cr50.bin.tot') |
| self.host.get_file(cr50_path, local_path) |
| expected_version = self.get_bin_version(cr50_path) |
| |
| cr50_utils.GSCTool(self.host, ['-a', cr50_path]) |
| |
| self.cr50.wait_for_reboot( |
| timeout=self.faft_config.gsc_update_wait_for_reboot) |
| cr50_version = self.cr50.get_active_version_info()[3].split('/')[-1] |
| logging.info('Cr50 running %s. Expected %s', cr50_version, |
| expected_version) |
| # TODO(mruthven): Decide if failing to update should be a provisioning |
| # failure. Raising a failure will prevent the suite from running. See |
| # how often it fails and why. |
| if cr50_version.split('/')[-1] != expected_version: |
| logging.info('Unable to udpate Cr50.') |
| filesystem_util.make_rootfs_writable(self.host) |
| cr50_utils.InstallImage(self.host, local_path, cr50_utils.CR50_PREPVT) |