ia64/xen-unstable

view tools/python/xen/xm/main.py @ 7078:fa4cc3f53c64

This patch adds a quick check to 'xm restore' that checks the
existence and readability of the file given.

This fixes the issue detected in xm-tests 03_restore_badparm_neg and
04_restore_badfilename_neg.

Signed-off-by: Dan Smith <danms@us.ibm.com>
Signed-off-by: Ewan Mellor <ewan@xensource.com>
author emellor@ewan
date Tue Sep 27 15:10:38 2005 +0100 (2005-09-27)
parents c9d690c52afc
children da98f8956925 9e0b6fbab872
line source
1 # (C) Copyright IBM Corp. 2005
2 # Copyright (C) 2004 Mike Wray
3 # Copyright (c) 2005 XenSource Ltd
4 #
5 # Authors:
6 # Sean Dague <sean at dague dot net>
7 # Mike Wray <mike dot wray at hp dot com>
8 #
9 # This library is free software; you can redistribute it and/or
10 # modify it under the terms of version 2.1 of the GNU Lesser General Public
11 # License as published by the Free Software Foundation.
12 #
13 # This library is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 # Lesser General Public License for more details.
17 #
18 # You should have received a copy of the GNU Lesser General Public
19 # License along with this library; if not, write to the Free Software
20 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 """Grand unified management application for Xen.
23 """
24 import os
25 import os.path
26 import sys
27 import commands
28 import re
29 from getopt import getopt
30 import socket
31 import warnings
32 warnings.filterwarnings('ignore', category=FutureWarning)
33 from xen.xend import PrettyPrint
34 from xen.xend import sxp
35 from xen.xm.opts import *
36 shorthelp = """Usage: xm <subcommand> [args]
37 Control, list, and manipulate Xen guest instances
39 xm common subcommands:
40 console <DomId> attach to console of DomId
41 create <CfgFile> create a domain based on Config File
42 destroy <DomId> terminate a domain immediately
43 help display this message
44 list [DomId, ...] list information about domains
45 mem-max <DomId> <Mem> set the maximum memory reservation for a domain
46 mem-set <DomId> <Mem> adjust the current memory usage for a domain
47 migrate <DomId> <Host> migrate a domain to another machine
48 pause <DomId> pause execution of a domain
49 reboot <DomId> reboot a domain
50 restore <File> create a domain from a saved state file
51 save <DomId> <File> save domain state (and config) to file
52 shutdown <DomId> shutdown a domain
53 top monitor system and domains in real-time
54 unpause <DomId> unpause a paused domain
56 For a complete list of subcommands run 'xm help --long'
57 For more help on xm see the xm(1) man page
58 For more help on xm create, see the xmdomain.cfg(5) man page"""
60 longhelp = """Usage: xm <subcommand> [args]
61 Control, list, and manipulate Xen guest instances
63 xm full list of subcommands:
65 Domain Commands:
66 console <DomId> attach to console of DomId
67 cpus-list <DomId> <VCpu> get the list of cpus for a VCPU
68 create <ConfigFile> create a domain
69 destroy <DomId> terminate a domain immediately
70 domid <DomName> convert a domain name to a domain id
71 domname <DomId> convert a domain id to a domain name
72 list list information about domains
73 mem-max <DomId> <Mem> set domain maximum memory limit
74 mem-set <DomId> <Mem> set the domain's memory dynamically
75 migrate <DomId> <Host> migrate a domain to another machine
76 pause <DomId> pause execution of a domain
77 reboot [-w|-a] <DomId> reboot a domain
78 restore <File> create a domain from a saved state file
79 save <DomId> <File> save domain state (and config) to file
80 shutdown [-w|-a] <DomId> shutdown a domain
81 sysrq <DomId> <letter> send a sysrq to a domain
82 unpause <DomId> unpause a paused domain
83 vcpu-enable <DomId> <VCPU> disable VCPU in a domain
84 vcpu-disable <DomId> <VCPU> enable VCPU in a domain
85 vcpu-list <DomId> get the list of VCPUs for a domain
86 vcpu-pin <DomId> <VCpu> <CPUS> set which cpus a VCPU can use.
88 Xen Host Commands:
89 dmesg [--clear] read or clear Xen's message buffer
90 info get information about the xen host
91 log print the xend log
92 top monitor system and domains in real-time
94 Scheduler Commands:
95 sched-bvt <options> set BVT scheduler parameters
96 sched-bvt-ctxallow <Allow>
97 Set the BVT scheduler context switch allowance
98 sched-sedf <options> set simple EDF parameters
100 Virtual Device Commands:
101 block-attach <DomId> <BackDev> <FrontDev> <Mode> [BackDomId]
102 Create a new virtual block device
103 block-detach <DomId> <DevId> Destroy a domain's virtual block device
104 block-list <DomId> List virtual block devices for a domain
105 block-refresh <DomId> <DevId> Refresh a virtual block device for a domain
106 network-limit <DomId> <Vif> <Credit> <Period>
107 Limit the transmission rate of a virtual network interface
108 network-list <DomId> List virtual network interfaces for a domain
110 Vnet commands:
111 vnet-list [-l|--long] list vnets
112 vnet-create <config> create a vnet from a config file
113 vnet-delete <vnetid> delete a vnet
115 For a short list of subcommands run 'xm help'
116 For more help on xm see the xm(1) man page
117 For more help on xm create, see the xmdomain.cfg(5) man page"""
119 ####################################################################
120 #
121 # Utility functions
122 #
123 ####################################################################
125 def arg_check(args,num,name):
126 if len(args) < num:
127 err("'xm %s' requires %s argument(s)!\n" % (name, num))
128 usage(name)
130 def unit(c):
131 if not c.isalpha():
132 return 0
133 base = 1
134 if c == 'G' or c == 'g': base = 1024 * 1024 * 1024
135 elif c == 'M' or c == 'm': base = 1024 * 1024
136 elif c == 'K' or c == 'k': base = 1024
137 else:
138 print 'ignoring unknown unit'
139 return base
141 def int_unit(str, dest):
142 base = unit(str[-1])
143 if not base:
144 return int(str)
146 value = int(str[:-1])
147 dst_base = unit(dest)
148 if dst_base == 0:
149 dst_base = 1
150 if dst_base > base:
151 return value / (dst_base / base)
152 else:
153 return value * (base / dst_base)
155 def err(msg):
156 print >>sys.stderr, "Error:", msg
158 def handle_xend_error(cmd, dom, ex):
159 error = str(ex)
160 if error == "Not found" and dom != None:
161 err("Domain '%s' not found when running 'xm %s'" % (dom, cmd))
162 sys.exit(1)
163 else:
164 raise ex
167 #########################################################################
168 #
169 # Main xm functions
170 #
171 #########################################################################
173 def xm_save(args):
174 arg_check(args,2,"save")
176 dom = args[0] # TODO: should check if this exists
177 savefile = os.path.abspath(args[1])
179 if not os.access(os.path.dirname(savefile), os.W_OK):
180 err("xm save: Unable to create file %s" % savefile)
181 sys.exit(1)
183 from xen.xend.XendClient import server
184 server.xend_domain_save(dom, savefile)
186 def xm_restore(args):
187 arg_check(args,1,"restore")
189 savefile = os.path.abspath(args[0])
191 if not os.access(savefile, os.R_OK):
192 err("xm restore: Unable to read file %s" % savefile)
193 sys.exit(1)
195 from xen.xend.XendClient import server
196 info = server.xend_domain_restore(savefile)
197 PrettyPrint.prettyprint(info)
198 id = sxp.child_value(info, 'domid')
199 if id is not None:
200 server.xend_domain_unpause(domid)
202 def xm_list(args):
203 use_long = 0
204 show_vcpus = 0
205 try:
206 (options, params) = getopt(args, 'lv', ['long','vcpus'])
207 except GetoptError, opterr:
208 err(opterr)
209 sys.exit(1)
211 n = len(params)
212 for (k, v) in options:
213 if k in ['-l', '--long']:
214 use_long = 1
215 if k in ['-v', '--vcpus']:
216 show_vcpus = 1
218 domsinfo = []
219 from xen.xend.XendClient import server
220 if n == 0:
221 doms = server.xend_domains()
222 doms.sort()
223 else:
224 doms = params
225 for dom in doms:
226 info = server.xend_domain(dom)
227 domsinfo.append(parse_doms_info(info))
229 if use_long:
230 for dom in doms:
231 info = server.xend_domain(dom)
232 PrettyPrint.prettyprint(info)
233 elif show_vcpus:
234 xm_show_vcpus(domsinfo)
235 else:
236 xm_brief_list(domsinfo)
238 def parse_doms_info(info):
239 dominfo = {}
240 dominfo['dom'] = int(sxp.child_value(info, 'domid', '-1'))
241 dominfo['name'] = sxp.child_value(info, 'name', '??')
242 dominfo['mem'] = int(sxp.child_value(info, 'memory', '0'))
243 dominfo['cpu'] = str(sxp.child_value(info, 'cpu', '0'))
244 dominfo['vcpus'] = int(sxp.child_value(info, 'vcpus', '0'))
245 # if there is more than 1 cpu, the value doesn't mean much
246 if dominfo['vcpus'] > 1:
247 dominfo['cpu'] = '-'
248 dominfo['state'] = sxp.child_value(info, 'state', '??')
249 dominfo['cpu_time'] = float(sxp.child_value(info, 'cpu_time', '0'))
250 # security identifiers
251 if ((int(sxp.child_value(info, 'ssidref', '0'))) != 0):
252 dominfo['ssidref1'] = int(sxp.child_value(info, 'ssidref', '0')) & 0xffff
253 dominfo['ssidref2'] = (int(sxp.child_value(info, 'ssidref', '0')) >> 16) & 0xffff
254 # get out the vcpu information
255 dominfo['vcpulist'] = []
256 vcpu_to_cpu = sxp.child_value(info, 'vcpu_to_cpu', '-1').split('|')
257 cpumap = sxp.child_value(info, 'cpumap', [])
258 mask = ((int(sxp.child_value(info, 'vcpus', '0')))**2) - 1
259 count = 0
260 for cpu in vcpu_to_cpu:
261 vcpuinfo = {}
262 vcpuinfo['name'] = sxp.child_value(info, 'name', '??')
263 vcpuinfo['dom'] = int(sxp.child_value(info, 'domid', '-1'))
264 vcpuinfo['vcpu'] = int(count)
265 vcpuinfo['cpu'] = int(cpu)
266 vcpuinfo['cpumap'] = int(cpumap[count])&mask
267 count = count + 1
268 dominfo['vcpulist'].append(vcpuinfo)
269 return dominfo
271 def xm_brief_list(domsinfo):
272 print 'Name Id Mem(MB) CPU VCPU(s) State Time(s)'
273 for dominfo in domsinfo:
274 if dominfo.has_key("ssidref1"):
275 print ("%(name)-16s %(dom)3d %(mem)7d %(cpu)3s %(vcpus)5d %(state)5s %(cpu_time)7.1f s:%(ssidref2)02x/p:%(ssidref1)02x" % dominfo)
276 else:
277 print ("%(name)-16s %(dom)3d %(mem)7d %(cpu)3s %(vcpus)5d %(state)5s %(cpu_time)7.1f" % dominfo)
279 def xm_show_vcpus(domsinfo):
280 print 'Name Id VCPU CPU CPUMAP'
281 for dominfo in domsinfo:
282 for vcpuinfo in dominfo['vcpulist']:
283 print ("%(name)-16s %(dom)3d %(vcpu)4d %(cpu)3d 0x%(cpumap)x" %
284 vcpuinfo)
286 def xm_vcpu_list(args):
287 xm_list(["-v"] + args)
289 def xm_reboot(args):
290 arg_check(args,1,"reboot")
291 from xen.xm import shutdown
292 # ugly hack because the opt parser apparently wants
293 # the subcommand name just to throw it away!
294 shutdown.main(["bogus", "-R"] + args)
296 def xm_pause(args):
297 arg_check(args, 1, "pause")
298 dom = args[0]
300 from xen.xend.XendClient import server
301 server.xend_domain_pause(dom)
303 def xm_unpause(args):
304 arg_check(args, 1, "unpause")
305 dom = args[0]
307 from xen.xend.XendClient import server
308 server.xend_domain_unpause(dom)
310 def xm_subcommand(command, args):
311 cmd = __import__(command, globals(), locals(), 'xen.xm')
312 cmd.main(["bogus"] + args)
315 #############################################################
317 def cpu_make_map(cpulist):
318 cpus = []
319 cpumap = 0
320 for c in cpulist.split(','):
321 if c.find('-') != -1:
322 (x,y) = c.split('-')
323 for i in range(int(x),int(y)+1):
324 cpus.append(int(i))
325 else:
326 cpus.append(int(c))
327 cpus.sort()
328 for c in cpus:
329 cpumap = cpumap | 1<<c
331 return cpumap
333 def xm_vcpu_pin(args):
334 arg_check(args, 3, "vcpu-pin")
336 dom = args[0]
337 vcpu = int(args[1])
338 cpumap = cpu_make_map(args[2])
340 from xen.xend.XendClient import server
341 server.xend_domain_pincpu(dom, vcpu, cpumap)
343 def xm_mem_max(args):
344 arg_check(args, 2, "mem-max")
346 dom = args[0]
347 mem = int_unit(args[1], 'm')
349 from xen.xend.XendClient import server
350 server.xend_domain_maxmem_set(dom, mem)
352 def xm_mem_set(args):
353 arg_check(args, 2, "mem-set")
355 dom = args[0]
356 mem_target = int_unit(args[1], 'm')
358 from xen.xend.XendClient import server
359 server.xend_domain_mem_target_set(dom, mem_target)
361 # TODO: why does this lookup by name? and what if that fails!?
362 def xm_vcpu_enable(args):
363 arg_check(args, 2, "vcpu-enable")
365 name = args[0]
366 vcpu = int(args[1])
368 from xen.xend.XendClient import server
369 dom = server.xend_domain(name)
370 id = sxp.child_value(dom, 'domid')
371 server.xend_domain_vcpu_hotplug(id, vcpu, 1)
373 def xm_vcpu_disable(args):
374 arg_check(args, 2, "vcpu-disable")
376 name = args[0]
377 vcpu = int(args[1])
379 from xen.xend.XendClient import server
380 dom = server.xend_domain(name)
381 id = sxp.child_value(dom, 'domid')
382 server.xend_domain_vcpu_hotplug(id, vcpu, 0)
384 def xm_domid(args):
385 name = args[0]
387 from xen.xend.XendClient import server
388 dom = server.xend_domain(name)
389 print sxp.child_value(dom, 'domid')
391 def xm_domname(args):
392 name = args[0]
394 from xen.xend.XendClient import server
395 dom = server.xend_domain(name)
396 print sxp.child_value(dom, 'name')
398 def xm_sched_bvt(args):
399 arg_check(args, 6, "sched-bvt")
400 dom = args[0]
401 v = map(long, args[1:6])
402 from xen.xend.XendClient import server
403 server.xend_domain_cpu_bvt_set(dom, *v)
405 def xm_sched_bvt_ctxallow(args):
406 arg_check(args, 1, "sched-bvt-ctxallow")
408 slice = int(args[0])
409 from xen.xend.XendClient import server
410 server.xend_node_cpu_bvt_slice_set(slice)
412 def xm_sched_sedf(args):
413 arg_check(args, 6, "sched-sedf")
415 dom = args[0]
416 v = map(int, args[1:6])
417 from xen.xend.XendClient import server
418 server.xend_domain_cpu_sedf_set(dom, *v)
420 def xm_info(args):
421 from xen.xend.XendClient import server
422 info = server.xend_node()
424 for x in info[1:]:
425 if len(x) < 2:
426 print "%-23s: (none)" % x[0]
427 else:
428 print "%-23s:" % x[0], x[1]
430 # TODO: remove as soon as console server shows up
431 def xm_console(args):
432 arg_check(args,1,"console")
434 dom = args[0]
435 from xen.xend.XendClient import server
436 info = server.xend_domain(dom)
437 domid = int(sxp.child_value(info, 'domid', '-1'))
438 cmd = "/usr/libexec/xen/xenconsole %d" % domid
439 os.execvp('/usr/libexec/xen/xenconsole', cmd.split())
440 console = sxp.child(info, "console")
442 def xm_top(args):
443 os.execv('/usr/sbin/xentop', ['/usr/sbin/xentop'])
445 def xm_dmesg(args):
447 gopts = Opts(use="""[-c|--clear]
449 Read Xen's message buffer (boot output, warning and error messages) or clear
450 its contents if the [-c|--clear] flag is specified.
451 """)
453 gopts.opt('clear', short='c',
454 fn=set_true, default=0,
455 use="Clear the contents of the Xen message buffer.")
456 # Work around for gopts
457 myargs = args
458 myargs.insert(0, "bogus")
459 gopts.parse(myargs)
460 if not (1 <= len(myargs) <= 2):
461 err('Invalid arguments: ' + str(myargs))
463 from xen.xend.XendClient import server
464 if not gopts.vals.clear:
465 print server.xend_node_get_dmesg()
466 else:
467 server.xend_node_clear_dmesg()
469 def xm_log(args):
470 from xen.xend.XendClient import server
471 print server.xend_node_log()
473 def xm_network_limit(args):
474 arg_check(args,4,"network-limit")
475 dom = args[0]
476 v = map(int, args[1:4])
477 from xen.xend.XendClient import server
478 server.xend_domain_vif_limit(dom, *v)
480 def xm_network_list(args):
481 arg_check(args,1,"network-list")
482 dom = args[0]
483 from xen.xend.XendClient import server
484 for x in server.xend_domain_devices(dom, 'vif'):
485 sxp.show(x)
486 print
488 def xm_block_list(args):
489 arg_check(args,1,"block-list")
490 dom = args[0]
491 from xen.xend.XendClient import server
492 for x in server.xend_domain_devices(dom, 'vbd'):
493 sxp.show(x)
494 print
496 def xm_block_attach(args):
497 n = len(args)
498 if n == 0:
499 usage("block-attach")
501 if n < 4 or n > 5:
502 err("%s: Invalid argument(s)" % args[0])
503 usage("block-attach")
505 dom = args[0]
506 vbd = ['vbd',
507 ['uname', args[1]],
508 ['dev', args[2]],
509 ['mode', args[3]]]
510 if n == 5:
511 vbd.append(['backend', args[4]])
513 from xen.xend.XendClient import server
514 server.xend_domain_device_create(dom, vbd)
516 def xm_block_refresh(args):
517 arg_check(args,2,"block-refresh")
519 dom = args[0]
520 dev = args[1]
522 from xen.xend.XendClient import server
523 server.xend_domain_device_refresh(dom, 'vbd', dev)
525 def xm_block_detach(args):
526 arg_check(args,2,"block-detach")
528 dom = args[0]
529 dev = args[1]
531 from xen.xend.XendClient import server
532 server.xend_domain_device_destroy(dom, 'vbd', dev)
534 def xm_vnet_list(args):
535 from xen.xend.XendClient import server
536 try:
537 (options, params) = getopt(args, 'l', ['long'])
538 except GetoptError, opterr:
539 err(opterr)
540 sys.exit(1)
542 use_long = 0
543 for (k, v) in options:
544 if k in ['-l', '--long']:
545 use_long = 1
547 if params:
548 use_long = 1
549 vnets = params
550 else:
551 vnets = server.xend_vnets()
553 for vnet in vnets:
554 try:
555 if use_long:
556 info = server.xend_vnet(vnet)
557 PrettyPrint.prettyprint(info)
558 else:
559 print vnet
560 except Exception, ex:
561 print vnet, ex
563 def xm_vnet_create(args):
564 arg_check(args, 1, "vnet-create")
565 conf = args[0]
566 from xen.xend.XendClient import server
567 server.xend_vnet_create(conf)
569 def xm_vnet_delete(args):
570 arg_check(args, 1, "vnet-delete")
571 vnet = args[0]
572 from xen.xend.XendClient import server
573 server.xend_vnet_delete(vnet)
575 commands = {
576 # console commands
577 "console": xm_console,
578 # xenstat commands
579 "top": xm_top,
580 # domain commands
581 "domid": xm_domid,
582 "domname": xm_domname,
583 "restore": xm_restore,
584 "save": xm_save,
585 "reboot": xm_reboot,
586 "list": xm_list,
587 # memory commands
588 "mem-max": xm_mem_max,
589 "mem-set": xm_mem_set,
590 # cpu commands
591 "vcpu-pin": xm_vcpu_pin,
592 # "cpus-list": xm_cpus_list,
593 "vcpu-enable": xm_vcpu_enable,
594 "vcpu-disable": xm_vcpu_disable,
595 "vcpu-list": xm_vcpu_list,
596 # special
597 "pause": xm_pause,
598 "unpause": xm_unpause,
599 # host commands
600 "dmesg": xm_dmesg,
601 "info": xm_info,
602 "log": xm_log,
603 # scheduler
604 "sched-bvt": xm_sched_bvt,
605 "sched-bvt-ctxallow": xm_sched_bvt_ctxallow,
606 "sched-sedf": xm_sched_sedf,
607 # block
608 "block-attach": xm_block_attach,
609 "block-detach": xm_block_detach,
610 "block-list": xm_block_list,
611 "block-refresh": xm_block_refresh,
612 # network
613 "network-limit": xm_network_limit,
614 "network-list": xm_network_list,
615 # vnet
616 "vnet-list": xm_vnet_list,
617 "vnet-create": xm_vnet_create,
618 "vnet-delete": xm_vnet_delete,
619 }
621 ## The commands supported by a separate argument parser in xend.xm.
622 subcommands = [
623 'create',
624 'destroy',
625 'migrate',
626 'sysrq',
627 'shutdown'
628 ]
630 for c in subcommands:
631 commands[c] = eval('lambda args: xm_subcommand("%s", args)' % c)
633 aliases = {
634 "balloon": "mem-set",
635 "vif-list": "network-list",
636 "vif-limit": "network-limit",
637 "vbd-create": "block-create",
638 "vbd-destroy": "block-destroy",
639 "vbd-list": "block-list",
640 "vbd-refresh": "block-refresh",
641 }
643 help = {
644 "--long": longhelp
645 }
648 def xm_lookup_cmd(cmd):
649 if commands.has_key(cmd):
650 return commands[cmd]
651 elif aliases.has_key(cmd):
652 deprecated(cmd,aliases[cmd])
653 return commands[aliases[cmd]]
654 else:
655 if len( cmd ) > 1:
656 matched_commands = filter( lambda (command, func): command[ 0:len(cmd) ] == cmd, commands.iteritems() )
657 if len( matched_commands ) == 1:
658 return matched_commands[0][1]
659 err('Sub Command %s not found!' % cmd)
660 usage()
662 def deprecated(old,new):
663 err('Option %s is deprecated, and will be removed in future!!!' % old)
664 err('Option %s is the new replacement, see "xm help %s" for more info' % (new, new))
666 def usage(cmd=None):
667 if help.has_key(cmd):
668 print help[cmd]
669 else:
670 print shorthelp
671 sys.exit(1)
673 def main(argv=sys.argv):
674 if len(argv) < 2:
675 usage()
677 if re.compile('-*help').match(argv[1]):
678 if len(argv) > 2:
679 usage(argv[2])
680 else:
681 usage()
682 sys.exit(0)
684 cmd = xm_lookup_cmd(argv[1])
686 # strip off prog name and subcmd
687 args = argv[2:]
688 if cmd:
689 try:
690 from xen.xend.XendClient import XendError
691 rc = cmd(args)
692 if rc:
693 usage()
694 except socket.error, ex:
695 print >>sys.stderr, ex
696 err("Error connecting to xend, is xend running?")
697 sys.exit(1)
698 except IOError:
699 err("Most commands need root access. Please try again as root")
700 sys.exit(1)
701 except XendError, ex:
702 if len(args) > 0:
703 handle_xend_error(argv[1], args[0], ex)
704 else:
705 print "Unexpected error:", sys.exc_info()[0]
706 print
707 print "Please report to xen-devel@lists.xensource.com"
708 raise
709 except SystemExit:
710 sys.exit(1)
711 except:
712 print "Unexpected error:", sys.exc_info()[0]
713 print
714 print "Please report to xen-devel@lists.xensource.com"
715 raise
717 else:
718 usage()
720 if __name__ == "__main__":
721 main()