ia64/xen-unstable

view tools/python/xen/xend/XendClient.py @ 7174:600f3d2b78d6

Remove the reason code from the destroy action -- the reason is only of value
on a graceful shutdown. Clarify the semantic difference between poweroff and
halt (we use halt to mean 'shutdown and stop' and poweroff to mean 'shutdown
and do whatever the configured behaviour is').

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author emellor@ewan
date Tue Oct 04 00:56:24 2005 +0100 (2005-10-04)
parents 9e0b6fbab872
children f5320ac7ed31
line source
1 #!/usr/bin/env python
2 #============================================================================
3 # This library is free software; you can redistribute it and/or
4 # modify it under the terms of version 2.1 of the GNU Lesser General Public
5 # License as published by the Free Software Foundation.
6 #
7 # This library is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 # Lesser General Public License for more details.
11 #
12 # You should have received a copy of the GNU Lesser General Public
13 # License along with this library; if not, write to the Free Software
14 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 #============================================================================
16 # Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
17 #============================================================================
19 """Client API for the HTTP interface on xend.
20 Callable as a script - see main().
21 Supports inet or unix connection to xend.
23 This API is the 'control-plane' for xend.
24 The 'data-plane' is done separately.
25 """
26 import os
27 import sys
28 import types
30 import sxp
31 import PrettyPrint
32 from XendProtocol import HttpXendClientProtocol, \
33 UnixXendClientProtocol, \
34 XendError
36 def fileof(val):
37 """Converter for passing configs or other 'large' data.
38 Handles lists, files directly.
39 Assumes a string is a file name and passes its contents.
40 """
41 if isinstance(val, types.ListType):
42 return sxp.to_string(val)
43 if isinstance(val, types.StringType):
44 return file(val)
45 if hasattr(val, 'readlines'):
46 return val
47 raise XendError('cannot convert value')
49 class URL:
50 """A URL.
51 """
53 def __init__(self, proto='http', host='localhost', port=None, path='', query=None, frag=None):
54 self.proto = proto
55 self.host = host
56 if port: port = int(port)
57 self.port = port
58 self.path = path
59 self.query = query
60 self.frag = frag
62 def url(self):
63 """Get the full URL string including protocol, location and the full path.
64 """
65 return self.proto + '://' + self.location() + self.fullpath()
67 def location(self):
68 """Get the location part of the URL, including host and port, if present.
69 """
70 if self.port:
71 return self.host + ':' + str(self.port)
72 else:
73 return self.host
75 def fullpath(self):
76 """Get the full path part of the URL, including query and fragment if present.
77 """
78 u = [ self.path ]
79 if self.query:
80 u.append('?')
81 u.append(self.query)
82 if self.frag:
83 u.append('#')
84 u.append(self.frag)
85 return ''.join(u)
87 def relative(self, path='', query=None, frag=None):
88 """Create a URL relative to this one.
89 """
90 return URL(proto=self.proto,
91 host=self.host,
92 port=self.port,
93 path=self.path + path,
94 query=query,
95 frag=frag)
97 class Xend:
98 """Client interface to Xend.
99 """
101 """Default location of the xend server."""
102 SRV_DEFAULT = "localhost:8000"
104 """Environment variable to set the location of xend."""
105 SRV_VAR = "XEND"
107 """Default path to the xend root on the server."""
108 ROOT_DEFAULT = "/xend/"
110 """Environment variable to set the xend root path."""
111 ROOT_VAR = "XEND_ROOT"
113 def __init__(self, client=None, srv=None, root=None):
114 """Create a xend client interface.
115 If the client protocol is not specified, the default
116 is to use a synchronous protocol.
118 @param client: client protocol to use
119 @param srv: server host, and optional port (format host:port)
120 @param root: xend root path on the server
121 """
122 if client is None:
123 client = HttpXendClientProtocol()
124 self.client = client
125 self.bind(srv, root)
127 def default_server(self):
128 """Get the default location of the xend server.
129 """
130 return os.getenv(self.SRV_VAR, self.SRV_DEFAULT)
132 def default_root(self):
133 """Get the default root path on the xend server.
134 """
135 return os.getenv(self.ROOT_VAR, self.ROOT_DEFAULT)
137 def bind(self, srv=None, root=None):
138 """Bind to a given server.
140 @param srv: server location (host:port)
141 @param root: xend root path on the server
142 """
143 if srv is None: srv = self.default_server()
144 if root is None: root = self.default_root()
145 if not root.endswith('/'): root += '/'
146 (host, port) = srv.split(':', 1)
147 self.url = URL(host=host, port=port, path=root)
149 def xendGet(self, url, args=None):
150 return self.client.xendGet(url, args)
152 def xendPost(self, url, data):
153 return self.client.xendPost(url, data)
155 def nodeurl(self, id=''):
156 return self.url.relative('node/' + str(id))
158 def domainurl(self, id=''):
159 return self.url.relative('domain/' + str(id))
161 def deviceurl(self, id=''):
162 return self.url.relative('device/' + str(id))
164 def vneturl(self, id=''):
165 return self.url.relative('vnet/' + str(id))
167 def xend(self):
168 return self.xendGet(self.url)
170 def xend_node(self):
171 return self.xendGet(self.nodeurl())
173 def xend_node_shutdown(self):
174 return self.xendPost(self.nodeurl(),
175 {'op' : 'shutdown'})
177 def xend_node_restart(self):
178 return self.xendPost(self.nodeurl(),
179 {'op' : 'reboot'})
181 def xend_node_get_dmesg(self):
182 return self.xendGet(self.nodeurl('dmesg'))
184 def xend_node_clear_dmesg(self):
185 return self.xendPost(self.nodeurl('dmesg'),
186 {'op' : 'clear' } )
188 def xend_node_log(self):
189 return self.xendGet(self.nodeurl('log'))
191 def xend_node_cpu_bvt_slice_set(self, ctx_allow):
192 return self.xendPost(self.nodeurl(),
193 {'op' : 'cpu_bvt_slice_set',
194 'ctx_allow' : ctx_allow })
196 def xend_domains(self):
197 return self.xendGet(self.domainurl())
199 def xend_domain_create(self, conf):
200 return self.xendPost(self.domainurl(),
201 {'op' : 'create',
202 'config' : fileof(conf) })
204 def xend_domain_restore(self, filename):
205 return self.xendPost(self.domainurl(),
206 {'op' : 'restore',
207 'file' : filename })
209 def xend_domain_configure(self, id, conf):
210 return self.xendPost(self.domainurl(id),
211 {'op' : 'configure',
212 'config' : fileof(conf) })
214 def xend_domain(self, id):
215 return self.xendGet(self.domainurl(id))
217 def xend_domain_unpause(self, id):
218 return self.xendPost(self.domainurl(id),
219 {'op' : 'unpause' })
221 def xend_domain_pause(self, id):
222 return self.xendPost(self.domainurl(id),
223 {'op' : 'pause' })
225 def xend_domain_shutdown(self, id, reason):
226 return self.xendPost(self.domainurl(id),
227 {'op' : 'shutdown',
228 'reason' : reason})
230 def xend_domain_sysrq(self, id, key):
231 return self.xendPost(self.domainurl(id),
232 {'op' : 'sysrq',
233 'key' : key})
235 def xend_domain_destroy(self, id):
236 return self.xendPost(self.domainurl(id),
237 {'op' : 'destroy' })
239 def xend_domain_save(self, id, filename):
240 return self.xendPost(self.domainurl(id),
241 {'op' : 'save',
242 'file' : filename })
244 def xend_domain_migrate(self, id, dst, live=0, resource=0):
245 return self.xendPost(self.domainurl(id),
246 {'op' : 'migrate',
247 'destination': dst,
248 'live' : live,
249 'resource' : resource })
251 def xend_domain_pincpu(self, id, vcpu, cpumap):
252 return self.xendPost(self.domainurl(id),
253 {'op' : 'pincpu',
254 'vcpu' : vcpu,
255 'cpumap' : cpumap })
257 def xend_domain_cpu_bvt_set(self, id, mcuadv, warpback, warpvalue, warpl, warpu):
258 return self.xendPost(self.domainurl(id),
259 {'op' : 'cpu_bvt_set',
260 'mcuadv' : mcuadv,
261 'warpback' : warpback,
262 'warpvalue': warpvalue,
263 'warpl' : warpl,
264 'warpu' : warpu })
266 def xend_domain_cpu_sedf_set(self, id, period, slice, latency, extratime, weight):
267 return self.xendPost(self.domainurl(id),
268 {'op' : 'cpu_sedf_set',
269 'period' : period,
270 'slice' : slice,
271 'latency' : latency,
272 'extratime' : extratime,
273 'weight' : weight })
275 def xend_domain_maxmem_set(self, id, memory):
276 return self.xendPost(self.domainurl(id),
277 { 'op' : 'maxmem_set',
278 'memory' : memory })
280 def xend_domain_mem_target_set(self, id, mem_target):
281 val = self.xendPost(self.domainurl(id),
282 {'op' : 'mem_target_set',
283 'target' : mem_target })
284 return val
286 def xend_domain_vcpu_hotplug(self, id, vcpu, state):
287 return self.xendPost(self.domainurl(id),
288 {'op' : 'vcpu_hotplug',
289 'vcpu' : vcpu,
290 'state' : state })
292 def xend_domain_vif_limit(self, id, vif, credit, period):
293 return self.xendPost(self.domainurl(id),
294 { 'op' : 'vif_limit_set',
295 'vif' : vif,
296 'credit' : credit,
297 'period' : period })
299 def xend_domain_devices(self, id, type):
300 return self.xendPost(self.domainurl(id),
301 {'op' : 'devices',
302 'type' : type })
304 def xend_domain_device_create(self, id, config):
305 return self.xendPost(self.domainurl(id),
306 {'op' : 'device_create',
307 'config' : fileof(config) })
309 def xend_domain_device_refresh(self, id, type, idx):
310 return self.xendPost(self.domainurl(id),
311 {'op' : 'device_refresh',
312 'type' : type,
313 'idx' : idx })
315 def xend_domain_device_destroy(self, id, type, idx):
316 return self.xendPost(self.domainurl(id),
317 {'op' : 'device_destroy',
318 'type' : type,
319 'idx' : idx })
321 def xend_domain_device_configure(self, id, config, idx):
322 return self.xendPost(self.domainurl(id),
323 {'op' : 'device_configure',
324 'idx' : idx,
325 'config' : fileof(config) })
327 def xend_vnets(self):
328 return self.xendGet(self.vneturl())
330 def xend_vnet_create(self, conf):
331 return self.xendPost(self.vneturl(),
332 {'op' : 'create',
333 'config' : fileof(conf) })
335 def xend_vnet(self, id):
336 return self.xendGet(self.vneturl(id))
338 def xend_vnet_delete(self, id):
339 return self.xendPost(self.vneturl(id),
340 {'op' : 'delete' })
342 def getHttpServer(srv=None):
343 """Create and return a xend client.
344 """
345 return Xend(srv=srv, client=XendClientProtocol())
347 def getUnixServer(srv=None):
348 """Create and return a unix-domain xend client.
349 """
350 return Xend(client=UnixXendClientProtocol(srv))
352 def xendmain(srv, fn, args, unix=False):
353 if unix:
354 xend = getUnixServer(srv)
355 else:
356 xend = getHttpServer(srv)
357 xend.rc = 0
358 try:
359 v = getattr(xend, fn)(*args)
360 PrettyPrint.prettyprint(v)
361 return 0
362 except XendError, err:
363 print 'ERROR:', err
364 return 1
366 def main(argv):
367 """Call an API function:
369 python XendClient.py fn args...
371 The leading 'xend_' on the function can be omitted.
372 Example:
374 python XendClient.py domains
375 (0 8)
376 python XendClient.py domain 0
377 (domain (id 0) (name Domain-0) (memory 128))
378 """
379 from getopt import getopt
380 short_options = 'x:au:d'
381 long_options = ['xend=', 'unix=', 'debug']
382 (options, args) = getopt(argv[1:], short_options, long_options)
383 srv = None
384 unix = 1
385 for k, v in options:
386 if k in ['-x', '--xend']:
387 srv = v
388 elif k in ['-u', '--unix']:
389 unix = int(v)
390 if len(args):
391 fn = args[0]
392 args = args[1:]
393 else:
394 fn = 'xend'
395 args = []
396 if not fn.startswith('xend'):
397 fn = 'xend_' + fn
398 sys.exit(xendmain(srv, fn, args, unix=unix))
400 if __name__ == "__main__":
401 main(sys.argv)
402 else:
403 server = getUnixServer()