blob: d78bb67b6d5021b45ed261691632bf2640ccb223 [file] [log] [blame]
Chris Masone8abb6fc2012-01-31 09:27:36 -08001# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Dale Curtis386eea72011-09-21 18:43:04 -07002# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
Chris Masone8abb6fc2012-01-31 09:27:36 -08005import logging
Eric Lia11a0452010-01-07 22:01:58 -08006import os
Christopher Wiley809301c2013-07-02 18:00:31 -07007import tempfile
Alex Miller4f341702013-03-25 12:39:12 -07008import urllib2
Christopher Wiley809301c2013-07-02 18:00:31 -07009
Chris Sosa3ee5d5c2012-02-23 11:18:41 -080010from autotest_lib.client.common_lib import error, global_config
Scott Zawalskieadbf702013-03-14 09:23:06 -040011from autotest_lib.client.common_lib.cros import dev_server
Chris Masone8abb6fc2012-01-31 09:27:36 -080012from autotest_lib.server import installable_object, autoserv_parser
Dan Shi82997b92015-05-06 12:08:02 -070013from autotest_lib.server import utils as server_utils
Scott Zawalskieadbf702013-03-14 09:23:06 -040014from autotest_lib.server.cros.dynamic_suite import tools
Chris Masone44e4d6c2012-08-15 14:25:53 -070015from autotest_lib.server.cros.dynamic_suite.constants import JOB_REPO_URL
Eric Li2eb800f2011-04-21 16:52:58 -070016
17
Chris Masone44e4d6c2012-08-15 14:25:53 -070018_CONFIG = global_config.global_config
19_PARSER = autoserv_parser.autoserv_parser
Eric Li2eb800f2011-04-21 16:52:58 -070020
Eric Lia11a0452010-01-07 22:01:58 -080021
22class SiteAutotest(installable_object.InstallableObject):
Dan Shib669cbd2013-09-13 11:17:17 -070023 """Site implementation of Autotest."""
Eric Lia11a0452010-01-07 22:01:58 -080024
Chris Sosa3ee5d5c2012-02-23 11:18:41 -080025 def get(self, location=None):
Eric Lia11a0452010-01-07 22:01:58 -080026 if not location:
27 location = os.path.join(self.serverdir, '../client')
28 location = os.path.abspath(location)
29 installable_object.InstallableObject.get(self, location)
30 self.got = True
31
Eric Lic7444bd2011-02-15 17:12:10 -080032
Chris Masone8abb6fc2012-01-31 09:27:36 -080033 def _get_fetch_location_from_host_attribute(self):
34 """Get repo to use for packages from host attribute, if possible.
35
36 Hosts are tagged with an attribute containing the URL
37 from which to source packages when running a test on that host.
38 If self.host is set, attempt to look this attribute up by calling out
39 to the AFE.
40
41 @returns value of the 'job_repo_url' host attribute, if present.
42 """
43 try:
Dan Shi349a33c2016-03-16 23:57:21 -070044 from autotest_lib.server.cros.dynamic_suite import frontend_wrappers
Chris Masone8abb6fc2012-01-31 09:27:36 -080045 if self.host:
Dan Shi349a33c2016-03-16 23:57:21 -070046 afe = frontend_wrappers.RetryingAFE(timeout_min=5, delay_sec=10)
Chris Masone8abb6fc2012-01-31 09:27:36 -080047 hosts = afe.get_hosts(hostname=self.host.hostname)
Chris Masone44e4d6c2012-08-15 14:25:53 -070048 if hosts and JOB_REPO_URL in hosts[0].attributes:
Dan Shi349a33c2016-03-16 23:57:21 -070049 logging.info('Get job repo url from host attributes: %s',
50 hosts[0].attributes[JOB_REPO_URL])
Chris Masone44e4d6c2012-08-15 14:25:53 -070051 return hosts[0].attributes[JOB_REPO_URL]
52 logging.warning("No %s for %s", JOB_REPO_URL, self.host)
Alex Miller4f341702013-03-25 12:39:12 -070053 except (ImportError, urllib2.URLError):
Chris Masone44e4d6c2012-08-15 14:25:53 -070054 logging.warning('Not attempting to look for %s', JOB_REPO_URL)
Chris Masone8abb6fc2012-01-31 09:27:36 -080055 pass
56 return None
57
58
Eric Li2eb800f2011-04-21 16:52:58 -070059 def get_fetch_location(self):
Chris Masone8abb6fc2012-01-31 09:27:36 -080060 """Generate list of locations where autotest can look for packages.
61
62 Old n' busted: Autotest packages are always stored at a URL that can
63 be derived from the one passed via the voodoo magic --image argument.
64 New hotness: Hosts are tagged with an attribute containing the URL
65 from which to source packages when running a test on that host.
66
67 @returns the list of candidate locations to check for packages.
68 """
Dale Curtis386eea72011-09-21 18:43:04 -070069 repos = super(SiteAutotest, self).get_fetch_location()
Chris Masone8abb6fc2012-01-31 09:27:36 -080070
Chris Masone44e4d6c2012-08-15 14:25:53 -070071 if _PARSER.options.image:
Scott Zawalskieadbf702013-03-14 09:23:06 -040072 image_opt = _PARSER.options.image
73 if image_opt.startswith('http://'):
74 # A devserver HTTP url was specified, set that as the repo_url.
75 repos.append(image_opt.replace(
joychen03eaad92013-06-26 09:55:21 -070076 'update', 'static').rstrip('/') + '/autotest')
Scott Zawalskieadbf702013-03-14 09:23:06 -040077 else:
78 # An image_name like stumpy-release/R27-3437.0.0 was specified,
79 # set this as the repo_url for the host. If an AFE is not being
80 # run, this will ensure that the installed build uses the
81 # associated artifacts for the test specified when running
82 # autoserv with --image. However, any subsequent tests run on
83 # the host will no longer have the context of the image option
84 # and will revert back to utilizing test code/artifacts that are
85 # currently present in the users source checkout.
Dan Shi69b9b972016-04-15 23:19:57 -070086 # devserver selected must be in the same subnet of self.host, if
87 # the host is in restricted subnet. Otherwise, host may not be
88 # able to reach the devserver and download packages from the
89 # repo_url.
90 hostname = self.host.hostname if self.host else None
91 devserver_url = dev_server.ImageServer.resolve(
92 image_opt, hostname).url()
Scott Zawalskieadbf702013-03-14 09:23:06 -040093 repo_url = tools.get_package_url(devserver_url, image_opt)
94 repos.append(repo_url)
Dan Shi82997b92015-05-06 12:08:02 -070095 elif not server_utils.is_inside_chroot():
96 # Only try to get fetch location from host attribute if the test
97 # is not running inside chroot.
Scott Zawalskieadbf702013-03-14 09:23:06 -040098 # No --image option was specified, look for the repo url via
99 # the host attribute. If we are not running with a full AFE
100 # autoserv will fall back to serving packages itself from whatever
101 # source version it is sync'd to rather than using the proper
102 # artifacts for the build on the host.
Chris Masonebe78eb02012-02-23 14:28:19 -0800103 found_repo = self._get_fetch_location_from_host_attribute()
104 if found_repo is not None:
105 # Add our new repo to the end, the package manager will
106 # later reverse the list of repositories resulting in ours
107 # being first
108 repos.append(found_repo)
Eric Li2eb800f2011-04-21 16:52:58 -0700109
Dale Curtis386eea72011-09-21 18:43:04 -0700110 return repos
Eric Li2eb800f2011-04-21 16:52:58 -0700111
112
Dan Shib669cbd2013-09-13 11:17:17 -0700113 def install(self, host=None, autodir=None, use_packaging=True):
Chris Masone8abb6fc2012-01-31 09:27:36 -0800114 """Install autotest. If |host| is not None, stores it in |self.host|.
115
116 @param host A Host instance on which autotest will be installed
117 @param autodir Location on the remote host to install to
Dan Shib669cbd2013-09-13 11:17:17 -0700118 @param use_packaging Enable install modes that use the packaging system.
119
Chris Masone8abb6fc2012-01-31 09:27:36 -0800120 """
121 if host:
122 self.host = host
123
Dan Shib669cbd2013-09-13 11:17:17 -0700124 super(SiteAutotest, self).install(host=host, autodir=autodir,
125 use_packaging=use_packaging)
Chris Masone8abb6fc2012-01-31 09:27:36 -0800126
127
Christopher Wiley809301c2013-07-02 18:00:31 -0700128 def _install(self, host=None, autodir=None, use_autoserv=True,
129 use_packaging=True):
130 """
131 Install autotest. If get() was not called previously, an
132 attempt will be made to install from the autotest svn
133 repository.
134
135 @param host A Host instance on which autotest will be installed
136 @param autodir Location on the remote host to install to
137 @param use_autoserv Enable install modes that depend on the client
138 running with the autoserv harness
139 @param use_packaging Enable install modes that use the packaging system
140
141 @exception AutoservError if a tarball was not specified and
142 the target host does not have svn installed in its path
143 """
144 # TODO(milleral): http://crbug.com/258161
145 super(SiteAutotest, self)._install(host, autodir, use_autoserv,
146 use_packaging)
147 # Send over the most recent global_config.ini after installation if one
148 # is available.
149 # This code is a bit duplicated from
150 # _BaseRun._create_client_config_file, but oh well.
151 if self.installed and self.source_material:
152 logging.info('Installing updated global_config.ini.')
153 destination = os.path.join(self.host.get_autodir(),
154 'global_config.ini')
155 with tempfile.NamedTemporaryFile() as client_config:
156 config = global_config.global_config
157 client_section = config.get_section_values('CLIENT')
158 client_section.write(client_config)
159 client_config.flush()
160 self.host.send_file(client_config.name, destination)
161
162
Chris Sosaf4d43ff2012-10-30 11:21:05 -0700163 def run_static_method(self, module, method, results_dir='.', host=None,
164 *args):
165 """Runs a non-instance method with |args| from |module| on the client.
166
167 This method runs a static/class/module autotest method on the client.
168 For example:
169 run_static_method("autotest_lib.client.cros.cros_ui", "reboot")
170
171 Will run autotest_lib.client.cros.cros_ui.reboot() on the client.
172
173 @param module: module name as you would refer to it when importing in a
174 control file. e.g. autotest_lib.client.common_lib.module_name.
175 @param method: the method you want to call.
176 @param results_dir: A str path where the results should be stored
177 on the local filesystem.
178 @param host: A Host instance on which the control file should
179 be run.
180 @param args: args to pass to the method.
181 """
182 control = "\n".join(["import %s" % module,
183 "%s.%s(%s)\n" % (module, method,
184 ','.join(map(repr, args)))])
185 self.run(control, results_dir=results_dir, host=host)
186
187
Chris Sosa3ee5d5c2012-02-23 11:18:41 -0800188class SiteClientLogger(object):
189 """Overrides default client logger to allow for using a local package cache.
190 """
191
192 def _process_line(self, line):
193 """Returns the package checksum file if it exists."""
194 logging.debug(line)
195 fetch_package_match = self.fetch_package_parser.search(line)
196 if fetch_package_match:
197 pkg_name, dest_path, fifo_path = fetch_package_match.groups()
Chris Masone44e4d6c2012-08-15 14:25:53 -0700198 serve_packages = _CONFIG.get_config_value(
Chris Sosa3ee5d5c2012-02-23 11:18:41 -0800199 "PACKAGES", "serve_packages_from_autoserv", type=bool)
200 if serve_packages and pkg_name == 'packages.checksum':
Chris Sosa3ee5d5c2012-02-23 11:18:41 -0800201 try:
202 checksum_file = os.path.join(
203 self.job.pkgmgr.pkgmgr_dir, 'packages', pkg_name)
204 if os.path.exists(checksum_file):
205 self.host.send_file(checksum_file, dest_path)
Chris Sosa3ee5d5c2012-02-23 11:18:41 -0800206 except error.AutoservRunError:
207 msg = "Package checksum file not found, continuing anyway"
208 logging.exception(msg)
209
Chris Sosa2cc4da02012-07-09 16:18:24 -0700210 try:
211 # When fetching a package, the client expects to be
212 # notified when the fetching is complete. Autotest
213 # does this pushing a B to a fifo queue to the client.
214 self.host.run("echo B > %s" % fifo_path)
215 except error.AutoservRunError:
216 msg = "Checksum installation failed, continuing anyway"
217 logging.exception(msg)
218 finally:
219 return
Chris Sosa3ee5d5c2012-02-23 11:18:41 -0800220
221 # Fall through to process the line using the default method.
222 super(SiteClientLogger, self)._process_line(line)
223
224
225 def _send_tarball(self, pkg_name, remote_dest):
226 """Uses tarballs in package manager by default."""
227 try:
228 server_package = os.path.join(self.job.pkgmgr.pkgmgr_dir,
229 'packages', pkg_name)
230 if os.path.exists(server_package):
231 self.host.send_file(server_package, remote_dest)
232 return
233
234 except error.AutoservRunError:
235 msg = ("Package %s could not be sent from the package cache." %
236 pkg_name)
237 logging.exception(msg)
238
239 # Fall through to send tarball the default method.
240 super(SiteClientLogger, self)._send_tarball(pkg_name, remote_dest)
241
242
Eric Lic7444bd2011-02-15 17:12:10 -0800243class _SiteRun(object):
244 pass