[Kimchi-devel] [PATCH 2/4] Update VCPU by using libvirt function

Crístian Deives cristiandeives at gmail.com
Mon Jun 29 17:21:22 UTC 2015


Currently, the VCPU count is updated by editing the configuration XML
(tag: <vcpu>). However, in some cases, editing that tag will only update
the maximum VCPU count, not the current one. For example, if the VM has
the following XML tag:

  <vcpu current='2'>8</vcpu>

and the user updates the VCPU value to 10, Kimchi will update the XML
tag to:

  <vcpu current='2'>10</vcpu>

which is probably not what the user wanted.

Use the libvirt function "setVcpusFlags" to update the current and the
maximum VCPU values to the one specified by the user.

Signed-off-by: Aline Manera <alinefm at linux.vnet.ibm.com>
Signed-off-by: Crístian Deives <cristiandeives at gmail.com>
---
 src/kimchi/mockmodel.py | 48 ++++++++++++++++++------------------------------
 src/kimchi/model/vms.py | 23 ++++++++++++++++++-----
 2 files changed, 36 insertions(+), 35 deletions(-)

diff --git a/src/kimchi/mockmodel.py b/src/kimchi/mockmodel.py
index aaf1af2..91278bd 100644
--- a/src/kimchi/mockmodel.py
+++ b/src/kimchi/mockmodel.py
@@ -25,6 +25,7 @@ import time
 
 import kimchi.model.cpuinfo
 
+from collections import defaultdict
 from lxml import objectify
 from lxml.builder import E
 
