debuggers.hg

view tools/python/xen/xend/server/XMLRPCServer.py @ 16559:5255eac35270

Implement legacy XML-RPC interface for ACM commands.

This patch implements a (non Xen-API) legacy XML-RPC interface for the
ACM commands and funnels the calls into code introduced by the Xen-API
support for ACM security management. Since some of the functionality
has changed, also the xm applications have changed. In particular the
following old commands have been removed along with some tools the
have become obsolete now:

- loadpolicy (included in: setpolicy)
- makepolicy (included in: setpolicy)
- cfgbootpolicy (included in: setpolicy)

and the following commands been introduced:

- setpolicy
- getpolicy
- resetpolicy

All tools have been adapted to work in Xen-API and legacy XML-RPC
mode. Both modes support the same functionality.

Signed-off-by: Stefan Berger <stefanb@us.ibm.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Dec 05 09:44:20 2007 +0000 (2007-12-05)
parents 0c14d0bf369e
children a762b4aed1a8
line source
1 #============================================================================
2 # This library is free software; you can redistribute it and/or
3 # modify it under the terms of version 2.1 of the GNU Lesser General Public
4 # License as published by the Free Software Foundation.
5 #
6 # This library is distributed in the hope that it will be useful,
7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9 # Lesser General Public License for more details.
10 #
11 # You should have received a copy of the GNU Lesser General Public
12 # License along with this library; if not, write to the Free Software
13 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14 #============================================================================
15 # Copyright (C) 2006 Anthony Liguori <aliguori@us.ibm.com>
16 # Copyright (C) 2006 XenSource Ltd.
17 #============================================================================
19 import errno
20 import socket
21 import types
22 import xmlrpclib
23 from xen.util.xmlrpclib2 import UnixXMLRPCServer, TCPXMLRPCServer
24 try:
25 from SSLXMLRPCServer import SSLXMLRPCServer
26 ssl_enabled = True
27 except ImportError:
28 ssl_enabled = False
30 from xen.xend import XendAPI, XendDomain, XendDomainInfo, XendNode
31 from xen.xend import XendLogging, XendDmesg
32 from xen.xend.XendClient import XML_RPC_SOCKET
33 from xen.xend.XendConstants import DOM_STATE_RUNNING
34 from xen.xend.XendLogging import log
35 from xen.xend.XendError import XendInvalidDomain
37 # vcpu_avail is a long and is not needed by the clients. It's far easier
38 # to just remove it then to try and marshal the long.
39 def fixup_sxpr(sexpr):
40 ret = []
41 for k in sexpr:
42 if type(k) in (list, tuple):
43 if len(k) != 2 or k[0] != 'vcpu_avail':
44 ret.append(fixup_sxpr(k))
45 else:
46 ret.append(k)
47 return ret
49 def lookup(domid):
50 info = XendDomain.instance().domain_lookup(domid)
51 return info
53 def dispatch(domid, fn, args):
54 info = lookup(domid)
55 return getattr(info, fn)(*args)
57 def domain(domid, full = 0):
58 info = lookup(domid)
59 return fixup_sxpr(info.sxpr(not full))
61 def domains(detail = True, full = False):
62 return domains_with_state(detail, DOM_STATE_RUNNING, full)
64 def domains_with_state(detail, state, full):
65 if detail:
66 domains = XendDomain.instance().list_sorted(state)
67 return map(lambda dom: fixup_sxpr(dom.sxpr(not full)), domains)
68 else:
69 return XendDomain.instance().list_names(state)
71 def domain_create(config):
72 info = XendDomain.instance().domain_create(config)
73 return fixup_sxpr(info.sxpr())
75 def domain_restore(src, paused=False):
76 info = XendDomain.instance().domain_restore(src, paused)
77 return fixup_sxpr(info.sxpr())
79 def get_log():
80 f = open(XendLogging.getLogFilename(), 'r')
81 try:
82 return f.read()
83 finally:
84 f.close()
86 methods = ['device_create', 'device_configure',
87 'destroyDevice','getDeviceSxprs',
88 'setMemoryTarget', 'setName', 'setVCpuCount', 'shutdown',
89 'send_sysrq', 'getVCPUInfo', 'waitForDevices',
90 'getRestartCount', 'getBlockDeviceClass']
92 exclude = ['domain_create', 'domain_restore']
94 class XMLRPCServer:
95 def __init__(self, auth, use_xenapi, use_tcp = False,
96 ssl_key_file = None, ssl_cert_file = None,
97 host = "localhost", port = 8006, path = XML_RPC_SOCKET,
98 hosts_allowed = None):
100 self.use_tcp = use_tcp
101 self.port = port
102 self.host = host
103 self.path = path
104 self.hosts_allowed = hosts_allowed
106 self.ssl_key_file = ssl_key_file
107 self.ssl_cert_file = ssl_cert_file
109 self.ready = False
110 self.running = True
111 self.auth = auth
112 self.xenapi = use_xenapi and XendAPI.XendAPI(auth) or None
114 def run(self):
115 authmsg = (self.auth == XendAPI.AUTH_NONE and
116 "; authentication has been disabled for this server." or
117 ".")
119 try:
120 if self.use_tcp:
121 using_ssl = self.ssl_key_file and self.ssl_cert_file
123 log.info("Opening %s XML-RPC server on %s%d%s",
124 using_ssl and 'HTTPS' or 'TCP',
125 self.host and '%s:' % self.host or
126 'all interfaces, port ',
127 self.port, authmsg)
129 if using_ssl:
130 if not ssl_enabled:
131 raise ValueError("pyOpenSSL not installed. "
132 "Unable to start HTTPS XML-RPC server")
133 self.server = SSLXMLRPCServer(
134 (self.host, self.port),
135 self.hosts_allowed,
136 self.xenapi is not None,
137 logRequests = False,
138 ssl_key_file = self.ssl_key_file,
139 ssl_cert_file = self.ssl_cert_file)
140 else:
141 self.server = TCPXMLRPCServer(
142 (self.host, self.port),
143 self.hosts_allowed,
144 self.xenapi is not None,
145 logRequests = False)
147 else:
148 log.info("Opening Unix domain socket XML-RPC server on %s%s",
149 self.path, authmsg)
150 self.server = UnixXMLRPCServer(self.path, self.hosts_allowed,
151 self.xenapi is not None,
152 logRequests = False)
153 except socket.error, exn:
154 log.error('Cannot start server: %s!', exn.args[1])
155 ready = True
156 running = False
157 return
158 except Exception, e:
159 log.exception('Cannot start server: %s!', e)
160 ready = True
161 running = False
162 return
164 # Register Xen API Functions
165 # -------------------------------------------------------------------
166 # exportable functions are ones that do not begin with '_'
167 # and has the 'api' attribute.
169 for meth_name in dir(self.xenapi):
170 if meth_name[0] != '_':
171 meth = getattr(self.xenapi, meth_name)
172 if callable(meth) and hasattr(meth, 'api'):
173 self.server.register_function(meth, getattr(meth, 'api'))
175 self.server.register_instance(XendAPI.XendAPIAsyncProxy(self.xenapi))
177 # Legacy deprecated xm xmlrpc api
178 # --------------------------------------------------------------------
180 # Functions in XendDomainInfo
181 for name in methods:
182 fn = eval("lambda domid, *args: dispatch(domid, '%s', args)"%name)
183 self.server.register_function(fn, "xend.domain.%s" % name)
185 inst = XendDomain.instance()
187 for name in dir(inst):
188 fn = getattr(inst, name)
189 if name.startswith("domain_") and callable(fn):
190 if name not in exclude:
191 self.server.register_function(fn, "xend.domain.%s" % name[7:])
193 # Functions in XendNode and XendDmesg
194 for type, lst, n in [(XendNode, ['info', 'send_debug_keys'], 'node'),
195 (XendDmesg, ['info', 'clear'], 'node.dmesg')]:
196 inst = type.instance()
197 for name in lst:
198 self.server.register_function(getattr(inst, name),
199 "xend.%s.%s" % (n, name))
201 # A few special cases
202 self.server.register_function(domain, 'xend.domain')
203 self.server.register_function(domains, 'xend.domains')
204 self.server.register_function(domains_with_state,
205 'xend.domains_with_state')
206 self.server.register_function(get_log, 'xend.node.log')
207 self.server.register_function(domain_create, 'xend.domain.create')
208 self.server.register_function(domain_restore, 'xend.domain.restore')
210 # A couple of the security functions
211 from xen.util.xsm import xsm as security
212 for name in security.xmlrpc_exports:
213 fn = getattr(security, name)
214 self.server.register_function(fn, "xend.security.%s" % name)
216 self.server.register_introspection_functions()
217 self.ready = True
219 # Custom runloop so we can cleanup when exiting.
220 # -----------------------------------------------------------------
221 try:
222 while self.running:
223 self.server.handle_request()
224 finally:
225 self.shutdown()
227 def cleanup(self):
228 log.debug('XMLRPCServer.cleanup()')
229 if hasattr(self, 'server'):
230 try:
231 # This is here to make sure the socket is actually
232 # cleaned up when close() is called. Otherwise
233 # SO_REUSEADDR doesn't take effect. To replicate,
234 # try 'xend reload' and look for EADDRINUSE.
235 #
236 # May be caued by us calling close() outside of
237 # the listen()ing thread.
238 self.server.socket.shutdown(2)
239 except socket.error, e:
240 pass # ignore any socket errors
241 try:
242 self.server.socket.close()
243 except socket.error, e:
244 pass
246 def shutdown(self):
247 self.running = False
248 if self.ready:
249 self.ready = False
250 self.cleanup()