debuggers.hg

view tools/python/xen/xm/main.py @ 4647:9c88ba91d330

bitkeeper revision 1.1346.1.1 (42670505dNhgnJm5dQD81pCalXMZgw)

manual merge
author iap10@freefall.cl.cam.ac.uk
date Thu Apr 21 01:42:29 2005 +0000 (2005-04-21)
parents 6bbac0aca316 3dc193a9786a
children 86285c9c18c1
line source
1 # Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
2 """Grand unified management application for Xen.
3 """
4 import os
5 import os.path
6 import sys
7 from getopt import getopt
8 import socket
10 from xen.xend import PrettyPrint
11 from xen.xend import sxp
12 from xen.xend.XendClient import XendError, server
13 from xen.xend.XendClient import main as xend_client_main
14 from xen.xm import create, destroy, migrate, shutdown, sysrq
15 from xen.xm.opts import *
17 def unit(c):
18 if not c.isalpha():
19 return 0
20 base = 1
21 if c == 'G' or c == 'g': base = 1024 * 1024 * 1024
22 elif c == 'M' or c == 'm': base = 1024 * 1024
23 elif c == 'K' or c == 'k': base = 1024
24 else:
25 print 'ignoring unknown unit'
26 return base
28 def int_unit(str, dest):
29 base = unit(str[-1])
30 if not base:
31 return int(str)
33 value = int(str[:-1])
34 dst_base = unit(dest)
35 if dst_base == 0:
36 dst_base = 1
37 if dst_base > base:
38 return value / (dst_base / base)
39 else:
40 return value * (base / dst_base)
42 class Group:
44 name = ""
45 info = ""
47 def __init__(self, xm):
48 self.xm = xm
49 self.progs = {}
51 def addprog(self, prog):
52 self.progs[prog.name] = prog
54 def getprog(self, name):
55 return self.progs.get(name)
57 def proglist(self):
58 kl = self.progs.keys()
59 kl.sort()
60 return [ self.getprog(k) for k in kl ]
62 def help(self, args):
63 if self.info:
64 print
65 print self.info
66 print
67 else:
68 print
70 def shortHelp(self, args):
71 self.help(args)
72 for p in self.proglist():
73 p.shortHelp(args)
75 class Prog:
76 """Base class for sub-programs.
77 """
79 """Program group it belongs to"""
80 group = 'all'
81 """Program name."""
82 name = '??'
83 """Short program info."""
84 info = ''
86 def __init__(self, xm):
87 self.xm = xm
89 def err(self, msg):
90 self.xm.err(msg)
92 def help(self, args):
93 self.shortHelp(args)
95 def shortHelp(self, args):
96 print "%-14s %s" % (self.name, self.info)
98 def main(self, args):
99 """Program main entry point.
100 """
101 pass
104 class ProgUnknown(Prog):
106 name = 'unknown'
107 info = ''
109 def help(self, args):
110 self.xm.err("Unknown command: %s\nTry '%s help' for more information."
111 % (args[0], self.xm.name))
113 main = help
115 class Xm:
116 """Main application.
117 """
119 def __init__(self):
120 self.name = 'xm'
121 self.unknown = ProgUnknown(self)
122 self.progs = {}
123 self.groups = {}
125 def err(self, msg):
126 print >>sys.stderr, "Error:", msg
127 sys.exit(1)
129 def main(self, args):
130 try:
131 self.main_call(args)
132 except socket.error, ex:
133 print >>sys.stderr, ex
134 self.err("Error connecting to xend, is xend running?")
135 except XendError, ex:
136 self.err(str(ex))
138 def main_call(self, args):
139 """Main entry point. Dispatches to the progs.
140 """
141 self.name = args[0]
142 if len(args) < 2:
143 args.append('help')
144 help = self.helparg(args)
145 p = self.getprog(args[1], self.unknown)
146 if help or len(args) < 2:
147 p.help(args[1:])
148 else:
149 p.main(args[1:])
151 def helparg(self, args):
152 for a in args:
153 if a in ['-h', '--help']:
154 return 1
155 return 0
157 def prog(self, pklass):
158 """Add a sub-program.
160 pklass program class (Prog subclass)
161 """
162 p = pklass(self)
163 self.progs[p.name] = p
164 self.getgroup(p.group).addprog(p)
165 return p
167 def getprog(self, name, val=None):
168 """Get a sub-program.
169 name Name of the sub-program (or optionally, an unambiguous
170 prefix of its name)
171 val Default return value if no (unique) match is found
172 """
174 match = None
175 for progname in self.progs.keys():
176 if progname == name:
177 match = progname
178 break
179 if progname.startswith(name):
180 if not match:
181 match = progname
182 else:
183 return val # name is ambiguous - bail out
185 return self.progs.get(match, val)
187 def group(self, klass):
188 g = klass(self)
189 self.groups[g.name] = g
190 return g
192 def getgroup(self, name):
193 return self.groups[name]
195 def grouplist(self):
196 kl = self.groups.keys()
197 kl.sort()
198 return [ self.getgroup(k) for k in kl ]
200 # Create the application object, then add the sub-program classes.
201 xm = Xm()
203 class GroupAll(Group):
205 name = "all"
206 info = ""
208 xm.group(GroupAll)
210 class GroupDomain(Group):
212 name = "domain"
213 info = "Commands on domains:"
215 xm.group(GroupDomain)
217 class GroupScheduler(Group):
219 name = "scheduler"
220 info = "Comands controlling scheduling:"
222 xm.group(GroupScheduler)
224 class GroupHost(Group):
226 name = "host"
227 info = "Commands related to the xen host (node):"
229 xm.group(GroupHost)
231 class GroupConsole(Group):
233 name = "console"
234 info = "Commands related to consoles:"
236 xm.group(GroupConsole)
238 class GroupVbd(Group):
240 name = "vbd"
241 info = "Commands related to virtual block devices:"
243 xm.group(GroupVbd)
245 class GroupVif(Group):
247 name = "vif"
248 info = "Commands related to virtual network interfaces:"
250 xm.group(GroupVif)
252 class ProgHelp(Prog):
254 name = "help"
255 info = "Print help."
257 def help(self, args):
258 if len(args) == 2:
259 name = args[1]
260 p = self.xm.getprog(name)
261 if p:
262 p.help(args[1:])
263 else:
264 print '%s: Unknown command: %s' % (self.name, name)
265 else:
266 for g in self.xm.grouplist():
267 g.shortHelp(args)
268 print "\nTry '%s help CMD' for help on CMD" % self.xm.name
270 main = help
272 xm.prog(ProgHelp)
274 class ProgCreate(Prog):
276 group = 'domain'
277 name = "create"
278 info = """Create a domain."""
280 def help(self, args):
281 create.main([args[0], '-h'])
283 def main(self, args):
284 create.main(args)
286 xm.prog(ProgCreate)
288 class ProgSave(Prog):
289 group = 'domain'
290 name = "save"
291 info = """Save domain state (and config) to file."""
293 def help(self, args):
294 print args[0], "DOM FILE"
295 print """\nSave domain with id DOM to FILE."""
297 def main(self, args):
298 if len(args) < 3: self.err("%s: Missing arguments" % args[0])
299 dom = args[1]
300 savefile = os.path.abspath(args[2])
301 server.xend_domain_save(dom, savefile)
303 xm.prog(ProgSave)
305 class ProgRestore(Prog):
306 group = 'domain'
307 name = "restore"
308 info = """Create a domain from a saved state."""
310 def help(self, args):
311 print args[0], "FILE"
312 print "\nRestore a domain from FILE."
314 def main(self, args):
315 if len(args) < 2: self.err("%s: Missing arguments" % args[0])
316 savefile = os.path.abspath(args[1])
317 info = server.xend_domain_restore(savefile)
318 PrettyPrint.prettyprint(info)
319 id = sxp.child_value(info, 'id')
320 if id is not None:
321 server.xend_domain_unpause(id)
323 xm.prog(ProgRestore)
325 class ProgMigrate(Prog):
326 group = 'domain'
327 name = "migrate"
328 info = """Migrate a domain to another machine."""
330 def help(self, args):
331 migrate.help([self.name] + args)
333 def main(self, args):
334 migrate.main(args)
336 xm.prog(ProgMigrate)
338 class ProgList(Prog):
339 group = 'domain'
340 name = "list"
341 info = """List information about domains."""
343 short_options = 'l'
344 long_options = ['long']
346 def help(self, args):
347 if help:
348 print args[0], '[options] [DOM...]'
349 print """\nGet information about domains.
350 Either all domains or the domains given.
352 -l, --long Get more detailed information.
353 """
354 return
356 def main(self, args):
357 use_long = 0
358 (options, params) = getopt(args[1:],
359 self.short_options,
360 self.long_options)
361 n = len(params)
362 for (k, v) in options:
363 if k in ['-l', '--long']:
364 use_long = 1
366 if n == 0:
367 doms = server.xend_domains()
368 doms.sort()
369 else:
370 doms = params
372 if use_long:
373 self.long_list(doms)
374 else:
375 self.brief_list(doms)
377 def brief_list(self, doms):
378 print 'Name Id Mem(MB) CPU State Time(s) Console'
379 for dom in doms:
380 info = server.xend_domain(dom)
381 d = {}
382 d['dom'] = int(sxp.child_value(info, 'id', '-1'))
383 d['name'] = sxp.child_value(info, 'name', '??')
384 d['mem'] = int(sxp.child_value(info, 'memory', '0'))
385 d['cpu'] = int(sxp.child_value(info, 'cpu', '0'))
386 d['state'] = sxp.child_value(info, 'state', '??')
387 d['cpu_time'] = float(sxp.child_value(info, 'cpu_time', '0'))
388 console = sxp.child(info, 'console')
389 if console:
390 d['port'] = sxp.child_value(console, 'console_port')
391 else:
392 d['port'] = ''
393 print ("%(name)-16s %(dom)3d %(mem)7d %(cpu)3d %(state)5s %(cpu_time)7.1f %(port)4s"
394 % d)
396 def long_list(self, doms):
397 for dom in doms:
398 info = server.xend_domain(dom)
399 PrettyPrint.prettyprint(info)
401 xm.prog(ProgList)
403 class ProgDestroy(Prog):
404 group = 'domain'
405 name = "destroy"
406 info = """Terminate a domain immediately."""
408 def help(self, args):
409 destroy.main([args[0], '-h'])
411 def main(self, args):
412 destroy.main(args)
414 xm.prog(ProgDestroy)
416 class ProgShutdown(Prog):
417 group = 'domain'
418 name = "shutdown"
419 info = """Shutdown a domain."""
421 def help(self, args):
422 shutdown.main([args[0], '-h'])
424 def main(self, args):
425 shutdown.main(args)
427 xm.prog(ProgShutdown)
429 class ProgSysrq(Prog):
430 group = 'domain'
431 name = "sysrq"
432 info = """Send a sysrq to a domain."""
434 def help(self, args):
435 sysrq.main([args[0], '-h'])
437 def main(self, args):
438 sysrq.main(args)
440 xm.prog(ProgSysrq)
442 class ProgPause(Prog):
443 group = 'domain'
444 name = "pause"
445 info = """Pause execution of a domain."""
447 def help(self, args):
448 print args[0], 'DOM'
449 print '\nPause execution of domain DOM.'
451 def main(self, args):
452 if len(args) < 2: self.err("%s: Missing domain" % args[0])
453 dom = args[1]
454 server.xend_domain_pause(dom)
456 xm.prog(ProgPause)
458 class ProgUnpause(Prog):
459 group = 'domain'
460 name = "unpause"
461 info = """Unpause a paused domain."""
463 def help(self, args):
464 print args[0], 'DOM'
465 print '\nUnpause execution of domain DOM.'
467 def main(self, args):
468 if len(args) < 2: self.err("%s: Missing domain" % args[0])
469 dom = args[1]
470 server.xend_domain_unpause(dom)
472 xm.prog(ProgUnpause)
474 class ProgPincpu(Prog):
475 group = 'domain'
476 name = "pincpu"
477 info = """Pin a domain to a cpu. """
479 def help(self, args):
480 print args[0],'DOM CPU'
481 print '\nPin domain DOM to cpu CPU.'
483 def main(self, args):
484 if len(args) != 3: self.err("%s: Invalid argument(s)" % args[0])
485 dom = args[1]
486 cpu = int(args[2])
487 server.xend_domain_pincpu(dom, cpu)
489 xm.prog(ProgPincpu)
491 class ProgMaxmem(Prog):
492 group = 'domain'
493 name = 'maxmem'
494 info = """Set domain memory limit."""
496 def help(self, args):
497 print args[0], "DOM MEMORY"
498 print "\nSet the memory limit for domain DOM to MEMORY megabytes."
500 def main(self, args):
501 if len(args) != 3: self.err("%s: Invalid argument(s)" % args[0])
502 dom = args[1]
503 mem = int_unit(args[2], 'm')
504 server.xend_domain_maxmem_set(dom, mem)
506 xm.prog(ProgMaxmem)
508 class ProgBalloon(Prog):
509 group = 'domain'
510 name = 'balloon'
511 info = """Set the domain's memory footprint using the balloon driver."""
513 def help(self, args):
514 print args[0], "DOM MEMORY_TARGET"
515 print """\nRequest domain DOM to adjust its memory footprint to
516 MEMORY_TARGET megabytes"""
518 def main(self, args):
519 if len(args) != 3: self.err("%s: Invalid argument(s)" % args[0])
520 dom = args[1]
521 mem_target = int_unit(args[2], 'm')
522 server.xend_domain_mem_target_set(dom, mem_target)
524 xm.prog(ProgBalloon)
526 class ProgDomid(Prog):
527 group = 'domain'
528 name = 'domid'
529 info = 'Convert a domain name to a domain id.'
531 def help(self, args):
532 print args[0], "DOM"
533 print '\nGet the domain id for the domain with name DOM.'
535 def main (self, args):
536 if len(args) != 2: self.err("%s: Invalid argument(s)" % args[0])
537 name = args[1]
538 dom = server.xend_domain(name)
539 print sxp.child_value(dom, 'id')
541 xm.prog(ProgDomid)
543 class ProgDomname(Prog):
544 group = 'domain'
545 name = 'domname'
546 info = 'Convert a domain id to a domain name.'
548 def help(self, args):
549 print args[0], "DOM"
550 print '\nGet the name for the domain with id DOM.'
552 def main (self, args):
553 if len(args) != 2: self.err("%s: Invalid argument(s)" % args[0])
554 name = args[1]
555 dom = server.xend_domain(name)
556 print sxp.child_value(dom, 'name')
558 xm.prog(ProgDomname)
560 class ProgBvt(Prog):
561 group = 'scheduler'
562 name = "bvt"
563 info = """Set BVT scheduler parameters."""
565 def help(self, args):
566 print args[0], "DOM MCUADV WARPBACK WARPVALUE WARPL WARPU"
567 print '\nSet Borrowed Virtual Time scheduler parameters.'
569 def main(self, args):
570 if len(args) != 7: self.err("%s: Invalid argument(s)" % args[0])
571 dom = args[1]
572 v = map(long, args[2:7])
573 server.xend_domain_cpu_bvt_set(dom, *v)
575 xm.prog(ProgBvt)
577 class ProgBvtslice(Prog):
578 group = 'scheduler'
579 name = "bvt_ctxallow"
580 info = """Set the BVT scheduler context switch allowance."""
582 def help(self, args):
583 print args[0], 'CTX_ALLOW'
584 print '\nSet Borrowed Virtual Time scheduler context switch allowance.'
586 def main(self, args):
587 if len(args) < 2: self.err('%s: Missing context switch allowance'
588 % args[0])
589 slice = int(args[1])
590 server.xend_node_cpu_bvt_slice_set(slice)
592 xm.prog(ProgBvtslice)
594 class ProgSedf(Prog):
595 group = 'scheduler'
596 name= "sedf"
597 info = """Set simple EDF parameters."""
599 def help(self, args):
600 print args[0], "DOM PERIOD SLICE LATENCY EXTRATIME WEIGHT"
601 print "\nSet simple EDF parameters."
603 def main(self, args):
604 if len(args) != 7: self.err("%s: Invalid argument(s)" % args[0])
605 dom = args[1]
606 v = map(int, args[2:7])
607 server.xend_domain_cpu_sedf_set(dom, *v)
609 xm.prog(ProgSedf)
611 class ProgInfo(Prog):
612 group = 'host'
613 name = "info"
614 info = """Get information about the xen host."""
616 def main(self, args):
617 info = server.xend_node()
618 for x in info[1:]:
619 print "%-23s:" % x[0], x[1]
621 xm.prog(ProgInfo)
623 class ProgConsoles(Prog):
624 group = 'console'
625 name = "consoles"
626 info = """Get information about domain consoles."""
628 def main(self, args):
629 l = server.xend_consoles()
630 print "Dom Port Id Connection"
631 for x in l:
632 info = server.xend_console(x)
633 d = {}
634 d['dom'] = sxp.child(info, 'domain', '?')[1]
635 d['port'] = sxp.child_value(info, 'console_port', '?')
636 d['id'] = sxp.child_value(info, 'id', '?')
637 connected = sxp.child(info, 'connected')
638 if connected:
639 d['conn'] = '%s:%s' % (connected[1], connected[2])
640 else:
641 d['conn'] = ''
642 print "%(dom)3s %(port)4s %(id)3s %(conn)s" % d
644 xm.prog(ProgConsoles)
646 class ProgConsole(Prog):
647 group = 'console'
648 name = "console"
649 info = """Open a console to a domain."""
651 def help(self, args):
652 print args[0], "DOM"
653 print "\nOpen a console to domain DOM."
655 def main(self, args):
656 if len(args) < 2: self.err("%s: Missing domain" % args[0])
657 dom = args[1]
658 info = server.xend_domain(dom)
659 console = sxp.child(info, "console")
660 if not console:
661 self.err("No console information")
662 port = sxp.child_value(console, "console_port")
663 from xen.util import console_client
664 console_client.connect("localhost", int(port))
666 xm.prog(ProgConsole)
668 class ProgCall(Prog):
669 name = "call"
670 info = "Call xend api functions."
672 def help (self, args):
673 print args[0], "function args..."
674 print """
675 Call a xend HTTP API function. The leading 'xend_' on the function
676 can be omitted. See xen.xend.XendClient for the API functions.
677 """
679 def main(self, args):
680 xend_client_main(args)
682 xm.prog(ProgCall)
684 class ProgDmesg(Prog):
685 group = 'host'
686 name = "dmesg"
687 info = """Read or clear Xen's message buffer."""
689 gopts = Opts(use="""[-c|--clear]
691 Read Xen's message buffer (boot output, warning and error messages) or clear
692 its contents if the [-c|--clear] flag is specified.
693 """)
695 gopts.opt('clear', short='c',
696 fn=set_true, default=0,
697 use="Clear the contents of the Xen message buffer.")
699 short_options = ['-c']
700 long_options = ['--clear']
702 def help(self, args):
703 self.gopts.argv = args
704 self.gopts.usage()
706 def main(self, args):
707 self.gopts.parse(args)
708 if not (1 <= len(args) <=2):
709 self.gopts.err('Invalid arguments: ' + str(args))
711 if not self.gopts.vals.clear:
712 print server.xend_node_get_dmesg()
713 else:
714 server.xend_node_clear_dmesg()
716 xm.prog(ProgDmesg)
718 class ProgLog(Prog):
719 group = 'host'
720 name = "log"
721 info = """Print the xend log."""
723 def main(self, args):
724 print server.xend_node_log()
726 xm.prog(ProgLog)
728 class ProgVifCreditLimit(Prog):
729 group = 'vif'
730 name= "vif-limit"
731 info = """Limit the transmission rate of a virtual network interface."""
733 def help(self, args):
734 print args[0], "DOMAIN VIF CREDIT_IN_BYTES PERIOD_IN_USECS"
735 print "\nSet the credit limit of a virtual network interface."
737 def main(self, args):
738 if len(args) != 5: self.err("%s: Invalid argument(s)" % args[0])
739 dom = args[1]
740 v = map(int, args[2:5])
741 server.xend_domain_vif_limit(dom, *v)
743 xm.prog(ProgVifCreditLimit)
745 class ProgVifList(Prog):
746 group = 'vif'
747 name = 'vif-list'
748 info = """List virtual network interfaces for a domain."""
750 def help(self, args):
751 print args[0], "DOM"
752 print "\nList virtual network interfaces for domain DOM"
754 def main(self, args):
755 if len(args) != 2: self.err("%s: Invalid argument(s)" % args[0])
756 dom = args[1]
757 for x in server.xend_domain_vifs(dom):
758 sxp.show(x)
759 print
761 xm.prog(ProgVifList)
763 class ProgVbdList(Prog):
764 group = 'vbd'
765 name = 'vbd-list'
766 info = """List virtual block devices for a domain."""
768 def help(self, args):
769 print args[0], "DOM"
770 print "\nList virtual block devices for domain DOM"
772 def main(self, args):
773 if len(args) != 2: self.err("%s: Invalid argument(s)" % args[0])
774 dom = args[1]
775 for x in server.xend_domain_vbds(dom):
776 sxp.show(x)
777 print
779 xm.prog(ProgVbdList)
781 class ProgVbdCreate(Prog):
782 group = 'vbd'
783 name = 'vbd-create'
784 info = """Create a new virtual block device for a domain"""
786 def help(self, args):
787 print args[0], "DOM UNAME DEV MODE [BACKEND]"
788 print """
789 Create a virtual block device for a domain.
791 UNAME - device to export, e.g. phy:hda2
792 DEV - device name in the domain, e.g. sda1
793 MODE - access mode: r for read, w for read-write
794 BACKEND - backend driver domain
795 """
797 def main(self, args):
798 n = len(args)
799 if n < 5 or n > 6: self.err("%s: Invalid argument(s)" % args[0])
800 dom = args[1]
801 vbd = ['vbd',
802 ['uname', args[2]],
803 ['dev', args[3]],
804 ['mode', args[4]]]
805 if n == 6:
806 vbd.append(['backend', args[5]])
807 server.xend_domain_device_create(dom, vbd)
809 xm.prog(ProgVbdCreate)
811 class ProgVbdRefresh(Prog):
812 group = 'vbd'
813 name = 'vbd-refresh'
814 info = """Refresh a virtual block device for a domain"""
816 def help(self, args):
817 print args[0], "DOM DEV"
818 print """
819 Refresh a virtual block device for a domain.
821 DEV - idx field in the device information
822 """
824 def main(self, args):
825 if len(args) != 3: self.err("%s: Invalid argument(s)" % args[0])
826 dom = args[1]
827 dev = args[2]
828 server.xend_domain_device_refresh(dom, 'vbd', dev)
830 xm.prog(ProgVbdRefresh)
833 class ProgVbdDestroy(Prog):
834 group = 'vbd'
835 name = 'vbd-destroy'
836 info = """Destroy a domain's virtual block device"""
838 def help(self, args):
839 print args[0], "DOM DEV"
840 print """
841 Destroy vbd DEV attached to domain DOM. Detaches the device
842 from the domain, but does not destroy the device contents.
843 The device indentifier DEV is the idx field in the device
844 information. This is visible in 'xm vbd-list'."""
846 def main(self, args):
847 if len(args) != 3: self.err("%s: Invalid argument(s)" % args[0])
848 dom = args[1]
849 dev = args[2]
850 server.xend_domain_device_destroy(dom, "vbd", dev)
852 xm.prog(ProgVbdDestroy)
854 def main(args):
855 xm.main(args)