From b20c71f82910417edcb5b595d1f5223095c17268 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Thu, 24 May 2007 14:58:50 -0400 Subject: [PATCH 01/15] Hook up delete VM menu item (Charles Coffing) --- src/virtManager/manager.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/virtManager/manager.py b/src/virtManager/manager.py index 68017b2cc..4980fcdae 100644 --- a/src/virtManager/manager.py +++ b/src/virtManager/manager.py @@ -171,6 +171,7 @@ class vmmManager(gobject.GObject): "on_vm_open_clicked": self.open_vm_console, "on_vm_new_clicked": self.show_vm_create, "on_vm_delete_clicked": self.delete_vm, + "on_menu_edit_delete_activate" : self.delete_vm, "on_menu_edit_details_activate": self.show_vm_details, "on_menu_host_details_activate": self.show_host, From c3b4a9da71493a35607adb70c8e005287bf7d11e Mon Sep 17 00:00:00 2001 From: "Hugh O. Brock" Date: Thu, 24 May 2007 15:51:32 -0400 Subject: [PATCH 02/15] Allow user to set mac addresses for new guests and new guest nics. Also fixes some validation bugs. Thanks to Masayuki Sunou --- src/virtManager/addhardware.py | 47 +++++++++++- src/virtManager/create.py | 51 ++++++++++++- src/vmm-add-hardware.glade | 133 ++++++++++++++++++++++++++++++++- src/vmm-create.glade | 133 ++++++++++++++++++++++++++++++++- 4 files changed, 354 insertions(+), 10 deletions(-) diff --git a/src/virtManager/addhardware.py b/src/virtManager/addhardware.py index e346ba8cf..00b549d04 100644 --- a/src/virtManager/addhardware.py +++ b/src/virtManager/addhardware.py @@ -71,6 +71,7 @@ class vmmAddHardware(gobject.GObject): "on_storage_file_address_changed": self.toggle_storage_size, "on_storage_toggled" : self.change_storage_type, "on_network_toggled" : self.change_network_type, + "on_mac_address_clicked" : self.change_macaddr_use, "on_create_help_clicked": self.show_help, }) @@ -138,6 +139,7 @@ class vmmAddHardware(gobject.GObject): self.change_storage_type() self.change_network_type() + self.change_macaddr_use() if os.getuid() == 0: self.window.get_widget("storage-partition").set_active(True) else: @@ -212,6 +214,12 @@ class vmmAddHardware(gobject.GObject): model = dev.get_model() return ["bridge", model.get_value(dev.get_active_iter(), 0)] + def get_config_macaddr(self): + macaddr = None + if self.window.get_widget("mac-address").get_active(): + macaddr = self.window.get_widget("create-mac-address").get_text() + return macaddr + def page_changed(self, notebook, page, page_number): if page_number == PAGE_DISK: pass @@ -244,6 +252,11 @@ class vmmAddHardware(gobject.GObject): self.window.get_widget("summary-net-target").set_text("-") else: raise ValueError, "Unknown networking type " + net[0] + macaddr = self.get_config_macaddr() + if macaddr != None: + self.window.get_widget("summary-mac-address").set_text(macaddr) + else: + self.window.get_widget("summary-mac-address").set_text("-") def close(self, ignore1=None,ignore2=None): self.topwin.hide() @@ -286,11 +299,12 @@ class vmmAddHardware(gobject.GObject): def add_network(self): net = self.get_config_network() + mac = self.get_config_macaddr() vnic = None if net[0] == "bridge": - vnic = virtinst.VirtualNetworkInterface(type=net[0], bridge=net[1]) + vnic = virtinst.VirtualNetworkInterface(macaddr=mac, type=net[0], bridge=net[1]) elif net[0] == "network": - vnic = virtinst.VirtualNetworkInterface(type=net[0], network=net[1]) + vnic = virtinst.VirtualNetworkInterface(macaddr=mac, type=net[0], network=net[1]) else: raise ValueError, "Unsupported networking type " + net[0] @@ -446,6 +460,12 @@ class vmmAddHardware(gobject.GObject): self.window.get_widget("net-network").set_sensitive(False) self.window.get_widget("net-device").set_sensitive(True) + def change_macaddr_use(self, ignore=None): + if self.window.get_widget("mac-address").get_active(): + self.window.get_widget("create-mac-address").set_sensitive(True) + else: + self.window.get_widget("create-mac-address").set_sensitive(False) + def validate(self, page_num): if page_num == PAGE_INTRO: if self.get_config_hardware_type() == None: @@ -484,6 +504,29 @@ class vmmAddHardware(gobject.GObject): _("You must select one of the physical devices")) return False + if self.window.get_widget("mac-address").get_active(): + mac= self.window.get_widget("create-mac-address").get_text() + if len(mac) != 17: + self._validation_error_box(_("Invalid MAC address"), \ + _("MAC adrress must be 17 characters")) + return False + if re.match("^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$",mac) == None: + self._validation_error_box(_("Invalid MAC address"), \ + _("MAC address must be a form such as AA:BB:CC:DD:EE:FF, and MAC adrress may contain numeric and alphabet of A-F(a-f) and ':' characters only")) + return False + hostdevs = virtinst.util.get_host_network_devices() + for hostdev in hostdevs: + if mac.lower() == hostdev[4]: + return self._yes_no_box(_('MAC adress "%s" is already in use by host!' % mac), \ + _("Do you really want to use the MAC address ?")) + vms = [] + for domains in self.vm.get_connection().vms.values(): + vms.append(domains.vm) + vnic = virtinst.VirtualNetworkInterface(macaddr=mac) + if vnic.countMACaddr(vms) > 0: + return self._yes_no_box(_('MAC adress "%s" is already in use by another guest!' % mac), \ + _("Do you really want to use the MAC address ?")) + return True def _validation_error_box(self, text1, text2=None): diff --git a/src/virtManager/create.py b/src/virtManager/create.py index 168694170..34b81ceb4 100644 --- a/src/virtManager/create.py +++ b/src/virtManager/create.py @@ -92,6 +92,7 @@ class vmmCreate(gobject.GObject): "on_storage_file_address_changed": self.toggle_storage_size, "on_storage_toggled" : self.change_storage_type, "on_network_toggled" : self.change_network_type, + "on_mac_address_clicked" : self.change_macaddr_use, "on_media_toggled" : self.change_media_type, "on_os_type_changed" : self.change_os_type, "on_cpu_architecture_changed": self.change_cpu_arch, @@ -238,6 +239,7 @@ class vmmCreate(gobject.GObject): self.change_media_type() self.change_storage_type() self.change_network_type() + self.change_macaddr_use() self.window.get_widget("create-vm-name").set_text("") self.window.get_widget("media-iso-image").set_active(True) self.window.get_widget("fv-iso-location").set_text("") @@ -362,6 +364,12 @@ class vmmCreate(gobject.GObject): model = dev.get_model() return ["bridge", model.get_value(dev.get_active_iter(), 0)] + def get_config_macaddr(self): + macaddr = None + if self.window.get_widget("mac-address").get_active(): + macaddr = self.window.get_widget("create-mac-address").get_text() + return macaddr + def get_config_maximum_memory(self): return self.window.get_widget("create-memory-max").get_value() @@ -449,6 +457,12 @@ class vmmCreate(gobject.GObject): self.window.get_widget("summary-net-target").set_text("-") else: raise ValueError, "Unknown networking type " + net[0] + macaddr = self.get_config_macaddr() + if macaddr != None: + self.window.get_widget("summary-mac-address").set_text(macaddr) + else: + self.window.get_widget("summary-mac-address").set_text("-") + self.window.get_widget("create-forward").hide() self.window.get_widget("create-finish").show() @@ -543,12 +557,13 @@ class vmmCreate(gobject.GObject): # network net = self.get_config_network() + mac = self.get_config_macaddr() if net[0] == "bridge": - guest.nics.append(virtinst.VirtualNetworkInterface(type=net[0], bridge=net[1])) + guest.nics.append(virtinst.VirtualNetworkInterface(macaddr=mac, type=net[0], bridge=net[1])) elif net[0] == "network": - guest.nics.append(virtinst.VirtualNetworkInterface(type=net[0], network=net[1])) + guest.nics.append(virtinst.VirtualNetworkInterface(macaddr=mac, type=net[0], network=net[1])) elif net[0] == "user": - guest.nics.append(virtinst.VirtualNetworkInterface(type=net[0])) + guest.nics.append(virtinst.VirtualNetworkInterface(macaddr=mac, type=net[0])) else: raise ValueError, "Unsupported networking type " + net[0] @@ -757,6 +772,12 @@ class vmmCreate(gobject.GObject): self.window.get_widget("net-network").set_sensitive(False) self.window.get_widget("net-device").set_sensitive(True) + def change_macaddr_use(self, ignore=None): + if self.window.get_widget("mac-address").get_active(): + self.window.get_widget("create-mac-address").set_sensitive(True) + else: + self.window.get_widget("create-mac-address").set_sensitive(False) + def set_max_memory(self, src): max_memory = src.get_adjustment().value startup_mem_adjustment = self.window.get_widget("create-memory-startup").get_adjustment() @@ -771,7 +792,7 @@ class vmmCreate(gobject.GObject): self._validation_error_box(_("Invalid System Name"), \ _("System name must be non-blank and less than 50 characters")) return False - if re.match("^[a-zA-Z0-9_]*$", name) == None: + if re.match("^[a-zA-Z0-9_-]*$", name) == None: self._validation_error_box(_("Invalid System Name"), \ _("System name may contain alphanumeric and '_' characters only")) return False @@ -838,6 +859,28 @@ class vmmCreate(gobject.GObject): _("You must select one of the physical devices")) return False + if self.window.get_widget("mac-address").get_active(): + mac = self.window.get_widget("create-mac-address").get_text() + if len(mac) != 17: + self._validation_error_box(_("Invalid MAC address"), \ + _("MAC adrress must be 17 characters")) + return False + if re.match("^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$",mac) == None: + self._validation_error_box(_("Invalid MAC address"), \ + _("MAC address must be a form such as AA:BB:CC:DD:EE:FF, and MAC adrress may contain numeric and alphabet of A-F(a-f) and ':' characters only")) + return False + hostdevs = virtinst.util.get_host_network_devices() + for hostdev in hostdevs: + if mac.lower() == hostdev[4]: + return self._yes_no_box(_('MAC adress "%s" is already in use by host!' % mac), \ + _("Do you really want to use the MAC address ?")) + vms = [] + for domains in self.connection.vms.values(): + vms.append(domains.vm) + vnic = virtinst.VirtualNetworkInterface(macaddr=mac) + if vnic.countMACaddr(vms) > 0: + return self._yes_no_box(_('MAC adress "%s" is already in use by another guest!' % mac), \ + _("Do you really want to use the MAC address ?")) # do this always, since there's no "leaving a notebook page" event. self.window.get_widget("create-back").set_sensitive(True) diff --git a/src/vmm-add-hardware.glade b/src/vmm-add-hardware.glade index d52b9acf0..3cddf6f39 100644 --- a/src/vmm-add-hardware.glade +++ b/src/vmm-add-hardware.glade @@ -992,7 +992,7 @@ True - 6 + 8 2 False 6 @@ -1319,6 +1319,79 @@ + + + + True + True + Set _fixed MAC address for this NIC? + True + GTK_RELIEF_NORMAL + True + False + False + True + + + + 0 + 2 + 6 + 7 + fill + + + + + + + True + _MAC address: + True + True + GTK_JUSTIFY_LEFT + False + False + 1 + 0.5 + 0 + 0 + create-mac-address + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 7 + 8 + fill + + + + + + + True + True + True + True + 17 + + True + + False + + + 1 + 2 + 7 + 8 + + + @@ -1597,7 +1670,7 @@ 6 True - 3 + 4 3 False 3 @@ -1742,6 +1815,62 @@ + + + + True + MAC address: + False + True + GTK_JUSTIFY_LEFT + False + False + 1 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 1 + 2 + 3 + 4 + fill + + + + + + + True + - + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 2 + 3 + 3 + 4 + fill + + + 0 diff --git a/src/vmm-create.glade b/src/vmm-create.glade index a9f9cc5ff..5f408820f 100644 --- a/src/vmm-create.glade +++ b/src/vmm-create.glade @@ -3118,7 +3118,7 @@ mipsel True - 6 + 8 2 False 6 @@ -3445,6 +3445,79 @@ mipsel + + + + True + _MAC address: + True + True + GTK_JUSTIFY_LEFT + False + False + 1 + 0.5 + 0 + 0 + create-mac-address + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 7 + 8 + fill + + + + + + + True + True + Set _fixed MAC address for your virtual system? + True + GTK_RELIEF_NORMAL + True + False + False + True + + + + 0 + 2 + 6 + 7 + fill + + + + + + + True + True + True + True + 17 + + True + + False + + + 1 + 2 + 7 + 8 + + + @@ -4225,7 +4298,7 @@ mipsel 6 True - 16 + 17 3 False 3 @@ -5038,6 +5111,62 @@ mipsel + + + + True + MAC address: + False + True + GTK_JUSTIFY_LEFT + False + False + 1 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 1 + 2 + 16 + 17 + fill + + + + + + + True + - + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 2 + 3 + 16 + 17 + fill + + + From aec4d3853b11c5254667b9b9673705cf18a78053 Mon Sep 17 00:00:00 2001 From: "Hugh O. Brock" Date: Thu, 24 May 2007 16:49:13 -0400 Subject: [PATCH 03/15] Handle the case where the source device and source type are null -- for example, if a cdrom device exists in the guest config but is not mapped to a backend device. --- src/virtManager/domain.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/virtManager/domain.py b/src/virtManager/domain.py index 39186a312..4869fb99b 100644 --- a/src/virtManager/domain.py +++ b/src/virtManager/domain.py @@ -456,23 +456,28 @@ class vmmDomain(gobject.GObject): type = node.prop("type") srcpath = None devdst = None + devtype = node.prop("device") + if devtype == None: + devtype = "disk" for child in node.children: if child.name == "source": if type == "file": srcpath = child.prop("file") elif type == "block": srcpath = child.prop("dev") + elif type == None: + type = "-" elif child.name == "target": devdst = child.prop("dev") - if srcpath == None: - raise RuntimeError("missing source path") + if devtype == "cdrom": + srcpath = "-" + type = "block" + else: + raise RuntimeError("missing source path") if devdst == None: raise RuntimeError("missing destination device") - devtype = node.prop("device") - if devtype == None: - devtype = "disk" disks.append([type, srcpath, devtype, devdst]) finally: From 3b8ee9b9e242c239de503450ba5bff2a585f6283 Mon Sep 17 00:00:00 2001 From: "Hugh O. Brock" Date: Wed, 13 Jun 2007 13:38:19 -0400 Subject: [PATCH 04/15] Fixes 242900, thanks to David Robinson --- src/virtManager/details.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/virtManager/details.py b/src/virtManager/details.py index 6d23e1365..4288509ec 100644 --- a/src/virtManager/details.py +++ b/src/virtManager/details.py @@ -472,7 +472,7 @@ class vmmDetails(gobject.GObject): vnic = None if netinfo[0] == "bridge": vnic = virtinst.VirtualNetworkInterface(type=netinfo[0], bridge=netinfo[1], macaddr=netinfo[3]) - elif net[0] == "network": + elif netinfo[0] == "network": vnic = virtinst.VirtualNetworkInterface(type=netinfo[0], network=netinfo[1], macaddr=netinfo[3]) else: vnic = virtinst.VirtualNetworkInterface(type=netinfo[0], macaddr=netinfo[3]) From 621de870622ef460c4fbeae1e501b79655f51099 Mon Sep 17 00:00:00 2001 From: Masayuki Sunou Date: Wed, 13 Jun 2007 15:09:10 -0400 Subject: [PATCH 05/15] [et-mgmt-tools] [PATCH] In virt-manager GUI, when the disk is added, VM cannot be started. Hi When the disk is added to active VM by virt-manager, VM cannot be restarted after VM is stopped. --> Bugzilla Bug 239763 https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=239763 This patch fixes it. When the device is attached to active VM, virt-manager adds the device twice in add_device() of "domain.py". 1. Call attachDevice() 2. Call define_domain() after the XML is updated Therefore, the same device is doubly attached. (So, when the device is disk, VM cannot be started) This patch fixes "domain.py" as follows so that the same device is not doubly attached. VM is active : Call attachDevice() only VM is inactive : Call define_domain() after the XML is updated Signed-off-by: Masayuki Sunou Thanks, Masayuki Sunou. ---------------------------------------------------------------------- --- src/virtManager/domain.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/virtManager/domain.py b/src/virtManager/domain.py index 4869fb99b..d117c9416 100644 --- a/src/virtManager/domain.py +++ b/src/virtManager/domain.py @@ -540,15 +540,15 @@ class vmmDomain(gobject.GObject): if self.is_active(): self.vm.attachDevice(xml) + else: + vmxml = self.vm.XMLDesc(0) - vmxml = self.vm.XMLDesc(0) + index = vmxml.find("") + newxml = vmxml[0:index] + xml + vmxml[index:] - index = vmxml.find("") - newxml = vmxml[0:index] + xml + vmxml[index:] + logging.debug("Redefine with " + newxml) - logging.debug("Redefine with " + newxml) - - self.get_connection().define_domain(newxml) + self.get_connection().define_domain(newxml) def remove_device(self, dev_xml): logging.debug("Removing device " + dev_xml) From 8ff8679b10edcc772093a2678cde2ce7d660a844 Mon Sep 17 00:00:00 2001 From: "Hugh O. Brock" Date: Wed, 13 Jun 2007 15:15:42 -0400 Subject: [PATCH 06/15] Backed out changeset ebd54b0c882ae581fc020b87df8583417b8b9e97 Applied this patch in error -- the correct fix is already in. --- src/virtManager/domain.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/virtManager/domain.py b/src/virtManager/domain.py index d117c9416..4869fb99b 100644 --- a/src/virtManager/domain.py +++ b/src/virtManager/domain.py @@ -540,15 +540,15 @@ class vmmDomain(gobject.GObject): if self.is_active(): self.vm.attachDevice(xml) - else: - vmxml = self.vm.XMLDesc(0) - index = vmxml.find("") - newxml = vmxml[0:index] + xml + vmxml[index:] + vmxml = self.vm.XMLDesc(0) - logging.debug("Redefine with " + newxml) + index = vmxml.find("") + newxml = vmxml[0:index] + xml + vmxml[index:] - self.get_connection().define_domain(newxml) + logging.debug("Redefine with " + newxml) + + self.get_connection().define_domain(newxml) def remove_device(self, dev_xml): logging.debug("Removing device " + dev_xml) From 04501bbe773dbf606a722f86fb47ae933ddd82b7 Mon Sep 17 00:00:00 2001 From: "Hugh O. Brock" Date: Wed, 13 Jun 2007 15:20:43 -0400 Subject: [PATCH 07/15] Fix BZ 239763 -- we shouldn't add a disk twice when we add it to a live domain on Xen 3.1. --- src/virtManager/domain.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/virtManager/domain.py b/src/virtManager/domain.py index 4869fb99b..051e0a926 100644 --- a/src/virtManager/domain.py +++ b/src/virtManager/domain.py @@ -538,10 +538,13 @@ class vmmDomain(gobject.GObject): def add_device(self, xml): logging.debug("Adding device " + xml) + # get the XML for the live domain before we attach the device + # otherwise the device gets added to the XML twice. + vmxml = self.vm.XMLDesc(0) + if self.is_active(): self.vm.attachDevice(xml) - vmxml = self.vm.XMLDesc(0) index = vmxml.find("") newxml = vmxml[0:index] + xml + vmxml[index:] From c320e035e7749a7037d091d627a0da1670e535f8 Mon Sep 17 00:00:00 2001 From: "Hugh O. Brock" Date: Wed, 13 Jun 2007 15:30:22 -0400 Subject: [PATCH 08/15] I thought that the following is the problem. ---------------------------------------------------------------------- In finish() of "create.py", the port number of VNC become -1. When "Status monitoring" is short, the port number of VNC is updated in a short time, but, when "Status monitoring" is long, the port number of VNC is not updated for a long time. Because the XML data cached in "domain.py" is updated only in tick(). ---------------------------------------------------------------------- And, I forgot retrying in "console.py". Therefore, I adopted updating the port number of VNC in "cerate.py". I remake the patch. This patch only clears XML in get_graphics_console(), and the connection to the console is not retried in "create.py". So, by applying this patch, the XML data is cleared by retrying in "console.py" even when "Status monitoring" is long, and the port number of VNC is updated. (Because retrying in "console.py" calls get_graphics_console()) Thanks, Masayuki Sunou. ---------------------------------------------------------------------- --- src/virtManager/domain.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/virtManager/domain.py b/src/virtManager/domain.py index 051e0a926..59d2093c2 100644 --- a/src/virtManager/domain.py +++ b/src/virtManager/domain.py @@ -430,6 +430,7 @@ class vmmDomain(gobject.GObject): return os.access(tty, os.R_OK | os.W_OK) def get_graphics_console(self): + self.xml = None type = self.get_xml_string("/domain/devices/graphics/@type") port = None if type == "vnc": From 5ee726869619bacb68275a5ec70f9bcf8b3bcbb8 Mon Sep 17 00:00:00 2001 From: "Hugh O. Brock" Date: Wed, 13 Jun 2007 17:15:51 -0400 Subject: [PATCH 09/15] Fix up system-name error message... hopefully for the last time... --- src/virtManager/create.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/virtManager/create.py b/src/virtManager/create.py index 34b81ceb4..33719d264 100644 --- a/src/virtManager/create.py +++ b/src/virtManager/create.py @@ -794,7 +794,7 @@ class vmmCreate(gobject.GObject): return False if re.match("^[a-zA-Z0-9_-]*$", name) == None: self._validation_error_box(_("Invalid System Name"), \ - _("System name may contain alphanumeric and '_' characters only")) + _("System name may contain alphanumeric, '_' and '-' characters only")) return False From bb7fffa4416c4fcb15a885161e9636bb3c60065d Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 15 Jun 2007 16:57:51 -0400 Subject: [PATCH 10/15] Fixed connection name with test:///default (Mark Johnson) --- AUTHORS | 1 + src/virtManager/connection.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/AUTHORS b/AUTHORS index e1ee43a23..6d55e7da7 100644 --- a/AUTHORS +++ b/AUTHORS @@ -21,6 +21,7 @@ Further patches have been submitted by: Mark Cave-Ayland Richard W.M. Jones Nobuhiro Itou + Mark Johnson <...send a patch & get your name here...> diff --git a/src/virtManager/connection.py b/src/virtManager/connection.py index 7aaed5413..6ebb9fbbd 100644 --- a/src/virtManager/connection.py +++ b/src/virtManager/connection.py @@ -189,6 +189,8 @@ class vmmConnection(gobject.GObject): return "QEMU session: " + self.get_hostname() else: return "QEMU system: " + self.get_hostname() + else: + return self.get_type() + ":" + self.get_hostname() def get_uri(self): From efa4e15f2f93f6c176eda17344a713e96824723e Mon Sep 17 00:00:00 2001 From: Masayuki Sunou Date: Mon, 18 Jun 2007 15:16:20 -0400 Subject: [PATCH 11/15] Re: [et-mgmt-tools] [PATCH] Fix the maximum number of VCPUin virt-manager Hi Hugh Thank you for reviewing. I remake this patch. > Hmm, this is good, but I'm inclined to think it would be better to put a > getMaxVcpus() call in connection.py and isolate the "check the > connection type and either call getMaxVcpus or arbitrarily return '32'" > there (so we don't repeat the code in two places). Also, it looks to me > like "Xen" is the default in xen_unified.c, at least in current libvirt > code, so you shouldn't need to supply "Xen" to the getMaxVcpus call. Can > you redo the patch along these lines? > This patch changes as follows. 1. getMaxVcpus() is executed from connection.py. 2. getMaxVcpus() is called with the result of get_type() not "Xen" Thanks, Masayuki Sunou. =============================================================================== --- src/virtManager/connection.py | 7 +++++++ src/virtManager/create.py | 1 + src/virtManager/details.py | 5 +++-- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/virtManager/connection.py b/src/virtManager/connection.py index 6ebb9fbbd..1f7faa2aa 100644 --- a/src/virtManager/connection.py +++ b/src/virtManager/connection.py @@ -225,6 +225,13 @@ class vmmConnection(gobject.GObject): def get_host_info(self): return self.hostinfo + def get_max_vcpus(self): + try: + return self.vmm.getMaxVcpus(self.get_type()) + except Exception, e: + logging.debug('Unable to get max vcpu') + return 32; + def connect(self, name, callback): handle_id = gobject.GObject.connect(self, name, callback) diff --git a/src/virtManager/create.py b/src/virtManager/create.py index 33719d264..92c503bc5 100644 --- a/src/virtManager/create.py +++ b/src/virtManager/create.py @@ -253,6 +253,7 @@ class vmmCreate(gobject.GObject): self.window.get_widget("create-memory-max").set_value(500) self.window.get_widget("create-memory-startup").set_value(500) self.window.get_widget("create-vcpus").set_value(1) + self.window.get_widget("create-vcpus").get_adjustment().upper = self.connection.get_max_vcpus() self.window.get_widget("non-sparse").set_active(True) model = self.window.get_widget("pv-media-url").get_model() self.populate_url_model(model, self.config.get_media_urls()) diff --git a/src/virtManager/details.py b/src/virtManager/details.py index 4288509ec..a0ba7c048 100644 --- a/src/virtManager/details.py +++ b/src/virtManager/details.py @@ -364,8 +364,9 @@ class vmmDetails(gobject.GObject): self.window.get_widget("state-host-cpus").set_text("%d" % self.vm.get_connection().host_active_processor_count()) status = self.vm.status() if status in [ libvirt.VIR_DOMAIN_SHUTOFF, libvirt.VIR_DOMAIN_CRASHED ]: - self.window.get_widget("config-vcpus").get_adjustment().upper = 32 - self.window.get_widget("state-vm-maxvcpus").set_text("32") + cpu_max = self.vm.get_connection().get_max_vcpus() + self.window.get_widget("config-vcpus").get_adjustment().upper = cpu_max + self.window.get_widget("state-vm-maxvcpus").set_text(str(cpu_max)) else: self.window.get_widget("config-vcpus").get_adjustment().upper = self.vm.vcpu_max_count() self.window.get_widget("state-vm-maxvcpus").set_text("%d" % (self.vm.vcpu_max_count())) From 1e1e4b0bba383ec9a096b240cdcacb5025b40b3c Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Tue, 19 Jun 2007 13:20:29 -0400 Subject: [PATCH 12/15] Allow user to dismiss the cursor grab notification permanently (rhbz 244347) --- src/virt-manager.schemas.in | 13 +++++++++ src/virtManager/config.py | 7 +++++ src/virtManager/console.py | 58 +++++++++++++++++++++++++------------ 3 files changed, 60 insertions(+), 18 deletions(-) diff --git a/src/virt-manager.schemas.in b/src/virt-manager.schemas.in index 7d5be34da..96b454b93 100644 --- a/src/virt-manager.schemas.in +++ b/src/virt-manager.schemas.in @@ -156,5 +156,18 @@ + + /schemas/apps/::PACKAGE::/console/grab-notify + /apps/::PACKAGE::/console/grab-notify + ::PACKAGE:: + bool + 1 + + + Whether to show notification when grabbing mouse + Whether to show the notification hint when grabbing the mouse in the console + + + diff --git a/src/virtManager/config.py b/src/virtManager/config.py index 54dc64751..92ac60e13 100644 --- a/src/virtManager/config.py +++ b/src/virtManager/config.py @@ -209,6 +209,13 @@ class vmmConfig: def set_console_keygrab(self, pref): self.conf.set_int(self.conf_dir + "/console/keygrab", pref) + def show_console_grab_notify(self): + return self.conf.get_bool(self.conf_dir + "/console/grab-notify") + + def set_console_grab_notify(self, state): + self.conf.set_bool(self.conf_dir + "/console/grab-notify", state) + + def get_secret_name(self, vm): return "vm-console-" + vm.get_uuid() diff --git a/src/virtManager/console.py b/src/virtManager/console.py index 4a9838e94..405715b82 100644 --- a/src/virtManager/console.py +++ b/src/virtManager/console.py @@ -68,6 +68,17 @@ class vmmConsole(gobject.GObject): self.vncViewerFailures = 0 self.vncViewerRetryDelay = 125 + self.notifyID = None + try: + bus = dbus.SessionBus() + self.notifyObject = bus.get_object("org.freedesktop.Notifications", "/org/freedesktop/Notifications") + self.notifyInterface = dbus.Interface(self.notifyObject, "org.freedesktop.Notifications") + self.notifyInterface.connect_to_signal("ActionInvoked", self.notify_action) + self.notifyInterface.connect_to_signal("NotificationClosed", self.notify_closed) + except Exception, e: + logging.error("Cannot initialize notification system" + str(e)) + pass + self.window.get_widget("console-pages").set_show_tabs(False) self.config.on_console_keygrab_changed(self.keygrab_changed) @@ -121,30 +132,41 @@ class vmmConsole(gobject.GObject): def notify_grabbed(self, src): topwin = self.window.get_widget("vmm-console") - try: - bus = dbus.SessionBus() - noteSvr = bus.get_object("org.freedesktop.Notifications", "/org/freedesktop/Notifications") - noteObj = dbus.Interface(noteSvr, "org.freedesktop.Notifications") - (x, y) = topwin.window.get_origin() - noteObj.Notify(topwin.get_title(), - 0, - '', - _("Pointer grabbed"), - _("The mouse pointer has been restricted to the virtual " \ - "console window. To release the pointer press the key pair " \ - "Ctrl+Alt"), - [], - {"desktop-entry": "virt-manager", - "x": x+200, "y": y}, - 5 * 1000); - except Exception, e: - pass topwin.set_title(_("Press Ctrl+Alt to release pointer.") + " " + self.title) + if self.config.show_console_grab_notify(): + try: + (x, y) = topwin.window.get_origin() + self.notifyID = self.notifyInterface.Notify(topwin.get_title(), + 0, + '', + _("Pointer grabbed"), + _("The mouse pointer has been restricted to the virtual " \ + "console window. To release the pointer press the key pair " \ + "Ctrl+Alt"), + ["dismiss", _("Do not show this notification in the future")], + {"desktop-entry": "virt-manager", + "x": x+200, "y": y}, + 8 * 1000); + except Exception, e: + logging.error("Cannot popup notification " + str(e)) + pass + def notify_ungrabbed(self, src): topwin = self.window.get_widget("vmm-console") topwin.set_title(self.title) + def notify_closed(self, id, reason=None): + if self.notifyID is not None and self.notifyID == id: + self.notifyID = None + + def notify_action(self, id, action): + if self.notifyID is None or self.notifyID != id: + return + + if action == "dismiss": + self.config.set_console_grab_notify(False) + def keygrab_changed(self, src, ignore1=None,ignore2=None,ignore3=None): if self.config.get_console_keygrab() == 2: self.vncViewer.set_autograb_keyboard(True) From a8ad929a028b42c61995d93beda027cff80fec59 Mon Sep 17 00:00:00 2001 From: "Hugh O. Brock" Date: Fri, 22 Jun 2007 13:32:13 -0400 Subject: [PATCH 13/15] Refactor virt-manager validation to use validation in virtinst. Eliminates regexes in two places, among other things. Thanks to Cole Robinson. --- AUTHORS | 1 + src/virtManager/create.py | 313 ++++++++++++++++++++++---------------- 2 files changed, 179 insertions(+), 135 deletions(-) diff --git a/AUTHORS b/AUTHORS index 6d55e7da7..e5f595af7 100644 --- a/AUTHORS +++ b/AUTHORS @@ -22,6 +22,7 @@ Further patches have been submitted by: Richard W.M. Jones Nobuhiro Itou Mark Johnson + Cole Robinson <...send a patch & get your name here...> diff --git a/src/virtManager/create.py b/src/virtManager/create.py index 92c503bc5..ebfabe422 100644 --- a/src/virtManager/create.py +++ b/src/virtManager/create.py @@ -102,6 +102,11 @@ class vmmCreate(gobject.GObject): self.set_initial_state() + # Guest to fill in with values along the way + self._guest = virtinst.Guest(type=self.get_domain_type()) + self._disk = None + self._net = None + def show(self): self.topwin.show() self.reset_state() @@ -477,97 +482,28 @@ class vmmCreate(gobject.GObject): return 0 def finish(self, ignore=None): - # first things first, are we trying to create a fully virt guest? - if self.get_config_method() == VM_FULLY_VIRT: - guest = virtinst.FullVirtGuest(type=self.get_domain_type(), \ - hypervisorURI=self.connection.get_uri(), \ - arch=self.get_domain_arch()) - try: - guest.cdrom = self.get_config_install_source() - except ValueError, e: - self._validation_error_box(_("Invalid FV media address"),e.args[0]) - try: - if self.get_config_os_type() is not None and self.get_config_os_type() != "generic": - logging.debug("OS Type: %s" % self.get_config_os_type()) - guest.os_type = self.get_config_os_type() - except ValueError, e: - self._validation_error_box(_("Invalid FV OS Type"),e.args[0]) - try: - if self.get_config_os_variant() is not None and self.get_config_os_type() != "generic": - logging.debug("OS Variant: %s" % self.get_config_os_variant()) - guest.os_variant = self.get_config_os_variant() - except ValueError, e: - self._validation_error_box(_("Invalid FV OS Variant"),e.args[0]) + # Validation should have mostly set up out guest. We just need + # to take care of a few pieces we didn't touch - else: - guest = virtinst.ParaVirtGuest(type=self.get_domain_type(), hypervisorURI=self.connection.get_uri()) - try: - guest.location = self.get_config_install_source() - except ValueError, e: - self._validation_error_box(_("Invalid PV media address"), e.args[0]) - return - ks = self.get_config_kickstart_source() - if ks != None and len(ks) != 0: - guest.extraargs = "ks=%s" % ks + guest = self._guest + guest.hypervisorURI = self.connection.get_uri() - # set the name + # UUID, append disk and nic try: - guest.name = self.get_config_name() + guest.uuid = virtinst.util.uuidToString(virtinst.util.randomUUID()) + except ValueError, E: + self._validation_error_box(_("UUID Error"), str(e)) + + try: + guest.disks.append(self._disk) except ValueError, e: - self._validation_error_box(_("Invalid system name"), e.args[0]) - return - - # set the memory + self._validation_error_box(_("Error Setting up Disk"), str(e)) + try: - guest.memory = int(self.get_config_initial_memory()) - except ValueError: - self._validation_error_box(_("Invalid memory setting"), e.args[0]) - return - - try: - guest.maxmemory = int(self.get_config_maximum_memory()) - except ValueError: - self._validation_error_box(_("Invalid memory setting"), e.args[0]) - return - - # set vcpus - guest.vcpus = int(self.get_config_virtual_cpus()) - - # disks - filesize = None - if self.get_config_disk_size() != None: - filesize = self.get_config_disk_size() / 1024.0 - try: - d = virtinst.VirtualDisk(self.get_config_disk_image(), filesize, sparse = self.is_sparse_file()) - if d.type == virtinst.VirtualDisk.TYPE_FILE and \ - self.get_config_method() == VM_PARA_VIRT \ - and virtinst.util.is_blktap_capable(): - d.driver_name = virtinst.VirtualDisk.DRIVER_TAP - if d.type == virtinst.VirtualDisk.TYPE_FILE and not \ - self.is_sparse_file(): - self.non_sparse = True - else: - self.non_sparse = False + guest.nics.append(self._net) except ValueError, e: - self._validation_error_box(_("Invalid storage address"), e.args[0]) - return - guest.disks.append(d) - - # uuid - guest.uuid = virtinst.util.uuidToString(virtinst.util.randomUUID()) - - # network - net = self.get_config_network() - mac = self.get_config_macaddr() - if net[0] == "bridge": - guest.nics.append(virtinst.VirtualNetworkInterface(macaddr=mac, type=net[0], bridge=net[1])) - elif net[0] == "network": - guest.nics.append(virtinst.VirtualNetworkInterface(macaddr=mac, type=net[0], network=net[1])) - elif net[0] == "user": - guest.nics.append(virtinst.VirtualNetworkInterface(macaddr=mac, type=net[0])) - else: - raise ValueError, "Unsupported networking type " + net[0] - + self._validation_error_box(_("Error Setting up Network"), str(e)) + # set up the graphics to use SDL import keytable keymap = None @@ -597,7 +533,7 @@ class vmmCreate(gobject.GObject): "\n Memory: " + str(guest.memory) + \ "\n Max Memory: " + str(guest.maxmemory) + \ "\n # VCPUs: " + str(guest.vcpus) + \ - "\n Filesize: " + str(filesize) + \ + "\n Filesize: " + str(self._disk.size) + \ "\n Disk image: " + str(self.get_config_disk_image()) +\ "\n Non-sparse file: " + str(self.non_sparse)) @@ -787,68 +723,131 @@ class vmmCreate(gobject.GObject): startup_mem_adjustment.upper = max_memory def validate(self, page_num): + + # Setting the values in the Guest/Disk/Network virtinst objects + # provides a lot of error checking for free, we just have to catch + # the messages + if page_num == PAGE_NAME: name = self.window.get_widget("create-vm-name").get_text() - if len(name) > 50 or len(name) == 0: - self._validation_error_box(_("Invalid System Name"), \ - _("System name must be non-blank and less than 50 characters")) + try: + self._guest.name = name + except ValueError, e: + self._validation_error_box(_("Invalid System Name"), str(e)) return False - if re.match("^[a-zA-Z0-9_-]*$", name) == None: - self._validation_error_box(_("Invalid System Name"), \ - _("System name may contain alphanumeric, '_' and '-' characters only")) - return False - - elif page_num == PAGE_TYPE: - if self.get_config_method() == VM_FULLY_VIRT and self.connection.get_type().startswith("Xen") and not virtinst.util.is_hvm_capable(): - self._validation_error_box(_("Hardware Support Required"), \ - _("Your hardware does not appear to support full virtualization. Only paravirtualized guests will be available on this hardware.")) - return False + + # Set up appropriate guest object dependent on selected type + name = self._guest.name + if self.get_config_method() == VM_PARA_VIRT: + self._guest = virtinst.ParaVirtGuest(\ + type=self.get_domain_type()) + else: + self._guest = virtinst.FullVirtGuest(\ + type=self.get_domain_type(), \ + arch=self.get_domain_arch()) + + self._guest.name = name # Transfer name over elif page_num == PAGE_FVINST: + if self.window.get_widget("media-iso-image").get_active(): + src = self.get_config_install_source() - if src == None or len(src) == 0: - self._validation_error_box(_("ISO Path Required"), \ - _("You must specify an ISO location for the guest installation")) - return False - elif not(os.path.exists(src)): - self._validation_error_box(_("ISO Path Not Found"), \ - _("You must specify a valid path to the ISO image for guest installation")) + try: + self._guest.cdrom = src + except ValueError, e: + self._validation_error_box(_("ISO Path Not Found"), str(e)) return False else: cdlist = self.window.get_widget("cd-path") - if cdlist.get_active() == -1: - self._validation_error_box(_("Install media required"), \ - _("You must select the CDROM install media for guest installation")) + src = self.get_config_install_source() + try: + self._guest.cdrom = src + except ValueError, e: + self._validation_error_box(_("CD-ROM Path Error"), str(e)) return False + + try: + if self.get_config_os_type() is not None \ + and self.get_config_os_type() != "generic": + logging.debug("OS Type: %s" % self.get_config_os_type()) + self._guest.os_type = self.get_config_os_type() + except ValueError, e: + self._validation_error_box(_("Invalid FV OS Type"), str(e)) + return False + try: + if self.get_config_os_variant() is not None \ + and self.get_config_os_type() != "generic": + logging.debug("OS Variant: %s" % self.get_config_os_variant()) + self._guest.os_variant = self.get_config_os_variant() + except ValueError, e: + self._validation_error_box(_("Invalid FV OS Variant"), str(e)) + return False elif page_num == PAGE_PVINST: + src = self.get_config_install_source() - if src == None or len(src) == 0: - self._validation_error_box(_("URL Required"), \ - _("You must specify a URL for the install image for the guest install")) + try: + self._guest.location = src + except ValueError, e: + self._validation_error_box(_("Invalid Install URL"), str(e)) return False + ks = self.get_config_kickstart_source() + if ks is not None and len(ks) != 0: + if not (ks.startswith("http://") or ks.startswith("ftp://") \ + or ks.startswith("nfs:")): + self._validation_error_box(_("Kickstart URL Error"), \ + _("Kickstart location must be an NFS, HTTP or FTP source")) + return False + else: + self._guest.extraargs = "ks=%s" % (ks,) + elif page_num == PAGE_DISK: + disk = self.get_config_disk_image() if disk == None or len(disk) == 0: self._validation_error_box(_("Storage Address Required"), \ _("You must specify a partition or a file for storage for the guest install")) return False + + # Attempt to set disk + filesize = None + if self.get_config_disk_size() != None: + filesize = self.get_config_disk_size() / 1024.0 + try: + if self.window.get_widget("storage-partition").get_active(): + type = virtinst.VirtualDisk.TYPE_BLOCK + else: + type = virtinst.VirtualDisk.TYPE_FILE - if not self.window.get_widget("storage-partition").get_active(): - if os.path.isdir(disk): - self._validation_error_box(_("Storage Address Is Directory"), \ - _("You chose 'Simple File' storage for your storage method, but chose a directory instead of a file. Please enter a new filename or choose an existing file.")) - return False + self._disk = virtinst.VirtualDisk(\ + self.get_config_disk_image(), \ + filesize, \ + sparse = self.is_sparse_file(), \ + type=type) - d = virtinst.VirtualDisk(self.get_config_disk_image(), self.get_config_disk_size(), sparse = self.is_sparse_file()) - if d.is_conflict_disk(self.connection.vmm) is True: - res = self._yes_no_box(_('Disk "%s" is already in use by another guest!' % disk), \ - _("Do you really want to use the disk ?")) + if self._disk.type == virtinst.VirtualDisk.TYPE_FILE and \ + self.get_config_method() == VM_PARA_VIRT and \ + virtinst.util.is_blktap_capable(): + self._disk.driver_name = virtinst.VirtualDisk.DRIVER_TAP + + if self._disk.type == virtinst.VirtualDisk.TYPE_FILE and not \ + self.is_sparse_file(): + self.non_sparse = True + else: + self.non_sparse = False + except ValueError, e: + self._validation_error_box(_("Invalid Storage Address"), \ + str(e)) + return False + + if self._disk.is_conflict_disk(self.connection.vmm) is True: + res = self._yes_no_box(_('Disk "%s" is already in use by another guest!' % disk), _("Do you really want to use the disk ?")) return res elif page_num == PAGE_NETWORK: + if self.window.get_widget("net-type-network").get_active(): if self.window.get_widget("net-network").get_active() == -1: self._validation_error_box(_("Virtual Network Required"), @@ -860,29 +859,73 @@ class vmmCreate(gobject.GObject): _("You must select one of the physical devices")) return False + net = self.get_config_network() + if self.window.get_widget("mac-address").get_active(): mac = self.window.get_widget("create-mac-address").get_text() - if len(mac) != 17: + if mac is None or len(mac) == 0: self._validation_error_box(_("Invalid MAC address"), \ - _("MAC adrress must be 17 characters")) + _("No MAC address was entered. Please enter a valid MAC address.")) return False - if re.match("^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$",mac) == None: - self._validation_error_box(_("Invalid MAC address"), \ - _("MAC address must be a form such as AA:BB:CC:DD:EE:FF, and MAC adrress may contain numeric and alphabet of A-F(a-f) and ':' characters only")) + try: + self._guest.mac = mac + except ValueError, e: + self._validation_error_box(_("Invalid Mac address"), \ + str(e)) return False + hostdevs = virtinst.util.get_host_network_devices() for hostdev in hostdevs: if mac.lower() == hostdev[4]: - return self._yes_no_box(_('MAC adress "%s" is already in use by host!' % mac), \ - _("Do you really want to use the MAC address ?")) - vms = [] - for domains in self.connection.vms.values(): - vms.append(domains.vm) - vnic = virtinst.VirtualNetworkInterface(macaddr=mac) - if vnic.countMACaddr(vms) > 0: - return self._yes_no_box(_('MAC adress "%s" is already in use by another guest!' % mac), \ - _("Do you really want to use the MAC address ?")) + return self._yes_no_box(_('MAC address "%s" is already in use by host!' % mac), _("Do you really want to use the MAC address ?")) + else: + mac = None + try: + if net[0] == "bridge": + self._net = virtinst.VirtualNetworkInterface(macaddr=mac, \ + type=net[0], \ + bridge=net[1]) + elif net[0] == "network": + self._net = virtinst.VirtualNetworkInterface(macaddr=mac, \ + type=net[0], \ + network=net[1]) + elif net[0] == "user": + self._net = virtinst.VirtualNetworkInterface(macaddr=mac, \ + type=net[0]) + except ValueError, e: + self._validation_error_box(_("Network Parameter Error"), \ + str(e)) + return False + vms = [] + for domains in self.connection.vms.values(): + vms.append(domains.vm) + if self._net.countMACaddr(vms) > 0: + return self._yes_no_box(_('MAC address "%s" is already in use by another guest!' % mac), _("Do you really want to use the MAC address ?")) + + elif page_num == PAGE_CPUMEM: + + # Set vcpus + try: + self._guest.vcpus = int(self.get_config_virtual_cpus()) + except ValueError, e: + self._validation_error_box(_("VCPU Count Error"), \ + str(e)) + return False + # Set Memory + try: + self._guest.memory = int(self.get_config_initial_memory()) + except ValueError, e: + self._validation_error_box(_("Memory Amount Error"), \ + str(e)) + return False + # Set Max Memory + try: + self._guest.maxmemory = int(self.get_config_maximum_memory()) + except ValueError, e: + self._validation_error_box(_("Max Memory Amount Error"), \ + str(e)) + return False # do this always, since there's no "leaving a notebook page" event. self.window.get_widget("create-back").set_sensitive(True) return True From fafa0d96f62d7262c19234d89951d320fd972fec Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 4 Jul 2007 00:41:25 -0400 Subject: [PATCH 14/15] Make help menu item GNOME HIG compliant (bz 246195) --- src/vmm-console.glade | 17 +++++++++++++++-- src/vmm-details.glade | 17 +++++++++++++++-- src/vmm-manager.glade | 27 ++++++++++++++++++++------- 3 files changed, 50 insertions(+), 11 deletions(-) diff --git a/src/vmm-console.glade b/src/vmm-console.glade index 1fdf65176..c30ef595e 100644 --- a/src/vmm-console.glade +++ b/src/vmm-console.glade @@ -192,9 +192,22 @@ True - gtk-help - True + _Contents + True + + + + + True + gtk-help + 1 + 0.5 + 0.5 + 0 + 0 + + diff --git a/src/vmm-details.glade b/src/vmm-details.glade index f1ca8586b..42a8e7ca6 100644 --- a/src/vmm-details.glade +++ b/src/vmm-details.glade @@ -170,9 +170,22 @@ True - gtk-help - True + _Contents + True + + + + + True + gtk-help + 1 + 0.5 + 0.5 + 0 + 0 + + diff --git a/src/vmm-manager.glade b/src/vmm-manager.glade index 7bb0c0b92..a57d64fa0 100644 --- a/src/vmm-manager.glade +++ b/src/vmm-manager.glade @@ -52,7 +52,7 @@ - + True gtk-new 1 @@ -75,7 +75,7 @@ - + True gtk-open 1 @@ -102,7 +102,7 @@ - + True gtk-connect 1 @@ -169,7 +169,7 @@ - + True gtk-properties 1 @@ -190,7 +190,7 @@ - + True gtk-delete 1 @@ -317,9 +317,22 @@ True - gtk-help - True + _Contents + True + + + + + True + gtk-help + 1 + 0.5 + 0.5 + 0 + 0 + + From e4eac282b4fdd5a34bc6f252b19773a12533c961 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 4 Jul 2007 00:41:39 -0400 Subject: [PATCH 15/15] Make application menu comment GNOME HIG compliant (bz 246195) --- src/virt-manager.desktop.in.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/virt-manager.desktop.in.in b/src/virt-manager.desktop.in.in index 6547a2cd0..8b3905328 100644 --- a/src/virt-manager.desktop.in.in +++ b/src/virt-manager.desktop.in.in @@ -1,6 +1,6 @@ [Desktop Entry] _Name=Virtual Machine Manager -_Comment=The virtual machine management tool +_Comment=Manage virtual machines Icon=::ICONDIR::/::PACKAGE::-icon.svg Exec=::PACKAGE:: Type=Application