3
# Fullly virtualized guest support
5
# Copyright 2006-2007 Red Hat, Inc.
6
# Jeremy Katz <katzj@redhat.com>
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.
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.
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,
30
from virtinst import _virtinst as _
33
class FullVirtGuest(Guest.XenGuest):
34
OS_TYPES = { "linux": { "label": "Linux", \
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" }, \
52
"windows": { "label": "Windows", \
56
"input": [ "tablet", "usb"],
57
"variants": { "winxp": { "label": "Microsoft Windows XP", \
60
"win2k": { "label": "Microsoft Windows 2000", \
63
"win2k3": { "label": "Microsoft Windows 2003" }, \
64
"vista": { "label": "Microsoft Windows Vista" }, \
67
"unix": { "label": "UNIX", \
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" }, \
78
"other": { "label": "Other", \
82
"input": [ "mouse", "ps2"],
83
"variants": { "msdos": { "label": "MS-DOS", \
86
"netware4": { "label": "Novell Netware 4" }, \
87
"netware5": { "label": "Novell Netware 5" }, \
88
"netware6": { "label": "Novell Netware 6" }, \
89
"generic": { "label": "Generic" }, \
95
return FullVirtGuest.OS_TYPES.keys()
96
list_os_types = staticmethod(list_os_types)
98
def list_os_variants(type):
99
return FullVirtGuest.OS_TYPES[type]["variants"].keys()
100
list_os_variants = staticmethod(list_os_variants)
102
def get_os_type_label(type):
103
return FullVirtGuest.OS_TYPES[type]["label"]
104
get_os_type_label = staticmethod(get_os_type_label)
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)
111
def __init__(self, type=None, arch=None, connection=None, hypervisorURI=None, emulator=None, installer=None):
113
installer = DistroManager.DistroInstaller(type = type)
114
Guest.Guest.__init__(self, type, connection, hypervisorURI, installer)
116
self.features = { "acpi": None, "pae": util.is_pae_capable(), "apic": None }
119
if self.type == "xen":
120
if os.uname()[4] in ("x86_64"):
121
emulator = "/usr/lib64/xen/bin/qemu-dm"
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"
130
self._os_variant = None
133
def get_os_type(self):
135
def set_os_type(self, val):
136
if FullVirtGuest.OS_TYPES.has_key(val):
139
raise ValueError, _("OS type %s does not exist in our dictionary") % val
140
os_type = property(get_os_type, set_os_type)
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
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)
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
155
if self.features is 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]
166
features[f] = FullVirtGuest.OS_TYPES[os_type][f]
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"]
173
os_distro = property(get_os_distro)
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])
181
def _get_features_xml(self):
183
features = self.os_features()
186
for k in sorted(features.keys()):
191
return ret + " </features>"
193
def _get_osblob(self, install):
194
osblob = self.installer._get_osblob(install, True, self.arch, self.loader)
198
return "%s\n %s" % (osblob, self._get_features_xml())
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)
205
return (""" <emulator>%(emulator)s</emulator>
206
<console device='pty'/>
207
""" % { "emulator": self.emulator }) + \
208
Guest.Guest._get_device_xml(self, install)
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)
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,
220
distro = self.os_distro)
221
if self._installer.install_disk is not None:
222
self._install_disks.append(self._installer.install_disk)
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"]
229
return FullVirtGuest.OS_TYPES[self.os_type]["continue"]
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!")
241
self.connect_console(consolecb)
243
# ensure there's time for the domain to finish destroying if the
244
# install has finished or the guest crashed
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)
252
def _get_disk_xml(self, install = True):
253
"""Get the disk config in the libvirt XML format"""
257
n = "%s%c" % (self.disknode, ord('a') + i)
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:
267
if d.target != cdnode:
268
raise ValueError, "The CDROM must be device %s" % cdnode
272
if nodes[d.target] != None:
273
raise ValueError, "The CDROM device %s is already used" % d.target
276
# Now assign regular disk node with remainder
277
for d in self._install_disks:
278
if d.device == Guest.VirtualDisk.DEVICE_CDROM:
281
if d.target is None: # Auto-assign disk
282
for n in sorted(nodes.keys()):
288
if nodes[d.target] != None: # Verify pre-assigned
289
raise ValueError, "The disk device %s is already used" % d.target
292
for d in self._install_disks:
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":
300
# .. so simply remove CDROM device completely in non-Xen
303
ret += d.get_xml_config(d.target)
304
if saved_path != None: