OLD | NEW |
| (Empty) |
1 import time, os, sys, urllib, re, signal, logging, datetime, glob, ConfigParser | |
2 import shutil | |
3 from autotest_lib.client.bin import utils, test, os_dep | |
4 from autotest_lib.client.common_lib import error | |
5 import kvm_utils | |
6 | |
7 | |
8 def check_configure_options(script_path): | |
9 """ | |
10 Return the list of available options (flags) of a given kvm configure build | |
11 script. | |
12 | |
13 @param script: Path to the configure script | |
14 """ | |
15 abspath = os.path.abspath(script_path) | |
16 help_raw = utils.system_output('%s --help' % abspath, ignore_status=True) | |
17 help_output = help_raw.split("\n") | |
18 option_list = [] | |
19 for line in help_output: | |
20 cleaned_line = line.lstrip() | |
21 if cleaned_line.startswith("--"): | |
22 option = cleaned_line.split()[0] | |
23 option = option.split("=")[0] | |
24 option_list.append(option) | |
25 | |
26 return option_list | |
27 | |
28 | |
29 def kill_qemu_processes(): | |
30 """ | |
31 Kills all qemu processes, also kills all processes holding /dev/kvm down. | |
32 """ | |
33 logging.debug("Killing any qemu processes that might be left behind") | |
34 utils.system("pkill qemu", ignore_status=True) | |
35 # Let's double check to see if some other process is holding /dev/kvm | |
36 if os.path.isfile("/dev/kvm"): | |
37 utils.system("fuser -k /dev/kvm", ignore_status=True) | |
38 | |
39 | |
40 def cpu_vendor(): | |
41 vendor = "intel" | |
42 if os.system("grep vmx /proc/cpuinfo 1>/dev/null") != 0: | |
43 vendor = "amd" | |
44 logging.debug("Detected CPU vendor as '%s'" %(vendor)) | |
45 return vendor | |
46 | |
47 | |
48 def _unload_kvm_modules(mod_list): | |
49 logging.info("Unloading previously loaded KVM modules") | |
50 for module in reversed(mod_list): | |
51 utils.unload_module(module) | |
52 | |
53 | |
54 def _load_kvm_modules(mod_list, module_dir=None, load_stock=False): | |
55 """ | |
56 Just load the KVM modules, without killing Qemu or unloading previous | |
57 modules. | |
58 | |
59 Load modules present on any sub directory of module_dir. Function will walk | |
60 through module_dir until it finds the modules. | |
61 | |
62 @param module_dir: Directory where the KVM modules are located. | |
63 @param load_stock: Whether we are going to load system kernel modules. | |
64 @param extra_modules: List of extra modules to load. | |
65 """ | |
66 if module_dir: | |
67 logging.info("Loading the built KVM modules...") | |
68 kvm_module_path = None | |
69 kvm_vendor_module_path = None | |
70 abort = False | |
71 | |
72 list_modules = ['%s.ko' % (m) for m in mod_list] | |
73 | |
74 list_module_paths = [] | |
75 for folder, subdirs, files in os.walk(module_dir): | |
76 for module in list_modules: | |
77 if module in files: | |
78 module_path = os.path.join(folder, module) | |
79 list_module_paths.append(module_path) | |
80 | |
81 # We might need to arrange the modules in the correct order | |
82 # to avoid module load problems | |
83 list_modules_load = [] | |
84 for module in list_modules: | |
85 for module_path in list_module_paths: | |
86 if os.path.basename(module_path) == module: | |
87 list_modules_load.append(module_path) | |
88 | |
89 if len(list_module_paths) != len(list_modules): | |
90 logging.error("KVM modules not found. If you don't want to use the " | |
91 "modules built by this test, make sure the option " | |
92 "load_modules: 'no' is marked on the test control " | |
93 "file.") | |
94 raise error.TestError("The modules %s were requested to be loaded, " | |
95 "but the only modules found were %s" % | |
96 (list_modules, list_module_paths)) | |
97 | |
98 for module_path in list_modules_load: | |
99 try: | |
100 utils.system("insmod %s" % module_path) | |
101 except Exception, e: | |
102 raise error.TestFail("Failed to load KVM modules: %s" % e) | |
103 | |
104 if load_stock: | |
105 logging.info("Loading current system KVM modules...") | |
106 for module in mod_list: | |
107 utils.system("modprobe %s" % module) | |
108 | |
109 | |
110 def create_symlinks(test_bindir, prefix=None, bin_list=None, unittest=None): | |
111 """ | |
112 Create symbolic links for the appropriate qemu and qemu-img commands on | |
113 the kvm test bindir. | |
114 | |
115 @param test_bindir: KVM test bindir | |
116 @param prefix: KVM prefix path | |
117 @param bin_list: List of qemu binaries to link | |
118 @param unittest: Path to configuration file unittests.cfg | |
119 """ | |
120 qemu_path = os.path.join(test_bindir, "qemu") | |
121 qemu_img_path = os.path.join(test_bindir, "qemu-img") | |
122 qemu_unittest_path = os.path.join(test_bindir, "unittests") | |
123 if os.path.lexists(qemu_path): | |
124 os.unlink(qemu_path) | |
125 if os.path.lexists(qemu_img_path): | |
126 os.unlink(qemu_img_path) | |
127 if unittest and os.path.lexists(qemu_unittest_path): | |
128 os.unlink(qemu_unittest_path) | |
129 | |
130 logging.debug("Linking qemu binaries") | |
131 | |
132 if bin_list: | |
133 for bin in bin_list: | |
134 if os.path.basename(bin) == 'qemu-kvm': | |
135 os.symlink(bin, qemu_path) | |
136 elif os.path.basename(bin) == 'qemu-img': | |
137 os.symlink(bin, qemu_img_path) | |
138 | |
139 elif prefix: | |
140 kvm_qemu = os.path.join(prefix, "bin", "qemu-system-x86_64") | |
141 if not os.path.isfile(kvm_qemu): | |
142 raise error.TestError('Invalid qemu path') | |
143 kvm_qemu_img = os.path.join(prefix, "bin", "qemu-img") | |
144 if not os.path.isfile(kvm_qemu_img): | |
145 raise error.TestError('Invalid qemu-img path') | |
146 os.symlink(kvm_qemu, qemu_path) | |
147 os.symlink(kvm_qemu_img, qemu_img_path) | |
148 | |
149 if unittest: | |
150 logging.debug("Linking unittest dir") | |
151 os.symlink(unittest, qemu_unittest_path) | |
152 | |
153 | |
154 def install_roms(rom_dir, prefix): | |
155 logging.debug("Path to roms specified. Copying roms to install prefix") | |
156 rom_dst_dir = os.path.join(prefix, 'share', 'qemu') | |
157 for rom_src in glob.glob('%s/*.bin' % rom_dir): | |
158 rom_dst = os.path.join(rom_dst_dir, os.path.basename(rom_src)) | |
159 logging.debug("Copying rom file %s to %s", rom_src, rom_dst) | |
160 shutil.copy(rom_src, rom_dst) | |
161 | |
162 | |
163 def save_build(build_dir, dest_dir): | |
164 logging.debug('Saving the result of the build on %s', dest_dir) | |
165 base_name = os.path.basename(build_dir) | |
166 tarball_name = base_name + '.tar.bz2' | |
167 os.chdir(os.path.dirname(build_dir)) | |
168 utils.system('tar -cjf %s %s' % (tarball_name, base_name)) | |
169 shutil.move(tarball_name, os.path.join(dest_dir, tarball_name)) | |
170 | |
171 | |
172 class KvmInstallException(Exception): | |
173 pass | |
174 | |
175 | |
176 class FailedKvmInstall(KvmInstallException): | |
177 pass | |
178 | |
179 | |
180 class KvmNotInstalled(KvmInstallException): | |
181 pass | |
182 | |
183 | |
184 class BaseInstaller(object): | |
185 # default value for load_stock argument | |
186 load_stock_modules = True | |
187 def __init__(self, mode=None): | |
188 self.install_mode = mode | |
189 self._full_module_list = None | |
190 | |
191 def set_install_params(self, test, params): | |
192 self.params = params | |
193 | |
194 load_modules = params.get('load_modules', 'no') | |
195 if not load_modules or load_modules == 'yes': | |
196 self.should_load_modules = True | |
197 elif load_modules == 'no': | |
198 self.should_load_modules = False | |
199 default_extra_modules = str(None) | |
200 self.extra_modules = eval(params.get("extra_modules", | |
201 default_extra_modules)) | |
202 | |
203 self.cpu_vendor = cpu_vendor() | |
204 | |
205 self.srcdir = test.srcdir | |
206 if not os.path.isdir(self.srcdir): | |
207 os.makedirs(self.srcdir) | |
208 | |
209 self.test_bindir = test.bindir | |
210 self.results_dir = test.resultsdir | |
211 | |
212 # KVM build prefix, for the modes that do need it | |
213 prefix = os.path.join(test.bindir, 'build') | |
214 self.prefix = os.path.abspath(prefix) | |
215 | |
216 # Current host kernel directory | |
217 default_host_kernel_source = '/lib/modules/%s/build' % os.uname()[2] | |
218 self.host_kernel_srcdir = params.get('host_kernel_source', | |
219 default_host_kernel_source) | |
220 | |
221 # Extra parameters that can be passed to the configure script | |
222 self.extra_configure_options = params.get('extra_configure_options', | |
223 None) | |
224 | |
225 # Do we want to save the result of the build on test.resultsdir? | |
226 self.save_results = True | |
227 save_results = params.get('save_results', 'no') | |
228 if save_results == 'no': | |
229 self.save_results = False | |
230 | |
231 self._full_module_list = list(self._module_list()) | |
232 | |
233 | |
234 def full_module_list(self): | |
235 """Return the module list used by the installer | |
236 | |
237 Used by the module_probe test, to avoid using utils.unload_module(). | |
238 """ | |
239 if self._full_module_list is None: | |
240 raise KvmNotInstalled("KVM modules not installed yet (installer: %s)
" % (type(self))) | |
241 return self._full_module_list | |
242 | |
243 | |
244 def _module_list(self): | |
245 """Generate the list of modules that need to be loaded | |
246 """ | |
247 yield 'kvm' | |
248 yield 'kvm-%s' % (self.cpu_vendor) | |
249 if self.extra_modules: | |
250 for module in self.extra_modules: | |
251 yield module | |
252 | |
253 | |
254 def _load_modules(self, mod_list): | |
255 """ | |
256 Load the KVM modules | |
257 | |
258 May be overridden by subclasses. | |
259 """ | |
260 _load_kvm_modules(mod_list, load_stock=self.load_stock_modules) | |
261 | |
262 | |
263 def load_modules(self, mod_list=None): | |
264 if mod_list is None: | |
265 mod_list = self.full_module_list() | |
266 self._load_modules(mod_list) | |
267 | |
268 | |
269 def _unload_modules(self, mod_list=None): | |
270 """ | |
271 Just unload the KVM modules, without trying to kill Qemu | |
272 """ | |
273 if mod_list is None: | |
274 mod_list = self.full_module_list() | |
275 _unload_kvm_modules(mod_list) | |
276 | |
277 | |
278 def unload_modules(self, mod_list=None): | |
279 """ | |
280 Kill Qemu and unload the KVM modules | |
281 """ | |
282 kill_qemu_processes() | |
283 self._unload_modules(mod_list) | |
284 | |
285 | |
286 def reload_modules(self): | |
287 """ | |
288 Reload the KVM modules after killing Qemu and unloading the current modu
les | |
289 """ | |
290 self.unload_modules() | |
291 self.load_modules() | |
292 | |
293 | |
294 def reload_modules_if_needed(self): | |
295 if self.should_load_modules: | |
296 self.reload_modules() | |
297 | |
298 | |
299 class YumInstaller(BaseInstaller): | |
300 """ | |
301 Class that uses yum to install and remove packages. | |
302 """ | |
303 load_stock_modules = True | |
304 def set_install_params(self, test, params): | |
305 super(YumInstaller, self).set_install_params(test, params) | |
306 # Checking if all required dependencies are available | |
307 os_dep.command("rpm") | |
308 os_dep.command("yum") | |
309 | |
310 default_pkg_list = str(['qemu-kvm', 'qemu-kvm-tools']) | |
311 default_qemu_bin_paths = str(['/usr/bin/qemu-kvm', '/usr/bin/qemu-img']) | |
312 default_pkg_path_list = str(None) | |
313 self.pkg_list = eval(params.get("pkg_list", default_pkg_list)) | |
314 self.pkg_path_list = eval(params.get("pkg_path_list", | |
315 default_pkg_path_list)) | |
316 self.qemu_bin_paths = eval(params.get("qemu_bin_paths", | |
317 default_qemu_bin_paths)) | |
318 | |
319 | |
320 def _clean_previous_installs(self): | |
321 kill_qemu_processes() | |
322 removable_packages = "" | |
323 for pkg in self.pkg_list: | |
324 removable_packages += " %s" % pkg | |
325 | |
326 utils.system("yum remove -y %s" % removable_packages) | |
327 | |
328 | |
329 def _get_packages(self): | |
330 for pkg in self.pkg_path_list: | |
331 utils.get_file(pkg, os.path.join(self.srcdir, | |
332 os.path.basename(pkg))) | |
333 | |
334 | |
335 def _install_packages(self): | |
336 """ | |
337 Install all downloaded packages. | |
338 """ | |
339 os.chdir(self.srcdir) | |
340 utils.system("yum install --nogpgcheck -y *.rpm") | |
341 | |
342 | |
343 def install(self): | |
344 self._clean_previous_installs() | |
345 self._get_packages() | |
346 self._install_packages() | |
347 create_symlinks(test_bindir=self.test_bindir, | |
348 bin_list=self.qemu_bin_paths) | |
349 self.reload_modules_if_needed() | |
350 if self.save_results: | |
351 save_build(self.srcdir, self.results_dir) | |
352 | |
353 | |
354 class KojiInstaller(YumInstaller): | |
355 """ | |
356 Class that handles installing KVM from the fedora build service, koji. | |
357 It uses yum to install and remove packages. | |
358 """ | |
359 load_stock_modules = True | |
360 def set_install_params(self, test, params): | |
361 """ | |
362 Gets parameters and initializes the package downloader. | |
363 | |
364 @param test: kvm test object | |
365 @param params: Dictionary with test arguments | |
366 """ | |
367 super(KojiInstaller, self).set_install_params(test, params) | |
368 default_koji_cmd = '/usr/bin/koji' | |
369 default_src_pkg = 'qemu' | |
370 self.src_pkg = params.get("src_pkg", default_src_pkg) | |
371 self.tag = params.get("koji_tag", None) | |
372 self.build = params.get("koji_build", None) | |
373 self.koji_cmd = params.get("koji_cmd", default_koji_cmd) | |
374 | |
375 | |
376 def _get_packages(self): | |
377 """ | |
378 Downloads the specific arch RPMs for the specific build name. | |
379 """ | |
380 downloader = kvm_utils.KojiDownloader(cmd=self.koji_cmd) | |
381 downloader.get(src_package=self.src_pkg, tag=self.tag, | |
382 build=self.build, dst_dir=self.srcdir) | |
383 | |
384 | |
385 def install(self): | |
386 super(KojiInstaller, self)._clean_previous_installs() | |
387 self._get_packages() | |
388 super(KojiInstaller, self)._install_packages() | |
389 create_symlinks(test_bindir=self.test_bindir, | |
390 bin_list=self.qemu_bin_paths) | |
391 self.reload_modules_if_needed() | |
392 if self.save_results: | |
393 save_build(self.srcdir, self.results_dir) | |
394 | |
395 | |
396 class SourceDirInstaller(BaseInstaller): | |
397 """ | |
398 Class that handles building/installing KVM directly from a tarball or | |
399 a single source code dir. | |
400 """ | |
401 def set_install_params(self, test, params): | |
402 """ | |
403 Initializes class attributes, and retrieves KVM code. | |
404 | |
405 @param test: kvm test object | |
406 @param params: Dictionary with test arguments | |
407 """ | |
408 super(SourceDirInstaller, self).set_install_params(test, params) | |
409 | |
410 self.mod_install_dir = os.path.join(self.prefix, 'modules') | |
411 self.installed_kmods = False # it will be set to True in case we | |
412 # installed our own modules | |
413 | |
414 srcdir = params.get("srcdir", None) | |
415 self.path_to_roms = params.get("path_to_rom_images", None) | |
416 | |
417 if self.install_mode == 'localsrc': | |
418 if srcdir is None: | |
419 raise error.TestError("Install from source directory specified" | |
420 "but no source directory provided on the" | |
421 "control file.") | |
422 else: | |
423 shutil.copytree(srcdir, self.srcdir) | |
424 | |
425 if self.install_mode == 'release': | |
426 release_tag = params.get("release_tag") | |
427 release_dir = params.get("release_dir") | |
428 release_listing = params.get("release_listing") | |
429 logging.info("Installing KVM from release tarball") | |
430 if not release_tag: | |
431 release_tag = kvm_utils.get_latest_kvm_release_tag( | |
432 release_listing) | |
433 tarball = os.path.join(release_dir, 'kvm', release_tag, | |
434 "kvm-%s.tar.gz" % release_tag) | |
435 logging.info("Retrieving release kvm-%s" % release_tag) | |
436 tarball = utils.unmap_url("/", tarball, "/tmp") | |
437 | |
438 elif self.install_mode == 'snapshot': | |
439 logging.info("Installing KVM from snapshot") | |
440 snapshot_dir = params.get("snapshot_dir") | |
441 if not snapshot_dir: | |
442 raise error.TestError("Snapshot dir not provided") | |
443 snapshot_date = params.get("snapshot_date") | |
444 if not snapshot_date: | |
445 # Take yesterday's snapshot | |
446 d = (datetime.date.today() - | |
447 datetime.timedelta(1)).strftime("%Y%m%d") | |
448 else: | |
449 d = snapshot_date | |
450 tarball = os.path.join(snapshot_dir, "kvm-snapshot-%s.tar.gz" % d) | |
451 logging.info("Retrieving kvm-snapshot-%s" % d) | |
452 tarball = utils.unmap_url("/", tarball, "/tmp") | |
453 | |
454 elif self.install_mode == 'localtar': | |
455 tarball = params.get("tarball") | |
456 if not tarball: | |
457 raise error.TestError("KVM Tarball install specified but no" | |
458 " tarball provided on control file.") | |
459 logging.info("Installing KVM from a local tarball") | |
460 logging.info("Using tarball %s") | |
461 tarball = utils.unmap_url("/", params.get("tarball"), "/tmp") | |
462 | |
463 if self.install_mode in ['release', 'snapshot', 'localtar']: | |
464 utils.extract_tarball_to_dir(tarball, self.srcdir) | |
465 | |
466 if self.install_mode in ['release', 'snapshot', 'localtar', 'srcdir']: | |
467 self.repo_type = kvm_utils.check_kvm_source_dir(self.srcdir) | |
468 configure_script = os.path.join(self.srcdir, 'configure') | |
469 self.configure_options = check_configure_options(configure_script) | |
470 | |
471 | |
472 def _build(self): | |
473 make_jobs = utils.count_cpus() | |
474 os.chdir(self.srcdir) | |
475 # For testing purposes, it's better to build qemu binaries with | |
476 # debugging symbols, so we can extract more meaningful stack traces. | |
477 cfg = "./configure --prefix=%s" % self.prefix | |
478 if "--disable-strip" in self.configure_options: | |
479 cfg += " --disable-strip" | |
480 steps = [cfg, "make clean", "make -j %s" % make_jobs] | |
481 logging.info("Building KVM") | |
482 for step in steps: | |
483 utils.system(step) | |
484 | |
485 | |
486 def _install_kmods_old_userspace(self, userspace_path): | |
487 """ | |
488 Run the module install command. | |
489 | |
490 This is for the "old userspace" code, that contained a 'kernel' subdirec
tory | |
491 with the kmod build code. | |
492 | |
493 The code would be much simpler if we could specify the module install | |
494 path as parameter to the toplevel Makefile. As we can't do that and | |
495 the module install code doesn't use --prefix, we have to call | |
496 'make -C kernel install' directly, setting the module directory | |
497 parameters. | |
498 | |
499 If the userspace tree doens't have a 'kernel' subdirectory, the | |
500 module install step will be skipped. | |
501 | |
502 @param userspace_path: the path the kvm-userspace directory | |
503 """ | |
504 kdir = os.path.join(userspace_path, 'kernel') | |
505 if os.path.isdir(kdir): | |
506 os.chdir(kdir) | |
507 # INSTALLDIR is the target dir for the modules | |
508 # ORIGMODDIR is the dir where the old modules will be removed. we | |
509 # don't want to mess with the system modules, so set it | |
510 # to a non-existing directory | |
511 utils.system('make install INSTALLDIR=%s ORIGMODDIR=/tmp/no-old-modu
les' % (self.mod_install_dir)) | |
512 self.installed_kmods = True | |
513 | |
514 | |
515 def _install_kmods(self, kmod_path): | |
516 """Run the module install command for the kmod-kvm repository | |
517 | |
518 @param kmod_path: the path to the kmod-kvm.git working copy | |
519 """ | |
520 os.chdir(kmod_path) | |
521 utils.system('make modules_install DESTDIR=%s' % (self.mod_install_dir)) | |
522 self.installed_kmods = True | |
523 | |
524 | |
525 def _install(self): | |
526 os.chdir(self.srcdir) | |
527 logging.info("Installing KVM userspace") | |
528 if self.repo_type == 1: | |
529 utils.system("make -C qemu install") | |
530 self._install_kmods_old_userspace(self.srcdir) | |
531 elif self.repo_type == 2: | |
532 utils.system("make install") | |
533 if self.path_to_roms: | |
534 install_roms(self.path_to_roms, self.prefix) | |
535 create_symlinks(self.test_bindir, self.prefix) | |
536 | |
537 | |
538 def _load_modules(self, mod_list): | |
539 # load the installed KVM modules in case we installed them | |
540 # ourselves. Otherwise, just load the system modules. | |
541 if self.installed_kmods: | |
542 logging.info("Loading installed KVM modules") | |
543 _load_kvm_modules(mod_list, module_dir=self.mod_install_dir) | |
544 else: | |
545 logging.info("Loading stock KVM modules") | |
546 _load_kvm_modules(mod_list, load_stock=True) | |
547 | |
548 | |
549 def install(self): | |
550 self._build() | |
551 self._install() | |
552 self.reload_modules_if_needed() | |
553 if self.save_results: | |
554 save_build(self.srcdir, self.results_dir) | |
555 | |
556 | |
557 class GitInstaller(SourceDirInstaller): | |
558 def _pull_code(self): | |
559 """ | |
560 Retrieves code from git repositories. | |
561 """ | |
562 params = self.params | |
563 | |
564 kernel_repo = params.get("git_repo") | |
565 user_repo = params.get("user_git_repo") | |
566 kmod_repo = params.get("kmod_repo") | |
567 test_repo = params.get("test_git_repo") | |
568 | |
569 kernel_branch = params.get("kernel_branch", "master") | |
570 user_branch = params.get("user_branch", "master") | |
571 kmod_branch = params.get("kmod_branch", "master") | |
572 test_branch = params.get("test_branch", "master") | |
573 | |
574 kernel_lbranch = params.get("kernel_lbranch", "master") | |
575 user_lbranch = params.get("user_lbranch", "master") | |
576 kmod_lbranch = params.get("kmod_lbranch", "master") | |
577 test_lbranch = params.get("test_lbranch", "master") | |
578 | |
579 kernel_commit = params.get("kernel_commit", None) | |
580 user_commit = params.get("user_commit", None) | |
581 kmod_commit = params.get("kmod_commit", None) | |
582 test_commit = params.get("test_commit", None) | |
583 | |
584 kernel_patches = eval(params.get("kernel_patches", "[]")) | |
585 user_patches = eval(params.get("user_patches", "[]")) | |
586 kmod_patches = eval(params.get("user_patches", "[]")) | |
587 | |
588 if not user_repo: | |
589 message = "KVM user git repository path not specified" | |
590 logging.error(message) | |
591 raise error.TestError(message) | |
592 | |
593 userspace_srcdir = os.path.join(self.srcdir, "kvm_userspace") | |
594 kvm_utils.get_git_branch(user_repo, user_branch, userspace_srcdir, | |
595 user_commit, user_lbranch) | |
596 self.userspace_srcdir = userspace_srcdir | |
597 | |
598 if user_patches: | |
599 os.chdir(self.userspace_srcdir) | |
600 for patch in user_patches: | |
601 utils.get_file(patch, os.path.join(self.userspace_srcdir, | |
602 os.path.basename(patch))) | |
603 utils.system('patch -p1 %s' % os.path.basename(patch)) | |
604 | |
605 if test_repo: | |
606 test_srcdir = os.path.join(self.srcdir, "kvm-unit-tests") | |
607 kvm_utils.get_git_branch(test_repo, test_branch, test_srcdir, | |
608 test_commit, test_lbranch) | |
609 unittest_cfg = os.path.join(test_srcdir, 'x86', | |
610 'unittests.cfg') | |
611 self.test_srcdir = test_srcdir | |
612 else: | |
613 unittest_cfg = os.path.join(userspace_srcdir, 'kvm', 'test', 'x86', | |
614 'unittests.cfg') | |
615 | |
616 self.unittest_cfg = None | |
617 if os.path.isfile(unittest_cfg): | |
618 self.unittest_cfg = unittest_cfg | |
619 | |
620 if kernel_repo: | |
621 kernel_srcdir = os.path.join(self.srcdir, "kvm") | |
622 kvm_utils.get_git_branch(kernel_repo, kernel_branch, kernel_srcdir, | |
623 kernel_commit, kernel_lbranch) | |
624 self.kernel_srcdir = kernel_srcdir | |
625 if kernel_patches: | |
626 os.chdir(self.kernel_srcdir) | |
627 for patch in kernel_patches: | |
628 utils.get_file(patch, os.path.join(self.userspace_srcdir, | |
629 os.path.basename(patch))) | |
630 utils.system('patch -p1 %s' % os.path.basename(patch)) | |
631 else: | |
632 self.kernel_srcdir = None | |
633 | |
634 if kmod_repo: | |
635 kmod_srcdir = os.path.join (self.srcdir, "kvm_kmod") | |
636 kvm_utils.get_git_branch(kmod_repo, kmod_branch, kmod_srcdir, | |
637 kmod_commit, kmod_lbranch) | |
638 self.kmod_srcdir = kmod_srcdir | |
639 if kmod_patches: | |
640 os.chdir(self.kmod_srcdir) | |
641 for patch in kmod_patches: | |
642 utils.get_file(patch, os.path.join(self.userspace_srcdir, | |
643 os.path.basename(patch))) | |
644 utils.system('patch -p1 %s' % os.path.basename(patch)) | |
645 else: | |
646 self.kmod_srcdir = None | |
647 | |
648 configure_script = os.path.join(self.userspace_srcdir, 'configure') | |
649 self.configure_options = check_configure_options(configure_script) | |
650 | |
651 | |
652 def _build(self): | |
653 make_jobs = utils.count_cpus() | |
654 cfg = './configure' | |
655 if self.kmod_srcdir: | |
656 logging.info('Building KVM modules') | |
657 os.chdir(self.kmod_srcdir) | |
658 module_build_steps = [cfg, | |
659 'make clean', | |
660 'make sync LINUX=%s' % self.kernel_srcdir, | |
661 'make'] | |
662 elif self.kernel_srcdir: | |
663 logging.info('Building KVM modules') | |
664 os.chdir(self.userspace_srcdir) | |
665 cfg += ' --kerneldir=%s' % self.host_kernel_srcdir | |
666 module_build_steps = [cfg, | |
667 'make clean', | |
668 'make -C kernel LINUX=%s sync' % self.kernel_srcdir] | |
669 else: | |
670 module_build_steps = [] | |
671 | |
672 for step in module_build_steps: | |
673 utils.run(step) | |
674 | |
675 logging.info('Building KVM userspace code') | |
676 os.chdir(self.userspace_srcdir) | |
677 cfg += ' --prefix=%s' % self.prefix | |
678 if "--disable-strip" in self.configure_options: | |
679 cfg += ' --disable-strip' | |
680 if self.extra_configure_options: | |
681 cfg += ' %s' % self.extra_configure_options | |
682 utils.system(cfg) | |
683 utils.system('make clean') | |
684 utils.system('make -j %s' % make_jobs) | |
685 | |
686 self.unittest_prefix = None | |
687 if self.unittest_cfg: | |
688 os.chdir(os.path.dirname(os.path.dirname(self.unittest_cfg))) | |
689 utils.system('./configure --prefix=%s' % self.prefix) | |
690 utils.system('make') | |
691 utils.system('make install') | |
692 self.unittest_prefix = os.path.join(self.prefix, 'share', 'qemu', | |
693 'tests') | |
694 | |
695 | |
696 def _install(self): | |
697 if self.kernel_srcdir: | |
698 os.chdir(self.userspace_srcdir) | |
699 # the kernel module install with --prefix doesn't work, and DESTDIR | |
700 # wouldn't work for the userspace stuff, so we clear WANT_MODULE: | |
701 utils.system('make install WANT_MODULE=') | |
702 # and install the old-style-kmod modules manually: | |
703 self._install_kmods_old_userspace(self.userspace_srcdir) | |
704 elif self.kmod_srcdir: | |
705 # if we have a kmod repository, it is easier: | |
706 # 1) install userspace: | |
707 os.chdir(self.userspace_srcdir) | |
708 utils.system('make install') | |
709 # 2) install kmod: | |
710 self._install_kmods(self.kmod_srcdir) | |
711 else: | |
712 # if we don't have kmod sources, we just install | |
713 # userspace: | |
714 os.chdir(self.userspace_srcdir) | |
715 utils.system('make install') | |
716 | |
717 if self.path_to_roms: | |
718 install_roms(self.path_to_roms, self.prefix) | |
719 create_symlinks(test_bindir=self.test_bindir, prefix=self.prefix, | |
720 bin_list=None, | |
721 unittest=self.unittest_prefix) | |
722 | |
723 | |
724 def install(self): | |
725 self._pull_code() | |
726 self._build() | |
727 self._install() | |
728 self.reload_modules_if_needed() | |
729 if self.save_results: | |
730 save_build(self.srcdir, self.results_dir) | |
731 | |
732 | |
733 class PreInstalledKvm(BaseInstaller): | |
734 # load_modules() will use the stock modules: | |
735 load_stock_modules = True | |
736 def install(self): | |
737 logging.info("Expecting KVM to be already installed. Doing nothing") | |
738 | |
739 | |
740 class FailedInstaller: | |
741 """ | |
742 Class used to be returned instead of the installer if a installation fails | |
743 | |
744 Useful to make sure no installer object is used if KVM installation fails. | |
745 """ | |
746 def __init__(self, msg="KVM install failed"): | |
747 self._msg = msg | |
748 | |
749 | |
750 def load_modules(self): | |
751 """Will refuse to load the KVM modules as install failed""" | |
752 raise FailedKvmInstall("KVM modules not available. reason: %s" % (self._
msg)) | |
753 | |
754 | |
755 installer_classes = { | |
756 'localsrc': SourceDirInstaller, | |
757 'localtar': SourceDirInstaller, | |
758 'release': SourceDirInstaller, | |
759 'snapshot': SourceDirInstaller, | |
760 'git': GitInstaller, | |
761 'yum': YumInstaller, | |
762 'koji': KojiInstaller, | |
763 'preinstalled': PreInstalledKvm, | |
764 } | |
765 | |
766 | |
767 def _installer_class(install_mode): | |
768 c = installer_classes.get(install_mode) | |
769 if c is None: | |
770 raise error.TestError('Invalid or unsupported' | |
771 ' install mode: %s' % install_mode) | |
772 return c | |
773 | |
774 | |
775 def make_installer(params): | |
776 # priority: | |
777 # - 'install_mode' param | |
778 # - 'mode' param | |
779 mode = params.get("install_mode", params.get("mode")) | |
780 klass = _installer_class(mode) | |
781 return klass(mode) | |
OLD | NEW |