[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [RFC 2/2] Domain Groups - Tools Support
diffstat domgrps-tools.patch examples/Makefile | 1 examples/xmexample.grp | 21 + libxc/Makefile | 1 libxc/xc_domain.c | 4 libxc/xc_domain_group.c | 100 +++++++++ libxc/xc_private.h | 31 ++ libxc/xenctrl.h | 31 ++ python/xen/lowlevel/xc/xc.c | 241 ++++++++++++++++++++-- python/xen/xend/XendCheckpoint.py | 54 ++++- python/xen/xend/XendClient.py | 1 python/xen/xend/XendConfig.py | 27 ++ python/xen/xend/XendConstants.py | 11 + python/xen/xend/XendDomain.py | 15 + python/xen/xend/XendDomainGroup.py | 347 +++++++++++++++++++++++++++++++++ python/xen/xend/XendDomainGroupInfo.py | 238 ++++++++++++++++++++++ python/xen/xend/XendDomainInfo.py | 37 ++- python/xen/xend/XendError.py | 4 python/xen/xend/server/XMLRPCServer.py | 34 ++- python/xen/xm/create.py | 8 python/xen/xm/group.py | 275 ++++++++++++++++++++++++++ python/xen/xm/main.py | 166 +++++++++++++++ 21 files changed, 1595 insertions(+), 52 deletions(-) diff -urN xen-unstable/tools/examples/Makefile xen-unstable-trp-domgrps-rebase-tip/tools/examples/Makefile --- xen-unstable/tools/examples/Makefile 2007-08-06 17:59:51.000000000 -0400 +++ xen-unstable-trp-domgrps-rebase-tip/tools/examples/Makefile 2007-11-19 18:42:00.000000000 -0500 @@ -16,6 +16,7 @@ XEN_CONFIGS += xmexample2 XEN_CONFIGS += xmexample.hvm XEN_CONFIGS += xmexample.vti +XEN_CONFIGS += xmexample.grp XEN_CONFIGS += xend-pci-quirks.sxp XEN_CONFIGS += xend-pci-permissive.sxp diff -urN xen-unstable/tools/examples/xmexample.grp xen-unstable-trp-domgrps-rebase-tip/tools/examples/xmexample.grp --- xen-unstable/tools/examples/xmexample.grp 1969-12-31 19:00:00.000000000 -0500 +++ xen-unstable-trp-domgrps-rebase-tip/tools/examples/xmexample.grp 2007-11-19 18:42:00.000000000 -0500 @@ -0,0 +1,21 @@ +################################################################################ +# +# Defines a group of domains +# +################################################################################ +# grp_name must be unique (within the scope of a xend instance) +# +# member_list contains names and paths to configuration files for each +# member of the domain group +# +# Note: The domain name in member_list must match the 'name' attribute in the +# corresponding VM configuration file. +################################################################################ + +(grp_name "TestGroup") + +(member_list + ('fc5-1:/etc/xen/vmconfig-1' + 'fc5-2:/etc/xen/vmconfig-2' + 'fc5-3:/etc/xen/vmconfig-3') +) diff -urN xen-unstable/tools/libxc/Makefile xen-unstable-trp-domgrps-rebase-tip/tools/libxc/Makefile --- xen-unstable/tools/libxc/Makefile 2007-12-17 16:45:04.000000000 -0500 +++ xen-unstable-trp-domgrps-rebase-tip/tools/libxc/Makefile 2007-12-17 16:09:54.000000000 -0500 @@ -10,6 +10,7 @@ CTRL_SRCS-$(CONFIG_IA64) += xc_core_ia64.c CTRL_SRCS-$(CONFIG_POWERPC) += xc_core_powerpc.c CTRL_SRCS-y += xc_domain.c +CTRL_SRCS-y += xc_domain_group.c CTRL_SRCS-y += xc_evtchn.c CTRL_SRCS-y += xc_misc.c CTRL_SRCS-y += xc_acm.c diff -urN xen-unstable/tools/libxc/xc_domain.c xen-unstable-trp-domgrps-rebase-tip/tools/libxc/xc_domain.c --- xen-unstable/tools/libxc/xc_domain.c 2007-12-17 16:45:04.000000000 -0500 +++ xen-unstable-trp-domgrps-rebase-tip/tools/libxc/xc_domain.c 2007-12-17 16:09:54.000000000 -0500 @@ -197,6 +197,7 @@ info->crashed = 1; } + info->grpid = domctl.u.getdomaininfo.group; info->ssidref = domctl.u.getdomaininfo.ssidref; info->nr_pages = domctl.u.getdomaininfo.tot_pages; info->max_memkb = domctl.u.getdomaininfo.max_pages << (PAGE_SHIFT-10); @@ -208,6 +209,9 @@ memcpy(info->handle, domctl.u.getdomaininfo.handle, sizeof(xen_domain_handle_t)); + memcpy(info->dg_handle, domctl.u.getdomaininfo.dg_handle, + sizeof(xen_domain_group_handle_t)); + next_domid = (uint16_t)domctl.domain + 1; info++; } diff -urN xen-unstable/tools/libxc/xc_domain_group.c xen-unstable-trp-domgrps-rebase-tip/tools/libxc/xc_domain_group.c --- xen-unstable/tools/libxc/xc_domain_group.c 1969-12-31 19:00:00.000000000 -0500 +++ xen-unstable-trp-domgrps-rebase-tip/tools/libxc/xc_domain_group.c 2007-11-19 18:42:00.000000000 -0500 @@ -0,0 +1,100 @@ +/****************************************************************************** + * xc_domain_group.c + * + * API for manipulating and obtaining information on domain groups. + * + * Chris Bookholt (hap10@xxxxxxxxxxxxxx) + */ + +#include "xc_private.h" +#include <xen/memory.h> + +int xc_domain_group_create(int xc_handle, + xen_domain_group_handle_t handle, + uint32_t *pdgid) +{ + int err; + DECLARE_DOMGRPCTL; + domgrpctl.cmd = XEN_DOMGRPCTL_creategrp; + memcpy(domgrpctl.u.create_grp.handle, handle, + sizeof(xen_domain_group_handle_t)); + + err = do_domgrpctl(xc_handle, &domgrpctl); + if (err) + return err; + + *pdgid = (uint16_t)domgrpctl.u.get_grp_info.dgid; + return 0; +} + +int xc_domain_group_pause(int xc_handle, uint32_t dgid) +{ + DECLARE_DOMGRPCTL; + domgrpctl.cmd = XEN_DOMGRPCTL_pausegrp; + domgrpctl.u.pause_grp.dgid = (dgid_t) dgid; + return do_domgrpctl(xc_handle, &domgrpctl); +} + +int xc_domain_group_unpause(int xc_handle, uint32_t dgid) +{ + DECLARE_DOMGRPCTL; + domgrpctl.cmd = XEN_DOMGRPCTL_unpausegrp; + domgrpctl.u.unpause_grp.dgid = (dgid_t) dgid; + return do_domgrpctl(xc_handle, &domgrpctl); +} + +int xc_domain_group_destroy(int xc_handle, uint32_t dgid) +{ + DECLARE_DOMGRPCTL; + domgrpctl.cmd = XEN_DOMGRPCTL_destroygrp; + domgrpctl.u.destroy_grp.dgid = (dgid_t) dgid; + return do_domgrpctl(xc_handle, &domgrpctl); +} + +int xc_domain_group_join(int xc_handle, uint32_t domid, uint32_t dgid) +{ + DECLARE_DOMGRPCTL; + domgrpctl.cmd = XEN_DOMGRPCTL_joingrp; + domgrpctl.u.join_grp.domid = (domid_t) domid; + domgrpctl.u.join_grp.dgid = (dgid_t) dgid; + return do_domgrpctl(xc_handle, &domgrpctl); +} + +#define TRANSFER_LIST_TO_INFO(list_name) \ + memcpy(info->list_name, domgrpctl.u.get_grp_info.list_name, \ + MAX_GROUP_SIZE*sizeof(domid_t)); + +int xc_domain_group_getinfo(int xc_handle, uint32_t first_dgid, + unsigned int max_grps, xc_grpinfo_t * info) +{ + unsigned int nr_grps; + uint32_t next_dgid = first_dgid; + DECLARE_DOMGRPCTL; + int rc = 0; + + memset(info, 0, max_grps * sizeof(xc_grpinfo_t)); + + for (nr_grps = 0; nr_grps < max_grps; nr_grps++) { + domgrpctl.cmd = XEN_DOMGRPCTL_getgrpinfo; + domgrpctl.u.get_grp_info.dgid = (dgid_t) next_dgid; + + rc = do_domgrpctl(xc_handle, &domgrpctl); + if (rc < 0) + break; + + info->dgid = (uint16_t) domgrpctl.u.get_grp_info.dgid; + info->size = (uint16_t) domgrpctl.u.get_grp_info.size; + + TRANSFER_LIST_TO_INFO(member_list); + memcpy(info->handle, domgrpctl.u.get_grp_info.handle, + sizeof(xen_domain_group_handle_t)); + + next_dgid = (uint16_t) domgrpctl.u.get_grp_info.dgid + 1; + info++; + } + + if (!nr_grps) + return rc; + + return nr_grps; +} diff -urN xen-unstable/tools/libxc/xc_private.h xen-unstable-trp-domgrps-rebase-tip/tools/libxc/xc_private.h --- xen-unstable/tools/libxc/xc_private.h 2007-11-19 10:38:07.000000000 -0500 +++ xen-unstable-trp-domgrps-rebase-tip/tools/libxc/xc_private.h 2007-11-19 18:42:00.000000000 -0500 @@ -23,10 +23,12 @@ #ifdef VALGRIND #define DECLARE_HYPERCALL privcmd_hypercall_t hypercall = { 0 } #define DECLARE_DOMCTL struct xen_domctl domctl = { 0 } +#define DECLARE_DOMGRPCTL struct xen_domgrpctl domgrpctl = { 0 } #define DECLARE_SYSCTL struct xen_sysctl sysctl = { 0 } #else #define DECLARE_HYPERCALL privcmd_hypercall_t hypercall #define DECLARE_DOMCTL struct xen_domctl domctl +#define DECLARE_DOMGRPCTL struct xen_domgrpctl domgrpctl #define DECLARE_SYSCTL struct xen_sysctl sysctl #endif @@ -125,6 +127,35 @@ return ret; } +static inline int do_domgrpctl(int xc_handle, struct xen_domgrpctl *domgrpctl) +{ + int ret = -1; + DECLARE_HYPERCALL; + + domgrpctl->interface_version = XEN_DOMGRPCTL_INTERFACE_VERSION; + + hypercall.op = __HYPERVISOR_domgrpctl; + hypercall.arg[0] = (unsigned long)domgrpctl; + + if ( mlock(domgrpctl, sizeof(*domgrpctl)) != 0 ) + { + PERROR("Could not lock memory for Xen hypercall"); + goto out1; + } + + if ( (ret = do_xen_hypercall(xc_handle, &hypercall)) < 0 ) + { + if ( errno == EACCES ) + DPRINTF("domgrpctl operation failed -- need to" + " rebuild the user-space tool set?\n"); + } + + safe_munlock(domgrpctl, sizeof(*domgrpctl)); + + out1: + return ret; +} + static inline int do_sysctl(int xc_handle, struct xen_sysctl *sysctl) { int ret = -1; diff -urN xen-unstable/tools/libxc/xenctrl.h xen-unstable-trp-domgrps-rebase-tip/tools/libxc/xenctrl.h --- xen-unstable/tools/libxc/xenctrl.h 2007-12-17 16:45:04.000000000 -0500 +++ xen-unstable-trp-domgrps-rebase-tip/tools/libxc/xenctrl.h 2007-12-17 16:09:54.000000000 -0500 @@ -21,6 +21,7 @@ #include <stdint.h> #include <xen/xen.h> #include <xen/domctl.h> +#include <xen/domgrpctl.h> #include <xen/sysctl.h> #include <xen/version.h> #include <xen/event_channel.h> @@ -151,6 +152,7 @@ typedef struct xc_dominfo { uint32_t domid; + uint32_t grpid; uint32_t ssidref; unsigned int dying:1, crashed:1, shutdown:1, paused:1, blocked:1, running:1, @@ -163,8 +165,16 @@ unsigned int nr_online_vcpus; unsigned int max_vcpu_id; xen_domain_handle_t handle; + xen_domain_group_handle_t dg_handle; } xc_dominfo_t; +typedef struct{ + dgid_t dgid; + uint16_t size; + domid_t member_list[MAX_GROUP_SIZE]; + xen_domain_group_handle_t handle; +} xc_grpinfo_t; + typedef xen_domctl_getdomaininfo_t xc_domaininfo_t; int xc_domain_create(int xc_handle, uint32_t ssidref, @@ -298,6 +308,27 @@ unsigned int max_doms, xc_dominfo_t *info); +int xc_domain_group_getinfo(int xc_handle, + uint32_t first_dgid, + unsigned int max_grps, + xc_grpinfo_t *info); + +int xc_domain_group_create(int xc_handle, + xen_domain_group_handle_t handle, + uint32_t *pdgid); + +int xc_domain_group_pause(int xc_handle, + uint32_t dgid); + +int xc_domain_group_unpause(int xc_handle, + uint32_t dgid); + +int xc_domain_group_destroy(int xc_handle, + uint32_t dgid); + +int xc_domain_group_join(int xc_handle, + uint32_t domid, + uint32_t dgid); /** * This function will set the execution context for the specified vcpu. diff -urN xen-unstable/tools/python/xen/lowlevel/xc/xc.c xen-unstable-trp-domgrps-rebase-tip/tools/python/xen/lowlevel/xc/xc.c --- xen-unstable/tools/python/xen/lowlevel/xc/xc.c 2007-12-17 16:45:04.000000000 -0500 +++ xen-unstable-trp-domgrps-rebase-tip/tools/python/xen/lowlevel/xc/xc.c 2007-12-17 16:09:54.000000000 -0500 @@ -40,10 +40,6 @@ int xc_handle; } XcObject; - -static PyObject *dom_op(XcObject *self, PyObject *args, - int (*fn)(int, uint32_t)); - static PyObject *pyxc_error_to_exception(void) { PyObject *pyerr; @@ -69,6 +65,21 @@ return NULL; } +static PyObject *xc_op(XcObject *self, PyObject *args, + int (*fn)(int, uint32_t)) +{ + uint32_t id; /* used for both domid and grpid */ + + if (!PyArg_ParseTuple(args, "i", &id)) + return NULL; + + if (fn(self->xc_handle, id) != 0) + return pyxc_error_to_exception(); + + Py_INCREF(zero); + return zero; +} + static PyObject *pyxc_domain_dumpcore(XcObject *self, PyObject *args) { uint32_t dom; @@ -155,12 +166,12 @@ static PyObject *pyxc_domain_pause(XcObject *self, PyObject *args) { - return dom_op(self, args, xc_domain_pause); + return xc_op(self, args, xc_domain_pause); } static PyObject *pyxc_domain_unpause(XcObject *self, PyObject *args) { - return dom_op(self, args, xc_domain_unpause); + return xc_op(self, args, xc_domain_unpause); } static PyObject *pyxc_domain_destroy_hook(XcObject *self, PyObject *args) @@ -175,7 +186,7 @@ static PyObject *pyxc_domain_destroy(XcObject *self, PyObject *args) { - return dom_op(self, args, xc_domain_destroy); + return xc_op(self, args, xc_domain_destroy); } static PyObject *pyxc_domain_shutdown(XcObject *self, PyObject *args) @@ -296,7 +307,7 @@ PyObject *args, PyObject *kwds) { - PyObject *list, *info_dict, *pyhandle; + PyObject *list, *info_dict, *pyhandle, *pydg_handle; uint32_t first_dom = 0; int max_doms = 1024, nr_doms, i, j; @@ -324,8 +335,9 @@ { 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:i,s:L,s:L,s:L,s:i,s:i}", "domid", (int)info[i].domid, + "dgid", (int)info[i].grpid, "online_vcpus", info[i].nr_online_vcpus, "max_vcpu_id", info[i].max_vcpu_id, "hvm", info[i].hvm, @@ -341,6 +353,7 @@ "ssidref", (int)info[i].ssidref, "shutdown_reason", info[i].shutdown_reason); pyhandle = PyList_New(sizeof(xen_domain_handle_t)); + pydg_handle = PyList_New(sizeof(xen_domain_group_handle_t)); if ( (pyhandle == NULL) || (info_dict == NULL) ) { Py_DECREF(list); @@ -351,7 +364,10 @@ } for ( j = 0; j < sizeof(xen_domain_handle_t); j++ ) PyList_SetItem(pyhandle, j, PyInt_FromLong(info[i].handle[j])); + for ( j = 0; j < sizeof(xen_domain_group_handle_t); j++ ) + PyList_SetItem(pydg_handle, j, PyInt_FromLong(info[i].dg_handle[j])); PyDict_SetItemString(info_dict, "handle", pyhandle); + PyDict_SetItemString(info_dict, "dg_handle", pydg_handle); Py_DECREF(pyhandle); PyList_SetItem(list, i, info_dict); } @@ -1214,21 +1230,6 @@ return zero; } -static PyObject *dom_op(XcObject *self, PyObject *args, - int (*fn)(int, uint32_t)) -{ - uint32_t dom; - - if (!PyArg_ParseTuple(args, "i", &dom)) - return NULL; - - if (fn(self->xc_handle, dom) != 0) - return pyxc_error_to_exception(); - - Py_INCREF(zero); - return zero; -} - #ifdef __powerpc__ static PyObject *pyxc_alloc_real_mode_area(XcObject *self, PyObject *args, @@ -1251,6 +1252,148 @@ } #endif /* powerpc */ +#define EXTRACT_DOM_LIST(list_name, dict) \ + dom_list = PyList_New(0); \ + for ( j = 0; j < info[i].size; j++ ) \ + PyList_Append(dom_list, PyInt_FromLong(info[i].list_name[j]));\ + PyDict_SetItemString(dict, #list_name, dom_list); \ + Py_DECREF(dom_list); + +static PyObject *pyxc_domain_group_getinfo(XcObject *self, + PyObject *args, + PyObject *kwds) +{ + PyObject *list, *info_dict, *dom_list, *pyhandle; + + uint32_t first_grp = 0; + /* max_grps is unrealistically large and causes a large heap allocation + for the duration of this function that, in the vast majority of cases, + will be very sparsely populated with information about real groups. + + Leaving this alone for now to keep an equal limit on max number of + groups in both the VMM and the control stack. + + Could add a new case to the domain group control hypercall to return + the current number of groups instead of assuming the worst case... + */ + int max_grps = NULL_GROUP_ID+1, nr_grps, i, j; + xc_grpinfo_t *info; + + static char *kwd_list[] = { "first_grp", "max_grps", NULL }; + + /* pull values from python args */ + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwd_list, + &first_grp, &max_grps) ) + return NULL; + + /* alloc space for the group info and ask Xen (via libxc) for the info */ + if ( (info = malloc(max_grps * sizeof(xc_grpinfo_t))) == NULL ) + return PyErr_NoMemory(); + nr_grps = xc_domain_group_getinfo(self->xc_handle, first_grp, max_grps, + info); + + if (nr_grps < 0) { + free(info); + return PyErr_SetFromErrno(xc_error_obj); + } + + /* iterate over the returned groups and + put the returned values into python objects */ + list = PyList_New(nr_grps); + for ( i = 0 ; i < nr_grps; i++ ) { + /* extract group ID and size */ + info_dict = Py_BuildValue( + "{s:i,s:i}", + "dgid", info[i].dgid, + "size", info[i].size); + + EXTRACT_DOM_LIST(member_list, info_dict); + + /* extract the group's handle */ + pyhandle = PyList_New(sizeof(xen_domain_group_handle_t)); + for ( j = 0; j < sizeof(xen_domain_group_handle_t); j++ ) + PyList_SetItem(pyhandle, j, PyInt_FromLong(info[i].handle[j])); + PyDict_SetItemString(info_dict, "dg_handle", pyhandle); + Py_DECREF(pyhandle); + + PyList_SetItem(list, i, info_dict); + } + + free(info); + + return list; +} + +static PyObject *pyxc_domain_group_create(XcObject *self, + PyObject *args, + PyObject *kwds) +{ + uint32_t dgid = 0; + int i; + PyObject *pyhandle = NULL; + xen_domain_group_handle_t handle = { + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef }; + + static char *kwd_list[] = { "handle", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwd_list, + &pyhandle)) + return NULL; + + if ( pyhandle != NULL ) + { + if ( !PyList_Check(pyhandle) || + (PyList_Size(pyhandle) != sizeof(xen_domain_group_handle_t)) ) + goto out_exception; + + for ( i = 0; i < sizeof(xen_domain_group_handle_t); i++ ) + { + PyObject *p = PyList_GetItem(pyhandle, i); + if ( !PyInt_Check(p) ) + goto out_exception; + handle[i] = (uint8_t)PyInt_AsLong(p); + } + } else + goto out_exception; + + if ( (xc_domain_group_create(self->xc_handle, handle, &dgid)) < 0 ) + return PyErr_SetFromErrno(xc_error_obj); + + return PyInt_FromLong(dgid); + +out_exception: + errno = EINVAL; + PyErr_SetFromErrno(xc_error_obj); + return NULL; +} + +static PyObject *pyxc_domain_group_pause(XcObject *self, PyObject *args) +{ + return xc_op(self, args, xc_domain_group_pause); +} + +static PyObject *pyxc_domain_group_unpause(XcObject *self, PyObject *args) +{ + return xc_op(self, args, xc_domain_group_unpause); +} + +static PyObject *pyxc_domain_group_destroy(XcObject *self, PyObject *args) +{ + return xc_op(self, args, xc_domain_group_destroy); +} + +static PyObject *pyxc_domain_group_join(XcObject *self, PyObject *args) +{ + uint32_t dgid, domid; + if (!PyArg_ParseTuple(args, "ii", &domid, &dgid)) + return NULL; + if (xc_domain_group_join(self->xc_handle, domid, dgid) != 0) + return PyErr_SetFromErrno(xc_error_obj); + Py_INCREF(zero); + return zero; +} + static PyMethodDef pyxc_methods[] = { { "handle", (PyCFunction)pyxc_handle, @@ -1265,6 +1408,13 @@ " dom [int, 0]: Domain identifier to use (allocated if zero).\n" "Returns: [int] new domain identifier; -1 on error.\n" }, + { "domain_group_create", + (PyCFunction)pyxc_domain_group_create, + METH_VARARGS | METH_KEYWORDS, "\n" + "Create a new domain group.\n" + " grp [int, 0]: Domain group identifier to use (allocated if zero).\n" + "Returns: [int] new domain group identifier; -1 on error.\n" }, + { "domain_max_vcpus", (PyCFunction)pyxc_domain_max_vcpus, METH_VARARGS, "\n" @@ -1288,6 +1438,13 @@ " dom [int]: Identifier of domain to be paused.\n\n" "Returns: [int] 0 on success; -1 on error.\n" }, + { "domain_group_pause", + (PyCFunction)pyxc_domain_group_pause, + METH_VARARGS, "\n" + "Temporarily pause execution of all domains in a group.\n" + " grp [int]: Identifier of domain group to be paused.\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + { "domain_unpause", (PyCFunction)pyxc_domain_unpause, METH_VARARGS, "\n" @@ -1295,6 +1452,13 @@ " dom [int]: Identifier of domain to be unpaused.\n\n" "Returns: [int] 0 on success; -1 on error.\n" }, + { "domain_group_unpause", + (PyCFunction)pyxc_domain_group_unpause, + METH_VARARGS, "\n" + "(Re)start execution of all domains in a group.\n" + " grp [int]: Identifier of domain group to be unpaused.\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + { "domain_destroy", (PyCFunction)pyxc_domain_destroy, METH_VARARGS, "\n" @@ -1302,6 +1466,13 @@ " dom [int]: Identifier of domain to be destroyed.\n\n" "Returns: [int] 0 on success; -1 on error.\n" }, + { "domain_group_destroy", + (PyCFunction)pyxc_domain_group_destroy, + METH_VARARGS, "\n" + "Destroy an empty domain group.\n" + " grp [int]: Identifier of domain group to be destroyed.\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + { "domain_destroy_hook", (PyCFunction)pyxc_domain_destroy_hook, METH_VARARGS, "\n" @@ -1375,6 +1546,20 @@ " shutdown_reason [int]: Numeric code from guest OS, explaining " "reason why it shut itself down.\n" }, + { "domain_group_getinfo", + (PyCFunction)pyxc_domain_group_getinfo, + METH_VARARGS | METH_KEYWORDS, "\n" + "Get information regarding a set of domain groups.\n" + " first_grp [int, 0]: First domain to retrieve info about.\n" + " max_grps [int, 1024]: Maximum number of domains to retrieve info" + " about.\n\n" + "Returns: [list of dicts] if list length is less than 'max_grps'\n" + " parameter then there was an error, or the end of the\n" + " group-id space was reached.\n" + " grp [int]: Id of group to which this info pertains\n" + " size [int]: Number of domains in this group\n" + " member_list [int array]: Unordered list of member Ids\n"}, + { "vcpu_getinfo", (PyCFunction)pyxc_vcpu_getinfo, METH_VARARGS | METH_KEYWORDS, "\n" @@ -1621,6 +1806,14 @@ " dom [int]: Domain whose time offset is being set.\n" "Returns: [int] 0 on success; -1 on error.\n" }, + { "domain_group_join", + (PyCFunction)pyxc_domain_group_join, + METH_VARARGS, "\n" + "Request that the given domain join the supplied group.\n" + " dom [int]: Identifier of domain joining group.\n" + " grp [int]: Identifier of group the given domain is joining.\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + { "domain_send_trigger", (PyCFunction)pyxc_domain_send_trigger, METH_VARARGS | METH_KEYWORDS, "\n" diff -urN xen-unstable/tools/python/xen/xend/server/XMLRPCServer.py xen-unstable-trp-domgrps-rebase-tip/tools/python/xen/xend/server/XMLRPCServer.py --- xen-unstable/tools/python/xen/xend/server/XMLRPCServer.py 2007-12-17 16:45:04.000000000 -0500 +++ xen-unstable-trp-domgrps-rebase-tip/tools/python/xen/xend/server/XMLRPCServer.py 2007-12-17 16:09:54.000000000 -0500 @@ -29,10 +29,11 @@ from xen.xend import XendAPI, XendDomain, XendDomainInfo, XendNode from xen.xend import XendLogging, XendDmesg +from xen.xend import XendDomainGroup from xen.xend.XendClient import XML_RPC_SOCKET from xen.xend.XendConstants import DOM_STATE_RUNNING from xen.xend.XendLogging import log -from xen.xend.XendError import XendInvalidDomain +from xen.xend.XendError import XendInvalidDomain, XendInvalidDomainGroup # 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. @@ -46,16 +47,16 @@ ret.append(k) return ret -def lookup(domid): +def lookup_dom(domid): info = XendDomain.instance().domain_lookup(domid) return info def dispatch(domid, fn, args): - info = lookup(domid) + info = lookup_dom(domid) return getattr(info, fn)(*args) def domain(domid, full = 0): - info = lookup(domid) + info = lookup_dom(domid) return fixup_sxpr(info.sxpr(not full)) def domains(detail = True, full = False): @@ -76,6 +77,19 @@ info = XendDomain.instance().domain_restore(src, paused) return fixup_sxpr(info.sxpr()) +def lookup_grp(dgid): + grpinfo = XendDomainGroup.instance().grp_lookup(dgid) + if not grpinfo: + raise XendInvalidDomainGroup("Invalid group: %s" % str(dgid)) + return grpinfo + +def group(dgid): + return lookup_grp(dgid) + +def group_create(config): + info = XendDomainGroup.instance().grp_create(config) + return info.sxpr() + def get_log(): f = open(XendLogging.getLogFilename(), 'r') try: @@ -91,6 +105,10 @@ exclude = ['domain_create', 'domain_restore'] +grp_methods = ['grp_destroy', 'grp_pause', 'grp_unpause', 'grp_members', + 'grp_join', 'grp_migrate', 'grp_list', 'grp_suspend', + 'grp_resume', 'grp_save', 'grp_restore', 'grp_shutdown'] + class XMLRPCServer: def __init__(self, auth, use_xenapi, use_tcp = False, ssl_key_file = None, ssl_cert_file = None, @@ -190,6 +208,12 @@ if name not in exclude: self.server.register_function(fn, "xend.domain.%s" % name[7:]) + # Domain Group Operations + xdg_inst = XendDomainGroup.instance() + for name in grp_methods: + fn = getattr(xdg_inst, name) + self.server.register_function(fn, "xend.group.%s" % name[4:]) + # Functions in XendNode and XendDmesg for type, lst, n in [(XendNode, ['info', 'send_debug_keys'], 'node'), (XendDmesg, ['info', 'clear'], 'node.dmesg')]: @@ -206,6 +230,8 @@ self.server.register_function(get_log, 'xend.node.log') self.server.register_function(domain_create, 'xend.domain.create') self.server.register_function(domain_restore, 'xend.domain.restore') + self.server.register_function(group, 'xend.group') + self.server.register_function(group_create, 'xend.group.create') # A couple of the security functions from xen.util.xsm import xsm as security diff -urN xen-unstable/tools/python/xen/xend/XendCheckpoint.py xen-unstable-trp-domgrps-rebase-tip/tools/python/xen/xend/XendCheckpoint.py --- xen-unstable/tools/python/xen/xend/XendCheckpoint.py 2007-11-19 10:38:07.000000000 -0500 +++ xen-unstable-trp-domgrps-rebase-tip/tools/python/xen/xend/XendCheckpoint.py 2007-12-03 14:26:13.000000000 -0500 @@ -70,10 +70,17 @@ try: dominfo.migrateDevices(network, dst, DEV_MIGRATE_STEP1, domain_name) - write_exact(fd, pack("!i", len(config)), - "could not write guest state file: config len") + dgid = dominfo.info['dgid'] + xdg = xen.xend.XendDomainGroup.instance() + grpinfo = xdg.grp_lookup_nr(dgid) + grpconfig = sxp.to_string(grpinfo.sxpr()) + + write_exact(fd, pack("!i", len(config)), "could not write guest state file: config len") write_exact(fd, config, "could not write guest state file: config") + write_exact(fd, pack("!i", len(grpconfig)), "could not write group state file: grpconfig len") + write_exact(fd, grpconfig, "could not write group state file: grpconfig") + image_cfg = dominfo.info.get('image', {}) hvm = dominfo.info.is_hvm() @@ -158,17 +165,16 @@ raise XendError("not a valid guest state file: found '%s'" % signature) - l = read_exact(fd, sizeof_int, + l = read_exact(fd, sizeof_int, "not a valid guest state file: config size read") vmconfig_size = unpack("!i", l)[0] - vmconfig_buf = read_exact(fd, vmconfig_size, - "not a valid guest state file: config read") + vmconfig_buf = read_exact(fd, vmconfig_size, + "not a valid guest state file: config read") p = sxp.Parser() p.input(vmconfig_buf) if not p.ready: raise XendError("not a valid guest state file: config parse") - vmconfig = p.get_val() if dominfo: @@ -194,6 +200,42 @@ apic = 0 pae = 0 + # re-create (if necessary) and re-join group + l = read_exact(fd, sizeof_int, + "not a valid group state file: grpconfig size read") + grpconfig_size = unpack("!i", l)[0] + grpconfig_buf = read_exact(fd, grpconfig_size, + "not a valid group state file: config read") + + p.reset() + p.input(grpconfig_buf) #FIXME: gracefully handle domains with no group data + if not p.ready: + raise XendError("not a valid group state file: config parse") + grpconfig = eval(p.get_val()) + + src_dguuid = sxp.child_value(vmconfig, 'dguuid') + src_grp_name = grpconfig['grp_name'] + + xdg = xen.xend.XendDomainGroup.instance() + xdg.domain_groups_lock.acquire() + log.debug("%s acquire grplock", xdg) + try: + grpinfo = xdg.grp_lookup(src_dguuid) + if not grpinfo: + grpcfg = {} + grpcfg['dguuid'] = src_dguuid + grpcfg['grp_name'] = src_grp_name + grpinfo = xen.xend.XendDomainGroupInfo.XendDomainGroupInfo(grpcfg) + grpinfo.construct(src_dguuid) + xdg.grp_join(dominfo.getDomid(), grpinfo.info['dgid']) + xdg.domain_groups_lock.release() + log.debug("%s release grplock", xdg) + except: + xdg.domain_groups_lock.release() + log.debug("%s release grplock", xdg) + dominfo.destroy() + raise XendError("problem joining/creating old group") + try: restore_image = image.create(dominfo, dominfo.info) memory = restore_image.getRequiredAvailableMemory( diff -urN xen-unstable/tools/python/xen/xend/XendClient.py xen-unstable-trp-domgrps-rebase-tip/tools/python/xen/xend/XendClient.py --- xen-unstable/tools/python/xen/xend/XendClient.py 2007-08-06 17:59:53.000000000 -0400 +++ xen-unstable-trp-domgrps-rebase-tip/tools/python/xen/xend/XendClient.py 2007-11-19 18:42:00.000000000 -0500 @@ -27,6 +27,7 @@ ERROR_INTERNAL = 1 ERROR_GENERIC = 2 ERROR_INVALID_DOMAIN = 3 +ERROR_INVALID_DOMAIN_GROUP = 4 uri = 'httpu:///var/run/xend/xmlrpc.sock' if os.environ.has_key('XM_SERVER'): diff -urN xen-unstable/tools/python/xen/xend/XendConfig.py xen-unstable-trp-domgrps-rebase-tip/tools/python/xen/xend/XendConfig.py --- xen-unstable/tools/python/xen/xend/XendConfig.py 2007-12-17 16:45:04.000000000 -0500 +++ xen-unstable-trp-domgrps-rebase-tip/tools/python/xen/xend/XendConfig.py 2007-12-17 16:09:54.000000000 -0500 @@ -27,7 +27,7 @@ from xen.xend.XendError import VmError from xen.xend.XendDevices import XendDevices from xen.xend.PrettyPrint import prettyprintstring -from xen.xend.XendConstants import DOM_STATE_HALTED +from xen.xend.XendConstants import DOM_STATE_HALTED,NULL_GROUP_ID,NULL_GROUP_UUID from xen.xend.xenstore.xstransact import xstransact from xen.xend.server.BlktapController import blktap_disk_types from xen.xend.server.netif import randomMAC @@ -111,6 +111,8 @@ XENAPI_CFG_TO_LEGACY_CFG = { 'uuid': 'uuid', + 'dgid': 'dgid', + 'dguuid': 'dguuid', 'VCPUs_max': 'vcpus', 'cpus': 'cpus', 'name_label': 'name', @@ -142,6 +144,8 @@ XENAPI_CFG_TYPES = { 'uuid': str, + 'dguid': int, + 'dguuid': str, 'name_label': str, 'name_description': str, 'user_version': str, @@ -197,6 +201,9 @@ LEGACY_CFG_TYPES = { 'uuid': str, + 'dgid': int, + 'dguuid': str, + 'grp_name': str, 'name': str, 'vcpus': int, 'vcpu_avail': long, @@ -222,6 +229,8 @@ # xenstore. LEGACY_XENSTORE_VM_PARAMS = [ 'uuid', + 'dgid', + 'dguuid', 'name', 'vcpus', 'vcpu_avail', @@ -336,7 +345,9 @@ 'vbd_refs': [], 'vtpm_refs': [], 'other_config': {}, - 'platform': {} + 'platform': {}, + 'dgid': NULL_GROUP_ID, + 'dguuid': NULL_GROUP_UUID, } return defaults @@ -388,6 +399,10 @@ self['uuid'] = uuid.createString() else: self['uuid'] = uuid.toString(uuid.fromString(self['uuid'])) + if 'dguuid' not in self or not self['dguuid']: + self['dguuid'] = uuid.createString() + else: + self['dguuid'] = uuid.toString(uuid.fromString(self['dguuid'])) def _name_sanity_check(self): if 'name_label' not in self: @@ -417,6 +432,7 @@ def _dominfo_to_xapi(self, dominfo, update_mem = False): self['domid'] = dominfo['domid'] + self['dgid'] = dominfo['dgid'] self['online_vcpus'] = dominfo['online_vcpus'] self['VCPUs_max'] = dominfo['max_vcpu_id'] + 1 @@ -448,6 +464,9 @@ if 'handle' in dominfo: self['uuid'] = uuid.toString(dominfo['handle']) + + if 'dg_handle' in dominfo: + self['dguuid'] = uuid.toString(dominfo['dg_handle']) def _parse_sxp(self, sxp_cfg): """ Populate this XendConfig using the parsed SXP. @@ -924,6 +943,8 @@ sxpr.append([legacy, int(self[xenapi])]) else: sxpr.append([legacy, self[xenapi]]) + else: + log.debug("Unconverted key: " + xenapi) MiB = 1024*1024 @@ -931,7 +952,7 @@ sxpr.append(["memory", int(self["memory_dynamic_max"])/MiB]) for legacy in LEGACY_UNSUPPORTED_BY_XENAPI_CFG: - if legacy in ('domid', 'uuid', 'cpus'): # skip these + if legacy in ('domid', 'uuid', 'cpus', 'dgid', 'dguuid'): # skip these continue if self.has_key(legacy) and self[legacy] not in (None, []): sxpr.append([legacy, self[legacy]]) diff -urN xen-unstable/tools/python/xen/xend/XendConstants.py xen-unstable-trp-domgrps-rebase-tip/tools/python/xen/xend/XendConstants.py --- xen-unstable/tools/python/xen/xend/XendConstants.py 2007-11-19 10:38:07.000000000 -0500 +++ xen-unstable-trp-domgrps-rebase-tip/tools/python/xen/xend/XendConstants.py 2007-11-19 18:42:00.000000000 -0500 @@ -123,4 +123,15 @@ # XS_VMROOT = "/vm/" +XS_GRPROOT = "/group/" +# +# Domain Group Constants +# + +GROUP0_ID = 0 +GROUP0_UUID = "00000000-0000-0000-0000-000000000000" +GROUP0_NAME = "Group-0" +NULL_GROUP_ID = 32767 +NULL_GROUP_UUID = "ffffffff-ffff-ffff-ffff-ffffffffffff" +NULL_GROUP_NAME = "Null-Group" diff -urN xen-unstable/tools/python/xen/xend/XendDomainGroupInfo.py xen-unstable-trp-domgrps-rebase-tip/tools/python/xen/xend/XendDomainGroupInfo.py --- xen-unstable/tools/python/xen/xend/XendDomainGroupInfo.py 1969-12-31 19:00:00.000000000 -0500 +++ xen-unstable-trp-domgrps-rebase-tip/tools/python/xen/xend/XendDomainGroupInfo.py 2007-12-03 12:32:56.000000000 -0500 @@ -0,0 +1,238 @@ +#============================================================================ +# 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 +#============================================================================ +# Author: Chris Bookholt <hap10@xxxxxxxxxxxxxx> +#============================================================================ +import logging +import string +import sxp +import uuid +import xen.lowlevel.xc +import XendDomain +import XendDomainInfo +from xen.xend.XendError import VmError +from xen.xend.xenstore.xstransact import xstransact +from xen.xend.XendConstants import XS_GRPROOT + + +xc = xen.lowlevel.xc.xc() +log = logging.getLogger("xend.XendDomainGroupInfo") +default_ops = ['create','shutdown','pause','unpause','save','restore', + 'migrate_up','migrate_down'] + + +def create(config): + log.debug("XendDomainGroupInfo.create(%s)", config) + + grp = XendDomainGroupInfo(parseConfig(config)) + + try: + grp.construct() + return grp + except: + raise VmError('Domain group construction failed') + + +def recreate(xeninfo): + log.debug("XendDomainGroupInfo.recreate(%s)", xeninfo) + + dgid = xeninfo['dgid'] + dg_handle = xeninfo['dg_handle'] + xeninfo['dguuid'] = uuid.toString(dg_handle) + + log.info("Recreating domain group %d, UUID %s.", dgid, xeninfo['dguuid']) + + return XendDomainGroupInfo(xeninfo) + + +def parseConfig(config): + result = {} + + result['grp_name'] = sxp.child_value(config,'grp_name') + result['member_list'] = sxp.child_value(config,'member_list') + + log.info("parseConfig result is %s" % result) + return result + + +def grp_get(dgid): + try: + grplist = xc.domain_group_getinfo(dgid, 1) + if grplist and grplist[0]['dgid'] == dgid: + return grplist[0] + except Exception, err: + # ignore missing domain group + log.debug("grp_getinfo(%d) failed, ignoring: %s", dgid, str(err)) + return None + + +class XendDomainGroupInfo: + def __init__(self, info): + + self.info = info + + if self.infoIsSet('dgid'): + self.dgid = self.info['dgid'] + + if not self.infoIsSet('dguuid'): + self.info['dguuid'] = uuid.toString(uuid.create()) + self.dguuid = self.info['dguuid'] + + if not self.infoIsSet('grp_name'): + self.info['grp_name'] = ("Group-%s" % self.dguuid) + self.grp_name = self.info['grp_name'] + + if not self.infoIsSet('grp_path'): + self.info['grp_path'] = "%s%s" % (XS_GRPROOT,self.dguuid) + self.grppath = self.info['grp_path'] + + self.parse_member_list() + self.validateInfo() + + + def parse_member_list(self): + # set up member info dict to pair members and their manifests + # TODO: add checks to ensure neither component is empty + self.members = [] + self.member_info = {} + + if self.infoIsSet('member_list'): + for str in self.info['member_list']: + if (':' not in str): + raise VmError('invalid grpinfo format; member_list missing \':\'') + smember = str.split(':') + mbr_name = smember[0] + self.members.append(mbr_name) + mbr_manifest_path = smember[1] + self.member_info[mbr_name] = mbr_manifest_path + + self.size = len(self.member_info) + self.info['size'] = self.size + + + def getName(self): + return self.info['grp_name'] + + + def getDgid(self): + return self.info['dgid'] + + + def getDguuid(self): + return self.info['dguuid'] + + + def update(self, info = None): + log.trace("XendDomainGroupInfo.update(%s) on grp %d", self.dgid) + + if not info: + info = grp_get(self.dgid) + if not info: + return + + self.info.update(info) + self.dgid = self.info['dgid'] + self.dguuid = self.info['dguuid'] + self.grp_name = self.info['grp_name'] + self.parse_member_list() + self.validateInfo() + + log.trace("XendDomainGroupInfo.update done on grp %d: %s", self.dgid, + self.info) + + + def sxpr(self): + return self.info + + + def validateInfo(self): + def defaultInfo(name, val): + if not self.infoIsSet(name): + self.info[name] = val() + try: + defaultInfo('grp_name', lambda: "Group-%s" % self.dguuid) + self.check_name(self.info['grp_name']) + except KeyError, exn: + log.exception(exn) + raise VmError('Unspecified domain group detail: %s' % exn) + + def _readGrp(self, *args): + return xstransact.Read(self.grppath, *args) + + + def _writeGrp(self, *args): + return xstransact.Write(self.grppath, *args) + + + def _removeGrp(self, *args): + return xstransact.Remove(self.grppath, *args) + + + def storeGrpDetails(self): + to_store = { + 'dgid': str(self.dgid), + 'dguuid': self.dguuid, + 'grp_name': self.grp_name, + 'members': ", ".join(self.members) + } + self._writeGrp(to_store) + + + # create an empty group + def construct(self, dguuid = None): + if dguuid: + dg_handle = uuid.fromString(dguuid) + else: + dg_handle = uuid.fromString(self.info['dguuid']) + self.dgid = xc.domain_group_create(dg_handle) + if (self.dgid < 0) or (self.dgid == None): + raise VmError('Creating domain group %s failed' % self.info['grp_name']) + self.info['dgid'] = self.dgid + self.storeGrpDetails() + + + def infoIsSet(self, name): + return name in self.info and self.info[name] is not None + + + def check_name(self, name): + # check for lack of name + if name is None or name == '': + raise VmError('missing grp name') + # check name for invalid characters + for c in name: + if c in string.digits: continue + if c in '_-.:/+': continue + if c in string.ascii_letters: continue + raise VmError("check_name: invalid grp name caused by [%s]" % c) + # check for duplicate names + xdg = xen.xend.XendDomainGroup.instance() + grp = xdg.grp_lookup_nr(name) + if grp and grp.info['dguuid'] != self.info['dguuid']: + raise VmError("Group name %s already exists" % name) + + + def destroy(self, rmxs): + ret = xc.domain_group_destroy(self.dgid) + if ret == 0 and rmxs: + self._removeGrp() + return ret + + + def pause(self): + xc.domain_group_pause(self.dgid) + + + def unpause(self): + xc.domain_group_unpause(self.dgid) diff -urN xen-unstable/tools/python/xen/xend/XendDomainGroup.py xen-unstable-trp-domgrps-rebase-tip/tools/python/xen/xend/XendDomainGroup.py --- xen-unstable/tools/python/xen/xend/XendDomainGroup.py 1969-12-31 19:00:00.000000000 -0500 +++ xen-unstable-trp-domgrps-rebase-tip/tools/python/xen/xend/XendDomainGroup.py 2007-12-03 14:37:28.000000000 -0500 @@ -0,0 +1,347 @@ +#============================================================================ +# 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 +#============================================================================ +# Author: Chris Bookholt <hap10@xxxxxxxxxxxxxx> +#============================================================================ +import logging +import os +import socket +import sys +import threading +import uuid + +import xen.lowlevel.xc +from xen.xend import XendDomain +from xen.xend import XendDomainGroupInfo +from xen.xend.XendError import XendError +from XendLogging import log +from xen.xend.XendConstants import XS_GRPROOT, GROUP0_ID, \ + GROUP0_NAME, NULL_GROUP_ID, NULL_GROUP_NAME + + +xc = xen.lowlevel.xc.xc() + + +class XendDomainGroup: + + def __init__(self): + self.domain_groups = {} + self.domain_groups_lock = threading.RLock() + self.xd = XendDomain.instance() + self.xst = xen.xend.xenstore.xstransact.xstransact + + + def init(self): + # not sure how xenstore permissions work + #xstransact.Mkdir(XS_GRPROOT) + #xstransact.SetPermissions(XS_GRPROOT, {'dom': DOM0_ID}) + self.domain_groups_lock.acquire() + try: + grps = self.xen_domain_groups() + for dgid,grpdata in grps.items(): + log.debug("init'ing grp%s: %s", dgid, grpdata) + if dgid == GROUP0_ID: + grpdata['grp_name'] = GROUP0_NAME + elif dgid == NULL_GROUP_ID: + grpdata['grp_name'] = NULL_GROUP_NAME + else: + path = "%s%s/grp_name" % (XS_GRPROOT,grpdata['dguuid']) + grpdata['grp_name'] = self.xst.Read(path) + if not grpdata['grp_name']: + grpdata['grp_name'] = "Group-%s" % grpdata['dguuid'] + grpinfo = XendDomainGroupInfo.recreate(grpdata) + self._add_domain_group(grpinfo) + grpinfo.storeGrpDetails() + finally: + self.domain_groups_lock.release() + + """ expects domain_groups_lock """ + def _add_domain_group(self, info): + dgid = info.dgid + self.domain_groups[dgid] = info + log.debug("Added grp%s to domain_groups: %s", dgid, info) + + + """ expects domain_groups_lock """ + def _delete_domain_group(self, dgid): + info = self.domain_groups.get(dgid) + if info: + del self.domain_groups[dgid] + log.debug("Deleted grp%s from domain_groups", dgid) + + + def _prependGrpPath(self, dguuid, string): + grppath = "%s%s" % (XS_GRPROOT,dguuid) + return "%s%s" % (grppath,string) + + + def _getGrpName(self, dguuid): + name = "" + namepath = "" + try: + namepath = self._prependGrpPath(dguuid, "/grp_name") + name = self.xst.Read(namepath) + except: + log.exception("Error reading %s from xenstore", namepath) + if (name == "") or (name == None): + grpinfo = self.grp_lookup_nr(dguuid) + if grpinfo: + name = grpinfo.grp_name + else: + name = "Group-%s" % dguuid + return name + + + def _rebuild_config(self, grpdata): + domlist = [] + for domid in grpdata['member_list']: + dominfo = self.xd.domain_lookup_nr(domid) + if dominfo: + domname = dominfo.getName() + # TODO: could store/retrieve member config paths to/from xs, + # but at the moment there is no need for accurate values once + # the members are started + domlist.append(domname+":nullconfig") + + sxpr = {} + sxpr['dgid'] = grpdata['dgid'] + sxpr['dg_handle'] = grpdata['dg_handle'] + sxpr['dguuid'] = uuid.toString(grpdata['dg_handle']) + sxpr['grp_name'] = self._getGrpName(sxpr['dguuid']) + sxpr['member_list'] = domlist + sxpr['size'] = len(domlist) + + return sxpr + + + def xen_domain_groups(self): + grps = {} + grplist = xc.domain_group_getinfo() + for grp in grplist: + dgid = grp['dgid'] + grpdata = self._rebuild_config(grp) + grps[dgid] = grpdata + return grps + + + """ expects domain_groups_lock """ + def refresh(self): + grps = self.xen_domain_groups() + + for grp in self.domain_groups.values(): + info = grps.get(grp.dgid) + if info: + grp.update(info) + else: + self._delete_domain_group(grp.dgid) + + for grp in grps: + if grp not in self.domain_groups: + try: + grpinfo = XendDomainGroupInfo.recreate(grps[grp]) + self._add_domain_group(grpinfo) + except: + log.exception( + "Failed to recreate information for domain " + "group %d.", grp) + + self.push_grp_data_to_xenstore() + + + """ expects domain_groups_lock """ + def push_grp_data_to_xenstore(self): + for grpinfo in self.domain_groups.values(): + grpinfo.storeGrpDetails() + + + def grp_lookup_nr(self, grp): + self.domain_groups_lock.acquire() + try: + # match by name + for grpinfo in self.domain_groups.values(): + if grpinfo.getName() == grp: + return grpinfo + # match by id + try: + if int(grp) in self.domain_groups: + return self.domain_groups[int(grp)] + except ValueError: + pass + # match by dguuid + for grpinfo in self.domain_groups.values(): + if grpinfo.getDguuid() == grp: + return grpinfo + # group not found + return None + finally: + self.domain_groups_lock.release() + + + def grp_lookup(self, grp): + self.domain_groups_lock.acquire() + try: + self.refresh() + return self.grp_lookup_nr(grp) + finally: + self.domain_groups_lock.release() + + + def grp_members(self, dgid): + grpinfo = self.grp_lookup(dgid) + return grpinfo.members + + + def grp_list(self): + self.domain_groups_lock.acquire() + try: + self.refresh() + return self.domain_groups.values() + finally: + self.domain_groups_lock.release() + + + def grp_create(self, config): + self.domain_groups_lock.acquire() + try: + grpinfo = XendDomainGroupInfo.create(config) + self._add_domain_group(grpinfo) + return grpinfo + finally: + self.domain_groups_lock.release() + + + def grp_shutdown(self, dgid, reason): + members = self.grp_members(dgid) + for domname in members: + dominfo = self.xd.domain_lookup(domname) + dominfo.shutdown(reason) + + + def grp_destroy(self, dgid, rmxs = True): + ret = -1 + self.domain_groups_lock.acquire() + try: + grpinfo = self.grp_lookup(dgid) + ret = grpinfo.destroy(rmxs) + if ret == 0: + self._delete_domain_group(dgid) + finally: + self.domain_groups_lock.release() + return ret + + + def grp_save(self, dgid, prefix): + members = self.grp_members(dgid) + for dom in members: + self.xd.domain_save(dom, prefix + "." + dom) + self.grp_destroy(dgid) + + + def grp_restore(self, srcs): + for dompath in srcs: + self.xd.domain_restore(dompath, paused=False) + + + def grp_suspend(self, dgid): + log.debug("grp_suspend not yet implemented") + # members = self.grp_members(dgid) + # for dom in members: + # self.xd.domain_suspend(dom) + # self.grp_destroy(dgid, rmxs=False) + + + def grp_resume(self, dgid): + log.debug("grp_resume not yet implemented") + # member_list_str = self.xst.Read(XS_GRPROOT, "%s/members" % dguuid) + # member_list = member_list_str.split(", ") + # for dom in member_list: + # self.xd.domain_resume(dom) + + + def grp_pause(self, dgid): + self.domain_groups_lock.acquire() + try: + grpinfo = self.grp_lookup(dgid) + return grpinfo.pause() + finally: + self.domain_groups_lock.release() + + + def grp_unpause(self, dgid): + self.domain_groups_lock.acquire() + try: + grpinfo = self.grp_lookup(dgid) + return grpinfo.unpause() + finally: + self.domain_groups_lock.release() + + + def grp_join(self, domid, dgid): + self.domain_groups_lock.acquire() + try: + dominfo = self.xd.domain_lookup(domid) + rc = xc.domain_group_join(domid, dgid) + if rc != 0: + raise XendError("group_join failed with error: %s" % rc) + + dominfo = self.xd.domain_lookup(domid) + dominfo._storeVmDetails() + dominfo._storeDomDetails() + self.xd.managed_config_save(dominfo) + + self.refresh() + + log.debug("dom%s joining grp%s", domid, dgid) + + return rc + finally: + self.domain_groups_lock.release() + + + def grp_migrate(self, dgid, dst, live, resource, port): + + def threadHelper(dom): + return threading.Thread(target = self.xd.domain_migrate, + args = (dom,dst,live,resource,port)) + + try: + member_names = self.grp_members(dgid) + migration_threads = {} + # spawn and start a threaded migration request + # for each group member + for domname in member_names: + migration_threads[domname] = threadHelper(domname) + migration_threads[domname].start() + log.debug("Migration began for domain %s to %s", + domname, dst) + # block until all group members finish migration + for domname in member_names: + migration_threads[domname].join() + log.debug("Migration complete for domain %s to %s", + domname, dst) + self.grp_destroy(dgid) + except e: + log.exception("error during grp_migrate: %s", str(e)) + + +def instance(): + """Singleton constructor. Use this instead of the class constructor. + """ + global inst + try: + inst + except: + inst = XendDomainGroup() + inst.init() + return inst diff -urN xen-unstable/tools/python/xen/xend/XendDomainInfo.py xen-unstable-trp-domgrps-rebase-tip/tools/python/xen/xend/XendDomainInfo.py --- xen-unstable/tools/python/xen/xend/XendDomainInfo.py 2007-12-17 16:45:04.000000000 -0500 +++ xen-unstable-trp-domgrps-rebase-tip/tools/python/xen/xend/XendDomainInfo.py 2007-12-17 16:09:54.000000000 -0500 @@ -952,6 +952,8 @@ def _storeDomDetails(self): to_store = { 'domid': str(self.domid), + 'dgid': str(self.info['dgid']), + 'dguuid': self.info['dguuid'], 'vm': self.vmpath, 'name': self.info['name_label'], 'console/limit': str(xoptions.get_console_limit() * 1024), @@ -1037,7 +1039,7 @@ # changed in Xenstore. cfg_vm = ['name', 'on_poweroff', 'on_reboot', 'on_crash', - 'rtc/timeoffset'] + 'rtc/timeoffset', 'dgid', 'dguuid', 'grp_name'] vm_details = self._readVMDetails([(k,XendConfig.LEGACY_CFG_TYPES[k]) for k in cfg_vm]) @@ -1086,6 +1088,9 @@ reason = self.readDom('control/shutdown') + # stash current dgid for restart/resume/restore + self.old_dgid = self.info.get('dgid') + if reason and reason != 'suspend': sst = self.readDom('xend/shutdown_start_time') now = time.time() @@ -1113,6 +1118,12 @@ def getDomid(self): return self.domid + def getDgid(self): + return self.info.get('dgid') + + def getOldDgid(self): + return self.old_dgid + def setName(self, name): self._checkName(name) self.info['name_label'] = name @@ -1393,8 +1404,21 @@ new_dom = None try: - new_dom = XendDomain.instance().domain_create_from_dict( - self.info) + xd = XendDomain.instance() + new_dom = xd.domain_create_from_dict(self.info) + + # rejoin former domain group + xdg = xen.xend.XendDomainGroup.instance() + + # wait until both needed locks are available + rc = False + while rc == False: + rc = xd.domains_lock.acquire( blocking = False ) + if rc == False: + time.sleep(1) + xdg.grp_join(new_dom.domid, self.old_dgid) + xd.domains_lock.release() + new_dom.waitForDevices() new_dom.unpause() rst_cnt = self._readVm('xend/restart_count') @@ -2845,9 +2869,10 @@ return (dev_uuid in self.info['%s_refs' % dev_class.lower()]) def __str__(self): - return '<domain id=%s name=%s memory=%s state=%s>' % \ - (str(self.domid), self.info['name_label'], - str(self.info['memory_dynamic_max']), DOM_STATES[self._stateGet()]) + return '<domain id=%s dgid=%s name=%s memory=%s state=%s>' % \ + (str(self.domid), str(self.info.get('dgid')), + self.info['name_label'], str(self.info['memory_dynamic_max']), + DOM_STATES[self._stateGet()]) __repr__ = __str__ diff -urN xen-unstable/tools/python/xen/xend/XendDomain.py xen-unstable-trp-domgrps-rebase-tip/tools/python/xen/xend/XendDomain.py --- xen-unstable/tools/python/xen/xend/XendDomain.py 2007-12-17 16:45:04.000000000 -0500 +++ xen-unstable-trp-domgrps-rebase-tip/tools/python/xen/xend/XendDomain.py 2007-12-17 16:09:54.000000000 -0500 @@ -432,6 +432,14 @@ if domid not in running_domids and domid != DOM0_ID: self._remove_domain(dom, domid) + # update group information + xdg = xen.xend.XendDomainGroup.instance() + xdg.domain_groups_lock.acquire() + try: + xdg.refresh() + finally: + xdg.domain_groups_lock.release() + def add_domain(self, info): """Add a domain to the list of running domains @@ -925,10 +933,15 @@ if hasattr(os, "O_LARGEFILE"): oflags |= os.O_LARGEFILE fd = os.open(chkpath, oflags) - XendCheckpoint.restore(self, + pdated_dominfo = XendCheckpoint.restore(self, fd, dominfo, paused = start_paused) + domid = dominfo.getDomid() + dgid = dominfo.getOldDgid() + xdg = xen.xend.XendDomainGroup.instance() + xdg.grp_join(domid, dgid) + self.add_domain(updated_dominfo) os.unlink(chkpath) except OSError, ex: raise XendError("Failed to read stored checkpoint file") diff -urN xen-unstable/tools/python/xen/xend/XendError.py xen-unstable-trp-domgrps-rebase-tip/tools/python/xen/xend/XendError.py --- xen-unstable/tools/python/xen/xend/XendError.py 2007-08-06 17:59:53.000000000 -0400 +++ xen-unstable-trp-domgrps-rebase-tip/tools/python/xen/xend/XendError.py 2007-11-19 18:42:00.000000000 -0500 @@ -24,6 +24,10 @@ def __init__(self, value): Fault.__init__(self, XendClient.ERROR_INVALID_DOMAIN, value) +class XendInvalidDomainGroup(Fault): + def __init__(self, value): + Fault.__init__(self, XendClient.ERROR_INVALID_DOMAIN_GROUP, value) + class XendError(Fault): def __init__(self, value): diff -urN xen-unstable/tools/python/xen/xm/create.py xen-unstable-trp-domgrps-rebase-tip/tools/python/xen/xm/create.py --- xen-unstable/tools/python/xen/xm/create.py 2007-12-17 16:45:04.000000000 -0500 +++ xen-unstable-trp-domgrps-rebase-tip/tools/python/xen/xm/create.py 2007-12-17 16:09:54.000000000 -0500 @@ -521,6 +521,11 @@ - suspend: Domain is suspended; """) +gopts.var('dgid', val='NUM', + fn=set_int, default=32767, + use='Default domain group to join.') + + def err(msg): """Print an error to stderr and exit. """ @@ -768,6 +773,8 @@ config.append(['backend', ['tpmif']]) if vals.localtime: config.append(['localtime', vals.localtime]) + if vals.dgid is not None: + config.append(['dgid', vals.dgid]) config_image = configure_image(vals) if vals.bootloader: @@ -1188,6 +1195,7 @@ map(lambda vm_ref: server.xenapi.VM.start(vm_ref, 0), vm_refs) elif not opts.is_xml: dom = make_domain(opts, config) + return dom def do_console(domain_name): cpid = os.fork() diff -urN xen-unstable/tools/python/xen/xm/group.py xen-unstable-trp-domgrps-rebase-tip/tools/python/xen/xm/group.py --- xen-unstable/tools/python/xen/xm/group.py 1969-12-31 19:00:00.000000000 -0500 +++ xen-unstable-trp-domgrps-rebase-tip/tools/python/xen/xm/group.py 2007-11-27 09:40:06.000000000 -0500 @@ -0,0 +1,275 @@ +#============================================================================ +# 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 +#============================================================================ +# Author: Chris Bookholt <hap10@xxxxxxxxxxxxxx> +#============================================================================ +import os.path +import sys +import xmlrpclib +import time +from xen.xm.opts import Opts +from xen.xend import sxp +from xen.xend.XendClient import server +from sets import Set + +opts = Opts() + +# print an error to stderr and exit. +def err(msg): + print >>sys.stderr, "Error:", msg + sys.exit(1) + + +def get_grp(dgid): + grpinfo = server.xend.group(dgid) + if not grpinfo: + err("group %s does not exist" % dgid) + return grpinfo + + +def idCheck(dgid, op): + dgid = int(dgid) + if (dgid == 0 or dgid == 32767): + err("cannot %s group %d" % (op,dgid)) + + +# wait @timeout seconds for @domname to be created +def wait_create(domname, timeout): + counter = 0 + while counter < timeout: + domains = server.xend.domains(0) + if domname in domains: + return + counter += 1 + time.sleep(1) + err("timeout reached; problem starting group member dom: %s" % domname) + + +# read and parse sxp config from file +def make_config(config_file_path): + try: + fin = file(config_file_path, 'rb') + try: + config = sxp.parse(fin) + finally: + fin.close() + if config is None: + config = ['grp_config'] + else: + config.insert(0, 'grp_config') + except Exception, ex: + print("Error: %s" % str(ex)) + raise Exception + return config + + +# create a domain group +def make_domain_group(config): + try: + grpinfo = server.xend.group.create(config) + except xmlrpclib.Fault, ex: + err(str(ex)) + except Exception, ex: + print("Error: %s" % str(ex)) + raise Exception + return grpinfo + + +# start the group members +def populate_group(grpinfo, managed): + if managed: + from xen.xm import new + else: + from xen.xm import create + + for domdata in grpinfo['member_list']: + domdata_list = domdata.split(":") + domname = domdata_list[0] + dom_config_path = domdata_list[1] + if managed: + #print "creating managed domain %s from file: %s" % (domname,dom_config_path) + new.main([None,dom_config_path]) + #print "starting managed domain %s" % domname + server.xend.domain.start(domname, False) + domid = sxp.child_value(server.xend.domain(domname), 'domid') + else: + domid = create.main([None,dom_config_path]) + wait_create(domname, 10) + dgid = grpinfo['dgid'] + grp_join(domid, dgid) + #grp_unpause(grp.dgid) + + +def grp_create(config_file_path, managed = False): + config = make_config(config_file_path) + grpinfo = make_domain_group(config) + populate_group(grpinfo, managed) + + +# shutdown or reboot a group of domains +def grp_shutdown(dgid, reason, keep): + grpinfo = get_grp(dgid) + idCheck(grpinfo['dgid'],"shutdown or reboot") + try: + server.xend.group.shutdown(dgid, reason) + if reason == "poweroff" and not keep: + print "waiting for group members to shutdown..." + from xen.xm.shutdown import wait_shutdown + wait_shutdown(opts, grpinfo['members']) + grp_destroy(dgid, force = False) + except xmlrpclib.Fault, ex: + err(str(ex)) + except Exception, ex: + print("Error: %s" % str(ex)) + raise Exception + + +# destroy a domain group +def grp_destroy(dgid, force = False): + grpinfo = get_grp(dgid) + idCheck(grpinfo['dgid'],"destroy") + try: + if force: + grp_pause(dgid) + for domid in grpinfo['members']: + server.xend.domain.destroy(domid) + print "waiting for group members to be destroyed..." + from xen.xm.shutdown import wait_shutdown + wait_shutdown(opts, grpinfo['members']) + server.xend.group.destroy(grpinfo['dgid']) + except xmlrpclib.Fault, ex: + err(str(ex)) + except Exception, ex: + print("Error: %s" % str(ex)) + raise Exception + return + + +# save a group of running domains +def grp_save(dgid, prefix): + grpinfo = get_grp(dgid) + idCheck(grpinfo['dgid'],"save") + try: + server.xend.group.save(dgid, prefix) + except xmlrpclib.Fault, ex: + err(str(ex)) + except Exception, ex: + print("Error: %s" % str(ex)) + raise Exception + + +# retore a group of running domains +def grp_restore(srcs): + try: + server.xend.group.restore(srcs) + except xmlrpclib.Fault, ex: + err(str(ex)) + except Exception, ex: + print("Error: %s" % str(ex)) + raise Exception + + +# suspend a group of running, managed domains +#def grp_suspend(dgid): +# grpinfo = get_grp(dgid) +# idCheck(grpinfo['dgid'],"suspend") +# try: +# server.xend.group.suspend(dgid) +# except xmlrpclib.Fault, ex: +# err(str(ex)) +# except Exception, ex: +# print("Error: %s" % str(ex)) +# raise Exception + + +# resume a suspended domain group +#def grp_resume(dgid): +# try: +# server.xend.group.resume(dgid) +# except xmlrpclib.Fault, ex: +# err(str(ex)) +# except Exception, ex: +# print("Error: %s" % str(ex)) +# raise Exception + + +# pause a domain group +def grp_pause(dgid): + grpinfo = get_grp(dgid) + idCheck(grpinfo['dgid'],"pause") + try: + server.xend.group.pause(grpinfo['dgid']) + except xmlrpclib.Fault, ex: + err(str(ex)) + except Exception, ex: + print("Error: %s" % str(ex)) + raise Exception + + +# unpause a domain group +def grp_unpause(dgid): + grpinfo = get_grp(dgid) + idCheck(grpinfo['dgid'],"unpause") + try: + server.xend.group.unpause(grpinfo['dgid']) + except xmlrpclib.Fault, ex: + err(str(ex)) + except Exception, ex: + print("Error: %s" % str(ex)) + raise Exception + + +# migrate a domain group +def grp_migrate(dgid, dst, live, resource, port): + grpinfo = get_grp(dgid) + idCheck(grpinfo['dgid'],"unpause") + try: + server.xend.group.migrate(grpinfo['dgid'], dst, live, resource, port) + except xmlrpclib.Fault, ex: + err(str(ex)) + except Exception, ex: + print("Error: %s" % str(ex)) + raise Exception + + +# cause a domain to join a group +def grp_join( dom, dgid ): + grpinfo = get_grp(dgid) + domid = sxp.child_value(server.xend.domain(dom), 'domid') + try: + server.xend.group.join(domid, grpinfo['dgid']) + except xmlrpclib.Fault, ex: + err(str(ex)) + except Exception, ex: + print("Error: %s" % str(ex)) + raise Exception + + +# print list of domain group stats +def grp_list(): + try: + domgrps = server.xend.group.list() + format = "%-20s %-6s %-5s %-46s" + print format % ('Name', 'ID', 'Size', 'Members') + for grpinfo in domgrps: + name = grpinfo['grp_name'] + dgid = grpinfo['dgid'] + size = grpinfo['size'] + members = ", ".join(grpinfo['members']) + print format % (name, dgid, size, members) + except xmlrpclib.Fault, ex: + err(str(ex)) + except Exception, ex: + print("Error: %s" % str(ex)) + raise Exception diff -urN xen-unstable/tools/python/xen/xm/main.py xen-unstable-trp-domgrps-rebase-tip/tools/python/xen/xm/main.py --- xen-unstable/tools/python/xen/xm/main.py 2007-12-17 16:45:04.000000000 -0500 +++ xen-unstable-trp-domgrps-rebase-tip/tools/python/xen/xm/main.py 2007-12-17 16:44:21.000000000 -0500 @@ -49,6 +49,7 @@ from xen.xm.opts import OptionError, Opts, wrap, set_true from xen.xm import console from xen.util.xmlrpcclient import ServerProxy +from xen.xm import group import xen.util.xsm.xsm as security from xen.util.xsm.xsm import XSMError from xen.util.acmpolicy import ACM_LABEL_UNLABELED_DISPLAY @@ -197,6 +198,27 @@ 'labels' : ('[policy] [type=dom|res|any]', 'List <type> labels for (active) policy.'), 'serve' : ('', 'Proxy Xend XMLRPC over stdio.'), + + # domain groups + + 'grp-create' : ('<config> [--managed | -m]','Create a domain group'), + 'grp-shutdown' : ('<grp> [--keep| -k]','Shutdown all domains in group'), + 'grp-destroy' : ('<grp> [--force | -f]','Destroy group'), + 'grp-reboot' : ('<grp>','Reboot all domains in group'), + 'grp-pause' : ('<grp>','Pause all domains in group'), + 'grp-unpause' : ('<grp>','Unpause all domains in group'), + 'grp-save' : ('<grp> <prefix>','Save all domains in group to ' + 'files with the specified prefix'), + 'grp-restore' : ('<CheckpointFile> [CheckpointFile ...]', + 'Restore all domains in group from file(s)'), + 'grp-suspend' : ('<grp>','Suspend all domains in group' + ' ** NOT YET IMPLEMENTED **'), + 'grp-resume' : ('<grp>','Resume all domains in group' + ' ** NOT YET IMPLEMENTED **'), + 'grp-migrate' : ('<grp> <host> [--live | -l]', + 'Migrate all domains in group to host'), + 'grp-join' : ('<dom> <grp>','Add domain to group'), + 'grp-list' : ('','List groups and their members'), } SUBCOMMAND_OPTIONS = { @@ -313,6 +335,22 @@ "vcpu-set", ] +group_commands = [ + "grp-create", + "grp-shutdown", + "grp-destroy", + "grp-reboot", + "grp-pause", + "grp-unpause", + "grp-save", + "grp-restore", + "grp-suspend", + "grp-resume", + "grp-migrate", + "grp-join", + "grp-list", +] + host_commands = [ "debug-keys", "dmesg", @@ -358,7 +396,7 @@ all_commands = (domain_commands + host_commands + scheduler_commands + device_commands + vnet_commands + acm_commands + - ['shell', 'event-monitor']) + ['shell', 'event-monitor'] + group_commands) ## @@ -529,14 +567,19 @@ def map2sxp(m): return [[k, m[k]] for k in m.keys()] -def arg_check(args, name, lo, hi = -1): +def arg_check(args, name, lo, hi = None): n = len([i for i in args if i != '--']) - if hi == -1: + if hi == None: if n != lo: err("'xm %s' requires %d argument%s.\n" % (name, lo, lo == 1 and '' or 's')) usage(name) + elif hi == -1: + if n < lo: + err("'xm %s' requires at least %d argument%s.\n" % (name, lo, + lo == 1 and '' or 's')) + usage(name) else: if n < lo or n > hi: err("'xm %s' requires between %d and %d arguments.\n" % @@ -863,6 +906,7 @@ parsed_info = { 'domid' : get_info('domid', str, ''), + 'dgid' : get_info('dgid', int, -1), 'name' : get_info('name', str, '??'), 'state' : get_info('state', str, ''), @@ -932,12 +976,11 @@ print format % d def xm_label_list(doms): - print '%-40s %5s %5s %5s %10s %9s %-10s' % \ - ('Name', 'ID', 'Mem', 'VCPUs', 'State', 'Time(s)', 'Label') - + print '%-40s %5s %5s %5s %10s %9s %-10s %7s' % \ + ('Name', 'ID', 'Mem', 'VCPUs', 'State', 'Time(s)', 'Label', 'Dgid') output = [] format = '%(name)-40s %(domid)5s %(mem)5d %(vcpus)5d %(state)10s ' \ - '%(cpu_time)8.1f %(seclabel)10s' + '%(cpu_time)8.1f %(seclabel)10s %(dgid)7d' for dom in doms: d = parse_doms_info(dom) @@ -2391,7 +2434,100 @@ print format2 % r - +def xm_grp_create(args): + arg_check(args, "grp-create", 1) + + CONFIG_ROOT = '/etc/xen/' + config_path = args[0] + + if ( os.path.exists( config_path ) ): + verified_config_path = config_path + elif ( os.path.exists(CONFIG_ROOT + config_path ) ): + verified_config_path = CONFIG_ROOT + config_path + else: + err( "configuration file [%s] not found" % config_path ) + return 1 + + return group.grp_create( verified_config_path ) + +def xm_grp_destroy(args): + force = False + arg_check(args, "grp-destroy", 1, 2) + dgid = args[0] + for clflag in ['--force', '-f']: + if clflag in args: + force = True + return group.grp_destroy(dgid, force) + +def xm_grp_shutdown(args): + keep = False + arg_check(args, "grp-shutdown", 1, 2) + dgid = args[0] + for clflag in ['--keep', '-k']: + if clflag in args: + keep = True + return group.grp_shutdown(dgid, "poweroff", keep) + +def xm_grp_reboot(args): + arg_check(args, "grp-reboot", 1) + dgid = args[0] + return group.grp_shutdown(dgid, "reboot", True) + +def xm_grp_pause(args): + arg_check(args, "grp-pause", 1) + dgid = args[0] + return group.grp_pause(dgid) + +def xm_grp_unpause(args): + arg_check(args, "grp-unpause", 1) + dgid = args[0] + return group.grp_unpause(dgid) + +def xm_grp_save(args): + arg_check(args, "grp-save", 2) + dgid = args[0] + prefix = args[1] + return group.grp_save(dgid, prefix) + +def xm_grp_restore(args): + arg_check(args, "grp-restore", 1, -1) + return group.grp_restore(args) + +def xm_grp_suspend(args): + print "Not yet implemented" + #arg_check(args, "grp-suspend", 1) + #dgid = args[0] + #return group.grp_suspend(dgid) + +def xm_grp_resume(args): + print "Not yet implemented" + #arg_check(args, "grp-resume", 1) + #dgid = args[0] + #return group.grp_resume(dgid) + +def xm_grp_migrate(args): + live = False + arg_check(args, "grp-migrate", 2, 3) + dgid = args[0] + dst = args[1] + for clflag in ['--live', '-l']: + if clflag in args: + live = True + # hardcode these options for now + resource = 0 + port = 0 + return group.grp_migrate(dgid,dst,live,resource,port) + +def xm_grp_join(args): + arg_check(args, "grp-join", 2) + domid = args[0] + dgid = args[1] + return group.grp_join(domid, dgid) + +def xm_grp_list(args): + arg_check(args, "grp-list", 0) + return group.grp_list() + commands = { "shell": xm_shell, "event-monitor": xm_event_monitor, @@ -2455,6 +2591,20 @@ "vnet-delete": xm_vnet_delete, # vtpm "vtpm-list": xm_vtpm_list, + # group + "grp-create": xm_grp_create, + "grp-shutdown": xm_grp_shutdown, + "grp-destroy": xm_grp_destroy, + "grp-reboot": xm_grp_reboot, + "grp-pause": xm_grp_pause, + "grp-unpause": xm_grp_unpause, + "grp-save": xm_grp_save, + "grp-restore": xm_grp_restore, + "grp-suspend": xm_grp_suspend, + "grp-resume": xm_grp_resume, + "grp-migrate": xm_grp_migrate, + "grp-join": xm_grp_join, + "grp-list": xm_grp_list, } ## The commands supported by a separate argument parser in xend.xm. _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |