[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] cpupools [4/6]: python/xend changes
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1271850632 -3600 # Node ID 3fd2342debf1b625594043aaeef69261e7034d78 # Parent 96715cf158e5a4fedfc9e2acc82c318900acbffc cpupools [4/6]: python/xend changes Signed-off-by: Juergen Gross <juergen.gross@xxxxxxxxxxxxxx> --- tools/python/xen/lowlevel/xc/xc.c | 241 ++++++++++++++++++++++++++ tools/python/xen/xend/XendAPI.py | 72 +++++++ tools/python/xen/xend/XendConfig.py | 5 tools/python/xen/xend/XendConstants.py | 2 tools/python/xen/xend/XendDomainInfo.py | 28 ++- tools/python/xen/xend/XendError.py | 21 ++ tools/python/xen/xend/XendNode.py | 24 ++ tools/python/xen/xend/server/SrvServer.py | 7 tools/python/xen/xend/server/XMLRPCServer.py | 10 + tools/python/xen/xm/create.dtd | 1 tools/python/xen/xm/create.py | 6 tools/python/xen/xm/main.py | 244 ++++++++++++++++++++++++++- tools/python/xen/xm/pool-create.py | 51 +++++ tools/python/xen/xm/pool-new.py | 50 +++++ tools/python/xen/xm/pool.py | 236 ++++++++++++++++++++++++++ tools/python/xen/xm/xenapi_create.py | 4 16 files changed, 985 insertions(+), 17 deletions(-) diff -r 96715cf158e5 -r 3fd2342debf1 tools/python/xen/lowlevel/xc/xc.c --- a/tools/python/xen/lowlevel/xc/xc.c Wed Apr 21 12:49:41 2010 +0100 +++ b/tools/python/xen/lowlevel/xc/xc.c Wed Apr 21 12:50:32 2010 +0100 @@ -329,7 +329,7 @@ static PyObject *pyxc_domain_getinfo(XcO { info_dict = Py_BuildValue( "{s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i" - ",s:L,s:L,s:L,s:i,s:i}", + ",s:L,s:L,s:L,s:i,s:i,s:i}", "domid", (int)info[i].domid, "online_vcpus", info[i].nr_online_vcpus, "max_vcpu_id", info[i].max_vcpu_id, @@ -344,7 +344,8 @@ static PyObject *pyxc_domain_getinfo(XcO "cpu_time", (long long)info[i].cpu_time, "maxmem_kb", (long long)info[i].max_memkb, "ssidref", (int)info[i].ssidref, - "shutdown_reason", info[i].shutdown_reason); + "shutdown_reason", info[i].shutdown_reason, + "cpupool", (int)info[i].cpupool); pyhandle = PyList_New(sizeof(xen_domain_handle_t)); if ( (pyhandle == NULL) || (info_dict == NULL) ) { @@ -1893,6 +1894,179 @@ static PyObject *pyxc_dom_set_memshr(XcO return zero; } +static PyObject *cpumap_to_cpulist(uint64_t cpumap) +{ + PyObject *cpulist = NULL; + uint32_t i; + + cpulist = PyList_New(0); + for ( i = 0; cpumap != 0; i++ ) + { + if ( cpumap & 1 ) + { + PyObject* pyint = PyInt_FromLong(i); + + PyList_Append(cpulist, pyint); + Py_DECREF(pyint); + } + cpumap >>= 1; + } + return cpulist; +} + +static PyObject *pyxc_cpupool_create(XcObject *self, + PyObject *args, + PyObject *kwds) +{ + uint32_t cpupool = 0, sched = XEN_SCHEDULER_CREDIT; + + static char *kwd_list[] = { "pool", "sched", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwd_list, &cpupool, + &sched)) + return NULL; + + if ( xc_cpupool_create(self->xc_handle, &cpupool, sched) < 0 ) + return pyxc_error_to_exception(); + + return PyInt_FromLong(cpupool); +} + +static PyObject *pyxc_cpupool_destroy(XcObject *self, + PyObject *args) +{ + uint32_t cpupool; + + if (!PyArg_ParseTuple(args, "i", &cpupool)) + return NULL; + + if (xc_cpupool_destroy(self->xc_handle, cpupool) != 0) + return pyxc_error_to_exception(); + + Py_INCREF(zero); + return zero; +} + +static PyObject *pyxc_cpupool_getinfo(XcObject *self, + PyObject *args, + PyObject *kwds) +{ + PyObject *list, *info_dict; + + uint32_t first_pool = 0; + int max_pools = 1024, nr_pools, i; + xc_cpupoolinfo_t *info; + + static char *kwd_list[] = { "first_pool", "max_pools", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwd_list, + &first_pool, &max_pools) ) + return NULL; + + info = calloc(max_pools, sizeof(xc_cpupoolinfo_t)); + if (info == NULL) + return PyErr_NoMemory(); + + nr_pools = xc_cpupool_getinfo(self->xc_handle, first_pool, max_pools, info); + + if (nr_pools < 0) + { + free(info); + return pyxc_error_to_exception(); + } + + list = PyList_New(nr_pools); + for ( i = 0 ; i < nr_pools; i++ ) + { + info_dict = Py_BuildValue( + "{s:i,s:i,s:i,s:N}", + "cpupool", (int)info[i].cpupool_id, + "sched", info[i].sched_id, + "n_dom", info[i].n_dom, + "cpulist", cpumap_to_cpulist(info[i].cpumap)); + if ( info_dict == NULL ) + { + Py_DECREF(list); + if ( info_dict != NULL ) { Py_DECREF(info_dict); } + free(info); + return NULL; + } + PyList_SetItem(list, i, info_dict); + } + + free(info); + + return list; +} + +static PyObject *pyxc_cpupool_addcpu(XcObject *self, + PyObject *args, + PyObject *kwds) +{ + uint32_t cpupool; + int cpu = -1; + + static char *kwd_list[] = { "cpupool", "cpu", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list, + &cpupool, &cpu) ) + return NULL; + + if (xc_cpupool_addcpu(self->xc_handle, cpupool, cpu) != 0) + return pyxc_error_to_exception(); + + Py_INCREF(zero); + return zero; +} + +static PyObject *pyxc_cpupool_removecpu(XcObject *self, + PyObject *args, + PyObject *kwds) +{ + uint32_t cpupool; + int cpu = -1; + + static char *kwd_list[] = { "cpupool", "cpu", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list, + &cpupool, &cpu) ) + return NULL; + + if (xc_cpupool_removecpu(self->xc_handle, cpupool, cpu) != 0) + return pyxc_error_to_exception(); + + Py_INCREF(zero); + return zero; +} + +static PyObject *pyxc_cpupool_movedomain(XcObject *self, + PyObject *args, + PyObject *kwds) +{ + uint32_t cpupool, domid; + + static char *kwd_list[] = { "cpupool", "domid", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "ii", kwd_list, + &cpupool, &domid) ) + return NULL; + + if (xc_cpupool_movedomain(self->xc_handle, cpupool, domid) != 0) + return pyxc_error_to_exception(); + + Py_INCREF(zero); + return zero; +} + +static PyObject *pyxc_cpupool_freeinfo(XcObject *self) +{ + uint64_t cpumap; + + if (xc_cpupool_freeinfo(self->xc_handle, &cpumap) != 0) + return pyxc_error_to_exception(); + + return cpumap_to_cpulist(cpumap); +} static PyMethodDef pyxc_methods[] = { { "handle", @@ -2008,7 +2182,8 @@ static PyMethodDef pyxc_methods[] = { " maxmem_kb [int]: Maximum memory limit, in kilobytes\n" " cpu_time [long]: CPU time consumed, in nanoseconds\n" " shutdown_reason [int]: Numeric code from guest OS, explaining " - "reason why it shut itself down.\n" }, + "reason why it shut itself down.\n" + " cpupool [int] Id of cpupool domain is bound to.\n" }, { "vcpu_getinfo", (PyCFunction)pyxc_vcpu_getinfo, @@ -2437,6 +2612,66 @@ static PyMethodDef pyxc_methods[] = { " dom [int]: Domain identifier.\n" " enable [int,0|1]: Disable or enable?\n" "Returns: [int] 0 on success; -1 on error.\n" }, + + { "cpupool_create", + (PyCFunction)pyxc_cpupool_create, + METH_VARARGS | METH_KEYWORDS, "\n" + "Create new cpupool.\n" + " pool [int, 0]: cpupool identifier to use (allocated if zero).\n" + " sched [int]: scheduler to use (credit if unspecified).\n\n" + "Returns: [int] new cpupool identifier; -1 on error.\n" }, + + { "cpupool_destroy", + (PyCFunction)pyxc_cpupool_destroy, + METH_VARARGS, "\n" + "Destroy a cpupool.\n" + " pool [int]: Identifier of cpupool to be destroyed.\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "cpupool_getinfo", + (PyCFunction)pyxc_cpupool_getinfo, + METH_VARARGS | METH_KEYWORDS, "\n" + "Get information regarding a set of cpupools, in increasing id order.\n" + " first_pool [int, 0]: First cpupool to retrieve info about.\n" + " max_pools [int, 1024]: Maximum number of cpupools to retrieve info" + " about.\n\n" + "Returns: [list of dicts] if list length is less than 'max_pools'\n" + " parameter then there was an error, or the end of the\n" + " cpupool-id space was reached.\n" + " pool [int]: Identifier of cpupool to which this info pertains\n" + " sched [int]: Scheduler used for this cpupool\n" + " n_dom [int]: Number of Domains in this cpupool\n" + " cpulist [list]: List of CPUs this cpupool is using\n" }, + + { "cpupool_addcpu", + (PyCFunction)pyxc_cpupool_addcpu, + METH_VARARGS | METH_KEYWORDS, "\n" + "Add a cpu to a cpupool.\n" + " pool [int]: Identifier of cpupool.\n" + " cpu [int, -1]: Cpu to add (lowest free if -1)\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "cpupool_removecpu", + (PyCFunction)pyxc_cpupool_removecpu, + METH_VARARGS | METH_KEYWORDS, "\n" + "Remove a cpu from a cpupool.\n" + " pool [int]: Identifier of cpupool.\n" + " cpu [int, -1]: Cpu to remove (highest used if -1)\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "cpupool_movedomain", + (PyCFunction)pyxc_cpupool_movedomain, + METH_VARARGS | METH_KEYWORDS, "\n" + "Move a domain to another cpupool.\n" + " pool [int]: Identifier of cpupool to move domain to.\n" + " dom [int]: Domain to move\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "cpupool_freeinfo", + (PyCFunction)pyxc_cpupool_freeinfo, + METH_NOARGS, "\n" + "Get info about cpus not in any cpupool.\n" + "Returns: [list]: List of CPUs\n" }, { NULL, NULL, 0, NULL } }; diff -r 96715cf158e5 -r 3fd2342debf1 tools/python/xen/xend/XendAPI.py --- a/tools/python/xen/xend/XendAPI.py Wed Apr 21 12:49:41 2010 +0100 +++ b/tools/python/xen/xend/XendAPI.py Wed Apr 21 12:50:32 2010 +0100 @@ -51,6 +51,7 @@ from XendPSCSI import XendPSCSI, XendPSC from XendPSCSI import XendPSCSI, XendPSCSI_HBA from XendDSCSI import XendDSCSI, XendDSCSI_HBA from XendXSPolicy import XendXSPolicy, XendACMPolicy +from xen.xend.XendCPUPool import XendCPUPool from XendAPIConstants import * from xen.util.xmlrpclib2 import stringify @@ -498,6 +499,7 @@ classes = { 'PSCSI_HBA' : valid_object("PSCSI_HBA"), 'DSCSI' : valid_object("DSCSI"), 'DSCSI_HBA' : valid_object("DSCSI_HBA"), + 'cpu_pool' : valid_object("cpu_pool"), } autoplug_classes = { @@ -514,6 +516,7 @@ autoplug_classes = { 'DSCSI_HBA' : XendDSCSI_HBA, 'XSPolicy' : XendXSPolicy, 'ACMPolicy' : XendACMPolicy, + 'cpu_pool' : XendCPUPool, } class XendAPI(object): @@ -914,7 +917,8 @@ class XendAPI(object): 'API_version_minor', 'API_version_vendor', 'API_version_vendor_implementation', - 'enabled'] + 'enabled', + 'resident_cpu_pools'] host_attr_rw = ['name_label', 'name_description', @@ -1014,6 +1018,8 @@ class XendAPI(object): return xen_api_todo() def host_get_logging(self, _, host_ref): return xen_api_todo() + def host_get_resident_cpu_pools(self, _, host_ref): + return xen_api_success(XendCPUPool.get_all()) # object methods def host_disable(self, session, host_ref): @@ -1076,7 +1082,9 @@ class XendAPI(object): 'PBDs': XendPBD.get_all(), 'PPCIs': XendPPCI.get_all(), 'PSCSIs': XendPSCSI.get_all(), - 'PSCSI_HBAs': XendPSCSI_HBA.get_all()} + 'PSCSI_HBAs': XendPSCSI_HBA.get_all(), + 'resident_cpu_pools': XendCPUPool.get_all(), + } return xen_api_success(record) def host_tmem_thaw(self, _, host_ref, cli_id): @@ -1185,7 +1193,10 @@ class XendAPI(object): 'stepping', 'flags', 'utilisation', - 'features'] + 'features', + 'cpu_pool'] + + host_cpu_funcs = [('get_unassigned_cpus', 'Set(host_cpu)')] # attributes def _host_cpu_get(self, ref, field): @@ -1210,21 +1221,28 @@ class XendAPI(object): return self._host_cpu_get(ref, 'flags') def host_cpu_get_utilisation(self, _, ref): return xen_api_success(XendNode.instance().get_host_cpu_load(ref)) + def host_cpu_get_cpu_pool(self, _, ref): + return xen_api_success(XendCPUPool.get_cpu_pool_by_cpu_ref(ref)) # object methods def host_cpu_get_record(self, _, ref): node = XendNode.instance() record = dict([(f, node.get_host_cpu_field(ref, f)) for f in self.host_cpu_attr_ro - if f not in ['uuid', 'host', 'utilisation']]) + if f not in ['uuid', 'host', 'utilisation', 'cpu_pool']]) record['uuid'] = ref record['host'] = node.uuid record['utilisation'] = node.get_host_cpu_load(ref) + record['cpu_pool'] = XendCPUPool.get_cpu_pool_by_cpu_ref(ref) return xen_api_success(record) # class methods def host_cpu_get_all(self, session): return xen_api_success(XendNode.instance().get_host_cpu_refs()) + def host_cpu_get_unassigned_cpus(self, session): + return xen_api_success( + [ref for ref in XendNode.instance().get_host_cpu_refs() + if len(XendCPUPool.get_cpu_pool_by_cpu_ref(ref)) == 0]) # Xen API: Class host_metrics @@ -1284,6 +1302,7 @@ class XendAPI(object): 'is_control_domain', 'metrics', 'crash_dumps', + 'cpu_pool', ] VM_attr_rw = ['name_label', @@ -1312,7 +1331,9 @@ class XendAPI(object): 'platform', 'PCI_bus', 'other_config', - 'security_label'] + 'security_label', + 'pool_name', + ] VM_methods = [('clone', 'VM'), ('start', None), @@ -1340,7 +1361,9 @@ class XendAPI(object): ('set_memory_dynamic_min_live', None), ('send_trigger', None), ('migrate', None), - ('destroy', None)] + ('destroy', None), + ('cpu_pool_migrate', None), + ] VM_funcs = [('create', 'VM'), ('restore', None), @@ -1540,6 +1563,17 @@ class XendAPI(object): return xen_api_success( xd.get_vm_by_uuid(vm_ref) == xd.privilegedDomain()) + def VM_get_cpu_pool(self, session, vm_ref): + dom = XendDomain.instance().get_vm_by_uuid(vm_ref) + pool_ref = XendCPUPool.query_pool_ref(dom.get_cpu_pool()) + return xen_api_success(pool_ref) + + def VM_get_pool_name(self, session, vm_ref): + return self.VM_get('pool_name', session, vm_ref) + + def VM_set_pool_name(self, session, vm_ref, value): + return self.VM_set('pool_name', session, vm_ref, value) + def VM_set_name_label(self, session, vm_ref, label): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) dom.setName(label) @@ -1618,7 +1652,8 @@ class XendAPI(object): if key.startswith("cpumap"): vcpu = int(key[6:]) try: - xendom.domain_pincpu(xeninfo.getDomid(), vcpu, value) + cpus = map(int, value.split(",")) + xendom.domain_pincpu(xeninfo.getDomid(), vcpu, cpus) except Exception, ex: log.exception(ex) @@ -1834,7 +1869,9 @@ class XendAPI(object): 'is_control_domain': xeninfo.info['is_control_domain'], 'metrics': xeninfo.get_metrics(), 'security_label': xeninfo.get_security_label(), - 'crash_dumps': [] + 'crash_dumps': [], + 'pool_name': xeninfo.info.get('pool_name'), + 'cpu_pool' : XendCPUPool.query_pool_ref(xeninfo.get_cpu_pool()), } return xen_api_success(record) @@ -1930,6 +1967,25 @@ class XendAPI(object): def VM_restore(self, _, src, paused): xendom = XendDomain.instance() xendom.domain_restore(src, bool(paused)) + return xen_api_success_void() + + def VM_cpu_pool_migrate(self, session, vm_ref, cpu_pool_ref): + xendom = XendDomain.instance() + xeninfo = xendom.get_vm_by_uuid(vm_ref) + domid = xeninfo.getDomid() + pool = XendAPIStore.get(cpu_pool_ref, XendCPUPool.getClass()) + if pool == None: + return xen_api_error(['HANDLE_INVALID', 'cpu_pool', cpu_pool_ref]) + if domid is not None: + if domid == 0: + return xen_api_error(['OPERATION_NOT_ALLOWED', + 'could not move Domain-0']) + try: + XendCPUPool.move_domain(cpu_pool_ref, domid) + except Exception, ex: + return xen_api_error(['INTERNAL_ERROR', + 'could not move domain']) + self.VM_set('pool_name', session, vm_ref, pool.get_name_label()) return xen_api_success_void() diff -r 96715cf158e5 -r 3fd2342debf1 tools/python/xen/xend/XendConfig.py --- a/tools/python/xen/xend/XendConfig.py Wed Apr 21 12:49:41 2010 +0100 +++ b/tools/python/xen/xend/XendConfig.py Wed Apr 21 12:50:32 2010 +0100 @@ -128,6 +128,7 @@ XENAPI_CFG_TO_LEGACY_CFG = { 'PV_bootloader': 'bootloader', 'PV_bootloader_args': 'bootloader_args', 'Description': 'description', + 'pool_name' : 'pool_name', } LEGACY_CFG_TO_XENAPI_CFG = reverse_dict(XENAPI_CFG_TO_LEGACY_CFG) @@ -233,6 +234,7 @@ XENAPI_CFG_TYPES = { 's3_integrity' : int, 'superpages' : int, 'memory_sharing': int, + 'pool_name' : str, 'Description': str, } @@ -279,6 +281,7 @@ LEGACY_CFG_TYPES = { 'bootloader': str, 'bootloader_args': str, 'description': str, + 'pool_name': str, } # Values that should be stored in xenstore's /vm/<uuid> that is used @@ -300,6 +303,7 @@ LEGACY_XENSTORE_VM_PARAMS = [ 'on_xend_stop', 'bootloader', 'bootloader_args', + 'pool_name', ] ## @@ -408,6 +412,7 @@ class XendConfig(dict): 'other_config': {}, 'platform': {}, 'target': 0, + 'pool_name' : 'Pool-0', 'superpages': 0, 'description': '', } diff -r 96715cf158e5 -r 3fd2342debf1 tools/python/xen/xend/XendConstants.py --- a/tools/python/xen/xend/XendConstants.py Wed Apr 21 12:49:41 2010 +0100 +++ b/tools/python/xen/xend/XendConstants.py Wed Apr 21 12:50:32 2010 +0100 @@ -133,6 +133,8 @@ VTPM_DELETE_SCRIPT = auxbin.scripts_dir( XS_VMROOT = "/vm/" +XS_POOLROOT = "/local/pool/" + NR_PCI_FUNC = 8 NR_PCI_DEV = 32 NR_PCI_DEVFN = NR_PCI_FUNC * NR_PCI_DEV diff -r 96715cf158e5 -r 3fd2342debf1 tools/python/xen/xend/XendDomainInfo.py --- a/tools/python/xen/xend/XendDomainInfo.py Wed Apr 21 12:49:41 2010 +0100 +++ b/tools/python/xen/xend/XendDomainInfo.py Wed Apr 21 12:50:32 2010 +0100 @@ -32,11 +32,12 @@ import copy import copy import os import stat +import shutil import traceback from types import StringTypes import xen.lowlevel.xc -from xen.util import asserts, auxbin +from xen.util import asserts, auxbin, mkdir from xen.util.blkif import blkdev_uname_to_file, blkdev_uname_to_taptype import xen.util.xsm.xsm as security from xen.util import xsconstants @@ -60,6 +61,7 @@ from xen.xend.xenstore.xswatch import xs from xen.xend.xenstore.xswatch import xswatch from xen.xend.XendConstants import * from xen.xend.XendAPIConstants import * +from xen.xend.XendCPUPool import XendCPUPool from xen.xend.server.DevConstants import xenbusState from xen.xend.server.BlktapController import TAPDISK_DEVICE, parseDeviceString @@ -2540,6 +2542,19 @@ class XendDomainInfo: oos = self.info['platform'].get('oos', 1) oos_off = 1 - int(oos) + # look-up pool id to use + pool_name = self.info['pool_name'] + if len(pool_name) == 0: + pool_name = "Pool-0" + + pool = XendCPUPool.lookup_pool(pool_name) + + if pool is None: + raise VmError("unknown pool %s" % pool_name) + pool_id = pool.query_pool_id() + if pool_id is None: + raise VmError("pool %s not activated" % pool_name) + flags = (int(hvm) << 0) | (int(hap) << 1) | (int(s3_integrity) << 2) | (int(oos_off) << 3) try: @@ -2548,6 +2563,7 @@ class XendDomainInfo: ssidref = ssidref, handle = uuid.fromString(self.info['uuid']), flags = flags, + #cpupool = pool_id, target = self.info.target()) except Exception, e: # may get here if due to ACM the operation is not permitted @@ -2560,6 +2576,11 @@ class XendDomainInfo: if self.domid: failmsg += ', error=%i' % int(self.domid) raise VmError(failmsg) + + try: + xc.cpupool_movedomain(pool_id, self.domid) + except Exception, e: + raise VmError('Moving domain to target pool failed') self.dompath = GetDomainPath(self.domid) @@ -3585,6 +3606,11 @@ class XendDomainInfo: retval = xc.sched_credit_domain_get(self.getDomid()) return retval + def get_cpu_pool(self): + if self.getDomid() is None: + return None + xeninfo = dom_get(self.domid) + return xeninfo['cpupool'] def get_power_state(self): return XEN_API_VM_POWER_STATE[self._stateGet()] def get_platform(self): diff -r 96715cf158e5 -r 3fd2342debf1 tools/python/xen/xend/XendError.py --- a/tools/python/xen/xend/XendError.py Wed Apr 21 12:49:41 2010 +0100 +++ b/tools/python/xen/xend/XendError.py Wed Apr 21 12:50:32 2010 +0100 @@ -18,6 +18,7 @@ from xmlrpclib import Fault +import types import XendClient class XendInvalidDomain(Fault): @@ -185,6 +186,26 @@ class DirectPCIError(XendAPIError): def __str__(self): return 'DIRECT_PCI_ERROR: %s' % self.error + +class PoolError(XendAPIError): + def __init__(self, error, spec=None): + XendAPIError.__init__(self) + self.spec = [] + if spec: + if isinstance(spec, types.ListType): + self.spec = spec + else: + self.spec = [spec] + self.error = error + + def get_api_error(self): + return [self.error] + self.spec + + def __str__(self): + if self.spec: + return '%s: %s' % (self.error, self.spec) + else: + return '%s' % self.error class VDIError(XendAPIError): def __init__(self, error, vdi): diff -r 96715cf158e5 -r 3fd2342debf1 tools/python/xen/xend/XendNode.py --- a/tools/python/xen/xend/XendNode.py Wed Apr 21 12:49:41 2010 +0100 +++ b/tools/python/xen/xend/XendNode.py Wed Apr 21 12:50:32 2010 +0100 @@ -43,6 +43,7 @@ from XendMonitor import XendMonitor from XendMonitor import XendMonitor from XendPPCI import XendPPCI from XendPSCSI import XendPSCSI, XendPSCSI_HBA +from xen.xend.XendCPUPool import XendCPUPool class XendNode: """XendNode - Represents a Domain 0 Host.""" @@ -159,6 +160,8 @@ class XendNode: self._init_PSCSIs() + self._init_cpu_pools() + def _init_networks(self): # Initialise networks @@ -361,6 +364,18 @@ class XendNode: for physical_host, pscsi_HBA_uuid in pscsi_HBA_table.items(): XendPSCSI_HBA(pscsi_HBA_uuid, {'physical_host': physical_host}) + def _init_cpu_pools(self): + # Initialise cpu_pools + saved_cpu_pools = self.state_store.load_state(XendCPUPool.getClass()) + if saved_cpu_pools: + for cpu_pool_uuid, cpu_pool in saved_cpu_pools.items(): + try: + XendCPUPool.recreate(cpu_pool, cpu_pool_uuid) + except CreateUnspecifiedAttributeError: + log.warn("Error recreating %s %s", + (XendCPUPool.getClass(), cpu_pool_uuid)) + XendCPUPool.recreate_active_pools() + def add_network(self, interface): # TODO @@ -581,6 +596,7 @@ class XendNode: self.save_PPCIs() self.save_PSCSIs() self.save_PSCSI_HBAs() + self.save_cpu_pools() def save_PIFs(self): pif_records = dict([(pif_uuid, XendAPIStore.get( @@ -622,6 +638,12 @@ class XendNode: pscsi_HBA_uuid, "PSCSI_HBA").get_record()) for pscsi_HBA_uuid in XendPSCSI_HBA.get_all()]) self.state_store.save_state('pscsi_HBA', pscsi_HBA_records) + + def save_cpu_pools(self): + cpu_pool_records = dict([(cpu_pool_uuid, XendAPIStore.get( + cpu_pool_uuid, XendCPUPool.getClass()).get_record()) + for cpu_pool_uuid in XendCPUPool.get_all_managed()]) + self.state_store.save_state(XendCPUPool.getClass(), cpu_pool_records) def shutdown(self): return 0 @@ -925,6 +947,7 @@ class XendNode: # physinfo is in KiB, need it in MiB info['total_memory'] = info['total_memory'] / 1024 info['free_memory'] = info['free_memory'] / 1024 + info['free_cpus'] = len(XendCPUPool.unbound_cpus()) ITEM_ORDER = ['nr_cpus', 'nr_nodes', @@ -935,6 +958,7 @@ class XendNode: 'virt_caps', 'total_memory', 'free_memory', + 'free_cpus', ] if show_numa != 0: diff -r 96715cf158e5 -r 3fd2342debf1 tools/python/xen/xend/server/SrvServer.py --- a/tools/python/xen/xend/server/SrvServer.py Wed Apr 21 12:49:41 2010 +0100 +++ b/tools/python/xen/xend/server/SrvServer.py Wed Apr 21 12:50:32 2010 +0100 @@ -52,6 +52,7 @@ from xen.xend.XendLogging import log from xen.xend.XendLogging import log from xen.xend.XendClient import XEN_API_SOCKET from xen.xend.XendDomain import instance as xenddomain +from xen.xend.XendCPUPool import XendCPUPool from xen.web.SrvDir import SrvDir from SrvRoot import SrvRoot @@ -145,6 +146,12 @@ class XendServers: status.write('0') status.close() status = None + + # auto start pools before domains are started + try: + XendCPUPool.autostart_pools() + except Exception, e: + log.exception("Failed while autostarting pools") # Reaching this point means we can auto start domains try: diff -r 96715cf158e5 -r 3fd2342debf1 tools/python/xen/xend/server/XMLRPCServer.py --- a/tools/python/xen/xend/server/XMLRPCServer.py Wed Apr 21 12:49:41 2010 +0100 +++ b/tools/python/xen/xend/server/XMLRPCServer.py Wed Apr 21 12:50:32 2010 +0100 @@ -33,6 +33,7 @@ from xen.xend.XendConstants import DOM_S from xen.xend.XendConstants import DOM_STATE_RUNNING from xen.xend.XendLogging import log from xen.xend.XendError import XendInvalidDomain +from xen.xend.XendCPUPool import XendCPUPool # vcpu_avail is a long and is not needed by the clients. It's far easier # to just remove it then to try and marshal the long. @@ -97,6 +98,10 @@ methods = ['device_create', 'device_conf 'getRestartCount', 'getBlockDeviceClass'] exclude = ['domain_create', 'domain_restore'] + +POOL_FUNCS = ['pool_create', 'pool_new', 'pool_start', 'pool_list', + 'pool_destroy', 'pool_delete', 'pool_cpu_add', 'pool_cpu_remove', + 'pool_migrate'] class XMLRPCServer: def __init__(self, auth, use_xenapi, use_tcp = False, @@ -197,6 +202,11 @@ class XMLRPCServer: if name not in exclude: self.server.register_function(fn, "xend.domain.%s" % name[7:]) + # Functions in XendPool + for name in POOL_FUNCS: + fn = getattr(XendCPUPool, name) + self.server.register_function(fn, "xend.cpu_pool.%s" % name[5:]) + # Functions in XendNode and XendDmesg for type, lst, n in [(XendNode, ['info', 'pciinfo', 'send_debug_keys', diff -r 96715cf158e5 -r 3fd2342debf1 tools/python/xen/xm/create.dtd --- a/tools/python/xen/xm/create.dtd Wed Apr 21 12:49:41 2010 +0100 +++ b/tools/python/xen/xm/create.dtd Wed Apr 21 12:50:32 2010 +0100 @@ -50,6 +50,7 @@ s3_integrity CDATA #REQUIRED vcpus_max CDATA #REQUIRED vcpus_at_startup CDATA #REQUIRED + pool_name CDATA #REQUIRED actions_after_shutdown %NORMAL_EXIT; #REQUIRED actions_after_reboot %NORMAL_EXIT; #REQUIRED actions_after_crash %CRASH_BEHAVIOUR; #REQUIRED diff -r 96715cf158e5 -r 3fd2342debf1 tools/python/xen/xm/create.py --- a/tools/python/xen/xm/create.py Wed Apr 21 12:49:41 2010 +0100 +++ b/tools/python/xen/xm/create.py Wed Apr 21 12:50:32 2010 +0100 @@ -658,6 +658,10 @@ gopts.var('suppress_spurious_page_faults gopts.var('suppress_spurious_page_faults', val='yes|no', fn=set_bool, default=None, use="""Do not inject spurious page faults into this guest""") + +gopts.var('pool', val='POOL NAME', + fn=set_value, default=None, + use="""CPU pool to use for the VM""") gopts.var('pci_msitranslate', val='TRANSLATE', fn=set_int, default=1, @@ -1147,6 +1151,8 @@ def make_config(vals): config.append(['localtime', vals.localtime]) if vals.oos: config.append(['oos', vals.oos]) + if vals.pool: + config.append(['pool_name', vals.pool]) config_image = configure_image(vals) if vals.bootloader: diff -r 96715cf158e5 -r 3fd2342debf1 tools/python/xen/xm/main.py --- a/tools/python/xen/xm/main.py Wed Apr 21 12:49:41 2010 +0100 +++ b/tools/python/xen/xm/main.py Wed Apr 21 12:50:32 2010 +0100 @@ -56,6 +56,7 @@ import xen.util.xsm.xsm as security import xen.util.xsm.xsm as security from xen.util.xsm.xsm import XSMError from xen.util.acmpolicy import ACM_LABEL_UNLABELED_DISPLAY +from xen.util.sxputils import sxp2map, map2sxp as map_to_sxp from xen.util import auxbin import XenAPI @@ -238,6 +239,23 @@ SUBCOMMAND_HELP = { 'tmem-freeable' : ('', 'Print freeable tmem (in MiB).'), 'tmem-shared-auth' : ('[<Domain>|-a|--all] [--uuid=<uuid>] [--auth=<0|1>]', 'De/authenticate shared tmem pool.'), + # + # pool commands + # + 'pool-create' : ('<ConfigFile> [vars]', + 'Create a CPU pool based an ConfigFile.'), + 'pool-new' : ('<ConfigFile> [vars]', + 'Adds a CPU pool to Xend CPU pool management'), + 'pool-start' : ('<CPU Pool>', 'Starts a Xend CPU pool'), + 'pool-list' : ('[<CPU Pool>] [-l|--long] [-c|--cpus]', 'List CPU pools on host'), + 'pool-destroy' : ('<CPU Pool>', 'Deactivates a CPU pool'), + 'pool-delete' : ('<CPU Pool>', + 'Removes a CPU pool from Xend management'), + 'pool-cpu-add' : ('<CPU Pool> <CPU nr>', 'Adds a CPU to a CPU pool'), + 'pool-cpu-remove': ('<CPU Pool> <CPU nr>', 'Removes a CPU from a CPU pool'), + 'pool-migrate' : ('<Domain> <CPU Pool>', + 'Moves a domain into a CPU pool'), + # security 'addlabel' : ('<label> {dom <ConfigFile>|res <resource>|mgt <managed domain>} [<policy>]', @@ -288,6 +306,7 @@ SUBCOMMAND_OPTIONS = { ('-l', '--long', 'Output all VM details in SXP'), ('', '--label', 'Include security labels'), ('', '--state=<state>', 'Select only VMs with the specified state'), + ('', '--pool=<pool>', 'Select only VMs in specified cpu pool'), ), 'console': ( ('-q', '--quiet', 'Do not print an error message if the domain does not exist'), @@ -349,6 +368,10 @@ SUBCOMMAND_OPTIONS = { ('-u', '--uuid', 'Specify uuid (abcdef01-2345-6789-01234567890abcdef).'), ('-A', '--auth', '0=auth,1=deauth'), ), + 'pool-list': ( + ('-l', '--long', 'Output all CPU pool details in SXP format'), + ('-c', '--cpus', 'Output list of CPUs used by a pool'), + ), } common_commands = [ @@ -494,9 +517,21 @@ tmem_commands = [ "tmem-shared-auth", ] +pool_commands = [ + "pool-create", + "pool-new", + "pool-start", + "pool-list", + "pool-destroy", + "pool-delete", + "pool-cpu-add", + "pool-cpu-remove", + "pool-migrate", + ] + all_commands = (domain_commands + host_commands + scheduler_commands + device_commands + vnet_commands + security_commands + - acm_commands + flask_commands + tmem_commands + + acm_commands + flask_commands + tmem_commands + pool_commands + ['shell', 'event-monitor']) @@ -890,7 +925,7 @@ def datetime_to_secs(v): v = str(v).replace(c, "") return time.mktime(time.strptime(v[0:14], '%Y%m%dT%H%M%S')) -def getDomains(domain_names, state, full = 0): +def getDomains(domain_names, state, full = 0, pool = None): if serverType == SERVER_XEN_API: doms_sxp = [] doms_dict = [] @@ -899,6 +934,9 @@ def getDomains(domain_names, state, full dom_metrics_recs = server.xenapi.VM_metrics.get_all_records() for dom_ref, dom_rec in dom_recs.items(): + if pool and pool != dom_rec['pool_name']: + continue + dom_metrics_rec = dom_metrics_recs[dom_rec['metrics']] states = ('running', 'blocked', 'paused', 'shutdown', @@ -939,7 +977,15 @@ def getDomains(domain_names, state, full if domain_names: return [server.xend.domain(dom, full) for dom in domain_names] else: - return server.xend.domains_with_state(True, state, full) + doms = server.xend.domains_with_state(True, state, full) + if not pool: + return doms + else: + doms_in_pool = [] + for dom in doms: + if sxp.child_value(dom, 'pool_name', '') == pool: + doms_in_pool.append(dom) + return doms_in_pool def xm_list(args): @@ -947,10 +993,11 @@ def xm_list(args): show_vcpus = 0 show_labels = 0 state = 'all' + pool = None try: (options, params) = getopt.gnu_getopt(args, 'lv', ['long','vcpus','label', - 'state=']) + 'state=','pool=']) except getopt.GetoptError, opterr: err(opterr) usage('list') @@ -964,10 +1011,16 @@ def xm_list(args): show_labels = 1 if k in ['--state']: state = v + if k in ['--pool']: + pool = v if state != 'all' and len(params) > 0: raise OptionError( "You may specify either a state or a particular VM, but not both") + + if pool and len(params) > 0: + raise OptionError( + "You may specify either a pool or a particular VM, but not both") if show_vcpus: print >>sys.stderr, ( @@ -975,7 +1028,7 @@ def xm_list(args): xm_vcpu_list(params) return - doms = getDomains(params, state, use_long) + doms = getDomains(params, state, use_long, pool) if use_long: map(PrettyPrint.prettyprint, doms) @@ -1890,6 +1943,13 @@ def xm_info(args): else: return "" + def getFreeCpuCount(): + cnt = 0 + for host_cpu_record in host_cpu_records: + if len(host_cpu_record.get("cpu_pool", [])) == 0: + cnt += 1 + return cnt + info = { "host": getVal(["name_label"]), "release": getVal(["software_version", "release"]), @@ -1901,6 +1961,7 @@ def xm_info(args): "threads_per_core": getVal(["cpu_configuration", "threads_per_core"]), "cpu_mhz": getCpuMhz(), "hw_caps": getCpuFeatures(), + "free_cpus": getFreeCpuCount(), "total_memory": int(host_metrics_record["memory_total"])/1024/1024, "free_memory": int(host_metrics_record["memory_free"])/1024/1024, "xen_major": getVal(["software_version", "xen_major"]), @@ -3528,6 +3589,169 @@ def xm_tmem_shared_auth(args): return server.xenapi.host.tmem_shared_auth(domid,uuid_str,auth) else: return server.xend.node.tmem_shared_auth(domid,uuid_str,auth) + +def get_pool_ref(name): + refs = server.xenapi.cpu_pool.get_by_name_label(name) + if len(refs) > 0: + return refs[0] + else: + err('unknown pool name') + sys.exit(1) + +def xm_pool_start(args): + arg_check(args, "pool-start", 1) + if serverType == SERVER_XEN_API: + ref = get_pool_ref(args[0]) + server.xenapi.cpu_pool.activate(ref) + else: + server.xend.cpu_pool.start(args[0]) + +def brief_pool_list(sxprs): + format_str = "%-16s %3s %8s %s %s" + for sxpr in sxprs: + if sxpr == sxprs[0]: + print "Name CPUs Sched Active Domain count" + record = sxp2map(sxpr) + name = record['name_label'] + sched_policy = record['sched_policy'] + if record['activated']: + cpus = record.get('host_CPU_numbers', []) + vms = record.get('started_VM_names', []) + if not isinstance(cpus, types.ListType): + cpus = [cpus] + if not isinstance(vms, types.ListType): + vms = [vms] + cpu_count = len(cpus) + vm_count = len(vms) + active = 'y' + else: + cpu_count = record['ncpu'] + vm_count = 0 + active = 'n' + print format_str % (name, cpu_count, sched_policy, active, vm_count) + +def brief_pool_list_cpus(sxprs): + format_str = "%-16s %s" + for sxpr in sxprs: + if sxpr == sxprs[0]: + print format_str % ("Name", "CPU list") + record = sxp2map(sxpr) + name = record['name_label'] + cpus = "" + if record['activated']: + cpus = record.get('host_CPU_numbers', []) + if isinstance(cpus, types.ListType): + cpus.sort() + cpus = reduce(lambda x,y: x + "%s," % y, cpus, "") + cpus = cpus[0:len(cpus)-1] + else: + cpus = str(cpus) + if len(cpus) == 0: + cpus = "-" + print format_str % (name, cpus) + +def xm_pool_list(args): + arg_check(args, "pool-list", 0, 2) + try: + (options, params) = getopt.gnu_getopt(args, 'lc', ['long','cpus']) + except getopt.GetoptError, opterr: + err(opterr) + usage('pool-list') + if len(params) > 1: + err("Only one pool name for selection allowed") + usage('pool-list') + + use_long = False + show_cpus = False + for (k, _) in options: + if k in ['-l', '--long']: + use_long = True + if k in ['-c', '--cpus']: + show_cpus = True + + if serverType == SERVER_XEN_API: + pools = server.xenapi.cpu_pool.get_all_records() + cpu_recs = server.xenapi.host_cpu.get_all_records() + sxprs = [] + for pool in pools.values(): + if pool['name_label'] in params or len(params) == 0: + started_VM_names = [['started_VM_names'] + [ + server.xenapi.VM.get_name_label(started_VM) + for started_VM in pool['started_VMs'] ] ] + host_CPU_numbers = [['host_CPU_numbers'] + [ + cpu_recs[cpu_ref]['number'] + for cpu_ref in pool['host_CPUs'] ] ] + sxpr = [ pool['uuid'] ] + map_to_sxp(pool) + \ + host_CPU_numbers + started_VM_names + sxprs.append(sxpr) + else: + sxprs = server.xend.cpu_pool.list(params) + + if len(params) > 0 and len(sxprs) == 0: + # pool not found + err("Pool '%s' does not exist." % params[0]) + + if use_long: + for sxpr in sxprs: + PrettyPrint.prettyprint(sxpr) + elif show_cpus: + brief_pool_list_cpus(sxprs) + else: + brief_pool_list(sxprs) + +def xm_pool_destroy(args): + arg_check(args, "pool-destroy", 1) + if serverType == SERVER_XEN_API: + ref = get_pool_ref(args[0]) + server.xenapi.cpu_pool.deactivate(ref) + else: + server.xend.cpu_pool.destroy(args[0]) + +def xm_pool_delete(args): + arg_check(args, "pool-delete", 1) + if serverType == SERVER_XEN_API: + ref = get_pool_ref(args[0]) + server.xenapi.cpu_pool.destroy(ref) + else: + server.xend.cpu_pool.delete(args[0]) + +def xm_pool_cpu_add(args): + arg_check(args, "pool-cpu-add", 2) + if serverType == SERVER_XEN_API: + ref = get_pool_ref(args[0]) + cpu_ref_list = server.xenapi.host_cpu.get_all_records() + cpu_ref = [ c_rec['uuid'] for c_rec in cpu_ref_list.values() + if c_rec['number'] == args[1] ] + if len(cpu_ref) == 0: + err('cpu number unknown') + else: + server.xenapi.cpu_pool.add_host_CPU_live(ref, cpu_ref[0]) + else: + server.xend.cpu_pool.cpu_add(args[0], args[1]) + +def xm_pool_cpu_remove(args): + arg_check(args, "pool-cpu-remove", 2) + if serverType == SERVER_XEN_API: + ref = get_pool_ref(args[0]) + cpu_ref_list = server.xenapi.host_cpu.get_all_records() + cpu_ref = [ c_rec['uuid'] for c_rec in cpu_ref_list.values() + if c_rec['number'] == args[1] ] + if len(cpu_ref) == 0: + err('cpu number unknown') + else: + server.xenapi.cpu_pool.remove_host_CPU_live(ref, cpu_ref[0]) + else: + server.xend.cpu_pool.cpu_remove(args[0], args[1]) + +def xm_pool_migrate(args): + arg_check(args, "pool-migrate", 2) + domname = args[0] + poolname = args[1] + if serverType == SERVER_XEN_API: + pool_ref = get_pool_ref(poolname) + server.xenapi.VM.cpu_pool_migrate(get_single_vm(domname), pool_ref) + else: + server.xend.cpu_pool.migrate(domname, poolname) commands = { @@ -3615,6 +3839,14 @@ commands = { "usb-list-assignable-devices": xm_usb_list_assignable_devices, "usb-hc-create": xm_usb_hc_create, "usb-hc-destroy": xm_usb_hc_destroy, + # pool + "pool-start": xm_pool_start, + "pool-list": xm_pool_list, + "pool-destroy": xm_pool_destroy, + "pool-delete": xm_pool_delete, + "pool-cpu-add": xm_pool_cpu_add, + "pool-cpu-remove": xm_pool_cpu_remove, + "pool-migrate": xm_pool_migrate, # tmem "tmem-thaw": xm_tmem_thaw, "tmem-freeze": xm_tmem_freeze, @@ -3646,6 +3878,8 @@ IMPORTED_COMMANDS = [ 'resetpolicy', 'getenforce', 'setenforce', + 'pool-create', + 'pool-new', ] for c in IMPORTED_COMMANDS: diff -r 96715cf158e5 -r 3fd2342debf1 tools/python/xen/xm/pool-create.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/python/xen/xm/pool-create.py Wed Apr 21 12:50:32 2010 +0100 @@ -0,0 +1,51 @@ +#============================================================================ +# 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 +#============================================================================ + +""" Create a new unmanaged pool. +""" + +import sys +from xen.xm.main import serverType, SERVER_XEN_API, server +from xen.xm.pool import parseCommandLine, err, help as help_options +from xen.util.sxputils import sxp2map + +def help(): + return help_options() + + +def main(argv): + try: + (opts, config) = parseCommandLine(argv) + except StandardError, ex: + err(str(ex)) + + if not opts: + return + + if serverType == SERVER_XEN_API: + record = sxp2map(config) + if type(record.get('proposed_CPUs', [])) != list: + record['proposed_CPUs'] = [record['proposed_CPUs']] + ref = server.xenapi.cpu_pool.create(record) + if ref: + server.xenapi.cpu_pool.activate(ref) + else: + server.xend.cpu_pool.create(config) + +if __name__ == '__main__': + main(sys.argv) + diff -r 96715cf158e5 -r 3fd2342debf1 tools/python/xen/xm/pool-new.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/python/xen/xm/pool-new.py Wed Apr 21 12:50:32 2010 +0100 @@ -0,0 +1,50 @@ +#============================================================================ +# 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 +#============================================================================ + +""" Create a new managed pool. +""" + +import sys +from xen.xm.main import serverType, SERVER_XEN_API, server +from xen.xm.pool import parseCommandLine, err, help as help_options +from xen.util.sxputils import sxp2map + + +def help(): + return help_options() + + +def main(argv): + try: + (opts, config) = parseCommandLine(argv) + except StandardError, ex: + err(str(ex)) + + if not opts: + return + + if serverType == SERVER_XEN_API: + record = sxp2map(config) + if type(record.get('proposed_CPUs', [])) != list: + record['proposed_CPUs'] = [record['proposed_CPUs']] + server.xenapi.cpu_pool.create(record) + else: + server.xend.cpu_pool.new(config) + +if __name__ == '__main__': + main(sys.argv) + diff -r 96715cf158e5 -r 3fd2342debf1 tools/python/xen/xm/pool.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/python/xen/xm/pool.py Wed Apr 21 12:50:32 2010 +0100 @@ -0,0 +1,236 @@ +#============================================================================ +# 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 +#============================================================================ + +""" Common function of cmds pool-new / pool-create. +""" + +import sys +import types +import os + +from xen.xend import PrettyPrint +from xen.xend import sxp + +from xen.xm.opts import Opts, set_value, set_true, append_value, OptionError + +GOPTS = Opts(use="""[options] [vars] + +Create a pool. + +Pool creation parameters can be set by command-line switches, from +a python configuration script or an SXP config file. See documentation +for --defconfig, --config. Configuration variables can be set using +VAR=VAL on the command line. For example name=Pool-1 sets name to Pool-1. + +""") + +GOPTS.opt('help', short='h', + fn=set_true, default=0, + use="Print this help.") + +GOPTS.opt('help_config', + fn=set_true, default=0, + use="Print the available configuration variables (vars) for the " + "configuration script.") + +GOPTS.opt('path', val='PATH', + fn=set_value, default='.:/etc/xen/pool', + use="Search path for configuration scripts. " + "The value of PATH is a colon-separated directory list.") + +GOPTS.opt('defconfig', short='f', val='FILE', + fn=set_value, default='xmdefconfig', + use="Use the given Python configuration script." + "The configuration script is loaded after arguments have been " + "processed. Each command-line option sets a configuration " + "variable named after its long option name, and these " + "variables are placed in the environment of the script before " + "it is loaded. Variables for options that may be repeated have " + "list values. Other variables can be set using VAR=VAL on the " + "command line. " + "After the script is loaded, option values that were not set " + "on the command line are replaced by the values set in the script.") + +GOPTS.default('defconfig') + +GOPTS.opt('config', short='F', val='FILE', + fn=set_value, default=None, + use="CPU pool configuration to use (SXP).\n" + "SXP is the underlying configuration format used by Xen.\n" + "SXP configurations can be hand-written or generated from Python " + "configuration scripts, using the -n (dryrun) option to print " + "the configuration.") + +GOPTS.opt('dryrun', short='n', + fn=set_true, default=0, + use="Dry run - prints the resulting configuration in SXP but " + "does not create the CPU pool.") + +GOPTS.var('name', val='NAME', fn=set_value, default=None, + use="CPU pool name.") + +GOPTS.var('sched', val='SCHED', fn=set_value, default='credit', + use="Scheduler to use for the CPU pool.") + +GOPTS.var('cpus', val='CPUS', fn=set_value, default=1, + use="CPUS to assign to the CPU pool.") + +GOPTS.var('other_config', val='OTHER_CONFIG', fn=append_value, default=[], + use="Additional info for CPU pool") + + +def sxp2map(sxp_val): + record = {} + for x in sxp_val: + if isinstance(x, (types.ListType, types.TupleType)) \ + and len(x) > 1: + if isinstance(x[1], (types.ListType, types.TupleType)): + record[x[0]] = sxp2map(x[1]) + else: + record[x[0]] = x[1] + return record + +def err(msg): + print >> sys.stderr, "Error: %s" % msg + sys.exit(-1) + +def make_cpus_config(cfg_cpus): + """ Taken from XendConfig. """ + # Convert 'cpus' to list of list of ints + + cpus_list = [] + # Convert the following string to list of ints. + # The string supports a list of ranges (0-3), + # seperated by commas, and negation (^1). + # Precedence is settled by order of the string: + # "0-3,^1" -> [0,2,3] + # "0-3,^1,1" -> [0,1,2,3] + def cnv(s): + l = [] + for c in s.split(','): + if c.find('-') != -1: + (x, y) = c.split('-') + for i in range(int(x), int(y)+1): + l.append(int(i)) + else: + # remove this element from the list + if len(c) > 0: + if c[0] == '^': + l = [x for x in l if x != int(c[1:])] + else: + l.append(int(c)) + return l + + if type(cfg_cpus) == list: + if len(cfg_cpus) > 0 and type(cfg_cpus[0]) == list: + # If sxp_cfg was created from config.sxp, + # the form of 'cpus' is list of list of string. + # Convert 'cpus' to list of list of ints. + # Conversion examples: + # [['1']] -> [[1]] + # [['0','2'],['1','3']] -> [[0,2],[1,3]] + try: + for c1 in cfg_cpus: + cpus = [] + for c2 in c1: + cpus.append(int(c2)) + cpus_list.append(cpus) + except ValueError, e: + raise err('cpus = %s: %s' % (cfg_cpus, e)) + else: + # Conversion examples: + # ["1"] -> [[1]] + # ["0,2","1,3"] -> [[0,2],[1,3]] + # ["0-3,^1","1-4,^2"] -> [[0,2,3],[1,3,4]] + try: + for c in cfg_cpus: + cpus = cnv(c) + cpus_list.append(cpus) + except ValueError, e: + raise err('cpus = %s: %s' % (cfg_cpus, e)) + else: + # Conversion examples: + # cpus=1: + # "1" -> [[1]] + # "0-3,^1" -> [[0,2,3]] + # cpus=2: + # "1" -> [[1],[1]] + # "0-3,^1" -> [[0,2,3],[0,2,3]] + try: + cpus_list = cnv(cfg_cpus) + except ValueError, e: + err('cpus = %s: %s' % (cfg_cpus, e)) + return cpus_list + +def make_config(vals): + config = ['pool'] + config += [['name_label', vals.name]] + config += [['sched_policy', vals.sched]] + if type(vals.cpus) == int: + config += [['ncpu', vals.cpus], ['proposed_CPUs' , []]] + elif type(vals.cpus) == str and len(vals.cpus) > 1 and vals.cpus[0] == '#': + try: + config += [['ncpu', int(vals.cpus[1:])], ['proposed_CPUs' , []]] + except ValueError, ex: + err('Wrong illegal of parameter "cpus"') + else: + prop_cpus = make_cpus_config(vals.cpus) + config += [['ncpu', len(prop_cpus)], + ['proposed_CPUs'] + prop_cpus] + other_config = [] + for entry in vals.other_config: + if '=' in entry: + (var, val) = entry.strip().split('=', 1) + other_config.append([var, val]) + config += [['other_config'] + other_config] + return config + +def parseCommandLine(argv): + GOPTS.reset() + args = GOPTS.parse(argv) + + if GOPTS.vals.help or GOPTS.vals.help_config: + if GOPTS.vals.help_config: + print GOPTS.val_usage() + return (None, None) + + # Process remaining args as config variables. + for arg in args: + if '=' in arg: + (var, val) = arg.strip().split('=', 1) + GOPTS.setvar(var.strip(), val.strip()) + if GOPTS.vals.config: + try: + config = sxp.parse(file(GOPTS.vals.config))[0] + except IOError, ex: + raise OptionError("Cannot read file %s: %s" % (config, ex[1])) + else: + GOPTS.load_defconfig() + if not GOPTS.getopt('name') and GOPTS.getopt('defconfig'): + GOPTS.setopt('name', os.path.basename( + GOPTS.getopt('defconfig'))) + config = make_config(GOPTS.vals) + + if GOPTS.vals.dryrun: + PrettyPrint.prettyprint(config) + return (None, None) + + return (GOPTS, config) + +def help(): + return str(GOPTS) + diff -r 96715cf158e5 -r 3fd2342debf1 tools/python/xen/xm/xenapi_create.py --- a/tools/python/xen/xm/xenapi_create.py Wed Apr 21 12:49:41 2010 +0100 +++ b/tools/python/xen/xm/xenapi_create.py Wed Apr 21 12:50:32 2010 +0100 @@ -310,6 +310,8 @@ class xenapi_create: get_child_nodes_as_dict(vm, "platform", "key", "value"), "other_config": get_child_nodes_as_dict(vm, "other_config", "key", "value"), + "pool_name": + vm.attributes["pool_name"].value, "PV_bootloader": "", "PV_kernel": @@ -696,6 +698,8 @@ class sxp2xml: = str(get_child_by_name(config, "s3_integrity", 0)) vm.attributes["superpages"] \ = str(get_child_by_name(config, "superpages", 0)) + vm.attributes["pool_name"] \ + = str(get_child_by_name(config, "pool_name", "Pool-0")) sec_data = get_child_by_name(config, "security") if sec_data: _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |