~ubuntu-branches/ubuntu/quantal/virtinst/quantal-proposed

« back to all changes in this revision

Viewing changes to virtinst/FullVirtGuest.py

  • Committer: Bazaar Package Importer
  • Author(s): Soren Hansen
  • Date: 2007-11-20 13:40:28 UTC
  • Revision ID: james.westby@ubuntu.com-20071120134028-rg0pjby0jc4mycks
Tags: upstream-0.300.1+hg20071120
ImportĀ upstreamĀ versionĀ 0.300.1+hg20071120

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/python -tt
 
2
#
 
3
# Fullly virtualized guest support
 
4
#
 
5
# Copyright 2006-2007  Red Hat, Inc.
 
6
# Jeremy Katz <katzj@redhat.com>
 
7
#
 
8
# This program is free software; you can redistribute it and/or modify
 
9
# it under the terms of the GNU General Public License as published by
 
10
# the Free  Software Foundation; either version 2 of the License, or
 
11
# (at your option)  any later version.
 
12
#
 
13
# This program is distributed in the hope that it will be useful,
 
14
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
# GNU General Public License for more details.
 
17
#
 
18
# You should have received a copy of the GNU General Public License
 
19
# along with this program; if not, write to the Free Software
 
20
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
21
# MA 02110-1301 USA.
 
22
 
 
23
import os
 
24
import libvirt
 
25
import Guest
 
26
import util
 
27
import DistroManager
 
28
import logging
 
29
import time
 
30
from virtinst import _virtinst as _
 
31
 
 
32
 
 
33
class FullVirtGuest(Guest.XenGuest):
 
34
    OS_TYPES = { "linux": { "label": "Linux", \
 
35
                            "acpi": True, \
 
36
                            "apic": True, \
 
37
                            "continue": False, \
 
38
                            "input": [ "mouse", "ps2"],
 
39
                            "variants": { "rhel2.1": { "label": "Red Hat Enterprise Linux 2.1", "distro": "rhel" }, \
 
40
                                          "rhel3": { "label": "Red Hat Enterprise Linux 3", "distro": "rhel" }, \
 
41
                                          "rhel4": { "label": "Red Hat Enterprise Linux 4", "distro": "rhel" }, \
 
42
                                          "rhel5": { "label": "Red Hat Enterprise Linux 5", "distro": "rhel" }, \
 
43
                                          "fedora5": { "label": "Fedora Core 5", "distro": "fedora" }, \
 
44
                                          "fedora6": { "label": "Fedora Core 6", "distro": "fedora" }, \
 
45
                                          "fedora7": { "label": "Fedora 7", "distro": "fedora" }, \
 
46
                                          "fedora8": { "label": "Fedora 8", "distro": "fedora" }, \
 
47
                                          "sles10": { "label": "Suse Linux Enterprise Server", "distro": "suse" }, \
 
48
                                          "generic24": { "label": "Generic 2.4.x kernel" }, \
 
49
                                          "generic26": { "label": "Generic 2.6.x kernel" }, \
 
50
                                          }, \
 
51
                            }, \
 
52
                 "windows": { "label": "Windows", \
 
53
                              "acpi": True, \
 
54
                              "apic": True, \
 
55
                              "continue": True, \
 
56
                              "input": [ "tablet", "usb"],
 
57
                              "variants": { "winxp": { "label": "Microsoft Windows XP", \
 
58
                                                       "acpi": False, \
 
59
                                                       "apic": False }, \
 
60
                                            "win2k": { "label": "Microsoft Windows 2000", \
 
61
                                                       "acpi": False, \
 
62
                                                       "apic": False }, \
 
63
                                            "win2k3": { "label": "Microsoft Windows 2003" }, \
 
64
                                            "vista": { "label": "Microsoft Windows Vista" }, \
 
65
                                            }, \
 
66
                              }, \
 
67
                 "unix": { "label": "UNIX", \
 
68
                           "acpi": True,
 
69
                           "apic": True,
 
70
                           "continue": False, \
 
71
                           "input": [ "mouse", "ps2"],
 
72
                           "variants": { "solaris9": { "label": "Sun Solaris 9" }, \
 
73
                                         "solaris10": { "label": "Sun Solaris 10" }, \
 
74
                                         "freebsd6": { "label": "Free BSD 6.x" }, \
 
75
                                         "openbsd4": { "label": "Open BSD 4.x" }, \
 
76
                                         }, \
 
77
                           }, \
 
78
                 "other": { "label": "Other", \
 
79
                            "acpi": True,
 
80
                            "apic": True,
 
81
                            "continue": False,
 
82
                            "input": [ "mouse", "ps2"],
 
83
                            "variants": { "msdos": { "label": "MS-DOS", \
 
84
                                                     "acpi": False, \
 
85
                                                     "apic": False }, \
 
86
                                          "netware4": { "label": "Novell Netware 4" }, \
 
87
                                          "netware5": { "label": "Novell Netware 5" }, \
 
88
                                          "netware6": { "label": "Novell Netware 6" }, \
 
89
                                          "generic": { "label": "Generic" }, \
 
90
                                          }, \
 
91
                            } \
 
92
                 }
 
