bitkeeper revision 1.1700 (42a854e79oBFuqa_DSY4Lr9IhenUQw)

Merge xenstore changes.
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
This commit is contained in:
cl349@firebug.cl.cam.ac.uk committed 2005-06-09 14:40:39 +00:00
commit 06940d306a
73 files changed
+12292 -826

No files matched your search

+13 -3
View File
@@ -9,13 +9,15 @@ extra_compile_args = [ "-fno-strict-aliasing", "-Wall", "-Werror" ]
include_dirs = [ XEN_ROOT + "/tools/python/xen/lowlevel/xu",
XEN_ROOT + "/tools/libxc",
XEN_ROOT + "/tools/xenstore",
XEN_ROOT + "/tools/xcs",
]
library_dirs = [ XEN_ROOT + "/tools/libxc",
XEN_ROOT + "/tools/xenstore",
]
libraries = [ "xc" ]
libraries = [ "xc", "xenstore" ]
xc = Extension("xc",
extra_compile_args = extra_compile_args,
@@ -30,7 +32,14 @@ xu = Extension("xu",
library_dirs = library_dirs,
libraries = libraries,
sources = [ "xen/lowlevel/xu/xu.c" ])
xs = Extension("xs",
extra_compile_args = extra_compile_args,
include_dirs = include_dirs + [ "xen/lowlevel/xs" ],
library_dirs = library_dirs,
libraries = libraries,
sources = [ "xen/lowlevel/xs/xs.c" ])
setup(name = 'xen',
version = '2.0',
description = 'Xen',
@@ -39,11 +48,12 @@ setup(name = 'xen',
'xen.util',
'xen.xend',
'xen.xend.server',
'xen.xend.xenstore',
'xen.xm',
'xen.web',
],
ext_package = "xen.lowlevel",
ext_modules = [ xc, xu ]
ext_modules = [ xc, xu, xs ]
)
os.chdir('logging')
+18 -13
View File
@@ -14,6 +14,7 @@
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include "xc_private.h"
#include "linux_boot_params.h"
@@ -259,25 +260,28 @@ static PyObject *pyxc_linux_build(PyObject *self,
{
XcObject *xc = (XcObject *)self;
u32 dom;
u32 dom;
char *image, *ramdisk = NULL, *cmdline = "";
int control_evtchn, flags = 0, vcpus = 1;
int flags = 0, vcpus = 1;
int control_evtchn, store_evtchn;
unsigned long store_mfn = 0;
static char *kwd_list[] = { "dom", "control_evtchn",
"image", "ramdisk", "cmdline", "flags", "vcpus",
NULL };
static char *kwd_list[] = { "dom", "control_evtchn", "store_evtchn",
"image", "ramdisk", "cmdline", "flags",
"vcpus", NULL };
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iis|ssii", kwd_list,
&dom, &control_evtchn,
&image, &ramdisk, &cmdline, &flags, &vcpus) )
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iiis|ssii", kwd_list,
&dom, &control_evtchn, &store_evtchn,
&image, &ramdisk, &cmdline, &flags,
&vcpus) )
return NULL;
if ( xc_linux_build(xc->xc_handle, dom, image,
ramdisk, cmdline, control_evtchn, flags, vcpus) != 0 )
ramdisk, cmdline, control_evtchn, flags, vcpus,
store_evtchn, &store_mfn) != 0 )
return PyErr_SetFromErrno(xc_error);
Py_INCREF(zero);
return zero;
return Py_BuildValue("{s:i}", "store_mfn", store_mfn);
}
static PyObject *pyxc_plan9_build(PyObject *self,
@@ -834,6 +838,7 @@ static PyMethodDef pyxc_methods[] = {
0, "\n"
"Query the xc control interface file descriptor.\n\n"
"Returns: [int] file descriptor\n" },
{ "domain_create",
(PyCFunction)pyxc_domain_create,
METH_VARARGS | METH_KEYWORDS, "\n"
@@ -844,8 +849,8 @@ static PyMethodDef pyxc_methods[] = {
{ "domain_dumpcore",
(PyCFunction)pyxc_domain_dumpcore,
METH_VARARGS | METH_KEYWORDS, "\n"
"dump core of a domain.\n"
" dom [int]: Identifier of domain to be paused.\n\n"
"Dump core of a domain.\n"
" dom [int]: Identifier of domain to dump core of.\n"
" corefile [string]: Name of corefile to be created.\n\n"
"Returns: [int] 0 on success; -1 on error.\n" },
+617
View File
@@ -0,0 +1,617 @@
#include <Python.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "xs.h"
/** @file
* Python interface to the Xen Store Daemon (xs).
*/
/* Needed for Python versions earlier than 2.3. */
//#ifndef PyMODINIT_FUNC
//#define PyMODINIT_FUNC DL_EXPORT(void)
//#endif
#define PYPKG "xen.lowlevel.xs"
/** Python wrapper round an xs handle.
*/
typedef struct XsHandle {
PyObject_HEAD;
struct xs_handle *xh;
} XsHandle;
static inline struct xs_handle *xshandle(PyObject *self)
{
struct xs_handle *xh = ((XsHandle*)self)->xh;
if (!xh)
PyErr_SetString(PyExc_RuntimeError, "invalid xenstore daemon handle");
return xh;
}
static inline PyObject *pyvalue_int(int val) {
return (val
? PyInt_FromLong(val)
: PyErr_SetFromErrno(PyExc_RuntimeError));
}
static inline PyObject *pyvalue_str(char *val) {
return (val
? PyString_FromString(val)
: PyErr_SetFromErrno(PyExc_RuntimeError));
}
static PyObject *xspy_write(PyObject *self, PyObject *args, PyObject *kwds)
{
static char *kwd_spec[] = { "path", "data", "create", "excl", NULL };
static char *arg_spec = "ss#|ii";
char *path = NULL;
char *data = NULL;
int data_n = 0;
int create = 0;
int excl = 0;
struct xs_handle *xh = xshandle(self);
PyObject *val = NULL;
int flags = 0;
int xsval = 0;
if (!xh)
goto exit;
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
&path, &data, &data_n, &create, &excl))
goto exit;
if (create)
flags |= O_CREAT;
if (excl)
flags |= O_EXCL;
xsval = xs_write(xh, path, data, data_n, flags);
val = pyvalue_int(xsval);
exit:
return val;
}
static PyObject *xspy_read(PyObject *self, PyObject *args, PyObject *kwds)
{
static char *kwd_spec[] = { "path", NULL };
static char *arg_spec = "s|";
char *path = NULL;
struct xs_handle *xh = xshandle(self);
char *xsval = NULL;
int xsval_n = 0;
PyObject *val = NULL;
if (!xh)
goto exit;
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
&path))
goto exit;
xsval = xs_read(xh, path, &xsval_n);
if (!xsval) {
val = pyvalue_int(0);
goto exit;
}
val = PyString_FromStringAndSize(xsval, xsval_n);
exit:
if (xsval)
free(xsval);
return val;
}
static PyObject *xspy_mkdir(PyObject *self, PyObject *args, PyObject *kwds)
{
static char *kwd_spec[] = { "path", NULL };
static char *arg_spec = "s|";
char *path = NULL;
struct xs_handle *xh = xshandle(self);
PyObject *val = NULL;
int xsval = 0;
if (!xh)
goto exit;
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path))
goto exit;
xsval = xs_mkdir(xh, path);
val = pyvalue_int(xsval);
exit:
return val;
}
static PyObject *xspy_ls(PyObject *self, PyObject *args, PyObject *kwds)
{
static char *kwd_spec[] = { "path", NULL };
static char *arg_spec = "s|";
char *path = NULL;
struct xs_handle *xh = xshandle(self);
PyObject *val = NULL;
char **xsval = NULL;
int xsval_n = 0;
int i;
if (!xh)
goto exit;
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path))
goto exit;
xsval = xs_directory(xh, path, &xsval_n);
if (!xsval) {
val = pyvalue_int(0);
goto exit;
}
val = PyList_New(xsval_n);
for (i = 0; i < xsval_n; i++)
PyList_SetItem(val, i, PyString_FromString(xsval[i]));
exit:
return val;
}
static PyObject *xspy_rm(PyObject *self, PyObject *args, PyObject *kwds)
{
static char *kwd_spec[] = { "path", NULL };
static char *arg_spec = "s|";
char *path = NULL;
struct xs_handle *xh = xshandle(self);
PyObject *val = NULL;
int xsval = 0;
if (!xh)
goto exit;
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path))
goto exit;
xsval = xs_rm(xh, path);
val = pyvalue_int(xsval);
exit:
return val;
}
static PyObject *xspy_get_permissions(PyObject *self, PyObject *args,
PyObject *kwds)
{
static char *kwd_spec[] = { "path", NULL };
static char *arg_spec = "s|";
char *path = NULL;
struct xs_handle *xh = xshandle(self);
PyObject *val = NULL;
struct xs_permissions *perms;
int perms_n = 0;
int i;
if (!xh)
goto exit;
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path))
goto exit;
perms = xs_get_permissions(xh, path, &perms_n);
if (!perms) {
PyErr_SetFromErrno(PyExc_RuntimeError);
goto exit;
}
val = PyList_New(perms_n);
for (i = 0; i < perms_n; i++, perms++) {
PyObject *p = Py_BuildValue("{s:i,s:i,s:i,s:i,s:i}",
"dom", perms->id,
"read", (perms->perms & XS_PERM_READ),
"write", (perms->perms & XS_PERM_WRITE),
"create", (perms->perms & XS_PERM_CREATE),
"owner", (perms->perms & XS_PERM_OWNER));
PyList_SetItem(val, i, p);
}
exit:
return val;
}
static PyObject *xspy_set_permissions(PyObject *self, PyObject *args,
PyObject *kwds)
{
static char *kwd_spec[] = { "path", "perms", NULL };
static char *arg_spec = "sO";
char *path = NULL;
PyObject *perms = NULL;
static char *perm_names[] = { "dom", "read", "write", "create", "owner",
NULL };
static char *perm_spec = "i|iiii";
struct xs_handle *xh = xshandle(self);
int i, xsval;
struct xs_permissions *xsperms = NULL;
int xsperms_n = 0;
PyObject *tuple0 = NULL;
PyObject *val = NULL;
if (!xh)
goto exit;
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
&path, &perms))
goto exit;
if (!PyList_Check(perms)) {
PyErr_SetString(PyExc_RuntimeError, "perms must be a list");
goto exit;
}
xsperms_n = PyList_Size(perms);
xsperms = calloc(xsperms_n, sizeof(struct xs_permissions));
if (!xsperms) {
PyErr_SetString(PyExc_RuntimeError, "out of memory");
goto exit;
}
tuple0 = PyTuple_New(0);
if (!tuple0)
goto exit;
for (i = 0; i < xsperms_n; i++) {
/* Domain the permissions apply to. */
int dom = 0;
/* Read/write perms. Set these. */
int p_read = 0, p_write = 0;
/* Create/owner perms. Ignore them.
* This is so the output from get_permissions() can be used
* as input to set_permissions().
*/
int p_create = 0, p_owner = 0;
PyObject *p = PyList_GetItem(perms, i);
if (!PyArg_ParseTupleAndKeywords(tuple0, p, perm_spec, perm_names,
&dom, &p_read, &p_write, &p_create,
&p_owner))
goto exit;
xsperms[i].id = dom;
if (p_read)
xsperms[i].perms |= XS_PERM_READ;
if (p_write)
xsperms[i].perms |= XS_PERM_WRITE;
}
xsval = xs_set_permissions(xh, path, xsperms, xsperms_n);
val = pyvalue_int(xsval);
exit:
Py_XDECREF(tuple0);
if (xsperms)
free(xsperms);
return val;
}
static PyObject *xspy_watch(PyObject *self, PyObject *args, PyObject *kwds)
{
static char *kwd_spec[] = { "path", "priority", NULL };
static char *arg_spec = "s|i";
char *path = NULL;
int priority = 0;
struct xs_handle *xh = xshandle(self);
PyObject *val = NULL;
int xsval = 0;
if (!xh)
goto exit;
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
&path, &priority))
goto exit;
xsval = xs_watch(xh, path, priority);
val = pyvalue_int(xsval);
exit:
return val;
}
static PyObject *xspy_read_watch(PyObject *self, PyObject *args,
PyObject *kwds)
{
static char *kwd_spec[] = { NULL };
static char *arg_spec = "";
struct xs_handle *xh = xshandle(self);
PyObject *val = NULL;
char *xsval = NULL;
if (!xh)
goto exit;
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec))
goto exit;
xsval = xs_read_watch(xh);
val = pyvalue_str(xsval);
exit:
if (xsval)
free(xsval);
return val;
}
static PyObject *xspy_acknowledge_watch(PyObject *self, PyObject *args,
PyObject *kwds)
{
static char *kwd_spec[] = { NULL };
static char *arg_spec = "";
struct xs_handle *xh = xshandle(self);
PyObject *val = NULL;
int xsval = 0;
if (!xh)
goto exit;
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec))
goto exit;
xsval = xs_acknowledge_watch(xh);
val = pyvalue_int(xsval);
exit:
return val;
}
static PyObject *xspy_unwatch(PyObject *self, PyObject *args, PyObject *kwds)
{
static char *kwd_spec[] = { "path", NULL };
static char *arg_spec = "s|";
char *path = NULL;
struct xs_handle *xh = xshandle(self);
PyObject *val = NULL;
int xsval = 0;
if (!xh)
goto exit;
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path))
goto exit;
xsval = xs_unwatch(xh, path);
val = pyvalue_int(xsval);
exit:
return val;
}
static PyObject *xspy_transaction_start(PyObject *self, PyObject *args,
PyObject *kwds)
{
static char *kwd_spec[] = { "path", NULL };
static char *arg_spec = "s|";
char *path = NULL;
struct xs_handle *xh = xshandle(self);
PyObject *val = NULL;
int xsval = 0;
if (!xh)
goto exit;
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path))
goto exit;
xsval = xs_transaction_start(xh, path);
val = pyvalue_int(xsval);
exit:
return val;
}
static PyObject *xspy_transaction_end(PyObject *self, PyObject *args,
PyObject *kwds)
{
static char *kwd_spec[] = { "abort", NULL };
static char *arg_spec = "|i";
int abort = 0;
struct xs_handle *xh = xshandle(self);
PyObject *val = NULL;
int xsval = 0;
if (!xh)
goto exit;
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &abort))
goto exit;
xsval = xs_transaction_end(xh, abort);
val = pyvalue_int(xsval);
exit:
return val;
}
static PyObject *xspy_introduce_domain(PyObject *self, PyObject *args,
PyObject *kwds)
{
static char *kwd_spec[] = { "dom", "page", "port", "path", NULL };
static char *arg_spec = "iiis|";
domid_t dom = 0;
unsigned long page = 0;
unsigned int port = 0;
char *path = NULL;
struct xs_handle *xh = xshandle(self);
PyObject *val = NULL;
int xsval = 0;
if (!xh)
goto exit;
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
&dom, &page, &port, &path))
goto exit;
printf("%s> dom=%u page=0x%08lx port=%u path=%s\n", __FUNCTION__, dom,
page, port, path);
xsval = xs_introduce_domain(xh, dom, page, port, path);
printf("%s> xsval=%d\n", __FUNCTION__, xsval);
val = pyvalue_int(xsval);
exit:
return val;
}
static PyObject *xspy_release_domain(PyObject *self, PyObject *args,
PyObject *kwds)
{
static char *kwd_spec[] = { "dom", NULL };
static char *arg_spec = "i|";
domid_t dom;
struct xs_handle *xh = xshandle(self);
PyObject *val = NULL;
int xsval = 0;
if (!xh)
goto exit;
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
&dom))
goto exit;
printf("%s> dom=%u\n", __FUNCTION__, dom);
xsval = xs_release_domain(xh, dom);
printf("%s> xsval=%d\n", __FUNCTION__, xsval);
val = pyvalue_int(xsval);
exit:
return val;
}
static PyObject *xspy_close(PyObject *self, PyObject *args, PyObject *kwds)
{
static char *kwd_spec[] = { NULL };
static char *arg_spec = "";
struct xs_handle *xh = xshandle(self);
PyObject *val = NULL;
int xsval = 1;
if (!xh)
goto exit;
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec))
goto exit;
xs_daemon_close(xh);
((XsHandle*)self)->xh = NULL;
val = pyvalue_int(xsval);
exit:
return val;
}
static PyObject *xspy_shutdown(PyObject *self, PyObject *args, PyObject *kwds)
{
static char *kwd_spec[] = { NULL };
static char *arg_spec = "";
struct xs_handle *xh = xshandle(self);
PyObject *val = NULL;
int xsval = 0;
if (!xh)
goto exit;
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec))
goto exit;
xsval = xs_shutdown(xh);
val = pyvalue_int(xsval);
exit:
return val;
}
#define XSPY_METH(_name) \
#_name, \
(PyCFunction) xspy_ ## _name, \
(METH_VARARGS | METH_KEYWORDS)
// mtime
// ctime
static PyMethodDef xshandle_methods[] = {
{ XSPY_METH(read),
"read(path) : read data\n" },
{ XSPY_METH(write),
"write(path, data, [creat], [excl]): write data\n" },
{ XSPY_METH(ls),
"ls(path): list directory.\n" },
{ XSPY_METH(mkdir),
"mkdir(path): make a directory.\n" },
{ XSPY_METH(rm),
"rm(path): remove a path (dir must be empty).\n" },
{ XSPY_METH(get_permissions),
"get_permissions(path)\n" },
{ XSPY_METH(set_permissions),
"set_permissions(path)\n" },
{ XSPY_METH(watch),
"watch(path)\n" },
{ XSPY_METH(read_watch),
"read_watch()\n" },
{ XSPY_METH(acknowledge_watch),
"acknowledge_watch()\n" },
{ XSPY_METH(unwatch),
"unwatch()\n" },
{ XSPY_METH(transaction_start),
"transaction_start()\n" },
{ XSPY_METH(transaction_end),
"transaction_end([abort])\n" },
{ XSPY_METH(introduce_domain),
"introduce_domain(dom, page, port)\n" },
{ XSPY_METH(release_domain),
"release_domain(dom)\n" },
{ XSPY_METH(close),
"close()\n" },
{ XSPY_METH(shutdown),
"shutdown()\n" },
{ NULL, NULL, 0, NULL }
};
static PyObject *xshandle_getattr(PyObject *self, char *name)
{
PyObject *val = NULL;
if (strcmp(name, "fileno") == 0) {
struct xs_handle *xh = xshandle(self);
val = PyInt_FromLong((xh ? xs_fileno(xh) : -1));
} else
val = Py_FindMethod(xshandle_methods, self, name);
return val;
}
static void xshandle_dealloc(PyObject *self)
{
XsHandle *xh = (XsHandle*)self;
if (xh->xh) {
xs_daemon_close(xh->xh);
xh->xh = NULL;
}
PyObject_Del(self);
}
static PyTypeObject xshandle_type = {
PyObject_HEAD_INIT(&PyType_Type)
0,
"xshandle",
sizeof(XsHandle),
0,
xshandle_dealloc, /* tp_dealloc */
NULL, /* tp_print */
xshandle_getattr, /* tp_getattr */
NULL, /* tp_setattr */
NULL, /* tp_compare */
NULL, /* tp_repr */
NULL, /* tp_as_number */
NULL, /* tp_as_sequence */
NULL, /* tp_as_mapping */
NULL /* tp_hash */
};
static PyObject *xshandle_open(PyObject *self, PyObject *args, PyObject *kwds)
{
static char *kwd_spec[] = { "readonly", NULL };
static char *arg_spec = "|i";
int readonly = 0;
XsHandle *xsh = NULL;
PyObject *val = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
&readonly))
goto exit;
xsh = PyObject_New(XsHandle, &xshandle_type);
if (!xsh)
goto exit;
xsh->xh = (readonly ? xs_daemon_open_readonly() : xs_daemon_open());
if (!xsh->xh) {
PyObject_Del(xsh);
val = pyvalue_int(0);
goto exit;
}
val = (PyObject *)xsh;
exit:
return val;
}
static PyMethodDef xs_methods[] = {
{ "open", (PyCFunction)xshandle_open, (METH_VARARGS | METH_KEYWORDS),
"Open a connection to the xenstore daemon.\n" },
{ NULL, NULL, 0, NULL }
};
PyMODINIT_FUNC initxs (void)
{
PyObject *module;
module = Py_InitModule(PYPKG, xs_methods);
}
+2 -1
View File
@@ -1370,7 +1370,8 @@ static PyObject *xu_port_new(PyObject *self, PyObject *args, PyObject *kwds)
fail1:
PyObject_Del((PyObject *)xup);
return NULL;
PyErr_SetString(PyExc_ValueError, "cannot create port");
return NULL;
}
static PyObject *xu_port_getattr(PyObject *obj, char *name)
+11
View File
@@ -0,0 +1,11 @@
from string import join, split
def macToString(mac):
return ':'.join(map(lambda x: "%02x" % x, mac))
def macFromString(str):
mac = [ int(x, 16) for x in str.split(':') ]
if len(mac) != 6:
raise ValueError("invalid mac: %s" % str)
return mac
+10 -13
View File
@@ -77,19 +77,16 @@ class SrvDir(SrvBase):
return v
def render_GET(self, req):
try:
if self.use_sxp(req):
req.setHeader("Content-type", sxp.mime_type)
self.ls(req, 1)
else:
req.write('<html><head></head><body>')
self.print_path(req)
self.ls(req)
self.form(req)
req.write('</body></html>')
return ''
except Exception, ex:
self._perform_err(ex, "GET", req)
if self.use_sxp(req):
req.setHeader("Content-type", sxp.mime_type)
self.ls(req, 1)
else:
req.write('<html><head></head><body>')
self.print_path(req)
self.ls(req)
self.form(req)
req.write('</body></html>')
return ''
def ls(self, req, use_sxp=0):
url = req.prePathURL()
+12 -9
View File
@@ -285,15 +285,18 @@ def prettyprint(sxpr, out=sys.stdout, width=80):
sxp.show(sxpr, out=out)
print >> out
def prettyprintstring(sxp):
class tmpstr:
def __init__(self):
self.str = ""
def write(self, str):
self.str = self.str + str
tmp = tmpstr()
prettyprint(sxp, out=tmp)
return tmp.str
def prettyprintstring(sxpr, width=80):
"""Prettyprint an SXP form to a string.
sxpr s-expression
width maximum output width
"""
io = StringIO.StringIO()
prettyprint(sxpr, out=io, width=width)
io.seek(0)
val = io.getvalue()
io.close()
return val
def main():
pin = sxp.Parser()
+4 -4
View File
@@ -43,7 +43,7 @@ def save(xd, fd, dominfo):
write_exact(fd, config, "could not write guest state file: config")
cmd = [PATH_XC_SAVE, str(xc.handle()), str(fd),
dominfo.id]
str(dominfo.id)]
log.info("[xc_save] " + join(cmd))
child = xPopen3(cmd, True, -1, [fd, xc.handle()])
@@ -63,10 +63,10 @@ def save(xd, fd, dominfo):
if fd == child.fromchild.fileno():
l = child.fromchild.readline()
if l.rstrip() == "suspend":
log.info("suspending %s" % dominfo.id)
log.info("suspending %d" % dominfo.id)
xd.domain_shutdown(dominfo.id, reason='suspend')
dominfo.state_wait("suspended")
log.info("suspend %s done" % dominfo.id)
log.info("suspend %d done" % dominfo.id)
child.tochild.write("done\n")
child.tochild.flush()
if filter(lambda (fd, event): event & select.POLLHUP, r):
@@ -109,7 +109,7 @@ def restore(xd, fd):
"not a valid guest state file: pfn count out of range")
cmd = [PATH_XC_RESTORE, str(xc.handle()), str(fd),
dominfo.id, str(nr_pfns)]
str(dominfo.id), str(nr_pfns)]
log.info("[xc_restore] " + join(cmd))
child = xPopen3(cmd, True, -1, [fd, xc.handle()])
child.tochild.close()
+152 -134
View File
@@ -7,46 +7,42 @@
"""
import errno
import os
import scheduler
import string
import sys
import traceback
import time
import traceback
import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
from xen.xend.server import relocate
import sxp
import XendRoot; xroot = XendRoot.instance()
import XendCheckpoint
import XendDB
import XendDomainInfo
import EventServer; eserver = EventServer.instance()
from XendError import XendError
from XendLogging import log
from xen.xend import sxp
from xen.xend import XendRoot; xroot = XendRoot.instance()
from xen.xend import XendCheckpoint
from xen.xend.XendDomainInfo import XendDomainInfo, shutdown_reason
from xen.xend import EventServer; eserver = EventServer.instance()
from xen.xend.XendError import XendError
from xen.xend.XendLogging import log
from xen.xend import scheduler
from xen.xend.server import channel
from xen.xend.server import relocate
from xen.xend.uuid import getUuid
from xen.xend.xenstore import XenNode, DBMap
__all__ = [ "XendDomain" ]
SHUTDOWN_TIMEOUT = 30
class XendDomainDict(dict):
def get_by_name(self, name):
try:
return filter(lambda d: d.name == name, self.values())[0]
except IndexError, err:
return None
class XendDomain:
"""Index of all domains. Singleton.
"""
"""Path to domain database."""
dbpath = "domain"
class XendDomainDict(dict):
def get_by_name(self, name):
try:
return filter(lambda d: d.name == name, self.values())[0]
except IndexError, err:
return None
"""Dict of domain info indexed by domain id."""
domains = XendDomainDict()
domains = None
def __init__(self):
# Hack alert. Python does not support mutual imports, but XendDomainInfo
@@ -54,8 +50,8 @@ class XendDomain:
# to import XendDomain from XendDomainInfo causes unbounded recursion.
# So we stuff the XendDomain instance (self) into xroot's components.
xroot.add_component("xen.xend.XendDomain", self)
# Table of domain info indexed by domain id.
self.db = XendDB.XendDB(self.dbpath)
self.domains = XendDomainDict()
self.dbmap = DBMap(db=XenNode("/domain"))
eserver.subscribe('xend.virq', self.onVirq)
self.initial_refresh()
@@ -77,18 +73,16 @@ class XendDomain:
domlist = xc.domain_getinfo()
doms = {}
for d in domlist:
domid = str(d['dom'])
domid = d['dom']
doms[domid] = d
return doms
def xen_domain(self, dom):
"""Get info about a single domain from xc.
Returns None if not found.
@param dom domain id (int)
"""
try:
dom = int(dom)
except ValueError:
return None
dominfo = xc.domain_getinfo(dom, 1)
if dominfo == [] or dominfo[0]['dom'] != dom:
dominfo = None
@@ -100,37 +94,36 @@ class XendDomain:
"""Refresh initial domain info from db.
"""
doms = self.xen_domains()
for config in self.db.fetchall("").values():
domid = str(sxp.child_value(config, 'id'))
if domid in doms:
self.dbmap.readDB()
for domdb in self.dbmap.values():
try:
domid = int(domdb.id)
except:
domid = None
# XXX if domid in self.domains, then something went wrong
if (domid is None) or (domid in self.domains):
domdb.delete()
elif domid in doms:
try:
self._new_domain(config, doms[domid])
self.update_domain(domid)
self._new_domain(domdb, doms[domid])
except Exception, ex:
log.exception("Error recreating domain info: id=%s", domid)
log.exception("Error recreating domain info: id=%d", domid)
self._delete_domain(domid)
else:
self._delete_domain(domid)
self.refresh(cleanup=True)
def sync_domain(self, info):
"""Sync info for a domain to disk.
info domain info
"""
self.db.save(info.id, info.sxpr())
def close(self):
pass
def _new_domain(self, savedinfo, info):
def _new_domain(self, db, info):
"""Create a domain entry from saved info.
@param savedinfo: saved info from the db
@param info: domain info from xen
@param db: saved info from the db
@param info: domain info from xen
@return: domain
"""
dominfo = XendDomainInfo.vm_recreate(savedinfo, info)
dominfo = XendDomainInfo.recreate(db, info)
self.domains[dominfo.id] = dominfo
return dominfo
@@ -144,11 +137,11 @@ class XendDomain:
for i, d in self.domains.items():
if i != d.id:
del self.domains[i]
self.db.delete(i)
self.dbmap.delete(d.uuid)
if info.id in self.domains:
notify = False
self.domains[info.id] = info
self.sync_domain(info)
info.exportToDB(save=True)
if notify:
eserver.inject('xend.domain.create', [info.name, info.id])
@@ -158,12 +151,26 @@ class XendDomain:
@param id: domain id
@param notify: send a domain died event if true
"""
try:
if self.xen_domain(id):
return
except:
pass
info = self.domains.get(id)
if info:
del self.domains[id]
info.cleanup()
info.delete()
if notify:
eserver.inject('xend.domain.died', [info.name, info.id])
self.db.delete(id)
# XXX this should not be needed
for domdb in self.dbmap.values():
try:
domid = int(domdb.id)
except:
domid = None
if (domid is None) or (domid == id):
domdb.delete()
def reap(self):
"""Look for domains that have crashed or stopped.
@@ -178,22 +185,19 @@ class XendDomain:
not(d['running'] or d['paused'] or d['blocked']))
if dead:
casualties.append(d)
destroyed = 0
for d in casualties:
id = str(d['dom'])
#print 'reap>', id
id = d['dom']
dominfo = self.domains.get(id)
name = (dominfo and dominfo.name) or '??'
if dominfo and dominfo.is_terminated():
#print 'reap> already terminated:', id
continue
log.debug('XendDomain>reap> domain died name=%s id=%s', name, id)
log.debug('XendDomain>reap> domain died name=%s id=%d', name, id)
if d['shutdown']:
reason = XendDomainInfo.shutdown_reason(d['shutdown_reason'])
log.debug('XendDomain>reap> shutdown name=%s id=%s reason=%s', name, id, reason)
reason = shutdown_reason(d['shutdown_reason'])
log.debug('XendDomain>reap> shutdown name=%s id=%d reason=%s', name, id, reason)
if reason in ['suspend']:
if dominfo and dominfo.is_terminated():
log.debug('XendDomain>reap> Suspended domain died id=%s', id)
log.debug('XendDomain>reap> Suspended domain died id=%d', id)
else:
eserver.inject('xend.domain.suspended', [name, id])
if dominfo:
@@ -203,10 +207,9 @@ class XendDomain:
eserver.inject('xend.domain.exit', [name, id, reason])
self.domain_restart_schedule(id, reason)
else:
if xroot.get_enable_dump() == 'true':
xc.domain_dumpcore(dom = int(id), corefile = "/var/xen/dump/%s.%s.core"%(name,id))
if xroot.get_enable_dump():
self.domain_dumpcore(id)
eserver.inject('xend.domain.exit', [name, id, 'crash'])
destroyed += 1
self.final_domain_destroy(id)
def refresh(self, cleanup=False):
@@ -216,7 +219,7 @@ class XendDomain:
self.reap()
doms = self.xen_domains()
# Add entries for any domains we don't know about.
for (id, d) in doms.items():
for id in doms.keys():
if id not in self.domains:
self.domain_lookup(id)
# Remove entries for domains that no longer exist.
@@ -234,16 +237,7 @@ class XendDomain:
scheduler.now(self.domain_restarts)
def update_domain(self, id):
"""Update the saved info for a domain.
@param id: domain id
"""
dominfo = self.domains.get(id)
if dominfo:
self.sync_domain(dominfo)
def refresh_domain(self, id):
"""Refresh information for a single domain.
"""Update information for a single domain.
@param id: domain id
"""
@@ -279,8 +273,7 @@ class XendDomain:
@param config: configuration
@return: domain
"""
dominfo = XendDomainInfo.vm_create(config)
self._add_domain(dominfo)
dominfo = XendDomainInfo.create(self.dbmap, config)
return dominfo
def domain_restart(self, dominfo):
@@ -293,7 +286,6 @@ class XendDomain:
[dominfo.name, dominfo.id, "begin"])
try:
dominfo.restart()
self._add_domain(dominfo)
log.info('Restarted domain name=%s id=%s', dominfo.name, dominfo.id)
eserver.inject("xend.domain.restart",
[dominfo.name, dominfo.id, "success"])
@@ -309,14 +301,13 @@ class XendDomain:
"""Configure an existing domain. This is intended for internal
use by domain restore and migrate.
@param id: domain id
@param vmconfig: vm configuration
"""
config = sxp.child_value(vmconfig, 'config')
dominfo = XendDomainInfo.vm_restore(config)
self._add_domain(dominfo)
uuid = sxp.child_value(vmconfig, 'uuid')
dominfo = XendDomainInfo.restore(self.dbmap, config, uuid=uuid)
return dominfo
def domain_restore(self, src, progress=False):
"""Restore a domain from file.
@@ -326,9 +317,7 @@ class XendDomain:
try:
fd = os.open(src, os.O_RDONLY)
return XendCheckpoint.restore(self, fd)
except OSError, ex:
raise XendError("can't read guest state file %s: %s" %
(src, ex[1]))
@@ -339,24 +328,35 @@ class XendDomain:
@param id: domain id
@return: domain object (or None)
"""
id = str(id)
self.refresh_domain(id)
self.update_domain(id)
return self.domains.get(id)
def domain_lookup(self, name):
name = str(name)
dominfo = self.domains.get_by_name(name) or self.domains.get(name)
if dominfo:
return dominfo
try:
d = self.xen_domain(name)
if d:
log.info("Creating entry for unknown domain: id=%s", name)
dominfo = XendDomainInfo.vm_recreate(None, d)
self._add_domain(dominfo)
return dominfo
except Exception, ex:
log.exception("Error creating domain info: id=%s", name)
def domain_lookup(self, id):
dominfo = self.domains.get(id)
if not dominfo:
try:
info = self.xen_domain(id)
if info:
uuid = getUuid()
log.info(
"Creating entry for unknown domain: id=%d uuid=%s",
id, uuid)
db = self.dbmap.addChild(uuid)
dominfo = XendDomainInfo.recreate(db, info)
self._add_domain(dominfo)
except Exception, ex:
log.exception("Error creating domain info: id=%d", id)
return dominfo
def domain_lookup_by_name(self, name):
dominfo = self.domains.get_by_name(name)
if not dominfo:
try:
id = int(name)
dominfo = self.domain_lookup(id)
except ValueError:
pass
return dominfo
def domain_unpause(self, id):
"""Unpause domain execution.
@@ -366,7 +366,7 @@ class XendDomain:
dominfo = self.domain_lookup(id)
eserver.inject('xend.domain.unpause', [dominfo.name, dominfo.id])
try:
return xc.domain_unpause(dom=dominfo.dom)
return xc.domain_unpause(dom=dominfo.id)
except Exception, ex:
raise XendError(str(ex))
@@ -378,7 +378,7 @@ class XendDomain:
dominfo = self.domain_lookup(id)
eserver.inject('xend.domain.pause', [dominfo.name, dominfo.id])
try:
return xc.domain_pause(dom=dominfo.dom)
return xc.domain_pause(dom=dominfo.id)
except Exception, ex:
raise XendError(str(ex))
@@ -436,7 +436,7 @@ class XendDomain:
@param id: domain id
@param reason: shutdown reason
"""
log.debug('domain_restart_schedule> %s %s %d', id, reason, force)
log.debug('domain_restart_schedule> %d %s %d', id, reason, force)
dominfo = self.domain_lookup(id)
if not dominfo:
return
@@ -484,7 +484,7 @@ class XendDomain:
except:
#todo
try:
val = xc.domain_destroy(dom=int(id))
val = xc.domain_destroy(dom=id)
except Exception, ex:
raise XendError(str(ex))
return val
@@ -553,7 +553,7 @@ class XendDomain:
"""
dominfo = self.domain_lookup(id)
try:
return xc.domain_pincpu(int(dominfo.id), vcpu, cpumap)
return xc.domain_pincpu(dominfo.id, vcpu, cpumap)
except Exception, ex:
raise XendError(str(ex))
@@ -562,7 +562,7 @@ class XendDomain:
"""
dominfo = self.domain_lookup(id)
try:
return xc.bvtsched_domain_set(dom=dominfo.dom, mcuadv=mcuadv,
return xc.bvtsched_domain_set(dom=dominfo.id, mcuadv=mcuadv,
warpback=warpback, warpvalue=warpvalue,
warpl=warpl, warpu=warpu)
except Exception, ex:
@@ -573,7 +573,7 @@ class XendDomain:
"""
dominfo = self.domain_lookup(id)
try:
return xc.bvtsched_domain_get(dominfo.dom)
return xc.bvtsched_domain_get(dominfo.id)
except Exception, ex:
raise XendError(str(ex))
@@ -581,20 +581,21 @@ class XendDomain:
def domain_cpu_sedf_set(self, id, period, slice, latency, extratime, weight):
"""Set Simple EDF scheduler parameters for a domain.
"""
dominfo = self.domain_lookup(id)
dominfo = self.domain_lookup(id)
try:
return xc.sedf_domain_set(dominfo.dom, period, slice, latency, extratime, weight)
return xc.sedf_domain_set(dominfo.id, period, slice, latency, extratime, weight)
except Exception, ex:
raise XendError(str(ex))
def domain_cpu_sedf_get(self, id):
"""Get Atropos scheduler parameters for a domain.
"""Get Simple EDF scheduler parameters for a domain.
"""
dominfo = self.domain_lookup(id)
try:
return xc.sedf_domain_get(dominfo.dom)
return xc.sedf_domain_get(dominfo.id)
except Exception, ex:
raise XendError(str(ex))
def domain_device_create(self, id, devconfig):
"""Create a new device for a domain.
@@ -603,44 +604,44 @@ class XendDomain:
"""
dominfo = self.domain_lookup(id)
val = dominfo.device_create(devconfig)
self.update_domain(dominfo.id)
dominfo.exportToDB()
return val
def domain_device_configure(self, id, devconfig, idx):
def domain_device_configure(self, id, devconfig, devid):
"""Configure an existing device for a domain.
@param id: domain id
@param devconfig: device configuration
@param idx: device index
@param devid: device id
@return: updated device configuration
"""
dominfo = self.domain_lookup(id)
val = dominfo.device_configure(devconfig, idx)
self.update_domain(dominfo.id)
val = dominfo.device_configure(devconfig, devid)
dominfo.exportToDB()
return val
def domain_device_refresh(self, id, type, idx):
def domain_device_refresh(self, id, type, devid):
"""Refresh a device.
@param id: domain id
@param idx: device index
@param devid: device id
@param type: device type
"""
dominfo = self.domain_lookup(id)
val = dominfo.device_refresh(type, idx)
self.update_domain(dominfo.id)
val = dominfo.device_refresh(type, devid)
dominfo.exportToDB()
return val
def domain_device_destroy(self, id, type, idx):
def domain_device_destroy(self, id, type, devid):
"""Destroy a device.
@param id: domain id
@param idx: device index
@param devid: device id
@param type: device type
"""
dominfo = self.domain_lookup(id)
val = dominfo.device_destroy(type, idx)
self.update_domain(dominfo.id)
val = dominfo.device_destroy(type, devid)
dominfo.exportToDB()
return val
def domain_devtype_ls(self, id, type):
@@ -653,22 +654,22 @@ class XendDomain:
dominfo = self.domain_lookup(id)
return dominfo.getDeviceSxprs(type)
def domain_devtype_get(self, id, type, idx):
def domain_devtype_get(self, id, type, devid):
"""Get a device from a domain.
@param id: domain
@param type: device type
@param idx: device index
@param devid: device id
@return: device object (or None)
"""
dominfo = self.domain_lookup(id)
return dominfo.getDeviceByIndex(type, idx)
return dominfo.getDevice(type, devid)
def domain_vif_limit_set(self, id, vif, credit, period):
"""Limit the vif's transmission rate
"""
dominfo = self.domain_lookup(id)
dev = dominfo.getDeviceById('vif', vif)
dev = dominfo.getDevice('vif', vif)
if not dev:
raise XendError("invalid vif")
return dev.setCreditLimit(credit, period)
@@ -681,30 +682,47 @@ class XendDomain:
"""
dominfo = self.domain_lookup(id)
try:
return xc.shadow_control(dominfo.dom, op)
return xc.shadow_control(dominfo.id, op)
except Exception, ex:
raise XendError(str(ex))
def domain_maxmem_set(self, id, mem):
"""Set the memory limit for a domain.
@param dom: domain
@param id: domain
@param mem: memory limit (in MB)
@return: 0 on success, -1 on error
"""
dominfo = self.domain_lookup(id)
maxmem = int(mem) * 1024
try:
return xc.domain_setmaxmem(dominfo.dom, maxmem_kb = maxmem)
return xc.domain_setmaxmem(dominfo.id, maxmem_kb = maxmem)
except Exception, ex:
raise XendError(str(ex))
def domain_mem_target_set(self, id, target):
def domain_mem_target_set(self, id, mem):
"""Set the memory target for a domain.
@param id: domain
@param mem: memory target (in MB)
@return: 0 on success, -1 on error
"""
dominfo = self.domain_lookup(id)
return dominfo.mem_target_set(target)
return dominfo.mem_target_set(mem)
def domain_dumpcore(self, id):
"""Save a core dump for a crashed domain.
@param id: domain
"""
dominfo = self.domain_lookup(id)
corefile = "/var/xen/dump/%s.%s.core"% (dominfo.name, dominfo.id)
try:
xc.domain_dumpcore(dom=dominfo.id, corefile=corefile)
except Exception, ex:
log.warning("Dumpcore failed, id=%s name=%s: %s",
dominfo.id, dominfo.name, ex)
def instance():
"""Singleton constructor. Use this instead of the class constructor.
"""
+254 -446
View File
@@ -14,21 +14,23 @@ import time
import threading
import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
import xen.util.ip
from xen.xend.server import channel, controller
from xen.util.ip import check_subnet, get_current_ipgw
from xen.util.blkif import blkdev_uname_to_file
from server.channel import channelFactory
import server.SrvDaemon; xend = server.SrvDaemon.instance()
from server import messages
from xen.xend.server import controller
from xen.xend.server import SrvDaemon; xend = SrvDaemon.instance()
from xen.xend.server import messages
from xen.xend.server.channel import EventChannel, channelFactory
from xen.xend import sxp
from xen.xend.PrettyPrint import prettyprintstring
from xen.xend.XendBootloader import bootloader
import sxp
from XendLogging import log
from xen.xend.XendLogging import log
from XendError import XendError, VmError
from XendRoot import get_component
from xen.xend.XendRoot import get_component
from PrettyPrint import prettyprintstring
from xen.xend.uuid import getUuid
from xen.xend.xenstore import DBVar
"""Flag for a block device backend domain."""
SIF_BLK_BE_DOMAIN = (1<<4)
@@ -45,11 +47,16 @@ DOMAIN_REBOOT = 1
"""Shutdown code for suspend."""
DOMAIN_SUSPEND = 2
"""Shutdown code for crash."""
DOMAIN_CRASH = 3
"""Map shutdown codes to strings."""
shutdown_reasons = {
DOMAIN_POWEROFF: "poweroff",
DOMAIN_REBOOT : "reboot",
DOMAIN_SUSPEND : "suspend" }
DOMAIN_SUSPEND : "suspend",
DOMAIN_CRASH : "crash",
}
"""Map shutdown reasons to the message type to use.
"""
@@ -81,7 +88,7 @@ STATE_VM_SUSPENDED = "suspended"
def domain_exists(name):
# See comment in XendDomain constructor.
xd = get_component('xen.xend.XendDomain')
return xd.domain_lookup(name)
return xd.domain_lookup_by_name(name)
def shutdown_reason(code):
"""Get a shutdown reason from a code.
@@ -110,25 +117,6 @@ def get_config_handler(name):
"""
return config_handlers.get(name)
"""Table of handlers for virtual machine images.
Indexed by image type.
"""
image_handlers = {}
def add_image_handler(name, h):
"""Add a handler for an image type
@param name: image type
@param h: handler: fn(config, name, memory, image)
"""
image_handlers[name] = h
def get_image_handler(name):
"""Get the handler for an image type.
@param name: image type
@return: handler or None
"""
return image_handlers.get(name)
"""Table of handlers for devices.
Indexed by device type.
"""
@@ -139,61 +127,6 @@ def add_device_handler(name, type):
def get_device_handler(name):
return device_handlers[name]
def vm_create(config):
"""Create a VM from a configuration.
If a vm has been partially created and there is an error it
is destroyed.
@param config configuration
@raise: VmError for invalid configuration
"""
vm = XendDomainInfo()
vm.construct(config)
return vm
def vm_restore(config):
"""Create a domain and a VM object to do a restore.
@param config: domain configuration
"""
vm = XendDomainInfo()
dom = xc.domain_create()
vm.dom_construct(dom, config)
return vm
def vm_recreate(savedinfo, info):
"""Create the VM object for an existing domain.
@param savedinfo: saved info from the domain DB
@type savedinfo: sxpr
@param info: domain info from xc
@type info: xc domain dict
"""
log.debug('savedinfo=' + prettyprintstring(savedinfo))
log.debug('info=' + str(info))
vm = XendDomainInfo()
vm.recreate = True
vm.savedinfo = savedinfo
vm.setdom(info['dom'])
vm.memory = info['mem_kb']/1024
start_time = sxp.child_value(savedinfo, 'start_time')
if start_time is not None:
vm.start_time = float(start_time)
vm.restart_state = sxp.child_value(savedinfo, 'restart_state')
vm.restart_count = int(sxp.child_value(savedinfo, 'restart_count', 0))
restart_time = sxp.child_value(savedinfo, 'restart_time')
if restart_time is not None:
vm.restart_time = float(restart_time)
config = sxp.child_value(savedinfo, 'config')
if config:
vm.construct(config)
else:
vm.name = sxp.child_value(savedinfo, 'name', "Domain-%d" % info['dom'])
vm.recreate = False
vm.savedinfo = None
return vm
def dom_get(dom):
"""Get info from xen for an existing domain.
@@ -213,25 +146,104 @@ class XendDomainInfo:
"""
MINIMUM_RESTART_TIME = 20
def __init__(self):
def create(cls, parentdb, config):
"""Create a VM from a configuration.
@param parentdb: parent db
@param config configuration
@raise: VmError for invalid configuration
"""
uuid = getUuid()
db = parentdb.addChild(uuid)
vm = cls(db)
vm.construct(config)
vm.saveDB(sync=True)
return vm
create = classmethod(create)
def recreate(cls, db, info):
"""Create the VM object for an existing domain.
@param db: domain db
@param info: domain info from xc
"""
dom = info['dom']
vm = cls(db)
db.readDB()
vm.importFromDB()
config = vm.config
log.debug('info=' + str(info))
log.debug('config=' + prettyprintstring(config))
vm.setdom(dom)
vm.memory = info['mem_kb']/1024
if config:
try:
vm.recreate = True
vm.construct(config)
finally:
vm.recreate = False
else:
vm.setName("Domain-%d" % dom)
vm.exportToDB(save=True)
return vm
recreate = classmethod(recreate)
def restore(cls, parentdb, config, uuid=None):
"""Create a domain and a VM object to do a restore.
@param parentdb: parent db
@param config: domain configuration
@param uuid: uuid to use
"""
db = parentdb.addChild(uuid)
vm = cls(db)
dom = xc.domain_create()
vm.setdom(dom)
vm.dom_construct(vm.id, config)
vm.saveDB(sync=True)
return vm
restore = classmethod(restore)
__exports__ = [
DBVar('id', ty='str'),
DBVar('name', ty='str'),
DBVar('uuid', ty='str'),
DBVar('config', ty='sxpr'),
DBVar('start_time', ty='float'),
DBVar('state', ty='str'),
DBVar('store_mfn', ty='long'),
DBVar('restart_mode', ty='str'),
DBVar('restart_state', ty='str'),
DBVar('restart_time', ty='float'),
DBVar('restart_count', ty='int'),
]
def __init__(self, db):
self.db = db
self.uuid = db.getName()
self.recreate = 0
self.restore = 0
self.config = None
self.id = None
self.dom = None
self.cpu_weight = 1
self.start_time = None
self.name = None
self.memory = None
self.image = None
self.ramdisk = None
self.cmdline = None
self.channel = None
self.store_channel = None
self.store_mfn = None
self.controllers = {}
self.configs = []
self.info = None
self.blkif_backend = False
self.netif_backend = False
@@ -249,22 +261,39 @@ class XendDomainInfo:
self.restart_count = 0
self.console_port = None
self.savedinfo = None
self.image_handler = None
self.is_vmx = False
self.vcpus = 1
self.bootloader = None
def setDB(self, db):
self.db = db
def saveDB(self, save=False, sync=False):
self.db.saveDB(save=save, sync=sync)
def exportToDB(self, save=False, sync=False):
if self.channel:
self.channel.saveToDB(self.db.addChild("channel"))
if self.store_channel:
self.store_channel.saveToDB(self.db.addChild("store_channel"))
self.db.exportToDB(self, fields=self.__exports__, save=save, sync=sync)
def importFromDB(self):
self.db.importFromDB(self, fields=self.__exports__)
def setdom(self, dom):
"""Set the domain id.
@param dom: domain id
"""
self.dom = int(dom)
self.id = str(dom)
self.id = int(dom)
#self.db.id = self.id
def getDomain(self):
return self.dom
return self.id
def setName(self, name):
self.name = name
self.db.name = self.name
def getName(self):
return self.name
@@ -272,6 +301,9 @@ class XendDomainInfo:
def getChannel(self):
return self.channel
def getStoreChannel(self):
return self.store_channel
def update(self, info):
"""Update with info from xc.domain_getinfo().
"""
@@ -284,6 +316,7 @@ class XendDomainInfo:
self.state = state
self.state_updated.notifyAll()
self.state_updated.release()
self.saveDB()
def state_wait(self, state):
self.state_updated.acquire()
@@ -293,14 +326,12 @@ class XendDomainInfo:
def __str__(self):
s = "domain"
s += " id=" + self.id
s += " id=" + str(self.id)
s += " name=" + self.name
s += " memory=" + str(self.memory)
console = self.getConsole()
if console:
s += " console=" + str(console.console_port)
if self.image:
s += " image=" + self.image
s += ""
return s
@@ -327,9 +358,10 @@ class XendDomainInfo:
self.controllers[type] = ctrl
return ctrl
def createDevice(self, type, devconfig, recreate=False):
def createDevice(self, type, devconfig, change=False):
ctrl = self.findDeviceController(type)
return ctrl.createDevice(devconfig, recreate=self.recreate)
return ctrl.createDevice(devconfig, recreate=self.recreate,
change=change)
def configureDevice(self, type, id, devconfig):
ctrl = self.getDeviceController(type)
@@ -343,30 +375,14 @@ class XendDomainInfo:
ctrl = self.getDeviceController(type)
return ctrl.deleteDevice(id)
def getDevice(self, type, id):
def getDevice(self, type, id, error=True):
ctrl = self.getDeviceController(type)
return ctrl.getDevice(id)
return ctrl.getDevice(id, error=error)
def getDeviceByIndex(self, type, idx):
ctrl = self.getDeviceController(type)
return ctrl.getDeviceByIndex(idx)
def getDeviceConfig(self, type, id):
ctrl = self.getDeviceController(type)
return ctrl.getDeviceConfig(id)
def getDeviceIds(self, type):
ctrl = self.getDeviceController(type)
return ctrl.getDeviceIds()
def getDeviceIndexes(self, type):
ctrl = self.getDeviceController(type)
return ctrl.getDeviceIndexes()
def getDeviceConfigs(self, type):
ctrl = self.getDeviceController(type)
return ctrl.getDeviceConfigs()
def getDeviceSxprs(self, type):
ctrl = self.getDeviceController(type)
return ctrl.getDeviceSxprs()
@@ -376,7 +392,8 @@ class XendDomainInfo:
['id', self.id],
['name', self.name],
['memory', self.memory] ]
if self.uuid:
sxpr.append(['uuid', self.uuid])
if self.info:
sxpr.append(['maxmem', self.info['maxmem_kb']/1024 ])
run = (self.info['running'] and 'r') or '-'
@@ -403,6 +420,8 @@ class XendDomainInfo:
if self.channel:
sxpr.append(self.channel.sxpr())
if self.store_channel:
sxpr.append(self.store_channel.sxpr())
console = self.getConsole()
if console:
sxpr.append(console.sxpr())
@@ -454,7 +473,7 @@ class XendDomainInfo:
return
if dominfo.is_terminated():
return
if not self.dom or (dominfo.dom != self.dom):
if not self.id or (dominfo.id != self.id):
raise VmError('vm name clash: ' + name)
def construct(self, config):
@@ -467,10 +486,10 @@ class XendDomainInfo:
self.config = config
try:
# Initial domain create.
self.name = sxp.child_value(config, 'name')
self.setName(sxp.child_value(config, 'name'))
self.check_name(self.name)
self.init_image()
self.configure_cpus(config)
self.find_image_handler()
self.init_domain()
self.register_domain()
self.configure_bootloader()
@@ -481,6 +500,7 @@ class XendDomainInfo:
self.configure_restart()
self.construct_image()
self.configure()
self.exportToDB()
except Exception, ex:
# Catch errors, cleanup and re-raise.
print 'Domain construction error:', ex
@@ -492,6 +512,7 @@ class XendDomainInfo:
def register_domain(self):
xd = get_component('xen.xend.XendDomain')
xd._add_domain(self)
self.exportToDB()
def configure_cpus(self, config):
try:
@@ -502,8 +523,8 @@ class XendDomainInfo:
if self.memory is None:
raise VmError('missing memory size')
cpu = sxp.child_value(config, 'cpu')
if self.recreate and self.dom and cpu is not None and int(cpu) >= 0:
xc.domain_pincpu(self.dom, 0, 1<<int(cpu))
if self.recreate and self.id and cpu is not None and int(cpu) >= 0:
xc.domain_pincpu(self.id, 0, 1<<int(cpu))
try:
image = sxp.child_value(self.config, 'image')
vcpus = sxp.child_value(image, 'vcpus')
@@ -512,89 +533,50 @@ class XendDomainInfo:
except:
raise VmError('invalid vcpus value')
def find_image_handler(self):
"""Construct the boot image for the domain.
@return vm
def init_image(self):
"""Create boot image handler for the domain.
"""
image = sxp.child_value(self.config, 'image')
if image is None:
raise VmError('missing image')
image_name = sxp.name(image)
if image_name is None:
raise VmError('missing image name')
if image_name == "vmx":
self.is_vmx = True
image_handler = get_image_handler(image_name)
if image_handler is None:
raise VmError('unknown image type: ' + image_name)
self.image_handler = image_handler
return self
self.image = ImageHandler.create(self, image)
def construct_image(self):
image = sxp.child_value(self.config, 'image')
self.image_handler(self, image)
return self
def config_devices(self, name):
"""Get a list of the 'device' nodes of a given type from the config.
@param name: device type
@type name: string
@return: device configs
@rtype: list
"""Construct the boot image for the domain.
"""
devices = []
for d in sxp.children(self.config, 'device'):
dev = sxp.child0(d)
if dev is None: continue
if name == sxp.name(dev):
devices.append(dev)
return devices
self.create_channel()
self.image.createImage()
self.image.exportToDB()
#if self.store_channel:
# self.db.introduceDomain(self.id,
# self.store_mfn,
# self.store_channel)
def get_device_savedinfo(self, type, index):
val = None
if self.savedinfo is None:
return val
devices = sxp.child(self.savedinfo, 'devices')
if devices is None:
return val
index = str(index)
for d in sxp.children(devices, type):
dindex = sxp.child_value(d, 'index')
if dindex is None: continue
if str(dindex) == index:
val = d
break
return val
def get_device_recreate(self, type, index):
return self.get_device_savedinfo(type, index) or self.recreate
def add_config(self, val):
"""Add configuration data to a virtual machine.
@param val: data to add
def delete(self):
"""Delete the vm's db.
"""
self.configs.append(val)
def destroy(self):
"""Completely destroy the vm.
"""
self.cleanup()
return self.destroy_domain()
if self.dom_get(self.id):
return
self.id = None
self.saveDB(sync=True)
try:
# Todo: eventually will have to wait for devices to signal
# destruction before can delete the db.
if self.db:
self.db.delete()
except Exception, ex:
log.warning("error in domain db delete: %s", ex)
pass
def destroy_domain(self):
"""Destroy the vm's domain.
The domain will not finally go away unless all vm
devices have been released.
"""
if self.channel:
self.channel.close()
self.channel = None
if self.dom is None: return 0
if self.id is None:
return
try:
return xc.domain_destroy(dom=self.dom)
xc.domain_destroy(dom=self.id)
except Exception, err:
log.exception("Domain destroy failed: %s", self.name)
@@ -603,6 +585,37 @@ class XendDomainInfo:
"""
self.state = STATE_VM_TERMINATED
self.release_devices()
if self.channel:
try:
self.channel.close()
self.channel = None
except:
pass
if self.store_channel:
try:
self.store_channel.close()
self.store_channel = None
except:
pass
#try:
# self.db.releaseDomain(self.id)
#except Exception, ex:
# log.warning("error in domain release on xenstore: %s", ex)
# pass
if self.image:
try:
self.image.destroy()
self.image = None
except:
pass
def destroy(self):
"""Clenup vm and destroy domain.
"""
self.cleanup()
self.destroy_domain()
self.saveDB()
return 0
def is_terminated(self):
"""Check if a domain has been terminated.
@@ -616,20 +629,13 @@ class XendDomainInfo:
for ctrl in self.getDeviceControllers():
if ctrl.isDestroyed(): continue
ctrl.destroyController(reboot=reboot)
if not reboot:
self.configs = []
def show(self):
"""Print virtual machine info.
"""
print "[VM dom=%d name=%s memory=%d" % (self.dom, self.name, self.memory)
print "[VM dom=%d name=%s memory=%d" % (self.id, self.name, self.memory)
print "image:"
sxp.show(self.image)
print
for val in self.configs:
print "config:"
sxp.show(val)
print
print "]"
def init_domain(self):
@@ -639,107 +645,42 @@ class XendDomainInfo:
return
if self.start_time is None:
self.start_time = time.time()
if self.restore:
return
dom = self.dom or 0
memory = self.memory
try:
cpu = int(sxp.child_value(self.config, 'cpu', '-1'))
except:
raise VmError('invalid cpu')
cpu_weight = self.cpu_weight
memory = memory * 1024 + self.pgtable_size(memory)
dom = xc.domain_create(dom= dom)
if self.bootloader:
try:
if kernel: os.unlink(kernel)
if ramdisk: os.unlink(ramdisk)
except OSError, e:
log.warning('unable to unlink kernel/ramdisk: %s' %(e,))
dom = self.image.initDomain(self.id, self.memory, cpu, self.cpu_weight)
log.debug('init_domain> Created domain=%d name=%s memory=%d',
dom, self.name, self.memory)
if not self.restore:
self.setdom(dom)
if dom <= 0:
raise VmError('Creating domain failed: name=%s memory=%d'
% (self.name, memory))
xc.domain_setcpuweight(dom, cpu_weight)
xc.domain_setmaxmem(dom, memory)
xc.domain_memory_increase_reservation(dom, memory)
if cpu != -1:
xc.domain_pincpu(dom, 0, 1<<int(cpu))
log.debug('init_domain> Created domain=%d name=%s memory=%d', dom, self.name, memory)
self.setdom(dom)
def build_domain(self, ostype, kernel, ramdisk, cmdline, memmap):
"""Build the domain boot image.
def openChannel(self, key, local, remote):
"""Create a channel to the domain.
If saved info is available recreate the channel.
@param key db key for the saved data (if any)
@param local default local port
@param remote default remote port
"""
if self.recreate or self.restore: return
if not os.path.isfile(kernel):
raise VmError('Kernel image does not exist: %s' % kernel)
if ramdisk and not os.path.isfile(ramdisk):
raise VmError('Kernel ramdisk does not exist: %s' % ramdisk)
if len(cmdline) >= 256:
log.warning('kernel cmdline too long, domain %d', self.dom)
dom = self.dom
buildfn = getattr(xc, '%s_build' % ostype)
flags = 0
if self.netif_backend: flags |= SIF_NET_BE_DOMAIN
if self.blkif_backend: flags |= SIF_BLK_BE_DOMAIN
#todo generalise this
if ostype == "vmx":
log.debug('building vmx domain')
err = buildfn(dom = dom,
image = kernel,
control_evtchn = 0,
memsize = self.memory,
memmap = memmap,
cmdline = cmdline,
ramdisk = ramdisk,
flags = flags)
else:
log.debug('building dom with %d vcpus', self.vcpus)
err = buildfn(dom = dom,
image = kernel,
control_evtchn = self.channel.getRemotePort(),
cmdline = cmdline,
ramdisk = ramdisk,
flags = flags,
vcpus = self.vcpus)
if err != 0:
raise VmError('Building domain failed: type=%s dom=%d err=%d'
% (ostype, dom, err))
def create_domain(self, ostype, kernel, ramdisk, cmdline, memmap=''):
"""Create a domain. Builds the image but does not configure it.
@param ostype: OS type
@param kernel: kernel image
@param ramdisk: kernel ramdisk
@param cmdline: kernel commandline
"""
self.create_channel()
self.build_domain(ostype, kernel, ramdisk, cmdline, memmap)
self.image = kernel
self.ramdisk = ramdisk
self.cmdline = cmdline
db = self.db.addChild(key)
chan = channelFactory().restoreFromDB(db, self.id, local, remote)
#todo: save here?
#chan.saveToDB(db)
return chan
def eventChannel(self, key):
db = self.db.addChild(key)
return EventChannel.restoreFromDB(db, 0, self.id)
def create_channel(self):
"""Create the control channel to the domain.
If saved info is available recreate the channel using the saved ports.
"""Create the channels to the domain.
"""
local = 0
remote = 1
if self.savedinfo:
info = sxp.child(self.savedinfo, "channel")
if info:
local = int(sxp.child_value(info, "local_port", 0))
remote = int(sxp.child_value(info, "remote_port", 1))
self.channel = channelFactory().openChannel(self.dom,
local_port=local,
remote_port=remote)
self.channel = self.openChannel("channel", 0, 1)
self.store_channel = self.eventChannel("store_channel")
def create_configured_devices(self):
devices = sxp.children(self.config, 'device')
indexes = {}
for d in devices:
dev_config = sxp.child0(d)
if dev_config is None:
@@ -748,13 +689,7 @@ class XendDomainInfo:
ctrl_type = get_device_handler(dev_type)
if ctrl_type is None:
raise VmError('unknown device type: ' + dev_type)
# Keep track of device indexes by type, so we can fish
# out saved info for recreation.
idx = indexes.get(dev_type, -1)
idx += 1
indexes[ctrl_type] = idx
recreate = self.get_device_recreate(dev_type, idx)
self.createDevice(ctrl_type, dev_config, recreate=recreate)
self.createDevice(ctrl_type, dev_config)
def create_devices(self):
"""Create the devices for a vm.
@@ -766,43 +701,6 @@ class XendDomainInfo:
ctrl.initController(reboot=True)
else:
self.create_configured_devices()
if self.is_vmx:
self.create_vmx_model()
def create_vmx_model(self):
#todo: remove special case for vmx
device_model = sxp.child_value(self.config, 'device_model')
if not device_model:
raise VmError("vmx: missing device model")
device_config = sxp.child_value(self.config, 'device_config')
if not device_config:
raise VmError("vmx: missing device config")
#todo: self.memory?
memory = sxp.child_value(self.config, "memory")
# Create an event channel
device_channel = channel.eventChannel(0, self.dom)
# see if a vncviewer was specified
# XXX RN: bit of a hack. should unify this, maybe stick in config space
vncconnect=""
image = sxp.child_value(self.config, "image")
args = sxp.child_value(image, "args")
if args:
arg_list = string.split(args)
for arg in arg_list:
al = string.split(arg, '=')
if al[0] == "VNC_VIEWER":
vncconnect=" -v %s" % al[1]
break
# Execute device model.
#todo: Error handling
# XXX RN: note that the order of args matter!
os.system(device_model
+ " -f %s" % device_config
+ vncconnect
+ " -d %d" % self.dom
+ " -p %d" % device_channel['port1']
+ " -m %s" % memory)
def device_create(self, dev_config):
"""Create a new device.
@@ -814,16 +712,14 @@ class XendDomainInfo:
self.config.append(['device', dev.getConfig()])
return dev.sxpr()
def device_configure(self, dev_config, idx):
def device_configure(self, dev_config, id):
"""Configure an existing device.
@param dev_config: device configuration
@param idx: device index
@param id: device id
"""
type = sxp.name(dev_config)
dev = self.getDeviceByIndex(type, idx)
if not dev:
raise VmError('invalid device: %s %s' % (type, idx))
dev = self.getDevice(type, id)
old_config = dev.getConfig()
new_config = dev.configure(dev_config, change=True)
# Patch new config into vm config.
@@ -833,26 +729,22 @@ class XendDomainInfo:
self.config[old_index] = new_full_config
return new_config
def device_refresh(self, type, idx):
def device_refresh(self, type, id):
"""Refresh a device.
@param type: device type
@param idx: device index
@param id: device id
"""
dev = self.getDeviceByIndex(type, idx)
if not dev:
raise VmError('invalid device: %s %s' % (type, idx))
dev = self.getDevice(type, id)
dev.refresh()
def device_delete(self, type, idx):
def device_delete(self, type, id):
"""Destroy and remove a device.
@param type: device type
@param idx: device index
@param id: device id
"""
dev = self.getDeviceByIndex(type, idx)
if not dev:
raise VmError('invalid device: %s %s' % (type, idx))
dev = self.getDevice(type, id)
dev_config = dev.getConfig()
if dev_config:
self.config.remove(['device', dev_config])
@@ -861,9 +753,7 @@ class XendDomainInfo:
def configure_bootloader(self):
"""Configure boot loader.
"""
bl = sxp.child_value(self.config, "bootloader")
if bl is not None:
self.bootloader = bl
self.bootloader = sxp.child_value(self.config, "bootloader")
def configure_console(self):
"""Configure the vm console port.
@@ -946,6 +836,7 @@ class XendDomainInfo:
if self.bootloader:
self.config = self.bootloader_config()
self.construct(self.config)
self.saveDB()
finally:
self.restart_state = None
@@ -1051,19 +942,6 @@ class XendDomainInfo:
log.warning("Unknown config field %s", field_name)
index[field_name] = field_index + 1
def pgtable_size(self, memory):
"""Return the size of memory needed for 1:1 page tables for physical
mode.
@param memory: size in MB
@return size in KB
"""
if self.is_vmx:
# Logic x86-32 specific.
# 1 page for the PGD + 1 pte page for 4MB of memory (rounded)
return (1 + ((memory + 3) >> 2)) * 4
return 0
def mem_target_set(self, target):
"""Set domain memory target in pages.
"""
@@ -1090,83 +968,6 @@ class XendDomainInfo:
return 0
return timeout - (time.time() - self.shutdown_pending['start'])
def vm_image_linux(vm, image):
"""Create a VM for a linux image.
@param name: vm name
@param memory: vm memory
@param image: image config
@return: vm
"""
kernel = sxp.child_value(image, "kernel")
cmdline = ""
ip = sxp.child_value(image, "ip", None)
if ip:
cmdline += " ip=" + ip
root = sxp.child_value(image, "root")
if root:
cmdline += " root=" + root
args = sxp.child_value(image, "args")
if args:
cmdline += " " + args
ramdisk = sxp.child_value(image, "ramdisk", '')
log.debug("creating linux domain with cmdline: %s" %(cmdline,))
vm.create_domain("linux", kernel, ramdisk, cmdline)
return vm
def vm_image_plan9(vm, image):
"""Create a VM for a Plan 9 image.
name vm name
memory vm memory
image image config
returns vm
"""
kernel = sxp.child_value(image, "kernel")
cmdline = ""
ip = sxp.child_value(image, "ip", "dhcp")
if ip:
cmdline += "ip=" + ip
root = sxp.child_value(image, "root")
if root:
cmdline += "root=" + root
args = sxp.child_value(image, "args")
if args:
cmdline += " " + args
ramdisk = sxp.child_value(image, "ramdisk", '')
log.debug("creating plan9 domain with cmdline: %s" %(cmdline,))
vm.create_domain("plan9", kernel, ramdisk, cmdline)
return vm
def vm_image_vmx(vm, image):
"""Create a VM for the VMX environment.
@param name: vm name
@param memory: vm memory
@param image: image config
@return: vm
"""
kernel = sxp.child_value(image, "kernel")
cmdline = ""
ip = sxp.child_value(image, "ip", "dhcp")
if ip:
cmdline += " ip=" + ip
root = sxp.child_value(image, "root")
if root:
cmdline += " root=" + root
args = sxp.child_value(image, "args")
if args:
cmdline += " " + args
ramdisk = sxp.child_value(image, "ramdisk", '')
memmap = sxp.child_value(vm.config, "memmap", '')
memmap = sxp.parse(open(memmap))[0]
from xen.util.memmap import memmap_parse
memmap = memmap_parse(memmap)
log.debug("creating vmx domain with cmdline: %s" %(cmdline,))
vm.create_domain("vmx", kernel, ramdisk, cmdline, memmap)
return vm
def vm_field_ignore(vm, config, val, index):
"""Dummy config field handler used for fields with built-in handling.
@@ -1192,13 +993,20 @@ def vm_field_maxmem(vm, config, val, index):
maxmem = int(maxmem)
except:
raise VmError("invalid maxmem: " + str(maxmem))
xc.domain_setmaxmem(vm.dom, maxmem_kb = maxmem * 1024)
xc.domain_setmaxmem(vm.id, maxmem_kb = maxmem * 1024)
#============================================================================
# Register image handlers.
add_image_handler('linux', vm_image_linux)
add_image_handler('plan9', vm_image_plan9)
add_image_handler('vmx', vm_image_vmx)
from image import \
addImageHandlerClass, \
ImageHandler, \
LinuxImageHandler, \
Plan9ImageHandler, \
VmxImageHandler
addImageHandlerClass(LinuxImageHandler)
addImageHandlerClass(Plan9ImageHandler)
addImageHandlerClass(VmxImageHandler)
# Ignore the fields we already handle.
add_config_handler('name', vm_field_ignore)
+7 -14
View File
@@ -25,9 +25,6 @@ import sxp
class XendRoot:
"""Root of the management classes."""
"""Default path to the root of the database."""
dbroot_default = "/var/lib/xen/xend-db"
"""Default path to the config file."""
config_default = "/etc/xen/xend-config.sxp"
@@ -82,7 +79,6 @@ class XendRoot:
components = {}
def __init__(self):
self.dbroot = None
self.config_path = None
self.config = None
self.logging = None
@@ -171,13 +167,15 @@ class XendRoot:
def configure(self):
self.set_config()
self.configure_logger()
self.dbroot = self.get_config_value("dbroot", self.dbroot_default)
def configure_logger(self):
logfile = self.get_config_value("logfile", self.logfile_default)
loglevel = self.get_config_value("loglevel", self.loglevel_default)
self.logging = XendLogging(logfile, level=loglevel)
#self.logging.addLogStderr()
from xen.xend.server import params
if params.XEND_DEBUG:
self.logging.addLogStderr()
def get_logging(self):
"""Get the XendLogging instance.
@@ -189,11 +187,6 @@ class XendRoot:
"""
return self.logging and self.logging.getLogger()
def get_dbroot(self):
"""Get the path to the database root.
"""
return self.dbroot
def set_config(self):
"""If the config file exists, read it. If not, ignore it.
@@ -241,9 +234,9 @@ class XendRoot:
def get_config_bool(self, name, val=None):
v = self.get_config_value(name, val)
if v in ['yes', '1', 'on', 1, True]:
if v in ['yes', '1', 'on', 'true', 1, True]:
return True
if v in ['no', '0', 'off', 0, False]:
if v in ['no', '0', 'off', 'false', 0, False]:
return False
raise XendError("invalid xend config %s: expected bool: %s" % (name, v))
@@ -325,7 +318,7 @@ class XendRoot:
return self.get_config_value('network-script', 'network')
def get_enable_dump(self):
return self.get_config_value('enable-dump', 'false')
return self.get_config_bool('enable-dump', 'no')
def get_vif_bridge(self):
return self.get_config_value('vif-bridge', 'xen-br0')
+11 -11
View File
@@ -4,11 +4,10 @@
"""
from xen.util import Brctl
import sxp
import XendDB
from XendError import XendError
from XendLogging import log
from xen.xend import sxp
from xen.xend.XendError import XendError
from xen.xend.XendLogging import log
from xen.xend.xenstore import XenNode, DBMap
def vnet_cmd(cmd):
out = None
@@ -63,14 +62,15 @@ class XendVnet:
"""Index of all vnets. Singleton.
"""
dbpath = "vnet"
dbpath = "/vnet"
def __init__(self):
# Table of vnet info indexed by vnet id.
self.vnet = {}
self.db = XendDB.XendDB(self.dbpath)
vnets = self.db.fetchall("")
for config in vnets.values():
self.dbmap = DBMap(db=XenNode(self.dbpath))
self.dbmap.readDB()
for vnetdb in self.dbmap.values():
config = vnetdb.config
info = XendVnetInfo(config)
self.vnet[info.id] = info
try:
@@ -115,7 +115,7 @@ class XendVnet:
"""
info = XendVnetInfo(config)
self.vnet[info.id] = info
self.db.save(info.id, info.sxpr())
self.dbmap["%s/config" % info.id] = info.sxpr()
info.configure()
def vnet_delete(self, id):
@@ -126,7 +126,7 @@ class XendVnet:
info = self.vnet_get(id)
if info:
del self.vnet[id]
self.db.delete(id)
self.dbmap.delete(id)
info.delete()
def instance():
+339
View File
@@ -0,0 +1,339 @@
import os
import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
from xen.xend import sxp
from xen.xend.XendError import VmError
from xen.xend.XendLogging import log
from xen.xend.xenstore import DBVar
class ImageHandler:
"""Abstract base class for image handlers.
initDomain() is called to initialise the domain memory.
createImage() is called to configure and build the domain from its
kernel image and ramdisk etc.
The method buildDomain() is used to build the domain, and must be
defined in a subclass. Usually this is the only method that needs
defining in a subclass.
The method createDeviceModel() is called to create the domain device
model if it needs one. The default is to do nothing.
The method destroy() is called when the domain is destroyed.
The default is to do nothing.
"""
#======================================================================
# Class vars and methods.
"""Table of image handler classes for virtual machine images.
Indexed by image type.
"""
imageHandlerClasses = {}
def addImageHandlerClass(cls, h):
"""Add a handler class for an image type
@param h: handler: ImageHandler subclass
"""
cls.imageHandlerClasses[h.ostype] = h
addImageHandlerClass = classmethod(addImageHandlerClass)
def findImageHandlerClass(cls, image):
"""Find the image handler class for an image config.
@param image config
@return ImageHandler subclass or None
"""
ty = sxp.name(image)
if ty is None:
raise VmError('missing image type')
imageClass = cls.imageHandlerClasses.get(ty)
if imageClass is None:
raise VmError('unknown image type: ' + ty)
return imageClass
findImageHandlerClass = classmethod(findImageHandlerClass)
def create(cls, vm, image):
"""Create an image handler for a vm.
@param vm vm
@param image image config
@return ImageHandler instance
"""
imageClass = cls.findImageHandlerClass(image)
return imageClass(vm, image)
create = classmethod(create)
#======================================================================
# Instance vars and methods.
db = None
ostype = None
config = None
kernel = None
ramdisk = None
cmdline = None
flags = 0
__exports__ = [
DBVar('ostype', ty='str'),
DBVar('config', ty='sxpr'),
DBVar('kernel', ty='str'),
DBVar('ramdisk', ty='str'),
DBVar('cmdline', ty='str'),
DBVar('flags', ty='int'),
]
def __init__(self, vm, config):
self.vm = vm
self.db = vm.db.addChild('/image')
self.config = config
def exportToDB(self, save=False):
self.db.exportToDB(self, fields=self.__exports__, save=save)
def importFromDB(self):
self.db.importFromDB(self, fields=self.__exports__)
def unlink(self, f):
if not f: return
try:
os.unlink(f)
except OSError, ex:
log.warning("error removing bootloader file '%s': %s", f, ex)
def initDomain(self, dom, memory, cpu, cpu_weight):
"""Initial domain create.
@return domain id
"""
mem_kb = self.getDomainMemory(memory)
if not self.vm.restore:
dom = xc.domain_create(dom = dom or 0)
# if bootloader, unlink here. But should go after buildDomain() ?
if self.vm.bootloader:
self.unlink(self.kernel)
self.unlink(self.ramdisk)
if dom <= 0:
raise VmError('Creating domain failed: name=%s' % self.vm.name)
log.debug("initDomain: cpu=%d mem_kb=%d dom=%d", cpu, mem_kb, dom)
# xc.domain_setuuid(dom, uuid)
xc.domain_setcpuweight(dom, cpu_weight)
xc.domain_setmaxmem(dom, mem_kb)
xc.domain_memory_increase_reservation(dom, mem_kb)
if cpu != -1:
xc.domain_pincpu(dom, 0, 1<<int(cpu))
return dom
def createImage(self):
"""Entry point to create domain memory image.
Override in subclass if needed.
"""
self.configure()
self.createDomain()
def configure(self):
"""Config actions common to all unix-like domains."""
self.kernel = sxp.child_value(self.config, "kernel")
self.cmdline = ""
ip = sxp.child_value(self.config, "ip", None)
if ip:
self.cmdline += " ip=" + ip
root = sxp.child_value(self.config, "root")
if root:
self.cmdline += " root=" + root
args = sxp.child_value(self.config, "args")
if args:
self.cmdline += " " + args
self.ramdisk = sxp.child_value(self.config, "ramdisk", '')
def createDomain(self):
"""Build the domain boot image.
"""
# Set params and call buildDomain().
self.flags = 0
if self.vm.netif_backend: self.flags |= SIF_NET_BE_DOMAIN
if self.vm.blkif_backend: self.flags |= SIF_BLK_BE_DOMAIN
if self.vm.recreate or self.vm.restore:
return
if not os.path.isfile(self.kernel):
raise VmError('Kernel image does not exist: %s' % self.kernel)
if self.ramdisk and not os.path.isfile(self.ramdisk):
raise VmError('Kernel ramdisk does not exist: %s' % self.ramdisk)
if len(self.cmdline) >= 256:
log.warning('kernel cmdline too long, domain %d', self.vm.getDomain())
log.info("buildDomain os=%s dom=%d vcpus=%d", self.ostype,
self.vm.getDomain(), self.vm.vcpus)
err = self.buildDomain()
if err != 0:
raise VmError('Building domain failed: ostype=%s dom=%d err=%d'
% (self.ostype, self.vm.getDomain(), err))
def getDomainMemory(self, mem_mb):
"""Memory (in KB) the domain will need for mem_mb (in MB)."""
return mem_mb * 1024
def buildDomain(self):
"""Build the domain. Define in subclass."""
raise NotImplementedError()
def createDeviceModel(self):
"""Create device model for the domain (define in subclass if needed)."""
pass
def destroy(self):
"""Extra cleanup on domain destroy (define in subclass if needed)."""
pass
addImageHandlerClass = ImageHandler.addImageHandlerClass
class LinuxImageHandler(ImageHandler):
ostype = "linux"
def buildDomain(self):
if self.vm.store_channel:
store_evtchn = self.vm.store_channel.port2
else:
store_evtchn = 0
ret = xc.linux_build(dom = self.vm.getDomain(),
image = self.kernel,
control_evtchn = self.vm.channel.getRemotePort(),
store_evtchn = store_evtchn,
cmdline = self.cmdline,
ramdisk = self.ramdisk,
flags = self.flags,
vcpus = self.vm.vcpus)
if isinstance(ret, dict):
self.vm.store_mfn = ret.get('store_mfn')
return 0
return ret
class Plan9ImageHandler(ImageHandler):
ostype = "plan9"
def buildDomain(self):
return xc.plan9_build(dom = self.vm.getDomain(),
image = self.kernel,
control_evtchn = self.vm.channel.getRemotePort(),
cmdline = self.cmdline,
ramdisk = self.ramdisk,
flags = self.flags,
vcpus = self.vm.vcpus)
class VmxImageHandler(ImageHandler):
__exports__ = ImageHandler.__exports__ + [
DBVar('memmap', ty='str'),
DBVar('memmap_value', ty='sxpr'),
# device channel?
]
ostype = "vmx"
memmap = None
memmap_value = None
device_channel = None
def createImage(self):
"""Create a VM for the VMX environment.
"""
self.configure()
self.parseMemmap()
self.createDomain()
def buildDomain(self):
return xc.vmx_build(dom = self.vm.getDomain(),
image = self.kernel,
control_evtchn = 0,
memsize = self.vm.memory,
memmap = self.memmap_value,
cmdline = self.cmdline,
ramdisk = self.ramdisk,
flags = self.flags)
def parseMemmap(self):
self.memmap = sxp.child_value(self.vm.config, "memmap")
if self.memmap is None:
raise VmError("missing memmap")
memmap = sxp.parse(open(self.memmap))[0]
from xen.util.memmap import memmap_parse
self.memmap_value = memmap_parse(memmap)
def createDeviceModel_old(self):
device_model = sxp.child_value(self.vm.config, 'device_model')
if not device_model:
raise VmError("vmx: missing device model")
device_config = sxp.child_value(self.vm.config, 'device_config')
if not device_config:
raise VmError("vmx: missing device config")
# Create an event channel.
self.device_channel = channel.eventChannel(0, self.vm.getDomain())
# Execute device model.
#todo: Error handling
os.system(device_model
+ " -f %s" % device_config
+ " -d %d" % self.vm.getDomain()
+ " -p %d" % self.device_channel['port1']
+ " -m %s" % self.vm.memory)
def createDeviceModel(self):
device_model = sxp.child_value(self.vm.config, 'device_model')
if not device_model:
raise VmError("vmx: missing device model")
device_config = sxp.child_value(self.vm.config, 'device_config')
if not device_config:
raise VmError("vmx: missing device config")
# Create an event channel
self.device_channel = channel.eventChannel(0, self.vm.getDomain())
# Execute device model.
#todo: Error handling
# XXX RN: note that the order of args matter!
os.system(device_model
+ " -f %s" % device_config
+ self.vncParams()
+ " -d %d" % self.vm.getDomain()
+ " -p %d" % self.device_channel['port1']
+ " -m %s" % self.vm.memory)
def vncParams(self):
# see if a vncviewer was specified
# XXX RN: bit of a hack. should unify this, maybe stick in config space
vncconnect=""
image = self.config
args = sxp.child_value(image, "args")
if args:
arg_list = string.split(args)
for arg in arg_list:
al = string.split(arg, '=')
if al[0] == "VNC_VIEWER":
vncconnect=" -v %s" % al[1]
break
return vncconnect
def destroy(self):
channel.eventChannelClose(self.device_channel)
def getDomainMemory(self, mem_mb):
return (mem_mb * 1024) + self.getPageTableSize(mem_mb)
def getPageTableSize(self, mem_mb):
"""Return the size of memory needed for 1:1 page tables for physical
mode.
@param mem_mb: size in MB
@return size in KB
"""
# Logic x86-32 specific.
# 1 page for the PGD + 1 pte page for 4MB of memory (rounded)
return (1 + ((mem_mb + 3) >> 2)) * 4
+1 -1
View File
@@ -30,7 +30,7 @@ class SrvConsole(SrvDir):
#self.ls()
req.write('<p>%s</p>' % self.info)
req.write('<p><a href="%s">Connect to domain %d</a></p>'
% (self.info.uri(), self.info.dom))
% (self.info.uri(), self.info.id))
self.form(req)
req.write('</body></html>')
+35 -9
View File
@@ -32,9 +32,6 @@ import event
import relocate
from params import *
DAEMONIZE = 0
DEBUG = 1
class Daemon:
"""The xend daemon.
"""
@@ -128,9 +125,13 @@ class Daemon:
def cleanup_xend(self, kill=False):
return self.cleanup_process(XEND_PID_FILE, "xend", kill)
def cleanup_xenstored(self, kill=False):
return self.cleanup_process(XENSTORED_PID_FILE, "xenstored", kill)
def cleanup(self, kill=False):
self.cleanup_xend(kill=kill)
#self.cleanup_xenstored(kill=kill)
def status(self):
"""Returns the status of the xend daemon.
The return value is defined by the LSB:
@@ -166,8 +167,29 @@ class Daemon:
pidfile.close()
return pid
def start_xenstored(self):
"""Fork and exec xenstored, writing its pid to XENSTORED_PID_FILE.
"""
def mkdirs(p):
try:
os.makedirs(p)
except:
pass
mkdirs(XENSTORED_RUN_DIR)
mkdirs(XENSTORED_LIB_DIR)
pid = self.fork_pid(XENSTORED_PID_FILE)
if pid:
# Parent
log.info("Started xenstored, pid=%d", pid)
else:
# Child
if XEND_DAEMONIZE and (not XENSTORED_DEBUG):
self.daemonize()
os.execl("/usr/sbin/xenstored", "xenstored", "--no-fork")
def daemonize(self):
if not DAEMONIZE: return
if not XEND_DAEMONIZE: return
# Detach from TTY.
os.setsid()
@@ -177,16 +199,16 @@ class Daemon:
os.close(0)
os.close(1)
os.close(2)
if DEBUG:
if XEND_DEBUG:
os.open('/dev/null', os.O_RDONLY)
# XXX KAF: Why doesn't this capture output from C extensions that
# fprintf(stdout) or fprintf(stderr) ??
os.open('/var/log/xend-debug.log', os.O_WRONLY|os.O_CREAT)
os.open(XEND_DEBUG_LOG, os.O_WRONLY|os.O_CREAT)
os.dup(1)
else:
os.open('/dev/null', os.O_RDWR)
os.dup(0)
os.open('/var/log/xend-debug.log', os.O_WRONLY|os.O_CREAT)
os.open(XEND_DEBUG_LOG, os.O_WRONLY|os.O_CREAT)
def start(self, trace=0):
@@ -196,11 +218,15 @@ class Daemon:
4 Insufficient privileges
"""
xend_pid = self.cleanup_xend()
xenstored_pid = self.cleanup_xenstored()
if self.set_user():
return 4
os.chdir("/")
if xenstored_pid == 0:
self.start_xenstored()
if xend_pid > 0:
# Trying to run an already-running service is a success.
return 0
@@ -308,7 +334,7 @@ class Daemon:
servers.start()
except Exception, ex:
print >>sys.stderr, 'Exception starting xend:', ex
if DEBUG:
if XEND_DEBUG:
traceback.print_exc()
log.exception("Exception starting xend")
self.exit(1)
+19 -19
View File
@@ -28,19 +28,19 @@ class SrvDomain(SrvDir):
fn = FormFn(self.xd.domain_configure,
[['dom', 'int'],
['config', 'sxpr']])
return fn(req.args, {'dom': self.dom.dom})
return fn(req.args, {'dom': self.dom.id})
def op_unpause(self, op, req):
val = self.xd.domain_unpause(self.dom.name)
val = self.xd.domain_unpause(self.dom.id)
return val
def op_pause(self, op, req):
val = self.xd.domain_pause(self.dom.name)
val = self.xd.domain_pause(self.dom.id)
return val
def op_shutdown(self, op, req):
fn = FormFn(self.xd.domain_shutdown,
[['dom', 'str'],
[['dom', 'int'],
['reason', 'str'],
['key', 'int']])
val = fn(req.args, {'dom': self.dom.id})
@@ -50,7 +50,7 @@ class SrvDomain(SrvDir):
def op_destroy(self, op, req):
fn = FormFn(self.xd.domain_destroy,
[['dom', 'str'],
[['dom', 'int'],
['reason', 'str']])
val = fn(req.args, {'dom': self.dom.id})
req.setHeader("Location", "%s/.." % req.prePathURL())
@@ -61,7 +61,7 @@ class SrvDomain(SrvDir):
def do_save(self, op, req):
fn = FormFn(self.xd.domain_save,
[['dom', 'str'],
[['dom', 'int'],
['file', 'str']])
val = fn(req.args, {'dom': self.dom.id})
return 0
@@ -71,7 +71,7 @@ class SrvDomain(SrvDir):
def do_migrate(self, op, req):
fn = FormFn(self.xd.domain_migrate,
[['dom', 'str'],
[['dom', 'int'],
['destination', 'str'],
['live', 'int'],
['resource', 'int']])
@@ -79,7 +79,7 @@ class SrvDomain(SrvDir):
def op_pincpu(self, op, req):
fn = FormFn(self.xd.domain_pincpu,
[['dom', 'str'],
[['dom', 'int'],
['vcpu', 'int'],
['cpumap', 'int']])
val = fn(req.args, {'dom': self.dom.id})
@@ -87,7 +87,7 @@ class SrvDomain(SrvDir):
def op_cpu_bvt_set(self, op, req):
fn = FormFn(self.xd.domain_cpu_bvt_set,
[['dom', 'str'],
[['dom', 'int'],
['mcuadv', 'int'],
['warpback', 'int'],
['warpvalue', 'int'],
@@ -99,7 +99,7 @@ class SrvDomain(SrvDir):
def op_cpu_sedf_set(self, op, req):
fn = FormFn(self.xd.domain_cpu_sedf_set,
[['dom', 'str'],
[['dom', 'int'],
['period', 'int'],
['slice', 'int'],
['latency', 'int'],
@@ -110,28 +110,28 @@ class SrvDomain(SrvDir):
def op_maxmem_set(self, op, req):
fn = FormFn(self.xd.domain_maxmem_set,
[['dom', 'str'],
[['dom', 'int'],
['memory', 'int']])
val = fn(req.args, {'dom': self.dom.id})
return val
def op_mem_target_set(self, op, req):
fn = FormFn(self.xd.domain_mem_target_set,
[['dom', 'str'],
[['dom', 'int'],
['target', 'int']])
val = fn(req.args, {'dom': self.dom.id})
return val
def op_devices(self, op, req):
fn = FormFn(self.xd.domain_devtype_ls,
[['dom', 'str'],
[['dom', 'int'],
['type', 'str']])
val = fn(req.args, {'dom': self.dom.id})
return val
def op_device(self, op, req):
fn = FormFn(self.xd.domain_devtype_get,
[['dom', 'str'],
[['dom', 'int'],
['type', 'str'],
['idx', 'int']])
val = fn(req.args, {'dom': self.dom.id})
@@ -142,14 +142,14 @@ class SrvDomain(SrvDir):
def op_device_create(self, op, req):
fn = FormFn(self.xd.domain_device_create,
[['dom', 'str'],
[['dom', 'int'],
['config', 'sxpr']])
val = fn(req.args, {'dom': self.dom.id})
return val
def op_device_refresh(self, op, req):
fn = FormFn(self.xd.domain_device_refresh,
[['dom', 'str'],
[['dom', 'int'],
['type', 'str'],
['idx', 'str']])
val = fn(req.args, {'dom': self.dom.id})
@@ -157,7 +157,7 @@ class SrvDomain(SrvDir):
def op_device_destroy(self, op, req):
fn = FormFn(self.xd.domain_device_destroy,
[['dom', 'str'],
[['dom', 'int'],
['type', 'str'],
['idx', 'str']])
val = fn(req.args, {'dom': self.dom.id})
@@ -165,7 +165,7 @@ class SrvDomain(SrvDir):
def op_device_configure(self, op, req):
fn = FormFn(self.xd.domain_device_configure,
[['dom', 'str'],
[['dom', 'int'],
['config', 'sxpr'],
['idx', 'str']])
val = fn(req.args, {'dom': self.dom.id})
@@ -173,7 +173,7 @@ class SrvDomain(SrvDir):
def op_vif_limit_set(self, op, req):
fn = FormFn(self.xd.domain_vif_limit_set,
[['dom', 'str'],
[['dom', 'int'],
['vif', 'int'],
['credit', 'int'],
['period', 'int']])
+1 -1
View File
@@ -24,7 +24,7 @@ class SrvDomainDir(SrvDir):
def domain(self, x):
val = None
dom = self.xd.domain_lookup(x)
dom = self.xd.domain_lookup_by_name(x)
if not dom:
raise XendError('No such domain ' + str(x))
val = SrvDomain(dom)
+26 -13
View File
@@ -5,14 +5,15 @@ import string
from xen.util import blkif
from xen.xend.XendError import XendError, VmError
from xen.xend import XendRoot
from xen.xend.XendRoot import get_component
from xen.xend.XendLogging import log
from xen.xend import sxp
from xen.xend import Blkctl
from xen.xend.xenstore import DBVar
import channel
from controller import CtrlMsgRcvr, Dev, DevController
from messages import *
from xen.xend.server import channel
from xen.xend.server.controller import CtrlMsgRcvr, Dev, DevController
from xen.xend.server.messages import *
class BlkifBackend:
""" Handler for the 'back-end' channel to a block device driver domain
@@ -56,7 +57,7 @@ class BlkifBackend:
def openEvtchn(self):
self.evtchn = channel.eventChannel(self.backendDomain, self.frontendDomain)
def getEventChannelBackend(self):
val = 0
if self.evtchn:
@@ -158,6 +159,18 @@ class BlkDev(Dev):
"""Info record for a block device.
"""
__exports__ = Dev.__exports__ + [
DBVar('dev', ty='str'),
DBVar('vdev', ty='int'),
DBVar('mode', ty='str'),
DBVar('viftype', ty='str'),
DBVar('params', ty='str'),
DBVar('node', ty='str'),
DBVar('device', ty='long'),
DBVar('start_sector', ty='long'),
DBVar('nr_sectors', ty='long'),
]
def __init__(self, controller, id, config, recreate=False):
Dev.__init__(self, controller, id, config, recreate=recreate)
self.dev = None
@@ -206,7 +219,8 @@ class BlkDev(Dev):
raise VmError('vbd: Device not found: %s' % self.dev)
try:
self.backendDomain = int(sxp.child_value(config, 'backend', '0'))
xd = get_component('xen.xend.XendDomain')
self.backendDomain = xd.domain_lookup_by_name(sxp.child_value(config, 'backend', '0')).id
except:
raise XendError('invalid backend domain')
@@ -214,8 +228,7 @@ class BlkDev(Dev):
def attach(self, recreate=False, change=False):
if recreate:
node = sxp.child_value(recreate, 'node')
self.setNode(node)
pass
else:
node = Blkctl.block('bind', self.type, self.params)
self.setNode(node)
@@ -263,7 +276,7 @@ class BlkDev(Dev):
def check_mounted(self, name):
mode = blkif.mount_mode(name)
xd = XendRoot.get_component('xen.xend.XendDomain')
xd = get_component('xen.xend.XendDomain')
for vm in xd.list():
ctrl = vm.getDeviceController(self.getType(), error=False)
if (not ctrl): continue
@@ -292,14 +305,14 @@ class BlkDev(Dev):
val.append(['uname', self.uname])
if self.node:
val.append(['node', self.node])
val.append(['index', self.getIndex()])
return val
def getBackend(self):
return self.controller.getBackend(self.backendDomain)
def refresh(self):
log.debug("Refreshing vbd domain=%d id=%s", self.frontendDomain, self.id)
log.debug("Refreshing vbd domain=%d id=%s", self.frontendDomain,
self.id)
self.interfaceChanged()
def destroy(self, change=False, reboot=False):
@@ -308,7 +321,8 @@ class BlkDev(Dev):
@param change: change flag
"""
self.destroyed = True
log.debug("Destroying vbd domain=%d id=%s", self.frontendDomain, self.id)
log.debug("Destroying vbd domain=%d id=%s", self.frontendDomain,
self.id)
self.send_be_vbd_destroy()
if change:
self.interfaceChanged()
@@ -445,5 +459,4 @@ class BlkifController(DevController):
log.error("Exception connecting backend: %s", ex)
else:
log.error('interface connect on unknown interface: id=%d', id)
+147 -36
View File
@@ -14,52 +14,129 @@ DEBUG = 0
RESPONSE_TIMEOUT = 20.0
def eventChannel(dom1, dom2):
"""Create an event channel between domains.
The returned dict contains dom1, dom2, port1 and port2 on success.
@return dict (empty on error)
class EventChannel(dict):
"""An event channel between domains.
"""
evtchn = xc.evtchn_bind_interdomain(dom1=dom1, dom2=dom2)
if evtchn:
evtchn['dom1'] = dom1
evtchn['dom2'] = dom2
return evtchn
def interdomain(cls, dom1, dom2, port1=0, port2=0):
"""Create an event channel between domains.
@return EventChannel (None on error)
"""
v = xc.evtchn_bind_interdomain(dom1=dom1, dom2=dom2,
port1=port1, port2=port2)
if v:
v = cls(dom1, dom2, v)
return v
interdomain = classmethod(interdomain)
def restoreFromDB(cls, db, dom1, dom2, port1=0, port2=0):
"""Create an event channel using db info if available.
Inverse to saveToDB().
@param db db
@param dom1
@param dom2
@param port1
@param port2
"""
try:
dom1 = int(db['dom1'])
except: pass
try:
dom2 = int(db['dom2'])
except: pass
try:
port1 = int(db['port1'])
except: pass
try:
port2 = int(db['port2'])
except: pass
evtchn = cls.interdomain(dom1, dom2, port1=port1, port2=port2)
return evtchn
restoreFromDB = classmethod(restoreFromDB)
def __init__(self, dom1, dom2, d):
d['dom1'] = dom1
d['dom2'] = dom2
self.update(d)
self.dom1 = dom1
self.dom2 = dom2
self.port1 = d.get('port1')
self.port2 = d.get('port2')
def close(self):
"""Close the event channel.
"""
def evtchn_close(dom, port):
try:
xc.evtchn_close(dom=dom, port=port)
except Exception, ex:
pass
if DEBUG:
print 'EventChannel>close>', self
evtchn_close(self.dom1, self.port1)
evtchn_close(self.dom2, self.port2)
def saveToDB(self, db):
"""Save the event channel to the db so it can be restored later,
using restoreFromDB() on the class.
@param db db
"""
db['dom1'] = str(self.dom1)
db['dom2'] = str(self.dom2)
db['port1'] = str(self.port1)
db['port2'] = str(self.port2)
db.saveDB()
def sxpr(self):
return ['event-channel',
['dom1', self.dom1 ],
['port1', self.port1 ],
['dom2', self.dom2 ],
['port2', self.port2 ]
]
def __repr__(self):
return ("<EventChannel dom1:%d:%d dom2:%d:%d>"
% (self.dom1, self.port1, self.dom2, self.port2))
def eventChannel(dom1, dom2, port1=0, port2=0):
"""Create an event channel between domains.
@return EventChannel (None on error)
"""
return EventChannel.interdomain(dom1, dom2, port1=port1, port2=port2)
def eventChannelClose(evtchn):
"""Close an event channel that was opened by eventChannel().
"""Close an event channel.
"""
def evtchn_close(dom, port):
if (dom is None) or (port is None): return
try:
xc.evtchn_close(dom=dom, port=port)
except Exception, ex:
pass
if not evtchn: return
if DEBUG:
print 'eventChannelClose>', evtchn
evtchn_close(evtchn.get('dom1'), evtchn.get('port1'))
evtchn_close(evtchn.get('dom2'), evtchn.get('port2'))
evtchn.close()
class ChannelFactory:
"""Factory for creating channels.
"""Factory for creating control channels.
Maintains a table of channels.
"""
""" Channels indexed by index. """
channels = {}
channels = None
thread = None
notifier = None
"""Map of ports to the virq they signal."""
virqPorts = {}
virqPorts = None
def __init__(self):
"""Constructor - do not use. Use the channelFactory function."""
self.channels = {}
self.virqPorts = {}
self.notifier = xu.notifier()
# Register interest in virqs.
self.bind_virq(xen.lowlevel.xc.VIRQ_DOM_EXC)
@@ -70,10 +147,6 @@ class ChannelFactory:
self.virqPorts[port] = virq
log.info("Virq %s on port %s", virq, port)
def virq(self):
log.error("virq")
self.notifier.virq_send(self.virqPort)
def start(self):
"""Fork a thread to read messages.
"""
@@ -182,9 +255,13 @@ class ChannelFactory:
return None
def openChannel(self, dom, local_port=0, remote_port=0):
return (self.findChannel(dom, local_port=local_port, remote_port=remote_port)
or
self.newChannel(dom, local_port, remote_port))
chan = self.findChannel(dom, local_port=local_port,
remote_port=remote_port)
if chan:
return chan
chan = self.newChannel(dom, local_port, remote_port)
return chan
def createPort(self, dom, local_port=0, remote_port=0):
"""Create a port for a channel to the given domain.
@@ -203,8 +280,31 @@ class ChannelFactory:
@type remote: int
@return: port object
"""
return xu.port(dom, local_port=int(local_port),
remote_port=int(remote_port))
return xu.port(dom, local_port=local_port, remote_port=remote_port)
def restoreFromDB(self, db, dom, local, remote):
"""Create a channel using ports restored from the db (if available).
Otherwise use the given ports. This is the inverse operation to
saveToDB() on a channel.
@param db db
@param dom domain the channel connects to
@param local default local port
@param remote default remote port
"""
try:
local_port = int(db['local_port'])
except:
local_port = local
try:
remote_port = int(db['remote_port'])
except:
remote_port = remote
try:
chan = self.openChannel(dom, local_port, remote_port)
except:
return None
return chan
def channelFactory():
"""Singleton constructor for the channel factory.
@@ -218,7 +318,7 @@ def channelFactory():
return inst
class Channel:
"""Chanel to a domain.
"""Control channel to a domain.
Maintains a list of device handlers to dispatch requests to, based
on the request type.
"""
@@ -239,6 +339,17 @@ class Channel:
# Make sure the port will deliver all the messages.
self.port.register(TYPE_WILDCARD)
def saveToDB(self, db):
"""Save the channel ports to the db so the channel can be restored later,
using restoreFromDB() on the factory.
@param db db
"""
if self.closed: return
db['local_port'] = str(self.getLocalPort())
db['remote_port'] = str(self.getRemotePort())
db.saveDB()
def getKey(self):
"""Get the channel key.
"""
+10 -4
View File
@@ -13,10 +13,11 @@ from xen.xend import EventServer; eserver = EventServer.instance()
from xen.xend.XendLogging import log
from xen.xend import XendRoot; xroot = XendRoot.instance()
from xen.xend import sxp
from xen.xend.xenstore import DBVar
from controller import CtrlMsgRcvr, Dev, DevController
from messages import *
from params import *
from xen.xend.server.controller import CtrlMsgRcvr, Dev, DevController
from xen.xend.server.messages import *
from xen.xend.server.params import *
class ConsoleProtocol(protocol.Protocol):
"""Asynchronous handler for a console socket.
@@ -76,6 +77,12 @@ class ConsoleDev(Dev, protocol.ServerFactory):
STATUS_CONNECTED = 'connected'
STATUS_LISTENING = 'listening'
__exports__ = Dev.__exports__ + [
DBVar('status', ty='str'),
#DBVar('listening', ty='str'),
DBVar('console_port', ty='int'),
]
def __init__(self, controller, id, config, recreate=False):
Dev.__init__(self, controller, id, config)
self.lock = threading.RLock()
@@ -129,7 +136,6 @@ class ConsoleDev(Dev, protocol.ServerFactory):
val.append(['local_port', self.getLocalPort() ])
val.append(['remote_port', self.getRemotePort() ])
val.append(['console_port', self.console_port ])
val.append(['index', self.getIndex()])
if self.addr:
val.append(['connected', self.addr[0], self.addr[1]])
finally:
+86 -39
View File
@@ -4,7 +4,8 @@ for a domain.
"""
from xen.xend.XendError import XendError
from messages import msgTypeName, printMsg, getMessageType
from xen.xend.xenstore import DBVar
from xen.xend.server.messages import msgTypeName, printMsg, getMessageType
DEBUG = 0
@@ -115,18 +116,18 @@ class DevControllerTable:
def getDevControllerClass(self, type):
return self.controllerClasses.get(type)
def addDevControllerClass(self, klass):
self.controllerClasses[klass.getType()] = klass
def addDevControllerClass(self, cls):
self.controllerClasses[cls.getType()] = cls
def delDevControllerClass(self, type):
if type in self.controllerClasses:
del self.controllerClasses[type]
def createDevController(self, type, vm, recreate=False):
klass = self.getDevControllerClass(type)
if not klass:
cls = self.getDevControllerClass(type)
if not cls:
raise XendError("unknown device type: " + type)
return klass.createDevController(vm, recreate=recreate)
return cls.createDevController(vm, recreate=recreate)
def getDevControllerTable():
"""Singleton constructor for the controller table.
@@ -138,11 +139,11 @@ def getDevControllerTable():
devControllerTable = DevControllerTable()
return devControllerTable
def addDevControllerClass(name, klass):
def addDevControllerClass(name, cls):
"""Add a device controller class to the controller table.
"""
klass.name = name
getDevControllerTable().addDevControllerClass(klass)
cls.type = name
getDevControllerTable().addDevControllerClass(cls)
def createDevController(name, vm, recreate=False):
return getDevControllerTable().createDevController(name, vm, recreate=recreate)
@@ -155,29 +156,57 @@ class DevController:
"""
name = None
# State:
# controller/<type> : for controller
# device/<type>/<id> : for each device
def createDevController(klass, vm, recreate=False):
def createDevController(cls, vm, recreate=False):
"""Class method to create a dev controller.
"""
ctrl = klass(vm, recreate=recreate)
ctrl = cls(vm, recreate=recreate)
ctrl.initController(recreate=recreate)
ctrl.exportToDB()
return ctrl
createDevController = classmethod(createDevController)
def getType(klass):
return klass.name
def getType(cls):
return cls.type
getType = classmethod(getType)
__exports__ = [
DBVar('type', 'str'),
DBVar('destroyed', 'bool'),
]
# Set when registered.
type = None
def __init__(self, vm, recreate=False):
self.destroyed = False
self.vm = vm
self.db = self.getDB()
self.deviceId = 0
self.devices = {}
self.device_order = []
def getDB(self):
"""Get the db node to use for a controller.
"""
return self.vm.db.addChild("/controller/%s" % self.getType())
def getDevDB(self, id):
"""Get the db node to use for a device.
"""
return self.vm.db.addChild("/device/%s/%s" % (self.getType(), id))
def exportToDB(self, save=False):
self.db.exportToDB(self, fields=self.__exports__, save=save)
def importFromDB(self):
self.db.importFromDB(self, fields=self.__exports__)
def getDevControllerType(self):
return self.dctype
@@ -229,18 +258,19 @@ class DevController:
i.e. it is being added at runtime rather than when the domain is created.
"""
dev = self.newDevice(self.nextDeviceId(), config, recreate=recreate)
if self.vm.recreate:
dev.importFromDB()
dev.init(recreate=recreate)
self.addDevice(dev)
idx = self.getDeviceIndex(dev)
recreate = self.vm.get_device_recreate(self.getType(), idx)
if not recreate:
dev.exportToDB()
dev.attach(recreate=recreate, change=change)
dev.exportToDB()
def configureDevice(self, id, config, change=False):
"""Reconfigure an existing device.
May be defined in subclass."""
dev = self.getDevice(id)
if not dev:
raise XendError("invalid device id: " + id)
dev = self.getDevice(id, error=True)
dev.configure(config, change=change)
def destroyDevice(self, id, change=False, reboot=False):
@@ -251,9 +281,7 @@ class DevController:
The device is not deleted, since it may be recreated later.
"""
dev = self.getDevice(id)
if not dev:
raise XendError("invalid device id: " + id)
dev = self.getDevice(id, error=True)
dev.destroy(change=change, reboot=reboot)
return dev
@@ -278,24 +306,15 @@ class DevController:
def isDestroyed(self):
return self.destroyed
def getDevice(self, id):
return self.devices.get(id)
def getDeviceByIndex(self, idx):
if 0 <= idx < len(self.device_order):
return self.device_order[idx]
else:
return None
def getDeviceIndex(self, dev):
return self.device_order.index(dev)
def getDevice(self, id, error=False):
dev = self.devices.get(id)
if error and not dev:
raise XendError("invalid device id: " + id)
return dev
def getDeviceIds(self):
return [ dev.getId() for dev in self.device_order ]
def getDeviceIndexes(self):
return range(0, len(self.device_order))
def getDevices(self):
return self.device_order
@@ -353,11 +372,42 @@ class Dev:
@type controller: DevController
"""
# ./status : need 2: actual and requested?
# down-down: initial.
# up-up: fully up.
# down-up: down requested, still up. Watch front and back, when both
# down go to down-down. But what if one (or both) is not connected?
# Still have front/back trees with status? Watch front/status, back/status?
# up-down: up requested, still down.
# Back-end watches ./status, front/status
# Front-end watches ./status, back/status
# i.e. each watches the other 2.
# Each is status/request status/actual?
#
# backend?
# frontend?
__exports__ = [
DBVar('id', ty='int'),
DBVar('type', ty='str'),
DBVar('config', ty='sxpr'),
DBVar('destroyed', ty='bool'),
]
def __init__(self, controller, id, config, recreate=False):
self.controller = controller
self.id = id
self.config = config
self.destroyed = False
self.type = self.getType()
self.db = controller.getDevDB(id)
def exportToDB(self, save=False):
self.db.exportToDB(self, fields=self.__exports__, save=save)
def importFromDB(self):
self.db.importFromDB(self, fields=self.__exports__)
def getDomain(self):
return self.controller.getDomain()
@@ -380,9 +430,6 @@ class Dev:
def getId(self):
return self.id
def getIndex(self):
return self.controller.getDeviceIndex(self)
def getConfig(self):
return self.config
+71 -14
View File
@@ -4,21 +4,75 @@
import random
from xen.util.mac import macFromString, macToString
from xen.xend import sxp
from xen.xend import Vifctl
from xen.xend.XendError import XendError, VmError
from xen.xend.XendLogging import log
from xen.xend import XendVnet
from xen.xend.XendRoot import get_component
from xen.xend.xenstore import DBVar
import channel
from controller import CtrlMsgRcvr, Dev, DevController
from messages import *
from xen.xend.server import channel
from xen.xend.server.controller import CtrlMsgRcvr, Dev, DevController
from xen.xend.server.messages import *
class NetDev(Dev):
"""A network device.
"""
# State:
# inherited +
# ./config
# ./mac
# ./be_mac
# ./bridge
# ./script
# ./ipaddr ?
#
# ./credit
# ./period
#
# ./vifctl: up/down?
# ./vifname
#
#
# Poss should have no backend state here - except for ref to backend's own tree
# for the device? And a status - the one we want.
# ./back/dom
# ./back/devid - id for back-end (netif_handle) - same as front/devid
# ./back/id - backend id (if more than one b/e per domain)
# ./back/status
# ./back/tx_shmem_frame - actually these belong in back-end state
# ./back/rx_shmem_frame
#
# ./front/dom
# ./front/devid
# ./front/status - need 2: one for requested, one for actual? Or drive from dev status
# and this is front status only.
# ./front/tx_shmem_frame
# ./front/rx_shmem_frame
#
# ./evtchn/front - here or in front/back?
# ./evtchn/back
# ./evtchn/status ?
# At present created by dev: but should be created unbound by front/back
# separately and then bound (by back)?
__exports__ = Dev.__exports__ + [
DBVar('config', ty='sxpr'),
DBVar('mac', ty='mac'),
DBVar('be_mac', ty='mac'),
DBVar('bridge', ty='str'),
DBVar('script', ty='str'),
#DBVar('ipaddr'),
DBVar('credit', ty='int'),
DBVar('period', ty='int'),
DBVar('vifname', ty='str'),
DBVar('evtchn'), #todo: export fields (renamed)
]
def __init__(self, controller, id, config, recreate=False):
Dev.__init__(self, controller, id, config, recreate=recreate)
self.vif = int(self.id)
@@ -49,15 +103,19 @@ class NetDev(Dev):
def _get_config_mac(self, config):
vmac = sxp.child_value(config, 'mac')
if not vmac: return None
mac = [ int(x, 16) for x in vmac.split(':') ]
if len(mac) != 6: raise XendError("invalid mac: %s" % vmac)
try:
mac = macFromString(vmac)
except:
raise XendError("invalid mac: %s" % vmac)
return mac
def _get_config_be_mac(self, config):
vmac = sxp.child_value(config, 'be_mac')
if not vmac: return None
mac = [ int(x, 16) for x in vmac.split(':') ]
if len(mac) != 6: raise XendError("invalid backend mac: %s" % vmac)
try:
mac = macFromString(vmac)
except:
raise XendError("invalid backend mac: %s" % vmac)
return mac
def _get_config_ipaddr(self, config):
@@ -102,7 +160,7 @@ class NetDev(Dev):
else:
#todo: Code below will fail on xend restart when backend is not domain 0.
xd = get_component('xen.xend.XendDomain')
self.backendDomain = int(xd.domain_lookup(sxp.child_value(config, 'backend', '0')).id)
self.backendDomain = xd.domain_lookup_by_name(sxp.child_value(config, 'backend', '0')).id
except:
raise XendError('invalid backend domain')
return self.config
@@ -127,13 +185,13 @@ class NetDev(Dev):
ipaddr = self._get_config_ipaddr(config)
xd = get_component('xen.xend.XendDomain')
backendDomain = str(xd.domain_lookup(sxp.child_value(config, 'backend', '0')).id)
backendDomain = xd.domain_lookup_by_name(sxp.child_value(config, 'backend', '0')).id
if (mac is not None) and (mac != self.mac):
raise XendError("cannot change mac")
if (be_mac is not None) and (be_mac != self.be_mac):
raise XendError("cannot change backend mac")
if (backendDomain is not None) and (backendDomain != str(self.backendDomain)):
if (backendDomain is not None) and (backendDomain != self.backendDomain):
raise XendError("cannot change backend")
if (bridge is not None) and (bridge != self.bridge):
changes['bridge'] = bridge
@@ -199,7 +257,6 @@ class NetDev(Dev):
val.append(['evtchn',
self.evtchn['port1'],
self.evtchn['port2']])
val.append(['index', self.getIndex()])
return val
def get_vifname(self):
@@ -213,12 +270,12 @@ class NetDev(Dev):
def get_mac(self):
"""Get the MAC address as a string.
"""
return ':'.join(map(lambda x: "%02x" % x, self.mac))
return macToString(self.mac)
def get_be_mac(self):
"""Get the backend MAC address as a string.
"""
return ':'.join(map(lambda x: "%02x" % x, self.be_mac))
return macToString(self.be_mac)
def vifctl_params(self, vmname=None):
"""Get the parameters to pass to vifctl.
@@ -230,7 +287,7 @@ class NetDev(Dev):
vm = xd.domain_lookup(dom)
vmname = vm.name
except:
vmname = 'DOM%d' % dom
vmname = 'Domain-%d' % dom
return { 'domain': vmname,
'vif' : self.get_vifname(),
'mac' : self.get_mac(),
+32 -4
View File
@@ -1,6 +1,34 @@
import os
def getenv(var, val, conv=None):
"""Get a value from the environment, with optional conversion.
@param var name of environment variable
@param val default value
@param conv conversion function to apply to env value
@return converted value or default
"""
try:
v = os.getenv(var)
if v is None:
v = val
else:
print var, '=', v
if conv:
v = conv(v)
except:
v = val
return v
# The following parameters could be placed in a configuration file.
XEND_PID_FILE = '/var/run/xend.pid'
XEND_TRACE_FILE = '/var/log/xend.trace'
XEND_USER = 'root'
XEND_PID_FILE = '/var/run/xend.pid'
XEND_TRACE_FILE = '/var/log/xend.trace'
XEND_DEBUG_LOG = '/var/log/xend-debug.log'
XEND_USER = 'root'
XEND_DEBUG = getenv("XEND_DEBUG", 0, conv=int)
XEND_DAEMONIZE = getenv("XEND_DAEMONIZE", not XEND_DEBUG, conv=int)
XENSTORED_PID_FILE = '/var/run/xenstored.pid'
XENSTORED_RUN_DIR = '/var/run/xenstored'
XENSTORED_LIB_DIR = '/var/lib/xenstored'
XENSTORED_DEBUG = getenv("XENSTORED_DEBUG", 0, conv=int)
+9 -4
View File
@@ -7,10 +7,11 @@
from xen.xend import sxp
from xen.xend.XendLogging import log
from xen.xend.XendError import XendError
from xen.xend.xenstore import DBVar
import channel
from controller import Dev, DevController
from messages import *
from xen.xend.server import channel
from xen.xend.server.controller import Dev, DevController
from xen.xend.server.messages import *
class UsbBackend:
"""Handler for the 'back-end' channel to a USB device driver domain
@@ -141,6 +142,11 @@ class UsbBackend:
class UsbDev(Dev):
__exports__ = Dev.__exports__ + [
DBVar('port', ty='int'),
DBVar('path', ty='str'),
]
def __init__(self, controller, id, config, recreate=False):
Dev.__init__(self, controller, id, config, recreate=recreate)
@@ -186,7 +192,6 @@ class UsbDev(Dev):
['port', self.port],
['path', self.path],
]
val.append(['index', self.getIndex()])
return val
def getBackend(self):
+65
View File
@@ -0,0 +1,65 @@
"""Universal(ly) Unique Identifiers (UUIDs).
"""
import commands
import random
def uuidgen(random=True):
"""Generate a UUID using the command uuidgen.
If random is true (default) generates a random uuid.
If random is false generates a time-based uuid.
"""
cmd = "uuidgen"
if random:
cmd += " -r"
else:
cmd += " -t"
return commands.getoutput(cmd)
class UuidFactoryUuidgen:
"""A uuid factory using uuidgen."""
def __init__(self):
pass
def getUuid(self):
return uuidgen()
class UuidFactoryRandom:
"""A random uuid factory."""
def __init__(self):
f = file("/dev/urandom", "r")
seed = f.read(16)
f.close()
self.rand = random.Random(seed)
def randBytes(self, n):
return [ self.rand.randint(0, 255) for i in range(0, n) ]
def getUuid(self):
bytes = self.randBytes(16)
# Encode the variant.
bytes[6] = (bytes[6] & 0x0f) | 0x40
bytes[8] = (bytes[8] & 0x3f) | 0x80
f = "%02x"
return ( "-".join([f*4, f*2, f*2, f*2, f*6]) % tuple(bytes) )
def getFactory():
"""Get the factory to use for creating uuids.
This is so it's easy to change the uuid factory.
For example, for testing we might want repeatable uuids
rather than the random ones we normally use.
"""
global uuidFactory
try:
uuidFactory
except:
#uuidFactory = UuidFactoryUuidgen()
uuidFactory = UuidFactoryRandom()
return uuidFactory
def getUuid():
return getFactory().getUuid()
@@ -0,0 +1,2 @@
from xsnode import *
from xsobj import *
+382
View File
@@ -0,0 +1,382 @@
import errno
import os
import os.path
import select
import sys
import time
from xen.lowlevel import xs
from xen.xend import sxp
from xen.xend.PrettyPrint import prettyprint
SELECT_TIMEOUT = 2.0
def getEventPath(event):
return os.path.join("/_event", event)
def getEventIdPath(event):
return os.path.join(eventPath(event), "@eid")
class Subscription:
def __init__(self, event, fn, id):
self.event = event
self.watcher = None
self.fn = fn
self.id = id
def watch(self, watcher):
self.watcher = watcher
watcher.addSubs(self)
def unwatch(self):
watcher = self.watcher
if watcher:
self.watcher = None
watcher.delSubs(self)
def notify(self, event):
try:
self.fn(event, id)
except SystemExitException:
raise
except:
pass
class Watcher:
def __init__(self, store, event):
self.path = getEventPath(event)
self.eidPath = getEventIdPath(event)
store.mkdirs(self.path)
if not store.exists(self.eidPath):
store.writeInt(self.eidPath, 0)
self.xs = None
self.subs = []
def __getattr__(self, k, v):
if k == "fileno":
if self.xs:
return self.xs.fileno
else:
return -1
else:
return self.__dict__.get(k, v)
def addSubs(self, subs):
self.subs.append(subs)
self.watch()
def delSubs(self, subs):
self.subs.remove(subs)
if len(self.subs) == 0:
self.unwatch()
def getEvent(self):
return self.event
def watch(self):
if self.xs: return
self.xs = xs.open()
self.xs.watch(path)
def unwatch(self):
if self.xs:
self.xs.unwatch(self.path)
self.xs.close()
self.xs = None
def watching(self):
return self.xs is not None
def getNotification(self):
p = self.xs.read_watch()
self.xs.acknowledge_watch()
eid = self.xs.readInt(self.eidPath)
return p
def notify(self, subs):
p = self.getNotification()
for s in subs:
s.notify(p)
class XenStore:
def __init__(self):
self.xs = None
#self.xs = xs.open()
self.subscription = {}
self.subscription_id = 0
self.events = {}
self.write("/", "")
def getxs(self):
if self.xs is None:
ex = None
for i in range(0,20):
try:
self.xs = xs.open()
ex = None
break
except Exception, ex:
print >>stderr, "Exception connecting to xsdaemon:", ex
print >>stderr, "Trying again..."
time.sleep(1)
else:
raise ex
#todo would like to reconnect if xs conn closes (e.g. daemon restart).
return self.xs
def dump(self, path="/", out=sys.stdout):
print 'dump>', path
val = ['node']
val.append(['path', path])
## perms = ['perms']
## for p in self.getPerms(path):
## l = ['perm']
## l.append('dom', p.get['dom'])
## for k in ['read', 'write', 'create', 'owner']:
## v = p.get(k)
## l.append([k, v])
## perms.append(l)
## val.append(perms)
data = self.read(path)
if data:
val.append(['data', data])
children = ['children']
for x in self.lsPaths(path):
print 'dump>', 'child=', x
children.append(self.dump(x))
if len(children) > 1:
val.append(children)
prettyprint(val, out=out)
return val
def getPerms(self, path):
return self.getxs().get_permissions(path)
def ls(self, path="/"):
return self.getxs().ls(path)
def lsPaths(self, path="/"):
return [ os.path.join(path, x) for x in self.ls(path) ]
def lsr(self, path="/", list=None):
if list is None:
list = []
list.append(path)
for x in self.lsPaths(path):
list.append(x)
self.lsr(x, list=list)
return list
def rm(self, path):
try:
#for x in self.lsPaths():
# self.getxs().rm(x)
self.getxs().rm(path)
except:
pass
def exists(self, path):
try:
self.getxs().ls(path)
return True
except RuntimeError, ex:
if ex.args[0] == errno.ENOENT:
return False
else:
raise
def mkdirs(self, path):
if self.exists(path):
return
elts = path.split("/")
p = "/"
for x in elts:
if x == "": continue
p = os.path.join(p, x)
if not self.exists(p):
self.getxs().write(p, "", create=True)
def read(self, path):
try:
return self.getxs().read(path)
except RuntimeError, ex:
if ex.args[0] == errno.EISDIR:
return None
else:
raise
def create(self, path, excl=False):
self.write(path, "", create=True, excl=excl)
def write(self, path, data, create=True, excl=False):
self.mkdirs(path)
self.getxs().write(path, data, create=create, excl=excl)
def begin(self, path):
self.getxs().begin_transaction(path)
def commit(self, abandon=False):
self.getxs().end_transaction(abort=abandon)
def subscribe(self, event, fn):
watcher = self.watchEvent(event)
self.subscription_id += 1
subs = Subscription(event, fn, self.subscription_id)
self.subscription[subs.id] = subs
subs.watch(watcher)
return subs.id
def unsubscribe(self, sid):
s = self.subscription.get(sid)
if not s: return
del self.subscription[s.id]
s.unwatch()
unwatchEvent(s.event)
def sendEvent(self, event, data):
eventPath = getEventPath(event)
eidPath = getEventIdPath(event)
try:
self.begin(eventPath)
self.mkdirs(eventPath)
if self.exists(eidPath):
eid = self.readInt(eidPath)
eid += 1
else:
eid = 1
self.writeInt(eidPath, eid)
self.write(os.path.join(eventPath, str(eid)), data)
finally:
self.commit()
def watchEvent(self, event):
if event in self.events:
return
watcher = Watcher(event)
self.watchers[watcher.getEvent()] = watcher
self.watchStart()
return watcher
def unwatchEvent(self, event):
watcher = self.watchers.get(event)
if not watcher:
return
if not watcher.watching():
del self.watchers[event]
def watchStart(self):
if self.watchThread: return
def watchMain(self):
try:
while True:
if self.watchThread is None: return
if not self.events:
return
rd = self.watchers.values()
try:
(rd, wr, er) = select.select(rd, [], [], SELECT_TIMEOUT)
for watcher in rd:
watcher.notify()
except socket.error, ex:
if ex.args[0] in (EAGAIN, EINTR):
pass
else:
raise
finally:
self.watchThread = None
def introduceDomain(self, dom, page, evtchn, path):
self.getxs().introduce_domain(dom, page, evtchn.port1, path)
def releaseDomain(self, dom):
self.getxs().release_domain(dom)
def getXenStore():
global xenstore
try:
return xenstore
except:
xenstore = XenStore()
return xenstore
class XenNode:
def __init__(self, path="/", create=True):
self.store = getXenStore()
self.path = path
if not self.store.exists(path):
if create:
self.store.create(path)
else:
raise ValueError("path does not exist: '%s'" % path)
def relPath(self, path=""):
if not path:
return self.path
if path and path.startswith("/"):
path = path[1:]
return os.path.join(self.path, path)
def delete(self, path=""):
self.store.rm(self.relPath(path))
def exists(self, path=""):
return self.store.exists(self.relPath(path))
def getNode(self, path="", create=True):
if path == "":
return self
else:
return XenNode(self.relPath(path=path), create=create)
getChild = getNode
def getData(self, path=""):
path = self.relPath(path)
try:
return self.store.read(path)
except:
return None
def setData(self, data, path=""):
path = self.relPath(path)
#print 'XenNode>setData>', 'path=', path, 'data=', data
return self.store.write(path, data)
def getLock(self):
return None
def lock(self, lockid):
return None
def unlock(self, lockid):
return None
def deleteChild(self, name):
self.delete(name)
def deleteChildren(self):
for name in self.ls():
self.deleteChild(name)
def getChildren(self):
return [ self.getNode(name) for name in self.ls() ]
def ls(self):
return self.store.ls(self.path)
def introduceDomain(self, dom, page, evtchn, path):
self.store.introduceDomain(dom, page, evtchn, path)
def releaseDomain(self, dom):
self.store.releaseDomain(dom)
def __repr__(self):
return "<XenNode %s>" % self.path
+522
View File
@@ -0,0 +1,522 @@
import string
import types
from xen.xend import sxp
from xsnode import XenNode
from xen.util.mac import macToString, macFromString
VALID_KEY_CHARS = string.ascii_letters + string.digits + "_-@"
def hasAttr(obj, attr):
if isinstance(obj, dict):
return obj.contains(attr)
else:
return hasattr(obj, attr)
def getAttr(obj, attr):
if isinstance(obj, dict):
return dict.get(attr)
else:
return getattr(obj, attr, None)
def setAttr(obj, attr, val):
if isinstance(obj, dict):
dict[attr] = val
else:
setattr(obj, attr, val)
class DBConverter:
"""Conversion of values to and from strings in xenstore.
"""
converters = {}
def checkType(cls, ty):
if ty is None or ty in cls.converters:
return
raise ValueError("invalid converter type: '%s'" % ty)
checkType = classmethod(checkType)
def getConverter(cls, ty=None):
if ty is None:
ty = "str"
conv = cls.converters.get(ty)
if not conv:
raise ValueError("no converter for type: '%s'" % ty)
return conv
getConverter = classmethod(getConverter)
def convertToDB(cls, val, ty=None):
return cls.getConverter(ty).toDB(val)
convertToDB = classmethod(convertToDB)
def convertFromDB(cls, val, ty=None):
return cls.getConverter(ty).fromDB(val)
convertFromDB = classmethod(convertFromDB)
# Must define in subclass.
name = None
def __init__(self):
self.register()
def register(self):
if not self.name:
raise ValueError("invalid converter name: '%s'" % self.name)
self.converters[self.name] = self
def toDB(self, val):
raise NotImplementedError()
def fromDB(self, val):
raise NotImplementedError()
class StrConverter(DBConverter):
name = "str"
def toDB(self, val):
# Convert True/False to 1/0, otherwise they convert to
# 'True' and 'False' rather than '1' and '0', even though
# isinstance(True/False, int) is true.
if isinstance(val, bool):
val = int(val)
return str(val)
def fromDB(self, data):
return data
StrConverter()
class BoolConverter(DBConverter):
name = "bool"
def toDB(self, val):
return str(int(bool(val)))
def fromDB(self, data):
return bool(int(data))
BoolConverter()
class SxprConverter(DBConverter):
name = "sxpr"
def toDB(self, val):
return sxp.to_string(val)
def fromDB(self, data):
return sxp.from_string(data)
SxprConverter()
class IntConverter(DBConverter):
name = "int"
def toDB(self, val):
return str(int(val))
def fromDB(self, data):
return int(data)
IntConverter()
class FloatConverter(DBConverter):
name = "float"
def toDB(self, val):
return str(float(val))
def fromDB(self, data):
return float(data)
FloatConverter()
class LongConverter(DBConverter):
name = "long"
def toDB(self, val):
return str(long(val))
def fromDB(self, data):
return long(data)
LongConverter()
class MacConverter(DBConverter):
name = "mac"
def toDB(self, val):
return macToString(val)
def fromDB(self, data):
return macFromString(data)
MacConverter()
class DBVar:
def __init__(self, var, ty=None, path=None):
DBConverter.checkType(ty)
if path is None:
path = var
self.var = var
self.ty = ty
self.path = path
varpath = filter(bool, self.var.split())
self.attrpath = varpath[:-1]
self.attr = varpath[-1]
def exportToDB(self, db, obj):
self.setDB(db, self.getObj(obj))
def importFromDB(self, db, obj):
self.setObj(obj, self.getDB(db))
def getObj(self, obj):
o = obj
for x in self.attrpath:
o = getAttr(o, x)
if o is None:
return None
return getAttr(o, self.attr)
def setObj(self, obj, val):
o = obj
for x in self.attrpath:
o = getAttr(o, x)
# Don't set obj attr if val is None.
if val is None and hasAttr(o, self.attr):
return
setAttr(o, self.attr, val)
def getDB(self, db):
try:
data = getattr(db, self.path)
except AttributeError:
return None
return DBConverter.convertFromDB(data, ty=self.ty)
def setDB(self, db, val):
# Don't set in db if val is None.
#print 'DBVar>setDB>', self.path, 'val=', val
if val is None:
return
data = DBConverter.convertToDB(val, ty=self.ty)
#print 'DBVar>setDB>', self.path, 'data=', data
setattr(db, self.path, data)
class DBMap(dict):
"""A persistent map. Extends dict with persistence.
Set and get values using the usual map syntax:
m[k], m.get(k)
m[k] = v
Also supports being treated as an object with attributes.
When 'k' is a legal identifier you may also use
m.k, getattr(m, k)
m.k = v, setattr(m, k)
k in m, hasattr(m, k)
When setting you can pass in a normal value, for example
m.x = 3
Getting works too:
m.x ==> 3
while m['x'] will return the map for x.
m['x'].getData() ==> 3
To get values from subdirs use get() to get the subdir first:
get(m, 'foo').x
m['foo'].x
instead of m.foo.x, because m.foo will return the data for field foo,
not the directory.
You can assign values into a subdir by passing a map:
m.foo = {'x': 1, 'y':2 }
You can also use paths as keys:
m['foo/x'] = 1
sets field x in subdir foo.
"""
__db__ = None
__data__ = None
__perms__ = None
__parent__ = None
__name__ = ""
__transaction__ = False
# True if value set since saved (or never saved).
__dirty__ = True
def __init__(self, parent=None, name="", db=None):
if parent is None:
self.__name__ = name
else:
if not isinstance(parent, DBMap):
raise ValueError("invalid parent")
self.__parent__ = parent
self.__name__ = name
db = self.__parent__.getChildDB(name)
self.setDB(db)
def getName(self):
return self.__name__
def getPath(self):
return self.__db__ and self.__db__.relPath()
def introduceDomain(self, dom, page, evtchn, path=None):
db = self.__db__
if path is None:
path = db.relPath()
print 'DBMap>introduceDomain>', dom, page, evtchn, path
try:
db.introduceDomain(dom, page, evtchn, path)
except Exception, ex:
import traceback
traceback.print_exc()
print 'DBMap>introduceDomain>', ex
pass # todo: don't ignore
def releaseDomain(self, dom):
db = self.__db__
print 'DBMap>releaseDomain>', dom
try:
db.releaseDomain(dom)
except Exception, ex:
import traceback
traceback.print_exc()
print 'DBMap>releaseDomain>', ex
pass # todo: don't ignore
def transactionBegin(self):
# Begin a transaction.
pass
def transactionCommit(self):
# Commit writes to db.
pass
def transactionFail(self):
# Fail a transaction.
# We have changed values, what do we do?
pass
def watch(self, fn):
pass
def unwatch(self, watch):
pass
def checkName(self, k):
if k == "":
raise ValueError("invalid key, empty string")
for c in k:
if c in VALID_KEY_CHARS: continue
raise ValueError("invalid key char '%s'" % c)
def _setData(self, v):
#print 'DBMap>_setData>', self.getPath(), 'data=', v
if v != self.__data__:
self.__dirty__ = True
self.__data__ = v
def setData(self, v):
if isinstance(v, dict):
for (key, val) in v.items():
self[key] = val
else:
self._setData(v)
def getData(self):
return self.__data__
def _set(self, k, v):
dict.__setitem__(self, k, v)
def _get(self, k):
try:
return dict.__getitem__(self, k)
except:
return None
def _del(self, k, v):
try:
dict.__delitem__(self, k)
except:
pass
def _contains(self, k):
return dict.__contains__(self, k)
def __setitem__(self, k, v, save=False):
node = self.addChild(k)
node.setData(v)
if save:
node.saveDB()
def __getitem__(self, k):
if self._contains(k):
v = self._get(k)
else:
v = self.readChildDB(k)
self._set(k, v)
return v
def __delitem__(self, k):
self._del(k)
self.deleteChildDB(k)
def __repr__(self):
if len(self):
return dict.__repr__(self)
else:
return repr(self.__data__)
def __setattr__(self, k, v):
if k.startswith("__"):
object.__setattr__(self, k, v)
else:
self.__setitem__(k, v, save=True)
return v
def __getattr__(self, k):
if k.startswith("__"):
v = object.__getattr__(self, k)
else:
try:
v = self.__getitem__(k).getData()
except LookupError, ex:
raise AttributeError(ex.args)
return v
def __delattr__(self, k):
return self.__delitem__(k)
def delete(self):
dict.clear(self)
self.__data__ = None
if self.__db__:
self.__db__.delete()
def clear(self):
dict.clear(self)
if self.__db__:
self.__db__.deleteChildren()
def getChild(self, k):
return self._get(k)
def getChildDB(self, k):
self.checkName(k)
return self.__db__ and self.__db__.getChild(k)
def deleteChildDB(self, k):
if self.__db__:
self.__db__.deleteChild(k)
def _addChild(self, k):
kid = self._get(k)
if kid is None:
kid = DBMap(parent=self, name=k, db=self.getChildDB(k))
self._set(k, kid)
return kid
def addChild(self, path):
l = path.split("/")
n = self
for x in l:
if x == "": continue
n = n._addChild(x)
return n
def setDB(self, db):
if (db is not None) and not isinstance(db, XenNode):
raise ValueError("invalid db")
self.__db__ = db
for (k, v) in self.items():
if v is None: continue
if isinstance(v, DBMap):
v._setDB(self.addChild(k), restore)
def readDB(self):
if self.__db__ is None:
return
self.__data__ = self.__db__.getData()
for k in self.__db__.ls():
n = self.addChild(k)
n.readDB()
self.__dirty__ = False
def readChildDB(self, k):
if self.__db__ and (k in self.__db__.ls()):
n = self.addChild(k)
n.readDB()
raise LookupError("invalid key '%s'" % k)
def saveDB(self, sync=False, save=False):
"""Save unsaved data to db.
If save or sync is true, saves whether dirty or not.
If sync is true, removes db entries not in the map.
"""
if self.__db__ is None:
#print 'DBMap>saveDB>',self.getPath(), 'no db'
return
# Write data.
#print 'DBMap>saveDB>', self.getPath(), 'dirty=', self.__dirty__, 'data=', self.__data__
if ((self.__data__ is not None)
and (sync or save or self.__dirty__)):
self.__db__.setData(self.__data__)
self.__dirty__ = False
else:
#print 'DBMap>saveDB>', self.getPath(), 'not written'
pass
# Write children.
for (name, node) in self.items():
if not isinstance(node, DBMap): continue
node.saveDB(sync=sync, save=save)
# Remove db nodes not in children.
if sync:
for name in self.__db__.ls():
if name not in self:
self.__db__.delete(name)
def importFromDB(self, obj, fields):
"""Set fields in obj from db fields.
"""
for f in fields:
f.importFromDB(self, obj)
def exportToDB(self, obj, fields, save=False, sync=False):
"""Set fields in db from obj fields.
"""
for f in fields:
f.exportToDB(self, obj)
self.saveDB(save=save, sync=sync)
@@ -0,0 +1,136 @@
#============================================================================
# Copyright (C) 2005 Mike Wray <mike.wray@hp.com>
#============================================================================
# HTTP interface onto xenstore (read-only).
# Mainly intended for testing.
import os
import os.path
from xen.web.httpserver import HttpServer, UnixHttpServer
from xen.web.SrvBase import SrvBase
from xen.web.SrvDir import SrvDir
from xen.xend.Args import FormFn
from xen.xend.xenstore import XenNode
def pathurl(req):
url = req.prePathURL()
if not url.endswith('/'):
url += '/'
return url
def writelist(req, l):
req.write('(')
for k in l:
req.write(' ' + k)
req.write(')')
def lsData(dbnode, req, url):
v = dbnode.getData()
if v is None:
req.write('<p>No data')
else:
req.write('<p>Data: <pre>')
req.write(str(v))
req.write('</pre>')
v = dbnode.getLock()
if v is None:
req.write("<p>Unlocked")
else:
req.write("<p>Lock = %s" % v)
def lsChildren(dbnode, req, url):
l = dbnode.ls()
if l:
req.write('<p>Children: <ul>')
for key in l:
child = dbnode.getChild(key)
data = child.getData()
if data is None: data = ""
req.write('<li><a href="%(url)s%(key)s">%(key)s</a> %(data)s</li>'
% { "url": url, "key": key, "data": data })
req.write('</ul>')
else:
req.write('<p>No children')
class DBDataResource(SrvBase):
"""Resource for the node data.
"""
def __init__(self, dbnode):
SrvBase.__init__(self)
self.dbnode = dbnode
def render_GET(self, req):
req.write('<html><head></head><body>')
self.print_path(req)
req.write("<pre>")
req.write(self.getData() or self.getNoData())
req.write("</pre>")
req.write('</body></html>')
def getContentType(self):
# Use content-type from metadata.
return "text/plain"
def getData(self):
v = self.dbnode.getData()
if v is None: return v
return str(v)
def getNoData(self):
return ""
class DBNodeResource(SrvDir):
"""Resource for a DB node.
"""
def __init__(self, dbnode):
SrvDir.__init__(self)
self.dbnode = dbnode
def get(self, x):
val = None
if x == "__data__":
val = DBDataResource(self.dbnode)
else:
if self.dbnode.exists(x):
child = self.dbnode.getChild(x, create=False)
else:
child = None
if child is not None:
val = DBNodeResource(child)
return val
def render_POST(self, req):
return self.perform(req)
def ls(self, req, use_sxp=0):
if use_sxp:
writelist(req, self.dbnode.getChildren())
else:
url = pathurl(req)
req.write("<fieldset>")
lsData(self.dbnode, req, url)
lsChildren(self.dbnode, req, url)
req.write("</fieldset>")
def form(self, req):
url = req.prePathURL()
pass
class DBRootResource(DBNodeResource):
"""Resource for the root of a DB.
"""
def __init__(self):
DBNodeResource.__init__(self, XenNode())
def main(argv):
root = SrvDir()
root.putChild('xenstore', DBRootResource())
interface = ''
port = 8003
server = HttpServer(root=root, interface=interface, port=port)
server.run()
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.