| 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 |