xref: /aosp_15_r20/external/autotest/client/bin/harness_autoserv.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
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