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:
Cole Robinson 2014-01-31 13:40:09 -05:00
parent 021ffd17e2
commit 90c9b3ca2e
5 changed files with 146 additions and 196 deletions

View File

@ -1738,132 +1738,61 @@
<property name="left_padding">21</property> <property name="left_padding">21</property>
<property name="right_padding">12</property> <property name="right_padding">12</property>
<child> <child>
<object class="GtkVBox" id="vbox220"> <object class="GtkGrid" id="table15">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</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> <child>
<object class="GtkTable" id="table15"> <object class="GtkLabel" id="label52">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="halign">start</property> <property name="xalign">0</property>
<property name="valign">start</property> <property name="label" translatable="yes">Model:</property>
<property name="n_rows">2</property> </object>
<property name="n_columns">2</property> <packing>
<property name="column_spacing">12</property> <property name="left_attach">0</property>
<property name="row_spacing">3</property> <property name="top_attach">1</property>
<child> <property name="width">1</property>
<object class="GtkLabel" id="label52"> <property name="height">1</property>
<property name="visible">True</property> </packing>
<property name="can_focus">False</property> </child>
<property name="xalign">0</property> <child>
<property name="label" translatable="yes">Model:</property> <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> </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> </child>
</object> </object>
<packing> <packing>
<property name="expand">False</property> <property name="left_attach">1</property>
<property name="fill">True</property> <property name="top_attach">1</property>
<property name="position">0</property> <property name="width">1</property>
<property name="height">1</property>
</packing> </packing>
</child> </child>
</object> </object>

View File

@ -378,7 +378,6 @@ class vmmDetails(vmmGObjectUI):
self.ignorePause = False self.ignorePause = False
self.ignoreDetails = False self.ignoreDetails = False
self._cpu_copy_host = False
from virtManager.console import vmmConsolePages from virtManager.console import vmmConsolePages
self.console = vmmConsolePages(self.vm, self.builder, self.topwin) 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_changed": lambda *x: self.enable_apply(x, EDIT_CPUSET),
"on_config_vcpupin_generate_clicked": self.config_vcpupin_generate, "on_config_vcpupin_generate_clicked": self.config_vcpupin_generate,
"on_cpu_model_changed": lambda *x: self.enable_apply(x, EDIT_CPU), "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_cores_changed": lambda *x: self.enable_apply(x, EDIT_TOPOLOGY),
"on_cpu_sockets_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_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_cpu_topology_enable_toggled": self.config_cpu_topology_enable,
"on_config_memory_changed": self.config_memory_changed, "on_config_memory_changed": self.config_memory_changed,
@ -860,20 +858,27 @@ class vmmDetails(vmmGObjectUI):
try: try:
cpu_values = caps.get_cpu_values(self.vm.get_arch()) 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: except:
logging.exception("Error populating CPU model list") logging.exception("Error populating CPU model list")
# CPU model combo # CPU model combo
cpu_model = self.widget("cpu-model") 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_model(model)
cpu_model.set_entry_text_column(0) cpu_model.set_entry_text_column(0)
model.set_sort_column_id(0, Gtk.SortType.ASCENDING) cpu_model.set_row_separator_func(sep_func, None)
for name in cpu_names: model.set_sort_column_id(2, Gtk.SortType.ASCENDING)
model.append([name, cpu_values.get_cpu(name)]) 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 combo
disk_cache = self.widget("disk-cache") disk_cache = self.widget("disk-cache")
@ -1420,13 +1425,45 @@ class vmmDetails(vmmGObjectUI):
def get_config_cpu_model(self): def get_config_cpu_model(self):
cpu_list = self.widget("cpu-model") 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(): row = None
if model == row[0]: for r in cpu_list.get_model():
return model, row[1].vendor 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 # # Details/Hardware listeners #
@ -1537,27 +1574,10 @@ class vmmDetails(vmmGObjectUI):
def config_maxvcpus_changed(self, ignore): def config_maxvcpus_changed(self, ignore):
self.enable_apply(EDIT_VCPUS) self.enable_apply(EDIT_VCPUS)
def config_cpu_copy_host(self, src_ignore): def on_cpu_copy_host_clicked(self, src):
# Update UI with output copied from host uiutil.set_grid_row_visible(
try: self.widget("cpu-model"), not src.get_active())
CPU = virtinst.CPU(self.vm.conn.get_backend()) self.enable_apply(EDIT_CPU)
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 config_cpu_topology_enable(self, src): def config_cpu_topology_enable(self, src):
do_enable = src.get_active() do_enable = src.get_active()
@ -1829,9 +1849,9 @@ class vmmDetails(vmmGObjectUI):
add_define(self.vm.define_cpuset, cpuset) add_define(self.vm.define_cpuset, cpuset)
if self.edited(EDIT_CPU): 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, add_define(self.vm.define_cpu,
model, vendor, self._cpu_copy_host) model, mode, copy_host)
if self.edited(EDIT_TOPOLOGY): if self.edited(EDIT_TOPOLOGY):
do_top = self.widget("cpu-topology-enable").get_active() 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) add_define(self.vm.define_cpu_topology, sockets, cores, threads)
ret = self._change_config_helper(df, da, hf, ha) return self._change_config_helper(df, da, hf, ha)
if ret:
self._cpu_copy_host = False
return ret
# Memory # Memory
def config_memory_apply(self): def config_memory_apply(self):
@ -2376,9 +2393,9 @@ class vmmDetails(vmmGObjectUI):
self.disk_io_graph.set_property("data_array", self.disk_io_graph.set_property("data_array",
self.vm.disk_io_vector()) self.vm.disk_io_vector())
self.network_traffic_graph.set_property("data_array", 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 conn = self.vm.conn
host_active_count = conn.host_active_processor_count() host_active_count = conn.host_active_processor_count()
maxvcpus = self.vm.vcpu_max_count() maxvcpus = self.vm.vcpu_max_count()
@ -2395,39 +2412,44 @@ class vmmDetails(vmmGObjectUI):
warn = bool(self.config_get_vcpus() > host_active_count) warn = bool(self.config_get_vcpus() > host_active_count)
self.widget("config-vcpus-warn-box").set_visible(warn) self.widget("config-vcpus-warn-box").set_visible(warn)
def _refresh_cpu_config(self, cpu): # CPU model config
model = cpu.model or "" cpu = self.vm.get_cpu_config()
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
show_top = bool(cpu.sockets or cpu.cores or cpu.threads) show_top = bool(cpu.sockets or cpu.cores or cpu.threads)
sockets = cpu.sockets or 1 sockets = cpu.sockets or 1
cores = cpu.cores or 1 cores = cpu.cores or 1
threads = cpu.threads or 1 threads = cpu.threads or 1
self.widget("cpu-topology-enable").set_active(show_top) 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-sockets").set_value(sockets)
self.widget("cpu-cores").set_value(cores) self.widget("cpu-cores").set_value(cores)
self.widget("cpu-threads").set_value(threads) self.widget("cpu-threads").set_value(threads)
def refresh_config_cpu(self): model = cpu.model or None
self._cpu_copy_host = False if not model:
cpu = self.vm.get_cpu_config() if cpu.mode == "host-model" or cpu.mode == "host-passthrough":
model = cpu.mode
self._refresh_cpu_count() if model:
self._refresh_cpu_config(cpu) 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): def refresh_config_memory(self):
host_mem_widget = self.widget("state-host-memory") host_mem_widget = self.widget("state-host-memory")

