#!/usr/bin/python from xen.lowlevel import xl class PyxlError(xl.Error): pass class PyxlArgError(PyxlError): pass class PyxlNoDomain(PyxlError): pass def superclass(self, orig, type, kwargs): if orig == None: return if orig.__class__ != type: raise TypeError map(lambda (k,v): kwargs.setdefault(k, v), filter(lambda (k,v): k[0] != '_' and not callable(v), map(lambda k:(k, getattr(orig, k)), dir(orig)))) return class Ctx: class __impl(xl.ctx): pass __instance = None def __init__(self): if Ctx.__instance is None: Ctx.__instance = self.__impl() self.__dict__['Ctx_instance'] = Ctx.__instance def __getattr__(self, attr): return getattr(self.__instance, attr) def __setattr__(self, attr, value): return setattr(self.__instance, attr, value) class DomInfo(xl.dominfo): def __init__(self, orig = None, **kwargs): superclass(self, orig, xl.dominfo, kwargs) xl.dominfo.__init__(self, **kwargs) self.name = None def set_name(self, name): self.name = str(name) def __repr__(self): if self.name is not None: return 'dominfo(%s:%d)'%(self.name, self.domid) else: return 'dominfo(%d)'%self.domid def __str__(self): return '%s %5d %5lu %5d %s%s%s%s%s%s %8.1f'%(self.name.ljust(40), self.domid, self.max_memkb / 1024, self.vcpu_online, self.running and 'r' or '-', self.blocked and 'b' or '-', self.paused and 'p' or '-', self.shutdown and 's' or '-', self.shutdown_reason == xl.SHUTDOWN_crash and 'c' or '-', self.dying and 'd' or '-', float(self.cpu_time) / 1e9) def find_domain(arg, by_name = True, by_id = True): ctx = Ctx() domlist = map(DomInfo, ctx.list_domains()) map(lambda x:x.set_name(ctx.domid_to_name(x.domid)), domlist) if by_id: dl_by_id = dict(map(lambda v:(v.domid, v), domlist)) try: return dl_by_id[int(arg)] except: pass if by_name: dl_by_name = dict(map(lambda v:(v.name, v), domlist)) try: return dl_by_name[str(arg)] except: pass raise PyxlNoDomain, "Domain '%s' not found"%arg def uuid(s): a = ''.join(map(lambda x:'%.2x'%x, s)) return '-'.join([a[0:8], a[8:12], a[12:16], a[16:20], a[20:]]) def do_rename(args): "Rename a domain" ctx = Ctx() if len(args) is not 3: raise PyxlArgError, 'Requires 2 arguments' d = find_domain(args[1]) ctx.domain_rename(d.domid, args[2], d.name) def do_list(args): "List information about all/some domains" verbose = '-v' in args ctx = Ctx() domlist = map(DomInfo, ctx.list_domains()) map(lambda x:x.set_name(ctx.domid_to_name(x.domid)), domlist) print 'Name ID Mem VCPUs\tState\tTime(s)' for x in domlist: print '%s%s'%(x, verbose and ' %s'%uuid(x.uuid) or '') def do_pause(args): "Pause execution of a domain" if len(args) is not 2: raise PyxlArgError ctx = Ctx() d = find_domain(args[1]) ctx.domain_pause(d.domid) def do_unpause(args): "Unpause a paused domain" if len(args) is not 2: raise PyxlArgError ctx = Ctx() d = find_domain(args[1]) ctx.domain_unpause(d.domid) def do_domid(args): "Convert a domain name to domain id" if len(args) is not 2: raise PyxlArgError ctx = Ctx() d = find_domain(args[1], by_id = False) print d.domid def do_domname(args): "Convert a domain id to domain name" if len(args) is not 2: raise PyxlArgError ctx = Ctx() d = find_domain(args[1], by_name = False) print d.name def do_pci_list_assignable(args): "List all the assignable pci devices" if len(args) is not 1: raise PyxlArgError ctx = Ctx() for x in ctx.device_pci_list_assignable(): print "%.4x:%.2x:%.2x.%.1x"%(x.domain, x.bus, x.dev, x.func) def do_pci_list(args): "List pass-through pci devices for a domain" if len(args) is not 2: raise PyxlArgError ctx = Ctx() d = find_domain(args[1]) for x in ctx.device_pci_list(d.domid): print "%.4x:%.2x:%.2x.%.1x"%(x.domain, x.bus, x.dev, x.func) def do_pci_add(args): "Insert a new pass-through pci device" if len(args) not in [3,4]: raise PyxlArgError ctx = Ctx() d = find_domain(args[1]) dev = ctx.device_pci_parse_bdf(args[2]) # TODO: virtual slot ctx.device_pci_add(d.domid, dev) def do_pci_del(args): "Remove a domain's pass-through pci device" if len(args) is not 3: raise PyxlArgError ctx = Ctx() d = find_domain(args[1]) dev = ctx.device_pci_parse_bdf(args[2]) ctx.device_pci_del(d.domid, dev) def callback(xl, domid, priv): print 'callback: %r %d %r'%(xl, domid, priv) def do_destroy(args): if len(args) not in [2,3]: raise PyxlArgError force = (len(args) > 2 and '-f' in args) ctx = Ctx() d = find_domain(args[1]) ctx.domain_destroy(d.domid, force) def do_create(args): hvmloader_path = '/home/scara/xen-unstable-tools.hg/tools/firmware/hvmloader/hvmloader' dm_path = '/home/scara/xen-unstable-tools.hg/tools/ioemu-remote/i386-dm/qemu-dm' name = 'pyxl-test' # create info ci = xl.domain_create_info() ci.hap = True ci.hvm = True ci.oos = True ci.name = name ci.platformdata = None ci.poolid = 0 ci.poolname = 'Pool-0' ci.xsdata = None ci.ssidref ci.uuid = ''.join([chr(0) for x in xrange(16)]) # build info bi = xl.domain_build_info() #bi.cpuid = None bi.cur_vcpus = 1 bi.max_vcpus = 1 bi.disable_migrate = False bi.hvm = True bi.u_hvm_pae = True bi.u_hvm_apic = True bi.u_hvm_acpi = True bi.u_hvm_nx = True bi.u_hvm_viridian = False bi.u_hvm_timeoffset = None bi.u_hvm_hpet = True bi.u_hvm_vpt_align = True bi.u_hvm_timer_mode = 1 bi.kernel = hvmloader_path bi.shadow_memkb = 3072 bi.video_memkb = 8192 bi.target_memkb = 262144 bi.max_memkb = 262144 bi.tsc_mode = 0 # create dm dm = xl.device_model_info() dm.device_model = dm_path dm.videoram = bi.video_memkb >> 10 dm.dom_name = name dm.boot = 'cda' dm.vnc = 1 dm.vncunused = 1 dm.vnclisten = '0.0.0.0' dm.apic = bi.u_hvm_apic dm.vcpus = bi.max_vcpus dm.vcpu_avail = bi.cur_vcpus # attach devices disks = [] d = xl.device_disk() d.physpath = '/vm/winxp.hd' d.phystype = 5 d.unpluggable = True d.virtpath = 'xvda' d.readwrite = True disks.append(d) config = xl.domain_config() config.c_info = ci config.b_info = bi config.dm_info = dm config.disks = disks ctx = Ctx() domid = ctx.domain_create(config, callback, 'test') print 'domid %d'%domid # unpause ctx.domain_unpause(domid) # daemonise maybe def do_help(args): "Print this message" global cmdtbl if len(args) > 1: usage(args[1]) return keys = cmdtbl.keys() keys.sort() print 'Usage pyxl [-v] [args]' print print 'pyxl full list of subcommands:' print for (k,fn,u) in map(lambda k:(k,) + cmdtbl[k], keys): print ' %s %s'%(k.ljust(20), fn.__doc__) def usage(subcmd, exc = None): global cmdtbl from sys import stderr if not cmdtbl.has_key(subcmd): stderr.write('No such command %s\n'%subcmd) return if exc is not None: for msg in (exc.args): stderr.write('\'xl %s\' %s\n'%(subcmd, msg)) if len(exc.args): stderr.write('\n') (fn, u) = cmdtbl[subcmd] stderr.write('Usage xl [-v] %s %s\n'%(subcmd, u)) stderr.write('\n%s\n\n'%fn.__doc__) cmdtbl = { 'create' : (do_create, ' [options] [vars]'), 'destroy' : (do_destroy, ' [-f]'), 'rename' : (do_rename, ' '), 'pause' : (do_pause, ''), 'unpause' : (do_unpause, ''), 'domid' : (do_domid, ''), 'domname' : (do_domname, ''), 'pci-attach' : (do_pci_add, ' [Virtual Slot]'), 'pci-detach' : (do_pci_del, ' '), 'pci-list' : (do_pci_list, ''), 'pci-list-assignable-devices' : (do_pci_list_assignable,''), 'list' : (do_list, '[Domain]'), 'help' : (do_help, '[subcommand]') } if __name__ == '__main__': from sys import argv if len(argv) < 2: do_help(['help']) raise SystemExit, True if not cmdtbl.has_key(argv[1]): from sys import stderr do_help(['help']) stderr.write('No such command %s\n'%argv[1]) raise SystemExit, True (fn, u) = cmdtbl[argv[1]] try: fn(argv[1:]) except PyxlArgError, e: usage(argv[1], e) raise SystemExit,True except xl.Error, e: from sys import stderr stderr.write('%s\n'%'\n'.join(map(lambda x:'Error: %s'%x, e.args))) raise SystemExit,True