direct-io.hg

view tools/python/xen/xm/main.py @ 2273:8c886cfa74e0

bitkeeper revision 1.1159.1.74 (4123662aRknZaZVDiDYz5H1bs5ZhmA)

Cset exclude: iap10@labyrinth.cl.cam.ac.uk|ChangeSet|20040817172414|62757
author iap10@labyrinth.cl.cam.ac.uk
date Wed Aug 18 14:22:34 2004 +0000 (2004-08-18)
parents dff63a2cfa54
children a6d73a771367
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([self.name] + 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 v = map(int, args[1:3])
447 server.xend_domain_pincpu(*v)
449 xm.prog(ProgPincpu)
451 class ProgMaxmem(Prog):
452 group = 'domain'
453 name = 'maxmem'
454 info = """Set domain memory limit."""
456 def help(self, args):
457 print args[0], "DOM MEMORY"
458 print "\nSet the memory limit for domain DOM to MEMORY megabytes."
460 def main(self, args):
461 if len(args) != 3: self.err("%s: Invalid argument(s)" % args[0])
462 v = map(int, args[1:3])
463 server.xend_domain_maxmem_set(*v)
465 xm.prog(ProgMaxmem)
467 class ProgDomid(Prog):
468 group = 'domain'
469 name = 'domid'
470 info = 'Convert a domain name to a domain id.'
472 def help(self, args):
473 print args[0], "DOM"
474 print '\nGet the domain id for the domain with name DOM.'
476 def main (self, args):
477 if len(args) != 2: self.err("%s: Invalid argument(s)" % args[0])
478 name = args[1]
479 dom = server.xend_domain(name)
480 print sxp.child_value(dom, 'id')
482 xm.prog(ProgDomid)
484 class ProgDomname(Prog):
485 group = 'domain'
486 name = 'domname'
487 info = 'Convert a domain id to a domain name.'
489 def help(self, args):
490 print args[0], "DOM"
491 print '\nGet the name for the domain with id DOM.'
493 def main (self, args):
494 if len(args) != 2: self.err("%s: Invalid argument(s)" % args[0])
495 name = args[1]
496 dom = server.xend_domain(name)
497 print sxp.child_value(dom, 'name')
499 xm.prog(ProgDomname)
501 class ProgBvt(Prog):
502 group = 'scheduler'
503 name = "bvt"
504 info = """Set BVT scheduler parameters."""
506 def help(self, args):
507 print args[0], "DOM MCUADV WARPBACK WARPVALUE WARPL WARPU"
508 print '\nSet Borrowed Virtual Time scheduler parameters.'
510 def main(self, args):
511 if len(args) != 7: self.err("%s: Invalid argument(s)" % args[0])
512 v = map(long, args[1:7])
513 server.xend_domain_cpu_bvt_set(*v)
515 xm.prog(ProgBvt)
517 class ProgBvtslice(Prog):
518 group = 'scheduler'
519 name = "bvt_ctxallow"
520 info = """Set the BVT scheduler context switch allowance."""
522 def help(self, args):
523 print args[0], 'CTX_ALLOW'
524 print '\nSet Borrowed Virtual Time scheduler context switch allowance.'
526 def main(self, args):
527 if len(args) < 2: self.err('%s: Missing context switch allowance'
528 % args[0])
529 slice = int(args[1])
530 server.xend_node_cpu_bvt_slice_set(slice)
532 xm.prog(ProgBvtslice)
534 class ProgFbvt(Prog):
535 group = 'scheduler'
536 name = "fbvt"
537 info = """Set FBVT scheduler parameters."""
539 def help(self, args):
540 print args[0], "DOM MCUADV WARP WARPL WARPU"
541 print '\nSet Fair Borrowed Virtual Time scheduler parameters.'
543 def main(self, args):
544 if len(args) != 6: self.err("%s: Invalid argument(s)" % args[0])
545 v = map(int, args[1:6])
546 server.xend_domain_cpu_fbvt_set(*v)
548 xm.prog(ProgFbvt)
550 class ProgFbvtslice(Prog):
551 group = 'scheduler'
552 name = "fbvt_ctxallow"
553 info = """Set the FBVT scheduler context switch allowance."""
555 def help(self, args):
556 print args[0], 'CTX_ALLOW'
557 print '\nSet Fair Borrowed Virtual Time scheduler context switch allowance.'
559 def main(self, args):
560 if len(args) < 2: self.err('%s: Missing context switch allowance.'
561 % args[0])
562 ctx_allow = int(args[1])
563 server.xend_node_cpu_fbvt_slice_set(ctx_allow)
565 xm.prog(ProgFbvtslice)
568 class ProgAtropos(Prog):
569 group = 'scheduler'
570 name= "atropos"
571 info = """Set atropos parameters."""
573 def help(self, args):
574 print args[0], "DOM PERIOD SLICE LATENCY XTRATIME"
575 print "\nSet atropos parameters."
577 def main(self, args):
578 if len(args) != 5: self.err("%s: Invalid argument(s)" % args[0])
579 v = map(int, args[1:5])
580 server.xend_domain_cpu_atropos_set(*v)
582 xm.prog(ProgAtropos)
584 class ProgRrobin(Prog):
585 group = 'scheduler'
586 name = "rrobin"
587 info = """Set round robin slice."""
589 def help(self, args):
590 print args[0], "SLICE"
591 print "\nSet round robin scheduler slice."
593 def main(self, args):
594 if len(args) != 2: self.err("%s: Invalid argument(s)" % args[0])
595 rrslice = int(args[1])
596 server.xend_node_rrobin_set(rrslice)
598 xm.prog(ProgRrobin)
600 class ProgInfo(Prog):
601 group = 'host'
602 name = "info"
603 info = """Get information about the xen host."""
605 def main(self, args):
606 info = server.xend_node()
607 for x in info[1:]:
608 print "%-23s:" % x[0], x[1]
610 xm.prog(ProgInfo)
612 class ProgConsoles(Prog):
613 group = 'console'
614 name = "consoles"
615 info = """Get information about domain consoles."""
617 def main(self, args):
618 l = server.xend_consoles()
619 print "Dom Port Id Connection"
620 for x in l:
621 info = server.xend_console(x)
622 d = {}
623 d['dom'] = sxp.child(info, 'domain', '?')[1]
624 d['port'] = sxp.child_value(info, 'console_port', '?')
625 d['id'] = sxp.child_value(info, 'id', '?')
626 connected = sxp.child(info, 'connected')
627 if connected:
628 d['conn'] = '%s:%s' % (connected[1], connected[2])
629 else:
630 d['conn'] = ''
631 print "%(dom)3s %(port)4s %(id)3s %(conn)s" % d
633 xm.prog(ProgConsoles)
635 class ProgConsole(Prog):
636 group = 'console'
637 name = "console"
638 info = """Open a console to a domain."""
640 def help(self, args):
641 print args[0], "DOM"
642 print "\nOpen a console to domain DOM."
644 def main(self, args):
645 if len(args) < 2: self.err("%s: Missing domain" % args[0])
646 dom = args[1]
647 info = server.xend_domain(dom)
648 console = sxp.child(info, "console")
649 if not console:
650 self.err("No console information")
651 port = sxp.child_value(console, "console_port")
652 from xen.util import console_client
653 console_client.connect("localhost", int(port))
655 xm.prog(ProgConsole)
657 class ProgCall(Prog):
658 name = "call"
659 info = "Call xend api functions."
661 def help (self, args):
662 print args[0], "function args..."
663 print """
664 Call a xend HTTP API function. The leading 'xend_' on the function
665 can be omitted. See xen.xend.XendClient for the API functions.
666 """
668 def main(self, args):
669 xend_client_main(args)
671 xm.prog(ProgCall)
673 class ProgDmesg(Prog):
674 group = 'host'
675 name = "dmesg"
676 info = """Print Xen boot output."""
678 def main(self, args):
679 print server.xend_node_dmesg()
681 xm.prog(ProgDmesg)
683 class ProgLog(Prog):
684 group = 'host'
685 name = "log"
686 info = """Print the xend log."""
688 def main(self, args):
689 print server.xend_node_log()
691 xm.prog(ProgLog)
693 class ProgVifList(Prog):
694 group = 'vif'
695 name = 'vif-list'
696 info = """List virtual network interfaces for a domain."""
698 def help(self, args):
699 print args[0], "DOM"
700 print "\nList virtual network interfaces for domain DOM"
702 def main(self, args):
703 if len(args) != 2: self.err("%s: Invalid argument(s)" % args[0])
704 dom = args[1]
705 for x in server.xend_domain_vifs(dom):
706 sxp.show(x)
707 print
709 xm.prog(ProgVifList)
711 class ProgVbdList(Prog):
712 group = 'vbd'
713 name = 'vbd-list'
714 info = """List virtual block devices for a domain."""
716 def help(self, args):
717 print args[0], "DOM"
718 print "\nList virtual block devices for domain DOM"
720 def main(self, args):
721 if len(args) != 2: self.err("%s: Invalid argument(s)" % args[0])
722 dom = args[1]
723 for x in server.xend_domain_vbds(dom):
724 sxp.show(x)
725 print
727 xm.prog(ProgVbdList)
729 class ProgVbdCreate(Prog):
730 group = 'vbd'
731 name = 'vbd-create'
732 info = """Create a new virtual block device for a domain"""
734 def help(self, args):
735 print args[0], "DOM UNAME DEV MODE"
736 print """
737 Create a virtual block device for a domain.
739 UNAME - device to export, e.g. phys:hda2
740 DEV - device name in the domain, e.g. xda1
741 MODE - access mode: r for read, w for read-write
742 """
744 def main(self, args):
745 if len(args) != 5: self.err("%s: Invalid argument(s)" % args[0])
746 dom = args[1]
747 vbd = ['vbd',
748 ['uname', args[2]],
749 ['dev', args[3]],
750 ['mode', args[4]]]
751 server.xend_domain_device_create(dom, vbd)
753 xm.prog(ProgVbdCreate)
755 class ProgVbdDestroy(Prog):
756 group = 'vbd'
757 name = 'vbd-destroy'
758 info = """Destroy a domain's virtual block device"""
760 def help(self, args):
761 print args[0], "DOM DEV"
762 print """
763 Destroy vbd DEV attached to domain DOM. Detaches the device
764 from the domain, but does not destroy the device contents."""
766 def main(self, args):
767 if len(args!=3): self.err("%s: Invalid argument(s)" % args[0])
768 dom = args[1]
769 dev = args[2]
770 sever.xend_domain_device_destroy(dom, "vbd", dev)
772 xm.prog(ProgVbdDestroy)
774 def main(args):
775 xm.main(args)