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
|