93
 
 
94
    def list_os_types():
 
95
        return FullVirtGuest.OS_TYPES.keys()
 
96
    list_os_types = staticmethod(list_os_types)
 
97
 
 
98
    def list_os_variants(type):
 
99
        return FullVirtGuest.OS_TYPES[type]["variants"].keys()
 
100
    list_os_variants = staticmethod(list_os_variants)
 
101
 
 
102
    def get_os_type_label(type):
 
103
        return FullVirtGuest.OS_TYPES[type]["label"]
 
104
    get_os_type_label = staticmethod(get_os_type_label)
 
105
 
 
106
    def get_os_variant_label(type, variant):
 
107
        return FullVirtGuest.OS_TYPES[type]["variants"][variant]["label"]
 
108
    get_os_variant_label = staticmethod(get_os_variant_label)
 
109
 
 
110
 
 
111
    def __init__(self, type=None, arch=None, connection=None, hypervisorURI=None, emulator=None, installer=None):
 
112
        if not installer:
 
113
            installer = DistroManager.DistroInstaller(type = type)
 
114
        Guest.Guest.__init__(self, type, connection, hypervisorURI, installer)
 
115
        self.disknode = "hd"
 
116
        self.features = { "acpi": None, "pae": util.is_pae_capable(), "apic": None }
 
117
        self.arch = arch
 
118
        if emulator is None:
 
119
            if self.type == "xen":
 
120
                if os.uname()[4] in ("x86_64"):
 
121
                    emulator = "/usr/lib64/xen/bin/qemu-dm"
 
122
                else:
 
123
                    emulator = "/usr/lib/xen/bin/qemu-dm"
 
124
        self.emulator = emulator
 
125
        if self.type == "xen":
 
126
            self.loader = "/usr/lib/xen/boot/hvmloader"
 
127
        else:
 
128
            self.loader = None
 
129
        self._os_type = None
 
130
        self._os_variant = None
 
131
 
 
132
 
 
133
    def get_os_type(self):
 
134
        return self._os_type
 
135
    def set_os_type(self, val):
 
136
        if FullVirtGuest.OS_TYPES.has_key(val):
 
137
            self._os_type = val
 
138
        else:
 
139
            raise ValueError, _("OS type %s does not exist in our dictionary") % val
 
140
    os_type = property(get_os_type, set_os_type)
 
141
 
 
142
    def get_os_variant(self):
 
143
        return self._os_variant
 
144
    def set_os_variant(self, val):
 
145
        if FullVirtGuest.OS_TYPES[self._os_type]["variants"].has_key(val):
 
146
            self._os_variant = val
 
147
        else:
 
148
            raise ValueError, _("OS variant %(var)s does not exist in our dictionary for OS type %(type)s") % {'var' : val, 'type' : self._os_type}
 
149
    os_variant = property(get_os_variant, set_os_variant)
 
150
 
 
151
    def os_features(self):
 
152
        """Determine the guest features, based on explicit settings in FEATURES
 
153
        and the OS_TYPE and OS_VARIANT. FEATURES takes precedence over the OS
 
154
        preferences"""
 
155
        if self.features is None:
 
156
            return None
 
157
        os_type = self.os_type
 
158
        os_variant = self.os_variant
 
159
        # explicitly disabling apic and acpi will override OS_TYPES values
 
160
        features = dict(self.features)
 
161
        for f in ["acpi", "apic"]:
 
162
            if features[f] is None and os_type is not None:
 
163
                if os_variant is not None and FullVirtGuest.OS_TYPES[os_type]["variants"][os_variant].has_key(f):
 
164
                    features[f] = FullVirtGuest.OS_TYPES[os_type]["variants"][os_variant][f]
 
165
                else:
 
166
                    features[f] = FullVirtGuest.OS_TYPES[os_type][f]
 
167
        return features
 
168
 
 
169
    def get_os_distro(self):
 
170
        if self.os_type is not None and self.os_variant is not None and "distro" in FullVirtGuest.OS_TYPES[self.os_type]["variants"][self.os_variant]:
 
171
            return FullVirtGuest.OS_TYPES[self.os_type]["variants"][self.os_variant]["distro"]
 
172
        return None
 
173
    os_distro = property(get_os_distro)
 
174
 
 
175
    def get_input_device(self):
 
176
        if self.os_type is None or not FullVirtGuest.OS_TYPES.has_key(self.os_type):
 
177
            return ("mouse", "ps2")
 
178
        input = FullVirtGuest.OS_TYPES[self.os_type]["input"]
 
179
        return (input[0], input[1])
 
180
 
 
181
    def _get_features_xml(self):
 
182
        ret = "<features>\n"
 
183
        features = self.os_features()
 
184
        if features:
 
185
            ret += "    "
 
186
            for k in sorted(features.keys()):
 
187
                v = features[k]
 
188
                if v:
 
189
                    ret += "<%s/>" %(k,)
 
190
            ret += "\n"
 
191
        return ret + "  </features>"
 
192
 
 
193
    def _get_osblob(self, install):
 
