Home | History | Annotate | Download | only in bin
      1 import os, logging, ConfigParser
      2 from autotest_lib.client.common_lib import autotemp, base_packages, error
      3 from autotest_lib.client.common_lib import global_config
      4 from autotest_lib.client.bin import harness
      5 
      6 
      7 class harness_autoserv(harness.harness):
      8     """
      9     The server harness for running from autoserv
     10 
     11     Properties:
     12             job
     13                     The job object for this job
     14     """
     15 
     16     def __init__(self, job, harness_args):
     17         """
     18                 job
     19                         The job object for this job
     20         """
     21         super(harness_autoserv, self).__init__(job)
     22         self.status = os.fdopen(3, 'w', 0)
     23 
     24         # If a bug on the client run code prevents global_config.ini
     25         # from being copied to the client machine, the client will run
     26         # without a global config, relying only on the defaults of the
     27         # config items. To avoid that happening silently, the check below
     28         # was written.
     29         try:
     30             cfg = global_config.global_config.get_section_values("CLIENT")
     31         except ConfigParser.NoSectionError:
     32             logging.error("Empty CLIENT configuration session. "
     33                           "global_config.ini missing. This probably means "
     34                           "a bug on the server code. Please verify.")
     35 
     36 
     37     def run_start(self):
     38         # set up the package fetcher for direct-from-autoserv fetches
     39         fetcher = AutoservFetcher(self.job.pkgmgr, self)
     40         self.job.pkgmgr.add_repository(fetcher)
     41 
     42 
     43     def _send_and_wait(self, title, *args):
     44         """Send a message to the autoserv and wait for it to signal
     45         completion.
     46 
     47         @param title: An alphanumeric string to title the message.
     48         @param *args: Additional arbitrary alphanumeric arguments to pass
     49                 to the server.
     50         """
     51         # create a named pipe for us to recieve a signal on
     52         fifo_dir = autotemp.tempdir(suffix='-fifo', unique_id='harness',
     53                                     dir=self.job.tmpdir)
     54         try:
     55             fifo_path = os.path.join(fifo_dir.name, 'autoserv.fifo')
     56             os.mkfifo(fifo_path)
     57 
     58             # send signal to the server as title[:args]:path
     59             msg = ':'.join([title] + list(args) + [fifo_path]) + '\n'
     60             self.status.write(msg)
     61 
     62             # wait for the server to signal back to us
     63             fifo = open(fifo_path)
     64             fifo.read(1)
     65             fifo.close()
     66         finally:
     67             fifo_dir.clean()
     68 
     69 
     70     def run_test_complete(self):
     71         """A test run by this job is complete, signal it to autoserv and
     72         wait for it to signal to continue"""
     73         self._send_and_wait('AUTOTEST_TEST_COMPLETE')
     74 
     75 
     76     def test_status(self, status, tag):
     77         """A test within this job is completing"""
     78         for line in status.split('\n'):
     79             # sent status messages with AUTOTEST_STATUS:tag:message
     80             msg = 'AUTOTEST_STATUS:%s:%s\n'
     81             msg %= (tag, line)
     82             self.status.write(msg)
     83 
     84 
     85     def fetch_package(self, pkg_name, dest_path):
     86         """Request a package from the remote autoserv.
     87 
     88         @param pkg_name: The name of the package, as generally used by the
     89                 client.common_lib.packages infrastructure.
     90         @param dest_path: The path the package should be copied to.
     91         """
     92         self._send_and_wait('AUTOTEST_FETCH_PACKAGE', pkg_name, dest_path)
     93 
     94 
     95 class AutoservFetcher(base_packages.RepositoryFetcher):
     96     def __init__(self, package_manager, job_harness):
     97         self.url = "autoserv://"
     98         self.job_harness = job_harness
     99 
    100 
    101     def fetch_pkg_file(self, filename, dest_path):
    102         if os.path.exists(dest_path):
    103             os.remove(dest_path)
    104 
    105         if not global_config.global_config.get_config_value(
    106                 'CLIENT', 'fetch_from_autoserv', type=bool, default=True):
    107             # In order to preserve autotest semantics, we treat this as a
    108             # PackageFetchError rather than a success or not including the
    109             # fetcher: see crosbug.com/35080.
    110             logging.error('Not fetching %s from autoserv.', filename)
    111             raise error.PackageFetchError(
    112                     '%s not fetched from autoserv as fetching from autoserv is '
    113                     'disabled.' % filename)
    114 
    115         logging.info('Fetching %s from autoserv to %s.', filename, dest_path)
    116         self.job_harness.fetch_package(filename, dest_path)
    117         if os.path.exists(dest_path):
    118             logging.debug('Successfully fetched %s from autoserv.', filename)
    119         else:
    120             raise error.PackageFetchError('%s not fetched from autoserv.'
    121                                           % filename)
    122