details: Add UI for enabling UEFI via 'customize before install'
We expose a simple combobox with two entries: BIOS, and UEFI. The UEFI option is only selectable if 1) libvirt supports the necessary domcapabilities bits, 2) it detects that qemu supports the necessary command line options, and 3) libvirt detects a UEFI binary on the host that maps to a known template via qemu.conf If those conditions aren't met, we disable the UEFI option, and show a small warning icon with an explanatory tooltip. The option can only be changed via New VM->Customize Before Install. For existing x86 VMs, it's a readonly label.
This commit is contained in:
parent
ead9d3f56d
commit
ae26313ed4
|
@ -957,6 +957,7 @@
|
|||
<object class="GtkLabel" id="overview-machine-label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="valign">start</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="label" translatable="yes">Machine _Type: </property>
|
||||
<property name="use_underline">True</property>
|
||||
|
@ -982,16 +983,15 @@
|
|||
<object class="GtkLabel" id="overview-chipset-title">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_top">2</property>
|
||||
<property name="valign">start</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="yalign">0</property>
|
||||
<property name="label" translatable="yes">Chipse_t:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="ellipsize">middle</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">4</property>
|
||||
<property name="top_attach">5</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
|
@ -1061,6 +1061,8 @@ if you know what you are doing.</small></property>
|
|||
<object class="GtkLabel" id="overview-chipset-label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="valign">start</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label">label</property>
|
||||
</object>
|
||||
|
@ -1077,6 +1079,79 @@ if you know what you are doing.</small></property>
|
|||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">5</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="overview-firmware-title">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="valign">start</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="label" translatable="yes">Firmware:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="box11">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">3</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="box16">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkComboBox" id="overview-firmware">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<signal name="changed" handler="on_overview_firmware_changed" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="overview-firmware-label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="valign">start</property>
|
||||
<property name="vexpand">False</property>
|
||||
<property name="label">label</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage" id="overview-firmware-warn">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-dialog-warning</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">4</property>
|
||||
|
@ -1310,9 +1385,6 @@ if you know what you are doing.</small></property>
|
|||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="tab">
|
||||
|
|
|
@ -48,6 +48,7 @@ from virtinst import VirtualRNGDevice
|
|||
(EDIT_NAME,
|
||||
EDIT_TITLE,
|
||||
EDIT_MACHTYPE,
|
||||
EDIT_FIRMWARE,
|
||||
EDIT_DESC,
|
||||
EDIT_IDMAP,
|
||||
|
||||
|
@ -103,7 +104,7 @@ EDIT_FS,
|
|||
|
||||
EDIT_HOSTDEV_ROMBAR,
|
||||
|
||||
) = range(1, 44)
|
||||
) = range(1, 45)
|
||||
|
||||
|
||||
# Columns in hw list model
|
||||
|
@ -398,6 +399,18 @@ def _chipset_label_from_machine(machine):
|
|||
return "i440FX"
|
||||
|
||||
|
||||
def _firmware_label_from_loader(vm, loader, force_uefi=False):
|
||||
domcaps = vm.get_domain_capabilities()
|
||||
if (domcaps.os.loader.values and
|
||||
loader == domcaps.os.loader.values[0].value) or force_uefi:
|
||||
return "UEFI"
|
||||
|
||||
if loader is None:
|
||||
return "BIOS"
|
||||
|
||||
return "Custom"
|
||||
|
||||
|
||||
class vmmDetails(vmmGObjectUI):
|
||||
__gsignals__ = {
|
||||
"action-save-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
||||
|
@ -548,6 +561,7 @@ class vmmDetails(vmmGObjectUI):
|
|||
"on_overview_name_changed": lambda *x: self.enable_apply(x, EDIT_NAME),
|
||||
"on_overview_title_changed": lambda *x: self.enable_apply(x, EDIT_TITLE),
|
||||
"on_machine_type_changed": lambda *x: self.enable_apply(x, EDIT_MACHTYPE),
|
||||
"on_overview_firmware_changed": lambda *x: self.enable_apply(x, EDIT_FIRMWARE),
|
||||
"on_overview_chipset_changed": lambda *x: self.enable_apply(x, EDIT_MACHTYPE),
|
||||
"on_idmap_uid_target_changed": lambda *x: self.enable_apply(x, EDIT_IDMAP),
|
||||
"on_idmap_uid_count_changed": lambda *x: self.enable_apply(x, EDIT_IDMAP),
|
||||
|
@ -873,6 +887,49 @@ class vmmDetails(vmmGObjectUI):
|
|||
continue
|
||||
machtype_model.append([machine])
|
||||
|
||||
# Firmware
|
||||
combo = self.widget("overview-firmware")
|
||||
model = Gtk.ListStore(str, str, bool)
|
||||
combo.set_model(model)
|
||||
text = Gtk.CellRendererText()
|
||||
combo.pack_start(text, True)
|
||||
combo.add_attribute(text, "text", 0)
|
||||
combo.add_attribute(text, "sensitive", 2)
|
||||
|
||||
domcaps = self.vm.get_domain_capabilities()
|
||||
uefipath = None
|
||||
if domcaps.os.loader.values:
|
||||
uefipath = domcaps.os.loader.values[0].value
|
||||
|
||||
warn_icon = self.widget("overview-firmware-warn")
|
||||
hv_supports_uefi = ("readonly" in domcaps.os.loader.enum_names() and
|
||||
"yes" in domcaps.os.loader.get_enum("readonly").get_values())
|
||||
if not hv_supports_uefi:
|
||||
warn_icon.set_tooltip_text(
|
||||
_("Libvirt or hypervisor does not support UEFI."))
|
||||
elif not uefipath:
|
||||
warn_icon.set_tooltip_text(
|
||||
_("Libvirt did not detect any UEFI/OVMF firmware image "
|
||||
"installed on the host."))
|
||||
|
||||
model.append([_firmware_label_from_loader(self.vm, None),
|
||||
None, True])
|
||||
model.append([_firmware_label_from_loader(
|
||||
self.vm, uefipath, force_uefi=True), uefipath,
|
||||
bool(uefipath and hv_supports_uefi)])
|
||||
combo.set_active(0)
|
||||
|
||||
self.widget("overview-firmware-warn").set_visible(
|
||||
not (uefipath and hv_supports_uefi) and self.is_customize_dialog)
|
||||
self.widget("overview-firmware").set_visible(self.is_customize_dialog)
|
||||
self.widget("overview-firmware-label").set_visible(
|
||||
not self.is_customize_dialog)
|
||||
show_firmware = ((self.conn.is_qemu() or self.conn.is_test_conn()) and
|
||||
arch in ["i686", "x86_64"] and
|
||||
not self.vm.is_management_domain())
|
||||
uiutil.set_grid_row_visible(
|
||||
self.widget("overview-firmware-title"), show_firmware)
|
||||
|
||||
# Chipset
|
||||
combo = self.widget("overview-chipset")
|
||||
model = Gtk.ListStore(str, str)
|
||||
|
@ -1974,6 +2031,10 @@ class vmmDetails(vmmGObjectUI):
|
|||
kwargs["title"] = self.widget("overview-title").get_text()
|
||||
hotplug_args["title"] = kwargs["title"]
|
||||
|
||||
if self.edited(EDIT_FIRMWARE):
|
||||
kwargs["loader"] = uiutil.get_list_selection(
|
||||
self.widget("overview-firmware"), 1)
|
||||
|
||||
if self.edited(EDIT_MACHTYPE):
|
||||
if self.widget("overview-chipset").is_visible():
|
||||
kwargs["machine"] = uiutil.get_list_selection(
|
||||
|
@ -2402,6 +2463,15 @@ class vmmDetails(vmmGObjectUI):
|
|||
self.widget("overview-arch").set_text(arch)
|
||||
self.widget("overview-emulator").set_text(emu)
|
||||
|
||||
# Firmware
|
||||
firmware = _firmware_label_from_loader(self.vm,
|
||||
self.vm.get_xmlobj().os.loader)
|
||||
if self.widget("overview-firmware").is_visible():
|
||||
uiutil.set_combo_entry(
|
||||
self.widget("overview-firmware"), firmware)
|
||||
elif self.widget("overview-firmware-label").is_visible():
|
||||
self.widget("overview-firmware-label").set_text(firmware)
|
||||
|
||||
# Machine settings
|
||||
machtype = self.vm.get_machtype()
|
||||
if arch not in ["i686", "x86_64"]:
|
||||
|
|
|
@ -27,6 +27,7 @@ import threading
|
|||
|
||||
import libvirt
|
||||
|
||||
from virtinst import DomainCapabilities
|
||||
from virtinst import DomainSnapshot
|
||||
from virtinst import Guest
|
||||
from virtinst import util
|
||||
|
@ -301,6 +302,7 @@ class vmmDomain(vmmLibvirtObject):
|
|||
self._has_managed_save = None
|
||||
self._snapshot_list = None
|
||||
self._autostart = None
|
||||
self._domain_caps = None
|
||||
|
||||
self.lastStatus = libvirt.VIR_DOMAIN_SHUTOFF
|
||||
self._lastStatusReason = getattr(libvirt, "VIR_DOMAIN_SHUTOFF_SHUTDOWN",
|
||||
|
@ -505,6 +507,20 @@ class vmmDomain(vmmLibvirtObject):
|
|||
return _("Snapshots require at least one writeable qcow2 disk "
|
||||
"image allocated to the guest.")
|
||||
|
||||
def get_domain_capabilities(self):
|
||||
if not self.conn.check_support(
|
||||
self.conn.SUPPORT_CONN_DOMAIN_CAPABILITIES):
|
||||
self._domain_caps = DomainCapabilities(self.conn.get_backend())
|
||||
|
||||
if not self._domain_caps:
|
||||
xml = self.conn.get_backend().getDomainCapabilities(
|
||||
self.get_xmlobj().emulator, self.get_xmlobj().os.arch,
|
||||
self.get_xmlobj().os.machine, self.get_xmlobj().type)
|
||||
self._domain_caps = DomainCapabilities(self.conn.get_backend(),
|
||||
parsexml=xml)
|
||||
|
||||
return self._domain_caps
|
||||
|
||||
|
||||
#############################
|
||||
# Internal XML handling API #
|
||||
|
@ -619,7 +635,7 @@ class vmmDomain(vmmLibvirtObject):
|
|||
newname)
|
||||
|
||||
def define_overview(self, machine=_SENTINEL, description=_SENTINEL,
|
||||
title=_SENTINEL, idmap_list=_SENTINEL):
|
||||
title=_SENTINEL, idmap_list=_SENTINEL, loader=_SENTINEL):
|
||||
def change(guest):
|
||||
if machine != _SENTINEL:
|
||||
guest.os.machine = machine
|
||||
|
@ -628,6 +644,20 @@ class vmmDomain(vmmLibvirtObject):
|
|||
if title != _SENTINEL:
|
||||
guest.title = title or None
|
||||
|
||||
if loader != _SENTINEL:
|
||||
if loader is None:
|
||||
# Implies seabios, aka the default, so clear everything
|
||||
guest.os.loader = None
|
||||
guest.os.loader_ro = None
|
||||
guest.os.loader_type = None
|
||||
guest.os.nvram = None
|
||||
guest.os.nvram_template = None
|
||||
else:
|
||||
# Implies UEFI
|
||||
guest.os.loader = loader
|
||||
guest.os.loader_type = "pflash"
|
||||
guest.os.loader_ro = True
|
||||
|
||||
if idmap_list != _SENTINEL:
|
||||
if idmap_list is not None:
|
||||
# pylint: disable=unpacking-non-sequence
|
||||
|
|
|
@ -298,6 +298,9 @@ SUPPORT_CONN_HYPERV_VAPIC = _make(
|
|||
SUPPORT_CONN_HYPERV_CLOCK = _make(
|
||||
version="1.2.2", hv_version={"qemu": "2.0.0", "test": 0})
|
||||
SUPPORT_CONN_LOADER_ROM = _make(version="1.2.9")
|
||||
SUPPORT_CONN_DOMAIN_CAPABILITIES = _make(
|
||||
function="virConnect.getDomainCapabilities",
|
||||
run_args=(None, None, None, None))
|
||||
|
||||
|
||||
# Domain checks
|
||||
|
|
Loading…
Reference in New Issue