Only in old/src/virtManager: create.py.orig Only in old/src/virtManager: delete.py.orig diff -rup old/src/virtManager/details.py virt-manager-0.7.0/src/virtManager/details.py --- old/src/virtManager/details.py 2009-09-17 17:31:58.267831000 -0400 +++ virt-manager-0.7.0/src/virtManager/details.py 2009-09-17 17:45:36.638881000 -0400 @@ -1502,7 +1502,27 @@ class vmmDetails(gobject.GObject): def config_vcpus_apply(self, src): vcpus = self.window.get_widget("config-vcpus").get_adjustment().value logging.info("Setting vcpus for " + self.vm.get_uuid() + " to " + str(vcpus)) - self.vm.set_vcpu_count(vcpus) + hotplug_err = False + + try: + if self.vm.is_active(): + self.vm.hotplug_vcpus(vcpus) + except Exception, e: + logging.debug("VCPU hotplug failed: %s" % str(e)) + hotplug_err = True + + # Change persistent config + try: + self.vm.define_vcpus(vcpus) + except Exception, e: + self.err.show_err(_("Error changing vcpu value: %s" % str(e)), + "".join(traceback.format_exc())) + return False + + if hotplug_err: + self.err.show_info(_("These changes will take effect after the " + "next guest reboot. ")) + self.window.get_widget("config-vcpus-apply").set_sensitive(False) def config_get_maxmem(self): @@ -1538,44 +1558,38 @@ class vmmDetails(gobject.GObject): def config_memory_apply(self, src): self.refresh_config_memory() - exc = None + hotplug_err = False + curmem = None maxmem = self.config_get_maxmem() if self.window.get_widget("config-memory").get_property("sensitive"): curmem = self.config_get_memory() - logging.info("Setting max-memory for " + self.vm.get_name() + - " to " + str(maxmem)) - - actual_cur = self.vm.get_memory() - if curmem is not None: - logging.info("Setting memory for " + self.vm.get_name() + - " to " + str(curmem)) - if (maxmem * 1024) < actual_cur: - # Set current first to avoid error - try: - self.vm.set_memory(curmem * 1024) - self.vm.set_max_memory(maxmem * 1024) - except Exception, e: - exc = e - else: - try: - self.vm.set_max_memory(maxmem * 1024) - self.vm.set_memory(curmem * 1024) - except Exception, e: - exc = e + if curmem: + curmem = int(curmem) * 1024 + if maxmem: + maxmem = int(maxmem) * 1024 - else: - try: - self.vm.set_max_memory(maxmem * 1024) - except Exception, e: - exc = e + try: + if self.vm.is_active(): + self.vm.hotplug_both_mem(curmem, maxmem) + except Exception, e: + logging.debug("Memory hotplug failed: %s" % str(e)) + hotplug_err = True - if exc: + # Change persistent config + try: + self.vm.define_both_mem(curmem, maxmem) + except Exception, e: self.err.show_err(_("Error changing memory values: %s" % str(e)), "".join(traceback.format_exc())) - else: - self.window.get_widget("config-memory-apply").set_sensitive(False) + return + + if hotplug_err: + self.err.show_info(_("These changes will take effect after the " + "next guest reboot. ")) + + self.window.get_widget("config-memory-apply").set_sensitive(False) def config_boot_options_changed(self, src): self.window.get_widget("config-boot-options-apply").set_sensitive(True) Only in old/src/virtManager: details.py.orig diff -rup old/src/virtManager/domain.py virt-manager-0.7.0/src/virtManager/domain.py --- old/src/virtManager/domain.py 2009-09-17 17:31:58.276831000 -0400 +++ virt-manager-0.7.0/src/virtManager/domain.py 2009-09-17 17:47:15.693255000 -0400 @@ -23,6 +23,7 @@ import libvirt import libxml2 import os import logging +import difflib from virtManager import util import virtinst.util as vutil @@ -113,6 +114,16 @@ class vmmDomain(gobject.GObject): self.refresh_inactive_xml() return self._orig_inactive_xml + def get_xml_to_define(self): + # FIXME: This isn't sufficient, since we pull stuff like disk targets + # from the active XML. This all needs proper fixing in the long + # term. + if self.is_active(): + return self.get_inactive_xml() + else: + self.update_xml() + return self.get_xml() + def refresh_inactive_xml(self): flags = (libvirt.VIR_DOMAIN_XML_INACTIVE | libvirt.VIR_DOMAIN_XML_SECURE) @@ -124,6 +135,36 @@ class vmmDomain(gobject.GObject): self._orig_inactive_xml = self.vm.XMLDesc(flags) + def redefine(self, xml_func, *args): + """ + Helper function for altering a redefining VM xml + + @param xml_func: Function to alter the running XML. Takes the + original XML as its first argument. + @param args: Extra arguments to pass to xml_func + """ + origxml = self.get_xml_to_define() + # Sanitize origxml to be similar to what we will get back + origxml = util.xml_parse_wrapper(origxml, lambda d, c: d.serialize()) + + newxml = xml_func(origxml, *args) + + if origxml == newxml: + logging.debug("Redefinition requested, but new xml was not" + " different") + return + + diff = "".join(difflib.unified_diff(origxml.splitlines(1), + newxml.splitlines(1), + fromfile="Original XML", + tofile="New XML")) + logging.debug("Redefining '%s' with XML diff:\n%s", + self.get_name(), diff) + self.get_connection().define_domain(newxml) + + # Invalidate cached XML + self.invalidate_xml() + def release_handle(self): del(self.vm) self.vm = None @@ -1126,16 +1167,6 @@ class vmmDomain(gobject.GObject): if doc != None: doc.freeDoc() - def get_xml_to_define(self): - # FIXME: This isn't sufficient, since we pull stuff like disk targets - # from the active XML. This all needs proper fixing in the long - # term. - if self.is_active(): - return self.get_inactive_xml() - else: - self.update_xml() - return self.get_xml() - def attach_device(self, xml): """Hotplug device to running guest""" if self.is_active(): @@ -1232,23 +1263,80 @@ class vmmDomain(gobject.GObject): doc.freeDoc() self._change_cdrom(result, dev_id_info) - def set_vcpu_count(self, vcpus): + def hotplug_vcpu(self, vcpus): + self.vm.setVcpus() + + def hotplug_vcpus(self, vcpus): vcpus = int(vcpus) - self.vm.setVcpus(vcpus) + if vcpus != self.vcpu_count(): + self.vm.setVcpus(vcpus) + + def define_vcpus(self, vcpus): + vcpus = int(vcpus) + + def set_node(doc, ctx, val, xpath): + node = ctx.xpathEval(xpath) + node = (node and node[0] or None) + + if node: + node.setContent(str(val)) + return doc.serialize() + + def change_vcpu_xml(xml, vcpus): + return util.xml_parse_wrapper(xml, set_node, vcpus, + "/domain/vcpu[1]") + + self.redefine(change_vcpu_xml, vcpus) + + def hotplug_memory(self, memory): + if memory != self.get_memory(): + self.vm.setMemory(memory) + + def hotplug_maxmem(self, maxmem): + if maxmem != self.maximum_memory(): + self.vm.setMaxMemory(maxmem) + + def hotplug_both_mem(self, memory, maxmem): + logging.info("Hotplugging curmem=%s maxmem=%s for VM '%s'" % + (memory, maxmem, self.get_name())) + + if self.is_active(): + actual_cur = self.get_memory() + if memory: + if maxmem < actual_cur: + # Set current first to avoid error + self.hotplug_memory(memory) + self.hotplug_maxmem(maxmem) + else: + self.hotplug_maxmem(maxmem) + self.hotplug_memory(memory) + else: + self.hotplug_maxmem(maxmem) + + def define_both_mem(self, memory, maxmem): + # Make sure we correctly define the XML with new values, since + # setMem and setMaxMem don't (or, aren't supposed to) affect + # the persistent config + self.invalidate_xml() + + def set_mem_node(doc, ctx, memval, xpath): + node = ctx.xpathEval(xpath) + node = (node and node[0] or None) + + if node: + node.setContent(str(memval)) + return doc.serialize() + + def change_mem_xml(xml, memory, maxmem): + if memory: + xml = util.xml_parse_wrapper(xml, set_mem_node, memory, + "/domain/currentMemory[1]") + if maxmem: + xml = util.xml_parse_wrapper(xml, set_mem_node, maxmem, + "/domain/memory[1]") + return xml - def set_memory(self, memory): - memory = int(memory) - # capture updated information due to failing to get proper maxmem setting - # if both current & max allocation are set simultaneously - maxmem = self.vm.info() - if (memory > maxmem[1]): - logging.warning("Requested memory " + str(memory) + " over maximum " + str(self.maximum_memory())) - memory = self.maximum_memory() - self.vm.setMemory(memory) - - def set_max_memory(self, memory): - memory = int(memory) - self.vm.setMaxMemory(memory) + self.redefine(change_mem_xml, memory, maxmem) def get_autostart(self): return self.vm.autostart() Only in old/src/virtManager: domain.py.orig diff -rup old/src/virtManager/util.py virt-manager-0.7.0/src/virtManager/util.py --- old/src/virtManager/util.py 2009-09-17 17:52:15.948670000 -0400 +++ virt-manager-0.7.0/src/virtManager/util.py 2009-09-17 17:52:58.963375000 -0400 @@ -140,3 +140,23 @@ def dup_conn(config, conn, libconn=None) newconn.connectThreadEvent.wait() return newconn.vmm + +def xml_parse_wrapper(xml, parse_func, *args, **kwargs): + """ + Parse the passed xml string into an xpath context, which is passed + to parse_func, along with any extra arguments. + """ + + doc = None + ctx = None + ret = None + try: + doc = libxml2.parseDoc(xml) + ctx = doc.xpathNewContext() + ret = parse_func(doc, ctx, *args, **kwargs) + finally: + if ctx != None: + ctx.xpathFreeContext() + if doc != None: + doc.freeDoc() + return ret diff -rup old/src/virtManager/util.py virt-manager-0.7.0/src/virtManager/util.py --- old/src/virtManager/util.py 2009-09-17 17:55:17.930744000 -0400 +++ virt-manager-0.7.0/src/virtManager/util.py 2009-09-17 17:55:31.355655000 -0400 @@ -21,6 +21,7 @@ import logging import gtk +import libxml2 import libvirt import virtManager