1#
2# Copyright 2007 Google Inc. Released under the GPL v2
3
4"""
5This module defines the Kernel class
6
7        Kernel: an os kernel
8"""
9
10__author__ = """
11mbligh@google.com (Martin J. Bligh),
12poirier@google.com (Benjamin Poirier),
13stutsman@google.com (Ryan Stutsman)"""
14
15
16import os, time
17from autotest_lib.client.common_lib import error
18from autotest_lib.server import kernel, utils
19
20
21class RPMKernel(kernel.Kernel):
22    """
23    This class represents a .rpm pre-built kernel.
24
25    It is used to obtain a built kernel and install it on a Host.
26
27    Implementation details:
28    This is a leaf class in an abstract class hierarchy, it must
29    implement the unimplemented methods in parent classes.
30    """
31    def __init__(self):
32        super(RPMKernel, self).__init__()
33
34    def install(self, host, label='autotest',
35                default=False, kernel_args = '', install_vmlinux=True):
36        """
37        Install a kernel on the remote host.
38
39        This will also invoke the guest's bootloader to set this
40        kernel as the default kernel if default=True.
41
42        Args:
43                host: the host on which to install the kernel
44                [kwargs]: remaining keyword arguments will be passed
45                        to Bootloader.add_kernel()
46
47        Raises:
48                AutoservError: no package has yet been obtained. Call
49                        RPMKernel.get() with a .rpm package.
50        """
51        if len(label) > 15:
52            raise error.AutoservError("label for kernel is too long \
53            (> 15 chars): %s" % label)
54        if self.source_material is None:
55            raise error.AutoservError("A kernel must first be \
56            specified via get()")
57        rpm = self.source_material
58
59        remote_tmpdir = host.get_tmp_dir()
60        remote_rpm = os.path.join(remote_tmpdir, os.path.basename(rpm))
61        rpm_package = utils.run('/usr/bin/rpm -q -p %s' % rpm).stdout
62        vmlinuz = self.get_image_name()
63        host.send_file(rpm, remote_rpm)
64        host.run('rpm -e ' + rpm_package, ignore_status = True)
65        host.run('rpm --force -i ' + remote_rpm)
66
67        # Copy over the uncompressed image if there is one
68        if install_vmlinux:
69            vmlinux = self.get_vmlinux_name()
70            host.run('cd /;rpm2cpio %s | cpio -imuv .%s'
71                    % (remote_rpm, vmlinux))
72            host.run('ls ' + vmlinux) # Verify
73
74        host.bootloader.remove_kernel(label)
75        host.bootloader.add_kernel(vmlinuz, label,
76                                   args=kernel_args, default=default)
77        if kernel_args:
78            host.bootloader.add_args(label, kernel_args)
79        if not default:
80            host.bootloader.boot_once(label)
81
82
83    def get_version(self):
84        """Get the version of the kernel to be installed.
85
86        Returns:
87                The version string, as would be returned
88                by 'make kernelrelease'.
89
90        Raises:
91                AutoservError: no package has yet been obtained. Call
92                        RPMKernel.get() with a .rpm package.
93        """
94        if self.source_material is None:
95            raise error.AutoservError("A kernel must first be \
96            specified via get()")
97
98        retval = utils.run('rpm -qpi %s | grep Version | awk \'{print($3);}\''
99            % utils.sh_escape(self.source_material))
100        return retval.stdout.strip()
101
102
103    def get_image_name(self):
104        """Get the name of the kernel image to be installed.
105
106        Returns:
107                The full path to the kernel image file as it will be
108                installed on the host.
109
110        Raises:
111                AutoservError: no package has yet been obtained. Call
112                        RPMKernel.get() with a .rpm package.
113        """
114        if self.source_material is None:
115            raise error.AutoservError("A kernel must first be \
116            specified via get()")
117
118        vmlinuz = utils.run('rpm -q -l -p %s | grep /boot/vmlinuz'
119            % self.source_material).stdout.strip()
120        return vmlinuz
121
122
123    def get_vmlinux_name(self):
124        """Get the name of the kernel image to be installed.
125
126        Returns:
127                The full path to the kernel image file as it will be
128                installed on the host. It is the uncompressed and
129                unstripped version of the kernel that can be used with
130                oprofile.
131
132        Raises:
133                AutoservError: no package has yet been obtained. Call
134                        RPMKernel.get() with a .rpm package.
135        """
136        if self.source_material is None:
137            raise error.AutoservError("A kernel must first be \
138            specified via get()")
139
140        vmlinux = utils.run('rpm -q -l -p %s | grep /boot/vmlinux'
141            % self.source_material).stdout.strip()
142        return vmlinux
143
144
145    def get_initrd_name(self):
146        """Get the name of the initrd file to be installed.
147
148        Returns:
149                The full path to the initrd file as it will be
150                installed on the host. If the package includes no
151                initrd file, None is returned
152
153        Raises:
154                AutoservError: no package has yet been obtained. Call
155                        RPMKernel.get() with a .rpm package.
156        """
157        if self.source_material is None:
158            raise error.AutoservError("A kernel must first be \
159            specified via get()")
160
161        res = utils.run('rpm -q -l -p %s | grep /boot/initrd'
162            % self.source_material, ignore_status=True)
163        if res.exit_status:
164            return None
165        return res.stdout.strip()
166