
From: CrÃstian Viana <vianac@linux.vnet.ibm.com> Signed-off-by: CrÃstian Viana <vianac@linux.vnet.ibm.com> Signed-off-by: Jose Ricardo Ziviani <joserz@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