[PATCH][Kimchi 1/2] Implements support to memory hotplug in non-NUMA guests

This patch makes necessary changes in Kimchi guest update to support memory hotplug operations in non-numa guests, due to latest Libvirt changes. --- model/utils.py | 18 ++++++++++++++++++ model/vms.py | 53 +++++++++++++++++------------------------------------ 2 files changed, 35 insertions(+), 36 deletions(-) diff --git a/model/utils.py b/model/utils.py index b7ea82e..da62971 100644 --- a/model/utils.py +++ b/model/utils.py @@ -129,3 +129,21 @@ def metadata_exists(dom): if root.find("metadata") is None: return False return True + + +def has_cpu_numa(dom): + """ + Verify if domain has NUMA configuration + Returns: True or False + """ + root = etree.fromstring(dom.XMLDesc(0)) + return (root.find('./cpu/numa') is not None) + + +def set_numa_memory(mem, root): + """ + Set new NUMA memory value + Returns: etree element updated + """ + root.find('./cpu/numa/cell').set('memory', str(mem)) + return root diff --git a/model/vms.py b/model/vms.py index cf40ad1..f88cfdb 100644 --- a/model/vms.py +++ b/model/vms.py @@ -61,9 +61,9 @@ from wok.plugins.kimchi.model.utils import set_metadata_node from wok.plugins.kimchi.screenshot import VMScreenshot from wok.plugins.kimchi.utils import get_next_clone_name from wok.plugins.kimchi.utils import template_name_from_uri -from wok.plugins.kimchi.xmlutils.cpu import get_cpu_xml, get_numa_xml from wok.plugins.kimchi.xmlutils.cpu import get_topology_xml from wok.plugins.kimchi.xmlutils.disk import get_vm_disk_info, get_vm_disks +from utils import has_cpu_numa, set_numa_memory DOM_STATE_MAP = {0: 'nostate', @@ -769,10 +769,10 @@ class VMModel(object): # topology is being undefined: remove it new_xml = xml_item_remove(new_xml, XPATH_TOPOLOGY) - # Updating memory and NUMA if necessary, if vm is offline + # Updating memory if vm is offline if (not dom.isActive() and 'memory' in params and params['memory'] != {}): - new_xml = self._update_memory_config(new_xml, params) + new_xml = self._update_memory_config(new_xml, params, dom) if 'graphics' in params: new_xml = self._update_graphics(dom, new_xml, params) @@ -810,7 +810,7 @@ class VMModel(object): vm_name = name return (nonascii_name if nonascii_name is not None else vm_name, dom) - def _update_memory_config(self, xml, params): + def _update_memory_config(self, xml, params, dom): # Cannot pass max memory if there is not support to memory hotplug # Then set max memory as memory, just to continue with the update if not self.caps.mem_hotplug_support: @@ -905,16 +905,18 @@ class VMModel(object): root.remove(currentMem) memory = root.find('.memory') - # If host/guest does not support memory hot plug, then there is - # NUMA configure, we must update the tag directly - if not self.caps.mem_hotplug_support: - if memory is not None: - memory.text = str(newMem) - else: + # Set NUMA parameterers if necessary. NUMA is not required for CPU + # and Memory hotplug anymore + if has_cpu_numa(dom): if memory is not None: # Libvirt is going to set the value automatically with # the value configured in NUMA tag root.remove(memory) + root = set_numa_memory(newMem, root) + else: + # update the memory tag directly + if memory is not None: + memory.text = str(newMem) if (maxMemTag is not None) and (not hasMaxMem): if newMem == newMaxMem: @@ -922,22 +924,6 @@ class VMModel(object): else: maxMemTag.set('slots', str(_get_slots(newMem, newMaxMem))) - # Set NUMA parameterers and create it if does not exist - # CPU tag DO NOT exist? Create it - cpu = root.find(XPATH_CPU) - if cpu is None: - cpu = get_cpu_xml(0, newMem) - root.insert(0, ET.fromstring(cpu)) - else: - # Does NUMA tag exist ? - numaTag = cpu.find('./numa') - if numaTag is None: - numa_element = get_numa_xml(0, newMem) - cpu.insert(0, ET.fromstring(numa_element)) - else: - cellTag = cpu.find('./numa/cell') - cellTag.set('memory', str(newMem)) - # Setting memory hard limit to max_memory + 1GiB memtune = root.find('memtune') if memtune is not None: @@ -990,12 +976,9 @@ class VMModel(object): if not self.caps.mem_hotplug_support: raise InvalidOperation("KCHVM0046E") - # Check if the vm xml supports memory hotplug, if not, static update - # must be done firstly, then Kimchi is going to update the xml xml = dom.XMLDesc(0) - numa_mem = xpath_get_text(xml, XPATH_NUMA_CELL + '/@memory') max_mem = xpath_get_text(xml, './maxMemory') - if numa_mem == [] or max_mem == []: + if max_mem == []: raise OperationFailed('KCHVM0042E', {'name': dom.name()}) # Memory live update must be done in chunks of 1024 Mib or 1Gib @@ -1038,12 +1021,10 @@ class VMModel(object): # Hot add given number of memory devices in the guest flags = libvirt.VIR_DOMAIN_MEM_CONFIG | libvirt.VIR_DOMAIN_MEM_LIVE # Create memory device xml - mem_dev_xml = etree.tostring( - E.memory( - E.target( - E.size('1', unit='GiB'), - E.node('0')), - model='dimm')) + tmp_xml = E.memory(E.target(E.size('1', unit='GiB')), model='dimm') + if has_cpu_numa(dom): + tmp_xml.find('target').append(E.node('0')) + mem_dev_xml = etree.tostring(tmp_xml) # Add chunks of 1G of memory for i in range(amount): dom.attachDeviceFlags(mem_dev_xml, flags) -- 2.1.0

THis patch adds a test to check memory hotplug in non-NUMA guests running in PowerPC. Only PowerPC supports hotplug in guest without NUMA configuration: https://libvirt.org/news-2015.html Commit: qemu: ppc64: Support memory hotplug without NUMA enabled (Peter Krempa) Signed-off-by: Rodrigo Trujillo <rodrigo.trujillo@linux.vnet.ibm.com> --- tests/test_model.py | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/tests/test_model.py b/tests/test_model.py index c89c269..737b39c 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -54,6 +54,19 @@ invalid_repository_urls = ['www.fedora.org', # missing protocol TMP_DIR = '/var/lib/kimchi/tests/' UBUNTU_ISO = TMP_DIR + 'ubuntu14.04.iso' +NON_NUMA_XML = """ +<domain type='kvm'> + <name>non-numa-kimchi-test</name> + <maxMemory slots='2' unit='GiB'>4</maxMemory> + <memory unit='GiB'>2</memory> + <os> + <type arch='ppc64'>hvm</type> + <boot dev='hd'/> + </os> + <features> + <acpi/> + </features> +</domain>""" def setUpModule(): @@ -821,6 +834,38 @@ class ModelTests(unittest.TestCase): self.assertRaises(InvalidOperation, inst.vm_update, 'kimchi-vm1', params) + msg = "Memory hotplug in non-numa guests only for PowerPC arch." + + @unittest.skipUnless(('ppc64' in os.uname()[4]), msg) + def test_non_numa_vm_memory_hotplug(self): + config.set("authentication", "method", "pam") + inst = model.Model(None, objstore_loc=self.tmp_store) + conn = inst.conn.get() + vm = 'non-numa-kimchi-test' + + with RollbackContext() as rollback: + conn.defineXML(NON_NUMA_XML) + rollback.prependDefer(conn.lookupByName(vm).undefine) + + # Start vm + inst.vm_start(vm) + + # Hotplug memory + params = {'memory': {'current': 3072}} + inst.vm_update(vm, params) + self.assertEquals(params['memory']['current'], + inst.vm_lookup(vm)['memory']['current']) + + params = {'memory': {'current': 4096}} + inst.vm_update(vm, params) + self.assertEquals(params['memory']['current'], + inst.vm_lookup(vm)['memory']['current']) + + # Stop vm and test persistence + inst.vm_poweroff(vm) + self.assertEquals(params['memory']['current'], + inst.vm_lookup(vm)['memory']['current']) + def test_vm_edit(self): config.set("authentication", "method", "pam") inst = model.Model(None, -- 2.1.0
participants (2)
-
Aline Manera
-
Rodrigo Trujillo