ia64/xen-unstable

view tools/python/xen/xm/main.py @ 7077:c9d690c52afc

This patch adds a quick check in "xm save" to make sure the path given
exists, and is writable.

This will fix the issue detected by xm-test 03_save_bogusfile_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:06:40 2005 +0100 (2005-09-27)
parents ad0270abc9b9
children fa4cc3f53c64
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 from xen.xend.XendClient import server
192 info = server.xend_domain_restore(savefile)
193 PrettyPrint.prettyprint(info)
194 id = sxp.child_value(info, 'domid')
195 if id is not None:
196 server.xend_domain_unpause(domid)
198 def xm_list(args):
199 use_long = 0
200 show_vcpus = 0
201 try:
202 (options, params) = getopt(args, 'lv', ['long','vcpus'])
203 except GetoptError, opterr:
204 err(opterr)
205 sys.exit(1)
207 n = len(params)
208 for (k, v) in options:
209 if k in ['-l', '--long']:
210 use_long = 1
211 if k in ['-v', '--vcpus']:
212 show_vcpus = 1
214 domsinfo = []
215 from xen.xend.XendClient import server
216 if n == 0:
217 doms = server.xend_domains()
218 doms.sort()
219 else:
220 doms = params
221 for dom in doms:
222 info = server.xend_domain(dom)
223 domsinfo.append(parse_doms_info(info))
225 if use_long:
226 for dom in doms:
227 info = server.xend_domain(dom)
228 PrettyPrint.prettyprint(info)
229 elif show_vcpus:
230 xm_show_vcpus(domsinfo)
231 else:
232 xm_brief_list(domsinfo)
234 def parse_doms_info(info):
235 dominfo = {}
236 dominfo['dom'] = int(sxp.child_value(info, 'domid', '-1'))
237 dominfo['name'] = sxp.child_value(info, 'name', '??')
238 dominfo['mem'] = int(sxp.child_value(info, 'memory', '0'))
239 dominfo['cpu'] = str(sxp.child_value(info, 'cpu', '0'))
240 dominfo['vcpus'] = int(sxp.child_value(info, 'vcpus', '0'))
241 # if there is more than 1 cpu, the value doesn't mean much
242 if dominfo['vcpus'] > 1:
243 dominfo['cpu'] = '-'
244 dominfo['state'] = sxp.child_value(info, 'state', '??')
245 dominfo['cpu_time'] = float(sxp.child_value(info, 'cpu_time', '0'))
246 # security identifiers
247 if ((int(sxp.child_value(info, 'ssidref', '0'))) != 0):
248 dominfo['ssidref1'] = int(sxp.child_value(info, 'ssidref', '0')) & 0xffff
249 dominfo['ssidref2'] = (int(sxp.child_value(info, 'ssidref', '0')) >> 16) & 0xffff
250 # get out the vcpu information
251 dominfo['vcpulist'] = []
252 vcpu_to_cpu = sxp.child_value(info, 'vcpu_to_cpu', '-1').split('|')
253 cpumap = sxp.child_value(info, 'cpumap', [])
254 mask = ((int(sxp.child_value(info, 'vcpus', '0')))**2) - 1
255 count = 0
256 for cpu in vcpu_to_cpu:
257 vcpuinfo = {}
258 vcpuinfo['name'] = sxp.child_value(info, 'name', '??')
259 vcpuinfo['dom'] = int(sxp.child_value(info, 'domid', '-1'))
260 vcpuinfo['vcpu'] = int(count)
261 vcpuinfo['cpu'] = int(cpu)
262 vcpuinfo['cpumap'] = int(cpumap[count])&mask
263 count = count + 1
264 dominfo['vcpulist'].append(vcpuinfo)
265 return dominfo
267 def xm_brief_list(domsinfo):
268 print 'Name Id Mem(MB) CPU VCPU(s) State Time(s)'
269 for dominfo in domsinfo:
270 if dominfo.has_key("ssidref1"):
271 print ("%(name)-16s %(dom)3d %(mem)7d %(cpu)3s %(vcpus)5d %(state)5s %(cpu_time)7.1f s:%(ssidref2)02x/p:%(ssidref1)02x" % dominfo)
272 else:
273 print ("%(name)-16s %(dom)3d %(mem)7d %(cpu)3s %(vcpus)5d %(state)5s %(cpu_time)7.1f" % dominfo)
275 def xm_show_vcpus(domsinfo):
276 print 'Name Id VCPU CPU CPUMAP'
277 for dominfo in domsinfo:
278 for vcpuinfo in dominfo['vcpulist']:
279 print ("%(name)-16s %(dom)3d %(vcpu)4d %(cpu)3d 0x%(cpumap)x" %
280 vcpuinfo)
282 def xm_vcpu_list(args):
283 xm_list(["-v"] + args)
285 def xm_reboot(args):
286 arg_check(args,1,"reboot")
287 from xen.xm import shutdown
288 # ugly hack because the opt parser apparently wants
289 # the subcommand name just to throw it away!
290 shutdown.main(["bogus", "-R"] + args)
292 def xm_pause(args):
293 arg_check(args, 1, "pause")
294 dom = args[0]
296 from xen.xend.XendClient import server
297 server.xend_domain_pause(dom)
299 def xm_unpause(args):
300 arg_check(args, 1, "unpause")
301 dom = args[0]
303 from xen.xend.XendClient import server
304 server.xend_domain_unpause(dom)
306 def xm_subcommand(command, args):
307 cmd = __import__(command, globals(), locals(), 'xen.xm')
308 cmd.main(["bogus"] + args)
311 #############################################################
313 def cpu_make_map(cpulist):
314 cpus = []
315 cpumap = 0
316 for c in cpulist.split(','):
317 if c.find('-') != -1:
318 (x,y) = c.split('-')
319 for i in range(int(x),int(y)+1):
320 cpus.append(int(i))
321 else:
322 cpus.append(int(c))
323 cpus.sort()
324 for c in cpus:
325 cpumap = cpumap | 1<<c
327 return cpumap
329 def xm_vcpu_pin(args):
330 arg_check(args, 3, "vcpu-pin")
332 dom = args[0]
333 vcpu = int(args[1])
334 cpumap = cpu_make_map(args[2])
336 from xen.xend.XendClient import server
337 server.xend_domain_pincpu(dom, vcpu, cpumap)
339 def xm_mem_max(args):
340 arg_check(args, 2, "mem-max")
342 dom = args[0]
343 mem = int_unit(args[1], 'm')
345 from xen.xend.XendClient import server
346 server.xend_domain_maxmem_set(dom, mem)
348 def xm_mem_set(args):
349 arg_check(args, 2, "mem-set")
351 dom = args[0]
352 mem_target = int_unit(args[1], 'm')
354 from xen.xend.XendClient import server
355 server.xend_domain_mem_target_set(dom, mem_target)
357 # TODO: why does this lookup by name? and what if that fails!?
358 def xm_vcpu_enable(args):
359 arg_check(args, 2, "vcpu-enable")
361 name = args[0]
362 vcpu = int(args[1])
364 from xen.xend.XendClient import server
365 dom = server.xend_domain(name)
366 id = sxp.child_value(dom, 'domid')
367 server.xend_domain_vcpu_hotplug(id, vcpu, 1)
369 def xm_vcpu_disable(args):
370 arg_check(args, 2, "vcpu-disable")
372 name = args[0]
373 vcpu = int(args[1])
375 from xen.xend.XendClient import server
376 dom = server.xend_domain(name)
377 id = sxp.child_value(dom, 'domid')
378 server.xend_domain_vcpu_hotplug(id, vcpu, 0)
380 def xm_domid(args):
381 name = args[0]
383 from xen.xend.XendClient import server
384 dom = server.xend_domain(name)
385 print sxp.child_value(dom, 'domid')
387 def xm_domname(args):
388 name = args[0]
390 from xen.xend.XendClient import server
391 dom = server.xend_domain(name)
392 print sxp.child_value(dom, 'name')
394 def xm_sched_bvt(args):
395 arg_check(args, 6, "sched-bvt")
396 dom = args[0]
397 v = map(long, args[1:6])
398 from xen.xend.XendClient import server
399 server.xend_domain_cpu_bvt_set(dom, *v)
401 def xm_sched_bvt_ctxallow(args):
402 arg_check(args, 1, "sched-bvt-ctxallow")
404 slice = int(args[0])
405 from xen.xend.XendClient import server
406 server.xend_node_cpu_bvt_slice_set(slice)
408 def xm_sched_sedf(args):
409 arg_check(args, 6, "sched-sedf")
411 dom = args[0]
412 v = map(int, args[1:6])
413 from xen.xend.XendClient import server
414 server.xend_domain_cpu_sedf_set(dom, *v)
416 def xm_info(args):
417 from xen.xend.XendClient import server
418 info = server.xend_node()
420 for x in info[1:]:
421 if len(x) < 2:
422 print "%-23s: (none)" % x[0]
423 else:
424 print "%-23s:" % x[0], x[1]
426 # TODO: remove as soon as console server shows up
427 def xm_console(args):
428 arg_check(args,1,"console")
430 dom = args[0]
431 from xen.xend.XendClient import server
432 info = server.xend_domain(dom)
433 domid = int(sxp.child_value(info, 'domid', '-1'))
434 cmd = "/usr/libexec/xen/xenconsole %d" % domid
435 os.execvp('/usr/libexec/xen/xenconsole', cmd.split())
436 console = sxp.child(info, "console")
438 def xm_top(args):
439 os.execv('/usr/sbin/xentop', ['/usr/sbin/xentop'])
441 def xm_dmesg(args):
443 gopts = Opts(use="""[-c|--clear]
445 Read Xen's message buffer (boot output, warning and error messages) or clear
446 its contents if the [-c|--clear] flag is specified.
447 """)
449 gopts.opt('clear', short='c',
450 fn=set_true, default=0,
451 use="Clear the contents of the Xen message buffer.")
452 # Work around for gopts
453 myargs = args
454 myargs.insert(0, "bogus")
455 gopts.parse(myargs)
456 if not (1 <= len(myargs) <= 2):
457 err('Invalid arguments: ' + str(myargs))
459 from xen.xend.XendClient import server
460 if not gopts.vals.clear:
461 print server.xend_node_get_dmesg()
462 else:
463 server.xend_node_clear_dmesg()
465 def xm_log(args):
466 from xen.xend.XendClient import server
467 print server.xend_node_log()
469 def xm_network_limit(args):
470 arg_check(args,4,"network-limit")
471 dom = args[0]
472 v = map(int, args[1:4])
473 from xen.xend.XendClient import server
474 server.xend_domain_vif_limit(dom, *v)
476 def xm_network_list(args):
477 arg_check(args,1,"network-list")
478 dom = args[0]
479 from xen.xend.XendClient import server
480 for x in server.xend_domain_devices(dom, 'vif'):
481 sxp.show(x)
482 print
484 def xm_block_list(args):
485 arg_check(args,1,"block-list")
486 dom = args[0]
487 from xen.xend.XendClient import server
488 for x in server.xend_domain_devices(dom, 'vbd'):
489 sxp.show(x)
490 print
492 def xm_block_attach(args):
493 n = len(args)
494 if n == 0:
495 usage("block-attach")
497 if n < 4 or n > 5:
498 err("%s: Invalid argument(s)" % args[0])
499 usage("block-attach")
501 dom = args[0]
502 vbd = ['vbd',
503 ['uname', args[1]],
504 ['dev', args[2]],
505 ['mode', args[3]]]
506 if n == 5:
507 vbd.append(['backend', args[4]])
509 from xen.xend.XendClient import server
510 server.xend_domain_device_create(dom, vbd)
512 def xm_block_refresh(args):
513 arg_check(args,2,"block-refresh")
515 dom = args[0]
516 dev = args[1]
518 from xen.xend.XendClient import server
519 server.xend_domain_device_refresh(dom, 'vbd', dev)
521 def xm_block_detach(args):
522 arg_check(args,2,"block-detach")
524 dom = args[0]
525 dev = args[1]
527 from xen.xend.XendClient import server
528 server.xend_domain_device_destroy(dom, 'vbd', dev)
530 def xm_vnet_list(args):
531 from xen.xend.XendClient import server
532 try:
533 (options, params) = getopt(args, 'l', ['long'])
534 except GetoptError, opterr:
535 err(opterr)
536 sys.exit(1)
538 use_long = 0
539 for (k, v) in options:
540 if k in ['-l', '--long']:
541 use_long = 1
543 if params:
544 use_long = 1
545 vnets = params
546 else:
547 vnets = server.xend_vnets()
549 for vnet in vnets:
550 try:
551 if use_long:
552 info = server.xend_vnet(vnet)
553 PrettyPrint.prettyprint(info)
554 else:
555 print vnet
556 except Exception, ex:
557 print vnet, ex
559 def xm_vnet_create(args):
560 arg_check(args, 1, "vnet-create")
561 conf = args[0]
562 from xen.xend.XendClient import server
563 server.xend_vnet_create(conf)
565 def xm_vnet_delete(args):
566 arg_check(args, 1, "vnet-delete")
567 vnet = args[0]
568 from xen.xend.XendClient import server
569 server.xend_vnet_delete(vnet)
571 commands = {
572 # console commands
573 "console": xm_console,
574 # xenstat commands
575 "top": xm_top,
576 # domain commands
577 "domid": xm_domid,
578 "domname": xm_domname,
579 "restore": xm_restore,
580 "save": xm_save,
581 "reboot": xm_reboot,
582 "list": xm_list,
583 # memory commands
584 "mem-max": xm_mem_max,
585 "mem-set": xm_mem_set,
586 # cpu commands
587 "vcpu-pin": xm_vcpu_pin,
588 # "cpus-list": xm_cpus_list,
589 "vcpu-enable": xm_vcpu_enable,
590 "vcpu-disable": xm_vcpu_disable,
591 "vcpu-list": xm_vcpu_list,
592 # special
593 "pause": xm_pause,
594 "unpause": xm_unpause,
595 # host commands
596 "dmesg": xm_dmesg,
597 "info": xm_info,
598 "log": xm_log,
599 # scheduler
600 "sched-bvt": xm_sched_bvt,
601 "sched-bvt-ctxallow": xm_sched_bvt_ctxallow,
602 "sched-sedf": xm_sched_sedf,
603 # block
604 "block-attach": xm_block_attach,
605 "block-detach": xm_block_detach,
606 "block-list": xm_block_list,
607 "block-refresh": xm_block_refresh,
608 # network
609 "network-limit": xm_network_limit,
610 "network-list": xm_network_list,
611 # vnet
612 "vnet-list": xm_vnet_list,
613 "vnet-create": xm_vnet_create,
614 "vnet-delete": xm_vnet_delete,
615 }
617 ## The commands supported by a separate argument parser in xend.xm.
618 subcommands = [
619 'create',
620 'destroy',
621 'migrate',
622 'sysrq',
623 'shutdown'
624 ]
626 for c in subcommands:
627 commands[c] = eval('lambda args: xm_subcommand("%s", args)' % c)
629 aliases = {
630 "balloon": "mem-set",
631 "vif-list": "network-list",
632 "vif-limit": "network-limit",
633 "vbd-create": "block-create",
634 "vbd-destroy": "block-destroy",
635 "vbd-list": "block-list",
636 "vbd-refresh": "block-refresh",
637 }
639 help = {
640 "--long": longhelp
641 }
644 def xm_lookup_cmd(cmd):
645 if commands.has_key(cmd):
646 return commands[cmd]
647 elif aliases.has_key(cmd):
648 deprecated(cmd,aliases[cmd])
649 return commands[aliases[cmd]]
650 else:
651 if len( cmd ) > 1:
652 matched_commands = filter( lambda (command, func): command[ 0:len(cmd) ] == cmd, commands.iteritems() )
653 if len( matched_commands ) == 1:
654 return matched_commands[0][1]
655 err('Sub Command %s not found!' % cmd)
656 usage()
658 def deprecated(old,new):
659 err('Option %s is deprecated, and will be removed in future!!!' % old)
660 err('Option %s is the new replacement, see "xm help %s" for more info' % (new, new))
662 def usage(cmd=None):
663 if help.has_key(cmd):
664 print help[cmd]
665 else:
666 print shorthelp
667 sys.exit(1)
669 def main(argv=sys.argv):
670 if len(argv) < 2:
671 usage()
673 if re.compile('-*help').match(argv[1]):
674 if len(argv) > 2:
675 usage(argv[2])
676 else:
677 usage()
678 sys.exit(0)
680 cmd = xm_lookup_cmd(argv[1])
682 # strip off prog name and subcmd
683 args = argv[2:]
684 if cmd:
685 try:
686 from xen.xend.XendClient import XendError
687 rc = cmd(args)
688 if rc:
689 usage()
690 except socket.error, ex:
691 print >>sys.stderr, ex
692 err("Error connecting to xend, is xend running?")
693 sys.exit(1)
694 except IOError:
695 err("Most commands need root access. Please try again as root")
696 sys.exit(1)
697 except XendError, ex:
698 if len(args) > 0:
699 handle_xend_error(argv[1], args[0], ex)
700 else:
701 print "Unexpected error:", sys.exc_info()[0]
702 print
703 print "Please report to xen-devel@lists.xensource.com"
704 raise
705 except SystemExit:
706 sys.exit(1)
707 except:
708 print "Unexpected error:", sys.exc_info()[0]
709 print
710 print "Please report to xen-devel@lists.xensource.com"
711 raise
713 else:
714 usage()
716 if __name__ == "__main__":
717 main()