@@ -54,10 +55,9 @@ mockmodel_defaults = {'storagepool': '/storagepools/default-pool',
 
 
 class MockModel(Model):
-    _mock_vms = {}
+    _mock_vms = defaultdict(list)
     _mock_snapshots = {}
     _XMLDesc = libvirt.virDomain.XMLDesc
-    _defineXML = libvirt.virConnect.defineXML
     _undefineDomain = libvirt.virDomain.undefine
     _libvirt_get_vol_path = LibvirtVMTemplate._get_volume_path
 
@@ -76,7 +76,6 @@ class MockModel(Model):
 
         kimchi.model.cpuinfo.get_topo_capabilities = \
             MockModel.get_topo_capabilities
-        libvirt.virConnect.defineXML = MockModel.domainDefineXML
         libvirt.virDomain.XMLDesc = MockModel.domainXMLDesc
         libvirt.virDomain.undefine = MockModel.undefineDomain
         libvirt.virDomain.attachDeviceFlags = MockModel.attachDeviceFlags
@@ -119,7 +118,7 @@ class MockModel(Model):
         imageinfo.probe_image = self._probe_image
 
     def reset(self):
-        MockModel._mock_vms = {}
+        MockModel._mock_vms = defaultdict(list)
         MockModel._mock_snapshots = {}
         self._mock_swupdate = MockSoftwareUpdate()
         self._mock_repositories = MockRepositories()
@@ -154,21 +153,15 @@ class MockModel(Model):
         return ET.fromstring(xml)
 
     @staticmethod
-    def domainDefineXML(conn, xml):
-        name = objectify.fromstring(xml).name.text
-        try:
-            dom = conn.lookupByName(name)
-            if not dom.isActive():
-                MockModel._mock_vms[name] = xml
-        except:
-            pass
+    def domainXMLDesc(dom, flags=0):
+        xml = MockModel._XMLDesc(dom, flags)
+        root = objectify.fromstring(xml)
 
-        return MockModel._defineXML(conn, xml)
+        for dev_xml in MockModel._mock_vms.get(dom.name(), []):
+            dev = objectify.fromstring(dev_xml)
+            root.devices.append(dev)
 
-    @staticmethod
-    def domainXMLDesc(dom, flags=0):
-        return MockModel._mock_vms.get(dom.name(),
-                                       MockModel._XMLDesc(dom, flags))
+        return ET.tostring(root, encoding="utf-8")
 
     @staticmethod
     def undefineDomain(dom):
@@ -179,12 +172,7 @@ class MockModel(Model):
 
     @staticmethod
     def attachDeviceFlags(dom, xml, flags=0):
-        old_xml = dom.XMLDesc(libvirt.VIR_DOMAIN_XML_SECURE)
-        root = objectify.fromstring(old_xml)
-        dev = objectify.fromstring(xml)
-        root.devices.append(dev)
-
-        MockModel._mock_vms[dom.name()] = ET.tostring(root, encoding="utf-8")
+        MockModel._mock_vms[dom.name()].append(xml)
 
     @staticmethod
     def _get_device_node(dom, xml):
@@ -210,16 +198,16 @@ class MockModel(Model):
 
     @staticmethod
     def detachDeviceFlags(dom, xml, flags=0):
-        root, dev = MockModel._get_device_node(dom, xml)
-        root.devices.remove(dev)
-
-        MockModel._mock_vms[dom.name()] = ET.tostring(root, encoding="utf-8")
+        if xml in MockModel._mock_vms[dom.name()]:
+            MockModel._mock_vms[dom.name()].remove(xml)
 
     @staticmethod
     def updateDeviceFlags(dom, xml, flags=0):
-        root, old_dev = MockModel._get_device_node(dom, xml)
-        root.devices.replace(old_dev, objectify.fromstring(xml))
-        MockModel._mock_vms[dom.name()] = ET.tostring(root, encoding="utf-8")
+        _, old_dev = MockModel._get_device_node(dom, xml)
+        old_xml = ET.tostring(old_dev, encoding="utf-8")
+        if old_xml in MockModel._mock_vms[dom.name()]:
+            MockModel._mock_vms[dom.name()].remove(old_xml)
+        MockModel._mock_vms[dom.name()].append(xml)
 
     @staticmethod
     def volResize(vol, size, flags=0):
diff --git a/src/kimchi/model/vms.py b/src/kimchi/model/vms.py
index e3819dc..c9ed5f6 100644
--- a/src/kimchi/model/vms.py
+++ b/src/kimchi/model/vms.py
@@ -60,8 +60,8 @@ DOM_STATE_MAP = {0: 'nostate',
                  6: 'crashed',
                  7: 'pmsuspended'}
 
-VM_STATIC_UPDATE_PARAMS = {'name': './name',
-                           'cpus': './vcpu'}
+VM_STATIC_UPDATE_PARAMS = {'name': './name'}
+
 VM_LIVE_UPDATE_PARAMS = {}
 
 XPATH_DOMAIN_DISK = "/domain/devices/disk[@device='disk']/source/@file"
@@ -207,8 +207,8 @@ class VMModel(object):
 
         with lock:
             dom = self.get_vm(name, self.conn)
-            dom = self._static_vm_update(dom, params)
             self._live_vm_update(dom, params)
+            dom = self._static_vm_update(dom, params)
             return dom.name().decode('utf-8')
 
     def clone(self, name):
@@ -731,8 +731,7 @@ class VMModel(object):
         vcpus = params.get('cpus')
         if numa_mem == []:
             if vcpus is None:
-                vcpus = int(xpath_get_text(xml,
-                                           VM_STATIC_UPDATE_PARAMS['cpus'])[0])
+                vcpus = int(xpath_get_text(xml, 'vcpu')[0])
             cpu = root.find('./cpu')
             if cpu is None:
                 cpu = get_cpu_xml(vcpus, params['memory'] << 10)
@@ -793,6 +792,20 @@ class VMModel(object):
         if 'memory' in params and dom.isActive():
             self._update_memory_live(dom, params)
 
+        if 'cpus' in params:
+            cpus = params['cpus']
+
+            try:
+                # set maximum VCPU count
+                dom.setVcpusFlags(cpus, libvirt.VIR_DOMAIN_AFFECT_CONFIG |
+                                  libvirt.VIR_DOMAIN_VCPU_MAXIMUM)
+
+                # set current VCPU count
+                dom.setVcpusFlags(cpus, libvirt.VIR_DOMAIN_AFFECT_CONFIG)
+            except libvirt.libvirtError, e:
+                raise OperationFailed('KCHVM0008E', {'name': dom.name(),
+                                                     'err': e.message})
+
     def _update_memory_live(self, dom, params):
         # Check if host supports memory device
         if not self.caps.mem_hotplug_support:
-- 
2.4.3




More information about the Kimchi-devel mailing list