details: Reword the CPU model UI a bit more
- Add options in the model drop down for clear, hvdefault, and app default - Make 'copy host' a check box, when enabled it hides the model dropdown - Detect if the VM CPU is a copy of the host CPU - Undocumented bit that allows passing in host-model/host-passthrough to the model field for people that really want those settings.
This commit is contained in:
parent
021ffd17e2
commit
90c9b3ca2e
163
ui/details.ui
163
ui/details.ui
|
@ -1738,132 +1738,61 @@
|
|||
<property name="left_padding">21</property>
|
||||
<property name="right_padding">12</property>
|
||||
<child>
|
||||
<object class="GtkVBox" id="vbox220">
|
||||
<object class="GtkGrid" id="table15">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">6</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="valign">start</property>
|
||||
<property name="row_spacing">3</property>
|
||||
<property name="column_spacing">12</property>
|
||||
<child>
|
||||
<object class="GtkTable" id="table15">
|
||||
<object class="GtkLabel" id="label52">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="valign">start</property>
|
||||
<property name="n_rows">2</property>
|
||||
<property name="n_columns">2</property>
|
||||
<property name="column_spacing">12</property>
|
||||
<property name="row_spacing">3</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label52">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">Model:</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">Model:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="cpu-copy-host">
|
||||
<property name="label" translatable="yes">Copy host CPU configuration</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<signal name="clicked" handler="on_cpu_copy_host_clicked" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">0</property>
|
||||
<property name="width">2</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkComboBox" id="cpu-model">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="has_entry">True</property>
|
||||
<signal name="changed" handler="on_cpu_model_changed" swapped="no"/>
|
||||
<child internal-child="entry">
|
||||
<object class="GtkEntry" id="combobox-entry33">
|
||||
<property name="can_focus">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="y_options">GTK_FILL</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkHBox" id="hbox21">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">20</property>
|
||||
<child>
|
||||
<object class="GtkAlignment" id="alignment33">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkComboBox" id="cpu-model">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="has_entry">True</property>
|
||||
<signal name="changed" handler="on_cpu_model_changed" swapped="no"/>
|
||||
<child internal-child="entry">
|
||||
<object class="GtkEntry" id="combobox-entry33">
|
||||
<property name="can_focus">False</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="y_options">GTK_FILL</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkAlignment" id="alignment37">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="y_options">GTK_FILL</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkHBox" id="hbox25">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="cpu-copy-host">
|
||||
<property name="label" translatable="yes">Copy host CPU configuration</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="valign">start</property>
|
||||
<signal name="clicked" handler="on_cpu_copy_host_clicked" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="cpu-clear">
|
||||
<property name="label" translatable="yes">Clear CPU configuration</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<signal name="clicked" handler="on_cpu_clear_clicked" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="y_options">GTK_FILL</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="width">1</property>
|
||||
<property name="height">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
|
|
|
@ -378,7 +378,6 @@ class vmmDetails(vmmGObjectUI):
|
|||
|
||||
self.ignorePause = False
|
||||
self.ignoreDetails = False
|
||||
self._cpu_copy_host = False
|
||||
|
||||
from virtManager.console import vmmConsolePages
|
||||
self.console = vmmConsolePages(self.vm, self.builder, self.topwin)
|
||||
|
@ -481,11 +480,10 @@ class vmmDetails(vmmGObjectUI):
|
|||
"on_config_vcpupin_changed": lambda *x: self.enable_apply(x, EDIT_CPUSET),
|
||||
"on_config_vcpupin_generate_clicked": self.config_vcpupin_generate,
|
||||
"on_cpu_model_changed": lambda *x: self.enable_apply(x, EDIT_CPU),
|
||||
"on_cpu_copy_host_clicked": self.on_cpu_copy_host_clicked,
|
||||
"on_cpu_cores_changed": lambda *x: self.enable_apply(x, EDIT_TOPOLOGY),
|
||||
"on_cpu_sockets_changed": lambda *x: self.enable_apply(x, EDIT_TOPOLOGY),
|
||||
"on_cpu_threads_changed": lambda *x: self.enable_apply(x, EDIT_TOPOLOGY),
|
||||
"on_cpu_copy_host_clicked": self.config_cpu_copy_host,
|
||||
"on_cpu_clear_clicked": self.config_cpu_clear,
|
||||
"on_cpu_topology_enable_toggled": self.config_cpu_topology_enable,
|
||||
|
||||
"on_config_memory_changed": self.config_memory_changed,
|
||||
|
@ -860,20 +858,27 @@ class vmmDetails(vmmGObjectUI):
|
|||
|
||||
try:
|
||||
cpu_values = caps.get_cpu_values(self.vm.get_arch())
|
||||
cpu_names = sorted([c.model for c in cpu_values.cpus],
|
||||
key=str.lower)
|
||||
except:
|
||||
logging.exception("Error populating CPU model list")
|
||||
|
||||
# CPU model combo
|
||||
cpu_model = self.widget("cpu-model")
|
||||
|
||||
model = Gtk.ListStore(str, object)
|
||||
def sep_func(model, it, ignore):
|
||||
return model[it][3]
|
||||
|
||||
# [label, sortkey, idstring, is sep]
|
||||
model = Gtk.ListStore(str, str, str, bool)
|
||||
cpu_model.set_model(model)
|
||||
cpu_model.set_entry_text_column(0)
|
||||
model.set_sort_column_id(0, Gtk.SortType.ASCENDING)
|
||||
for name in cpu_names:
|
||||
model.append([name, cpu_values.get_cpu(name)])
|
||||
cpu_model.set_row_separator_func(sep_func, None)
|
||||
model.set_sort_column_id(2, Gtk.SortType.ASCENDING)
|
||||
model.append([_("Application Default"), "1", "appdefault", False])
|
||||
model.append([_("Hypervisor Default"), "2", "hypdefault", False])
|
||||
model.append([_("Clear CPU configuration"), "3", "clearcpu", False])
|
||||
model.append([None, None, None, True])
|
||||
for name in [c.model for c in cpu_values.cpus]:
|
||||
model.append([name, name, name, False])
|
||||
|
||||
# Disk cache combo
|
||||
disk_cache = self.widget("disk-cache")
|
||||
|
@ -1420,13 +1425,45 @@ class vmmDetails(vmmGObjectUI):
|
|||
|
||||
def get_config_cpu_model(self):
|
||||
cpu_list = self.widget("cpu-model")
|
||||
model = cpu_list.get_child().get_text()
|
||||
text = cpu_list.get_child().get_text()
|
||||
model = None
|
||||
mode = None
|
||||
copy_host = bool(self.widget("cpu-copy-host").get_active())
|
||||
key = None
|
||||
|
||||
for row in cpu_list.get_model():
|
||||
if model == row[0]:
|
||||
return model, row[1].vendor
|
||||
row = None
|
||||
for r in cpu_list.get_model():
|
||||
if text == r[0]:
|
||||
row = r
|
||||
break
|
||||
|
||||
if row:
|
||||
key = row[2]
|
||||
elif text == "host-model" or text == "host-passthrough":
|
||||
mode = text
|
||||
else:
|
||||
model = text
|
||||
|
||||
if key == "hypdefault" or key == "clearcpu":
|
||||
# Clear the whole CPU
|
||||
pass
|
||||
elif key == "appdefault":
|
||||
cpu_type = self.config.get_default_cpu_setting()
|
||||
|
||||
if cpu_type == "hv-default":
|
||||
pass
|
||||
elif cpu_type == "host-cpu-model":
|
||||
if self.vm.conn.caps.host.cpu.model:
|
||||
model = self.vm.conn.caps.host.cpu.model
|
||||
elif cpu_type == "host-model":
|
||||
copy_host = True
|
||||
else:
|
||||
raise RuntimeError("Unknown cpu default '%s'" % cpu_type)
|
||||
elif key:
|
||||
model = key
|
||||
|
||||
return model, mode, copy_host
|
||||
|
||||
return model, None
|
||||
|
||||
##############################
|
||||
# Details/Hardware listeners #
|
||||
|
@ -1537,27 +1574,10 @@ class vmmDetails(vmmGObjectUI):
|
|||
def config_maxvcpus_changed(self, ignore):
|
||||
self.enable_apply(EDIT_VCPUS)
|
||||
|
||||
def config_cpu_copy_host(self, src_ignore):
|
||||
# Update UI with output copied from host
|
||||
try:
|
||||
CPU = virtinst.CPU(self.vm.conn.get_backend())
|
||||
CPU.copy_host_cpu()
|
||||
|
||||
self._refresh_cpu_config(CPU)
|
||||
self._cpu_copy_host = True
|
||||
except Exception, e:
|
||||
self.err.show_err(_("Error copying host CPU: %s") % str(e))
|
||||
return
|
||||
|
||||
def config_cpu_clear(self, src_ignore):
|
||||
try:
|
||||
CPU = virtinst.CPU(self.vm.conn.get_backend())
|
||||
CPU.clear()
|
||||
|
||||
self._refresh_cpu_config(CPU)
|
||||
except Exception, e:
|
||||
self.err.show_err(_("Error clear CPU config: %s") % str(e))
|
||||
return
|
||||
def on_cpu_copy_host_clicked(self, src):
|
||||
uiutil.set_grid_row_visible(
|
||||
self.widget("cpu-model"), not src.get_active())
|
||||
self.enable_apply(EDIT_CPU)
|
||||
|
||||
def config_cpu_topology_enable(self, src):
|
||||
do_enable = src.get_active()
|
||||
|
@ -1829,9 +1849,9 @@ class vmmDetails(vmmGObjectUI):
|
|||
add_define(self.vm.define_cpuset, cpuset)
|
||||
|
||||
if self.edited(EDIT_CPU):
|
||||
model, vendor = self.get_config_cpu_model()
|
||||
model, mode, copy_host = self.get_config_cpu_model()
|
||||
add_define(self.vm.define_cpu,
|
||||
model, vendor, self._cpu_copy_host)
|
||||
model, mode, copy_host)
|
||||
|
||||
if self.edited(EDIT_TOPOLOGY):
|
||||
do_top = self.widget("cpu-topology-enable").get_active()
|
||||
|
@ -1845,10 +1865,7 @@ class vmmDetails(vmmGObjectUI):
|
|||
|
||||
add_define(self.vm.define_cpu_topology, sockets, cores, threads)
|
||||
|
||||
ret = self._change_config_helper(df, da, hf, ha)
|
||||
if ret:
|
||||
self._cpu_copy_host = False
|
||||
return ret
|
||||
return self._change_config_helper(df, da, hf, ha)
|
||||
|
||||
# Memory
|
||||
def config_memory_apply(self):
|
||||
|
@ -2376,9 +2393,9 @@ class vmmDetails(vmmGObjectUI):
|
|||
self.disk_io_graph.set_property("data_array",
|
||||
self.vm.disk_io_vector())
|
||||
self.network_traffic_graph.set_property("data_array",
|
||||
self.vm.network_traffic_vector())
|
||||
self.vm.network_traffic_vector())
|
||||
|
||||
def _refresh_cpu_count(self):
|
||||
def refresh_config_cpu(self):
|
||||
conn = self.vm.conn
|
||||
host_active_count = conn.host_active_processor_count()
|
||||
maxvcpus = self.vm.vcpu_max_count()
|
||||
|
@ -2395,39 +2412,44 @@ class vmmDetails(vmmGObjectUI):
|
|||
warn = bool(self.config_get_vcpus() > host_active_count)
|
||||
self.widget("config-vcpus-warn-box").set_visible(warn)
|
||||
|
||||
def _refresh_cpu_config(self, cpu):
|
||||
model = cpu.model or ""
|
||||
caps = self.vm.conn.caps
|
||||
|
||||
capscpu = None
|
||||
try:
|
||||
arch = self.vm.get_arch()
|
||||
if arch:
|
||||
cpu_values = caps.get_cpu_values(arch)
|
||||
for c in cpu_values.cpus:
|
||||
if model and c.model == model:
|
||||
capscpu = c
|
||||
break
|
||||
except:
|
||||
pass
|
||||
|
||||
# CPU model config
|
||||
cpu = self.vm.get_cpu_config()
|
||||
show_top = bool(cpu.sockets or cpu.cores or cpu.threads)
|
||||
sockets = cpu.sockets or 1
|
||||
cores = cpu.cores or 1
|
||||
threads = cpu.threads or 1
|
||||
|
||||
self.widget("cpu-topology-enable").set_active(show_top)
|
||||
self.widget("cpu-model").get_child().set_text(model)
|
||||
self.widget("cpu-sockets").set_value(sockets)
|
||||
self.widget("cpu-cores").set_value(cores)
|
||||
self.widget("cpu-threads").set_value(threads)
|
||||
|
||||
def refresh_config_cpu(self):
|
||||
self._cpu_copy_host = False
|
||||
cpu = self.vm.get_cpu_config()
|
||||
model = cpu.model or None
|
||||
if not model:
|
||||
if cpu.mode == "host-model" or cpu.mode == "host-passthrough":
|
||||
model = cpu.mode
|
||||
|
||||
self._refresh_cpu_count()
|
||||
self._refresh_cpu_config(cpu)
|
||||
if model:
|
||||
self.widget("cpu-model").get_child().set_text(model)
|
||||
else:
|
||||
uiutil.set_combo_entry(
|
||||
self.widget("cpu-model"), "hypdefault", 2)
|
||||
|
||||
# Determine if CPU definition is just the host copy
|
||||
hostcpu = self.conn.caps.host.cpu
|
||||
is_host = False
|
||||
if (hostcpu.model and
|
||||
cpu.model == hostcpu.model and
|
||||
len(cpu.features) == len(hostcpu.features.names())):
|
||||
is_host = True
|
||||
for feature in cpu.features:
|
||||
if (feature.policy != "require" or
|
||||
feature.name not in hostcpu.features.names()):
|
||||
is_host = False
|
||||
break
|
||||
|
||||
self.widget("cpu-copy-host").set_active(bool(is_host))
|
||||
self.on_cpu_copy_host_clicked(self.widget("cpu-copy-host"))
|
||||
|
||||
def refresh_config_memory(self):
|
||||
host_mem_widget = self.widget("state-host-memory")
|
||||
|
|
|
@ -535,21 +535,18 @@ class vmmDomain(vmmLibvirtObject):
|
|||
cpu.cores = cores
|
||||
cpu.threads = threads
|
||||
return self._redefine(change)
|
||||
def define_cpu(self, model, vendor, from_host):
|
||||
def define_cpu(self, model, mode, copy_host):
|
||||
def change(guest):
|
||||
if from_host:
|
||||
if copy_host:
|
||||
guest.cpu.copy_host_cpu()
|
||||
elif guest.cpu.model != model:
|
||||
# Since we don't expose this in the UI, have host value trump
|
||||
# caps value
|
||||
guest.cpu.vendor = vendor
|
||||
|
||||
guest.cpu.model = model or None
|
||||
if guest.cpu.model is None:
|
||||
for f in guest.cpu.features:
|
||||
guest.cpu.remove_feature(f)
|
||||
return
|
||||
|
||||
elif mode:
|
||||
guest.cpu.clear()
|
||||
guest.cpu.mode = mode
|
||||
elif model:
|
||||
guest.cpu.model = model
|
||||
guest.cpu.vendor = None
|
||||
else:
|
||||
guest.cpu.clear()
|
||||
return self._redefine(change)
|
||||
|
||||
# Mem define methods
|
||||
|
|
|
@ -124,7 +124,7 @@ def set_row_selection(listwidget, prevkey):
|
|||
|
||||
def set_combo_entry(combo, value, rowidx=0):
|
||||
"""
|
||||
Search the passed combobox for value, comparing againt
|
||||
Search the passed combobox for value, comparing against
|
||||
rowidx. If found, select it. If not found, and
|
||||
the combobox has a text entry, stick the value in their and
|
||||
select it.
|
||||
|
|
|
@ -132,6 +132,8 @@ class CPUValues(object):
|
|||
child = child.next
|
||||
|
||||
def get_arch(self, arch):
|
||||
if not arch:
|
||||
return None
|
||||
if re.match(r'i[4-9]86', arch):
|
||||
arch = "x86"
|
||||
elif arch == "x86_64":
|
||||
|
|
Loading…
Reference in New Issue