Home | History | Annotate | Download | only in factory_InstallVM
      1 # Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 """
      6 Factory install VM tests.
      7 
      8 This test supports the flags documented in FactoryInstallTest, plus:
      9 
     10     debug_vnc: whether to run VNC on the KVM (for debugging only)
     11     debug_save_hda: if specified, path to save the hda.bin to after
     12         running the factory install shim (for debugging only)
     13     debug_reuse_hda: if specified, path to an existing hda.bin image
     14         to reuse (for debugging only)
     15 """
     16 
     17 
     18 import os, re
     19 
     20 from autotest_lib.client.bin import utils as client_utils
     21 from autotest_lib.server.cros.factory_install_test import FactoryInstallTest
     22 from autotest_lib.server.hosts import ssh_host
     23 
     24 
     25 # How long to wait after killing KVMs.
     26 _KILL_KVM_WAIT_SEC = 5
     27 
     28 # The size of the "SSD" in the KVM.
     29 _HDA_SIZE_MB = 8192
     30 
     31 # The name of the image used for hda.  This should be unique to this test,
     32 # since we will kill all stray KVM processes using this disk image.
     33 _HDA_FILENAME = "factory_InstallVM_hda.bin"
     34 
     35 
     36 class factory_InstallVM(FactoryInstallTest):
     37     """
     38     Factory install VM tests.
     39 
     40     See file-level docstring for more information.
     41     """
     42 
     43     def _get_kvm_command(self, kvm_args=[]):
     44         """
     45         Returns the command to run KVM.
     46 
     47         @param kvm_args: A list of extra args to pass to KVM.
     48         """
     49         kvm_base_args = [
     50             "kvm",
     51             "-m", "2048",
     52             "-net", "nic,model=virtio",
     53             "-net", "user,hostfwd=tcp::%d-:22" % self.ssh_tunnel_port,
     54             "-vga", "vmware",  # Because -vga std is slow
     55             ]
     56 
     57         if self.vnc:
     58             # Without nographic, we need to explicitly add "-serial stdio"
     59             # (or output will go to vc).  Use 127.0.0.1 to ensure that kvm
     60             # listens with IPv4.
     61             kvm_base_args.extend(["-serial", "stdio", "-vnc", "127.0.0.1:1"])
     62         else:
     63             kvm_base_args.append("-nographic")
     64 
     65         return " ".join(kvm_base_args + kvm_args)
     66 
     67     def _kill_kvm(self):
     68         """
     69         Kills the KVM on the client machine.
     70 
     71         This will kill any KVM whose command line contains _HDA_FILENAME
     72         (which is specific to this test).
     73         """
     74         def try_kill_kvm():
     75             pattern = "^kvm.*%s" % _HDA_FILENAME,
     76             if (self.client.run("pgrep -f '%s'" % pattern, ignore_status=True)
     77                 .exit_status == 1):
     78                 return True
     79             self.client.run("pkill -f '%s'" % (pattern))
     80             return False
     81 
     82         client_utils.poll_for_condition(
     83             try_kill_kvm, timeout=_KILL_KVM_WAIT_SEC, desc="Kill KVM")
     84 
     85     def get_hwid_cfg(self):
     86         """
     87         Overridden from superclass.
     88         """
     89         return "vm"
     90 
     91     def get_dut_client(self):
     92         """
     93         Overridden from superclass.
     94         """
     95         return ssh_host.SSHHost("localhost", port=self.ssh_tunnel_port)
     96 
     97     def run_factory_install(self, local_hdb):
     98         """
     99         Overridden from superclass.
    100         """
    101         self.hda = os.path.join(self.client.get_tmp_dir(), _HDA_FILENAME)
    102 
    103         if self.reuse_hda is not None:
    104             self.client.run("cp %s %s" % (self.reuse_hda, self.hda))
    105         else:
    106             # Mount partition 12 the image and modify it to enable serial
    107             # logging.
    108             mount = self._mount_partition(local_hdb, 12)
    109             self._modify_file(
    110                 os.path.join(mount, "syslinux/usb.A.cfg"),
    111                 lambda contents: re.sub(r"console=\w+", "console=ttyS0",
    112                                         contents))
    113             self._umount_partition(mount)
    114 
    115             # On the client, create a nice big sparse file for hda
    116             # (a.k.a. the SSD).
    117             self.client.run("truncate -s %dM %s" % (_HDA_SIZE_MB, self.hda))
    118             hdb = os.path.join(self.client.get_tmp_dir(), "hdb.bin")
    119             self.client.send_file(local_hdb, hdb)
    120 
    121             # Fire up the KVM and wait for the factory install to complete.
    122             self._kill_kvm()  # Just in case
    123             self.client.run_grep(
    124                 self._get_kvm_command(
    125                     ["-drive", "file=%s,boot=off" % self.hda,
    126                      "-drive", "file=%s,boot=on" % hdb,
    127                      "-no-reboot"]),
    128                 timeout=FactoryInstallTest.FACTORY_INSTALL_TIMEOUT_SEC,
    129                 stdout_ok_regexp="Factory Installer Complete")
    130             self._kill_kvm()
    131 
    132             if self.save_hda is not None:
    133                 self.client.run("cp %s %s" % (self.hda, self.save_hda))
    134 
    135         # Run KVM again (the factory tests should now come up).
    136         kvm = self.client.run(self._get_kvm_command([
    137                     "-hda", self.hda,
    138                     "-daemonize",
    139                     "-no-reboot"]))
    140 
    141     def reboot_for_wipe(self):
    142         """
    143         Overridden from superclass.
    144         """
    145         # Use halt instead of reboot; reboot doesn't work consistently in KVM.
    146         self.get_dut_client().halt()
    147         self._kill_kvm()
    148 
    149         # Start KVM again.  The ChromeOS test image should now come up.
    150         kvm = self.client.run(
    151             self._get_kvm_command(["-hda", self.hda, "-daemonize"]))
    152 
    153     def run_once(self, host, debug_reuse_hda=None, debug_save_hda=None,
    154                  debug_vnc=False, **args):
    155         self.client = host
    156         self.reuse_hda = debug_reuse_hda
    157         self.save_hda = debug_save_hda
    158         self.vnc = self.parse_boolean(debug_vnc)
    159 
    160         self.cleanup_tasks.append(self._kill_kvm)
    161 
    162         super(factory_InstallVM, self).run_once(**args)
    163