mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
[XEND] Make XMLRPC Server shutdown cleanly.
We can now catch the end of Xend and clean up domains accordingly. Signed-off-by: Alastair Tse <atse@xensource.com>
This commit is contained in:
1 parent
d03a635aec
commit
ef46d763af
3 files changed
+70
-19
No files matched your search
@@ -195,6 +195,8 @@ class Daemon:
|
||||
sig)
|
||||
else:
|
||||
self.run(w and os.fdopen(w, 'w') or None)
|
||||
# if we reach here, the child should quit.
|
||||
os._exit(0)
|
||||
|
||||
return ret
|
||||
|
||||
@@ -290,6 +292,8 @@ class Daemon:
|
||||
relocate.listenRelocation()
|
||||
servers = SrvServer.create()
|
||||
servers.start(status)
|
||||
del servers
|
||||
|
||||
except Exception, ex:
|
||||
print >>sys.stderr, 'Exception starting xend:', ex
|
||||
if XEND_DEBUG:
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
|
||||
import fcntl
|
||||
import time
|
||||
import signal
|
||||
from threading import Thread
|
||||
|
||||
from xen.web.httpserver import HttpServer, UnixHttpServer
|
||||
@@ -54,7 +55,6 @@ from xen.web.SrvDir import SrvDir
|
||||
from SrvRoot import SrvRoot
|
||||
from XMLRPCServer import XMLRPCServer
|
||||
|
||||
|
||||
xroot = XendRoot.instance()
|
||||
|
||||
|
||||
@@ -66,6 +66,14 @@ class XendServers:
|
||||
def add(self, server):
|
||||
self.servers.append(server)
|
||||
|
||||
def cleanup(self, signum = 0, frame = None):
|
||||
log.debug("SrvServer.cleanup()")
|
||||
for server in self.servers:
|
||||
try:
|
||||
server.shutdown()
|
||||
except:
|
||||
pass
|
||||
|
||||
def start(self, status):
|
||||
# Running the network script will spawn another process, which takes
|
||||
# the status fd with it unless we set FD_CLOEXEC. Failing to do this
|
||||
@@ -100,8 +108,24 @@ class XendServers:
|
||||
status.write('0')
|
||||
status.close()
|
||||
|
||||
for t in threads:
|
||||
t.join()
|
||||
# Prepare to catch SIGTERM (received when 'xend stop' is executed)
|
||||
# and call each server's cleanup if possible
|
||||
signal.signal(signal.SIGTERM, self.cleanup)
|
||||
|
||||
# Interruptible Thread.join - Python Bug #1167930
|
||||
# Replaces: for t in threads: t.join()
|
||||
# Reason: The above will cause python signal handlers to be
|
||||
# blocked so we're not able to catch SIGTERM in any
|
||||
# way for cleanup
|
||||
runningThreads = len([t for t in threads if t.isAlive()])
|
||||
while runningThreads > 0:
|
||||
try:
|
||||
for t in threads:
|
||||
t.join(1.0)
|
||||
runningThreads = len([t for t in threads if t.isAlive()])
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def create():
|
||||
root = SrvDir()
|
||||
|
||||
@@ -16,16 +16,15 @@
|
||||
# Copyright (C) 2006 XenSource Ltd.
|
||||
#============================================================================
|
||||
|
||||
from types import ListType
|
||||
import xmlrpclib
|
||||
|
||||
from xen.xend import XendDomain, XendDomainInfo, XendNode, \
|
||||
XendLogging, XendDmesg
|
||||
from xen.util.xmlrpclib2 import UnixXMLRPCServer, TCPXMLRPCServer
|
||||
|
||||
from xen.xend.XendClient import XML_RPC_SOCKET, ERROR_INVALID_DOMAIN
|
||||
from xen.xend.XendError import *
|
||||
from xen.xend import XendDomain, XendDomainInfo, XendNode
|
||||
from xen.xend import XendLogging, XendDmesg
|
||||
from xen.xend.XendClient import XML_RPC_SOCKET
|
||||
from xen.xend.XendLogging import log
|
||||
from types import ListType
|
||||
from xen.xend.XendError import XendInvalidDomain
|
||||
|
||||
def lookup(domid):
|
||||
info = XendDomain.instance().domain_lookup_by_name_or_id(domid)
|
||||
@@ -75,8 +74,8 @@ def get_log():
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
methods = ['device_create', 'device_configure', 'destroyDevice',
|
||||
'getDeviceSxprs',
|
||||
methods = ['device_create', 'device_configure',
|
||||
'destroyDevice','getDeviceSxprs',
|
||||
'setMemoryTarget', 'setName', 'setVCpuCount', 'shutdown',
|
||||
'send_sysrq', 'getVCPUInfo', 'waitForDevices',
|
||||
'getRestartCount']
|
||||
@@ -84,25 +83,33 @@ methods = ['device_create', 'device_configure', 'destroyDevice',
|
||||
exclude = ['domain_create', 'domain_restore']
|
||||
|
||||
class XMLRPCServer:
|
||||
def __init__(self, use_tcp=False):
|
||||
self.ready = False
|
||||
def __init__(self, use_tcp=False, host = "localhost", port = 8006,
|
||||
path = XML_RPC_SOCKET):
|
||||
self.use_tcp = use_tcp
|
||||
self.port = port
|
||||
self.host = host
|
||||
self.path = path
|
||||
|
||||
self.ready = False
|
||||
self.running = True
|
||||
|
||||
def run(self):
|
||||
if self.use_tcp:
|
||||
# bind to something fixed for now as we may eliminate
|
||||
# tcp support completely.
|
||||
self.server = TCPXMLRPCServer(("localhost", 8005), logRequests=False)
|
||||
self.server = TCPXMLRPCServer((self.host, self.port),
|
||||
logRequests = False)
|
||||
else:
|
||||
self.server = UnixXMLRPCServer(XML_RPC_SOCKET, False)
|
||||
self.server = UnixXMLRPCServer(self.path, logRequests = False)
|
||||
|
||||
# Legacy deprecated xm xmlrpc api
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
# Functions in XendDomainInfo
|
||||
for name in methods:
|
||||
fn = eval("lambda domid, *args: dispatch(domid, '%s', args)"%name)
|
||||
self.server.register_function(fn, "xend.domain.%s" % name)
|
||||
|
||||
# Functions in XendDomain
|
||||
inst = XendDomain.instance()
|
||||
|
||||
for name in dir(inst):
|
||||
fn = getattr(inst, name)
|
||||
if name.startswith("domain_") and callable(fn):
|
||||
@@ -126,4 +133,20 @@ class XMLRPCServer:
|
||||
|
||||
self.server.register_introspection_functions()
|
||||
self.ready = True
|
||||
self.server.serve_forever()
|
||||
|
||||
# Custom runloop so we can cleanup when exiting.
|
||||
# -----------------------------------------------------------------
|
||||
try:
|
||||
self.server.socket.settimeout(1.0)
|
||||
while self.running:
|
||||
self.server.handle_request()
|
||||
finally:
|
||||
self.cleanup()
|
||||
|
||||
def cleanup(self):
|
||||
log.debug("XMLRPCServer.cleanup()")
|
||||
|
||||
def shutdown(self):
|
||||
self.running = False
|
||||
self.ready = False
|
||||
|
||||