[Kimchi-devel] [PATCH v3 5/5] Hot add/remove CPUs on PPC

Jose Ricardo Ziviani joserz at linux.vnet.ibm.com
Wed Sep 16 18:51:52 UTC 2015


From: Crístian Viana <vianac at linux.vnet.ibm.com>

Signed-off-by: Crístian Viana <vianac at linux.vnet.ibm.com>
Signed-off-by: Jose Ricardo Ziviani <joserz at linux.vnet.ibm.com>
---
 src/kimchi/i18n.py      |  3 +++
 src/kimchi/model/vms.py | 71 ++++++++++++++++++++++++++++++++++++++++---------
 2 files changed, 62 insertions(+), 12 deletions(-)

diff --git a/src/kimchi/i18n.py b/src/kimchi/i18n.py
index 5efeabe..ecc10ff 100644
--- a/src/kimchi/i18n.py
+++ b/src/kimchi/i18n.py
@@ -124,6 +124,9 @@ messages = {
     "KCHVM0051E": _("Cannot reset %(name)s. Virtual machine is already shut off."),
     "KCHVM0052E": _("Unable to update the following parameters while the VM is offline: %(params)s"),
     "KCHVM0053E": _("Unable to update the following parameters while the VM is online: %(params)s"),
+    "KCHVM0054E": _("VM '%(vm)s' cannot have more than %(cpus)d CPUs. Please update the CPU value when the VM is not running."),
+    "KCHVM0055E": _("VM '%(vm)s' cannot have less than %(cpus)d CPUs. Please update the CPU value when the VM is not running."),
+    "KCHVM0056E": _("Unable to hotplug CPUs. Details: %(err)s"),
 
     "KCHVMHDEV0001E": _("VM %(vmid)s does not contain directly assigned host device %(dev_name)s."),
     "KCHVMHDEV0002E": _("The host device %(dev_name)s is not allowed to directly assign to VM."),
diff --git a/src/kimchi/model/vms.py b/src/kimchi/model/vms.py
index f4d15af..3ea8903 100644
--- a/src/kimchi/model/vms.py
+++ b/src/kimchi/model/vms.py
@@ -81,6 +81,7 @@ XPATH_DOMAIN_MAC_BY_ADDRESS = "./devices/interface[@type='network']/"\
 XPATH_DOMAIN_MEMORY = '/domain/memory'
 XPATH_DOMAIN_MEMORY_UNIT = '/domain/memory/@unit'
 XPATH_DOMAIN_UUID = '/domain/uuid'
+XPATH_DOMAIN_DEV_CPU_ID = '/domain/devices/spapr-cpu-socket/@id'
 
 XPATH_NUMA_CELL = './cpu/numa/cell'
 
@@ -832,17 +833,61 @@ class VMModel(object):
         if 'cpus' in params:
             cpus = params['cpus']
 
-            try:
-                # set maximum VCPU count
-                max_vcpus = self.conn.get().getMaxVcpus('kvm')
-                dom.setVcpusFlags(max_vcpus, 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})
+            if DOM_STATE_MAP[dom.info()[0]] == 'shutoff':
+                try:
+                    # set maximum VCPU count
+                    max_vcpus = self.conn.get().getMaxVcpus('kvm')
+                    dom.setVcpusFlags(max_vcpus,
+                                      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})
+            else:
+                try:
+                    dev_cpu_ids = xpath_get_text(dom.XMLDesc(0),
+                                                 XPATH_DOMAIN_DEV_CPU_ID)
+                    vcpu_count = dom.vcpus(libvirt.VIR_DOMAIN_AFFECT_LIVE)
+                    total_cpu_count = vcpu_count + len(dev_cpu_ids)
+                    new_cpu_count = int(params['cpus'])
+                    max_cpu_count = dom.maxVcpus()
+
+                    if new_cpu_count > total_cpu_count:  # add CPUs
+                        if new_cpu_count > max_cpu_count:
+                            raise InvalidOperation('KCHVM0054E',
+                                                   {'cpus': max_cpu_count})
+
+                        if len(dev_cpu_ids) == 0:
+                            # there are no CPU devices yet; start from 0
+                            dev_id = 0
+                        else:
+                            # there are some CPU devices;
+                            # start from the last ID + 1
+                            dev_cpu_ids.sort()
+                            dev_id = int(dev_cpu_ids[-1]) + 1
+
+                        for i in xrange(new_cpu_count - total_cpu_count):
+                            xml = E('spapr-cpu-socket', id=str(dev_id))
+                            dom.attachDevice(etree.tostring(xml))
+                            dev_id += 1
+                    elif new_cpu_count < total_cpu_count:  # remove CPUs
+                        if new_cpu_count < vcpu_count:
+                            raise InvalidOperation('KCHVM0055E',
+                                                   {'cpus': vcpu_count})
+
+                        # the CPU IDs must be removed in descending order
+                        dev_cpu_ids.sort(reverse=True)
+                        last_id_idx = total_cpu_count - new_cpu_count
+                        to_remove = dev_cpu_ids[:last_id_idx]
+
+                        for dev_id in to_remove:
+                            xml = E('spapr-cpu-socket', id=dev_id)
+                            dom.detachDevice(etree.tostring(xml))
+                except (libvirt.libvirtError, ValueError), e:
+                    raise OperationFailed('KCHVM0056E', {'err': e.message})
 
     def _update_memory_live(self, dom, params):
         # Check if host supports memory device
@@ -1042,12 +1087,14 @@ class VMModel(object):
         else:
             memory = info[2] >> 10
 
+        cpu_devs = xpath_get_text(dom.XMLDesc(0), XPATH_DOMAIN_DEV_CPU_ID)
+
         return {'name': name,
                 'state': state,
                 'stats': res,
                 'uuid': dom.UUIDString(),
                 'memory': memory,
-                'cpus': info[3],
+                'cpus': info[3] + len(cpu_devs),
                 'screenshot': screenshot,
                 'icon': icon,
                 # (type, listen, port, passwd, passwdValidTo)
-- 
1.9.1




More information about the Kimchi-devel mailing list