• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2019 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5
6""" The autotest performing Cr50 update to the TOT image."""
7
8
9import logging
10import os
11import re
12
13from autotest_lib.client.common_lib.cros import cr50_utils
14from autotest_lib.client.common_lib import error
15from autotest_lib.server import utils
16from autotest_lib.server.cros import filesystem_util, gsutil_wrapper
17from autotest_lib.server.cros.faft.firmware_test import FirmwareTest
18
19
20# TOT cr50 images are built as part of the reef image builder.
21BUILDER = 'reef'
22GS_URL = 'gs://chromeos-releases/dev-channel/' + BUILDER
23# Firmware artifacts are stored in files like this.
24#   ChromeOS-firmware-R79-12519.0.0-reef.tar.bz2
25FIRMWARE_NAME = 'ChromeOS-firmware-%s-%s.tar.bz2'
26REMOTE_TMPDIR = '/tmp/cr50_tot_update'
27CR50_IMAGE_PATH = 'cr50/ec.bin'
28# Wait 10 seconds for the update to take effect.
29class provision_Cr50TOT(FirmwareTest):
30    """Update cr50 to TOT.
31
32    The reef builder builds cr50. Fetch the image from the latest reef build
33    and update cr50 to that image. This expects that the DUT is running node
34    locked RO.
35    """
36    version = 1
37
38    def get_latest_builds(self, board='reef-release',
39                          bucket='chromeos-image-archive',
40                          num_builds=5):
41        """Gets the latest build for the given board.
42
43        Args:
44          board: The board for which the latest build needs to be fetched.
45          bucket: The GS bucket name.
46          num_builds: Number of builds to return.
47
48        Raises:
49          error.TestFail() if the List() method is unable to retrieve the
50              contents of the path gs://<bucket>/<board> for any reason.
51        """
52        path = 'gs://%s/%s' % (bucket, board)
53        cmd = 'gsutil ls -- %s' % path
54        try:
55            contents = utils.system_output(cmd).splitlines()
56            latest_contents = contents[(num_builds * -1):]
57            latest_builds = []
58            for content in latest_contents:
59                latest_builds.append(content.strip(path).strip('/'))
60            latest_builds.reverse()
61            logging.info('Checking latest builds %s', latest_builds)
62            return latest_builds
63        except Exception as e:
64            raise error.TestFail('Could not determine the latest build due '
65                                 'to exception: %s' % e)
66
67    def get_cr50_build(self, latest_ver, remote_dir):
68        """Download the TOT cr50 image from the reef artifacts."""
69        bucket = os.path.join(GS_URL, latest_ver.split('-')[-1])
70        filename = FIRMWARE_NAME % (latest_ver, BUILDER)
71        logging.info('Using cr50 image from %s', latest_ver)
72
73        # Download the firmware artifacts from google storage.
74        gsutil_wrapper.copy_private_bucket(host=self.host,
75                                           bucket=bucket,
76                                           filename=filename,
77                                           destination=remote_dir)
78
79        # Extract the cr50 image.
80        dut_path = os.path.join(remote_dir, filename)
81        result = self.host.run('tar xfv %s -C %s' % (dut_path, remote_dir))
82        return os.path.join(remote_dir, CR50_IMAGE_PATH)
83
84
85    def get_latest_cr50_build(self):
86        self.host.run('mkdir -p %s' % (REMOTE_TMPDIR))
87        latest_builds = self.get_latest_builds()
88        for latest_build in latest_builds:
89            try:
90                return self.get_cr50_build(latest_build, REMOTE_TMPDIR)
91            except Exception as e:
92                logging.warn('Unable to find %s cr50 image %s', latest_build, e)
93        raise error.TestFail('Unable to find latest cr50 image in %s' %
94                             latest_builds)
95
96
97    def get_bin_version(self, dut_path):
98        """Get the cr50 version from the image."""
99        find_ver_cmd = 'grep -a cr50_v.*tpm2 %s' % dut_path
100        version_output = self.host.run(find_ver_cmd).stdout.strip()
101        return re.findall('cr50_v\S+\s', version_output)[0].strip()
102
103
104    def run_once(self, host, force=False):
105        """Update cr50 to the TOT image from the reef builder."""
106        # TODO(mruthven): remove once the test is successfully scheduled.
107        logging.info('SUCCESSFULLY SCHEDULED PROVISION CR50 TOT UPDATE')
108        if not force:
109            logging.info('skipping update')
110            return
111        logging.info('cr50 version %s', host.servo.get('cr50_version'))
112        self.host = host
113        cr50_path = self.get_latest_cr50_build()
114        logging.info('cr50 image is at %s', cr50_path)
115        local_path = os.path.join(self.resultsdir, 'cr50.bin.tot')
116        self.host.get_file(cr50_path, local_path)
117        expected_version = self.get_bin_version(cr50_path)
118
119        cr50_utils.GSCTool(self.host, ['-a', cr50_path])
120
121        self.cr50.wait_for_reboot(
122                timeout=self.faft_config.gsc_update_wait_for_reboot)
123        cr50_version = self.cr50.get_active_version_info()[3].split('/')[-1]
124        logging.info('Cr50 running %s. Expected %s', cr50_version,
125                     expected_version)
126        # TODO(mruthven): Decide if failing to update should be a provisioning
127        # failure. Raising a failure will prevent the suite from running. See
128        # how often it fails and why.
129        if cr50_version.split('/')[-1] != expected_version:
130            logging.info('Unable to udpate Cr50.')
131        filesystem_util.make_rootfs_writable(self.host)
132        cr50_utils.InstallImage(self.host, local_path, cr50_utils.CR50_PREPVT)
133