View File

@ -535,21 +535,18 @@ class vmmDomain(vmmLibvirtObject):
cpu.cores = cores cpu.cores = cores
cpu.threads = threads cpu.threads = threads
return self._redefine(change) return self._redefine(change)
def define_cpu(self, model, vendor, from_host): def define_cpu(self, model, mode, copy_host):
def change(guest): def change(guest):
if from_host: if copy_host:
guest.cpu.copy_host_cpu() guest.cpu.copy_host_cpu()
elif guest.cpu.model != model: elif mode:
# Since we don't expose this in the UI, have host value trump guest.cpu.clear()
# caps value guest.cpu.mode = mode
guest.cpu.vendor = vendor elif model:
guest.cpu.model = model
guest.cpu.model = model or None guest.cpu.vendor = None
if guest.cpu.model is None: else:
for f in guest.cpu.features: guest.cpu.clear()
guest.cpu.remove_feature(f)
return
return self._redefine(change) return self._redefine(change)
# Mem define methods # Mem define methods

View File

@ -124,7 +124,7 @@ def set_row_selection(listwidget, prevkey):
def set_combo_entry(combo, value, rowidx=0): 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 rowidx. If found, select it. If not found, and
the combobox has a text entry, stick the value in their and the combobox has a text entry, stick the value in their and
select it. select it.

View File

@ -132,6 +132,8 @@ class CPUValues(object):
child = child.next child = child.next
def get_arch(self, arch): def get_arch(self, arch):
if not arch:
return None
if re.match(r'i[4-9]86', arch): if re.match(r'i[4-9]86', arch):
arch = "x86" arch = "x86"
elif arch == "x86_64": elif arch == "x86_64":