2
# Common code for all guests
4
# Copyright 2006-2009 Red Hat, Inc.
5
# Jeremy Katz <katzj@redhat.com>
7
# This program is free software; you can redistribute it and/or modify
8
# it under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 2 of the License, or
10
# (at your option) any later version.
12
# This program is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
17
# You should have received a copy of the GNU General Public License
18
# along with this program; if not, write to the Free Software
19
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
27
import urlgrabber.progress as progress
32
import CapabilitiesParser
33
import VirtualGraphics
35
import XMLBuilderDomain
37
from XMLBuilderDomain import _xml_property
38
import DistroInstaller
39
from VirtualDevice import VirtualDevice
40
from VirtualDisk import VirtualDisk
41
from VirtualInputDevice import VirtualInputDevice
42
from VirtualCharDevice import VirtualCharDevice
43
from VirtualController import VirtualControllerUSB
44
from Clock import Clock
45
from Seclabel import Seclabel
47
from DomainNumatune import DomainNumatune
48
from DomainFeatures import DomainFeatures
51
from virtinst import _gettext as _
54
class Guest(XMLBuilderDomain.XMLBuilderDomain):
56
# OS Dictionary static variables and methods
57
_DEFAULTS = osdict.DEFAULTS
58
_OS_TYPES = osdict.OS_TYPES
60
_default_os_type = None
65
Return a strip representation of OS list for printing
68
for t in Guest.list_os_types():
69
for v in Guest.list_os_variants(t):
70
ret += "%-20s : %s\n" % (v, Guest.get_os_variant_label(t, v))
74
def list_os_types(supported=False, filtervars=None):
76
@param filtervars: List of only variants we want to show by default
78
vals = osdict.sort_helper(Guest._OS_TYPES)
80
if not Guest.list_os_variants(t, supported=supported,
81
filtervars=filtervars):
86
def list_os_variants(type, sortpref=None, supported=False, filtervars=None):
88
Return a list of sorted os variants for the passed distro type
90
@param sortpref: An option list of osdict 'distro' tags to
91
prioritize in the returned list, e.g. passing ["fedora"] will make
92
the sorted list have all fedora distros first
93
@param filtervars: List of only variants we want to show by default
95
vals = osdict.sort_helper(Guest._OS_TYPES[type]["variants"],
100
if v not in filtervars:
103
if not osdict.lookup_osdict_key(None, None,
104
type, v, "supported"):
111
def get_os_type_label(type):
112
return Guest._OS_TYPES[type]["label"]
115
def get_os_variant_label(type, variant):
116
return Guest._OS_TYPES[type]["variants"][variant]["label"]
119
def cpuset_str_to_tuple(conn, cpuset):
120
return DomainNumatune.cpuset_str_to_tuple(conn, cpuset)
123
def generate_cpuset(conn, mem):
125
Generates a cpu pinning string based on host NUMA configuration.
127
If host doesn't have a suitable NUMA configuration, a RuntimeError
130
caps = CapabilitiesParser.parse(conn.getCapabilities())
132
if caps.host.topology is None:
133
raise RuntimeError(_("No topology section in capabilities xml."))
135
cells = caps.host.topology.cells
137
raise RuntimeError(_("Capabilities only show <= 1 cell. "
140
# Capabilities tells us about the available memory 'cells' on the
141
# system. Each 'cell' has associated 'cpu's.
143
# Use getCellsFreeMemory to determine which 'cell' has the smallest
144
# amount of memory which fits the requested VM memory amount, then
145
# pin the VM to that 'cell's associated 'cpu's
147
cell_mem = conn.getCellsFreeMemory(0, len(cells))
150
for i in range(len(cells)):
151
if cell_mem[i] < mem:
152
# Cell doesn't have enough mem to fit, skip it
155
if len(cells[i].cpus) == 0:
156
# No cpus to use for the cell
159
# Find smallest cell that fits
160
if cell_id < 0 or cell_mem[i] < cell_mem[cell_id]:
164
raise RuntimeError(_("Could not find any usable NUMA "
165
"cell/cpu combinations."))
167
# Build cpuset string
169
for cpu in cells[cell_id].cpus:
172
cpustr += str(cpu.id)
176
def __init__(self, type=None, connection=None, hypervisorURI=None,
177
installer=None, parsexml=None, caps=None, conn=None):
179
# Set up the connection, since it is fundamental for other init
180
conn = conn or connection
182
logging.debug("No conn passed to Guest, opening URI '%s'" %
184
conn = self._open_uri(hypervisorURI)
187
raise RuntimeError(_("Unable to connect to hypervisor, aborting "
193
self._maxmemory = None
194
self._hugepage = None
198
self._autostart = False
200
self._seclabel = None
201
self._description = None
202
self._features = None
204
self._emulator = None
205
self._installer = installer
208
self._os_variant = None
209
self._os_autodetect = False
211
# DEPRECATED: Public device lists unaltered by install process
217
# General device list. Only access through API calls (even internally)
220
# Device list to use/alter during install process. Don't access
221
# directly, use internal APIs
222
self._install_devices = []
224
# The libvirt virDomain object we 'Create'
226
self._consolechild = None
228
self._default_input_device = None
229
self._default_console_device = None
231
caps = caps or (self._installer and self._installer._get_caps())
232
XMLBuilderDomain.XMLBuilderDomain.__init__(self, conn, parsexml,
237
if not self.installer:
238
i = DistroInstaller.DistroInstaller(type=type,
240
os_type=self._default_os_type,
241
caps=self._get_caps())
244
# Add default devices (if applicable)
245
inp = self._get_default_input_device()
248
self._default_input_device = inp
250
con = self._get_default_console_device()
251
con.virtinst_default = True
253
self._default_console_device = con
255
# Need to do this after all parameter init
256
self._features = DomainFeatures(self.conn)
257
self._clock = Clock(self.conn)
258
self._seclabel = Seclabel(self.conn)
259
self._cpu = CPU(self.conn)
260
self._numatune = DomainNumatune(self.conn)
262
def _open_uri(self, uri):
263
# This is here so test suite can overwrite it, to make sure
264
# Guest is never opening anything
265
return libvirt.open(uri)
267
######################
268
# Property accessors #
269
######################
271
def get_installer(self):
272
return self._installer
273
def set_installer(self, val):
274
self._installer = val
275
installer = property(get_installer, set_installer)
279
clock = property(get_clock)
280
def get_seclabel(self):
281
return self._seclabel
282
seclabel = property(get_seclabel)
285
cpu = property(get_cpu)
286
def get_numatune(self):
287
return self._numatune
288
numatune = property(get_numatune)
290
def _get_features(self):
291
return self._features
292
features = property(_get_features)
294
# Domain name of the guest
297
def set_name(self, val):
298
_util.validate_name(_("Guest"), val, lencheck=True)
301
if self.replace != True:
303
self.conn.lookupByName(val)
310
raise ValueError(_("Guest name '%s' is already in use.") % val)
313
name = _xml_property(get_name, set_name,
316
# Memory allocated to the guest. Should be given in MB
317
def get_memory(self):
319
def set_memory(self, val):
320
if (type(val) is not type(1) or val <= 0):
321
raise ValueError(_("Memory value must be an integer greater "
325
if self.maxmemory is None or self.maxmemory < val:
327
def _xml_memory_value(self):
328
return int(self.memory) * 1024
329
memory = _xml_property(get_memory, set_memory,
330
xpath="./currentMemory",
331
get_converter=lambda s, x: int(x) / 1024,
332
set_converter=lambda s, x: int(x) * 1024)
334
# Memory allocated to the guest. Should be given in MB
335
def get_maxmemory(self):
336
return self._maxmemory
337
def set_maxmemory(self, val):
338
if (type(val) is not type(1) or val <= 0):
339
raise ValueError(_("Max Memory value must be an integer greater "
341
self._maxmemory = val
342
def _xml_maxmemory_value(self):
343
return int(self.maxmemory) * 1024
344
maxmemory = _xml_property(get_maxmemory, set_maxmemory,
346
get_converter=lambda s, x: int(x) / 1024,
347
set_converter=lambda s, x: int(x) * 1024)
348
def get_hugepage(self):
349
return self._hugepage
350
def set_hugepage(self, val):
353
self._hugepage = bool(val)
354
hugepage = _xml_property(get_hugepage, set_hugepage,
355
xpath="./memoryBacking/hugepages", is_bool=True)
360
def set_uuid(self, val):
361
val = _util.validate_uuid(val)
363
uuid = _xml_property(get_uuid, set_uuid,
366
def __validate_cpus(self, val):
367
maxvcpus = _util.get_max_vcpus(self.conn, self.type)
370
raise ValueError(_("Number of vcpus must be a positive integer."))
372
raise ValueError(_("Number of vcpus must be no greater than %d "
373
"for this vm type.") % maxvcpus)
376
# number of vcpus for the guest
379
def set_vcpus(self, val):
380
val = self.__validate_cpus(val)
383
# Don't force set maxvcpus unless already specified
384
if self.maxvcpus is not None and self.maxvcpus < val:
386
def _vcpus_get_converter(self, val):
387
# If no current VCPUs, return maxvcpus
391
vcpus = _xml_property(get_vcpus, set_vcpus,
392
xpath="./vcpu/@current",
393
get_converter=_vcpus_get_converter)
395
def _get_maxvcpus(self):
396
return self._maxvcpus
397
def _set_maxvcpus(self, val):
398
val = self.__validate_cpus(val)
400
maxvcpus = _xml_property(_get_maxvcpus, _set_maxvcpus,
402
get_converter=lambda s, x: int(x))
404
# set phy-cpus for the guest
405
def get_cpuset(self):
407
def set_cpuset(self, val):
408
if val is None or val == "":
412
DomainNumatune.validate_cpuset(self.conn, val)
414
cpuset = _xml_property(get_cpuset, set_cpuset,
415
xpath="./vcpu/@cpuset")
417
def get_graphics_dev(self):
418
gdevs = self.get_devices(VirtualDevice.VIRTUAL_DEV_GRAPHICS)
419
return (gdevs and gdevs[0] or None)
420
def set_graphics_dev(self, val):
421
gdev = self.graphics_dev
425
self.remove_device(gdev)
426
graphics_dev = property(get_graphics_dev, set_graphics_dev)
428
# GAH! - installer.os_type = "hvm" or "xen" (aka xen paravirt)
429
# guest.os_type = "Solaris", "Windows", "Linux"
430
# FIXME: We should really rename this property to something else,
431
# change it throughout the codebase for readability sake, but
432
# maintain back compat.
433
def get_os_type(self):
435
def set_os_type(self, val):
436
if type(val) is not str:
437
raise ValueError(_("OS type must be a string."))
440
if val in self._OS_TYPES:
441
if self._os_type != val:
442
# Invalidate variant, since it may not apply to the new os type
444
self._os_variant = None
446
raise ValueError(_("OS type '%s' does not exist in our "
449
os_type = property(get_os_type, set_os_type)
451
def get_os_variant(self):
452
return self._os_variant
453
def set_os_variant(self, val):
454
if type(val) is not str:
455
raise ValueError(_("OS variant must be a string."))
459
if val in self._OS_TYPES[self.os_type]["variants"]:
460
self._os_variant = val
462
raise ValueError(_("OS variant '%(var)s' does not exist in "
463
"our dictionary for OS type '%(ty)s'") %
464
{'var' : val, 'ty' : self._os_type})
467
for ostype in self.list_os_types():
468
if (val in self._OS_TYPES[ostype]["variants"] and
469
not self._OS_TYPES[ostype]["variants"][val].get("skip")):
470
logging.debug("Setting os type to '%s' for variant '%s'",
472
self.os_type = ostype
473
self._os_variant = val
477
raise ValueError(_("Unknown OS variant '%s'" % val))
479
os_variant = property(get_os_variant, set_os_variant)
481
def set_os_autodetect(self, val):
482
self._os_autodetect = bool(val)
483
def get_os_autodetect(self):
484
return self._os_autodetect
485
os_autodetect = property(get_os_autodetect, set_os_autodetect)
487
# Get the current variants 'distro' tag: 'rhel', 'fedora', etc.
488
def get_os_distro(self):
489
return self._lookup_osdict_key("distro")
490
os_distro = property(get_os_distro)
492
def get_autostart(self):
493
return self._autostart
494
def set_autostart(self, val):
495
self._autostart = bool(val)
496
autostart = property(get_autostart, set_autostart,
497
doc="Have domain autostart when the host boots.")
499
def _get_description(self):
500
return self._description
501
def _set_description(self, val):
502
self._description = val
503
description = _xml_property(_get_description, _set_description,
504
xpath="./description")
506
def _get_emulator(self):
507
return self._emulator
508
def _set_emulator(self, val):
510
emulator = _xml_property(_get_emulator, _set_emulator,
511
xpath="./devices/emulator")
513
def _get_replace(self):
515
def _set_replace(self, val):
516
self._replace = bool(val)
517
replace = property(_get_replace, _set_replace,
518
doc=_("Whether we should overwrite an existing guest "
519
"with the same name."))
521
#########################
522
# DEPRECATED PROPERTIES #
523
#########################
525
# Deprecated: Should set graphics_dev.keymap directly
526
def get_keymap(self):
527
if self.graphics_dev is None:
529
return self.graphics_dev.keymap
530
def set_keymap(self, val):
531
if self.graphics_dev is not None:
532
self.graphics_dev.keymap = val
533
keymap = property(get_keymap, set_keymap)
535
# Deprecated: Should set guest.graphics_dev = VirtualGraphics(...)
536
def get_graphics(self):
537
if self.graphics_dev is None:
538
return { "enabled" : False }
539
return { "enabled" : True, "type" : self.graphics_dev, \
540
"keymap" : self.graphics_dev.keymap}
541
def set_graphics(self, val):
544
# a dictionary with keys: enabled, type, port, keymap
545
# a tuple of the form : (enabled, type, port, keymap)
547
# : "vnc", "sdl", or false
553
if type(val) == dict:
554
if "enabled" not in val:
555
raise ValueError(_("Must specify whether graphics are enabled"))
557
enabled = val["enabled"]
563
elif type(val) == tuple:
574
if val in ("vnc", "sdl"):
580
if enabled not in (True, False):
581
raise ValueError(_("Graphics enabled must be True or False"))
584
gdev = VirtualGraphics.VirtualGraphics(type=gtype)
589
self.graphics_dev = gdev
591
graphics = property(get_graphics, set_graphics)
593
# Hypervisor name (qemu, xen, kvm, etc.)
594
# Deprecated: should be pulled directly from the installer
596
return self._installer.type
597
def set_type(self, val):
598
self._installer.type = val
599
type = property(get_type, set_type)
601
# Deprecated: should be pulled directly from the installer
603
return self.installer.arch
604
def set_arch(self, val):
605
self.installer.arch = val
606
arch = property(get_arch, set_arch)
608
# Deprecated: Should be called from the installer directly
609
def get_location(self):
610
return self._installer.location
611
def set_location(self, val):
612
self._installer.location = val
613
location = property(get_location, set_location)
615
# Deprecated: Should be called from the installer directly
616
def get_scratchdir(self):
617
return self._installer.scratchdir
618
scratchdir = property(get_scratchdir)
620
# Deprecated: Should be called from the installer directly
622
return self._installer.boot
623
def set_boot(self, val):
624
self._installer.boot = val
625
boot = property(get_boot, set_boot)
627
# Deprecated: Should be called from the installer directly
628
def get_extraargs(self):
629
return self._installer.extraargs
630
def set_extraargs(self, val):
631
self._installer.extraargs = val
632
extraargs = property(get_extraargs, set_extraargs)
634
# Deprecated: Should set the installer values directly
636
return self._installer.location
637
def set_cdrom(self, val):
638
self._installer.location = val
639
self._installer.cdrom = True
640
cdrom = property(get_cdrom, set_cdrom)
643
########################################
644
# Device Add/Remove Public API methods #
645
########################################
647
def _dev_build_list(self, devtype, devlist=None):
649
devlist = self._devices
653
if i.virtual_device_type == devtype:
657
def add_device(self, dev):
659
Add the passed device to the guest's device list.
661
@param dev: VirtualDevice instance to attach to guest
663
if not isinstance(dev, VirtualDevice):
664
raise ValueError(_("Must pass a VirtualDevice instance."))
667
xml = dev.get_xml_config()
668
node = libxml2.parseDoc(xml).children
669
dev.set_xml_node(node)
670
self._add_child_node("./devices", node)
672
return self._add_device(dev)
674
def _add_device(self, dev):
675
devtype = dev.virtual_device_type
677
# If user adds a device conflicting with a default assigned device
679
if (dev.virtual_device_type == VirtualDevice.VIRTUAL_DEV_INPUT and
680
self._default_input_device):
681
if self._default_input_device in self.get_all_devices():
682
self.remove_device(self._default_input_device)
683
self._default_input_device = None
685
if (dev.virtual_device_type in [VirtualDevice.VIRTUAL_DEV_CONSOLE,
686
VirtualDevice.VIRTUAL_DEV_SERIAL] and
687
self._default_console_device):
688
if self._default_console_device in self.get_all_devices():
689
self.remove_device(self._default_console_device)
690
self._default_console_device = None
692
# Actually add the device
693
if devtype == VirtualDevice.VIRTUAL_DEV_DISK:
694
self.disks.append(dev)
695
elif devtype == VirtualDevice.VIRTUAL_DEV_NET:
696
self.nics.append(dev)
697
elif devtype == VirtualDevice.VIRTUAL_DEV_AUDIO:
698
self.sound_devs.append(dev)
699
elif devtype == VirtualDevice.VIRTUAL_DEV_HOSTDEV:
700
self.hostdevs.append(dev)
702
self._devices.append(dev)
705
def get_devices(self, devtype):
707
Return a list of devices of type 'devtype' that will installed on
710
@param devtype: Device type to search for (one of
711
VirtualDevice.virtual_device_types)
713
if devtype == VirtualDevice.VIRTUAL_DEV_DISK:
714
devlist = self.disks[:]
715
elif devtype == VirtualDevice.VIRTUAL_DEV_NET:
716
devlist = self.nics[:]
717
elif devtype == VirtualDevice.VIRTUAL_DEV_AUDIO:
718
devlist = self.sound_devs[:]
719
elif devtype == VirtualDevice.VIRTUAL_DEV_HOSTDEV:
720
devlist = self.hostdevs[:]
722
devlist = self._dev_build_list(devtype)
724
devlist.extend(self._install_devices)
725
return self._dev_build_list(devtype, devlist)
727
def get_all_devices(self):
729
Return a list of all devices being installed with the guest
732
for devtype in VirtualDevice.virtual_device_types:
733
retlist.extend(self.get_devices(devtype))
736
def remove_device(self, dev):
738
Remove the passed device from the guest's device list
740
@param dev: VirtualDevice instance
743
for devlist in [self.disks, self.nics, self.sound_devs, self.hostdevs,
744
self._devices, self._install_devices]:
754
raise ValueError(_("Did not find device %s") % str(dev))
757
xpath = dev.get_xml_node_path()
759
self._remove_child_xpath(xpath)
762
################################
763
# Private xml building methods #
764
################################
766
def _parsexml(self, xml, node):
767
XMLBuilderDomain.XMLBuilderDomain._parsexml(self, xml, node)
770
"disk" : virtinst.VirtualDisk,
771
"interface" : virtinst.VirtualNetworkInterface,
772
"sound" : virtinst.VirtualAudio,
773
"hostdev" : virtinst.VirtualHostDevice,
774
"input" : virtinst.VirtualInputDevice,
775
"serial" : virtinst.VirtualCharDevice,
776
"parallel" : virtinst.VirtualCharDevice,
777
"console" : virtinst.VirtualCharDevice,
778
"channel" : virtinst.VirtualCharDevice,
779
"graphics" : virtinst.VirtualGraphics,
780
"video" : virtinst.VirtualVideoDevice,
781
"watchdog" : virtinst.VirtualWatchdog,
782
"controller": virtinst.VirtualController,
783
"filesystem": virtinst.VirtualFilesystem,
784
"smartcard" : virtinst.VirtualSmartCardDevice,
785
"redirdev" : virtinst.VirtualRedirDevice,
788
# Hand off all child element parsing to relevant classes
789
caps = self._get_caps()
790
for node in self._xml_node.children:
791
if node.name != "devices":
794
children = filter(lambda x: (x.name in device_mappings and
797
for devnode in children:
798
objclass = device_mappings.get(devnode.name)
800
if objclass == virtinst.VirtualCharDevice:
801
dev = objclass(self.conn, devnode.name,
802
parsexmlnode=devnode, caps=caps)
804
dev = objclass(conn=self.conn,
805
parsexmlnode=devnode, caps=caps)
806
self._add_device(dev)
808
self._installer = virtinst.Installer.Installer(self.conn,
809
parsexmlnode=self._xml_node,
811
self._features = DomainFeatures(self.conn,
812
parsexmlnode=self._xml_node,
814
self._clock = Clock(self.conn, parsexmlnode=self._xml_node, caps=caps)
815
self._seclabel = Seclabel(self.conn, parsexmlnode=self._xml_node,
817
self._cpu = CPU(self.conn, parsexmlnode=self._xml_node, caps=caps)
818
self._numatune = DomainNumatune(self.conn,
819
parsexmlnode=self._xml_node, caps=caps)
821
def _get_default_input_device(self):
823
Return a VirtualInputDevice.
825
if self.installer and self.installer.is_container():
827
dev = VirtualInputDevice(self.conn)
830
def _get_default_console_device(self):
832
Only implemented for FullVirtGuest
834
dev = VirtualCharDevice.get_dev_instance(self.conn,
835
VirtualCharDevice.DEV_CONSOLE,
836
VirtualCharDevice.CHAR_PTY)
839
def _get_device_xml(self, devs, install=True):
841
def do_remove_media(d):
842
# Keep cdrom around, but with no media attached,
843
# But only if we are a distro that doesn't have a multi
844
# stage install (aka not Windows)
845
return (d.virtual_device_type == VirtualDevice.VIRTUAL_DEV_DISK and
846
d.device == VirtualDisk.DEVICE_CDROM
849
not self.get_continue_inst())
852
# Skip transient labeled non-media disks
853
return (d.virtual_device_type == VirtualDevice.VIRTUAL_DEV_DISK and
854
d.device == VirtualDisk.DEVICE_DISK
858
# Wrapper for building disk XML, handling transient CDROMs
859
def get_dev_xml(dev):
862
if do_skip_disk(dev):
865
if do_remove_media(dev):
869
return dev.get_xml_config()
874
xml = self._get_emulator_xml()
877
xml = _util.xml_append(xml, get_dev_xml(dev))
881
def _get_emulator_xml(self):
882
emulator = self.emulator
883
if self.installer.is_xenpv():
886
if (not self.emulator and
887
self.installer.is_hvm() and
889
if self._get_caps().host.arch in ("x86_64"):
890
emulator = "/usr/lib64/xen/bin/qemu-dm"
892
emulator = "/usr/lib/xen/bin/qemu-dm"
895
if emulator is not None:
896
emu_xml = " <emulator>%s</emulator>" % emulator
900
def _get_features_xml(self, features):
902
Return features (pae, acpi, apic) xml
904
if self.installer and self.installer.is_container():
906
return features.get_xml_config()
908
def _get_cpu_xml(self):
912
self.cpu.set_topology_defaults(self.vcpus)
913
return self.cpu.get_xml_config()
915
def _get_clock_xml(self):
919
return self.clock.get_xml_config()
921
def _get_seclabel_xml(self):
923
Return <seclabel> XML
927
xml = self.seclabel.get_xml_config()
931
def _get_osblob(self, install):
933
Return os, features, and clock xml (Implemented in subclass)
937
osxml = self.installer.get_xml_config(self, install)
941
xml = _util.xml_append(xml,
942
self.installer.get_xml_config(self, install))
945
def _get_vcpu_xml(self):
946
curvcpus_supported = virtinst.support.check_conn_support(
948
virtinst.support.SUPPORT_CONN_MAXVCPUS_XML)
950
if self.cpuset is not None:
951
cpuset = " cpuset='%s'" % self.cpuset
957
if maxv != curv and curvcpus_supported:
958
curxml = " current='%s'" % curv
962
return " <vcpu%s%s>%s</vcpu>" % (cpuset, curxml, maxv)
964
############################
965
# Install Helper functions #
966
############################
968
def _prepare_install(self, meter, dry=False):
969
self._install_devices = []
972
# Fetch install media, prepare installer devices
973
self._installer.prepare(guest=self,
976
# Initialize install device list
977
for dev in self._installer.install_devices:
978
self._install_devices.append(dev)
980
def _cleanup_install(self):
981
self._installer.cleanup()
983
def _create_devices(self, progresscb):
985
Ensure that devices are setup
987
for dev in self.get_all_devices():
988
dev.setup_dev(self.conn, progresscb)
994
def _get_xml_config(self, install=True, disk_boot=False):
996
Return the full Guest xml configuration.
998
@param install: Whether we want the 'OS install' configuration or
999
the 'post-install' configuration. (Some Installers,
1000
like the LiveCDInstaller may not have an 'install'
1002
@type install: C{bool}
1003
@param disk_boot: Whether we should boot off the harddisk, regardless
1004
of our position in the install process (this is
1005
used for 2 stage installs, where the second stage
1006
boots off the disk. You probably don't need to touch
1008
@type disk_boot: C{bool}
1010
# We do a shallow copy of the device list here, and set the defaults.
1011
# This way, default changes aren't persistent, and we don't need
1012
# to worry about when to call set_defaults
1013
origdevs = self.get_all_devices()
1015
for dev in origdevs:
1016
devs.append(dev.copy())
1017
tmpfeat = self.features.copy()
1019
def get_transient_devices(devtype):
1020
return self._dev_build_list(devtype, devs)
1021
def remove_transient_device(device):
1024
# Set device defaults so we can validly generate XML
1025
self._set_defaults(get_transient_devices,
1026
remove_transient_device,
1034
osblob_install = install
1036
osblob_install = False
1038
osblob = self._get_osblob(osblob_install)
1039
if osblob_install and not self.installer.has_install_phase():
1043
if self.description is not None:
1044
desc = str(self.description)
1045
desc_xml = (" <description>%s</description>" %
1046
_util.xml_escape(desc))
1049
add = lambda x: _util.xml_append(xml, x)
1051
xml = add("<domain type='%s'>" % self.type)
1052
xml = add(" <name>%s</name>" % self.name)
1053
xml = add(" <uuid>%s</uuid>" % self.uuid)
1055
xml = add(" <memory>%s</memory>" % (self.maxmemory * 1024))
1056
xml = add(" <currentMemory>%s</currentMemory>" % (self.memory * 1024))
1060
if self.hugepage is True:
1061
xml = add(" <memoryBacking>")
1062
xml = add(" <hugepages/>")
1063
xml = add(" </memoryBacking>")
1065
xml = add(self._get_vcpu_xml())
1067
xml = add(self.numatune.get_xml_config())
1069
# XXX: <bootloader> goes here, not in installer XML
1070
xml = add(" %s" % osblob)
1071
xml = add(self._get_features_xml(tmpfeat))
1072
xml = add(self._get_cpu_xml())
1073
xml = add(self._get_clock_xml())
1074
xml = add(" <on_poweroff>destroy</on_poweroff>")
1075
xml = add(" <on_reboot>%s</on_reboot>" % action)
1076
xml = add(" <on_crash>%s</on_crash>" % action)
1077
xml = add(" <devices>")
1078
xml = add(self._get_device_xml(devs, install))
1079
xml = add(" </devices>")
1080
xml = add(self._get_seclabel_xml())
1081
xml = add("</domain>\n")
1085
def post_install_check(self):
1087
Back compat mapping to installer post_install_check
1089
return self.installer.post_install_check(self)
1091
def get_continue_inst(self):
1093
Return True if this guest requires a call to 'continue_install',
1094
which means the OS requires a 2 stage install (windows)
1096
# If we are doing an 'import' or 'liveCD' install, there is
1097
# no true install process, so continue install has no meaning
1098
if not self.installer.has_install_phase():
1101
return self._lookup_osdict_key("continue")
1103
def validate_parms(self):
1105
Do some pre-install domain validation
1107
if self.domain is not None:
1108
raise RuntimeError(_("Domain has already been started!"))
1110
if self.name is None or self.memory is None:
1111
raise RuntimeError(_("Name and memory must be specified for "
1114
if _util.vm_uuid_collision(self.conn, self.uuid):
1115
raise RuntimeError(_("The UUID you entered is already in "
1116
"use by another guest!"))
1118
def connect_console(self, consolecb, wait=True):
1120
Launched the passed console callback for the already defined
1121
domain. If domain isn't running, return an error.
1124
self._consolechild) = self._wait_and_connect_console(consolecb)
1126
# If we connected the console, wait for it to finish
1127
self._waitpid_console(self._consolechild, wait)
1129
def terminate_console(self):
1131
Kill guest console if it is open (and actually exists), otherwise
1134
if self._consolechild:
1136
os.kill(self._consolechild, signal.SIGKILL)
1140
def domain_is_shutdown(self):
1142
Return True if the created domain object is shutdown
1148
dominfo = dom.info()
1151
cpu_time = dominfo[4]
1153
if state == libvirt.VIR_DOMAIN_SHUTOFF:
1156
# If 'wait' was specified, the dom object we have was looked up
1157
# before initially shutting down, which seems to bogus up the
1158
# info data (all 0's). So, if it is bogus, assume the domain is
1159
# shutdown. We will catch the error later.
1160
return state == libvirt.VIR_DOMAIN_NOSTATE and cpu_time == 0
1162
def domain_is_crashed(self):
1164
Return True if the created domain object is in a crashed state
1169
dominfo = self.domain.info()
1172
return state == libvirt.VIR_DOMAIN_CRASHED
1174
##########################
1175
# Actual install methods #
1176
##########################
1178
def remove_original_vm(self, force=None):
1180
Remove the existing VM with the same name if requested, or error
1181
if there is a collision.
1184
force = self.replace
1188
vm = self.conn.lookupByName(self.name)
1189
except libvirt.libvirtError:
1196
raise RuntimeError(_("Domain named %s already exists!") %
1200
logging.debug("Explicitly replacing guest '%s'", self.name)
1202
logging.info("Destroying guest '%s'", self.name)
1205
logging.info("Undefining guest '%s'", self.name)
1207
except libvirt.libvirtError, e:
1208
raise RuntimeError(_("Could not remove old vm '%s': %s") %
1209
(self.name, str(e)))
1211
def start_install(self, consolecb=None, meter=None, removeOld=None,
1212
wait=True, dry=False, return_xml=False, noboot=False):
1214
Begin the guest install (stage1).
1215
@param return_xml: Don't create the guest, just return generated XML
1219
self.validate_parms()
1220
self._consolechild = None
1222
self._prepare_install(meter, dry)
1224
# Create devices if required (disk images, etc.)
1226
self._create_devices(meter)
1228
start_xml, final_xml = self._build_xml(is_initial)
1230
return (start_xml, final_xml)
1234
# Remove existing VM if requested
1235
self.remove_original_vm(removeOld)
1237
self.domain = self._create_guest(consolecb, meter, wait,
1238
start_xml, final_xml, is_initial,
1241
# Set domain autostart flag if requested
1242
self._flag_autostart()
1246
self._cleanup_install()
1248
def continue_install(self, consolecb=None, meter=None, wait=True,
1249
dry=False, return_xml=False):
1251
Continue with stage 2 of a guest install. Only required for
1252
guests which have the 'continue' flag set (accessed via
1256
start_xml, final_xml = self._build_xml(is_initial)
1258
return (start_xml, final_xml)
1262
return self._create_guest(consolecb, meter, wait,
1263
start_xml, final_xml, is_initial, False)
1265
def _build_meter(self, meter, is_initial):
1267
meter_label = _("Creating domain...")
1269
meter_label = _("Starting domain...")
1272
meter = progress.BaseMeter()
1273
meter.start(size=None, text=meter_label)
1277
def _build_xml(self, is_initial):
1278
log_label = is_initial and "install" or "continue"
1279
disk_boot = not is_initial
1281
start_xml = self.get_xml_config(install=True, disk_boot=disk_boot)
1282
final_xml = self.get_xml_config(install=False)
1284
logging.debug("Generated %s XML: %s",
1286
(start_xml and ("\n" + start_xml) or "None required"))
1287
logging.debug("Generated boot XML: \n%s", final_xml)
1289
return start_xml, final_xml
1291
def _create_guest(self, consolecb, meter, wait,
1292
start_xml, final_xml, is_initial, noboot):
1294
Actually do the XML logging, guest defining/creating, console
1295
launching and waiting
1297
@param is_initial: If running initial guest creation, else we
1298
are continuing the install
1299
@param noboot: Don't boot guest if no install phase
1301
meter = self._build_meter(meter, is_initial)
1302
doboot = not noboot or self.installer.has_install_phase()
1306
if is_initial and doboot:
1307
dom = self.conn.createLinux(start_xml or final_xml, 0)
1309
dom = self.conn.defineXML(start_xml or final_xml)
1317
logging.debug("Started guest, connecting to console if requested")
1319
self._consolechild) = self._wait_and_connect_console(consolecb)
1321
self.domain = self.conn.defineXML(final_xml)
1324
logging.debug("XML fetched from libvirt object:\n%s",
1326
except Exception, e:
1327
logging.debug("Error fetching XML from libvirt object: %s", e)
1329
# if we connected the console, wait for it to finish
1330
self._waitpid_console(self._consolechild, wait)
1332
return self.conn.lookupByName(self.name)
1335
def _wait_and_connect_console(self, consolecb):
1337
Wait for domain to appear and be running, then connect to
1338
the console if necessary
1341
dom = _wait_for_domain(self.conn, self.name)
1344
raise RuntimeError(_("Domain has not existed. You should be "
1345
"able to find more information in the logs"))
1346
elif dom.ID() == -1:
1347
raise RuntimeError(_("Domain has not run yet. You should be "
1348
"able to find more information in the logs"))
1351
child = consolecb(dom)
1355
def _waitpid_console(self, console_child, do_wait):
1357
Wait for console to close if it was launched
1359
if not console_child or not do_wait:
1363
os.waitpid(console_child, 0)
1364
except OSError, (err_no, msg):
1365
logging.debug("waitpid: %s: %s", err_no, msg)
1367
# ensure there's time for the domain to finish destroying if the
1368
# install has finished or the guest crashed
1371
def _flag_autostart(self):
1373
Set the autostart flag for self.domain if the user requested it
1375
if not self.autostart:
1379
self.domain.setAutostart(True)
1380
except libvirt.libvirtError, e:
1381
if support.is_error_nosupport(e):
1382
logging.warn("Could not set autostart flag: libvirt "
1383
"connection does not support autostart.")
1392
def set_defaults(self):
1394
Public function to set guest defaults. Things like preferred
1395
disk bus (unless one is specified). These changes are persistent.
1396
The install process will call a non-persistent version, so calling
1397
this manually isn't required.
1399
self._set_defaults(self.get_devices, self.remove_device,
1402
def _set_hvm_defaults(self, devlist_func, features):
1403
disktype = VirtualDevice.VIRTUAL_DEV_DISK
1404
nettype = VirtualDevice.VIRTUAL_DEV_NET
1405
disk_bus = self._lookup_device_param(disktype, "bus")
1406
net_model = self._lookup_device_param(nettype, "model")
1408
# Only overwrite params if they weren't already specified
1409
for net in devlist_func(nettype):
1410
if net_model and not net.model:
1411
net.model = net_model
1413
for disk in devlist_func(disktype):
1414
if (disk_bus and not disk.bus and
1415
disk.device == VirtualDisk.DEVICE_DISK):
1418
if self.clock.offset == None:
1419
self.clock.offset = self._lookup_osdict_key("clock")
1421
if features["acpi"] is None:
1422
features["acpi"] = self._lookup_osdict_key("acpi")
1423
if features["apic"] is None:
1424
features["apic"] = self._lookup_osdict_key("apic")
1425
if features["pae"] is None and self._get_caps():
1426
features["pae"] = self._get_caps().support_pae()
1429
def _set_pv_defaults(self, devlist_func, remove_func):
1430
# Default file backed PV guests to tap driver
1431
for d in devlist_func(VirtualDevice.VIRTUAL_DEV_DISK):
1432
if (d.type == VirtualDisk.TYPE_FILE
1433
and _util.is_blktap_capable()
1434
and d.driver_name == None):
1435
d.driver_name = VirtualDisk.DRIVER_TAP
1437
for d in devlist_func(VirtualDevice.VIRTUAL_DEV_INPUT):
1438
if d.type == d.INPUT_TYPE_DEFAULT:
1439
d.type = d.INPUT_TYPE_MOUSE
1440
if d.bus == d.INPUT_BUS_DEFAULT:
1441
d.bus = d.INPUT_BUS_XEN
1443
for d in devlist_func(VirtualDevice.VIRTUAL_DEV_CONSOLE):
1444
if hasattr(d, "virtinst_default"):
1447
def add_usb_ich9_controllers(self):
1448
ctrl = VirtualControllerUSB(self.conn,
1450
self.add_device(ctrl)
1452
ctrl = VirtualControllerUSB(self.conn,
1454
ctrl.get_master().startport = 0
1455
self.add_device(ctrl)
1457
ctrl = VirtualControllerUSB(self.conn,
1459
ctrl.get_master().startport = 2
1460
self.add_device(ctrl)
1462
ctrl = VirtualControllerUSB(self.conn,
1464
ctrl.get_master().startport = 4
1465
self.add_device(ctrl)
1467
def _set_defaults(self, devlist_func, remove_func, features):
1468
if self.installer.is_hvm():
1469
self._set_hvm_defaults(devlist_func, features)
1470
if self.installer.is_xenpv():
1471
self._set_pv_defaults(devlist_func, remove_func)
1473
soundtype = VirtualDevice.VIRTUAL_DEV_AUDIO
1474
videotype = VirtualDevice.VIRTUAL_DEV_VIDEO
1475
inputtype = VirtualDevice.VIRTUAL_DEV_INPUT
1476
gfxtype = VirtualDevice.VIRTUAL_DEV_GRAPHICS
1477
channeltype = VirtualDevice.VIRTUAL_DEV_CHANNEL
1479
# Set default input values
1480
input_type = self._lookup_device_param(inputtype, "type")
1481
input_bus = self._lookup_device_param(inputtype, "bus")
1482
for inp in devlist_func(inputtype):
1483
if (inp.type == inp.INPUT_TYPE_DEFAULT and
1484
inp.bus == inp.INPUT_BUS_DEFAULT):
1485
inp.type = input_type
1488
# Generate disk targets, and set preferred disk bus
1490
for disk in devlist_func(VirtualDevice.VIRTUAL_DEV_DISK):
1492
if disk.device == disk.DEVICE_FLOPPY:
1495
if self.installer.is_hvm():
1497
elif self.installer.is_xenpv():
1499
used_targets.append(disk.generate_target(used_targets))
1501
# Set sound device model
1502
sound_model = self._lookup_device_param(soundtype, "model")
1503
for sound in devlist_func(soundtype):
1504
if sound.model == sound.MODEL_DEFAULT:
1505
sound.model = sound_model
1507
# Set video device model
1508
# QXL device (only if we use spice) - safe even if guest is VGA only
1510
for gfx in devlist_func(gfxtype):
1511
if gfx.type == gfx.TYPE_SPICE:
1516
video_model = self._lookup_device_param(videotype, "model_type")
1518
for video in devlist_func(videotype):
1519
if video.model_type == video.MODEL_DEFAULT:
1520
video.model_type = video_model
1522
# Spice agent channel (only if we use spice)
1523
def has_spice_agent():
1524
for chn in devlist_func(channeltype):
1525
if chn.char_type == chn.CHAR_SPICEVMC:
1529
not has_spice_agent() and
1530
support.check_conn_support(self.conn,
1531
support.SUPPORT_CONN_HV_CHAR_SPICEVMC)):
1532
agentdev = VirtualCharDevice.get_dev_instance(self.conn,
1533
VirtualCharDevice.DEV_CHANNEL,
1534
VirtualCharDevice.CHAR_SPICEVMC)
1535
self.add_device(agentdev)
1538
if self.uuid is None:
1540
for ignore in range(256):
1541
self.uuid = _util.uuidToString(_util.randomUUID())
1542
if _util.vm_uuid_collision(self.conn, self.uuid):
1548
logging.debug("Failed to generate non-conflicting UUID")
1551
###################################
1552
# Guest Dictionary Helper methods #
1553
###################################
1555
def _is_rhel6(self):
1556
emulator = self.emulator or ""
1558
return (self.type in ["qemu", "kvm"] and
1559
emulator.startswith("/usr/libexec/qemu"))
1561
def _lookup_osdict_key(self, key):
1563
Using self.os_type and self.os_variant to find key in OSTYPES
1564
@returns: dict value, or None if os_type/variant wasn't set
1566
return osdict.lookup_osdict_key(self.conn, self.type,
1567
self.os_type, self.os_variant,
1570
def _lookup_device_param(self, device_key, param):
1572
Check the OS dictionary for the prefered device setting for passed
1573
device type and param (bus, model, etc.)
1576
support._set_rhel6(self._is_rhel6())
1577
return osdict.lookup_device_param(self.conn, self.type,
1578
self.os_type, self.os_variant,
1581
support._set_rhel6(False)
1584
def _wait_for_domain(conn, name):
1585
# sleep in .25 second increments until either a) we get running
1586
# domain ID or b) it's been 5 seconds. this is so that
1587
# we can try to gracefully handle domain restarting failures
1589
for ignore in range(1, int(5 / .25)): # 5 seconds, .25 second sleeps
1591
dom = conn.lookupByName(name)
1592
if dom and dom.ID() != -1:
1594
except libvirt.libvirtError, e:
1595
logging.debug("No guest running yet: " + str(e))
1601
# Back compat class to avoid ABI break
1603
Guest.get_config_xml = Guest.get_xml_config