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