ia64/xen-unstable

view tools/python/scripts/xapi.py @ 19527:0e24e9674ded

tools: Always use sane upstream (`native') python paths

Previously, by default we would install our python modules into
/usr/lib/python/xen, for example /usr/lib/python/xen/__init__.py.
Upstream python's standard install location (a) includes the Python
version number and (b) puts things in site-packages by default.

Our best conjecture for the reason for this was an attempt to make the
installs portable between different python versions. However, that
doesn't work because compiled python modules (.pyc), and C python
extensions corresponding to one version of python, are not compatible
across different versions of python.

This is why upstream include the version number.

site-packages is the standard location for locally-installed packages
and is automatically included on the python search path.

In this change, we abandon our own unusual python path setup:

* Invoke setup.py in an entirely standard manner. We pass
PREFIX and DESTDIR using the appropriate options provided by
setup.py for those purposes (adding them to setup.py calls
which were previously lacking them).

* Since the installation locations are now on the standard
python path, we no longer need to add anything to the path
in any of our python utilities. Therefore remove all that
code from every python script. (Many of these scripts
unconditionally added /usr/lib/python and /usr/lib64/python which
is wrong even in the old world.)

* There is no longer any special `Xen python path'. xen-python-path
is no longer needed. It is no longer called by anything in our
tree. However since out-of-tree callers may still invoke it, we
retain it. It now prints a fixed string referring to a directory
which does not to exist; callers (who use it to augment their
python path) will thus add a nonexistent directory to their python
path which is harmless.

* Remove various workarounds including use of setup.py --home
(which is intended for something completely different).

* Remove tests for the XEN_PYTHON_NATIVE_INSTALL build-time
environment variable. The new behaviour is the behaviour which we
should have had if this variable had been set. That is, it is now
as if this variable was always set but also bugs in the resulting
install have been fixed.

This should be a proper fix for the bug addressed by c/s 19515.

Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Apr 08 19:13:04 2009 +0100 (2009-04-08)
parents 2adbc1d22fe7
children
line source
1 #!/usr/bin/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) 2006 XenSource Ltd.
17 #============================================================================
19 import sys
20 import time
21 import re
22 import os
24 from xen.util.xmlrpclib2 import ServerProxy
25 from optparse import *
26 from pprint import pprint
27 from types import DictType
28 from getpass import getpass
30 # Get default values from the environment
31 SERVER_URI = os.environ.get('XAPI_SERVER_URI', 'http://localhost:9363/')
32 SERVER_USER = os.environ.get('XAPI_SERVER_USER', '')
33 SERVER_PASS = os.environ.get('XAPI_SERVER_PASS', '')
35 MB = 1024 * 1024
37 HOST_INFO_FORMAT = '%-20s: %-50s'
38 VM_LIST_FORMAT = '%(name_label)-18s %(memory_actual)-5s %(VCPUs_number)-5s'\
39 ' %(power_state)-10s %(uuid)-36s'
40 SR_LIST_FORMAT = '%(name_label)-18s %(uuid)-36s %(physical_size)-10s' \
41 '%(type)-10s'
42 VDI_LIST_FORMAT = '%(name_label)-18s %(uuid)-36s %(virtual_size)-8s'
43 VBD_LIST_FORMAT = '%(device)-6s %(uuid)-36s %(VDI)-8s'
44 TASK_LIST_FORMAT = '%(name_label)-18s %(uuid)-36s %(status)-8s %(progress)-4s'
45 VIF_LIST_FORMAT = '%(name)-8s %(device)-7s %(uuid)-36s %(MAC)-10s'
46 CONSOLE_LIST_FORMAT = '%(uuid)-36s %(protocol)-8s %(location)-32s'
48 COMMANDS = {
49 'host-info': ('', 'Get Xen Host Info'),
50 'host-set-name': ('', 'Set host name'),
51 'pif-list': ('', 'List all PIFs'),
52 'sr-list': ('', 'List all SRs'),
53 'vbd-list': ('', 'List all VBDs'),
54 'vbd-create': ('<domname> <pycfg> [opts]',
55 'Create VBD attached to domname'),
56 'vdi-create': ('<pycfg> [opts]', 'Create a VDI'),
57 'vdi-list' : ('', 'List all VDI'),
58 'vdi-rename': ('<vdi_uuid> <new_name>', 'Rename VDI'),
59 'vdi-destroy': ('<vdi_uuid>', 'Delete VDI'),
60 'vif-create': ('<domname> <pycfg>', 'Create VIF attached to domname'),
61 'vtpm-create' : ('<domname> <pycfg>', 'Create VTPM attached to domname'),
63 'vm-create': ('<pycfg>', 'Create VM with python config'),
64 'vm-destroy': ('<domname>', 'Delete VM'),
66 'vm-list': ('[--long]', 'List all domains.'),
67 'vm-name': ('<uuid>', 'Name of UUID.'),
68 'vm-shutdown': ('<name> [opts]', 'Shutdown VM with name'),
69 'vm-start': ('<name>', 'Start VM with name'),
70 'vm-uuid': ('<name>', 'UUID of a domain by name.'),
71 'async-vm-start': ('<name>', 'Start VM asynchronously'),
72 }
74 OPTIONS = {
75 'sr-list': [(('-l', '--long'),
76 {'action':'store_true',
77 'help':'List all properties of SR'})
78 ],
80 'vdi-list': [(('-l', '--long'),
81 {'action':'store_true',
82 'help':'List all properties of VDI'})
83 ],
84 'vif-list': [(('-l', '--long'),
85 {'action':'store_true',
86 'help':'List all properties of VIF'})
87 ],
88 'vm-list': [(('-l', '--long'),
89 {'action':'store_true',
90 'help':'List all properties of VMs'})
91 ],
92 'vm-shutdown': [(('-f', '--force'), {'help': 'Shutdown Forcefully',
93 'action': 'store_true'})],
95 'vdi-create': [(('--name-label',), {'help': 'Name for VDI'}),
96 (('--name-description',), {'help': 'Description for VDI'}),
97 (('--virtual-size',), {'type': 'int',
98 'default': 0,
99 'help': 'Size of VDI in bytes'}),
100 (('--type',), {'choices': ['system', 'user', 'ephemeral'],
101 'default': 'system',
102 'help': 'VDI type'}),
103 (('--sharable',), {'action': 'store_true',
104 'help': 'VDI sharable'}),
105 (('--read-only',), {'action': 'store_true',
106 'help': 'Read only'}),
107 (('--sr',), {})],
109 'vbd-create': [(('--VDI',), {'help': 'UUID of VDI to attach to.'}),
110 (('--mode',), {'choices': ['RO', 'RW'],
111 'help': 'device mount mode'}),
112 (('--driver',), {'choices':['paravirtualised', 'ioemu'],
113 'help': 'Driver for VBD'}),
114 (('--device',), {'help': 'Device name on guest domain'})]
116 }
118 class OptionError(Exception):
119 pass
121 class XenAPIError(Exception):
122 pass
124 #
125 # Extra utility functions
126 #
128 class IterableValues(Values):
129 """Better interface to the list of values from optparse."""
131 def __iter__(self):
132 for opt, val in self.__dict__.items():
133 if opt[0] == '_' or callable(val):
134 continue
135 yield opt, val
138 def parse_args(cmd_name, args, set_defaults = False):
139 argstring, desc = COMMANDS[cmd_name]
140 parser = OptionParser(usage = 'xapi %s %s' % (cmd_name, argstring),
141 description = desc)
142 if cmd_name in OPTIONS:
143 for optargs, optkwds in OPTIONS[cmd_name]:
144 parser.add_option(*optargs, **optkwds)
146 if set_defaults:
147 default_values = parser.get_default_values()
148 defaults = IterableValues(default_values.__dict__)
149 else:
150 defaults = IterableValues()
151 (opts, extraargs) = parser.parse_args(args = list(args),
152 values = defaults)
153 return opts, extraargs
155 def execute(server, fn, args, async = False):
156 if async:
157 func = eval('server.Async.%s' % fn)
158 else:
159 func = eval('server.%s' % fn)
161 result = func(*args)
162 if type(result) != DictType:
163 raise TypeError("Function returned object of type: %s" %
164 str(type(result)))
165 if 'Value' not in result:
166 raise XenAPIError(*result['ErrorDescription'])
167 return result['Value']
169 _initialised = False
170 _server = None
171 _session = None
172 def connect(*args):
173 global _server, _session, _initialised
175 if not _initialised:
176 # try without password or default credentials
177 try:
178 _server = ServerProxy(SERVER_URI)
179 _session = execute(_server.session, 'login_with_password',
180 (SERVER_USER, SERVER_PASS))
181 except:
182 login = raw_input("Login: ")
183 password = getpass()
184 creds = (login, password)
185 _server = ServerProxy(SERVER_URI)
186 _session = execute(_server.session, 'login_with_password',
187 creds)
189 _initialised = True
190 return (_server, _session)
192 def _stringify(adict):
193 return dict([(k, str(v)) for k, v in adict.items()])
195 def _read_python_cfg(filename):
196 cfg = {}
197 execfile(filename, {}, cfg)
198 return cfg
200 def resolve_vm(server, session, vm_name):
201 vm_uuid = execute(server, 'VM.get_by_name_label', (session, vm_name))
202 if not vm_uuid:
203 return None
204 else:
205 return vm_uuid[0]
207 def resolve_vdi(server, session, vdi_name):
208 vdi_uuid = execute(server, 'VDI.get_by_name_label', (session, vdi_name))
209 if not vdi_uuid:
210 return None
211 else:
212 return vdi_uuid[0]
214 #
215 # Actual commands
216 #
218 def xapi_host_info(args, async = False):
219 server, session = connect()
220 hosts = execute(server, 'host.get_all', (session,))
221 for host in hosts: # there is only one, but ..
222 hostinfo = execute(server, 'host.get_record', (session, host))
223 print HOST_INFO_FORMAT % ('Name', hostinfo['name_label'])
224 print HOST_INFO_FORMAT % ('Version', hostinfo['software_version'])
225 print HOST_INFO_FORMAT % ('CPUs', len(hostinfo['host_CPUs']))
226 print HOST_INFO_FORMAT % ('VMs', len(hostinfo['resident_VMs']))
227 print HOST_INFO_FORMAT % ('UUID', host)
229 for host_cpu_uuid in hostinfo['host_CPUs']:
230 host_cpu = execute(server, 'host_cpu.get_record',
231 (session, host_cpu_uuid))
232 print 'CPU %s Util: %.2f' % (host_cpu['number'],
233 float(host_cpu['utilisation']))
235 def xapi_host_set_name(args, async = False):
236 if len(args) < 1:
237 raise OptionError("No hostname specified")
239 server, session = connect()
240 hosts = execute(server, 'host.get_all', (session,))
241 if len(hosts) > 0:
242 execute(server, 'host.set_name_label', (session, hosts[0], args[0]))
243 print 'Hostname: %s' % execute(server, 'host.get_name_label',
244 (session, hosts[0]))
246 def xapi_vm_uuid(args, async = False):
247 if len(args) < 1:
248 raise OptionError("No domain name specified")
250 server, session = connect()
251 vm_uuid = resolve_vm(server, session, args[0])
252 print vm_uuid
254 def xapi_vm_name(args, async = False):
255 if len(args) < 1:
256 raise OptionError("No UUID specified")
258 server, session = connect()
259 vm_name = execute(server, 'VM.get_name_label', (session, args[0]))
260 print vm_name
262 def xapi_vm_list(args, async = False):
263 opts, args = parse_args('vm-list', args, set_defaults = True)
264 is_long = opts and opts.long
266 list_only = args
268 server, session = connect()
269 vm_uuids = execute(server, 'VM.get_all', (session,))
270 if not is_long:
271 print VM_LIST_FORMAT % {'name_label':'Name',
272 'memory_actual':'Mem',
273 'VCPUs_number': 'VCPUs',
274 'power_state': 'State',
275 'uuid': 'UUID'}
277 for uuid in vm_uuids:
278 vm_info = execute(server, 'VM.get_record', (session, uuid))
280 # skip domain if we don't want
281 if list_only and vm_info['name_label'] not in list_only:
282 continue
284 if is_long:
285 vbds = vm_info['VBDs']
286 vifs = vm_info['VIFs']
287 vtpms = vm_info['VTPMs']
288 vif_infos = []
289 vbd_infos = []
290 vtpm_infos = []
291 for vbd in vbds:
292 vbd_info = execute(server, 'VBD.get_record', (session, vbd))
293 vbd_infos.append(vbd_info)
294 for vif in vifs:
295 vif_info = execute(server, 'VIF.get_record', (session, vif))
296 vif_infos.append(vif_info)
297 for vtpm in vtpms:
298 vtpm_info = execute(server, 'VTPM.get_record', (session, vtpm))
299 vtpm_infos.append(vtpm_info)
300 vm_info['VBDs'] = vbd_infos
301 vm_info['VIFs'] = vif_infos
302 vm_info['VTPMs'] = vtpm_infos
303 pprint(vm_info)
304 else:
305 print VM_LIST_FORMAT % _stringify(vm_info)
307 def xapi_vm_create(args, async = False):
308 if len(args) < 1:
309 raise OptionError("Configuration file not specified")
311 filename = args[0]
312 cfg = _read_python_cfg(filename)
314 print 'Creating VM from %s ..' % filename
315 server, session = connect()
316 uuid = execute(server, 'VM.create', (session, cfg), async = async)
317 print 'Done. (%s)' % uuid
318 print uuid
320 def xapi_vm_destroy(args, async = False):
321 if len(args) < 1:
322 raise OptionError("No domain name specified.")
324 server, session = connect()
325 vm_uuid = resolve_vm(server, session, args[0])
326 print 'Destroying VM %s (%s)' % (args[0], vm_uuid)
327 success = execute(server, 'VM.destroy', (session, vm_uuid), async = async)
328 print 'Done.'
331 def xapi_vm_start(args, async = False):
332 if len(args) < 1:
333 raise OptionError("No Domain name specified.")
335 server, session = connect()
336 vm_uuid = resolve_vm(server, session, args[0])
337 print 'Starting VM %s (%s)' % (args[0], vm_uuid)
338 success = execute(server, 'VM.start', (session, vm_uuid, False), async = async)
339 if async:
340 print 'Task started: %s' % success
341 else:
342 print 'Done.'
344 def xapi_vm_suspend(args, async = False):
345 if len(args) < 1:
346 raise OptionError("No Domain name specified.")
348 server, session = connect()
349 vm_uuid = resolve_vm(server, session, args[0])
350 print 'Suspending VM %s (%s)' % (args[0], vm_uuid)
351 success = execute(server, 'VM.suspend', (session, vm_uuid), async = async)
352 if async:
353 print 'Task started: %s' % success
354 else:
355 print 'Done.'
358 def xapi_vm_resume(args, async = False):
359 if len(args) < 1:
360 raise OptionError("No Domain name specified.")
362 server, session = connect()
363 vm_uuid = resolve_vm(server, session, args[0])
364 print 'Resuming VM %s (%s)' % (args[0], vm_uuid)
365 success = execute(server, 'VM.resume', (session, vm_uuid, False), async = async)
366 if async:
367 print 'Task started: %s' % success
368 else:
369 print 'Done.'
371 def xapi_vm_pause(args, async = False):
372 if len(args) < 1:
373 raise OptionError("No Domain name specified.")
375 server, session = connect()
376 vm_uuid = resolve_vm(server, session, args[0])
377 print 'Pausing VM %s (%s)' % (args[0], vm_uuid)
378 success = execute(server, 'VM.pause', (session, vm_uuid), async = async)
379 if async:
380 print 'Task started: %s' % success
381 else:
382 print 'Done.'
384 def xapi_vm_unpause(args, async = False):
385 if len(args) < 1:
386 raise OptionError("No Domain name specified.")
388 server, session = connect()
389 vm_uuid = resolve_vm(server, session, args[0])
390 print 'Pausing VM %s (%s)' % (args[0], vm_uuid)
391 success = execute(server, 'VM.unpause', (session, vm_uuid), async = async)
392 if async:
393 print 'Task started: %s' % success
394 else:
395 print 'Done.'
397 def xapi_task_list(args, async = False):
398 server, session = connect()
399 all_tasks = execute(server, 'task.get_all', (session,))
401 print TASK_LIST_FORMAT % {'name_label': 'Task Name',
402 'uuid': 'UUID',
403 'status': 'Status',
404 'progress': '%'}
406 for task_uuid in all_tasks:
407 task = execute(server, 'task.get_record', (session, task_uuid))
408 print TASK_LIST_FORMAT % task
410 def xapi_task_clear(args, async = False):
411 server, session = connect()
412 all_tasks = execute(server, 'task.get_all', (session,))
413 for task_uuid in all_tasks:
414 success = execute(server, 'task.destroy', (session, task_uuid))
415 print 'Destroyed Task %s' % task_uuid
417 def xapi_vm_shutdown(args, async = False):
418 opts, args = parse_args("vm-shutdown", args, set_defaults = True)
420 if len(args) < 1:
421 raise OptionError("No Domain name specified.")
423 server, session = connect()
424 vm_uuid = resolve_vm(server, session, args[0])
425 if opts.force:
426 print 'Forcefully shutting down VM %s (%s)' % (args[0], vm_uuid)
427 success = execute(server, 'VM.hard_shutdown', (session, vm_uuid), async = async)
428 else:
429 print 'Shutting down VM %s (%s)' % (args[0], vm_uuid)
430 success = execute(server, 'VM.clean_shutdown', (session, vm_uuid), async = async)
432 if async:
433 print 'Task started: %s' % success
434 else:
435 print 'Done.'
437 def xapi_vbd_create(args, async = False):
438 opts, args = parse_args('vbd-create', args)
440 if len(args) < 2:
441 raise OptionError("Configuration file and domain not specified")
443 domname = args[0]
445 if len(args) > 1:
446 filename = args[1]
447 cfg = _read_python_cfg(filename)
448 else:
449 cfg = {}
451 for opt, val in opts:
452 cfg[opt] = val
454 print 'Creating VBD ...',
455 server, session = connect()
456 vm_uuid = resolve_vm(server, session, domname)
457 cfg['VM'] = vm_uuid
458 vbd_uuid = execute(server, 'VBD.create', (session, cfg), async = async)
459 if async:
460 print 'Task started: %s' % vbd_uuid
461 else:
462 print 'Done. (%s)' % vbd_uuid
464 def xapi_vif_create(args, async = False):
465 if len(args) < 2:
466 raise OptionError("Configuration file not specified")
468 domname = args[0]
469 filename = args[1]
470 cfg = _read_python_cfg(filename)
472 print 'Creating VIF from %s ..' % filename
473 server, session = connect()
474 vm_uuid = resolve_vm(server, session, domname)
475 cfg['VM'] = vm_uuid
476 vif_uuid = execute(server, 'VIF.create', (session, cfg), async = async)
477 if async:
478 print 'Task started: %s' % vif_uuid
479 else:
480 print 'Done. (%s)' % vif_uuid
482 def xapi_vbd_list(args, async = False):
483 server, session = connect()
484 domname = args[0]
486 dom_uuid = resolve_vm(server, session, domname)
487 vbds = execute(server, 'VM.get_VBDs', (session, dom_uuid))
489 print VBD_LIST_FORMAT % {'device': 'Device',
490 'uuid' : 'UUID',
491 'VDI': 'VDI'}
493 for vbd in vbds:
494 vbd_struct = execute(server, 'VBD.get_record', (session, vbd))
495 print VBD_LIST_FORMAT % vbd_struct
498 def xapi_vbd_stats(args, async = False):
499 server, session = connect()
500 domname = args[0]
501 dom_uuid = resolve_vm(server, session, domname)
503 vbds = execute(server, 'VM.get_VBDs', (session, dom_uuid))
504 for vbd_uuid in vbds:
505 print execute(server, 'VBD.get_io_read_kbs', (session, vbd_uuid))
507 def xapi_vif_list(args, async = False):
508 server, session = connect()
509 opts, args = parse_args('vdi-list', args, set_defaults = True)
510 is_long = opts and opts.long
512 domname = args[0]
514 dom_uuid = resolve_vm(server, session, domname)
515 vifs = execute(server, 'VM.get_VIFs', (session, dom_uuid))
517 if not is_long:
518 print VIF_LIST_FORMAT % {'name': 'Name',
519 'device': 'Device',
520 'uuid' : 'UUID',
521 'MAC': 'MAC'}
523 for vif in vifs:
524 vif_struct = execute(server, 'VIF.get_record', (session, vif))
525 print VIF_LIST_FORMAT % vif_struct
526 else:
527 for vif in vifs:
528 vif_struct = execute(server, 'VIF.get_record', (session, vif))
529 pprint(vif_struct)
531 def xapi_console_list(args, async = False):
532 server, session = connect()
533 opts, args = parse_args('vdi-list', args, set_defaults = True)
534 is_long = opts and opts.long
536 domname = args[0]
538 dom_uuid = resolve_vm(server, session, domname)
539 consoles = execute(server, 'VM.get_consoles', (session, dom_uuid))
541 if not is_long:
542 print CONSOLE_LIST_FORMAT % {'protocol': 'Protocol',
543 'location': 'Location',
544 'uuid': 'UUID'}
546 for console in consoles:
547 console_struct = execute(server, 'console.get_record',
548 (session, console))
549 print CONSOLE_LIST_FORMAT % console_struct
550 else:
551 for console in consoles:
552 console_struct = execute(server, 'console.get_record',
553 (session, console))
554 pprint(console_struct)
557 def xapi_vdi_list(args, async = False):
558 opts, args = parse_args('vdi-list', args, set_defaults = True)
559 is_long = opts and opts.long
561 server, session = connect()
562 vdis = execute(server, 'VDI.get_all', (session,))
564 if not is_long:
565 print VDI_LIST_FORMAT % {'name_label': 'VDI Label',
566 'uuid' : 'UUID',
567 'virtual_size': 'Bytes'}
569 for vdi in vdis:
570 vdi_struct = execute(server, 'VDI.get_record', (session, vdi))
571 print VDI_LIST_FORMAT % vdi_struct
573 else:
574 for vdi in vdis:
575 vdi_struct = execute(server, 'VDI.get_record', (session, vdi))
576 pprint(vdi_struct)
578 def xapi_sr_list(args, async = False):
579 opts, args = parse_args('sr-list', args, set_defaults = True)
580 is_long = opts and opts.long
582 server, session = connect()
583 srs = execute(server, 'SR.get_all', (session,))
584 if not is_long:
585 print SR_LIST_FORMAT % {'name_label': 'SR Label',
586 'uuid' : 'UUID',
587 'physical_size': 'Size (MB)',
588 'type': 'Type'}
590 for sr in srs:
591 sr_struct = execute(server, 'SR.get_record', (session, sr))
592 sr_struct['physical_size'] = int(sr_struct['physical_size'])/MB
593 print SR_LIST_FORMAT % sr_struct
594 else:
595 for sr in srs:
596 sr_struct = execute(server, 'SR.get_record', (session, sr))
597 pprint(sr_struct)
599 def xapi_sr_rename(args, async = False):
600 server, session = connect()
601 sr = execute(server, 'SR.get_by_name_label', (session, args[0]))
602 execute(server, 'SR.set_name_label', (session, sr[0], args[1]))
604 def xapi_vdi_create(args, async = False):
605 opts, args = parse_args('vdi-create', args)
607 if len(args) > 0:
608 cfg = _read_python_cfg(args[0])
609 else:
610 cfg = {}
612 for opt, val in opts:
613 cfg[opt] = val
615 server, session = connect()
616 srs = []
617 if cfg.get('SR'):
618 srs = execute(server, 'SR.get_by_name_label', (session, cfg['SR']))
619 else:
620 srs = execute(server, 'SR.get_all', (session,))
622 sr = srs[0]
623 cfg['SR'] = sr
625 size = cfg['virtual_size']/MB
626 print 'Creating VDI of size: %dMB ..' % size,
627 uuid = execute(server, 'VDI.create', (session, cfg), async = async)
628 if async:
629 print 'Task started: %s' % uuid
630 else:
631 print 'Done. (%s)' % uuid
634 def xapi_vdi_destroy(args, async = False):
635 server, session = connect()
636 if len(args) < 1:
637 raise OptionError('Not enough arguments')
639 vdi_uuid = args[0]
640 print 'Deleting VDI %s' % vdi_uuid
641 result = execute(server, 'VDI.destroy', (session, vdi_uuid), async = async)
642 if async:
643 print 'Task started: %s' % result
644 else:
645 print 'Done.'
647 def xapi_vdi_rename(args, async = False):
648 server, session = connect()
649 if len(args) < 2:
650 raise OptionError('Not enough arguments')
652 vdi_uuid = execute(server, 'VDI.get_by_name_label', session, args[0])
653 vdi_name = args[1]
655 print 'Renaming VDI %s to %s' % (vdi_uuid[0], vdi_name)
656 result = execute(server, 'VDI.set_name_label',
657 (session, vdi_uuid[0], vdi_name), async = async)
658 if async:
659 print 'Task started: %s' % result
660 else:
661 print 'Done.'
665 def xapi_vtpm_create(args, async = False):
666 server, session = connect()
667 domname = args[0]
668 cfg = _read_python_cfg(args[1])
670 vm_uuid = resolve_vm(server, session, domname)
671 cfg['VM'] = vm_uuid
672 print "Creating vTPM with cfg = %s" % cfg
673 vtpm_uuid = execute(server, 'VTPM.create', (session, cfg))
674 print "Done. (%s)" % vtpm_uuid
677 def xapi_pif_list(args, async = False):
678 server, session = connect()
679 pif_uuids = execute(server, 'PIF.get_all', (session,))
680 for pif_uuid in pif_uuids:
681 pif = execute(server, 'PIF.get_record', (session, pif_uuid))
682 print pif
685 def xapi_debug_wait(args, async = False):
686 secs = 10
687 if len(args) > 0:
688 secs = int(args[0])
689 server, session = connect()
690 task_uuid = execute(server, 'debug.wait', (session, secs), async=async)
691 print 'Task UUID: %s' % task_uuid
693 def xapi_vm_stat(args, async = False):
694 domname = args[0]
696 server, session = connect()
697 vm_uuid = resolve_vm(server, session, domname)
698 vif_uuids = execute(server, 'VM.get_VIFs', (session, vm_uuid))
699 vbd_uuids = execute(server, 'VM.get_VBDs', (session, vm_uuid))
700 vcpus_utils = execute(server, 'VM.get_VCPUs_utilisation',
701 (session, vm_uuid))
703 for vcpu_num in sorted(vcpus_utils.keys()):
704 print 'CPU %s : %5.2f%%' % (vcpu_num, vcpus_utils[vcpu_num] * 100)
706 for vif_uuid in vif_uuids:
707 vif = execute(server, 'VIF.get_record', (session, vif_uuid))
708 print '%(device)s: rx: %(io_read_kbs)10.2f tx: %(io_write_kbs)10.2f' \
709 % vif
710 for vbd_uuid in vbd_uuids:
711 vbd = execute(server, 'VBD.get_record', (session, vbd_uuid))
712 print '%(device)s: rd: %(io_read_kbs)10.2f wr: %(io_write_kbs)10.2f' \
713 % vbd
715 #
716 # Command Line Utils
717 #
718 import cmd
719 import shlex
721 class XenAPICmd(cmd.Cmd):
722 def __init__(self, server, session):
723 cmd.Cmd.__init__(self)
724 self.server = server
725 self.session = session
726 self.prompt = ">>> "
728 def default(self, line):
729 words = shlex.split(line)
730 if len(words) > 0:
731 cmd_name = words[0].replace('-', '_')
732 is_async = 'async' in cmd_name
733 if is_async:
734 cmd_name = re.sub('async_', '', cmd_name)
736 func_name = 'xapi_%s' % cmd_name
737 func = globals().get(func_name)
739 if func:
740 try:
741 args = tuple(words[1:])
742 func(args, async = is_async)
743 return True
744 except SystemExit:
745 return False
746 except OptionError, e:
747 print 'Error:', str(e)
748 return False
749 except Exception, e:
750 import traceback
751 traceback.print_exc()
752 return False
753 print '*** Unknown command: %s' % words[0]
754 return False
756 def do_EOF(self, line):
757 print
758 sys.exit(0)
760 def do_help(self, line):
761 usage(print_usage = False)
763 def emptyline(self):
764 pass
766 def postcmd(self, stop, line):
767 return False
769 def precmd(self, line):
770 words = shlex.split(line)
771 if len(words) > 0:
772 words0 = words[0].replace('-', '_')
773 return ' '.join([words0] + words[1:])
774 else:
775 return line
777 def shell():
778 server, session = connect()
779 x = XenAPICmd(server, session)
780 x.cmdloop('Xen API Prompt. Type "help" for a list of functions')
782 def usage(command = None, print_usage = True):
783 if not command:
784 if print_usage:
785 print 'Usage: xapi <subcommand> [options] [args]'
786 print
787 print 'Subcommands:'
788 print
790 for func in sorted(globals().keys()):
791 if func.startswith('xapi_'):
792 command = func[5:].replace('_', '-')
793 args, description = COMMANDS.get(command, ('', ''))
794 print '%-16s %-40s' % (command, description)
795 print
796 else:
797 parse_args(command, ['-h'])
799 def main(args):
801 # poor man's optparse that doesn't abort on unrecognised opts
803 options = {}
804 remaining = []
806 arg_n = 0
807 while args:
808 arg = args.pop(0)
810 if arg in ('--help', '-h'):
811 options['help'] = True
812 elif arg in ('--server', '-s') and args:
813 options['server'] = args.pop(0)
814 elif arg in ('--user', '-u') and args:
815 options['user'] = args.pop(0)
816 elif arg in ('--password', '-p') and args:
817 options['password'] = args.pop(0)
818 else:
819 remaining.append(arg)
821 # abort here if these conditions are true
823 if options.get('help') and not remaining:
824 usage()
825 sys.exit(1)
827 if options.get('help') and remaining:
828 usage(remaining[0])
829 sys.exit(1)
831 if not remaining:
832 usage()
833 sys.exit(1)
835 if options.get('server'):
836 # it is ugly to use a global, but it is simple
837 global SERVER_URI
838 SERVER_URI = options['server']
840 if options.get('user'):
841 global SERVER_USER
842 SERVER_USER = options['user']
844 if options.get('password'):
845 global SERVER_PASS
846 SERVER_PASS = options['password']
848 subcmd = remaining[0].replace('-', '_')
849 is_async = 'async' in subcmd
850 if is_async:
851 subcmd = re.sub('async_', '', subcmd)
852 subcmd_func_name = 'xapi_' + subcmd
853 subcmd_func = globals().get(subcmd_func_name, None)
855 if subcmd == 'shell':
856 shell()
857 elif not subcmd_func or not callable(subcmd_func):
858 print 'Error: Unable to find subcommand \'%s\'' % subcmd
859 usage()
860 sys.exit(1)
862 try:
863 subcmd_func(remaining[1:], async = is_async)
864 except XenAPIError, e:
865 print 'Error: %s' % str(e.args[0])
866 sys.exit(2)
867 except OptionError, e:
868 print 'Error: %s' % e
870 sys.exit(0)
872 if __name__ == "__main__":
873 import sys
874 main(sys.argv[1:])