This commit is contained in:
djm@kirby.fc.hp.com committed 2005-10-08 14:28:24 -06:00
commit c575162f2a
275 files changed
+5769 -37044

No files matched your search

+3
View File
@@ -15,5 +15,8 @@ install: all
CFLAGS="$(CFLAGS)" python setup.py install --root="$(DESTDIR)"
endif
test:
export LD_LIBRARY_PATH=$$(readlink -f ../libxc):$$(readlink -f ../xenstore); python test.py -b -u
clean:
rm -rf build *.pyc *.pyo *.o *.a *~
+3
View File
@@ -0,0 +1,3 @@
The file test.py here is from the Zope project, and is Copyright (c) 2001,
2002 Zope Corporation and Contributors. This file is released under the Zope
Public License, version 2.0, a copy of which is in the file ZPL-2.0.
+59
View File
@@ -0,0 +1,59 @@
Zope Public License (ZPL) Version 2.0
-----------------------------------------------
This software is Copyright (c) Zope Corporation (tm) and
Contributors. All rights reserved.
This license has been certified as open source. It has also
been designated as GPL compatible by the Free Software
Foundation (FSF).
Redistribution and use in source and binary forms, with or
without modification, are permitted provided that the
following conditions are met:
1. Redistributions in source code must retain the above
copyright notice, this list of conditions, and the following
disclaimer.
2. Redistributions in binary form must reproduce the above
copyright notice, this list of conditions, and the following
disclaimer in the documentation and/or other materials
provided with the distribution.
3. The name Zope Corporation (tm) must not be used to
endorse or promote products derived from this software
without prior written permission from Zope Corporation.
4. The right to distribute this software or to use it for
any purpose does not give you the right to use Servicemarks
(sm) or Trademarks (tm) of Zope Corporation. Use of them is
covered in a separate agreement (see
http://www.zope.com/Marks).
5. If any files are modified, you must cause the modified
files to carry prominent notices stating that you changed
the files and the date of any change.
Disclaimer
THIS SOFTWARE IS PROVIDED BY ZOPE CORPORATION ``AS IS''
AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
NO EVENT SHALL ZOPE CORPORATION OR ITS CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
This software consists of contributions made by Zope
Corporation and many individuals on behalf of Zope
Corporation. Specific attributions are listed in the
accompanying credits file.
+3 -1
View File
@@ -42,7 +42,9 @@ setup(name = 'xen',
'xen.xend.xenstore',
'xen.xm',
'xen.web',
'xen.sv'
'xen.sv',
'xen.xend.tests'
],
ext_package = "xen.lowlevel",
ext_modules = [ xc, xs ]
+1094
View File
File diff suppressed because it is too large. Load diff
+9 -125
View File
@@ -432,106 +432,21 @@ static PyObject *pyxc_evtchn_alloc_unbound(PyObject *self,
{
XcObject *xc = (XcObject *)self;
u32 dom;
int port = 0;
u32 dom, remote_dom;
int port;
static char *kwd_list[] = { "dom", "port", NULL };
static char *kwd_list[] = { "dom", "remote_dom", NULL };
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list,
&dom, &port) )
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "ii", kwd_list,
&dom, &remote_dom) )
return NULL;
if ( xc_evtchn_alloc_unbound(xc->xc_handle, dom, &port) != 0 )
if ( (port = xc_evtchn_alloc_unbound(xc->xc_handle, dom, remote_dom)) < 0 )
return PyErr_SetFromErrno(xc_error);
return PyInt_FromLong(port);
}
static PyObject *pyxc_evtchn_bind_interdomain(PyObject *self,
PyObject *args,
PyObject *kwds)
{
XcObject *xc = (XcObject *)self;
u32 dom1 = DOMID_SELF, dom2 = DOMID_SELF;
int port1 = 0, port2 = 0;
static char *kwd_list[] = { "dom1", "dom2", "port1", "port2", NULL };
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|iiii", kwd_list,
&dom1, &dom2, &port1, &port2) )
return NULL;
if ( xc_evtchn_bind_interdomain(xc->xc_handle, dom1,
dom2, &port1, &port2) != 0 )
return PyErr_SetFromErrno(xc_error);
return Py_BuildValue("{s:i,s:i}",
"port1", port1,
"port2", port2);
}
static PyObject *pyxc_evtchn_bind_virq(PyObject *self,
PyObject *args,
PyObject *kwds)
{
XcObject *xc = (XcObject *)self;
int virq, port;
static char *kwd_list[] = { "virq", NULL };
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &virq) )
return NULL;
if ( xc_evtchn_bind_virq(xc->xc_handle, virq, &port) != 0 )
return PyErr_SetFromErrno(xc_error);
return PyInt_FromLong(port);
}
static PyObject *pyxc_evtchn_close(PyObject *self,
PyObject *args,
PyObject *kwds)
{
XcObject *xc = (XcObject *)self;
u32 dom = DOMID_SELF;
int port;
static char *kwd_list[] = { "port", "dom", NULL };
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list,
&port, &dom) )
return NULL;
if ( xc_evtchn_close(xc->xc_handle, dom, port) != 0 )
return PyErr_SetFromErrno(xc_error);
Py_INCREF(zero);
return zero;
}
static PyObject *pyxc_evtchn_send(PyObject *self,
PyObject *args,
PyObject *kwds)
{
XcObject *xc = (XcObject *)self;
int port;
static char *kwd_list[] = { "port", NULL };
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &port) )
return NULL;
if ( xc_evtchn_send(xc->xc_handle, port) != 0 )
return PyErr_SetFromErrno(xc_error);
Py_INCREF(zero);
return zero;
}
static PyObject *pyxc_evtchn_status(PyObject *self,
PyObject *args,
PyObject *kwds)
@@ -1028,42 +943,11 @@ static PyMethodDef pyxc_methods[] = {
{ "evtchn_alloc_unbound",
(PyCFunction)pyxc_evtchn_alloc_unbound,
METH_VARARGS | METH_KEYWORDS, "\n"
"Allocate an unbound local port that will await a remote connection.\n"
" dom [int]: Remote domain to accept connections from.\n\n"
"Allocate an unbound port that will await a remote connection.\n"
" dom [int]: Domain whose port space to allocate from.\n"
" remote_dom [int]: Remote domain to accept connections from.\n\n"
"Returns: [int] Unbound event-channel port.\n" },
{ "evtchn_bind_interdomain",
(PyCFunction)pyxc_evtchn_bind_interdomain,
METH_VARARGS | METH_KEYWORDS, "\n"
"Open an event channel between two domains.\n"
" dom1 [int, SELF]: First domain to be connected.\n"
" dom2 [int, SELF]: Second domain to be connected.\n\n"
"Returns: [dict] dictionary is empty on failure.\n"
" port1 [int]: Port-id for endpoint at dom1.\n"
" port2 [int]: Port-id for endpoint at dom2.\n" },
{ "evtchn_bind_virq",
(PyCFunction)pyxc_evtchn_bind_virq,
METH_VARARGS | METH_KEYWORDS, "\n"
"Bind an event channel to the specified VIRQ.\n"
" virq [int]: VIRQ to bind.\n\n"
"Returns: [int] Bound event-channel port.\n" },
{ "evtchn_close",
(PyCFunction)pyxc_evtchn_close,
METH_VARARGS | METH_KEYWORDS, "\n"
"Close an event channel. If interdomain, sets remote end to 'unbound'.\n"
" dom [int, SELF]: Dom-id of one endpoint of the channel.\n"
" port [int]: Port-id of one endpoint of the channel.\n\n"
"Returns: [int] 0 on success; -1 on error.\n" },
{ "evtchn_send",
(PyCFunction)pyxc_evtchn_send,
METH_VARARGS | METH_KEYWORDS, "\n"
"Send an event along a locally-connected event channel.\n"
" port [int]: Port-id of a local channel endpoint.\n\n"
"Returns: [int] 0 on success; -1 on error.\n" },
{ "evtchn_status",
(PyCFunction)pyxc_evtchn_status,
METH_VARARGS | METH_KEYWORDS, "\n"
+4 -60
View File
@@ -462,19 +462,20 @@ static PyObject *xspy_read_watch(PyObject *self, PyObject *args,
char **xsval = NULL;
PyObject *token;
int i;
unsigned int num;
if (!xh)
goto exit;
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec))
goto exit;
Py_BEGIN_ALLOW_THREADS
xsval = xs_read_watch(xh);
xsval = xs_read_watch(xh, &num);
Py_END_ALLOW_THREADS
if (!xsval) {
PyErr_SetFromErrno(PyExc_RuntimeError);
goto exit;
}
if (sscanf(xsval[1], "%li", (unsigned long *)&token) != 1) {
if (sscanf(xsval[XS_WATCH_TOKEN], "%li", (unsigned long *)&token) != 1) {
PyErr_SetString(PyExc_RuntimeError, "invalid token");
goto exit;
}
@@ -487,7 +488,7 @@ static PyObject *xspy_read_watch(PyObject *self, PyObject *args,
goto exit;
}
/* Create tuple (path, token). */
val = Py_BuildValue("(sO)", xsval[0], token);
val = Py_BuildValue("(sO)", xsval[XS_WATCH_PATH], token);
exit:
if (xsval)
free(xsval);
@@ -774,39 +775,6 @@ static PyObject *xspy_close(PyObject *self, PyObject *args, PyObject *kwds)
return val;
}
#define xspy_shutdown_doc "\n" \
"Shutdown the xenstore daemon.\n" \
"\n" \
"Returns None on success.\n" \
"Raises RuntimeError on error.\n" \
"\n"
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;
Py_BEGIN_ALLOW_THREADS
xsval = xs_shutdown(xh);
Py_END_ALLOW_THREADS
if (!xsval) {
PyErr_SetFromErrno(PyExc_RuntimeError);
goto exit;
}
Py_INCREF(Py_None);
val = Py_None;
exit:
return val;
}
#define xspy_get_domain_path_doc "\n" \
"Return store path of domain.\n" \
" domid [int]: domain id\n" \
@@ -849,28 +817,6 @@ static PyObject *xspy_get_domain_path(PyObject *self, PyObject *args,
return val;
}
#define xspy_fileno_doc "\n" \
"Get the file descriptor of the xenstore socket.\n" \
"Allows an xs object to be passed to select().\n" \
"\n" \
"Returns: [int] file descriptor.\n" \
"\n"
static PyObject *xspy_fileno(PyObject *self, PyObject *args, PyObject *kwds)
{
static char *kwd_spec[] = { NULL };
static char *arg_spec = "";
struct xs_handle *xh = xshandle(self);
PyObject *val = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec))
goto exit;
val = PyInt_FromLong((xh ? xs_fileno(xh) : -1));
exit:
return val;
}
#define XSPY_METH(_name) { \
.ml_name = #_name, \
.ml_meth = (PyCFunction) xspy_ ## _name, \
@@ -894,9 +840,7 @@ static PyMethodDef xshandle_methods[] = {
XSPY_METH(introduce_domain),
XSPY_METH(release_domain),
XSPY_METH(close),
XSPY_METH(shutdown),
XSPY_METH(get_domain_path),
XSPY_METH(fileno),
{ /* Terminator. */ },
};
+2 -2
View File
@@ -139,7 +139,7 @@ class DomActionTab( ActionTab ):
if not dom is None and dom != '0':
if DEBUG: print ">DomShutDown %s" % dom
try:
server.xend_domain_shutdown( int( dom ), "halt" )
server.xend_domain_shutdown( int( dom ), "poweroff" )
except:
pass
@@ -175,7 +175,7 @@ class DomActionTab( ActionTab ):
if not dom is None and dom != '0':
if DEBUG: print ">DomDestroy %s" % dom
try:
server.xend_domain_destroy( int( dom ), "halt" )
server.xend_domain_destroy(int( dom ))
except:
pass
+3
View File
@@ -437,6 +437,9 @@ class HttpRequest:
send_body = self.hasBody()
if not self.close_connection:
self.setResponseHeader("Connection", "keep-alive")
self.setResponseHeader("Pragma", "no-cache")
self.setResponseHeader("Cache-Control", "no-cache")
self.setResponseHeader("Expires", "-1")
if send_body:
self.output.seek(0, 0)
body = self.output.getvalue()
-19
View File
@@ -1,19 +0,0 @@
#============================================================================
# This library is free software; you can redistribute it and/or
# modify it under the terms of version 2.1 of the GNU Lesser General Public
# License as published by the Free Software Foundation.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#============================================================================
# Copyright (C) 2005 Mike Wray <mike.wray@hp.com>
#============================================================================
from unix import listenUNIX, connectUNIX
from tcp import listenTCP, connectTCP, SetCloExec
-265
View File
@@ -1,265 +0,0 @@
#============================================================================
# This library is free software; you can redistribute it and/or
# modify it under the terms of version 2.1 of the GNU Lesser General Public
# License as published by the Free Software Foundation.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#============================================================================
# Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
#============================================================================
"""Simple publish/subscribe event server.
"""
import string
from threading import Lock
import scheduler
# subscribe a.b.c h: map a.b.c -> h
# subscribe a.b.* h: map a.b.* -> h
# subscribe a.b.? h: map a.b.? -> h
#
# for event a.b.c.d:
#
# lookup a.b.c.d, call handlers
#
# lookup a.b.c.?, call handlers
#
# lookup a.b.c.d.*, call handlers
# lookup a.b.c.*, call handlers
# lookup a.b.*, call handlers
# lookup a.*, call handlers
# lookup *, call handlers
# a.b.c.d = (a b c d)
# a.b.c.? = (a b c _)
# a.b.c.* = (a b c . _)
class EventServer:
DOT = '.'
QUERY = '?'
DOT_QUERY = DOT + QUERY
STAR = '*'
DOT_STAR = DOT + STAR
def __init__(self, run=0):
self.handlers = {}
self.run = run
self.queue = []
self.lock = Lock()
def start(self):
"""Enable event handling. Sends any queued events.
"""
try:
self.lock.acquire()
self.run = 1
queue = self.queue
self.queue = []
finally:
self.lock.release()
for (e,v) in queue:
self.inject(e, v)
def stop(self):
"""Suspend event handling. Events injected while suspended
are queued until we are started again.
"""
try:
self.lock.acquire()
self.run = 0
finally:
self.lock.release()
def subscribe(self, event, handler):
"""Subscribe to an event. For example 'a.b.c.d'.
A subcription like 'a.b.c.?' ending in '?' matches any value
for the '?'. A subscription like 'a.b.c.*' ending in '*' matches
any event type with the same prefix, 'a.b.c' in this case.
event event name
handler event handler fn(event, val)
"""
try:
self.lock.acquire()
hl = self.handlers.get(event)
if hl is None:
self.handlers[event] = [handler]
else:
hl.append(handler)
finally:
self.lock.release()
def unsubscribe_all(self, event=None):
"""Unsubscribe all handlers for a given event, or all handlers.
event event (optional)
"""
try:
self.lock.acquire()
if event == None:
self.handlers.clear()
elif event in self.handlers:
del self.handlers[event]
finally:
self.lock.release()
def unsubscribe(self, event, handler):
"""Unsubscribe a given event and handler.
event event
handler handler
"""
try:
self.lock.acquire()
hl = self.handlers.get(event)
if hl is None:
return
if handler in hl:
hl.remove(handler)
finally:
self.lock.release()
def inject(self, event, val, async=1):
"""Inject an event. Handlers for it are called if running, otherwise
it is queued.
event event type
val event value
"""
try:
self.lock.acquire()
if not self.run:
self.queue.append( (event, val) )
return
finally:
self.lock.release()
if async:
scheduler.now(self.call_handlers, event, val)
else:
self.call_handlers(event, val)
def call_handlers(self, event, val):
"""Internal method to call event handlers.
"""
#print ">event", event, val
self.call_event_handlers(event, event, val)
self.call_query_handlers(event, val)
self.call_star_handlers(event, val)
def call_event_handlers(self, key, event, val):
"""Call the handlers for an event.
It is safe for handlers to subscribe or unsubscribe.
key key for handler list
event event type
val event value
"""
try:
self.lock.acquire()
hl = self.handlers.get(key)
if hl is None:
return
# Copy the handler list so that handlers can call
# subscribe/unsubscribe safely - python list iteration
# is not safe against list modification.
hl = hl[:]
finally:
self.lock.release()
# Must not hold the lock while calling the handlers.
for h in hl:
try:
h(event, val)
except:
pass
def call_query_handlers(self, event, val):
"""Call regex handlers for events matching 'event' that end in '?'.
event event type
val event value
"""
dot_idx = event.rfind(self.DOT)
if dot_idx == -1:
self.call_event_handlers(self.QUERY, event, val)
else:
event_query = event[0:dot_idx] + self.DOT_QUERY
self.call_event_handlers(event_query, event, val)
def call_star_handlers(self, event, val):
"""Call regex handlers for events matching 'event' that end in '*'.
event event type
val event value
"""
etype = string.split(event, self.DOT)
for i in range(len(etype), 0, -1):
event_star = self.DOT.join(etype[0:i]) + self.DOT_STAR
self.call_event_handlers(event_star, event, val)
self.call_event_handlers(self.STAR, event, val)
def instance():
global inst
try:
inst
except:
inst = EventServer()
inst.start()
return inst
def main():
def sys_star(event, val):
print 'sys_star', event, val
def sys_foo(event, val):
print 'sys_foo', event, val
s.unsubscribe('sys.foo', sys_foo)
def sys_foo2(event, val):
print 'sys_foo2', event, val
def sys_bar(event, val):
print 'sys_bar', event, val
def sys_foo_bar(event, val):
print 'sys_foo_bar', event, val
def foo_bar(event, val):
print 'foo_bar', event, val
s = EventServer()
s.start()
s.subscribe('sys.*', sys_star)
s.subscribe('sys.foo', sys_foo)
s.subscribe('sys.foo', sys_foo2)
s.subscribe('sys.bar', sys_bar)
s.subscribe('sys.foo.bar', sys_foo_bar)
s.subscribe('foo.bar', foo_bar)
s.inject('sys.foo', 'hello')
print
s.inject('sys.bar', 'hello again')
print
s.inject('sys.foo.bar', 'hello again')
print
s.inject('foo.bar', 'hello again')
print
s.inject('foo', 'hello again')
print
s.start()
s.unsubscribe('sys.*', sys_star)
s.unsubscribe_all('sys.*')
s.inject('sys.foo', 'hello')
if __name__ == "__main__":
main()
+131 -106
View File
@@ -1,4 +1,5 @@
# Copyright (C) 2005 Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
# Copyright (C) 2005 XenSource Ltd
# This file is subject to the terms and conditions of the GNU General
# Public License. See the file "COPYING" in the main directory of
@@ -7,15 +8,14 @@
import os
import re
import select
import string
import sxp
from string import join
from struct import pack, unpack, calcsize
from xen.util.xpopen import xPopen3
import xen.lowlevel.xc
import XendDomainInfo
from xen.xend.xenstore.xsutil import IntroduceDomain
from XendError import XendError
@@ -42,57 +42,55 @@ def read_exact(fd, size, errmsg):
raise XendError(errmsg)
return buf
def save(xd, fd, dominfo, live):
def save(fd, dominfo, live):
write_exact(fd, SIGNATURE, "could not write guest state file: signature")
config = sxp.to_string(dominfo.sxpr())
write_exact(fd, pack("!i", len(config)),
"could not write guest state file: config len")
write_exact(fd, config, "could not write guest state file: config")
# xc_save takes three customization parameters: maxit, max_f, and flags
# the last controls whether or not save is 'live', while the first two
# further customize behaviour when 'live' save is enabled. Passing "0"
# simply uses the defaults compiled into libxenguest; see the comments
# and/or code in xc_linux_save() for more information.
cmd = [PATH_XC_SAVE, str(xc.handle()), str(fd),
str(dominfo.domid), "0", "0", str(int(live)) ]
log.info("[xc_save] " + join(cmd))
child = xPopen3(cmd, True, -1, [fd, xc.handle()])
lasterr = ""
p = select.poll()
p.register(child.fromchild.fileno())
p.register(child.childerr.fileno())
while True:
r = p.poll()
for (fd, event) in r:
if not event & select.POLLIN:
continue
if fd == child.childerr.fileno():
l = child.childerr.readline()
log.error(l.rstrip())
lasterr = l.rstrip()
if fd == child.fromchild.fileno():
l = child.fromchild.readline()
if l.rstrip() == "suspend":
log.info("suspending %d" % dominfo.domid)
xd.domain_shutdown(dominfo.domid, reason='suspend')
dominfo.state_wait(XendDomainInfo.STATE_VM_SUSPENDED)
log.info("suspend %d done" % dominfo.domid)
child.tochild.write("done\n")
child.tochild.flush()
if filter(lambda (fd, event): event & select.POLLHUP, r):
break
domain_name = dominfo.getName()
# Rename the domain temporarily, so that we don't get a name clash if this
# domain is migrating (live or non-live) to the local host. Doing such a
# thing is useful for debugging.
dominfo.setName('migrating-' + domain_name)
if child.wait() >> 8 == 127:
lasterr = "popen %s failed" % PATH_XC_SAVE
if child.wait() != 0:
raise XendError("xc_save failed: %s" % lasterr)
try:
write_exact(fd, pack("!i", len(config)),
"could not write guest state file: config len")
write_exact(fd, config, "could not write guest state file: config")
# xc_save takes three customization parameters: maxit, max_f, and
# flags the last controls whether or not save is 'live', while the
# first two further customize behaviour when 'live' save is
# enabled. Passing "0" simply uses the defaults compiled into
# libxenguest; see the comments and/or code in xc_linux_save() for
# more information.
cmd = [PATH_XC_SAVE, str(xc.handle()), str(fd),
str(dominfo.getDomid()), "0", "0", str(int(live)) ]
log.debug("[xc_save]: %s", string.join(cmd))
def saveInputHandler(line, tochild):
log.debug("In saveInputHandler %s", line)
if line == "suspend":
log.debug("Suspending %d ...", dominfo.getDomid())
dominfo.shutdown('suspend')
dominfo.waitForShutdown()
log.info("Domain %d suspended.", dominfo.getDomid())
tochild.write("done\n")
tochild.flush()
forkHelper(cmd, fd, saveInputHandler, False)
dominfo.destroyDomain()
except Exception, exn:
log.exception("Save failed on domain %s (%d).", domain_name,
dominfo.getDomid())
try:
dominfo.setName(domain_name)
except:
log.exception("Failed to reset the migrating domain's name")
raise Exception, exn
dominfo.closeStoreChannel()
xd.domain_destroy(dominfo.domid)
return None
def restore(xd, fd):
signature = read_exact(fd, len(SIGNATURE),
@@ -113,71 +111,98 @@ def restore(xd, fd):
raise XendError("not a valid guest state file: config parse")
vmconfig = p.get_val()
dominfo = xd.domain_configure(vmconfig)
l = read_exact(fd, sizeof_unsigned_long,
"not a valid guest state file: pfn count read")
nr_pfns = unpack("=L", l)[0] # XXX endianess
if nr_pfns > 1024*1024: # XXX
raise XendError(
"not a valid guest state file: pfn count out of range")
dominfo = xd.restore_(vmconfig)
if dominfo.store_channel:
store_evtchn = dominfo.store_channel.port2
else:
store_evtchn = 0
assert dominfo.store_channel
assert dominfo.console_channel
assert dominfo.getDomainPath()
if dominfo.console_channel:
console_evtchn = dominfo.console_channel.port2
else:
console_evtchn = 0
try:
l = read_exact(fd, sizeof_unsigned_long,
"not a valid guest state file: pfn count read")
nr_pfns = unpack("=L", l)[0] # XXX endianess
if nr_pfns > 1024*1024: # XXX
raise XendError(
"not a valid guest state file: pfn count out of range")
cmd = [PATH_XC_RESTORE, str(xc.handle()), str(fd),
str(dominfo.domid), str(nr_pfns),
str(store_evtchn), str(console_evtchn)]
log.info("[xc_restore] " + join(cmd))
store_evtchn = dominfo.store_channel
console_evtchn = dominfo.console_channel
cmd = [PATH_XC_RESTORE, str(xc.handle()), str(fd),
str(dominfo.getDomid()), str(nr_pfns),
str(store_evtchn), str(console_evtchn)]
log.debug("[xc_restore]: %s", string.join(cmd))
def restoreInputHandler(line, _):
m = re.match(r"^(store-mfn) (\d+)$", line)
if m:
store_mfn = int(m.group(2))
dominfo.setStoreRef(store_mfn)
log.debug("IntroduceDomain %d %d %d %s",
dominfo.getDomid(),
store_mfn,
dominfo.store_channel,
dominfo.getDomainPath())
IntroduceDomain(dominfo.getDomid(),
store_mfn,
dominfo.store_channel,
dominfo.getDomainPath())
else:
m = re.match(r"^(console-mfn) (\d+)$", line)
if m:
dominfo.setConsoleRef(int(m.group(2)))
forkHelper(cmd, fd, restoreInputHandler, True)
return dominfo
except:
dominfo.destroy()
raise
def forkHelper(cmd, fd, inputHandler, closeToChild):
child = xPopen3(cmd, True, -1, [fd, xc.handle()])
child.tochild.close()
lasterr = ""
p = select.poll()
p.register(child.fromchild.fileno())
p.register(child.childerr.fileno())
while True:
r = p.poll()
for (fd, event) in r:
if not event & select.POLLIN:
continue
if fd == child.childerr.fileno():
l = child.childerr.readline()
log.error(l.rstrip())
lasterr = l.rstrip()
if fd == child.fromchild.fileno():
l = child.fromchild.readline()
while l:
log.info(l.rstrip())
m = re.match(r"^(store-mfn) (\d+)\n$", l)
if m:
if dominfo.store_channel:
dominfo.setStoreRef(int(m.group(2)))
if dominfo.store_mfn >= 0:
IntroduceDomain(dominfo.domid,
dominfo.store_mfn,
dominfo.store_channel.port1,
dominfo.path)
m = re.match(r"^(console-mfn) (\d+)\n$", l)
if m:
dominfo.setConsoleRef(int(m.group(2)))
try:
l = child.fromchild.readline()
except:
l = None
if filter(lambda (fd, event): event & select.POLLHUP, r):
break
if closeToChild:
child.tochild.close()
try:
fds = [child.fromchild.fileno(),
child.childerr.fileno()]
p = select.poll()
map(p.register, fds)
while len(fds) > 0:
r = p.poll()
for (fd, event) in r:
if event & select.POLLIN:
if fd == child.childerr.fileno():
lasterr = child.childerr.readline().rstrip()
log.error('%s', lasterr)
else:
l = child.fromchild.readline().rstrip()
while l:
log.debug('%s', l)
inputHandler(l, child.tochild)
try:
l = child.fromchild.readline().rstrip()
except:
l = None
if event & select.POLLERR:
raise XendError('Error reading from child process for %s',
cmd)
if event & select.POLLHUP:
fds.remove(fd)
p.unregister(fd)
finally:
child.fromchild.close()
child.childerr.close()
if not closeToChild:
child.tochild.close()
if child.wait() >> 8 == 127:
lasterr = "popen %s failed" % PATH_XC_RESTORE
lasterr = "popen failed"
if child.wait() != 0:
raise XendError("xc_restore failed: %s" % lasterr)
return dominfo
raise XendError("%s failed: %s" % (string.join(cmd), lasterr))
+8 -9
View File
@@ -232,10 +232,9 @@ class Xend:
{'op' : 'sysrq',
'key' : key})
def xend_domain_destroy(self, id, reason):
def xend_domain_destroy(self, id):
return self.xendPost(self.domainurl(id),
{'op' : 'destroy',
'reason' : reason })
{'op' : 'destroy' })
def xend_domain_save(self, id, filename):
return self.xendPost(self.domainurl(id),
@@ -307,22 +306,22 @@ class Xend:
{'op' : 'device_create',
'config' : fileof(config) })
def xend_domain_device_refresh(self, id, type, idx):
def xend_domain_device_refresh(self, id, type, dev):
return self.xendPost(self.domainurl(id),
{'op' : 'device_refresh',
'type' : type,
'idx' : idx })
'dev' : dev })
def xend_domain_device_destroy(self, id, type, idx):
def xend_domain_device_destroy(self, id, type, dev):
return self.xendPost(self.domainurl(id),
{'op' : 'device_destroy',
'type' : type,
'idx' : idx })
'dev' : dev })
def xend_domain_device_configure(self, id, config, idx):
def xend_domain_device_configure(self, id, config, dev):
return self.xendPost(self.domainurl(id),
{'op' : 'device_configure',
'idx' : idx,
'dev' : dev,
'config' : fileof(config) })
def xend_vnets(self):
+257 -224
View File
@@ -22,14 +22,15 @@
Needs to be persistent for one uptime.
"""
import os
import logging
import threading
import xen.lowlevel.xc
from xen.xend import sxp
import XendDomainInfo
from xen.xend import XendRoot
from xen.xend import XendCheckpoint
from xen.xend.XendDomainInfo import XendDomainInfo
from xen.xend import EventServer
from xen.xend.XendError import XendError
from xen.xend.XendLogging import log
from xen.xend.server import relocate
@@ -37,26 +38,17 @@ from xen.xend.server import relocate
xc = xen.lowlevel.xc.new()
xroot = XendRoot.instance()
eserver = EventServer.instance()
__all__ = [ "XendDomain" ]
PRIV_DOMAIN = 0
class XendDomainDict(dict):
def get_by_name(self, name):
try:
return filter(lambda d: d.getName() == name, self.values())[0]
except IndexError, err:
return None
class XendDomain:
"""Index of all domains. Singleton.
"""
"""Dict of domain info indexed by domain id."""
domains = None
## public:
def __init__(self):
# Hack alert. Python does not support mutual imports, but XendDomainInfo
@@ -64,18 +56,30 @@ 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)
self.domains = XendDomainDict()
self.domains = {}
self.domains_lock = threading.Condition()
self.watchReleaseDomain()
self.refresh()
self.dom0_setup()
self.domains_lock.acquire()
try:
self.refresh(True)
self.dom0_setup()
finally:
self.domains_lock.release()
def list(self):
"""Get list of domain objects.
@return: domain objects
"""
self.refresh()
return self.domains.values()
self.domains_lock.acquire()
try:
self.refresh()
return self.domains.values()
finally:
self.domains_lock.release()
def list_sorted(self):
"""Get list of domain objects, sorted by name.
@@ -94,15 +98,25 @@ class XendDomain:
doms = self.list_sorted()
return map(lambda x: x.getName(), doms)
## private:
def onReleaseDomain(self):
self.refresh()
self.domains_lock.acquire()
try:
self.refresh()
finally:
self.domains_lock.release()
def watchReleaseDomain(self):
from xen.xend.xenstore.xswatch import xswatch
self.releaseDomain = xswatch("@releaseDomain", self.onReleaseDomain)
def xen_domains(self):
"""Get table of domains indexed by id from xc.
"""Get table of domains indexed by id from xc. Expects to be
protected by the domains_lock.
"""
domlist = xc.domain_getinfo()
doms = {}
@@ -111,68 +125,37 @@ class XendDomain:
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)
"""
dominfo = xc.domain_getinfo(dom, 1)
if dominfo == [] or dominfo[0]['dom'] != dom:
dominfo = None
else:
dominfo = dominfo[0]
return dominfo
def recreate_domain(self, xeninfo):
"""Refresh initial domain info from db."""
dominfo = XendDomainInfo.recreate(xeninfo)
self._add_domain(dominfo)
return dominfo
def dom0_setup(self):
dom0 = self.domain_lookup(PRIV_DOMAIN)
if not dom0:
dom0 = self.recreate_domain(self.xen_domain(PRIV_DOMAIN))
dom0.dom0_init_store()
"""Expects to be protected by the domains_lock."""
dom0 = self.domains[PRIV_DOMAIN]
dom0.dom0_enforce_vcpus()
def _add_domain(self, info, notify=True):
"""Add a domain entry to the tables.
@param info: domain info object
@param notify: send a domain created event if true
def _add_domain(self, info):
"""Add the given domain entry to this instance's internal cache.
Expects to be protected by the domains_lock.
"""
if info.getDomid() in self.domains:
notify = False
self.domains[info.getDomid()] = info
info.exportToDB()
if notify:
eserver.inject('xend.domain.create', [info.getName(),
info.getDomid()])
def _delete_domain(self, domid, notify=True):
"""Remove a domain from the tables.
@param id: domain id
@param notify: send a domain died event if true
def _delete_domain(self, domid):
"""Remove the given domain from this instance's internal cache.
Expects to be protected by the domains_lock.
"""
info = self.domains.get(domid)
if info:
del self.domains[domid]
info.cleanup()
info.delete()
if notify:
eserver.inject('xend.domain.died', [info.getName(),
info.getDomid()])
info.cleanupDomain()
def refresh(self):
"""Refresh domain list from Xen.
def refresh(self, initialising = False):
"""Refresh domain list from Xen. Expects to be protected by the
domains_lock.
@param initialising True if this is the first refresh after starting
Xend. This does not change this method's behaviour, except for
logging.
"""
doms = self.xen_domains()
for d in self.domains.values():
@@ -183,30 +166,33 @@ class XendDomain:
self._delete_domain(d.getDomid())
for d in doms:
if d not in self.domains:
try:
self.recreate_domain(doms[d])
except:
log.exception(
"Failed to recreate information for domain %d. "
"Destroying it in the hope of recovery.", d)
if doms[d]['dying']:
log.log(initialising and logging.ERROR or logging.DEBUG,
'Cannot recreate information for dying domain %d.'
' Xend will ignore this domain from now on.',
doms[d]['dom'])
else:
try:
xc.domain_destroy(dom = d)
dominfo = XendDomainInfo.recreate(doms[d])
self._add_domain(dominfo)
except:
log.exception('Destruction of %d failed.', d)
if d == PRIV_DOMAIN:
log.exception(
"Failed to recreate information for domain "
"%d. Doing nothing except crossing my "
"fingers.", d)
else:
log.exception(
"Failed to recreate information for domain "
"%d. Destroying it in the hope of "
"recovery.", d)
try:
xc.domain_destroy(dom = d)
except:
log.exception('Destruction of %d failed.', d)
def update_domain(self, id):
"""Update information for a single domain.
@param id: domain id
"""
dominfo = self.xen_domain(id)
if dominfo:
d = self.domains.get(id)
if d:
d.update(dominfo)
else:
self._delete_domain(id)
## public:
def domain_create(self, config):
"""Create a domain from a configuration.
@@ -214,24 +200,22 @@ class XendDomain:
@param config: configuration
@return: domain
"""
dominfo = XendDomainInfo.create(config)
self._add_domain(dominfo)
return dominfo
self.domains_lock.acquire()
try:
dominfo = XendDomainInfo.create(config)
self._add_domain(dominfo)
return dominfo
finally:
self.domains_lock.release()
def domain_configure(self, config):
"""Configure an existing domain. This is intended for internal
use by domain restore and migrate.
"""Configure an existing domain.
@param vmconfig: vm configuration
"""
# We accept our configuration specified as ['config' [...]], which
# some tools or configuration files may be using. For save-restore,
# we use the value of XendDomainInfo.sxpr() directly, which has no
# such item.
nested = sxp.child_value(config, 'config')
if nested:
config = nested
return XendDomainInfo.restore(config)
# !!!
raise XendError("Unsupported")
def domain_restore(self, src):
"""Restore a domain from file.
@@ -241,89 +225,156 @@ class XendDomain:
try:
fd = os.open(src, os.O_RDONLY)
dominfo = XendCheckpoint.restore(self, fd)
self._add_domain(dominfo)
return dominfo
try:
return self.domain_restore_fd(fd)
finally:
os.close(fd)
except OSError, ex:
raise XendError("can't read guest state file %s: %s" %
(src, ex[1]))
def domain_get(self, id):
"""Get up-to-date info about a domain.
def domain_restore_fd(self, fd):
"""Restore a domain from the given file descriptor."""
@param id: domain id
@return: domain object (or None)
"""
self.update_domain(id)
return self.domains.get(id)
def domain_lookup(self, id):
return self.domains.get(id)
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.
@param id: domain id
"""
dominfo = self.domain_lookup(id)
eserver.inject('xend.domain.unpause', [dominfo.getName(),
dominfo.getDomid()])
try:
return XendCheckpoint.restore(self, fd)
except:
# I don't really want to log this exception here, but the error
# handling in the relocation-socket handling code (relocate.py) is
# poor, so we need to log this for debugging.
log.exception("Restore failed")
raise
def restore_(self, config):
"""Create a domain as part of the restore process. This is called
only from {@link XendCheckpoint}.
A restore request comes into XendDomain through {@link
#domain_restore} or {@link #domain_restore_fd}. That request is
forwarded immediately to XendCheckpoint which, when it is ready, will
call this method. It is necessary to come through here rather than go
directly to {@link XendDomainInfo.restore} because we need to
serialise the domain creation process, but cannot lock
domain_restore_fd as a whole, otherwise we will deadlock waiting for
the old domain to die.
"""
self.domains_lock.acquire()
try:
dominfo = XendDomainInfo.restore(config)
self._add_domain(dominfo)
return dominfo
finally:
self.domains_lock.release()
def domain_lookup(self, domid):
self.domains_lock.acquire()
try:
self.refresh()
return self.domains.get(domid)
finally:
self.domains_lock.release()
def domain_lookup_nr(self, domid):
self.domains_lock.acquire()
try:
return self.domains.get(domid)
finally:
self.domains_lock.release()
def domain_lookup_by_name_or_id(self, name):
self.domains_lock.acquire()
try:
self.refresh()
return self.domain_lookup_by_name_or_id_nr(name)
finally:
self.domains_lock.release()
def domain_lookup_by_name_or_id_nr(self, name):
self.domains_lock.acquire()
try:
dominfo = self.domain_lookup_by_name_nr(name)
if dominfo:
return dominfo
else:
try:
return self.domains.get(int(name))
except ValueError:
return None
finally:
self.domains_lock.release()
def domain_lookup_by_name_nr(self, name):
self.domains_lock.acquire()
try:
matching = filter(lambda d: d.getName() == name,
self.domains.values())
n = len(matching)
if n == 1:
return matching[0]
elif n > 1:
log.error('Name uniqueness has been violated for name %s! '
'Recovering by renaming:', name)
for d in matching:
d.renameUniquely()
return None
finally:
self.domains_lock.release()
def privilegedDomain(self):
self.domains_lock.acquire()
try:
return self.domains[PRIV_DOMAIN]
finally:
self.domains_lock.release()
def domain_unpause(self, domid):
"""Unpause domain execution."""
try:
dominfo = self.domain_lookup(domid)
log.info("Domain %s (%d) unpaused.", dominfo.getName(),
dominfo.getDomid())
return xc.domain_unpause(dom=dominfo.getDomid())
except Exception, ex:
raise XendError(str(ex))
def domain_pause(self, id):
"""Pause domain execution.
@param id: domain id
"""
dominfo = self.domain_lookup(id)
eserver.inject('xend.domain.pause', [dominfo.getName(),
dominfo.getDomid()])
def domain_pause(self, domid):
"""Pause domain execution."""
try:
dominfo = self.domain_lookup(domid)
log.info("Domain %s (%d) paused.", dominfo.getName(),
dominfo.getDomid())
return xc.domain_pause(dom=dominfo.getDomid())
except Exception, ex:
raise XendError(str(ex))
def domain_shutdown(self, domid, reason='poweroff'):
def domain_shutdown(self, domid, reason = 'poweroff'):
"""Shutdown domain (nicely).
- poweroff: restart according to exit code and restart mode
- reboot: restart on exit
- halt: do not restart
Returns immediately.
@param id: domain id
@param reason: shutdown type: poweroff, reboot, suspend, halt
@param reason: shutdown reason: poweroff, reboot, suspend, halt
"""
self.callInfo(domid, XendDomainInfo.shutdown, reason)
self.callInfo(domid, XendDomainInfo.XendDomainInfo.shutdown, reason)
def domain_sysrq(self, domid, key):
"""Send a SysRq to the specified domain."""
return self.callInfo(domid, XendDomainInfo.send_sysrq, key)
return self.callInfo(domid, XendDomainInfo.XendDomainInfo.send_sysrq,
key)
def domain_destroy(self, domid, reason='halt'):
"""Terminate domain immediately.
- halt: cancel any restart for the domain
- reboot schedule a restart for the domain
@param domid: domain id
"""
def domain_destroy(self, domid):
"""Terminate domain immediately."""
if domid == PRIV_DOMAIN:
raise XendError("Cannot destroy privileged domain %i" % domid)
@@ -338,68 +389,52 @@ class XendDomain:
raise XendError(str(ex))
return val
def domain_migrate(self, id, dst, live=False, resource=0):
"""Start domain migration.
def domain_migrate(self, domid, dst, live=False, resource=0):
"""Start domain migration."""
@param id: domain id
"""
# Need a cancel too?
# Don't forget to cancel restart for it.
dominfo = self.domain_lookup(id)
dominfo = self.domain_lookup(domid)
port = xroot.get_xend_relocation_port()
sock = relocate.setupRelocation(dst, port)
# temporarily rename domain for localhost migration
if dst == "localhost":
dominfo.setName("tmp-" + dominfo.getName())
try:
XendCheckpoint.save(self, sock.fileno(), dominfo, live)
except:
if dst == "localhost":
dominfo.setName(
string.replace(dominfo.getName(), "tmp-", "", 1))
raise
XendCheckpoint.save(sock.fileno(), dominfo, live)
return None
def domain_save(self, id, dst):
def domain_save(self, domid, dst):
"""Start saving a domain to file.
@param id: domain id
@param dst: destination file
"""
try:
dominfo = self.domain_lookup(id)
dominfo = self.domain_lookup(domid)
fd = os.open(dst, os.O_WRONLY | os.O_CREAT | os.O_TRUNC)
# For now we don't support 'live checkpoint'
return XendCheckpoint.save(self, fd, dominfo, False)
try:
# For now we don't support 'live checkpoint'
return XendCheckpoint.save(fd, dominfo, False)
finally:
os.close(fd)
except OSError, ex:
raise XendError("can't write guest state file %s: %s" %
(dst, ex[1]))
def domain_pincpu(self, id, vcpu, cpumap):
def domain_pincpu(self, domid, vcpu, cpumap):
"""Set which cpus vcpu can use
@param id: domain
@param vcpu: vcpu number
@param cpumap: bitmap of usbale cpus
@param cpumap: bitmap of usable cpus
"""
dominfo = self.domain_lookup(id)
dominfo = self.domain_lookup(domid)
try:
return xc.domain_pincpu(dominfo.getDomid(), vcpu, cpumap)
except Exception, ex:
raise XendError(str(ex))
def domain_cpu_bvt_set(self, id, mcuadv, warpback, warpvalue, warpl, warpu):
def domain_cpu_bvt_set(self, domid, mcuadv, warpback, warpvalue, warpl,
warpu):
"""Set BVT (Borrowed Virtual Time) scheduler parameters for a domain.
"""
dominfo = self.domain_lookup(id)
dominfo = self.domain_lookup(domid)
try:
return xc.bvtsched_domain_set(dom=dominfo.getDomid(),
mcuadv=mcuadv,
@@ -409,30 +444,31 @@ class XendDomain:
except Exception, ex:
raise XendError(str(ex))
def domain_cpu_bvt_get(self, id):
def domain_cpu_bvt_get(self, domid):
"""Get BVT (Borrowed Virtual Time) scheduler parameters for a domain.
"""
dominfo = self.domain_lookup(id)
dominfo = self.domain_lookup(domid)
try:
return xc.bvtsched_domain_get(dominfo.getDomid())
except Exception, ex:
raise XendError(str(ex))
def domain_cpu_sedf_set(self, id, period, slice, latency, extratime, weight):
def domain_cpu_sedf_set(self, domid, period, slice_, latency, extratime,
weight):
"""Set Simple EDF scheduler parameters for a domain.
"""
dominfo = self.domain_lookup(id)
dominfo = self.domain_lookup(domid)
try:
return xc.sedf_domain_set(dominfo.getDomid(), period, slice,
return xc.sedf_domain_set(dominfo.getDomid(), period, slice_,
latency, extratime, weight)
except Exception, ex:
raise XendError(str(ex))
def domain_cpu_sedf_get(self, id):
def domain_cpu_sedf_get(self, domid):
"""Get Simple EDF scheduler parameters for a domain.
"""
dominfo = self.domain_lookup(id)
dominfo = self.domain_lookup(domid)
try:
return xc.sedf_domain_get(dominfo.getDomid())
except Exception, ex:
@@ -442,63 +478,58 @@ class XendDomain:
def domain_device_create(self, domid, devconfig):
"""Create a new device for the specified domain.
"""
return self.callInfo(domid, XendDomainInfo.device_create, devconfig)
return self.callInfo(domid,
XendDomainInfo.XendDomainInfo.device_create,
devconfig)
def domain_device_configure(self, domid, devconfig, devid):
"""Configure an existing device in the specified domain.
@return: updated device configuration
"""
return self.callInfo(domid, XendDomainInfo.device_configure,
return self.callInfo(domid,
XendDomainInfo.XendDomainInfo.device_configure,
devconfig, devid)
def domain_device_refresh(self, domid, devtype, devid):
"""Refresh a device."""
return self.callInfo(domid, XendDomainInfo.device_refresh, devtype,
devid)
def domain_device_destroy(self, domid, devtype, devid):
"""Destroy a device."""
return self.callInfo(domid, XendDomainInfo.destroyDevice, devtype,
devid)
return self.callInfo(domid,
XendDomainInfo.XendDomainInfo.destroyDevice,
devtype, devid)
def domain_devtype_ls(self, domid, devtype):
"""Get list of device sxprs for the specified domain."""
return self.callInfo(domid, XendDomainInfo.getDeviceSxprs, devtype)
return self.callInfo(domid,
XendDomainInfo.XendDomainInfo.getDeviceSxprs,
devtype)
def domain_vif_limit_set(self, id, vif, credit, period):
def domain_vif_limit_set(self, domid, vif, credit, period):
"""Limit the vif's transmission rate
"""
dominfo = self.domain_lookup(id)
dominfo = self.domain_lookup(domid)
dev = dominfo.getDevice('vif', vif)
if not dev:
raise XendError("invalid vif")
return dev.setCreditLimit(credit, period)
def domain_shadow_control(self, id, op):
"""Shadow page control.
@param id: domain
@param op: operation
"""
dominfo = self.domain_lookup(id)
def domain_shadow_control(self, domid, op):
"""Shadow page control."""
dominfo = self.domain_lookup(domid)
try:
return xc.shadow_control(dominfo.getDomid(), op)
except Exception, ex:
raise XendError(str(ex))
def domain_maxmem_set(self, id, mem):
def domain_maxmem_set(self, domid, mem):
"""Set the memory limit for a domain.
@param id: domain
@param mem: memory limit (in MiB)
@return: 0 on success, -1 on error
"""
dominfo = self.domain_lookup(id)
dominfo = self.domain_lookup(domid)
maxmem = int(mem) * 1024
try:
return xc.domain_setmaxmem(dominfo.getDomid(),
@@ -511,7 +542,8 @@ class XendDomain:
@param mem: memory target (in MiB)
"""
self.callInfo(domid, XendDomainInfo.setMemoryTarget, mem << 10)
self.callInfo(domid, XendDomainInfo.XendDomainInfo.setMemoryTarget,
mem << 10)
def domain_vcpu_hotplug(self, domid, vcpu, state):
@@ -520,12 +552,13 @@ class XendDomain:
@param vcpu: target VCPU in domain
@param state: which state VCPU will become
"""
self.callInfo(domid, XendDomainInfo.vcpu_hotplug, vcpu, state)
self.callInfo(domid, XendDomainInfo.XendDomainInfo.vcpu_hotplug, vcpu,
state)
def domain_dumpcore(self, domid):
"""Save a core dump for a crashed domain."""
self.callInfo(domid, XendDomainInfo.dumpCore)
self.callInfo(domid, XendDomainInfo.XendDomainInfo.dumpCore)
## private:
File diff suppressed because it is too large. Load diff
+6 -13
View File
@@ -26,17 +26,15 @@ configured values.
import os
import os.path
import string
import sys
import EventServer
from XendLogging import XendLogging
from XendError import XendError
# Initial create of the event server.
eserver = EventServer.instance()
import sxp
class XendRoot:
"""Root of the management classes."""
@@ -96,9 +94,7 @@ class XendRoot:
self.config = None
self.logging = None
self.configure()
eserver.subscribe('xend.*', self.event_handler)
#eserver.subscribe('xend.domain.created', self.event_handler)
#eserver.subscribe('xend.domain.died', self.event_handler)
def add_component(self, name, val):
"""Add a xend component.
@@ -118,9 +114,6 @@ class XendRoot:
"""
return self.components.get(name)
def start(self):
eserver.inject('xend.start', 0)
def _format(self, msg, args):
if args:
return str(msg) % args
@@ -246,10 +239,10 @@ class XendRoot:
return sxp.child_value(self.config, name, val=val)
def get_config_bool(self, name, val=None):
v = self.get_config_value(name, val)
if v in ['yes', '1', 'on', 'true', 1, True]:
v = string.lower(str(self.get_config_value(name, val)))
if v in ['yes', 'y', '1', 'on', 'true', 't']:
return True
if v in ['no', '0', 'off', 'false', 0, False]:
if v in ['no', 'n', '0', 'off', 'false', 'f']:
return False
raise XendError("invalid xend config %s: expected bool: %s" % (name, v))
+29 -27
View File
@@ -13,6 +13,7 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#============================================================================
# Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
# Copyright (C) 2005 XenSource Ltd
#============================================================================
"""Handler for vnet operations.
@@ -22,7 +23,8 @@ from xen.util import Brctl
from xen.xend import sxp
from xen.xend.XendError import XendError
from xen.xend.XendLogging import log
from xen.xend.xenstore import XenNode, DBMap, DBVar
from xen.xend.xenstore.xstransact import xstransact
def vnet_cmd(cmd):
out = None
@@ -39,39 +41,40 @@ class XendVnetInfo:
vifctl_ops = {'up': 'vif.add', 'down': 'vif.del'}
__exports__ = [
DBVar('id', ty='str'),
DBVar('dbid', ty='str'),
DBVar('config', ty='sxpr'),
]
def __init__(self, db, config=None):
def __init__(self, dbpath, config=None):
if config:
self.id = sxp.child_value(config, 'id')
self.id = str(self.id)
self.id = str(sxp.child_value(config, 'id'))
self.dbid = self.id.replace(':', '-')
self.db = db.addChild(self.dbid)
self.dbpath = dbpath + '/' + self.dbid
self.config = config
else:
self.db = db
self.dbpath = dbpath
self.importFromDB()
config = self.config
self.bridge = sxp.child_value(config, 'bridge')
self.bridge = sxp.child_value(self.config, 'bridge')
if not self.bridge:
self.bridge = "vnet%s" % self.id
self.vnetif = sxp.child_value(config, 'vnetif')
self.vnetif = sxp.child_value(self.config, 'vnetif')
if not self.vnetif:
self.vnetif = "vnif%s" % self.id
def saveToDB(self, save=False, sync=False):
self.db.saveDB(save=save, sync=sync)
def exportToDB(self, save=False, sync=False):
self.db.exportToDB(self, fields=self.__exports__, save=save, sync=sync)
to_store = {
'id' : self.id,
'dbid' : self.dbid,
'config' : sxp.to_string
}
xstransact.Write(self.dbpath, to_store)
def importFromDB(self):
self.db.importFromDB(self, fields=self.__exports__)
(self.id, self.dbid, c) = xstransact.Gather(self.dbpath,
('id', str),
('dbid', str),
('config', str))
self.config = sxp.from_string(c)
def sxpr(self):
return self.config
@@ -88,7 +91,7 @@ class XendVnetInfo:
Brctl.vif_bridge_rem({'bridge': self.bridge, 'vif': self.vnetif})
Brctl.bridge_del(self.bridge)
val = vnet_cmd(['vnet.del', self.id])
self.db.delete()
xstransact.Remove(self.dbpath)
return val
def vifctl(self, op, vif, vmac):
@@ -107,18 +110,17 @@ class XendVnet:
def __init__(self):
# Table of vnet info indexed by vnet id.
self.vnet = {}
self.db = DBMap(db=XenNode(self.dbpath))
self.db.readDB()
for vnetdb in self.db.values():
listing = xstransact.List(self.dbpath)
for entry in listing:
try:
info = XendVnetInfo(vnetdb)
info = XendVnetInfo(self.dbpath + '/' + entry)
self.vnet[info.id] = info
info.configure()
except XendError, ex:
log.warning("Failed to configure vnet %s: %s", str(info.id), str(ex))
except Exception, ex:
log.exception("Vnet error")
vnetdb.delete()
xstransact.Remove(self.dbpath + '/' + entry)
def vnet_of_bridge(self, bridge):
"""Get the vnet for a bridge (if any).
@@ -155,9 +157,9 @@ class XendVnet:
@param config: config
"""
info = XendVnetInfo(self.db, config=config)
info = XendVnetInfo(self.dbpath, config=config)
self.vnet[info.id] = info
info.saveToDB()
info.exportToDB()
info.configure()
def vnet_delete(self, id):
+9 -11
View File
@@ -25,8 +25,6 @@ from xen.xend import sxp
from xen.xend.XendError import VmError
from xen.xend.XendLogging import log
from xen.xend.server import channel
xc = xen.lowlevel.xc.new()
@@ -168,11 +166,11 @@ class LinuxImageHandler(ImageHandler):
def buildDomain(self):
if self.vm.store_channel:
store_evtchn = self.vm.store_channel.port2
store_evtchn = self.vm.store_channel
else:
store_evtchn = 0
if self.vm.console_channel:
console_evtchn = self.vm.console_channel.port2
console_evtchn = self.vm.console_channel
else:
console_evtchn = 0
@@ -228,16 +226,17 @@ class VmxImageHandler(ImageHandler):
def buildDomain(self):
# Create an event channel
self.device_channel = channel.eventChannel(0, self.vm.getDomid())
log.info("VMX device model port: %d", self.device_channel.port2)
self.device_channel = xc.evtchn_alloc_unbound(dom=self.vm.getDomid(),
remote_dom=0)
log.info("VMX device model port: %d", self.device_channel)
if self.vm.store_channel:
store_evtchn = self.vm.store_channel.port2
store_evtchn = self.vm.store_channel
else:
store_evtchn = 0
log.debug("dom = %d", self.vm.getDomid())
log.debug("image = %s", self.kernel)
log.debug("control_evtchn = %d", self.device_channel.port2)
log.debug("control_evtchn = %d", self.device_channel)
log.debug("store_evtchn = %d", store_evtchn)
log.debug("memsize = %d", self.vm.getMemoryTarget() / 1024)
log.debug("flags = %d", self.flags)
@@ -245,7 +244,7 @@ class VmxImageHandler(ImageHandler):
ret = xc.vmx_build(dom = self.vm.getDomid(),
image = self.kernel,
control_evtchn = self.device_channel.port2,
control_evtchn = self.device_channel,
store_evtchn = store_evtchn,
memsize = self.vm.getMemoryTarget() / 1024,
flags = self.flags,
@@ -334,7 +333,7 @@ class VmxImageHandler(ImageHandler):
if len(vnc):
args = args + vnc
args = args + ([ "-d", "%d" % self.vm.getDomid(),
"-p", "%d" % self.device_channel.port1,
"-p", "%d" % self.device_channel,
"-m", "%s" % (self.vm.getMemoryTarget() / 1024)])
args = args + self.dmargs
env = dict(os.environ)
@@ -358,7 +357,6 @@ class VmxImageHandler(ImageHandler):
return vncconnect
def destroy(self):
channel.eventChannelClose(self.device_channel)
import signal
if not self.pid:
return
+51 -9
View File
@@ -75,10 +75,29 @@ class DevController:
"""
frontpath = self.frontendPath(devid)
backpath = xstransact.Read("%s/backend" % frontpath)
backpath = xstransact.Read(frontpath, "backend")
xstransact.Remove(frontpath)
xstransact.Remove(backpath)
if backpath:
xstransact.Remove(backpath)
else:
raise VmError("Device not connected")
def configurations(self):
return map(self.configuration, self.deviceIDs())
def configuration(self, devid):
"""@return an s-expression giving the current configuration of the
specified device. This would be suitable for giving to {@link
#createDevice} in order to recreate that device."""
backdomid = int(xstransact.Read(self.frontendPath(devid),
"backend-id"))
return [self.deviceClass, ['backend', backdomid]]
def sxprs(self):
@@ -150,7 +169,20 @@ class DevController:
raise
## private:
def readBackend(self, devid, *args):
frontpath = self.frontendPath(devid)
backpath = xstransact.Read(frontpath, "backend")
return xstransact.Read(backpath, *args)
def deviceIDs(self):
"""@return The IDs of each of the devices currently configured for
this instance's deviceClass.
"""
return map(int, xstransact.List(self.frontendRoot()))
## private:
def writeDetails(self, config, devid, backDetails, frontDetails):
"""Write the details in the store to trigger creation of a device.
@@ -167,8 +199,17 @@ class DevController:
"""
import xen.xend.XendDomain
backdom = xen.xend.XendDomain.instance().domain_lookup_by_name(
sxp.child_value(config, 'backend', '0'))
xd = xen.xend.XendDomain.instance()
backdom_name = sxp.child_value(config, 'backend')
if backdom_name:
backdom = xd.domain_lookup_by_name_or_id_nr(backdom_name)
else:
backdom = xd.privilegedDomain()
if not backdom:
raise VmError("Cannot configure device for unknown backend %s" %
backdom_name)
frontpath = self.frontendPath(devid)
backpath = self.backendPath(backdom, devid)
@@ -197,9 +238,9 @@ class DevController:
def backendPath(self, backdom, devid):
"""@param backdom [XendDomainInfo] The backend domain info."""
return "%s/backend/%s/%s/%d" % (backdom.getPath(),
return "%s/backend/%s/%s/%d" % (backdom.getDomainPath(),
self.deviceClass,
self.vm.getUuid(), devid)
self.vm.getDomid(), devid)
def frontendPath(self, devid):
@@ -207,8 +248,9 @@ class DevController:
def frontendRoot(self):
return "%s/device/%s" % (self.vm.getPath(), self.deviceClass)
return "%s/device/%s" % (self.vm.getDomainPath(), self.deviceClass)
def frontendMiscPath(self):
return "%s/device-misc/%s" % (self.vm.getPath(), self.deviceClass)
return "%s/device-misc/%s" % (self.vm.getDomainPath(),
self.deviceClass)
+17 -15
View File
@@ -2,6 +2,7 @@
## Xen controller daemon
## Copyright (c) 2004, K A Fraser (University of Cambridge)
## Copyright (C) 2004, Mike Wray <mike.wray@hp.com>
## Copyright (C) 2005, XenSource Ltd
###########################################################
import os
@@ -13,20 +14,14 @@ import pwd
import re
import traceback
from xen.xend import EventServer
from xen.xend.server import SrvServer
from xen.xend.XendLogging import log
from xen.xend import XendRoot
import event
import relocate
from params import *
eserver = EventServer.instance()
xroot = XendRoot.instance()
class Daemon:
"""The xend daemon.
"""
@@ -71,14 +66,17 @@ class Daemon:
@param pidfile: file to read
@return pid or 0
"""
pid = 0
if os.path.isfile(pidfile) and os.path.getsize(pidfile):
try:
pid = open(pidfile, 'r').read()
pid = int(pid)
f = open(pidfile, 'r')
try:
return int(f.read())
finally:
f.close()
except:
pid = 0
return pid
return 0
else:
return 0
def find_process(self, pid, name):
"""Search for a process.
@@ -146,8 +144,10 @@ class Daemon:
if self.child:
# Parent
pidfile = open(pidfile, 'w')
pidfile.write(str(self.child))
pidfile.close()
try:
pidfile.write(str(self.child))
finally:
pidfile.close()
return self.child
@@ -200,8 +200,10 @@ class Daemon:
if self.fork_pid(XEND_PID_FILE):
os.close(w)
r = os.fdopen(r, 'r')
s = r.read()
r.close()
try:
s = r.read()
finally:
r.close()
if not len(s):
ret = 1
else:
+3 -14
View File
@@ -71,8 +71,7 @@ class SrvDomain(SrvDir):
def op_destroy(self, op, req):
fn = FormFn(self.xd.domain_destroy,
[['dom', 'int'],
['reason', 'str']])
[['dom', 'int']])
val = fn(req.args, {'dom': self.dom.domid})
req.setHeader("Location", "%s/.." % req.prePathURL())
return val
@@ -157,19 +156,11 @@ class SrvDomain(SrvDir):
val = fn(req.args, {'dom': self.dom.domid})
return val
def op_device_refresh(self, op, req):
fn = FormFn(self.xd.domain_device_refresh,
[['dom', 'int'],
['type', 'str'],
['idx', 'int']])
val = fn(req.args, {'dom': self.dom.domid})
return val
def op_device_destroy(self, op, req):
fn = FormFn(self.xd.domain_device_destroy,
[['dom', 'int'],
['type', 'str'],
['idx', 'int']])
['dev', 'str']])
val = fn(req.args, {'dom': self.dom.domid})
return val
@@ -177,7 +168,7 @@ class SrvDomain(SrvDir):
fn = FormFn(self.xd.domain_device_configure,
[['dom', 'int'],
['config', 'sxpr'],
['idx', 'int']])
['dev', 'str']])
val = fn(req.args, {'dom': self.dom.domid})
return val
@@ -232,8 +223,6 @@ class SrvDomain(SrvDir):
req.write('<form method="post" action="%s">' % url)
req.write('<input type="submit" name="op" value="destroy">')
req.write('<input type="radio" name="reason" value="halt" checked>Halt')
req.write('<input type="radio" name="reason" value="reboot">Reboot')
req.write('</form>')
req.write('<form method="post" action="%s">' % url)
+1 -1
View File
@@ -38,7 +38,7 @@ class SrvDomainDir(SrvDir):
self.xd = XendDomain.instance()
def domain(self, x):
dom = self.xd.domain_lookup_by_name(x)
dom = self.xd.domain_lookup_by_name_or_id(x)
if not dom:
raise XendError('No such domain ' + str(x))
return SrvDomain(dom)
+1 -4
View File
@@ -13,10 +13,9 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#============================================================================
# Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
# Copyright (C) 2005 XenSource Ltd
#============================================================================
from xen.xend import XendRoot
xroot = XendRoot.instance()
from xen.web.SrvDir import SrvDir
class SrvRoot(SrvDir):
@@ -39,8 +38,6 @@ class SrvRoot(SrvDir):
self.add(name, klass)
for (name, klass) in self.subdirs:
self.get(name)
xroot.start()
def __repr__(self):
return "<SrvRoot %x %s>" %(id(self), self.table.keys())
+47 -5
View File
@@ -23,7 +23,7 @@ import string
from xen.util import blkif
from xen.xend import sxp
from xen.xend.server.DevController import DevController
from DevController import DevController
class BlkifController(DevController):
@@ -40,14 +40,15 @@ class BlkifController(DevController):
def getDeviceDetails(self, config):
"""@see DevController.getDeviceDetails"""
typedev = sxp.child_value(config, 'dev')
if re.match('^ioemu:', typedev):
dev = sxp.child_value(config, 'dev')
if re.match('^ioemu:', dev):
return (0,{},{})
devid = blkif.blkdev_name_to_number(sxp.child_value(config, 'dev'))
devid = blkif.blkdev_name_to_number(dev)
(typ, params) = string.split(sxp.child_value(config, 'uname'), ':', 1)
back = { 'type' : typ,
back = { 'dev' : dev,
'type' : typ,
'params' : params
}
@@ -57,3 +58,44 @@ class BlkifController(DevController):
front = { 'virtual-device' : "%i" % devid }
return (devid, back, front)
def configuration(self, devid):
"""@see DevController.configuration"""
result = DevController.configuration(self, devid)
(dev, typ, params, ro) = self.readBackend(devid,
'dev', 'type', 'params',
'read-only')
if dev:
result.append(['dev', dev])
if typ and params:
result.append(['uname', typ + ":" + params])
if ro:
result.append(['mode', 'r'])
else:
result.append(['mode', 'w'])
return result
def destroyDevice(self, devid):
"""@see DevController.destroyDevice"""
# If we are given a device name, then look up the device ID from it,
# and destroy that ID instead. If what we are given is an integer,
# then assume it's a device ID and pass it straight through to our
# superclass's method.
try:
DevController.destroyDevice(self, int(devid))
except ValueError:
for i in self.deviceIDs():
if self.readBackend(i, 'dev') == devid:
DevController.destroyDevice(self, i)
return
# Try this, but it's almost certainly going to throw VmError,
# since we can't find the device.
DevController.destroyDevice(self, int(devid))
-92
View File
@@ -1,92 +0,0 @@
#============================================================================
# This library is free software; you can redistribute it and/or
# modify it under the terms of version 2.1 of the GNU Lesser General Public
# License as published by the Free Software Foundation.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#============================================================================
# Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
#============================================================================
import threading
import select
import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
from xen.xend.XendLogging import log
DEBUG = 0
RESPONSE_TIMEOUT = 20.0
class EventChannel(dict):
"""An event channel between domains.
"""
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 __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 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.
"""
if not evtchn: return
evtchn.close()
+22 -44
View File
@@ -13,19 +13,23 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#============================================================================
# Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
# Copyright (C) 2005 XenSource Ltd
#============================================================================
import sys
import StringIO
from xen.web import reactor, protocol
from xen.web import protocol, tcp, unix
from xen.xend import scheduler
from xen.xend import sxp
from xen.xend import PrettyPrint
from xen.xend import EventServer; eserver = EventServer.instance()
from xen.xend.XendError import XendError
from xen.xend import XendRoot; xroot = XendRoot.instance()
from xen.xend import XendRoot
xroot = XendRoot.instance()
DEBUG = 0
@@ -38,13 +42,7 @@ class EventProtocol(protocol.Protocol):
self.daemon = daemon
# Event queue.
self.queue = []
# Subscribed events.
self.events = []
self.parser = sxp.Parser()
self.pretty = 0
# For debugging subscribe to everything and make output pretty.
#self.subscribe(['*'])
self.pretty = 1
def dataReceived(self, data):
@@ -68,7 +66,7 @@ class EventProtocol(protocol.Protocol):
scheduler.now(self.connectionLost)
def connectionLost(self, reason=None):
self.unsubscribe()
pass
def send_reply(self, sxpr):
io = StringIO.StringIO()
@@ -99,16 +97,6 @@ class EventProtocol(protocol.Protocol):
def send_event(self, val):
return self.send_reply(['event', val[0], val[1]])
def unsubscribe(self):
for event in self.events:
eserver.unsubscribe(event, self.queue_event)
def subscribe(self, events):
self.unsubscribe()
for event in events:
eserver.subscribe(event, self.queue_event)
self.events = events
def queue_event(self, name, v):
# Despite the name we don't queue the event here.
# We send it because the transport will queue it.
@@ -126,7 +114,7 @@ class EventProtocol(protocol.Protocol):
op_method = getattr(self, op_method_name, self.operror)
return op_method(op_name, req)
def op_help(self, name, req):
def op_help(self, _1, _2):
def nameop(x):
if x.startswith('op_'):
return x[3:].replace('_', '.')
@@ -136,37 +124,27 @@ class EventProtocol(protocol.Protocol):
l = [ nameop(k) for k in dir(self) if k.startswith('op_') ]
return l
def op_quit(self, name, req):
def op_quit(self, _1, _2):
self.loseConnection()
def op_exit(self, name, req):
def op_exit(self, _1, _2):
sys.exit(0)
def op_pretty(self, name, req):
def op_pretty(self, _1, _2):
self.pretty = 1
def op_info(self, name, req):
def op_info(self, _1, _2):
val = ['info']
#val += self.daemon.blkifs()
#val += self.daemon.netifs()
#val += self.daemon.usbifs()
return val
def op_sys_subscribe(self, name, v):
# (sys.subscribe event*)
# Subscribe to the events:
self.subscribe(v[1:])
def op_sys_inject(self, name, v):
# (sys.inject event)
event = v[1]
eserver.inject(sxp.name(event), event)
def op_trace(self, name, v):
def op_trace(self, _, v):
mode = (v[1] == 'on')
self.daemon.tracing(mode)
def op_log_stderr(self, name, v):
def op_log_stderr(self, _, v):
mode = v[1]
logging = xroot.get_logging()
if mode == 'on':
@@ -174,11 +152,11 @@ class EventProtocol(protocol.Protocol):
else:
logging.removeLogStderr()
def op_domain_ls(self, name, v):
def op_domain_ls(self, _1, _2):
xd = xroot.get_component("xen.xend.XendDomain")
return xd.list_names()
def op_domain_configure(self, name, v):
def op_domain_configure(self, _, v):
domid = sxp.child_value(v, "dom")
config = sxp.child_value(v, "config")
if domid is None:
@@ -188,7 +166,7 @@ class EventProtocol(protocol.Protocol):
xd = xroot.get_component("xen.xend.XendDomain")
xd.domain_configure(domid, config)
def op_domain_unpause(self, name, v):
def op_domain_unpause(self, _, v):
domid = sxp.child_value(v, "dom")
if domid is None:
raise XendError("missing domain id")
@@ -200,18 +178,18 @@ class EventFactory(protocol.ServerFactory):
"""
def __init__(self, daemon):
#protocol.ServerFactory.__init__(self)
protocol.ServerFactory.__init__(self)
self.daemon = daemon
def buildProtocol(self, addr):
def buildProtocol(self, _):
return EventProtocol(self.daemon)
def listenEvent(daemon):
factory = EventFactory(daemon)
if xroot.get_xend_unix_server():
path = '/var/lib/xend/event-socket'
reactor.listenUNIX(path, factory)
unix.listenUNIX(path, factory)
if xroot.get_xend_http_server():
port = xroot.get_xend_event_port()
interface = xroot.get_xend_address()
reactor.listenTCP(port, factory, interface=interface)
tcp.listenTCP(port, factory, interface=interface)
+27 -3
View File
@@ -23,10 +23,14 @@
import os
from xen.xend import sxp
from xen.xend import XendRoot
from xen.xend.server.DevController import DevController
xroot = XendRoot.instance()
class NetifController(DevController):
"""Network interface controller. Handles all network devices for a domain.
"""
@@ -38,9 +42,6 @@ class NetifController(DevController):
def getDeviceDetails(self, config):
"""@see DevController.getDeviceDetails"""
from xen.xend import XendRoot
xroot = XendRoot.instance()
def _get_config_ipaddr(config):
val = []
for ipaddr in sxp.children(config, elt='ip'):
@@ -68,3 +69,26 @@ class NetifController(DevController):
'mac' : mac }
return (devid, back, front)
def configuration(self, devid):
"""@see DevController.configuration"""
result = DevController.configuration(self, devid)
(script, ip, bridge, mac) = self.readBackend(devid,
'script', 'ip', 'bridge',
'mac')
if script:
result.append(['script',
script.replace(xroot.network_script_dir + os.sep,
"")])
if ip:
result.append(['ip', ip.split(" ")])
if bridge:
result.append(['bridge', bridge])
if mac:
result.append(['mac', mac])
return result
+10 -7
View File
@@ -13,21 +13,24 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#============================================================================
# Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
# Copyright (C) 2005 XenSource Ltd
#============================================================================
import socket
import sys
import StringIO
from xen.web import reactor, protocol
from xen.web import protocol, tcp, unix
from xen.xend import scheduler
from xen.xend import sxp
from xen.xend import EventServer; eserver = EventServer.instance()
from xen.xend.XendError import XendError
from xen.xend import XendRoot; xroot = XendRoot.instance()
from xen.xend import XendRoot
from xen.xend.XendLogging import log
from xen.xend import XendCheckpoint
xroot = XendRoot.instance()
DEBUG = 0
@@ -115,7 +118,7 @@ class RelocationProtocol(protocol.Protocol):
self.send_reply(["ready", name])
self.transport.sock.setblocking(1)
xd = xroot.get_component("xen.xend.XendDomain")
XendCheckpoint.restore(xd, self.transport.sock.fileno())
xd.domain_restore_fd(self.transport.sock.fileno())
self.transport.sock.setblocking(0)
else:
log.error(name + ": no transport")
@@ -136,11 +139,11 @@ def listenRelocation():
factory = RelocationFactory()
if xroot.get_xend_unix_server():
path = '/var/lib/xend/relocation-socket'
reactor.listenUNIX(path, factory)
unix.listenUNIX(path, factory)
if xroot.get_xend_relocation_server():
port = xroot.get_xend_relocation_port()
interface = xroot.get_xend_relocation_address()
l = reactor.listenTCP(port, factory, interface=interface)
l = tcp.listenTCP(port, factory, interface=interface)
l.setCloExec()
def setupRelocation(dst, port):
+15 -2
View File
@@ -37,11 +37,24 @@ class TPMifController(DevController):
def getDeviceDetails(self, config):
"""@see DevController.getDeviceDetails"""
devid = int(sxp.child_value(config, 'instance', '0'))
log.debug("The domain has a TPM with instance %d." % devid)
log.info("The domain has a TPM with instance %d." % devid)
back = { 'instance' : "%i" % devid }
front = { 'handle' : "%i" % devid }
return (devid, back, front)
def configuration(self, devid):
result = DevController.configuration(self, devid)
(instance) = self.readBackend(devif,
'instance')
if instance:
result.append(['instance', instance])
log.info("configuration: instance=%d." % instance)
return result
+18
View File
@@ -0,0 +1,18 @@
import unittest
import xen.xend.sxp
class test_sxp(unittest.TestCase):
def testAllFromString(self):
def t(input, expected):
self.assertEqual(xen.xend.sxp.all_from_string(input), expected)
t('String', ['String'])
t('(String Thing)', [['String', 'Thing']])
t('(String) (Thing)', [['String'], ['Thing']])
def test_suite():
return unittest.makeSuite(test_sxp)
@@ -14,5 +14,3 @@
#============================================================================
# Copyright (C) 2005 Mike Wray <mike.wray@hp.com>
#============================================================================
from xsnode import *
from xsobj import *
-477
View File
@@ -1,477 +0,0 @@
#============================================================================
# This library is free software; you can redistribute it and/or
# modify it under the terms of version 2.1 of the GNU Lesser General Public
# License as published by the Free Software Foundation.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#============================================================================
# Copyright (C) 2005 Mike Wray <mike.wray@hp.com>
#============================================================================
import errno
import os
import os.path
import select
import socket
import sys
import threading
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):
if event and event.startswith("/"):
event = event[1:]
return os.path.join("/event", event)
def getEventIdPath(event):
return os.path.join(getEventPath(event), "@eid")
class Subscription:
def __init__(self, path, fn, sid):
self.path = path
self.watcher = None
self.fn = fn
self.sid = sid
def getPath(self):
return self.path
def getSid(self):
return self.sid
def watch(self, watcher):
self.watcher = watcher
watcher.addSubs(self)
def unwatch(self):
watcher = self.watcher
if watcher:
self.watcher = None
watcher.delSubs(self)
return watcher
def notify(self, token, path, val):
try:
self.fn(self, token, path, val)
except SystemExit:
raise
except Exception, ex:
pass
class Watcher:
def __init__(self, store, path):
self.path = path
store.mkdirs(self.path)
self.xs = None
self.subscriptions = []
def fileno(self):
if self.xs:
return self.xs.fileno()
else:
return -1
def getPath(self):
return self.path
def getToken(self):
return self.path
def addSubs(self, subs):
self.subscriptions.append(subs)
self.watch()
def delSubs(self, subs):
self.subscriptions.remove(subs)
if len(self.subscriptions) == 0:
self.unwatch()
def watch(self):
if self.xs: return
self.xs = xs.open()
self.xs.watch(path=self.getPath(), token=self.getToken())
def unwatch(self):
if self.xs:
## Possibly crashes xenstored.
## try:
## self.xs.unwatch(path=self.getPath(), token=self.getToken())
## except Exception, ex:
## print 'Watcher>unwatch>', ex
try:
self.xs.close()
except Exception, ex:
pass
self.xs = None
def watching(self):
return self.xs is not None
def getNotification(self):
p = self.xs.read_watch()
self.xs.acknowledge_watch(p[1])
return p
def notify(self):
try:
(path, token) = self.getNotification()
if path.endswith("@eid"):
pass
else:
val = self.xs.read(path)
for subs in self.subscriptions:
subs.notify(token, path, val)
except SystemExit:
raise
except Exception, ex:
raise
class EventWatcher(Watcher):
def __init__(self, store, path, event):
Watcher.__init__(self, store, path)
self.event = event
self.eidPath = getEventIdPath(event)
if not store.exists(self.eidPath):
store.write(self.eidPath, str(0))
def getEvent(self):
return self.event
def getToken(self):
return self.event
class XenStore:
xs = None
watchThread = None
subscription_id = 1
def __init__(self):
self.subscriptions = {}
self.watchers = {}
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 SystemExit:
raise
except Exception, ex:
print >>sys.stderr, "Exception connecting to xenstored:", ex
print >>sys.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 RuntimeError(ex.args[0],
ex.args[1] +
(', in exists(%s)' % (str(path))))
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, "")
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):
self.write(path, "")
def write(self, path, data):
try:
self.getxs().write(path, data)
except RuntimeError, ex:
raise RuntimeError(ex.args[0],
ex.args[1] +
(', while writing %s : %s' % (str(path),
str(data))))
def begin(self):
self.getxs().transaction_start()
def commit(self, abandon=False):
self.getxs().transaction_end(abort=abandon)
def watch(self, path, fn):
watcher = self.watchers.get(path)
if not watcher:
watcher = self.addWatcher(Watcher(self, path))
return self.addSubscription(watcher, fn)
def unwatch(self, sid):
s = self.subscriptions.get(sid)
if not s: return
del self.subscriptions[s.sid]
watcher = s.unwatch()
if watcher and not watcher.watching():
try:
del self.watchers[watcher.getPath()]
except:
pass
def subscribe(self, event, fn):
path = getEventPath(event)
watcher = self.watchers.get(path)
if not watcher:
watcher = self.addWatcher(EventWatcher(self, path, event))
return self.addSubscription(watcher, fn)
unsubscribe = unwatch
def sendEvent(self, event, data):
eventPath = getEventPath(event)
eidPath = getEventIdPath(event)
try:
#self.begin(eventPath)
self.mkdirs(eventPath)
eid = 1
if self.exists(eidPath):
try:
eid = int(self.read(eidPath))
eid += 1
except Exception, ex:
pass
self.write(eidPath, str(eid))
self.write(os.path.join(eventPath, str(eid)), data)
finally:
#self.commit()
pass
def addWatcher(self, watcher):
self.watchers[watcher.getPath()] = watcher
self.watchStart()
return watcher
def addSubscription(self, watcher, fn):
self.subscription_id += 1
subs = Subscription(watcher.getPath(), fn, self.subscription_id)
self.subscriptions[subs.sid] = subs
subs.watch(watcher)
return subs.sid
def watchStart(self):
if self.watchThread: return
self.watchThread = threading.Thread(name="Watcher",
target=self.watchMain)
self.watchThread.setDaemon(True)
self.watchThread.start()
def watchMain(self):
try:
while True:
if self.watchThread is None: return
if not self.watchers:
return
rd = self.watchers.values()
try:
(srd, swr, ser) = select.select(rd, [], [], SELECT_TIMEOUT)
for watcher in srd:
watcher.notify()
except socket.error, ex:
if ex.args[0] in (EAGAIN, EINTR):
pass
else:
raise
finally:
self.watchThread = None
def getXenStore():
global xenstore
try:
return xenstore
except:
xenstore = XenStore()
return xenstore
def sendEvent(event, val):
getXenStore.sendEvent(event, val)
def subscribe(event, fn):
return getXenStore().subscribe(event, fn)
def unsubscribe(sid):
getXenStore().unsubscribe(sid)
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 getStore(self):
return self.store
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=""):
return self.store.write(self.relPath(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 watch(self, fn, path=""):
"""Watch a path for changes. The path is relative
to the node and defaults to the node itself.
"""
return self.store.watch(self.relPath(path), fn)
def unwatch(self, sid):
return self.store.unwatch(sid)
def subscribe(self, event, fn):
return self.store.subscribe(event, fn)
def unsubscribe(self, sid):
self.store.unsubscribe(sid)
def sendEvent(self, event, data):
return self.store.sendEvent(event, data)
def __repr__(self):
return "<XenNode %s>" % self.path
-537
View File
@@ -1,537 +0,0 @@
#============================================================================
# This library is free software; you can redistribute it and/or
# modify it under the terms of version 2.1 of the GNU Lesser General Public
# License as published by the Free Software Foundation.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#============================================================================
# Copyright (C) 2005 Mike Wray <mike.wray@hp.com>
#============================================================================
import string
import types
from xen.xend.XendLogging import log
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):
try:
if isinstance(obj, dict):
return obj.get(attr)
else:
return getattr(obj, attr, None)
except AttributeError:
return None
except LookupError:
return None
def setAttr(obj, attr, val):
if isinstance(obj, dict):
obj[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 exportTypeToDB(cls, db, path, val, ty=None):
return cls.getConverter(ty).exportToDB(db, path, val)
exportTypeToDB = classmethod(exportTypeToDB)
def importTypeFromDB(cls, db, path, ty=None):
return cls.getConverter(ty).importFromDB(db, path)
importTypeFromDB = classmethod(importTypeFromDB)
# 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 exportToDB(self, db, path, val):
if val is None:
return
try:
data = self.toDB(val)
except Exception, ex:
raise
setattr(db, path, data)
def importFromDB(self, db, path):
data = getAttr(db, path)
if data is None:
val = None
else:
try:
val = self.fromDB(data.getData())
except Exception, ex:
raise
return val
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):
val = self.getObj(obj)
DBConverter.exportTypeToDB(db, self.path, val, ty=self.ty)
def importFromDB(self, db, obj):
val = DBConverter.importTypeFromDB(db, self.path, ty=self.ty)
self.setObj(obj, val)
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)
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 watch(self, fn, path=""):
return self.__db__.watch(fn, path=path)
def unwatch(self, sid):
return self.__db__.unwatch(sid)
def subscribe(self, event, fn):
return self.__db__.subscribe(event, fn)
def unsubscribe(self, sid):
return self.__db__.unsubscribe(sid)
def sendEvent(self, event, val):
return self.__db__.sendEvent(event, val)
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 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()
l = self.__db__.ls()
if l:
for k in l:
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)
@@ -1,149 +0,0 @@
#============================================================================
# This library is free software; you can redistribute it and/or
# modify it under the terms of version 2.1 of the GNU Lesser General Public
# License as published by the Free Software Foundation.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#============================================================================
# Copyright (C) 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()
+9 -6
View File
@@ -7,14 +7,17 @@
import threading
from xen.lowlevel import xs
handles = {}
xs_lock = threading.Lock()
xs_handle = None
# XXX need to g/c handles from dead threads
def xshandle():
if not handles.has_key(threading.currentThread()):
handles[threading.currentThread()] = xs.open()
return handles[threading.currentThread()]
global xs_handle, xs_lock
if not xs_handle:
xs_lock.acquire()
if not xs_handle:
xs_handle = xs.open()
xs_lock.release()
return xs_handle
def IntroduceDomain(domid, page, port, path):
return xshandle().introduce_domain(domid, page, port, path)
+7 -20
View File
@@ -12,7 +12,6 @@ from xen.lowlevel import xs
class xswatch:
watchThread = None
threadcond = threading.Condition()
xs = None
xslock = threading.Lock()
@@ -21,43 +20,31 @@ class xswatch:
self.args = args
self.kwargs = kwargs
xswatch.watchStart()
xswatch.xslock.acquire()
xswatch.xs.watch(path, self)
xswatch.xslock.release()
def watchStart(cls):
cls.threadcond.acquire()
cls.xslock.acquire()
if cls.watchThread:
cls.threadcond.release()
cls.xslock.release()
return
# XXX: When we fix xenstored to have better watch semantics,
# this can change to shared xshandle(). Currently that would result
# in duplicate watch firings, thus failed extra xs.acknowledge_watch.
cls.xs = xs.open()
cls.watchThread = threading.Thread(name="Watcher",
target=cls.watchMain)
cls.watchThread.setDaemon(True)
cls.watchThread.start()
while cls.xs == None:
cls.threadcond.wait()
cls.threadcond.release()
cls.xslock.release()
watchStart = classmethod(watchStart)
def watchMain(cls):
cls.threadcond.acquire()
cls.xs = xs.open()
cls.threadcond.notifyAll()
cls.threadcond.release()
while True:
try:
(fd, _1, _2) = select.select([ cls.xs ], [], [])
cls.xslock.acquire()
# reconfirm ready to read with lock
(fd, _1, _2) = select.select([ cls.xs ], [], [], 0.001)
if not cls.xs in fd:
cls.xslock.release()
continue
we = cls.xs.read_watch()
watch = we[1]
cls.xs.acknowledge_watch(watch)
cls.xslock.release()
except RuntimeError, ex:
print ex
raise
+43 -1
View File
@@ -163,11 +163,47 @@ gopts.var('cpu_weight', val='WEIGHT',
gopts.var('restart', val='onreboot|always|never',
fn=set_value, default=None,
use="""Whether the domain should be restarted on exit.
use="""Deprecated. Use on_poweroff, on_reboot, and on_crash
instead.
Whether the domain should be restarted on exit.
- onreboot: restart on exit with shutdown code reboot
- always: always restart on exit, ignore exit code
- never: never restart on exit, ignore exit code""")
gopts.var('on_poweroff', val='destroy|restart|preserve|rename-restart',
fn=set_value, default=None,
use="""Behaviour when a domain exits with reason 'poweroff'.
- destroy: the domain is cleaned up as normal;
- restart: a new domain is started in place of the old one;
- preserve: no clean-up is done until the domain is manually
destroyed (using xm destroy, for example);
- rename-restart: the old domain is not cleaned up, but is
renamed and a new domain started in its place.
""")
gopts.var('on_reboot', val='destroy|restart|preserve|rename-restart',
fn=set_value, default=None,
use="""Behaviour when a domain exits with reason 'reboot'.
- destroy: the domain is cleaned up as normal;
- restart: a new domain is started in place of the old one;
- preserve: no clean-up is done until the domain is manually
destroyed (using xm destroy, for example);
- rename-restart: the old domain is not cleaned up, but is
renamed and a new domain started in its place.
""")
gopts.var('on_crash', val='destroy|restart|preserve|rename-restart',
fn=set_value, default=None,
use="""Behaviour when a domain exits with reason 'crash'.
- destroy: the domain is cleaned up as normal;
- restart: a new domain is started in place of the old one;
- preserve: no clean-up is done until the domain is manually
destroyed (using xm destroy, for example);
- rename-restart: the old domain is not cleaned up, but is
renamed and a new domain started in its place.
""")
gopts.var('blkif', val='no|yes',
fn=set_bool, default=0,
use="Make the domain a block device backend.")
@@ -536,6 +572,12 @@ def make_config(opts, vals):
config.append(['backend', ['tpmif']])
if vals.restart:
config.append(['restart', vals.restart])
if vals.on_poweroff:
config.append(['on_poweroff', vals.on_poweroff])
if vals.on_reboot:
config.append(['on_reboot', vals.on_reboot])
if vals.on_crash:
config.append(['on_crash', vals.on_crash])
if vals.bootloader:
config.append(['bootloader', vals.bootloader])
+3 -13
View File
@@ -21,19 +21,15 @@
from xen.xend.XendClient import server
from xen.xm.opts import *
gopts = Opts(use="""[options] [DOM]
gopts = Opts(use="""[DOM]
Destroy a domain, optionally restarting it.
Destroy a domain.
""")
gopts.opt('help', short='h',
fn=set_true, default=0,
use="Print this help.")
gopts.opt('reboot', short='R',
fn=set_true, default=0,
use='Destroy and restart.')
def main(argv):
opts = gopts
args = opts.parse(argv)
@@ -42,10 +38,4 @@ def main(argv):
return
if len(args) < 1: opts.err('Missing domain')
dom = args[0]
if opts.vals.reboot:
mode = 'reboot'
else:
mode = 'halt'
server.xend_domain_destroy(dom, mode)
server.xend_domain_destroy(dom)
+23 -20
View File
@@ -30,9 +30,15 @@ from getopt import getopt
import socket
import warnings
warnings.filterwarnings('ignore', category=FutureWarning)
import xen.xend.XendError
import xen.xend.XendProtocol
from xen.xend import PrettyPrint
from xen.xend import sxp
from xen.xm.opts import *
shorthelp = """Usage: xm <subcommand> [args]
Control, list, and manipulate Xen guest instances
@@ -80,8 +86,8 @@ xm full list of subcommands:
shutdown [-w|-a] <DomId> shutdown a domain
sysrq <DomId> <letter> send a sysrq to a domain
unpause <DomId> unpause a paused domain
vcpu-enable <DomId> <VCPU> disable VCPU in a domain
vcpu-disable <DomId> <VCPU> enable VCPU in a domain
vcpu-enable <DomId> <VCPU> enable VCPU in a domain
vcpu-disable <DomId> <VCPU> disable VCPU in a domain
vcpu-list <DomId> get the list of VCPUs for a domain
vcpu-pin <DomId> <VCpu> <CPUS> set which cpus a VCPU can use.
@@ -100,9 +106,10 @@ xm full list of subcommands:
Virtual Device Commands:
block-attach <DomId> <BackDev> <FrontDev> <Mode> [BackDomId]
Create a new virtual block device
block-detach <DomId> <DevId> Destroy a domain's virtual block device
block-detach <DomId> <DevId> Destroy a domain's virtual block device,
where <DevId> may either be the device ID
or the device name as mounted in the guest.
block-list <DomId> List virtual block devices for a domain
block-refresh <DomId> <DevId> Refresh a virtual block device for a domain
network-limit <DomId> <Vif> <Credit> <Period>
Limit the transmission rate of a virtual network interface
network-list <DomId> List virtual network interfaces for a domain
@@ -160,6 +167,9 @@ def handle_xend_error(cmd, dom, ex):
if error == "Not found" and dom != None:
err("Domain '%s' not found when running 'xm %s'" % (dom, cmd))
sys.exit(1)
elif error == "Exception: Device not connected":
err("Device not connected")
sys.exit(1)
else:
raise ex
@@ -513,15 +523,6 @@ def xm_block_attach(args):
from xen.xend.XendClient import server
server.xend_domain_device_create(dom, vbd)
def xm_block_refresh(args):
arg_check(args,2,"block-refresh")
dom = args[0]
dev = args[1]
from xen.xend.XendClient import server
server.xend_domain_device_refresh(dom, 'vbd', dev)
def xm_block_detach(args):
arg_check(args,2,"block-detach")
@@ -608,7 +609,6 @@ commands = {
"block-attach": xm_block_attach,
"block-detach": xm_block_detach,
"block-list": xm_block_list,
"block-refresh": xm_block_refresh,
# network
"network-limit": xm_network_limit,
"network-list": xm_network_list,
@@ -637,7 +637,6 @@ aliases = {
"vbd-create": "block-create",
"vbd-destroy": "block-destroy",
"vbd-list": "block-list",
"vbd-refresh": "block-refresh",
}
help = {
@@ -687,7 +686,6 @@ def main(argv=sys.argv):
args = argv[2:]
if cmd:
try:
from xen.xend.XendClient import XendError
rc = cmd(args)
if rc:
usage()
@@ -698,7 +696,15 @@ def main(argv=sys.argv):
except IOError:
err("Most commands need root access. Please try again as root")
sys.exit(1)
except XendError, ex:
except xen.xend.XendError.XendError, ex:
if len(args) > 0:
handle_xend_error(argv[1], args[0], ex)
else:
print "Unexpected error:", sys.exc_info()[0]
print
print "Please report to xen-devel@lists.xensource.com"
raise
except xen.xend.XendProtocol.XendError, ex:
if len(args) > 0:
handle_xend_error(argv[1], args[0], ex)
else:
@@ -719,6 +725,3 @@ def main(argv=sys.argv):
if __name__ == "__main__":
main()
+8 -12
View File
@@ -73,19 +73,15 @@ def shutdown(opts, doms, mode, wait):
opts.info("All domains terminated")
def shutdown_mode(opts):
mode = 'poweroff'
if opts.vals.wait:
mode = 'halt'
if opts.vals.reboot:
opts.err("Can't specify wait and reboot")
if opts.vals.halt and opts.vals.reboot:
opts.err("Can't specify halt and reboot")
if opts.vals.halt:
return 'halt'
elif opts.vals.reboot:
return 'reboot'
else:
if opts.vals.halt and opts.vals.reboot:
opts.err("Can't specify halt and reboot")
if opts.vals.halt:
mode = 'halt'
elif opts.vals.reboot:
mode = 'reboot'
return mode
return 'poweroff'
def main_all(opts, args):
mode = shutdown_mode(opts)
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.