details: Allow renaming offline VMs
Since libvirt doesn't have an easy way to do this, we need to actually undefine the VM and redefine it with the new name. Hopefully this doesn't go wrong :) Add listeners in console.py and manager.py to change the VM name accordingly in the UI.
This commit is contained in:
parent
ca5bd0de0a
commit
148229375a
|
@ -748,8 +748,35 @@ class vmmConnection(vmmGObject):
|
|||
|
||||
return net
|
||||
|
||||
def rename_vm(self, domainobj, origxml, newxml):
|
||||
# Undefine old domain
|
||||
domainobj.delete()
|
||||
|
||||
newobj = None
|
||||
try:
|
||||
try:
|
||||
# Redefine new domain
|
||||
newobj = self.define_domain(newxml)
|
||||
except Exception, renameerr:
|
||||
try:
|
||||
logging.exception("Error defining new name XML")
|
||||
newobj = self.define_domain(origxml)
|
||||
except Exception, fixerr:
|
||||
logging.exception("Failed to redefine original domain!")
|
||||
raise RuntimeError(
|
||||
_("Domain rename failed. Attempting to recover also "
|
||||
"failed.\n\n"
|
||||
"Original error: %s\n\n"
|
||||
"Recover error: %s" %
|
||||
(str(renameerr), str(fixerr))))
|
||||
raise
|
||||
finally:
|
||||
if newobj:
|
||||
# Reinsert handle into new domain
|
||||
domainobj.change_name_backend(newobj)
|
||||
|
||||
def define_domain(self, xml):
|
||||
self.vmm.defineXML(xml)
|
||||
return self.vmm.defineXML(xml)
|
||||
def define_interface(self, xml):
|
||||
self.vmm.interfaceDefineXML(xml, 0)
|
||||
|
||||
|
|
|
@ -485,8 +485,9 @@ class vmmConsolePages(vmmGObjectUI):
|
|||
self.topwin = self.window.get_widget(self.windowname)
|
||||
self.err = vmmErrorDialog(self.topwin)
|
||||
|
||||
self.title = vm.get_name() + " " + self.topwin.get_title()
|
||||
self.topwin.set_title(self.title)
|
||||
self.pointer_is_grabbed = False
|
||||
self.change_title()
|
||||
self.vm.connect("config-changed", self.change_title)
|
||||
|
||||
# State for disabling modifiers when keyboard is grabbed
|
||||
self.accel_groups = gtk.accel_groups_from_object(self.topwin)
|
||||
|
@ -533,6 +534,17 @@ class vmmConsolePages(vmmGObjectUI):
|
|||
# Initialization helpers #
|
||||
##########################
|
||||
|
||||
def change_title(self, ignore1=None):
|
||||
title = self.vm.get_name() + " " + _("Virtual Machine")
|
||||
|
||||
if self.pointer_is_grabbed and self.viewer:
|
||||
keystr = self.viewer.get_grab_keys()
|
||||
keymsg = _("Press %s to release pointer.") % keystr
|
||||
|
||||
title = keymsg + " " + title
|
||||
|
||||
self.topwin.set_title(title)
|
||||
|
||||
def viewer_focus_changed(self, ignore1=None, ignore2=None):
|
||||
has_focus = self.viewer and self.viewer.get_widget() and \
|
||||
self.viewer.get_widget().get_property("has-focus")
|
||||
|
@ -546,12 +558,12 @@ class vmmConsolePages(vmmGObjectUI):
|
|||
self._enable_modifiers()
|
||||
|
||||
def pointer_grabbed(self, src_ignore):
|
||||
keystr = self.viewer.get_grab_keys()
|
||||
self.topwin.set_title(_("Press %s to release pointer.") % keystr +
|
||||
" " + self.title)
|
||||
self.pointer_is_grabbed = True
|
||||
self.change_title()
|
||||
|
||||
def pointer_ungrabbed(self, src_ignore):
|
||||
self.topwin.set_title(self.title)
|
||||
self.pointer_is_grabbed = False
|
||||
self.change_title()
|
||||
|
||||
def _disable_modifiers(self):
|
||||
if self.gtk_settings_accel is not None:
|
||||
|
|
|
@ -336,6 +336,7 @@ class vmmDetails(vmmGObjectUI):
|
|||
|
||||
"on_details_pages_switch_page": self.switch_page,
|
||||
|
||||
"on_overview_name_changed": self.config_enable_apply,
|
||||
"on_overview_acpi_changed": self.config_enable_apply,
|
||||
"on_overview_apic_changed": self.config_enable_apply,
|
||||
"on_overview_clock_changed": self.config_enable_apply,
|
||||
|
@ -1093,6 +1094,7 @@ class vmmDetails(vmmGObjectUI):
|
|||
self.toggle_toolbar(
|
||||
self.window.get_widget("details-menu-view-toolbar"))
|
||||
|
||||
active = vm.is_active()
|
||||
destroy = vm.is_destroyable()
|
||||
run = vm.is_runable()
|
||||
stop = vm.is_stoppable()
|
||||
|
@ -1121,6 +1123,8 @@ class vmmDetails(vmmGObjectUI):
|
|||
finally:
|
||||
self.ignorePause = False
|
||||
|
||||
self.window.get_widget("overview-name").set_editable(not active)
|
||||
|
||||
self.window.get_widget("config-vcpus").set_sensitive(not ro)
|
||||
self.window.get_widget("config-vcpupin").set_sensitive(not ro)
|
||||
self.window.get_widget("config-memory").set_sensitive(not ro)
|
||||
|
@ -1610,6 +1614,9 @@ class vmmDetails(vmmGObjectUI):
|
|||
|
||||
# Overview section
|
||||
def config_overview_apply(self):
|
||||
# Overview details
|
||||
name = self.window.get_widget("overview-name").get_text()
|
||||
|
||||
# Machine details
|
||||
enable_acpi = self.window.get_widget("overview-acpi").get_active()
|
||||
enable_apic = self.window.get_widget("overview-apic").get_active()
|
||||
|
@ -1635,12 +1642,14 @@ class vmmDetails(vmmGObjectUI):
|
|||
desc_widget = self.window.get_widget("overview-description")
|
||||
desc = desc_widget.get_buffer().get_property("text") or ""
|
||||
|
||||
return self._change_config_helper([self.vm.define_acpi,
|
||||
return self._change_config_helper([self.vm.define_name,
|
||||
self.vm.define_acpi,
|
||||
self.vm.define_apic,
|
||||
self.vm.define_clock,
|
||||
self.vm.define_seclabel,
|
||||
self.vm.define_description],
|
||||
[(enable_acpi,),
|
||||
[(name,),
|
||||
(enable_acpi,),
|
||||
(enable_apic,),
|
||||
(clock,),
|
||||
(semodel, setype, selabel),
|
||||
|
|
|
@ -158,6 +158,10 @@ class vmmDomainBase(vmmLibvirtObject):
|
|||
self._stats_disk_supported = True
|
||||
self._stats_disk_skip = []
|
||||
|
||||
def change_name_backend(self, newbackend):
|
||||
# Used for changing the domain object after a rename
|
||||
self._backend = newbackend
|
||||
|
||||
# Info accessors
|
||||
def get_name(self):
|
||||
raise NotImplementedError()
|
||||
|
@ -350,6 +354,29 @@ class vmmDomainBase(vmmLibvirtObject):
|
|||
|
||||
return self._redefine_guest(change)
|
||||
|
||||
def define_name(self, newname):
|
||||
# Do this, so that _guest_to_define has original inactive XML
|
||||
self._invalidate_xml()
|
||||
|
||||
guest = self._get_guest_to_define()
|
||||
if guest.name == newname:
|
||||
return
|
||||
|
||||
if self.is_active():
|
||||
raise RuntimeError(_("Cannot rename an active guest"))
|
||||
|
||||
logging.debug("Changing guest name to '%s'" % newname)
|
||||
origxml = guest.get_xml_config()
|
||||
guest.name = newname
|
||||
newxml = guest.get_xml_config()
|
||||
|
||||
try:
|
||||
self.get_connection().rename_vm(self, origxml, newxml)
|
||||
finally:
|
||||
self._invalidate_xml()
|
||||
|
||||
self.emit("config-changed")
|
||||
|
||||
def define_acpi(self, newvalue):
|
||||
def change(guest):
|
||||
guest.features["acpi"] = bool(newvalue)
|
||||
|
|
|
@ -697,6 +697,7 @@ class vmmManager(vmmGObjectUI):
|
|||
vm = connection.get_vm(vmuuid)
|
||||
vm.connect("status-changed", self.vm_status_changed)
|
||||
vm.connect("resources-sampled", self.vm_resources_sampled)
|
||||
vm.connect("config-changed", self.vm_resources_sampled)
|
||||
|
||||
vmlist = self.window.get_widget("vm-list")
|
||||
model = vmlist.get_model()
|
||||
|
@ -763,12 +764,7 @@ class vmmManager(vmmGObjectUI):
|
|||
statetext = "<span size='smaller'>%s</span>" % row[ROW_STATUS]
|
||||
return domtext + "\n" + statetext
|
||||
|
||||
def _append_vm(self, model, vm, conn):
|
||||
row_key = self.vm_row_key(vm)
|
||||
if row_key in self.rows:
|
||||
return
|
||||
|
||||
parent = self.rows[conn.get_uri()].iter
|
||||
def _build_vm_row(self, vm):
|
||||
row = []
|
||||
row.insert(ROW_HANDLE, vm)
|
||||
row.insert(ROW_NAME, vm.get_name())
|
||||
|
@ -785,11 +781,23 @@ class vmmManager(vmmGObjectUI):
|
|||
|
||||
row[ROW_MARKUP] = self._build_vm_markup(vm, row)
|
||||
|
||||
return row
|
||||
|
||||
def _append_vm(self, model, vm, conn):
|
||||
row_key = self.vm_row_key(vm)
|
||||
if row_key in self.rows:
|
||||
return
|
||||
|
||||
row = self._build_vm_row(vm)
|
||||
parent = self.rows[conn.get_uri()].iter
|
||||
|
||||
_iter = model.append(parent, row)
|
||||
path = model.get_path(_iter)
|
||||
self.rows[row_key] = model[path]
|
||||
|
||||
# Expand a connection when adding a vm to it
|
||||
self.window.get_widget("vm-list").expand_row(model.get_path(parent), False)
|
||||
self.window.get_widget("vm-list").expand_row(model.get_path(parent),
|
||||
False)
|
||||
|
||||
def _append_connection(self, model, conn):
|
||||
row = []
|
||||
|
@ -894,6 +902,7 @@ class vmmManager(vmmGObjectUI):
|
|||
return
|
||||
|
||||
row = self.rows[self.vm_row_key(vm)]
|
||||
row[ROW_NAME] = vm.get_name()
|
||||
row[ROW_STATUS] = vm.run_status()
|
||||
row[ROW_STATUS_ICON] = vm.run_status_icon_large()
|
||||
row[ROW_IS_VM_RUNNING] = vm.is_active()
|
||||
|
|
|
@ -1008,7 +1008,9 @@
|
|||
<widget class="GtkLabel" id="label43">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">Name:</property>
|
||||
<property name="label" translatable="yes">_Name:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="mnemonic_widget">overview-name</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
|
@ -1065,20 +1067,6 @@
|
|||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="overview-name">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label">test-vm</property>
|
||||
<property name="selectable">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="x_options">GTK_FILL</property>
|
||||
<property name="y_options">GTK_FILL</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label24">
|
||||
<property name="visible">True</property>
|
||||
|
@ -1127,6 +1115,18 @@
|
|||
<property name="x_options">GTK_FILL</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkEntry" id="overview-name">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="invisible_char">●</property>
|
||||
<signal name="changed" handler="on_overview_name_changed"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
|
@ -3785,7 +3785,7 @@ I/O:</property>
|
|||
<widget class="GtkVBox" id="network-source-box">
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox19">
|
||||
<widget class="GtkHBox" id="hbox7">
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<widget class="GtkComboBox" id="network-source-combo">
|
||||
|
@ -4039,7 +4039,7 @@ I/O:</property>
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkAlignment" id="alignment29">
|
||||
<widget class="GtkAlignment" id="alignment5">
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
|
@ -4052,7 +4052,7 @@ I/O:</property>
|
|||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label5">
|
||||
<widget class="GtkLabel" id="label6">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Virtual port</property>
|
||||
<property name="use_markup">True</property>
|
||||
|
@ -4783,7 +4783,7 @@ I/O:</property>
|
|||
<property name="label_xalign">0</property>
|
||||
<property name="shadow_type">none</property>
|
||||
<child>
|
||||
<widget class="GtkAlignment" id="alignment5">
|
||||
<widget class="GtkAlignment" id="alignment10">
|
||||
<property name="visible">True</property>
|
||||
<property name="top_padding">3</property>
|
||||
<property name="left_padding">12</property>
|
||||
|
@ -4843,7 +4843,7 @@ I/O:</property>
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label6">
|
||||
<widget class="GtkLabel" id="label15">
|
||||
<property name="visible">True</property>
|
||||
<property name="label">phy</property>
|
||||
</widget>
|
||||
|
@ -4862,7 +4862,7 @@ I/O:</property>
|
|||
<property name="label_xalign">0</property>
|
||||
<property name="shadow_type">none</property>
|
||||
<child>
|
||||
<widget class="GtkAlignment" id="alignment10">
|
||||
<widget class="GtkAlignment" id="alignment22">
|
||||
<property name="visible">True</property>
|
||||
<property name="top_padding">3</property>
|
||||
<property name="left_padding">12</property>
|
||||
|
@ -4942,7 +4942,7 @@ I/O:</property>
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox7">
|
||||
<widget class="GtkHBox" id="hbox12">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
|
@ -5000,7 +5000,7 @@ I/O:</property>
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label15">
|
||||
<widget class="GtkLabel" id="label25">
|
||||
<property name="visible">True</property>
|
||||
<property name="label">vid</property>
|
||||
</widget>
|
||||
|
@ -5019,7 +5019,7 @@ I/O:</property>
|
|||
<property name="label_xalign">0</property>
|
||||
<property name="shadow_type">none</property>
|
||||
<child>
|
||||
<widget class="GtkAlignment" id="alignment22">
|
||||
<widget class="GtkAlignment" id="alignment30">
|
||||
<property name="visible">True</property>
|
||||
<property name="top_padding">3</property>
|
||||
<property name="left_padding">12</property>
|
||||
|
@ -5059,7 +5059,7 @@ I/O:</property>
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox12">
|
||||
<widget class="GtkHBox" id="hbox13">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
|
@ -5093,7 +5093,7 @@ I/O:</property>
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox13">
|
||||
<widget class="GtkHBox" id="hbox20">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
|
@ -5149,7 +5149,7 @@ I/O:</property>
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label25">
|
||||
<widget class="GtkLabel" id="label35">
|
||||
<property name="visible">True</property>
|
||||
<property name="label">wdog</property>
|
||||
</widget>
|
||||
|
@ -5165,7 +5165,7 @@ I/O:</property>
|
|||
<property name="label_xalign">0</property>
|
||||
<property name="shadow_type">none</property>
|
||||
<child>
|
||||
<widget class="GtkAlignment" id="alignment30">
|
||||
<widget class="GtkAlignment" id="alignment34">
|
||||
<property name="visible">True</property>
|
||||
<property name="top_padding">3</property>
|
||||
<property name="left_padding">12</property>
|
||||
|
|
Loading…
Reference in New Issue