debuggers.hg

view tools/python/xen/xm/main.py @ 3611:3dc193a9786a

bitkeeper revision 1.1159.170.102 (41fa2751heRkQ76AYa9Oe-6cOyJuLw)

Enhanced SEDF scheduler
author sd386@font.cl.cam.ac.uk
date Fri Jan 28 11:51:45 2005 +0000 (2005-01-28)
parents f8e1f285e41f
children 9c88ba91d330
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 class Group:
19 name = ""
20 info = ""
22 def __init__(self, xm):
23 self.xm = xm
24 self.progs = {}
26 def addprog(self, prog):
27 self.progs[prog.name] = prog
29 def getprog(self, name):
30 return self.progs.get(name)
32 def proglist(self):
33 kl = self.progs.keys()
34 kl.sort()
35 return [ self.getprog(k) for k in kl ]
37 def help(self, args):
38 if self.info:
39 print
40 print self.info
41 print
42 else:
43 print
45 def shortHelp(self, args):
46 self.help(args)
47 for p in self.proglist():
48 p.shortHelp(args)
50 class Prog:
51 """Base class for sub-programs.
52 """
54 """Program group it belongs to"""
55 group = 'all'
56 """Program name."""
57 name = '??'
58 """Short program info."""
59 info = ''
61 def __init__(self, xm):
62 self.xm = xm
64 def err(self, msg):
65 self.xm.err(msg)
67 def help(self, args):
68 self.shortHelp(args)
70 def shortHelp(self, args):
71 print "%-14s %s" % (self.name, self.info)
73 def main(self, args):
74 """Program main entry point.
75 """
76 pass
79 class ProgUnknown(Prog):
81 name = 'unknown'
82 info = ''
84 def help(self, args):
85 self.xm.err("Unknown command: %s\nTry '%s help' for more information."
86 % (args[0], self.xm.name))
88 main = help
90 class Xm:
91 """Main application.
92 """
94 def __init__(self):
95 self.name = 'xm'
96 self.unknown = ProgUnknown(self)
97 self.progs = {}
98 self.groups = {}
100 def err(self, msg):
101 print >>sys.stderr, "Error:", msg
102 sys.exit(1)
104 def main(self, args):
105 try:
106 self.main_call(args)
107 except socket.error, ex:
108 print >>sys.stderr, ex
109 self.err("Error connecting to xend, is xend running?")
110 except XendError, ex:
111 self.err(str(ex))
113 def main_call(self, args):
114 """Main entry point. Dispatches to the progs.
115 """
116 self.name = args[0]
117 if len(args) < 2:
118 args.append('help')
119 help = self.helparg(args)
120 p = self.getprog(args[1], self.unknown)
121 if help or len(args) < 2:
122 p.help(args[1:])
123 else:
124 p.main(args[1:])
126 def helparg(self, args):
127 for a in args:
128 if a in ['-h', '--help']:
129 return 1
130 return 0
132 def prog(self, pklass):
133 """Add a sub-program.
135 pklass program class (Prog subclass)
136 """
137 p = pklass(self)
138 self.progs[p.name] = p
139 self.getgroup(p.group).addprog(p)
140 return p
142 def getprog(self, name, val=None):
143 """Get a sub-program.
144 name Name of the sub-program (or optionally, an unambiguous
145 prefix of its name)
146 val Default return value if no (unique) match is found
147 """
149 match = None
150 for progname in self.progs.keys():
151 if progname == name:
152 match = progname
153 break
154 if progname.startswith(name):
155 if not match:
156 match = progname
157 else:
158 return val # name is ambiguous - bail out
160 return self.progs.get(match, val)
162 def group(self, klass):
163 g = klass(self)
164 self.groups[g.name] = g
165 return g
167 def getgroup(self, name):
168 return self.groups[name]
170 def grouplist(self):
171 kl = self.groups.keys()
172 kl.sort()
173 return [ self.getgroup(k) for k in kl ]
175 # Create the application object, then add the sub-program classes.
176 xm = Xm()
178 class GroupAll(Group):
180 name = "all"
181 info = ""
183 xm.group(GroupAll)
185 class GroupDomain(Group):
187 name = "domain"
188 info = "Commands on domains:"
190 xm.group(GroupDomain)
192 class GroupScheduler(Group):
194 name = "scheduler"
195 info = "Comands controlling scheduling:"
197 xm.group(GroupScheduler)
199 class GroupHost(Group):
201 name = "host"
202 info = "Commands related to the xen host (node):"
204 xm.group(GroupHost)
206 class GroupConsole(Group):
208 name = "console"
209 info = "Commands related to consoles:"
211 xm.group(GroupConsole)
213 class GroupVbd(Group):
215 name = "vbd"
216 info = "Commands related to virtual block devices:"
218 xm.group(GroupVbd)
220 class GroupVif(Group):
222 name = "vif"
223 info = "Commands related to virtual network interfaces:"
225 xm.group(GroupVif)
227 class ProgHelp(Prog):
229 name = "help"
230 info = "Print help."
232 def help(self, args):
233 if len(args) == 2:
234 name = args[1]
235 p = self.xm.getprog(name)
236 if p:
237 p.help(args[1:])
238 else:
239 print '%s: Unknown command: %s' % (self.name, name)
240 else:
241 for g in self.xm.grouplist():
242 g.shortHelp(args)
243 print "\nTry '%s help CMD' for help on CMD" % self.xm.name
245 main = help
247 xm.prog(ProgHelp)
249 class ProgCreate(Prog):
251 group = 'domain'
252 name = "create"
253 info = """Create a domain."""
255 def help(self, args):
256 create.main([args[0], '-h'])
258 def main(self, args):
259 create.main(args)
261 xm.prog(ProgCreate)
263 class ProgSave(Prog):
264 group = 'domain'
265 name = "save"
266 info = """Save domain state (and config) to file."""
268 def help(self, args):
269 print args[0], "DOM FILE"
270 print """\nSave domain with id DOM to FILE."""
272 def main(self, args):
273 if len(args) < 3: self.err("%s: Missing arguments" % args[0])
274 dom = args[1]
275 savefile = os.path.abspath(args[2])
276 server.xend_domain_save(dom, savefile)
278 xm.prog(ProgSave)
280 class ProgRestore(Prog):
281 group = 'domain'
282 name = "restore"
283 info = """Create a domain from a saved state."""
285 def help(self, args):
286 print args[0], "FILE"
287 print "\nRestore a domain from FILE."
289 def main(self, args):
290 if len(args) < 2: self.err("%s: Missing arguments" % args[0])
291 savefile = os.path.abspath(args[1])
292 info = server.xend_domain_restore(savefile)
293 PrettyPrint.prettyprint(info)
294 id = sxp.child_value(info, 'id')
295 if id is not None:
296 server.xend_domain_unpause(id)
298 xm.prog(ProgRestore)
300 class ProgMigrate(Prog):
301 group = 'domain'
302 name = "migrate"
303 info = """Migrate a domain to another machine."""
305 def help(self, args):
306 migrate.help([self.name] + args)
308 def main(self, args):
309 migrate.main(args)
311 xm.prog(ProgMigrate)
313 class ProgList(Prog):
314 group = 'domain'
315 name = "list"
316 info = """List information about domains."""
318 short_options = 'l'
319 long_options = ['long']
321 def help(self, args):
322 if help:
323 print args[0], '[options] [DOM...]'
324 print """\nGet information about domains.
325 Either all domains or the domains given.
327 -l, --long Get more detailed information.
328 """
329 return
331 def main(self, args):
332 use_long = 0
333 (options, params) = getopt(args[1:],
334 self.short_options,
335 self.long_options)
336 n = len(params)
337 for (k, v) in options:
338 if k in ['-l', '--long']:
339 use_long = 1
341 if n == 0:
342 doms = server.xend_domains()
343 doms.sort()
344 else:
345 doms = params
347 if use_long:
348 self.long_list(doms)
349 else:
350 self.brief_list(doms)
352 def brief_list(self, doms):
353 print 'Name Id Mem(MB) CPU State Time(s) Console'
354 for dom in doms:
355 info = server.xend_domain(dom)
356 d = {}
357 d['dom'] = int(sxp.child_value(info, 'id', '-1'))
358 d['name'] = sxp.child_value(info, 'name', '??')
359 d['mem'] = int(sxp.child_value(info, 'memory', '0'))
360 d['cpu'] = int(sxp.child_value(info, 'cpu', '0'))
361 d['state'] = sxp.child_value(info, 'state', '??')
362 d['cpu_time'] = float(sxp.child_value(info, 'cpu_time', '0'))
363 console = sxp.child(info, 'console')
364 if console:
365 d['port'] = sxp.child_value(console, 'console_port')
366 else:
367 d['port'] = ''
368 print ("%(name)-16s %(dom)3d %(mem)7d %(cpu)3d %(state)5s %(cpu_time)7.1f %(port)4s"
369 % d)
371 def long_list(self, doms):
372 for dom in doms:
373 info = server.xend_domain(dom)
374 PrettyPrint.prettyprint(info)
376 xm.prog(ProgList)
378 class ProgDestroy(Prog):
379 group = 'domain'
380 name = "destroy"
381 info = """Terminate a domain immediately."""
383 def help(self, args):
384 destroy.main([args[0], '-h'])
386 def main(self, args):
387 destroy.main(args)
389 xm.prog(ProgDestroy)
391 class ProgShutdown(Prog):
392 group = 'domain'
393 name = "shutdown"
394 info = """Shutdown a domain."""
396 def help(self, args):
397 shutdown.main([args[0], '-h'])
399 def main(self, args):
400 shutdown.main(args)
402 xm.prog(ProgShutdown)
404 class ProgSysrq(Prog):
405 group = 'domain'
406 name = "sysrq"
407 info = """Send a sysrq to a domain."""
409 def help(self, args):
410 sysrq.main([args[0], '-h'])
412 def main(self, args):
413 sysrq.main(args)
415 xm.prog(ProgSysrq)
417 class ProgPause(Prog):
418 group = 'domain'
419 name = "pause"
420 info = """Pause execution of a domain."""
422 def help(self, args):
423 print args[0], 'DOM'
424 print '\nPause execution of domain DOM.'
426 def main(self, args):
427 if len(args) < 2: self.err("%s: Missing domain" % args[0])
428 dom = args[1]
429 server.xend_domain_pause(dom)
431 xm.prog(ProgPause)
433 class ProgUnpause(Prog):
434 group = 'domain'
435 name = "unpause"
436 info = """Unpause a paused domain."""
438 def help(self, args):
439 print args[0], 'DOM'
440 print '\nUnpause execution of domain DOM.'
442 def main(self, args):
443 if len(args) < 2: self.err("%s: Missing domain" % args[0])
444 dom = args[1]
445 server.xend_domain_unpause(dom)
447 xm.prog(ProgUnpause)
449 class ProgPincpu(Prog):
450 group = 'domain'
451 name = "pincpu"
452 info = """Pin a domain to a cpu. """
454 def help(self, args):
455 print args[0],'DOM CPU'
456 print '\nPin domain DOM to cpu CPU.'
458 def main(self, args):
459 if len(args) != 3: self.err("%s: Invalid argument(s)" % args[0])
460 dom = args[1]
461 cpu = int(args[2])
462 server.xend_domain_pincpu(dom, cpu)
464 xm.prog(ProgPincpu)
466 class ProgMaxmem(Prog):
467 group = 'domain'
468 name = 'maxmem'
469 info = """Set domain memory limit."""
471 def help(self, args):
472 print args[0], "DOM MEMORY"
473 print "\nSet the memory limit for domain DOM to MEMORY megabytes."
475 def main(self, args):
476 if len(args) != 3: self.err("%s: Invalid argument(s)" % args[0])
477 dom = args[1]
478 mem = int(args[2])
479 server.xend_domain_maxmem_set(dom, mem)
481 xm.prog(ProgMaxmem)
483 class ProgBalloon(Prog):
484 group = 'domain'
485 name = 'balloon'
486 info = """Set the domain's memory footprint using the balloon driver."""
488 def help(self, args):
489 print args[0], "DOM MEMORY_TARGET"
490 print """\nRequest domain DOM to adjust its memory footprint to
491 MEMORY_TARGET megabytes"""
493 def main(self, args):
494 if len(args) != 3: self.err("%s: Invalid argument(s)" % args[0])
495 dom = args[1]
496 mem_target = int(args[2])
497 server.xend_domain_mem_target_set(dom, mem_target)
499 xm.prog(ProgBalloon)
501 class ProgDomid(Prog):
502 group = 'domain'
503 name = 'domid'
504 info = 'Convert a domain name to a domain id.'
506 def help(self, args):
507 print args[0], "DOM"
508 print '\nGet the domain id for the domain with name DOM.'
510 def main (self, args):
511 if len(args) != 2: self.err("%s: Invalid argument(s)" % args[0])
512 name = args[1]
513 dom = server.xend_domain(name)
514 print sxp.child_value(dom, 'id')
516 xm.prog(ProgDomid)
518 class ProgDomname(Prog):
519 group = 'domain'
520 name = 'domname'
521 info = 'Convert a domain id to a domain name.'
523 def help(self, args):
524 print args[0], "DOM"
525 print '\nGet the name for the domain with id DOM.'
527 def main (self, args):
528 if len(args) != 2: self.err("%s: Invalid argument(s)" % args[0])
529 name = args[1]
530 dom = server.xend_domain(name)
531 print sxp.child_value(dom, 'name')
533 xm.prog(ProgDomname)
535 class ProgBvt(Prog):
536 group = 'scheduler'
537 name = "bvt"
538 info = """Set BVT scheduler parameters."""
540 def help(self, args):
541 print args[0], "DOM MCUADV WARPBACK WARPVALUE WARPL WARPU"
542 print '\nSet Borrowed Virtual Time scheduler parameters.'
544 def main(self, args):
545 if len(args) != 7: self.err("%s: Invalid argument(s)" % args[0])
546 dom = args[1]
547 v = map(long, args[2:7])
548 server.xend_domain_cpu_bvt_set(dom, *v)
550 xm.prog(ProgBvt)
552 class ProgBvtslice(Prog):
553 group = 'scheduler'
554 name = "bvt_ctxallow"
555 info = """Set the BVT scheduler context switch allowance."""
557 def help(self, args):
558 print args[0], 'CTX_ALLOW'
559 print '\nSet Borrowed Virtual Time scheduler context switch allowance.'
561 def main(self, args):
562 if len(args) < 2: self.err('%s: Missing context switch allowance'
563 % args[0])
564 slice = int(args[1])
565 server.xend_node_cpu_bvt_slice_set(slice)
567 xm.prog(ProgBvtslice)
570 class ProgAtropos(Prog):
571 group = 'scheduler'
572 name= "atropos"
573 info = """Set atropos parameters."""
575 def help(self, args):
576 print args[0], "DOM PERIOD SLICE LATENCY XTRATIME"
577 print "\nSet atropos parameters."
579 def main(self, args):
580 if len(args) != 6: self.err("%s: Invalid argument(s)" % args[0])
581 dom = args[1]
582 v = map(int, args[2:6])
583 server.xend_domain_cpu_atropos_set(dom, *v)
585 xm.prog(ProgAtropos)
587 class ProgRrobin(Prog):
588 group = 'scheduler'
589 name = "rrobin"
590 info = """Set round robin slice."""
592 def help(self, args):
593 print args[0], "SLICE"
594 print "\nSet round robin scheduler slice."
596 def main(self, args):
597 if len(args) != 2: self.err("%s: Invalid argument(s)" % args[0])
598 rrslice = int(args[1])
599 server.xend_node_rrobin_set(rrslice)
601 xm.prog(ProgRrobin)
603 class ProgSedf(Prog):
604 group = 'scheduler'
605 name= "sedf"
606 info = """Set simple EDF parameters."""
608 def help(self, args):
609 print args[0], "DOM PERIOD SLICE LATENCY EXTRATIME WEIGHT"
610 print "\nSet simple EDF parameters."
612 def main(self, args):
613 if len(args) != 7: self.err("%s: Invalid argument(s)" % args[0])
614 dom = args[1]
615 v = map(int, args[2:7])
616 server.xend_domain_cpu_sedf_set(dom, *v)
618 xm.prog(ProgSedf)
620 class ProgInfo(Prog):
621 group = 'host'
622 name = "info"
623 info = """Get information about the xen host."""
625 def main(self, args):
626 info = server.xend_node()
627 for x in info[1:]:
628 print "%-23s:" % x[0], x[1]
630 xm.prog(ProgInfo)
632 class ProgConsoles(Prog):
633 group = 'console'
634 name = "consoles"
635 info = """Get information about domain consoles."""
637 def main(self, args):
638 l = server.xend_consoles()
639 print "Dom Port Id Connection"
640 for x in l:
641 info = server.xend_console(x)
642 d = {}
643 d['dom'] = sxp.child(info, 'domain', '?')[1]
644 d['port'] = sxp.child_value(info, 'console_port', '?')
645 d['id'] = sxp.child_value(info, 'id', '?')
646 connected = sxp.child(info, 'connected')
647 if connected:
648 d['conn'] = '%s:%s' % (connected[1], connected[2])
649 else:
650 d['conn'] = ''
651 print "%(dom)3s %(port)4s %(id)3s %(conn)s" % d
653 xm.prog(ProgConsoles)
655 class ProgConsole(Prog):
656 group = 'console'
657 name = "console"
658 info = """Open a console to a domain."""
660 def help(self, args):
661 print args[0], "DOM"
662 print "\nOpen a console to domain DOM."
664 def main(self, args):
665 if len(args) < 2: self.err("%s: Missing domain" % args[0])
666 dom = args[1]
667 info = server.xend_domain(dom)
668 console = sxp.child(info, "console")
669 if not console:
670 self.err("No console information")
671 port = sxp.child_value(console, "console_port")
672 from xen.util import console_client
673 console_client.connect("localhost", int(port))
675 xm.prog(ProgConsole)
677 class ProgCall(Prog):
678 name = "call"
679 info = "Call xend api functions."
681 def help (self, args):
682 print args[0], "function args..."
683 print """
684 Call a xend HTTP API function. The leading 'xend_' on the function
685 can be omitted. See xen.xend.XendClient for the API functions.
686 """
688 def main(self, args):
689 xend_client_main(args)
691 xm.prog(ProgCall)
693 class ProgDmesg(Prog):
694 group = 'host'
695 name = "dmesg"
696 info = """Read or clear Xen's message buffer."""
698 gopts = Opts(use="""[-c|--clear]
700 Read Xen's message buffer (boot output, warning and error messages) or clear
701 its contents if the [-c|--clear] flag is specified.
702 """)
704 gopts.opt('clear', short='c',
705 fn=set_true, default=0,
706 use="Clear the contents of the Xen message buffer.")
708 short_options = ['-c']
709 long_options = ['--clear']
711 def help(self, args):
712 self.gopts.argv = args
713 self.gopts.usage()
715 def main(self, args):
716 self.gopts.parse(args)
717 if not (1 <= len(args) <=2):
718 self.gopts.err('Invalid arguments: ' + str(args))
720 if not self.gopts.vals.clear:
721 print server.xend_node_get_dmesg()
722 else:
723 server.xend_node_clear_dmesg()
725 xm.prog(ProgDmesg)
727 class ProgLog(Prog):
728 group = 'host'
729 name = "log"
730 info = """Print the xend log."""
732 def main(self, args):
733 print server.xend_node_log()
735 xm.prog(ProgLog)
737 class ProgVifList(Prog):
738 group = 'vif'
739 name = 'vif-list'
740 info = """List virtual network interfaces for a domain."""
742 def help(self, args):
743 print args[0], "DOM"
744 print "\nList virtual network interfaces for domain DOM"
746 def main(self, args):
747 if len(args) != 2: self.err("%s: Invalid argument(s)" % args[0])
748 dom = args[1]
749 for x in server.xend_domain_vifs(dom):
750 sxp.show(x)
751 print
753 xm.prog(ProgVifList)
755 class ProgVbdList(Prog):
756 group = 'vbd'
757 name = 'vbd-list'
758 info = """List virtual block devices for a domain."""
760 def help(self, args):
761 print args[0], "DOM"
762 print "\nList virtual block devices for domain DOM"
764 def main(self, args):
765 if len(args) != 2: self.err("%s: Invalid argument(s)" % args[0])
766 dom = args[1]
767 for x in server.xend_domain_vbds(dom):
768 sxp.show(x)
769 print
771 xm.prog(ProgVbdList)
773 class ProgVbdCreate(Prog):
774 group = 'vbd'
775 name = 'vbd-create'
776 info = """Create a new virtual block device for a domain"""
778 def help(self, args):
779 print args[0], "DOM UNAME DEV MODE [BACKEND]"
780 print """
781 Create a virtual block device for a domain.
783 UNAME - device to export, e.g. phy:hda2
784 DEV - device name in the domain, e.g. sda1
785 MODE - access mode: r for read, w for read-write
786 BACKEND - backend driver domain
787 """
789 def main(self, args):
790 n = len(args)
791 if n < 5 or n > 6: self.err("%s: Invalid argument(s)" % args[0])
792 dom = args[1]
793 vbd = ['vbd',
794 ['uname', args[2]],
795 ['dev', args[3]],
796 ['mode', args[4]]]
797 if n == 6:
798 vbd.append(['backend', args[5]])
799 server.xend_domain_device_create(dom, vbd)
801 xm.prog(ProgVbdCreate)
803 class ProgVbdDestroy(Prog):
804 group = 'vbd'
805 name = 'vbd-destroy'
806 info = """Destroy a domain's virtual block device"""
808 def help(self, args):
809 print args[0], "DOM DEV"
810 print """
811 Destroy vbd DEV attached to domain DOM. Detaches the device
812 from the domain, but does not destroy the device contents.
813 The device indentifier DEV is the idx field in the device
814 information. This is visible in 'xm vbd-list'."""
816 def main(self, args):
817 if len(args) != 3: self.err("%s: Invalid argument(s)" % args[0])
818 dom = args[1]
819 dev = args[2]
820 server.xend_domain_device_destroy(dom, "vbd", dev)
822 xm.prog(ProgVbdDestroy)
824 def main(args):
825 xm.main(args)