• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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"""
6Factory install VM tests.
7
8This 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
18import os, re
19
20from autotest_lib.client.bin import utils as client_utils
21from autotest_lib.server.cros.factory_install_test import FactoryInstallTest
22from 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
36class 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