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