Signed-off-by: juergen.gross@xxxxxxxxxxxxxx diff -r dbf0fd95180f tools/python/xen/xend/XendCPUPool.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/python/xen/xend/XendCPUPool.py Fri Apr 23 12:56:25 2010 +0200 @@ -0,0 +1,905 @@ +#============================================================================ +# This library is free software; you can redistribute it and/or +# modify it under the terms of version 2.1 of the GNU Lesser General Public +# License as published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#============================================================================ +# Copyright (c) 2009 Fujitsu Technology Solutions. +#============================================================================ + +""" CPU Pool support including XEN-API and Legacy API. +""" + +import types +import threading +import re +import xen.lowlevel.xc +import XendNode +import XendDomain +from xen.xend.XendLogging import log +from xen.xend.XendBase import XendBase +from xen.xend import XendAPIStore +from xen.xend.XendConstants import XS_POOLROOT +from xen.xend import uuid as genuuid +from xen.xend.XendError import VmError, XendAPIError, PoolError +from xen.xend.xenstore.xstransact import xstransact +from xen.util.sxputils import sxp2map, map2sxp + + +XEND_ERROR_INTERNAL = 'INTERNAL_ERROR' +XEND_ERROR_UNKOWN_SCHED_POLICY = 'UNKOWN_SCHED_POLICY' +XEND_ERROR_BAD_POOL_STATE = 'POOL_BAD_STATE' +XEND_ERROR_POOL_PARAM = 'PARAMETER_ERROR' +XEND_ERROR_INSUFFICIENT_CPUS = 'INSUFFICIENT_CPUS' +XEND_ERROR_POOL_RECONF = 'POOL_RECONF' +XEND_ERROR_INVALID_CPU = 'INVAILD_CPU' +XEND_ERROR_LAST_CPU_NOT_REM = 'LAST_CPU_NOT_REMOVEABLE' + + +XEN_SCHEDULER_TO_ID = { + 'credit2': xen.lowlevel.xc.XEN_SCHEDULER_CREDIT2, + 'credit' : xen.lowlevel.xc.XEN_SCHEDULER_CREDIT, + 'sedf' : xen.lowlevel.xc.XEN_SCHEDULER_SEDF, + } + +xc = xen.lowlevel.xc.xc() + +class XendCPUPool(XendBase): + """ CPU Pool management. + @ivar pool_lock: Lock to secure modification of pool data + @type pool_lock: Rlock + """ + + pool_lock = threading.RLock() + + def getClass(cls): + return "cpu_pool" + + def getAttrRO(cls): + attrRO = ['resident_on', + 'started_VMs', + 'host_CPUs', + 'activated', + ] + return XendBase.getAttrRO() + attrRO + + def getAttrRW(cls): + attrRW = ['name_label', + 'name_description', + 'auto_power_on', + 'ncpu', + 'sched_policy', + 'proposed_CPUs', + 'other_config', + ] + return XendBase.getAttrRW() + attrRW + + def getMethods(cls): + methods = ['destroy', + 'activate', + 'deactivate', + 'add_host_CPU_live', + 'remove_host_CPU_live', + 'add_to_proposed_CPUs', + 'remove_from_proposed_CPUs', + 'add_to_other_config', + 'remove_from_other_config', + ] + return XendBase.getMethods() + methods + + def getFuncs(cls): + funcs = ['create', + 'get_by_name_label', + ] + return XendBase.getFuncs() + funcs + + getClass = classmethod(getClass) + getAttrRO = classmethod(getAttrRO) + getAttrRW = classmethod(getAttrRW) + getMethods = classmethod(getMethods) + getFuncs = classmethod(getFuncs) + + + # + # XenAPI function calls + # + + def create(cls, record): + """ Create a new managed pool instance. + @param record: attributes of pool + @type record: dict + @return: uuid of created pool + @rtype: str + """ + new_uuid = genuuid.createString() + XendCPUPool(record, new_uuid) + XendNode.instance().save_cpu_pools() + return new_uuid + + create = classmethod(create) + + + def get_by_name_label(cls, name_label): + """ Query a Pool(ref) by its name. + @return: ref of pool + @rtype: str + """ + cls.pool_lock.acquire() + try: + return [ inst.get_uuid() + for inst in XendAPIStore.get_all(cls.getClass()) + if inst.name_label == name_label + ] + finally: + cls.pool_lock.release() + + get_by_name_label = classmethod(get_by_name_label) + + + def get_cpu_pool_by_cpu_ref(cls, host_cpu): + """ Query cpu_pool ref the given cpu belongs to. + @param host_cpu: ref of host_cpu to lookup + @type host_cpu: str + @return: list cpu_pool refs (list contains not more than one element) + @rtype: list of str + """ + node = XendNode.instance() + cpu_nr = node.get_host_cpu_field(host_cpu, 'number') + for pool_rec in xc.cpupool_getinfo(): + if cpu_nr in pool_rec['cpulist']: + # pool found; return the ref + return cls.query_pool_ref(pool_rec['cpupool']) + return [] + + get_cpu_pool_by_cpu_ref = classmethod(get_cpu_pool_by_cpu_ref) + + + def get_all_managed(cls): + """ Query all managed pools. + @return: uuids of all managed pools + @rtype: list of str + """ + cls.pool_lock.acquire() + try: + managed_pools = [ inst.get_uuid() + for inst in XendAPIStore.get_all(cls.getClass()) + if inst.is_managed() ] + finally: + cls.pool_lock.release() + return managed_pools + + get_all_managed = classmethod(get_all_managed) + + + # + # XenAPI methods calls + # + + def __init__(self, record, new_uuid, managed_pool=True): + XendBase.__init__(self, new_uuid, record) + try: + self._managed = managed_pool + self.name_label = None + + name = record.get('name_label', 'Pool-Unnamed') + self._checkName(name) + self.name_label = name + self.name_description = record.get('name_description', + self.name_label) + self.proposed_cpus = [ int(cpu) + for cpu in record.get('proposed_CPUs', []) ] + self.auto_power_on = bool(record.get('auto_power_on', False)) + self.ncpu = int(record.get('ncpu', 1)) + self.sched_policy = record.get('sched_policy', '') + self.other_config = record.get('other_config', {}) + except Exception, ex: + XendBase.destroy(self) + raise ex + + + def get_resident_on(self): + """ Always return uuid of own node. + @return: uuid of this node + @rytpe: str + """ + return XendNode.instance().uuid + + def get_started_VMs(self): + """ Query all VMs currently assigned to pool. + @return: ref of all VMs assigned to pool; if pool is not active, + an empty list will be returned + @rtype: list of str + """ + if self.get_activated(): + # search VMs related to this pool + pool_id = self.query_pool_id() + started_VMs = [ vm.get_uuid() + for vm in XendDomain.instance().list('all') + if vm.get_cpu_pool() == pool_id ] + else: + # pool not active, so it couldn't have any started VMs + started_VMs = [] + + return started_VMs + + def get_host_CPUs(self): + """ Query all cpu refs of this pool currently asisgned . + - Read pool id of this pool from xenstore + - Read cpu configuration from hypervisor + - lookup cpu number -> cpu ref + @return: host_cpu refs + @rtype: list of str + """ + if self.get_activated(): + node = XendNode.instance() + pool_id = self.query_pool_id() + if pool_id == None: + raise PoolError(XEND_ERROR_INTERNAL, + [self.getClass(), 'get_host_CPUs']) + cpus = [] + for pool_rec in xc.cpupool_getinfo(): + if pool_rec['cpupool'] == pool_id: + cpus = pool_rec['cpulist'] + + # query host_cpu ref for any cpu of the pool + host_CPUs = [ cpu_ref + for cpu_ref in node.get_host_cpu_refs() + if node.get_host_cpu_field(cpu_ref, 'number') + in cpus ] + else: + # pool not active, so it couldn't have any assigned cpus + host_CPUs = [] + + return host_CPUs + + def get_activated(self): + """ Query if the pool is registered in XendStore. + If pool uuid is not in XenStore, the pool is not activated. + @return: True, if activated + @rtype: bool + """ + return self.query_pool_id() != None + + def get_name_label(self): + return self.name_label + + def get_name_description(self): + return self.name_description + + def get_auto_power_on(self): + return self.auto_power_on + + def get_ncpu(self): + return self.ncpu + + def get_sched_policy(self): + if len(self.sched_policy) == 0: + # default scheduler selected + return XendNode.instance().get_vcpus_policy() + else: + return self.sched_policy + + def get_proposed_CPUs(self): + return [ str(cpu) for cpu in self.proposed_cpus ] + + def get_other_config(self): + return self.other_config + + def set_name_label(self, name_label): + self._checkName(name_label) + self.name_label = name_label + if self._managed: + XendNode.instance().save_cpu_pools() + + def set_name_description(self, name_descr): + self.name_description = name_descr + if self._managed: + XendNode.instance().save_cpu_pools() + + def set_auto_power_on(self, auto_power_on): + self.auto_power_on = bool(int(auto_power_on)) + if self._managed: + XendNode.instance().save_cpu_pools() + + def set_ncpu(self, ncpu): + _ncpu = int(ncpu) + if _ncpu < 1: + raise PoolError(XEND_ERROR_POOL_PARAM, 'ncpu') + self.ncpu = _ncpu + if self._managed: + XendNode.instance().save_cpu_pools() + + def set_sched_policy(self, sched_policy): + if self.get_activated(): + raise PoolError(XEND_ERROR_BAD_POOL_STATE, 'activated') + self.sched_policy = sched_policy + if self._managed: + XendNode.instance().save_cpu_pools() + + def set_proposed_CPUs(self, proposed_cpus): + if self.get_activated(): + raise PoolError(XEND_ERROR_BAD_POOL_STATE, 'activated') + self.proposed_cpus = [ int(cpu) for cpu in proposed_cpus ] + if self._managed: + XendNode.instance().save_cpu_pools() + + def set_other_config(self, other_config): + self.other_config = other_config + if self._managed: + XendNode.instance().save_cpu_pools() + + def destroy(self): + """ In order to destroy a cpu pool, it must be deactivated """ + self.pool_lock.acquire() + try: + if self.get_activated(): + raise PoolError(XEND_ERROR_BAD_POOL_STATE, 'activated') + XendBase.destroy(self) + finally: + self.pool_lock.release() + XendNode.instance().save_cpu_pools() + + def activate(self): + """ Create pool in hypervisor and add cpus. + Preconditions: + - pool not already active + - enough unbound cpus available + Actions: + - create pool in hypervisor + - select free cpus (preferred from proposed_CPUs list) and bind it to + the pool + - create entries in Xenstore + """ + self.pool_lock.acquire() + try: + if self.get_activated(): + raise PoolError(XEND_ERROR_BAD_POOL_STATE, 'activated') + sched_policy = self.get_sched_policy() + if sched_policy not in XEN_SCHEDULER_TO_ID.keys(): + raise PoolError(XEND_ERROR_UNKOWN_SCHED_POLICY) + unbound_cpus = set(self.unbound_cpus()) + if len(unbound_cpus) < self.ncpu: + raise PoolError(XEND_ERROR_INSUFFICIENT_CPUS, + [str(self.ncpu), str(len(unbound_cpus))]) + + # build list of cpu numbers to bind to pool + cpu_set = set(self.proposed_cpus).intersection(unbound_cpus) + if len(cpu_set) < self.ncpu: + pool_cpus = (list(cpu_set) + + list(unbound_cpus.difference(cpu_set))) + else: + pool_cpus = list(cpu_set) + pool_cpus = pool_cpus[0:self.ncpu] + + # create pool in hypervisor + pool_id = xc.cpupool_create( + sched = XEN_SCHEDULER_TO_ID.get(sched_policy, 0)) + + self.update_XS(pool_id) + # add cpus + for cpu in pool_cpus: + xc.cpupool_addcpu(pool_id, cpu) + + finally: + self.pool_lock.release() + + def deactivate(self): + """ Delete pool in hypervisor + Preconditions: + - pool is activated + - no running VMs in pool + Actions: + - call hypervisor for deletion + - remove path of pool in xenstore + """ + self.pool_lock.acquire() + try: + if not self.get_activated(): + raise PoolError(XEND_ERROR_BAD_POOL_STATE, 'deactivated') + if len(self.get_started_VMs()) != 0: + raise PoolError(XEND_ERROR_BAD_POOL_STATE, 'in use') + + pool_id = self.query_pool_id() + # remove cpus from pool + cpus = [] + for pool_rec in xc.cpupool_getinfo(): + if pool_rec['cpupool'] == pool_id: + cpus = pool_rec['cpulist'] + for cpu_number in cpus: + xc.cpupool_removecpu(pool_id, cpu_number) + xc.cpupool_destroy(pool_id) + + # update XenStore + xs_path = XS_POOLROOT + "%s/" % pool_id + xstransact.Remove(xs_path) + finally: + self.pool_lock.release() + + def add_host_CPU_live(self, cpu_ref): + """ Add cpu to pool, if it is currently not assigned to a pool. + @param cpu_ref: reference of host_cpu instance to add + @type cpu_ref: str + """ + if not self.get_activated(): + raise PoolError(XEND_ERROR_BAD_POOL_STATE, 'deactivated') + node = XendNode.instance() + number = node.get_host_cpu_field(cpu_ref, 'number') + + self.pool_lock.acquire() + try: + pool_id = self.query_pool_id() + other_pool_ref = self.get_cpu_pool_by_cpu_ref(cpu_ref) + if len(other_pool_ref) != 0: + raise PoolError(XEND_ERROR_INVALID_CPU, + 'cpu already assigned to pool "%s"' % other_pool_ref[0]) + xc.cpupool_addcpu(pool_id, number) + finally: + self.pool_lock.release() + + if number not in self.proposed_cpus: + self.proposed_cpus.append(number) + self._update_ncpu(pool_id) + if self._managed: + XendNode.instance().save_cpu_pools() + + def remove_host_CPU_live(self, cpu_ref): + """ Remove cpu from pool. + After successfull call, the cpu is free. + Remove of the last cpu of the pool is rejected. + @param cpu_ref: reference of host_cpu instance to remove + @type cpu_ref: str + """ + if not self.get_activated(): + raise PoolError(XEND_ERROR_BAD_POOL_STATE, 'deactivated') + node = XendNode.instance() + number = node.get_host_cpu_field(cpu_ref, 'number') + + self.pool_lock.acquire() + try: + pool_id = self.query_pool_id() + pool_rec = {} + for pool in xc.cpupool_getinfo(): + if pool['cpupool'] == pool_id: + pool_rec = pool + break + + if number in pool_rec['cpulist']: + if len(pool_rec['cpulist']) < 2 and pool_rec['n_dom'] > 0: + raise PoolError(XEND_ERROR_LAST_CPU_NOT_REM, + 'could not remove last cpu') + xc.cpupool_removecpu(pool_id, number) + else: + raise PoolError(XEND_ERROR_INVALID_CPU, + 'CPU not assigned to pool') + finally: + self.pool_lock.release() + + if number in self.proposed_cpus: + self.proposed_cpus.remove(number) + self._update_ncpu(pool_id) + if self._managed: + XendNode.instance().save_cpu_pools() + + def add_to_proposed_CPUs(self, cpu): + if self.get_activated(): + raise PoolError(XEND_ERROR_BAD_POOL_STATE, 'activated') + + _cpu = int(cpu) + if _cpu not in self.proposed_cpus: + self.proposed_cpus.append(_cpu) + self.proposed_cpus.sort() + if self._managed: + XendNode.instance().save_cpu_pools() + + def remove_from_proposed_CPUs(self, cpu): + if self.get_activated(): + raise PoolError(XEND_ERROR_BAD_POOL_STATE, 'activated') + _cpu = int(cpu) + if _cpu in self.proposed_cpus: + self.proposed_cpus.remove(_cpu) + if self._managed: + XendNode.instance().save_cpu_pools() + + def add_to_other_config(self, key, value): + self.other_config[key] = value + if self._managed: + XendNode.instance().save_cpu_pools() + + def remove_from_other_config(self, key): + if key in self.other_config: + del self.other_config[key] + if self._managed: + XendNode.instance().save_cpu_pools() + + + # + # Legacy RPC calls + # + def pool_new(cls, config): + try: + record = sxp2map(config) + if record.has_key('proposed_CPUs') and \ + not isinstance(record['proposed_CPUs'], types.ListType): + record['proposed_CPUs'] = [record['proposed_CPUs']] + new_uuid = cls.create(record) + except XendAPIError, ex: + raise VmError(ex.get_api_error()) + return new_uuid + + def pool_create(cls, config): + try: + record = sxp2map(config) + if record.has_key('proposed_CPUs') and \ + not isinstance(record['proposed_CPUs'], types.ListType): + record['proposed_CPUs'] = [record['proposed_CPUs']] + new_uuid = genuuid.createString() + pool = XendCPUPool(record, new_uuid, False) + pool.activate() + except XendAPIError, ex: + raise VmError(ex.get_api_error()) + + def pool_start(cls, poolname): + pool = cls.lookup_pool(poolname) + if not pool: + raise VmError('unknown pool %s' % poolname) + try: + pool.activate() + except XendAPIError, ex: + raise VmError(ex.get_api_error()) + + def pool_list(cls, names): + sxprs = [] + try: + node = XendNode.instance() + xd = XendDomain.instance() + pools = cls.get_all_records() + for (pool_uuid, pool_vals) in pools.items(): + if pool_vals['name_label'] in names or len(names) == 0: + # conv host_cpu refs to cpu number + cpus = [ node.get_host_cpu_field(cpu_ref, 'number') + for cpu_ref in pool_vals['host_CPUs'] ] + cpus.sort() + pool_vals['host_CPU_numbers'] = cpus + # query VMs names. Take in account, that a VM + # returned by get_all_records could be destroy, now + vm_names = [ vm.getName() + for vm in map(xd.get_vm_by_uuid, + pool_vals['started_VMs']) + if vm ] + pool_vals['started_VM_names'] = vm_names + pool_vals['auto_power_on'] = int(pool_vals['auto_power_on']) + sxprs += [[pool_uuid] + map2sxp(pool_vals)] + except XendAPIError, ex: + raise VmError(ex.get_api_error()) + return sxprs + + def pool_destroy(cls, poolname): + pool = cls.lookup_pool(poolname) + if not pool: + raise VmError('unknown pool %s' % poolname) + try: + pool.deactivate() + if not pool.is_managed(): + pool.destroy() + except XendAPIError, ex: + raise VmError(ex.get_api_error()) + + def pool_delete(cls, poolname): + pool = cls.lookup_pool(poolname) + if not pool: + raise VmError('unknown pool %s' % poolname) + try: + pool.destroy() + except XendAPIError, ex: + raise VmError(ex.get_api_error()) + + def pool_cpu_add(cls, poolname, cpu): + pool = cls.lookup_pool(poolname) + if not pool: + raise VmError('unknown pool %s' % poolname) + try: + cpu_ref = cls._cpu_number_to_ref(int(cpu)) + if cpu_ref: + pool.add_host_CPU_live(cpu_ref) + else: + raise PoolError(XEND_ERROR_INVALID_CPU, + 'CPU unknown') + except XendAPIError, ex: + raise VmError(ex.get_api_error()) + + def pool_cpu_remove(cls, poolname, cpu): + pool = cls.lookup_pool(poolname) + if not pool: + raise VmError('unknown pool %s' % poolname) + try: + cpu_ref = cls._cpu_number_to_ref(int(cpu)) + if cpu_ref: + pool.remove_host_CPU_live(cpu_ref) + else: + raise PoolError(XEND_ERROR_INVALID_CPU, + 'CPU unknown') + except XendAPIError, ex: + raise VmError(ex.get_api_error()) + + def pool_migrate(cls, domname, poolname): + dom = XendDomain.instance() + pool = cls.lookup_pool(poolname) + if not pool: + raise VmError('unknown pool %s' % poolname) + dominfo = dom.domain_lookup_nr(domname) + if not dominfo: + raise VmError('unknown domain %s' % domname) + domid = dominfo.getDomid() + if domid is not None: + if domid == 0: + raise VmError('could not move Domain-0') + try: + cls.move_domain(pool.get_uuid(), domid) + except Exception, ex: + raise VmError('could not move domain') + dominfo.info['pool_name'] = poolname + dom.managed_config_save(dominfo) + + pool_new = classmethod(pool_new) + pool_create = classmethod(pool_create) + pool_start = classmethod(pool_start) + pool_list = classmethod(pool_list) + pool_destroy = classmethod(pool_destroy) + pool_delete = classmethod(pool_delete) + pool_cpu_add = classmethod(pool_cpu_add) + pool_cpu_remove = classmethod(pool_cpu_remove) + pool_migrate = classmethod(pool_migrate) + + + # + # methods + # + + def is_managed(self): + """ Check, if pool is managed. + @return: True, if managed + @rtype: bool + """ + return self._managed + + def query_pool_id(self): + """ Get corresponding pool-id of pool instance from XenStore. + @return: pool id or None + @rytpe: int + """ + self.pool_lock.acquire() + try: + for pool_id in xstransact.List(XS_POOLROOT): + uuid = xstransact.Read(XS_POOLROOT + "%s/" % pool_id, 'uuid') + if uuid == self.get_uuid(): + return int(pool_id) + finally: + self.pool_lock.release() + + return None + + def update_XS(self, pool_id): + """ Write (or update) data in xenstore taken from instance. + @param pool_id: Pool id to build path to pool data in xenstore + @type pool_id: int + """ + self.pool_lock.acquire() + try: + xs_path = XS_POOLROOT + "%s/" % pool_id + xs_entries = { 'uuid' : self.get_uuid(), + 'name' : self.name_label, + 'description' : self.name_description + } + xstransact.Mkdir(xs_path) + xstransact.Mkdir(xs_path, 'other_config') + xstransact.Write(xs_path, xs_entries) + xstransact.Write('%s%s' % (xs_path, 'other_config'), + self.other_config) + finally: + self.pool_lock.release() + + def _update_ncpu(self, pool_id): + for pool_rec in xc.cpupool_getinfo(): + if pool_rec['cpupool'] == pool_id: + self.ncpu = len(pool_rec['cpulist']) + + def _checkName(self, name): + """ Check if a pool name is valid. Valid names contain alphabetic + characters, digits, or characters in '_-.:/+'. + The same name cannot be used for more than one pool at the same + time. + @param name: name + @type name: str + @raise: PoolError if invalid + """ + if name is None or name == '': + raise PoolError(XEND_ERROR_POOL_PARAM, 'Missing Pool Name') + if not re.search(r'^[A-Za-z0-9_\-\.\:\/\+]+$', name): + raise PoolError(XEND_ERROR_POOL_PARAM, 'Invalid Pool Name') + + pool = self.lookup_pool(name) + if pool and pool.get_uuid() != self.get_uuid(): + raise PoolError(XEND_ERROR_POOL_PARAM, + 'Pool name "%s" already exists' % name) + + + # + # class methods + # + + def recreate_active_pools(cls): + """ Read active pool config from hypervisor and create pool instances. + - Query pool ids and assigned CPUs from hypervisor. + - Query additional information for any pool from xenstore. + If an entry for a pool id is missing in xenstore, it will be + recreated with a new uuid and generic name (this is an error case) + - Create an XendCPUPool instance for any pool id + Function have to be called after recreation of managed pools. + """ + log.debug('recreate_active_pools') + + for pool_rec in xc.cpupool_getinfo(): + pool = pool_rec['cpupool'] + + # read pool data from xenstore + path = XS_POOLROOT + "%s/" % pool + uuid = xstransact.Read(path, 'uuid') + if not uuid: + # xenstore entry missing / invaild; create entry with new uuid + uuid = genuuid.createString() + name = "Pool-%s" % pool + try: + inst = XendCPUPool( { 'name_label' : name }, uuid, False ) + inst.update_XS(pool) + except PoolError, ex: + # log error and skip domain + log.error('cannot recreate pool %s; skipping (reason: %s)' \ + % (name, ex)) + else: + (name, descr) = xstransact.Read(path, 'name', 'description') + other_config = {} + for key in xstransact.List(path + 'other_config'): + other_config[key] = xstransact.Read( + path + 'other_config/%s' % key) + + # check existance of pool instance + inst = XendAPIStore.get(uuid, cls.getClass()) + if inst: + # update attributes of existing instance + inst.name_label = name + inst.name_description = descr + inst.other_config = other_config + else: + # recreate instance + try: + inst = XendCPUPool( + { 'name_label' : name, + 'name_description' : descr, + 'other_config' : other_config, + 'proposed_CPUs' : pool_rec['cpulist'], + 'ncpu' : len(pool_rec['cpulist']), + }, + uuid, False ) + except PoolError, ex: + # log error and skip domain + log.error( + 'cannot recreate pool %s; skipping (reason: %s)' \ + % (name, ex)) + + recreate_active_pools = classmethod(recreate_active_pools) + + + def recreate(cls, record, current_uuid): + """ Recreate a pool instance while xend restart. + @param record: attributes of pool + @type record: dict + @param current_uuid: uuid of pool to create + @type current_uuid: str + """ + XendCPUPool(record, current_uuid) + + recreate = classmethod(recreate) + + + def autostart_pools(cls): + """ Start managed pools that are marked as autostart pools. + Function is called after recreation of managed domains while + xend restart. + """ + cls.pool_lock.acquire() + try: + for inst in XendAPIStore.get_all(cls.getClass()): + if inst.is_managed() and inst.auto_power_on and \ + inst.query_pool_id() == None: + inst.activate() + finally: + cls.pool_lock.release() + + autostart_pools = classmethod(autostart_pools) + + + def move_domain(cls, pool_ref, domid): + cls.pool_lock.acquire() + try: + pool = XendAPIStore.get(pool_ref, cls.getClass()) + pool_id = pool.query_pool_id() + + xc.cpupool_movedomain(pool_id, domid) + finally: + cls.pool_lock.release() + + move_domain = classmethod(move_domain) + + + def query_pool_ref(cls, pool_id): + """ Get pool ref by pool id. + Take the ref from xenstore. + @param pool_id: + @type pool_id: int + @return: ref + @rtype: str + """ + uuid = xstransact.Read(XS_POOLROOT + "%s/" % pool_id, 'uuid') + if uuid: + return [uuid] + else: + return [] + + query_pool_ref = classmethod(query_pool_ref) + + + def lookup_pool(cls, id_or_name): + """ Search XendCPUPool instance with given id_or_name. + @param id_or_name: pool id or pool nameto search + @type id_or_name: [int, str] + @return: instane or None if not found + @rtype: XendCPUPool + """ + pool_uuid = None + try: + pool_id = int(id_or_name) + # pool id given ? + pool_uuid = cls.query_pool_ref(pool_id) + if not pool_uuid: + # not found -> search name + pool_uuid = cls.get_by_name_label(id_or_name) + except ValueError: + # pool name given + pool_uuid = cls.get_by_name_label(id_or_name) + + if len(pool_uuid) > 0: + return XendAPIStore.get(pool_uuid[0], cls.getClass()) + else: + return None + + lookup_pool = classmethod(lookup_pool) + + + def _cpu_number_to_ref(cls, number): + node = XendNode.instance() + for cpu_ref in node.get_host_cpu_refs(): + if node.get_host_cpu_field(cpu_ref, 'number') == number: + return cpu_ref + return None + + _cpu_number_to_ref = classmethod(_cpu_number_to_ref) + + + def unbound_cpus(cls): + """ Build list containing the numbers of all cpus not bound to a pool. + Info is taken from Hypervisor. + @return: list of cpu numbers + @rytpe: list of int + """ + return xc.cpupool_freeinfo() + + unbound_cpus = classmethod(unbound_cpus) +