194
        osblob = self.installer._get_osblob(install, True, self.arch, self.loader)
 
195
        if osblob is None:
 
196
            return None
 
197
 
 
198
        return "%s\n  %s" % (osblob, self._get_features_xml())
 
199
 
 
200
    def _get_device_xml(self, install = True):
 
201
        if self.emulator is None:
 
202
            return """    <console device='pty'/>
 
203
""" + Guest.Guest._get_device_xml(self, install)
 
204
        else:
 
205
            return ("""    <emulator>%(emulator)s</emulator>
 
206
    <console device='pty'/>
 
207
""" % { "emulator": self.emulator }) + \
 
208
        Guest.Guest._get_device_xml(self, install)
 
209
 
 
210
    def validate_parms(self):
 
211
        #if not self.location:
 
212
        #    raise ValueError, _("A CD must be specified to boot from")
 
213
        Guest.Guest.validate_parms(self)
 
214
 
 
215
    def _prepare_install(self, meter):
 
216
        Guest.Guest._prepare_install(self, meter)
 
217
        if self.location or self.cdrom:
 
218
            self._installer.prepare(guest = self,
 
219
                                    meter = meter,
 
220
                                    distro = self.os_distro)
 
221
        if self._installer.install_disk is not None:
 
222
            self._install_disks.append(self._installer.install_disk)
 
223
 
 
224
    def get_continue_inst(self):
 
225
        if self.os_type is not None:
 
226
            if self.os_variant is not None and FullVirtGuest.OS_TYPES[self.os_type]["variants"][self.os_variant].has_key("continue"):
 
227
                return FullVirtGuest.OS_TYPES[self.os_type]["variants"][self.os_variant]["continue"]
 
228
            else:
 
229
                return FullVirtGuest.OS_TYPES[self.os_type]["continue"]
 
230
        return False
 
231
 
 
232
    def continue_install(self, consolecb, meter):
 
233
        install_xml = self.get_config_xml(disk_boot = True)
 
234
        logging.debug("Starting guest from '%s'" % ( install_xml ))
 
235
        meter.start(size=None, text="Starting domain...")
 
236
        self.domain = self.conn.createLinux(install_xml, 0)
 
237
        if self.domain is None:
 
238
            raise RuntimeError, _("Unable to start domain for guest, aborting installation!")
 
239
        meter.end(0)
 
240
 
 
241
        self.connect_console(consolecb)
 
242
 
 
243
        # ensure there's time for the domain to finish destroying if the
 
244
        # install has finished or the guest crashed
 
245
        if consolecb:
 
246
            time.sleep(1)
 
247
 
 
248
        # This should always work, because it'll lookup a config file
 
249
        # for inactive guest, or get the still running install..
 
250
        return self.conn.lookupByName(self.name)
 
251
 
 
252
    def _get_disk_xml(self, install = True):
 
253
        """Get the disk config in the libvirt XML format"""
 
254
        ret = ""
 
255
        nodes = {}
 
256
        for i in range(4):
 
257
            n = "%s%c" % (self.disknode, ord('a') + i)
 
258
            nodes[n] = None
 
259
 
 
260
        # First assign CDROM device nodes, since they're scarce resource
 
261
        cdnode = self.disknode + "c"
 
262
        for d in self._install_disks:
 
263
            if d.device != Guest.VirtualDisk.DEVICE_CDROM:
 
264
                continue
 
265
 
 
266
            if d.target:
 
267
                if d.target != cdnode:
 
268
                    raise ValueError, "The CDROM must be device %s" % cdnode
 
269
            else:
 
270
                d.target = cdnode
 
271
 
 
272
            if nodes[d.target] != None:
 
273
                raise ValueError, "The CDROM device %s is already used" % d.target
 
274
            nodes[d.target] = d
 
275
 
 
276
        # Now assign regular disk node with remainder
 
277
        for d in self._install_disks:
 
278
            if d.device == Guest.VirtualDisk.DEVICE_CDROM:
 
279
                continue
 
280
 
 
281
            if d.target is None: # Auto-assign disk
 
282
                for n in sorted(nodes.keys()):
 
283
                    if nodes[n] is None:
 
284
                        d.target = n
 
285
                        nodes[d.target] = d
 
286
                        break
 
287
            else:
 
288
                if nodes[d.target] != None: # Verify pre-assigned
 
289
                    raise ValueError, "The disk device %s is already used" % d.target
 
290
                nodes[d.target] = d
 
291
 
 
292
        for d in self._install_disks:
 
293
            saved_path = None
 
294
            if d.device == Guest.VirtualDisk.DEVICE_CDROM and d.transient and not install:
 
295
                # XXX hack. libvirt can't currently handle QEMU having an empty disk path..
 
296
                if self.type == "xen":
 
297
                    saved_path = d.path
 
298
                    d.path = None
 
299
                else:
 
300
                    # .. so simply remove CDROM device completely in non-Xen
 
301
                    continue
 
302
 
 
303
            ret += d.get_xml_config(d.target)
 
304
            if saved_path != None:
 
305
                d.path = saved_path
 
306
 
 
307
        return ret