Home | History | Annotate | Download | only in provision_TestbedUpdate
      1 # Copyright 2016 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 import logging
      6 import sys
      7 
      8 from autotest_lib.client.common_lib import error
      9 from autotest_lib.server import afe_utils
     10 from autotest_lib.server import test
     11 
     12 
     13 class provision_TestbedUpdate(test.test):
     14     """A test that can provision a machine to the correct Android version."""
     15     version = 1
     16 
     17     def _builds_to_set(self, builds):
     18         """Helper function to convert a build string into a set of builds.
     19 
     20         @param builds: Testbed build string to convert into a set.
     21 
     22         @returns: A set of the different builds in the build string.
     23         """
     24         result = set()
     25         if not builds:
     26             return result
     27         builds = builds.split(',')
     28         for build in builds:
     29             # Remove any build multipliers, i.e. <build>#2
     30             build = build.split('#')[0]
     31             result.add(build)
     32         return result
     33 
     34 
     35     def initialize(self, host, value, force=False, is_test_na=False,
     36                    repair=False):
     37         """Initialize.
     38 
     39         @param host: The testbed object to update to |value|.
     40                      NOTE: This arg must be called host to align with the other
     41                            provision actions.
     42         @param value: String of the image we want to install on the testbed.
     43         @param force: not used by initialize.
     44         @param is_test_na: boolean, if True, will simply skip the test
     45                            and emit TestNAError. The control file
     46                            determines whether the test should be skipped
     47                            and passes the decision via this argument. Note
     48                            we can't raise TestNAError in control file as it won't
     49                            be caught and handled properly.
     50         @param repair: not used by initialize.
     51         """
     52         if is_test_na:
     53             raise error.TestNAError('Provisioning not applicable.')
     54         # We check value in initialize so that it fails faster.
     55         if not (value or repair):
     56             raise error.TestFail('No build version specified.')
     57 
     58 
     59     def run_once(self, host, value=None, force=False, repair=False):
     60         """The method called by the control file to start the test.
     61 
     62         @param host: The testbed object to update to |value|.
     63                      NOTE: This arg must be called host to align with the other
     64                            provision actions.
     65         @param value: The testbed object to provision with a build
     66                       corresponding to |value|.
     67         @param force: True iff we should re-provision the machine regardless of
     68                       the current image version.  If False and the image
     69                       version matches our expected image version, no
     70                       provisioning will be done.
     71         @param repair: Not yet supported for testbeds.
     72 
     73         """
     74         testbed = host
     75         logging.debug('Start provisioning %s to %s', testbed, value)
     76 
     77         if not value and not repair:
     78             raise error.TestFail('No build provided and this is not a repair '
     79                                  ' job.')
     80 
     81         if not force:
     82             info = testbed.host_info_store.get()
     83             # If the host is already on the correct build, we have nothing to
     84             # do.
     85             if self._builds_to_set(info.build) == self._builds_to_set(value):
     86                 # We can't raise a TestNA, as would make sense, as that makes
     87                 # job.run_test return False as if the job failed.  However, it'd
     88                 # still be nice to get this into the status.log, so we manually
     89                 # emit an INFO line instead.
     90                 self.job.record('INFO', None, None,
     91                                 'Testbed already running %s' % value)
     92                 return
     93 
     94         try:
     95             afe_utils.machine_install_and_update_labels(
     96                     host, image=value)
     97         except error.InstallError as e:
     98             logging.error(e)
     99             raise error.TestFail, str(e), sys.exc_info()[2]
    100         logging.debug('Finished provisioning %s to %s', host, value)
    101