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,
25
import urlgrabber.progress as progress
28
import CapabilitiesParser
29
import VirtualGraphics
31
from VirtualDevice import VirtualDevice
32
from VirtualDisk import VirtualDisk
33
from Clock import Clock
34
from Seclabel import Seclabel
37
from virtinst import _virtinst as _
41
def _validate_cpuset(conn, val):
42
if val is None or val == "":
45
if type(val) is not type("string") or len(val) == 0:
46
raise ValueError, _("cpuset must be string")
47
if re.match("^[0-9,-]*$", val) is None:
48
raise ValueError, _("cpuset can only contain numeric, ',', or "
51
pcpus = _util.get_phy_cpus(conn)
52
for c in val.split(','):
56
raise ValueError, _("cpuset contains invalid format.")
57
if int(x) >= pcpus or int(y) >= pcpus:
58
raise ValueError, _("cpuset's pCPU numbers must be less "
65
raise ValueError, _("cpuset's pCPU numbers must be less "
71
# OS Dictionary static variables and methods
72
_DEFAULTS = osdict.DEFAULTS
73
_OS_TYPES = osdict.OS_TYPES
76
return osdict.sort_helper(Guest._OS_TYPES)
77
list_os_types = staticmethod(list_os_types)
79
def list_os_variants(type):
80
return osdict.sort_helper(Guest._OS_TYPES[type]["variants"])
81
list_os_variants = staticmethod(list_os_variants)
83
def get_os_type_label(type):
84
return Guest._OS_TYPES[type]["label"]
85
get_os_type_label = staticmethod(get_os_type_label)
87
def get_os_variant_label(type, variant):
88
return Guest._OS_TYPES[type]["variants"][variant]["label"]
89
get_os_variant_label = staticmethod(get_os_variant_label)
91
def cpuset_str_to_tuple(conn, cpuset):
92
_validate_cpuset(conn, cpuset)
93
pinlist = [False] * _util.get_phy_cpus(conn)
95
entries = cpuset.split(",")
97
series = e.split("-", 1)
100
pinlist[int(series[0])] = True
103
start = int(series[0])
106
for i in range(start, end):
109
return tuple(pinlist)
110
cpuset_str_to_tuple = staticmethod(cpuset_str_to_tuple)
112
def __init__(self, type=None, connection=None, hypervisorURI=None,
115
# Set up the connection, since it is fundamental for other init
116
self.conn = connection
117
if self.conn == None:
118
logging.debug("No conn passed to Guest, opening URI '%s'" % \
120
self.conn = libvirt.open(hypervisorURI)
122
if self.conn == None:
123
raise RuntimeError, _("Unable to connect to hypervisor, aborting "
126
# We specifically ignore the 'type' parameter here, since
127
# it has been replaced by installer.type, and child classes can
128
# use it when creating a default installer.
130
self._installer = installer
134
self._maxmemory = None
137
self._graphics_dev = None
138
self._autostart = False
139
self._clock = Clock(self.conn)
140
self._seclabel = None
141
self._description = None
146
self._os_variant = None
147
self._os_autodetect = False
149
# DEPRECATED: Public device lists unaltered by install process
155
# General device list. Only access through API calls (even internally)
158
# Device list to use/alter during install process. Don't access
159
# directly, use internal APIs
160
self._install_devices = []
162
# The libvirt virDomain object we 'Create'
164
self._consolechild = None
166
# Default disk target prefix ('hd' or 'xvd'). Set in subclass
169
# Default bus for disks (set in subclass)
172
# Indicates that default devices have been assigned, so look for
173
# the user to overwrite
174
self._default_console_assigned = None
175
self._default_input_assigned = None
177
self._caps = CapabilitiesParser.parse(self.conn.getCapabilities())
180
######################
181
# Property accessors #
182
######################
184
def get_installer(self):
185
return self._installer
186
def set_installer(self, val):
187
self._installer = val
188
installer = property(get_installer, set_installer)
192
clock = property(get_clock)
194
def get_seclabel(self):
195
return self._seclabel
196
def set_seclabel(self, val):
197
if val and not isinstance(val, Seclabel):
198
raise ValueError("'seclabel' must be a Seclabel() instance.")
201
# Check for validation purposes
204
seclabel = property(get_seclabel, set_seclabel)
206
# Domain name of the guest
209
def set_name(self, val):
210
_util.validate_name(_("Guest"), val)
213
if self.replace != True:
215
self.conn.lookupByName(val)
222
raise ValueError(_("Guest name '%s' is already in use.") % val)
225
name = property(get_name, set_name)
227
# Memory allocated to the guest. Should be given in MB
228
def get_memory(self):
230
def set_memory(self, val):
231
if (type(val) is not type(1) or val <= 0):
232
raise ValueError, _("Memory value must be an integer greater "
235
if self._maxmemory is None or self._maxmemory < val:
236
self._maxmemory = val
237
memory = property(get_memory, set_memory)
239
# Memory allocated to the guest. Should be given in MB
240
def get_maxmemory(self):
241
return self._maxmemory
242
def set_maxmemory(self, val):
243
if (type(val) is not type(1) or val <= 0):
244
raise ValueError, _("Max Memory value must be an integer greater "
246
self._maxmemory = val
247
maxmemory = property(get_maxmemory, set_maxmemory)
252
def set_uuid(self, val):
253
val = _util.validate_uuid(val)
255
uuid = property(get_uuid, set_uuid)
257
# number of vcpus for the guest
260
def set_vcpus(self, val):
261
maxvcpus = _util.get_max_vcpus(self.conn, self.type)
262
if type(val) is not int or val < 1:
263
raise ValueError, _("Number of vcpus must be a postive integer.")
265
raise ValueError, _("Number of vcpus must be no greater than %d "
266
"for this vm type.") % maxvcpus
268
vcpus = property(get_vcpus, set_vcpus)
270
# set phy-cpus for the guest
271
def get_cpuset(self):
273
def set_cpuset(self, val):
274
if val is None or val == "":
278
_validate_cpuset(self.conn, val)
280
cpuset = property(get_cpuset, set_cpuset)
282
def get_graphics_dev(self):
283
return self._graphics_dev
284
def set_graphics_dev(self, val):
285
self._graphics_dev = val
286
graphics_dev = property(get_graphics_dev, set_graphics_dev)
288
# GAH! - installer.os_type = "hvm" or "xen" (aka xen paravirt)
289
# guest.os_type = "Solaris", "Windows", "Linux"
290
# FIXME: We should really rename this property to something else,
291
# change it throughout the codebase for readability sake, but
292
# maintain back compat.
293
def get_os_type(self):
295
def set_os_type(self, val):
296
if type(val) is not str:
297
raise ValueError(_("OS type must be a string."))
300
if self._OS_TYPES.has_key(val):
301
if self._os_type != val:
302
# Invalidate variant, since it may not apply to the new os type
304
self._os_variant = None
306
raise ValueError, _("OS type '%s' does not exist in our "
309
# Default may have changed with OS info
310
self._set_default_input_dev()
311
os_type = property(get_os_type, set_os_type)
313
def get_os_variant(self):
314
return self._os_variant
315
def set_os_variant(self, val):
316
if type(val) is not str:
317
raise ValueError(_("OS variant must be a string."))
321
if self._OS_TYPES[self.os_type]["variants"].has_key(val):
322
self._os_variant = val
324
raise ValueError, _("OS variant '%(var)s' does not exist in "
325
"our dictionary for OS type '%(ty)s'" ) % \
326
{'var' : val, 'ty' : self._os_type}
329
for ostype in self.list_os_types():
330
if self._OS_TYPES[ostype]["variants"].has_key(val) and \
331
not self._OS_TYPES[ostype]["variants"][val].get("skip"):
332
logging.debug("Setting os type to '%s' for variant '%s'" %\
334
self.os_type = ostype
335
self._os_variant = val
339
raise ValueError, _("Unknown OS variant '%s'" % val)
341
# Default may have changed with OS info
342
self._set_default_input_dev()
343
os_variant = property(get_os_variant, set_os_variant)
345
def set_os_autodetect(self, val):
346
self._os_autodetect = bool(val)
347
def get_os_autodetect(self):
348
return self._os_autodetect
349
os_autodetect = property(get_os_autodetect, set_os_autodetect)
351
# Get the current variants 'distro' tag: 'rhel', 'fedora', etc.
352
def get_os_distro(self):
353
return self._lookup_osdict_key("distro")
354
os_distro = property(get_os_distro)
356
def get_autostart(self):
357
return self._autostart
358
def set_autostart(self, val):
359
self._autostart = bool(val)
360
autostart = property(get_autostart, set_autostart,
361
doc="Have domain autostart when the host boots.")
363
def _get_description(self):
364
return self._description
365
def _set_description(self, val):
366
self._description = val
367
description = property(_get_description, _set_description)
369
def _get_replace(self):
371
def _set_replace(self, val):
372
self._replace = bool(val)
373
replace = property(_get_replace, _set_replace,
374
doc=_("Whether we should overwrite an existing guest "
375
"with the same name."))
377
#########################
378
# DEPRECATED PROPERTIES #
379
#########################
381
# Deprecated: Should set graphics_dev.keymap directly
382
def get_keymap(self):
383
if self._graphics_dev is None:
385
return self._graphics_dev.keymap
386
def set_keymap(self, val):
387
if self._graphics_dev is not None:
388
self._graphics_dev.keymap = val
389
keymap = property(get_keymap, set_keymap)
391
# Deprecated: Should set guest.graphics_dev = VirtualGraphics(...)
392
def get_graphics(self):
393
if self._graphics_dev is None:
394
return { "enabled" : False }
395
return { "enabled" : True, "type" : self._graphics_dev, \
396
"keymap" : self._graphics_dev.keymap}
397
def set_graphics(self, val):
400
# a dictionary with keys: enabled, type, port, keymap
401
# a tuple of the form : (enabled, type, port, keymap)
403
# : "vnc", "sdl", or false
409
if type(val) == dict:
410
if not val.has_key("enabled"):
411
raise ValueError, _("Must specify whether graphics are enabled")
412
enabled = val["enabled"]
413
if val.has_key("type"):
415
if val.has_key("opts"):
417
elif type(val) == tuple:
427
if val in ("vnc", "sdl"):
433
if enabled not in (True, False):
434
raise ValueError, _("Graphics enabled must be True or False")
437
gdev = VirtualGraphics.VirtualGraphics(type=gtype)
442
self._graphics_dev = gdev
444
graphics = property(get_graphics, set_graphics)
446
# Hypervisor name (qemu, xen, kvm, etc.)
447
# Deprecated: should be pulled directly from the installer
449
return self._installer.type
450
def set_type(self, val):
451
self._installer.type = val
452
type = property(get_type, set_type)
454
# Deprecated: should be pulled directly from the installer
456
return self.installer.arch
457
def set_arch(self, val):
458
self.installer.arch = val
459
arch = property(get_arch, set_arch)
461
# Deprecated: Should be called from the installer directly
462
def get_location(self):
463
return self._installer.location
464
def set_location(self, val):
465
self._installer.location = val
466
location = property(get_location, set_location)
468
# Deprecated: Should be called from the installer directly
469
def get_scratchdir(self):
470
return self._installer.scratchdir
471
scratchdir = property(get_scratchdir)
473
# Deprecated: Should be called from the installer directly
475
return self._installer.boot
476
def set_boot(self, val):
477
self._installer.boot = val
478
boot = property(get_boot, set_boot)
480
# Deprecated: Should be called from the installer directly
481
def get_extraargs(self):
482
return self._installer.extraargs
483
def set_extraargs(self, val):
484
self._installer.extraargs = val
485
extraargs = property(get_extraargs, set_extraargs)
487
# Deprecated: Should set the installer values directly
489
return self._installer.location
490
def set_cdrom(self, val):
491
self._installer.location = val
492
self._installer.cdrom = True
493
cdrom = property(get_cdrom, set_cdrom)
496
########################################
497
# Device Add/Remove Public API methods #
498
########################################
500
def _dev_build_list(self, devtype, devlist=None):
502
devlist = self._devices
506
if i.virtual_device_type == devtype:
510
def add_device(self, dev):
512
Add the passed device to the guest's device list.
514
@param dev: VirtualDevice instance to attach to guest
516
if not isinstance(dev, VirtualDevice):
517
raise ValueError(_("Must pass a VirtualDevice instance."))
518
devtype = dev.virtual_device_type
520
# Handling for back compat default device behavior
521
if ((devtype == VirtualDevice.VIRTUAL_DEV_CONSOLE or
522
devtype == VirtualDevice.VIRTUAL_DEV_SERIAL) and
523
self._default_console_assigned == True):
525
rmdev = self.get_devices(VirtualDevice.VIRTUAL_DEV_CONSOLE)[0]
526
self.remove_device(rmdev)
527
self._default_console_assigned = False
529
if (devtype == VirtualDevice.VIRTUAL_DEV_INPUT and
530
self._default_input_assigned == True):
532
rmdev = self.get_devices(VirtualDevice.VIRTUAL_DEV_INPUT)[0]
533
self.remove_device(rmdev)
534
self._default_input_assigned = False
536
# Actually add the device
537
if devtype == VirtualDevice.VIRTUAL_DEV_DISK:
538
self.disks.append(dev)
539
elif devtype == VirtualDevice.VIRTUAL_DEV_NET:
540
self.nics.append(dev)
541
elif devtype == VirtualDevice.VIRTUAL_DEV_AUDIO:
542
self.sound_devs.append(dev)
543
elif devtype == VirtualDevice.VIRTUAL_DEV_GRAPHICS:
544
self._graphics_dev = dev
545
elif devtype == VirtualDevice.VIRTUAL_DEV_HOSTDEV:
546
self.hostdevs.append(dev)
548
self._devices.append(dev)
550
def get_devices(self, devtype):
552
Return a list of devices of type 'devtype' that will installed on
555
@param devtype: Device type to search for (one of
556
VirtualDevice.virtual_device_types)
558
if devtype == VirtualDevice.VIRTUAL_DEV_DISK:
560
elif devtype == VirtualDevice.VIRTUAL_DEV_NET:
562
elif devtype == VirtualDevice.VIRTUAL_DEV_AUDIO:
563
return self.sound_devs[:]
564
elif devtype == VirtualDevice.VIRTUAL_DEV_GRAPHICS:
565
return self._graphics_dev and [self._graphics_dev] or []
566
elif devtype == VirtualDevice.VIRTUAL_DEV_HOSTDEV:
567
return self.hostdevs[:]
569
return self._dev_build_list(devtype)
571
def get_all_devices(self):
573
Return a list of all devices being installed with the guest
576
for devtype in VirtualDevice.virtual_device_types:
577
retlist.extend(self.get_devices(devtype))
580
def remove_device(self, dev):
582
Remove the passed device from the guest's device list
584
@param dev: VirtualDevice instance
587
if dev == self._graphics_dev:
588
self._graphics_dev = None
591
for devlist in [self.disks, self.nics, self.sound_devs, self.hostdevs,
602
raise ValueError(_("Did not find device %s") % str(dev))
604
if (dev.virtual_device_type == VirtualDevice.VIRTUAL_DEV_INPUT and
605
self._default_input_assigned == True):
606
self._default_input_assigned = False
607
if (dev.virtual_device_type in [VirtualDevice.VIRTUAL_DEV_CONSOLE,
608
VirtualDevice.VIRTUAL_DEV_SERIAL] and
609
self._default_console_assigned == True):
610
self._default_console_assigned = False
613
# Device fetching functions used internally during the install process.
614
# These allow us to change dev defaults, add install media, etc. during
615
# the install, but revert to a clean state if the install fails
616
def _get_install_devs(self, devtype):
617
return self._dev_build_list(devtype, self._install_devices)
619
def _add_install_dev(self, dev):
620
self._install_devices.append(dev)
622
def _get_all_install_devs(self):
624
for devtype in VirtualDevice.virtual_device_types:
625
retlist.extend(self._get_install_devs(devtype))
629
################################
630
# Private xml building methods #
631
################################
633
def _get_input_device(self):
634
""" Return a tuple of the form (devtype, bus) for the desired
635
input device. (Must be implemented in subclass) """
636
raise NotImplementedError
638
def _get_device_xml(self, install=True):
639
# If install hasn't been prepared yet, make sure we use
640
# the regular device list
641
inst_devs = self._get_all_install_devs()
642
reg_devs = self.get_all_devices()
643
if len(inst_devs) >= len(reg_devs):
648
def do_remove_media(d):
649
# Keep cdrom around, but with no media attached,
650
# But only if we are a distro that doesn't have a multi
651
# stage install (aka not Windows)
652
return (d.virtual_device_type == VirtualDevice.VIRTUAL_DEV_DISK and
653
d.device == VirtualDisk.DEVICE_CDROM
656
not self.get_continue_inst())
658
# Wrapper for building disk XML, handling transient CDROMs
659
def get_dev_xml(dev):
662
if do_remove_media(dev):
666
return dev.get_xml_config()
674
xml = _util.xml_append(xml, get_dev_xml(dev))
678
def _get_features(self):
680
Determine the guest features, based on explicit settings in FEATURES
681
and the OS_TYPE and OS_VARIANT. FEATURES takes precedence over the OS
684
if self.features is None:
687
# explicitly disabling apic and acpi will override OS_TYPES values
688
features = dict(self.features)
689
for f in ["acpi", "apic"]:
690
val = self._lookup_osdict_key(f)
691
if features.get(f) == None:
695
def _get_features_xml(self):
697
Return features (pae, acpi, apic) xml
699
features = self._get_features()
700
found_feature = False
702
ret = " <features>\n"
706
for k in sorted(features.keys()):
713
if not found_feature:
714
# Don't print empty feature block if no features added
717
return ret + " </features>"
719
def _get_cpu_xml(self):
723
# Just a stub for now
726
def _get_clock_xml(self):
730
return self.clock.get_xml_config()
732
def _get_seclabel_xml(self):
734
Return <seclabel> XML
738
xml = self.seclabel.get_xml_config()
742
def _get_osblob(self, install):
744
Return os, features, and clock xml (Implemented in subclass)
748
osxml = self.installer.get_install_xml(self, install)
752
xml = _util.xml_append(xml,
753
self.installer.get_install_xml(self, install))
756
############################
757
# Install Helper functions #
758
############################
760
def _prepare_install(self, meter):
761
# Initialize install device list
762
self._install_devices = self.get_all_devices()[:]
764
# Set regular device defaults
767
self._installer.prepare(guest = self,
769
if self._installer.install_disk is not None:
770
self._add_install_dev(self._installer.install_disk)
772
# Run 'set_defaults' after install prep, since some installers
773
# (ImageInstaller) alter the device list.
774
self._set_defaults(self._get_install_devs)
776
def _cleanup_install(self):
777
# Empty install dev list
778
self._install_devices = []
780
self._installer.cleanup()
782
def _create_devices(self, progresscb):
784
Ensure that devices are setup
786
for dev in self._get_all_install_devs():
787
dev.setup_dev(self.conn, progresscb)
793
def get_config_xml(self, install = True, disk_boot = False):
795
Return the full Guest xml configuration.
797
@param install: Whether we want the 'OS install' configuration or
798
the 'post-install' configuration. (Some Installers,
799
like the LiveCDInstaller may not have an 'install'
801
@type install: C{bool}
802
@param disk_boot: Whether we should boot off the harddisk, regardless
803
of our position in the install process (this is
804
used for 2 stage installs, where the second stage
805
boots off the disk. You probably don't need to touch
807
@type disk_boot: C{bool}
810
# Set device defaults so we can validly generate XML
811
self._set_defaults(self.get_devices)
818
osblob_install = install
820
osblob_install = False
822
osblob = self._get_osblob(osblob_install)
824
# This means there is no 'install' phase, so just return
828
if self.cpuset is not None:
829
cpuset = " cpuset='" + self.cpuset + "'"
832
if self.description is not None:
833
desc = str(self.description)
834
desc_xml = (" <description>%s</description>" %
835
_util.xml_escape(desc))
838
add = lambda x: _util.xml_append(xml, x)
840
xml = add("<domain type='%s'>" % self.type)
841
xml = add(" <name>%s</name>" % self.name)
842
xml = add(" <currentMemory>%s</currentMemory>" % (self.memory * 1024))
843
xml = add(" <memory>%s</memory>" % (self.maxmemory * 1024))
844
xml = add(" <uuid>%s</uuid>" % self.uuid)
846
xml = add(" %s" % osblob)
847
xml = add(self._get_features_xml())
848
xml = add(self._get_cpu_xml())
849
xml = add(self._get_clock_xml())
850
xml = add(" <on_poweroff>destroy</on_poweroff>")
851
xml = add(" <on_reboot>%s</on_reboot>" % action)
852
xml = add(" <on_crash>%s</on_crash>" % action)
853
xml = add(" <vcpu%s>%d</vcpu>" % (cpuset, self.vcpus))
854
xml = add(" <devices>")
855
xml = add(self._get_device_xml(install))
856
xml = add(" </devices>")
857
xml = add(self._get_seclabel_xml())
858
xml = add("</domain>\n")
862
def post_install_check(self):
864
Back compat mapping to installer post_install_check
866
return self.installer.post_install_check(self)
868
def get_continue_inst(self):
870
Return True if this guest requires a call to 'continue_install',
871
which means the OS requires a 2 stage install (windows)
873
val = self._lookup_osdict_key("continue")
878
# If we are doing an 'import' or 'liveCD' install, there is
879
# no true install process, so continue install has no meaning
880
if not self.get_config_xml(install=True):
884
def validate_parms(self):
886
Do some pre-install domain validation
888
if self.domain is not None:
889
raise RuntimeError, _("Domain has already been started!")
891
if self.name is None or self.memory is None:
892
raise RuntimeError(_("Name and memory must be specified for "
895
if _util.vm_uuid_collision(self.conn, self.uuid):
896
raise RuntimeError(_("The UUID you entered is already in "
897
"use by another guest!"))
899
def connect_console(self, consolecb, wait=True):
901
Launched the passed console callback for the already defined
902
domain. If domain isn't running, return an error.
905
self._consolechild) = self._wait_and_connect_console(consolecb)
907
# If we connected the console, wait for it to finish
908
self._waitpid_console(self._consolechild, wait)
910
def terminate_console(self):
912
Kill guest console if it is open (and actually exists), otherwise
915
if self._consolechild:
917
os.kill(self._consolechild, signal.SIGKILL)
921
def domain_is_shutdown(self):
923
Return True if the created domain object is shutdown
932
cpu_time = dominfo[4]
934
if state == libvirt.VIR_DOMAIN_SHUTOFF:
937
# If 'wait' was specified, the dom object we have was looked up
938
# before initially shutting down, which seems to bogus up the
939
# info data (all 0's). So, if it is bogus, assume the domain is
940
# shutdown. We will catch the error later.
941
return state == libvirt.VIR_DOMAIN_NOSTATE and cpu_time == 0
943
def domain_is_crashed(self):
945
Return True if the created domain object is in a crashed state
950
dominfo = self.domain.info()
953
return state == libvirt.VIR_DOMAIN_CRASHED
955
##########################
956
# Actual install methods #
957
##########################
959
def start_install(self, consolecb=None, meter=None, removeOld=None,
962
Begin the guest install (stage1).
964
if removeOld == None:
965
removeOld = self.replace
967
self.validate_parms()
968
self._consolechild = None
970
self._prepare_install(meter)
972
return self._do_install(consolecb, meter, removeOld, wait)
974
self._cleanup_install()
976
def continue_install(self, consolecb=None, meter=None, wait=True):
978
Continue with stage 2 of a guest install. Only required for
979
guests which have the 'continue' flag set (accessed via
982
return self._create_guest(consolecb, meter, wait,
983
_("Starting domain..."), "continue",
987
def _create_guest(self, consolecb, meter, wait,
988
meter_label, log_label,
992
Actually do the XML logging, guest defining/creating, console
993
launching and waiting
996
meter = progress.BaseMeter()
998
start_xml = self.get_config_xml(install=True, disk_boot=disk_boot)
999
final_xml = self.get_config_xml(install=False)
1000
logging.debug("Generated %s XML: %s" %
1002
(start_xml and ("\n" + start_xml) or "None required")))
1005
meter.start(size=None, text=meter_label)
1008
dom = self.conn.createLinux(start_xml, 0)
1010
dom = self.conn.defineXML(start_xml)
1016
logging.debug("Started guest, looking to see if it is running")
1018
self._consolechild) = self._wait_and_connect_console(consolecb)
1020
logging.debug("Generated boot XML: \n%s" % final_xml)
1021
self.domain = self.conn.defineXML(final_xml)
1023
# if we connected the console, wait for it to finish
1024
self._waitpid_console(self._consolechild, wait)
1026
return self.conn.lookupByName(self.name)
1028
def _do_install(self, consolecb, meter, removeOld=False, wait=True):
1029
# Remove existing VM if requested
1030
self._replace_original_vm(removeOld)
1032
# Create devices if required (disk images, etc.)
1033
self._create_devices(meter)
1035
self.domain = self._create_guest(consolecb, meter, wait,
1036
_("Creating domain..."),
1039
# Set domain autostart flag if requested
1040
self._flag_autostart()
1044
def _wait_and_connect_console(self, consolecb):
1046
Wait for domain to appear and be running, then connect to
1047
the console if necessary
1050
dom = _wait_for_domain(self.conn, self.name)
1053
raise RuntimeError(_("Domain has not existed. You should be "
1054
"able to find more information in the logs"))
1055
elif dom.ID() == -1:
1056
raise RuntimeError(_("Domain has not run yet. You should be "
1057
"able to find more information in the logs"))
1060
logging.debug("Launching console callback")
1061
child = consolecb(dom)
1065
def _waitpid_console(self, console_child, do_wait):
1067
Wait for console to close if it was launched
1069
if not console_child or not do_wait:
1073
os.waitpid(console_child, 0)
1074
except OSError, (err_no, msg):
1075
logging.debug("waitpid: %s: %s" % (err_no, msg))
1077
# ensure there's time for the domain to finish destroying if the
1078
# install has finished or the guest crashed
1081
def _replace_original_vm(self, removeOld):
1083
Remove the existing VM with the same name if requested, or error
1084
if there is a collision.
1088
vm = self.conn.lookupByName(self.name)
1089
except libvirt.libvirtError:
1096
raise RuntimeError(_("Domain named %s already exists!") %
1101
logging.info("Destroying image %s" % self.name)
1104
logging.info("Removing old definition for image %s" % self.name)
1106
except libvirt.libvirtError, e:
1107
raise RuntimeError(_("Could not remove old vm '%s': %s") %
1108
(self.name, str(e)))
1111
def _flag_autostart(self):
1113
Set the autostart flag for self.domain if the user requested it
1115
if not self.autostart:
1119
self.domain.setAutostart(True)
1120
except libvirt.libvirtError, e:
1121
if support.is_error_nosupport(e):
1122
logging.warn("Could not set autostart flag: libvirt "
1123
"connection does not support autostart.")
1132
def _set_default_input_dev(self):
1133
# This is called at init time, but also whenever the OS changes,
1134
# since the input dev maybe be dependent on OS
1135
if self._default_input_assigned == False:
1138
for d in self.get_devices(VirtualDevice.VIRTUAL_DEV_INPUT):
1139
self.remove_device(d)
1141
# Add default input device
1142
self._default_input_assigned = False
1143
self.add_device(self._get_input_device())
1144
self._default_input_assigned = True
1146
def set_defaults(self):
1148
Public function to set guest defaults. Things like preferred
1149
disk bus (unless one is specified). This will be called by the
1150
install process, but can be called earlier if needed
1152
self._set_defaults(self.get_devices)
1154
def _set_defaults(self, devlist_func):
1155
soundtype = VirtualDevice.VIRTUAL_DEV_AUDIO
1156
videotype = VirtualDevice.VIRTUAL_DEV_VIDEO
1158
# Generate disk targets, and set preferred disk bus
1160
for disk in devlist_func(VirtualDevice.VIRTUAL_DEV_DISK):
1162
if disk.device == disk.DEVICE_FLOPPY:
1165
disk.bus = self._diskbus
1166
used_targets.append(disk.generate_target(used_targets))
1168
# Set sound device model
1169
sound_model = self._lookup_device_param(soundtype, "model")
1170
for sound in devlist_func(soundtype):
1171
if sound.model == sound.MODEL_DEFAULT:
1172
sound.model = sound_model
1174
# Set video device model
1175
video_model = self._lookup_device_param(videotype, "model_type")
1176
for video in devlist_func(videotype):
1177
if video.model_type == video.MODEL_DEFAULT:
1178
video.model_type = video_model
1181
if self.uuid is None:
1183
self.uuid = _util.uuidToString(_util.randomUUID())
1184
if _util.vm_uuid_collision(self.conn, self.uuid):
1189
###################################
1190
# Guest Dictionary Helper methods #
1191
###################################
1193
def _lookup_osdict_key(self, key):
1195
Using self.os_type and self.os_variant to find key in OSTYPES
1196
@returns: dict value, or None if os_type/variant wasn't set
1198
return osdict.lookup_osdict_key(self.conn, self.type, self.os_type,
1199
self.os_variant, key)
1201
def _lookup_device_param(self, device_key, param):
1203
Check the OS dictionary for the prefered device setting for passed
1204
device type and param (bus, model, etc.)
1206
return osdict.lookup_device_param(self.conn, self.type, self.os_type,
1207
self.os_variant, device_key, param)
1210
def _wait_for_domain(conn, name):
1211
# sleep in .25 second increments until either a) we get running
1212
# domain ID or b) it's been 5 seconds. this is so that
1213
# we can try to gracefully handle domain restarting failures
1215
for ignore in range(1, int(5 / .25)): # 5 seconds, .25 second sleeps
1217
dom = conn.lookupByName(name)
1218
if dom and dom.ID() != -1:
1220
except libvirt.libvirtError, e:
1221
logging.debug("No guest running yet: " + str(e))
1227
# Back compat class to avoid ABI break