OLD | NEW |
(Empty) | |
| 1 import os, logging, datetime, glob |
| 2 import shutil |
| 3 from autotest_lib.client.bin import utils, 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 |