guest: Encode defaults into the XML at install time
Previously we made all the default encoding non-permanent by XML objects before generating the XML, making changes to the copies, and restoring to the old state after the XML is returned to the user. This allows us to call start_install multiple times with the same Guest object and not alter it's original config... but that feature isn't really useful anymore, and this behavior makes the 'customize before install' dialog difficult to handle. So drop most of it, and fix some of the minor fallout.
This commit is contained in:
parent
be5c2c742c
commit
86f1133777
|
@ -287,43 +287,43 @@ class TestXMLMisc(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
# Use connver=12005 so that non-rhel displays ac97
|
# Use connver=12005 so that non-rhel displays ac97
|
||||||
conn = utils.open_rhelkvm(connver=12005)
|
conn = utils.open_rhelkvm(connver=12005)
|
||||||
|
|
||||||
g = _make_guest(conn=conn)
|
g = _make_guest(conn=conn)
|
||||||
do_install = False
|
|
||||||
|
|
||||||
# Call get_xml_config sets first round of defaults w/o os_variant set
|
|
||||||
g.get_install_xml(do_install)
|
|
||||||
|
|
||||||
g.os_variant = "fedora11"
|
g.os_variant = "fedora11"
|
||||||
self._compare(g, "install-f11-norheldefaults", do_install)
|
self._compare(g, "install-f11-norheldefaults", False)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
CLIConfig.stable_defaults = True
|
CLIConfig.stable_defaults = True
|
||||||
|
|
||||||
|
g = _make_guest(conn=conn)
|
||||||
|
g.os_variant = "fedora11"
|
||||||
origemu = g.emulator
|
origemu = g.emulator
|
||||||
g.emulator = "/usr/libexec/qemu-kvm"
|
g.emulator = "/usr/libexec/qemu-kvm"
|
||||||
self.assertTrue(g.conn.stable_defaults())
|
self.assertTrue(g.conn.stable_defaults())
|
||||||
|
|
||||||
setattr(g.conn, "_support_cache", {})
|
setattr(g.conn, "_support_cache", {})
|
||||||
self._compare(g, "install-f11-rheldefaults", do_install)
|
self._compare(g, "install-f11-rheldefaults", False)
|
||||||
g.emulator = origemu
|
g.emulator = origemu
|
||||||
setattr(g.conn, "_support_cache", {})
|
setattr(g.conn, "_support_cache", {})
|
||||||
finally:
|
finally:
|
||||||
CLIConfig.stable_defaults = False
|
CLIConfig.stable_defaults = False
|
||||||
|
|
||||||
# Verify main guest wasn't polluted
|
|
||||||
self._compare(g, "install-f11-norheldefaults", do_install)
|
|
||||||
|
|
||||||
def test_no_vmvga_RHEL(self):
|
def test_no_vmvga_RHEL(self):
|
||||||
# Test that vmvga is not used on RHEL
|
# Test that vmvga is not used on RHEL
|
||||||
conn = utils.open_rhelkvm()
|
conn = utils.open_rhelkvm()
|
||||||
g = _make_guest(conn=conn)
|
def _make():
|
||||||
|
g = _make_guest(conn=conn)
|
||||||
try:
|
|
||||||
g.emulator = "/usr/libexec/qemu-kvm"
|
g.emulator = "/usr/libexec/qemu-kvm"
|
||||||
g.add_default_video_device()
|
g.add_default_video_device()
|
||||||
g.os_variant = "ubuntu13.10"
|
g.os_variant = "ubuntu13.10"
|
||||||
|
return g
|
||||||
|
|
||||||
|
try:
|
||||||
|
g = _make()
|
||||||
self._compare(g, "install-novmvga-rhel", True)
|
self._compare(g, "install-novmvga-rhel", True)
|
||||||
|
|
||||||
CLIConfig.stable_defaults = True
|
CLIConfig.stable_defaults = True
|
||||||
|
g = _make()
|
||||||
self._compare(g, "install-novmvga-rhel", True)
|
self._compare(g, "install-novmvga-rhel", True)
|
||||||
finally:
|
finally:
|
||||||
CLIConfig.stable_defaults = False
|
CLIConfig.stable_defaults = False
|
||||||
|
|
|
@ -1626,7 +1626,7 @@ class ParserDisk(VirtCLIParser):
|
||||||
if not inst.target:
|
if not inst.target:
|
||||||
skip_targets = [d.target for d in self.guest.get_devices("disk")]
|
skip_targets = [d.target for d in self.guest.get_devices("disk")]
|
||||||
inst.generate_target(skip_targets)
|
inst.generate_target(skip_targets)
|
||||||
inst.cli_set_target = True
|
inst.cli_generated_target = True
|
||||||
|
|
||||||
return inst
|
return inst
|
||||||
|
|
||||||
|
|
|
@ -125,6 +125,7 @@ class Guest(XMLBuilder):
|
||||||
self.__os_object = None
|
self.__os_object = None
|
||||||
self._random_uuid = None
|
self._random_uuid = None
|
||||||
self._install_devices = []
|
self._install_devices = []
|
||||||
|
self._defaults_are_set = False
|
||||||
|
|
||||||
# The libvirt virDomain object we 'Create'
|
# The libvirt virDomain object we 'Create'
|
||||||
self.domain = None
|
self.domain = None
|
||||||
|
@ -301,22 +302,12 @@ class Guest(XMLBuilder):
|
||||||
self.add_device(dev)
|
self.add_device(dev)
|
||||||
self._install_devices.append(dev)
|
self._install_devices.append(dev)
|
||||||
|
|
||||||
|
|
||||||
##############
|
|
||||||
# Public API #
|
|
||||||
##############
|
|
||||||
|
|
||||||
def _prepare_get_xml(self):
|
def _prepare_get_xml(self):
|
||||||
# We do a shallow copy of the device list here, and set the defaults.
|
# We do a shallow copy of the OS block here, so that we can
|
||||||
# This way, default changes aren't persistent, and we don't need
|
# set the install time properties but not permanently overwrite
|
||||||
# to worry about when to call set_defaults
|
# any config the user explicitly requested.
|
||||||
#
|
data = self.os
|
||||||
# XXX: this is hacky, we should find a way to use xmlbuilder.copy(),
|
|
||||||
# but need to make sure it's not a massive performance hit
|
|
||||||
data = (self._devices[:], self.features, self.os)
|
|
||||||
try:
|
try:
|
||||||
self._propstore["_devices"] = [dev.copy() for dev in self._devices]
|
|
||||||
self._propstore["features"] = self.features.copy()
|
|
||||||
self._propstore["os"] = self.os.copy()
|
self._propstore["os"] = self.os.copy()
|
||||||
except:
|
except:
|
||||||
self._finish_get_xml(data)
|
self._finish_get_xml(data)
|
||||||
|
@ -324,11 +315,9 @@ class Guest(XMLBuilder):
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def _finish_get_xml(self, data):
|
def _finish_get_xml(self, data):
|
||||||
(self._propstore["_devices"],
|
self._propstore["os"] = data
|
||||||
self._propstore["features"],
|
|
||||||
self._propstore["os"]) = data
|
|
||||||
|
|
||||||
def get_install_xml(self, *args, **kwargs):
|
def _get_install_xml(self, *args, **kwargs):
|
||||||
data = self._prepare_get_xml()
|
data = self._prepare_get_xml()
|
||||||
try:
|
try:
|
||||||
return self._do_get_install_xml(*args, **kwargs)
|
return self._do_get_install_xml(*args, **kwargs)
|
||||||
|
@ -355,14 +344,19 @@ class Guest(XMLBuilder):
|
||||||
if osblob_install and not self.installer.has_install_phase():
|
if osblob_install and not self.installer.has_install_phase():
|
||||||
return None
|
return None
|
||||||
|
|
||||||
self.installer.alter_bootconfig(self, osblob_install, self.os)
|
self.installer.alter_bootconfig(self, osblob_install)
|
||||||
self._set_transient_device_defaults(install)
|
self._set_transient_device_defaults(install)
|
||||||
|
|
||||||
action = install and "destroy" or "restart"
|
action = install and "destroy" or "restart"
|
||||||
self.on_reboot = action
|
self.on_reboot = action
|
||||||
self.on_crash = action
|
self.on_crash = action
|
||||||
|
|
||||||
self._set_defaults()
|
self._set_osxml_defaults()
|
||||||
|
|
||||||
|
# Only set defaults on any install devices
|
||||||
|
for dev in self._install_devices:
|
||||||
|
dev.set_defaults(self)
|
||||||
|
self._set_disk_defaults(disks=self._install_devices)
|
||||||
|
|
||||||
self.bootloader = None
|
self.bootloader = None
|
||||||
if (not install and
|
if (not install and
|
||||||
|
@ -373,6 +367,11 @@ class Guest(XMLBuilder):
|
||||||
|
|
||||||
return self.get_xml_config()
|
return self.get_xml_config()
|
||||||
|
|
||||||
|
|
||||||
|
##############
|
||||||
|
# Public API #
|
||||||
|
##############
|
||||||
|
|
||||||
def get_continue_inst(self):
|
def get_continue_inst(self):
|
||||||
"""
|
"""
|
||||||
Return True if this guest requires a call to 'continue_install',
|
Return True if this guest requires a call to 'continue_install',
|
||||||
|
@ -385,11 +384,6 @@ class Guest(XMLBuilder):
|
||||||
|
|
||||||
return self._os_object.is_windows()
|
return self._os_object.is_windows()
|
||||||
|
|
||||||
|
|
||||||
##########################
|
|
||||||
# Actual install methods #
|
|
||||||
##########################
|
|
||||||
|
|
||||||
def start_install(self, meter=None,
|
def start_install(self, meter=None,
|
||||||
dry=False, return_xml=False, noboot=False):
|
dry=False, return_xml=False, noboot=False):
|
||||||
"""
|
"""
|
||||||
|
@ -400,6 +394,7 @@ class Guest(XMLBuilder):
|
||||||
raise RuntimeError(_("Domain has already been started!"))
|
raise RuntimeError(_("Domain has already been started!"))
|
||||||
|
|
||||||
is_initial = True
|
is_initial = True
|
||||||
|
self.set_install_defaults()
|
||||||
|
|
||||||
self._prepare_install(meter, dry)
|
self._prepare_install(meter, dry)
|
||||||
try:
|
try:
|
||||||
|
@ -461,8 +456,8 @@ class Guest(XMLBuilder):
|
||||||
log_label = is_initial and "install" or "continue"
|
log_label = is_initial and "install" or "continue"
|
||||||
disk_boot = not is_initial
|
disk_boot = not is_initial
|
||||||
|
|
||||||
start_xml = self.get_install_xml(install=True, disk_boot=disk_boot)
|
start_xml = self._get_install_xml(install=True, disk_boot=disk_boot)
|
||||||
final_xml = self.get_install_xml(install=False)
|
final_xml = self._get_install_xml(install=False)
|
||||||
|
|
||||||
logging.debug("Generated %s XML: %s",
|
logging.debug("Generated %s XML: %s",
|
||||||
log_label,
|
log_label,
|
||||||
|
@ -554,6 +549,21 @@ class Guest(XMLBuilder):
|
||||||
# Device defaults #
|
# Device defaults #
|
||||||
###################
|
###################
|
||||||
|
|
||||||
|
def set_install_defaults(self):
|
||||||
|
"""
|
||||||
|
Allow API users to set defaults ahead of time if they want it.
|
||||||
|
Used by vmmDomainVirtinst so the 'Customize before install' dialog
|
||||||
|
shows accurate values.
|
||||||
|
|
||||||
|
If the user doesn't explicitly call this, it will be called by
|
||||||
|
start_install()
|
||||||
|
"""
|
||||||
|
if self._defaults_are_set:
|
||||||
|
return
|
||||||
|
|
||||||
|
self._set_defaults()
|
||||||
|
self._defaults_are_set = True
|
||||||
|
|
||||||
def stable_defaults(self, *args, **kwargs):
|
def stable_defaults(self, *args, **kwargs):
|
||||||
return self.conn.stable_defaults(self.emulator, *args, **kwargs)
|
return self.conn.stable_defaults(self.emulator, *args, **kwargs)
|
||||||
|
|
||||||
|
@ -673,7 +683,6 @@ class Guest(XMLBuilder):
|
||||||
dev.path = None
|
dev.path = None
|
||||||
|
|
||||||
def _set_defaults(self):
|
def _set_defaults(self):
|
||||||
self._set_osxml_defaults()
|
|
||||||
self._set_clock_defaults()
|
self._set_clock_defaults()
|
||||||
self._set_emulator_defaults()
|
self._set_emulator_defaults()
|
||||||
self._set_cpu_defaults()
|
self._set_cpu_defaults()
|
||||||
|
@ -917,7 +926,11 @@ class Guest(XMLBuilder):
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _set_disk_defaults(self):
|
def _set_disk_defaults(self, disks=None):
|
||||||
|
alldisks = self.get_devices("disk")
|
||||||
|
if disks is None:
|
||||||
|
disks = alldisks
|
||||||
|
|
||||||
def set_disk_bus(d):
|
def set_disk_bus(d):
|
||||||
if d.is_floppy():
|
if d.is_floppy():
|
||||||
d.bus = "fdc"
|
d.bus = "fdc"
|
||||||
|
@ -948,15 +961,19 @@ class Guest(XMLBuilder):
|
||||||
else:
|
else:
|
||||||
d.bus = "ide"
|
d.bus = "ide"
|
||||||
|
|
||||||
|
|
||||||
|
# Generate disk targets
|
||||||
used_targets = []
|
used_targets = []
|
||||||
for disk in self.get_devices("disk"):
|
for disk in disks:
|
||||||
if not disk.bus:
|
if not disk.bus:
|
||||||
set_disk_bus(disk)
|
set_disk_bus(disk)
|
||||||
|
|
||||||
# Generate disk targets
|
for disk in alldisks:
|
||||||
if disk.target and not getattr(disk, "cli_set_target", False):
|
if disk.target and not getattr(disk,
|
||||||
|
"cli_generated_target", False):
|
||||||
used_targets.append(disk.target)
|
used_targets.append(disk.target)
|
||||||
else:
|
elif disk in disks:
|
||||||
|
disk.cli_generated_target = False
|
||||||
used_targets.append(disk.generate_target(used_targets))
|
used_targets.append(disk.generate_target(used_targets))
|
||||||
|
|
||||||
def _set_net_defaults(self):
|
def _set_net_defaults(self):
|
||||||
|
|
|
@ -112,7 +112,7 @@ class Installer(object):
|
||||||
dev.validate()
|
dev.validate()
|
||||||
return dev
|
return dev
|
||||||
|
|
||||||
def alter_bootconfig(self, guest, isinstall, bootconfig):
|
def alter_bootconfig(self, guest, isinstall):
|
||||||
"""
|
"""
|
||||||
Generate the portion of the guest xml that determines boot devices
|
Generate the portion of the guest xml that determines boot devices
|
||||||
and parameters. (typically the <os></os> block)
|
and parameters. (typically the <os></os> block)
|
||||||
|
@ -128,20 +128,20 @@ class Installer(object):
|
||||||
|
|
||||||
bootorder = self._build_boot_order(isinstall, guest)
|
bootorder = self._build_boot_order(isinstall, guest)
|
||||||
|
|
||||||
if not bootconfig.bootorder:
|
if not guest.os.bootorder:
|
||||||
# Per device <boot order> is not compatible with os/boot.
|
# Per device <boot order> is not compatible with os/boot.
|
||||||
if not any(d.boot.order for d in guest.get_all_devices()):
|
if not any(d.boot.order for d in guest.get_all_devices()):
|
||||||
bootconfig.bootorder = bootorder
|
guest.os.bootorder = bootorder
|
||||||
|
|
||||||
if not isinstall:
|
if not isinstall:
|
||||||
return
|
return
|
||||||
|
|
||||||
if self._install_kernel:
|
if self._install_kernel:
|
||||||
bootconfig.kernel = self._install_kernel
|
guest.os.kernel = self._install_kernel
|
||||||
if self._install_initrd:
|
if self._install_initrd:
|
||||||
bootconfig.initrd = self._install_initrd
|
guest.os.initrd = self._install_initrd
|
||||||
if self.extraargs:
|
if self.extraargs:
|
||||||
bootconfig.kernel_args = self.extraargs
|
guest.os.kernel_args = self.extraargs
|
||||||
|
|
||||||
|
|
||||||
##########################
|
##########################
|
||||||
|
|
Loading…
Reference in New Issue