diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/xend/lib/domain_controller.h | 7 | ||||
-rw-r--r-- | tools/xend/lib/utils.c | 1 | ||||
-rw-r--r-- | tools/xenmgr/lib/XendDomainInfo.py | 3 | ||||
-rwxr-xr-x | tools/xenmgr/lib/server/channel.py | 141 | ||||
-rw-r--r-- | tools/xenmgr/lib/xm/create.py | 20 | ||||
-rw-r--r-- | tools/xenmgr/lib/xm/main.py | 52 |
6 files changed, 178 insertions, 46 deletions
diff --git a/tools/xend/lib/domain_controller.h b/tools/xend/lib/domain_controller.h index af202b5ec3..8a9cea0664 100644 --- a/tools/xend/lib/domain_controller.h +++ b/tools/xend/lib/domain_controller.h @@ -523,21 +523,20 @@ typedef struct { */ /* - * Subtypes for console messages. + * Subtypes for suspend messages. */ /* None. */ /****************************************************************************** - * CONSOLE DEFINITIONS + * SHUTDOWN DEFINITIONS */ /* - * Subtypes for console messages. + * Subtypes for shutdown messages. */ #define CMSG_SHUTDOWN_HALT 0 /* Shutdown and halt (don't die). */ #define CMSG_SHUTDOWN_POWEROFF 1 /* 'Poweroff' => clean death. */ #define CMSG_SHUTDOWN_REBOOT 2 /* Shutdown and restart. */ - #endif /* __DOMAIN_CONTROLLER_H__ */ diff --git a/tools/xend/lib/utils.c b/tools/xend/lib/utils.c index f761490648..2d96577203 100644 --- a/tools/xend/lib/utils.c +++ b/tools/xend/lib/utils.c @@ -607,6 +607,7 @@ static PyObject *xu_message_new(PyObject *self, PyObject *args) case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED): P2C(netif_fe_driver_status_changed_t, status, u32); P2C(netif_fe_driver_status_changed_t, nr_interfaces, u32); + break; } if ( dict_items_parsed != PyDict_Size(payload) ) diff --git a/tools/xenmgr/lib/XendDomainInfo.py b/tools/xenmgr/lib/XendDomainInfo.py index f05397c169..db636136a2 100644 --- a/tools/xenmgr/lib/XendDomainInfo.py +++ b/tools/xenmgr/lib/XendDomainInfo.py @@ -350,6 +350,8 @@ def xen_domain_create(config, ostype, name, memory, kernel, ramdisk, cmdline, vi buildfn = getattr(xc, '%s_build' % ostype) print 'xen_domain_create> build ', ostype, dom, kernel, cmdline, ramdisk + if len(cmdline) >= 256: + print 'Warning: kernel cmdline too long' err = buildfn(dom = dom, image = kernel, control_evtchn = console.port2, @@ -433,7 +435,6 @@ def vm_create(config): """ # todo - add support for scheduling params? print 'vm_create>' - xenctl.vdisk.VBD_EXPERT_MODE = 0 vm = None try: name = sxp.child_value(config, 'name') diff --git a/tools/xenmgr/lib/server/channel.py b/tools/xenmgr/lib/server/channel.py index 04f7441f7a..130d23254f 100755 --- a/tools/xenmgr/lib/server/channel.py +++ b/tools/xenmgr/lib/server/channel.py @@ -41,14 +41,28 @@ class ChannelFactory: def domChannel(self, dom): """Get the channel for the given domain. + Construct if necessary. """ for chan in self.channels.values(): + if not isinstance(chan, Channel): continue if chan.dom == dom: return chan chan = Channel(self, dom) self.addChannel(chan) return chan + def virqChannel(self, virq): + """Get the channel for the given virq. + Construct if necessary. + """ + for chan in self.channels.values(): + if not isinstance(chan, VirqChannel): continue + if chan.virq == virq: + return chan + chan = VirqChannel(self, virq) + self.addChannel(chan) + return chan + def channelClosed(self, channel): """The given channel has been closed - remove it. """ @@ -70,28 +84,127 @@ def channelFactory(): inst = ChannelFactory() return inst -class Channel: +class BaseChannel: + """Abstract superclass for channels. + + The subclass constructor must set idx to the port to use. + """ + + def __init__(self, factory): + self.factory = factory + self.idx = -1 + self.closed = 0 + + def getIndex(self): + """Get the channel index. + """ + return self.idx + + def notificationReceived(self, type): + """Called when a notification is received. + Closes the channel on error, otherwise calls + handleNotification(type), which should be defined + in a subclass. + """ + #print 'notificationReceived> type=', type, self + if self.closed: return + if type == self.factory.notifier.EXCEPTION: + print 'notificationReceived> EXCEPTION' + info = xc.evtchn_status(self.idx) + if info['status'] == 'unbound': + print 'notificationReceived> EXCEPTION closing...' + self.close() + return + self.handleNotification(type) + + def close(self): + """Close the channel. Calls channelClosed() on the factory. + Override in subclass. + """ + self.factory.channelClosed(self) + + def handleNotification(self, type): + """Handle notification. + Define in subclass. + """ + pass + + +class VirqChannel(BaseChannel): + """A channel for handling a virq. + """ + + def __init__(self, factory, virq): + """Create a channel for the given virq using the given factory. + + Do not call directly, use virqChannel on the factory. + """ + BaseChannel.__init__(self, factory) + self.virq = virq + # Notification port (int). + self.port = xc.evtchn_bind_virq(virq) + self.idx = port + # Clients to call when a virq arrives. + self.clients = [] + + def __repr__(self): + return ('<VirqChannel virq=%d port=%d>' + % (self.virq, self.port)) + + def getVirq(self): + """Get the channel's virq. + """ + return self.virq + + def close(self): + """Close the channel. Calls lostChannel(self) on all its clients and + channelClosed() on the factory. + """ + for c in self.clients: + c.lostChannel(self) + del self.clients + BaseChannel.close(self) + + def registerClient(self, client): + """Register a client. The client will be called with + client.virqReceived(virq) when a virq is received. + The client will be called with client.lostChannel(self) if the + channel is closed. + """ + self.clients.append(client) + + def handleNotification(self, type): + for c in self.clients: + c.virqReceived(self.virq) + + def notify(self): + xc.evtchn_send(self.port) + + +class Channel(BaseChannel): """A control channel to a domain. Messages for the domain device controllers are multiplexed over the channel (console, block devs, net devs). """ def __init__(self, factory, dom): """Create a channel to the given domain using the given factory. + + Do not call directly, use domChannel on the factory. """ - self.factory = factory + BaseChannel.__init__(self, factory) + # Domain. self.dom = dom + # Domain port (object). self.port = self.factory.createPort(dom) + # Channel port (int). self.idx = self.port.local_port + # Registered devices. self.devs = [] + # Devices indexed by the message types they handle. self.devs_by_type = {} - self.closed = 0 + # Output queue. self.queue = [] - def getIndex(self): - """Get the channel index. - """ - return self.idx - def getLocalPort(self): """Get the local port. """ @@ -153,23 +266,13 @@ class Channel: self.port.local_port, self.port.remote_port)) - def notificationReceived(self, type): - #print 'notificationReceived> type=', type, self - if self.closed: return - if type == self.factory.notifier.EXCEPTION: - print 'notificationReceived> EXCEPTION' - info = xc.evtchn_status(self.idx) - if info['status'] == 'unbound': - print 'notificationReceived> EXCEPTION closing...' - self.close() - return + def handleNotification(self, type): work = 0 work += self.handleRequests() work += self.handleResponses() work += self.handleWrites() if work: self.notify() - #print 'notificationReceived<', work def notify(self): self.port.notify() diff --git a/tools/xenmgr/lib/xm/create.py b/tools/xenmgr/lib/xm/create.py index 3843007a10..a5e9e888c5 100644 --- a/tools/xenmgr/lib/xm/create.py +++ b/tools/xenmgr/lib/xm/create.py @@ -30,7 +30,11 @@ gopts.opt('defaults', short='f', val='FILE', gopts.opt('config', short='F', val='FILE', fn=set_value, default=None, - use='Domain configuration to use.') + use='Domain configuration to use (SXP).') + +gopts.opt('load', short='L', val='FILE', + fn=set_value, default=None, + use='Domain saved state to load.') def set_var(opt, k, v): opt.set(v) @@ -231,6 +235,7 @@ def preprocess_ip(opts): setip = (opts.hostname or opts.netmask or opts.gateway or opts.dhcp or opts.interface) if not setip: return + if not opts ip = (opts.ip + ':' + ':' + opts.gateway @@ -261,10 +266,9 @@ def make_domain(opts, config): """Create, build and start a domain. Returns: [int] the ID of the new domain. """ - restore = 0 #todo - - if restore: - dominfo = server.xend_domain_restore(state_file, config) + if opts.load: + filename = os.path.abspath(opts.load) + dominfo = server.xend_domain_restore(filename, config) else: dominfo = server.xend_domain_create(config) @@ -285,13 +289,13 @@ def make_domain(opts, config): def main(argv): opts = gopts args = opts.parse(argv) + if opts.help: + opts.usage() + return if opts.config: pass else: opts.load_defaults() - if opts.help: - opts.usage() - return preprocess(opts) config = make_config(opts) if opts.dryrun: diff --git a/tools/xenmgr/lib/xm/main.py b/tools/xenmgr/lib/xm/main.py index 32a7be879b..fb7d839f4a 100644 --- a/tools/xenmgr/lib/xm/main.py +++ b/tools/xenmgr/lib/xm/main.py @@ -1,4 +1,8 @@ -#!/usr/bin/python +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com> +"""Grand unified management application for Xen. +""" +import os +import os.path import sys from xenmgr import PrettyPrint @@ -17,6 +21,8 @@ class Xm: sys.exit(1) def main(self, args): + """Main entry point. Dispatches to the xm_ methods. + """ self.prog = args[0] if len(args) < 2: self.err("Missing command\nTry '%s help' for more information." @@ -33,10 +39,16 @@ class Xm: return 0 def unknown(self, help, args): - self.err("Unknown command: %s\nTry '%s help' for more information." - % (args[0], self.prog)) + if help and len(args) == 1: + self.xm_help(help, args) + else: + self.err("Unknown command: %s\nTry '%s help' for more information." + % (args[0], self.prog)) def help(self, meth, args): + """Print help on an xm_ method. + Uses the method documentation string if there is one. + """ name = meth[3:] f = getattr(self, meth) print "%-14s %s" % (name, f.__doc__ or '') @@ -53,24 +65,36 @@ class Xm: create.main(args) def xm_save(self, help, args): - """Save domain state to file.""" + """Save domain state (and config) to file.""" if help: - print args[0], "DOM FILE" - print "\nSave domain with id DOM to FILE." + print args[0], "DOM FILE [CONFIG]" + print """\nSave domain with id DOM to FILE. + Optionally save config to CONFIG.""" return if len(args) < 3: self.err("%s: Missing arguments" % args[0]) dom = args[1] - filename = args[2] - server.xend_domain_save(dom, filename) - + savefile = os.path.abspath(args[2]) + configfile = None + if len(args) == 4: + configfile = os.path.abspath(args[3]) + if configfile: + out = file(configfile, 'w') + config = server.xend_domain(dom) + PrettyPrint.prettyprint(config, out=out) + out.close() + server.xend_domain_save(dom, savefile) + def xm_restore(self, help, args): """Create a domain from a saved state.""" if help: - print args[0], "FILE" - print "\nRestore a domain from FILE." - if len(args) < 2: self.err("%s: Missing file" % args[0]) - filename = args[1] - server.xend_domain_restore(None, filename) + print args[0], "FILE CONFIG" + print "\nRestore a domain from FILE using configuration CONFIG." + return + if len(args) < 3: self.err("%s: Missing arguments" % args[0]) + savefile = os.path.abspath(args[1]) + configfile = os.path.abspath(args[2]) + info = server.xend_domain_restore(savefile, configfile) + PrettyPrint.prettyprint(info) def xm_domains(self, help, args): """List domains.""" |