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