ia64/xen-unstable

view tools/python/xen/xm/main.py @ 2656:cb94a45f41fb

bitkeeper revision 1.1159.115.1 (417457c52HnHChOJGxHncu97gsa5cg)

Atropos scheduler set takes 5 arguments. As noted by Diwaker Gupta.
author cl349@freefall.cl.cam.ac.uk
date Mon Oct 18 23:54:45 2004 +0000 (2004-10-18)
parents aed97013f9fe
children 1214770ada19
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
16 class Group:
18 name = ""
19 info = ""
21 def __init__(self, xm):
22 self.xm = xm
23 self.progs = {}
25 def addprog(self, prog):
26 self.progs[prog.name] = prog
28 def getprog(self, name):
29 return self.progs.get(name)
31 def proglist(self):
32 kl = self.progs.keys()
33 kl.sort()
34 return [ self.getprog(k) for k in kl ]
36 def help(self, args):
37 if self.info:
38 print
39 print self.info
40 print
41 else:
42 print
44 def shortHelp(self, args):
45 self.help(args)
46 for p in self.proglist():
47 p.shortHelp(args)
49 class Prog:
50 """Base class for sub-programs.
51 """
53 """Program group it belongs to"""
54 group = 'all'
55 """Program name."""
56 name = '??'
57 """Short program info."""
58 info = ''
60 def __init__(self, xm):
61 self.xm = xm
63 def err(self, msg):
64 self.xm.err(msg)
66 def help(self, args):
67 self.shortHelp(args)
69 def shortHelp(self, args):
70 print "%-14s %s" % (self.name, self.info)
72 def main(self, args):
73 """Program main entry point.
74 """
75 pass
78 class ProgUnknown(Prog):
80 name = 'unknown'
81 info = ''
83 def help(self, args):
84 self.xm.err("Unknown command: %s\nTry '%s help' for more information."
85 % (args[0], self.xm.name))
87 main = help
89 class Xm:
90 """Main application.
91 """
93 def __init__(self):
94 self.name = 'xm'
95 self.unknown = ProgUnknown(self)
96 self.progs = {}
97 self.groups = {}
99 def err(self, msg):
100 print >>sys.stderr, "Error:", msg
101 sys.exit(1)
103 def main(self, args):
104 try:
105 self.main_call(args)
106 except socket.error, ex:
107 print >>sys.stderr, ex
108 self.err("Error connecting to xend, is xend running?")
109 except XendError, ex:
110 self.err(str(ex))
112 def main_call(self, args):
113 """Main entry point. Dispatches to the progs.
114 """
115 self.name = args[0]
116 if len(args) < 2:
117 args.append('help')
118 help = self.helparg(args)
119 p = self.getprog(args[1], self.unknown)
120 if help or len(args) < 2:
121 p.help(args[1:])
122 else:
123 p.main(args[1:])
125 def helparg(self, args):
126 for a in args:
127 if a in ['-h', '--help']:
128 return 1
129 return 0
131 def prog(self, pklass):
132 """Add a sub-program.
134 pklass program class (Prog subclass)
135 """
136 p = pklass(self)
137 self.progs[p.name] = p
138 self.getgroup(p.group).addprog(p)
139 return p
141 def getprog(self, name, val=None):
142 """Get a sub-program.
143 name Name of the sub-program (or optionally, an unambiguous
144 prefix of its name)
145 val Default return value if no (unique) match is found
146 """
148 match = None
149 for progname in self.progs.keys():
150 if progname == name:
151 match = progname
152 break
153 if progname.startswith(name):
154 if not match:
155 match = progname
156 else:
157 return val # name is ambiguous - bail out
159 return self.progs.get(match, val)
161 def group(self, klass):
162 g = klass(self)
163 self.groups[g.name] = g
164 return g
166 def getgroup(self, name):
167 return self.groups[name]
169 def grouplist(self):
170 kl = self.groups.keys()
171 kl.sort()
172 return [ self.getgroup(k) for k in kl ]
174 # Create the application object, then add the sub-program classes.
175 xm = Xm()
177 class GroupAll(Group):
179 name = "all"
180 info = ""
182 xm.group(GroupAll)
184 class GroupDomain(Group):
186 name = "domain"
187 info = "Commands on domains:"
189 xm.group(GroupDomain)
191 class GroupScheduler(Group):
193 name = "scheduler"
194 info = "Comands controlling scheduling:"
196 xm.group(GroupScheduler)
198 class GroupHost(Group):
200 name = "host"
201 info = "Commands related to the xen host (node):"
203 xm.group(GroupHost)
205 class GroupConsole(Group):
207 name = "console"
208 info = "Commands related to consoles:"
210 xm.group(GroupConsole)
212 class GroupVbd(Group):
214 name = "vbd"
215 info = "Commands related to virtual block devices:"
217 xm.group(GroupVbd)
219 class GroupVif(Group):
221 name = "vif"
222 info = "Commands related to virtual network interfaces:"
224 xm.group(GroupVif)
226 class ProgHelp(Prog):
228 name = "help"
229 info = "Print help."
231 def help(self, args):
232 if len(args) == 2:
233 name = args[1]
234 p = self.xm.getprog(name)
235 if p:
236 p.help(args[1:])
237 else:
238 print '%s: Unknown command: %s' % (self.name, name)
239 else:
240 for g in self.xm.grouplist():
241 g.shortHelp(args)
242 print "\nTry '%s help CMD' for help on CMD" % self.xm.name
244 main = help
246 xm.prog(ProgHelp)
248 class ProgCreate(Prog):
250 group = 'domain'
251 name = "create"
252 info = """Create a domain."""
254 def help(self, args):
255 create.main([args[0], '-h'])
257 def main(self, args):
258 create.main(args)
260 xm.prog(ProgCreate)
262 class ProgSave(Prog):
263 group = 'domain'
264 name = "save"
265 info = """Save domain state (and config) to file."""
267 def help(self, args):
268 print args[0], "DOM FILE"
269 print """\nSave domain with id DOM to FILE."""
271 def main(self, args):
272 if len(args) < 3: self.err("%s: Missing arguments" % args[0])
273 dom = args[1]
274 savefile = os.path.abspath(args[2])
275 server.xend_domain_save(dom, savefile)
277 xm.prog(ProgSave)
279 class ProgRestore(Prog):
280 group = 'domain'
281 name = "restore"
282 info = """Create a domain from a saved state."""
284 def help(self, args):
285 print args[0], "FILE"
286 print "\nRestore a domain from FILE."
288 def main(self, args):
289 if len(args) < 2: self.err("%s: Missing arguments" % args[0])
290 savefile = os.path.abspath(args[1])
291 info = server.xend_domain_restore(savefile)
292 PrettyPrint.prettyprint(info)
293 id = sxp.child_value(info, 'id')
294 if id is not None:
295 server.xend_domain_unpause(id)
297 xm.prog(ProgRestore)
299 class ProgMigrate(Prog):
300 group = 'domain'
301 name = "migrate"
302 info = """Migrate a domain to another machine."""
304 def help(self, args):
305 migrate.help([self.name] + args)
307 def main(self, args):
308 migrate.main(args)
310 xm.prog(ProgMigrate)
312 class ProgList(Prog):
313 group = 'domain'
314 name = "list"
315 info = """List information about domains."""
317 short_options = 'l'
318 long_options = ['long']
320 def help(self, args):
321 if help:
322 print args[0], '[options] [DOM...]'
323 print """\nGet information about domains.
324 Either all domains or the domains given.
326 -l, --long Get more detailed information.
327 """
328 return
330 def main(self, args):
331 use_long = 0
332 (options, params) = getopt(args[1:],
333 self.short_options,
334 self.long_options)
335 n = len(params)
336 for (k, v) in options:
337 if k in ['-l', '--long']:
338 use_long = 1
340 if n == 0:
341 doms = server.xend_domains()
342 doms.sort()
343 else:
344 doms = params
346 if use_long:
347 self.long_list(doms)
348 else:
349 self.brief_list(doms)
351 def brief_list(self, doms):
352 print 'Name Id Mem(MB) CPU State Time(s) Console'
353 for dom in doms:
354 info = server.xend_domain(dom)
355 d = {}
356 d['dom'] = int(sxp.child_value(info, 'id', '-1'))
357 d['name'] = sxp.child_value(info, 'name', '??')
358 d['mem'] = int(sxp.child_value(info, 'memory', '0'))
359 d['cpu'] = int(sxp.child_value(info, 'cpu', '0'))
360 d['state'] = sxp.child_value(info, 'state', '??')
361 d['cpu_time'] = float(sxp.child_value(info, 'cpu_time', '0'))
362 console = sxp.child(info, 'console')
363 if console:
364 d['port'] = sxp.child_value(console, 'console_port')
365 else:
366 d['port'] = ''
367 print ("%(name)-16s %(dom)3d %(mem)7d %(cpu)3d %(state)5s %(cpu_time)7.1f %(port)4s"
368 % d)
370 def long_list(self, doms):
371 for dom in doms:
372 info = server.xend_domain(dom)
373 PrettyPrint.prettyprint(info)
375 xm.prog(ProgList)
377 class ProgDestroy(Prog):
378 group = 'domain'
379 name = "destroy"
380 info = """Terminate a domain immediately."""
382 def help(self, args):
383 destroy.main([args[0], '-h'])
385 def main(self, args):
386 destroy.main(args)
388 xm.prog(ProgDestroy)
390 class ProgShutdown(Prog):
391 group = 'domain'
392 name = "shutdown"
393 info = """Shutdown a domain."""
395 def help(self, args):
396 shutdown.main([args[0], '-h'])
398 def main(self, args):
399 shutdown.main(args)
401 xm.prog(ProgShutdown)
403 class ProgPause(Prog):
404 group = 'domain'
405 name = "pause"
406 info = """Pause execution of a domain."""
408 def help(self, args):
409 print args[0], 'DOM'
410 print '\nPause execution of domain DOM.'
412 def main(self, args):
413 if len(args) < 2: self.err("%s: Missing domain" % args[0])
414 dom = args[1]
415 server.xend_domain_pause(dom)
417 xm.prog(ProgPause)
419 class ProgUnpause(Prog):
420 group = 'domain'
421 name = "unpause"
422 info = """Unpause a paused domain."""
424 def help(self, args):
425 print args[0], 'DOM'
426 print '\nUnpause execution of domain DOM.'
428 def main(self, args):
429 if len(args) < 2: self.err("%s: Missing domain" % args[0])
430 dom = args[1]
431 server.xend_domain_unpause(dom)
433 xm.prog(ProgUnpause)
435 class ProgPincpu(Prog):
436 group = 'domain'
437 name = "pincpu"
438 info = """Pin a domain to a cpu. """
440 def help(self, args):
441 print args[0],'DOM CPU'
442 print '\nPin domain DOM to cpu CPU.'
444 def main(self, args):
445 if len(args) != 3: self.err("%s: Invalid argument(s)" % args[0])
446 dom = args[1]
447 cpu = int(args[2])
448 server.xend_domain_pincpu(dom, cpu)
450 xm.prog(ProgPincpu)
452 class ProgMaxmem(Prog):
453 group = 'domain'
454 name = 'maxmem'
455 info = """Set domain memory limit."""
457 def help(self, args):
458 print args[0], "DOM MEMORY"
459 print "\nSet the memory limit for domain DOM to MEMORY megabytes."
461 def main(self, args):
462 if len(args) != 3: self.err("%s: Invalid argument(s)" % args[0])
463 dom = args[1]
464 mem = int(args[2])
465 server.xend_domain_maxmem_set(dom, mem)
467 xm.prog(ProgMaxmem)
469 class ProgDomid(Prog):
470 group = 'domain'
471 name = 'domid'
472 info = 'Convert a domain name to a domain id.'
474 def help(self, args):
475 print args[0], "DOM"
476 print '\nGet the domain id for the domain with name DOM.'
478 def main (self, args):
479 if len(args) != 2: self.err("%s: Invalid argument(s)" % args[0])
480 name = args[1]
481 dom = server.xend_domain(name)
482 print sxp.child_value(dom, 'id')
484 xm.prog(ProgDomid)
486 class ProgDomname(Prog):
487 group = 'domain'
488 name = 'domname'
489 info = 'Convert a domain id to a domain name.'
491 def help(self, args):
492 print args[0], "DOM"
493 print '\nGet the name for the domain with id DOM.'
495 def main (self, args):
496 if len(args) != 2: self.err("%s: Invalid argument(s)" % args[0])
497 name = args[1]
498 dom = server.xend_domain(name)
499 print sxp.child_value(dom, 'name')
501 xm.prog(ProgDomname)
503 class ProgBvt(Prog):
504 group = 'scheduler'
505 name = "bvt"
506 info = """Set BVT scheduler parameters."""
508 def help(self, args):
509 print args[0], "DOM MCUADV WARPBACK WARPVALUE WARPL WARPU"
510 print '\nSet Borrowed Virtual Time scheduler parameters.'
512 def main(self, args):
513 if len(args) != 7: self.err("%s: Invalid argument(s)" % args[0])
514 dom = args[1]
515 v = map(long, args[2:7])
516 server.xend_domain_cpu_bvt_set(dom, *v)
518 xm.prog(ProgBvt)
520 class ProgBvtslice(Prog):
521 group = 'scheduler'
522 name = "bvt_ctxallow"
523 info = """Set the BVT scheduler context switch allowance."""
525 def help(self, args):
526 print args[0], 'CTX_ALLOW'
527 print '\nSet Borrowed Virtual Time scheduler context switch allowance.'
529 def main(self, args):
530 if len(args) < 2: self.err('%s: Missing context switch allowance'
531 % args[0])
532 slice = int(args[1])
533 server.xend_node_cpu_bvt_slice_set(slice)
535 xm.prog(ProgBvtslice)
537 class ProgFbvt(Prog):
538 group = 'scheduler'
539 name = "fbvt"
540 info = """Set FBVT scheduler parameters."""
542 def help(self, args):
543 print args[0], "DOM MCUADV WARP WARPL WARPU"
544 print '\nSet Fair Borrowed Virtual Time scheduler parameters.'
546 def main(self, args):
547 if len(args) != 6: self.err("%s: Invalid argument(s)" % args[0])
548 dom = args[1]
549 v = map(int, args[2:6])
550 server.xend_domain_cpu_fbvt_set(dom, *v)
552 xm.prog(ProgFbvt)
554 class ProgFbvtslice(Prog):
555 group = 'scheduler'
556 name = "fbvt_ctxallow"
557 info = """Set the FBVT scheduler context switch allowance."""
559 def help(self, args):
560 print args[0], 'CTX_ALLOW'
561 print '\nSet Fair Borrowed Virtual Time scheduler context switch allowance.'
563 def main(self, args):
564 if len(args) < 2: self.err('%s: Missing context switch allowance.'
565 % args[0])
566 ctx_allow = int(args[1])
567 server.xend_node_cpu_fbvt_slice_set(ctx_allow)
569 xm.prog(ProgFbvtslice)
572 class ProgAtropos(Prog):
573 group = 'scheduler'
574 name= "atropos"
575 info = """Set atropos parameters."""
577 def help(self, args):
578 print args[0], "DOM PERIOD SLICE LATENCY XTRATIME"
579 print "\nSet atropos parameters."
581 def main(self, args):
582 if len(args) != 6: self.err("%s: Invalid argument(s)" % args[0])
583 dom = args[1]
584 v = map(int, args[2:6])
585 server.xend_domain_cpu_atropos_set(dom, *v)
587 xm.prog(ProgAtropos)
589 class ProgRrobin(Prog):
590 group = 'scheduler'
591 name = "rrobin"
592 info = """Set round robin slice."""
594 def help(self, args):
595 print args[0], "SLICE"
596 print "\nSet round robin scheduler slice."
598 def main(self, args):
599 if len(args) != 2: self.err("%s: Invalid argument(s)" % args[0])
600 rrslice = int(args[1])
601 server.xend_node_rrobin_set(rrslice)
603 xm.prog(ProgRrobin)
605 class ProgInfo(Prog):
606 group = 'host'
607 name = "info"
608 info = """Get information about the xen host."""
610 def main(self, args):
611 info = server.xend_node()
612 for x in info[1:]:
613 print "%-23s:" % x[0], x[1]
615 xm.prog(ProgInfo)
617 class ProgConsoles(Prog):
618 group = 'console'
619 name = "consoles"
620 info = """Get information about domain consoles."""
622 def main(self, args):
623 l = server.xend_consoles()
624 print "Dom Port Id Connection"
625 for x in l:
626 info = server.xend_console(x)
627 d = {}
628 d['dom'] = sxp.child(info, 'domain', '?')[1]
629 d['port'] = sxp.child_value(info, 'console_port', '?')
630 d['id'] = sxp.child_value(info, 'id', '?')
631 connected = sxp.child(info, 'connected')
632 if connected:
633 d['conn'] = '%s:%s' % (connected[1], connected[2])
634 else:
635 d['conn'] = ''
636 print "%(dom)3s %(port)4s %(id)3s %(conn)s" % d
638 xm.prog(ProgConsoles)
640 class ProgConsole(Prog):
641 group = 'console'
642 name = "console"
643 info = """Open a console to a domain."""
645 def help(self, args):
646 print args[0], "DOM"
647 print "\nOpen a console to domain DOM."
649 def main(self, args):
650 if len(args) < 2: self.err("%s: Missing domain" % args[0])
651 dom = args[1]
652 info = server.xend_domain(dom)
653 console = sxp.child(info, "console")
654 if not console:
655 self.err("No console information")
656 port = sxp.child_value(console, "console_port")
657 from xen.util import console_client
658 console_client.connect("localhost", int(port))
660 xm.prog(ProgConsole)
662 class ProgCall(Prog):
663 name = "call"
664 info = "Call xend api functions."
666 def help (self, args):
667 print args[0], "function args..."
668 print """
669 Call a xend HTTP API function. The leading 'xend_' on the function
670 can be omitted. See xen.xend.XendClient for the API functions.
671 """
673 def main(self, args):
674 xend_client_main(args)
676 xm.prog(ProgCall)
678 class ProgDmesg(Prog):
679 group = 'host'
680 name = "dmesg"
681 info = """Print Xen boot output."""
683 def main(self, args):
684 print server.xend_node_dmesg()
686 xm.prog(ProgDmesg)
688 class ProgLog(Prog):
689 group = 'host'
690 name = "log"
691 info = """Print the xend log."""
693 def main(self, args):
694 print server.xend_node_log()
696 xm.prog(ProgLog)
698 class ProgVifList(Prog):
699 group = 'vif'
700 name = 'vif-list'
701 info = """List virtual network interfaces for a domain."""
703 def help(self, args):
704 print args[0], "DOM"
705 print "\nList virtual network interfaces for domain DOM"
707 def main(self, args):
708 if len(args) != 2: self.err("%s: Invalid argument(s)" % args[0])
709 dom = args[1]
710 for x in server.xend_domain_vifs(dom):
711 sxp.show(x)
712 print
714 xm.prog(ProgVifList)
716 class ProgVbdList(Prog):
717 group = 'vbd'
718 name = 'vbd-list'
719 info = """List virtual block devices for a domain."""
721 def help(self, args):
722 print args[0], "DOM"
723 print "\nList virtual block devices for domain DOM"
725 def main(self, args):
726 if len(args) != 2: self.err("%s: Invalid argument(s)" % args[0])
727 dom = args[1]
728 for x in server.xend_domain_vbds(dom):
729 sxp.show(x)
730 print
732 xm.prog(ProgVbdList)
734 class ProgVbdCreate(Prog):
735 group = 'vbd'
736 name = 'vbd-create'
737 info = """Create a new virtual block device for a domain"""
739 def help(self, args):
740 print args[0], "DOM UNAME DEV MODE [BACKEND]"
741 print """
742 Create a virtual block device for a domain.
744 UNAME - device to export, e.g. phy:hda2
745 DEV - device name in the domain, e.g. xda1
746 MODE - access mode: r for read, w for read-write
747 BACKEND - backend driver domain
748 """
750 def main(self, args):
751 n = len(args)
752 if n < 5 or n > 6: self.err("%s: Invalid argument(s)" % args[0])
753 dom = args[1]
754 vbd = ['vbd',
755 ['uname', args[2]],
756 ['dev', args[3]],
757 ['mode', args[4]]]
758 if n == 6:
759 vbd.append(['backend', args[5]])
760 server.xend_domain_device_create(dom, vbd)
762 xm.prog(ProgVbdCreate)
764 class ProgVbdDestroy(Prog):
765 group = 'vbd'
766 name = 'vbd-destroy'
767 info = """Destroy a domain's virtual block device"""
769 def help(self, args):
770 print args[0], "DOM DEV"
771 print """
772 Destroy vbd DEV attached to domain DOM. Detaches the device
773 from the domain, but does not destroy the device contents.
774 The device indentifier DEV is the idx field in the device
775 information. This is visible in 'xm vbd-list'."""
777 def main(self, args):
778 if len(args) != 3: self.err("%s: Invalid argument(s)" % args[0])
779 dom = args[1]
780 dev = args[2]
781 server.xend_domain_device_destroy(dom, "vbd", dev)
783 xm.prog(ProgVbdDestroy)
785 def main(args):
786 xm.main(args)