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