ia64/xen-unstable

changeset 1564:46d2220a5d07

bitkeeper revision 1.1011.1.1 (40dac272gGtMUxrtDr9Jr2GTujO_-w)

Merge ssh://xenbk@gandalf.hpl.hp.com//var/bk/xeno-unstable.bk
into labyrinth.cl.cam.ac.uk:/auto/groups/xeno/BK/xeno.bk
author iap10@labyrinth.cl.cam.ac.uk
date Thu Jun 24 12:00:50 2004 +0000 (2004-06-24)
parents 6802d4f0ce7f 92c056054f01
children f027c0742a03
files docs/xen_config.html tools/xenmgr/lib/EventTypes.py tools/xenmgr/lib/XendClient.py tools/xenmgr/lib/XendDomain.py tools/xenmgr/lib/XendDomainInfo.py tools/xenmgr/lib/server/SrvConsoleServer.py tools/xenmgr/lib/server/SrvDomain.py tools/xenmgr/lib/server/blkif.py tools/xenmgr/lib/server/controller.py tools/xenmgr/lib/server/messages.py tools/xenmgr/lib/server/netif.py tools/xenmgr/lib/xm/create.py tools/xenmgr/lib/xm/main.py tools/xenmgr/lib/xm/opts.py tools/xenmgr/lib/xm/shutdown.py
line diff
     1.1 --- a/docs/xen_config.html	Thu Jun 24 10:28:58 2004 +0000
     1.2 +++ b/docs/xen_config.html	Thu Jun 24 12:00:50 2004 +0000
     1.3 @@ -86,13 +86,13 @@ Defines a netbsd kernel image and its co
     1.4      <li>args: string, optional. Extra kernel args.
     1.5  </ul>
     1.6  
     1.7 -<h2>(controller (block)) element</h2>
     1.8 -Define that the vm is a block device controller backend.
     1.9 +<h2>(backend (blkif)) element</h2>
    1.10 +The vm is a block device backend.
    1.11  The vm can have pci devices configured, but no virtual
    1.12  block devices.
    1.13  
    1.14 -<h2>(controller (net)) element</h2>
    1.15 -Define that the vm is a net device controller backend.
    1.16 +<h2>(backend (netif)) element</h2>
    1.17 +The vm is a net device backend.
    1.18  The domain may not have virtual network interfaces (vifs) configured.
    1.19  
    1.20  <h2>(device (vif)) element</h2>
     2.1 --- a/tools/xenmgr/lib/EventTypes.py	Thu Jun 24 10:28:58 2004 +0000
     2.2 +++ b/tools/xenmgr/lib/EventTypes.py	Thu Jun 24 12:00:50 2004 +0000
     2.3 @@ -8,7 +8,7 @@
     2.4  ## xend.domain.unpause: dom
     2.5  ## xend.domain.pause: dom
     2.6  ## xend.domain.shutdown: dom
     2.7 -## xend.domain.halt: dom
     2.8 +## xend.domain.destroy: dom
     2.9  
    2.10  ## xend.domain.migrate.begin: dom, to
    2.11  ## Begin tells: src host, src domain uri, dst host. Dst id known?
     3.1 --- a/tools/xenmgr/lib/XendClient.py	Thu Jun 24 10:28:58 2004 +0000
     3.2 +++ b/tools/xenmgr/lib/XendClient.py	Thu Jun 24 12:00:50 2004 +0000
     3.3 @@ -199,9 +199,9 @@ class Xend:
     3.4          return xend_call(self.domainurl(id),
     3.5                           {'op'      : 'shutdown'})
     3.6  
     3.7 -    def xend_domain_halt(self, id):
     3.8 +    def xend_domain_destroy(self, id):
     3.9          return xend_call(self.domainurl(id),
    3.10 -                         {'op'      : 'halt'})
    3.11 +                         {'op'      : 'destroy'})
    3.12  
    3.13      def xend_domain_save(self, id, filename):
    3.14          return xend_call(self.domainurl(id),
     4.1 --- a/tools/xenmgr/lib/XendDomain.py	Thu Jun 24 10:28:58 2004 +0000
     4.2 +++ b/tools/xenmgr/lib/XendDomain.py	Thu Jun 24 12:00:50 2004 +0000
     4.3 @@ -6,6 +6,8 @@
     4.4  """
     4.5  import sys
     4.6  
     4.7 +from twisted.internet import defer
     4.8 +
     4.9  import Xc; xc = Xc.new()
    4.10  import xenctl.ip
    4.11  
    4.12 @@ -59,21 +61,26 @@ class XendDomain:
    4.13          for d in domlist:
    4.14              domid = str(d['dom'])
    4.15              doms[domid] = d
    4.16 +        dlist = []
    4.17          for config in self.domain_db.values():
    4.18              domid = str(sxp.child_value(config, 'id'))
    4.19              print "dom=", domid, "config=", config
    4.20              if domid in doms:
    4.21                  print "dom=", domid, "new"
    4.22 -                self._new_domain(config)
    4.23 +                deferred = self._new_domain(config, doms[domid])
    4.24 +                dlist.append(deferred)
    4.25              else:
    4.26                  print "dom=", domid, "del"
    4.27                  self._delete_domain(domid)
    4.28 -        print "doms:"
    4.29 -        for d in self.domain.values(): print 'dom', d
    4.30 -        print "refresh..."
    4.31 -        self.refresh()
    4.32 -        print "doms:"
    4.33 -        for d in self.domain.values(): print 'dom', d
    4.34 +        deferred = defer.DeferredList(dlist, fireOnOneErrback=1)
    4.35 +        def cbok(val):
    4.36 +            print "doms:"
    4.37 +            for d in self.domain.values(): print 'dom', d
    4.38 +            print "refresh..."
    4.39 +            self.refresh()
    4.40 +            print "doms:"
    4.41 +            for d in self.domain.values(): print 'dom', d
    4.42 +        deferred.addCallback(cbok)
    4.43  
    4.44      def sync(self):
    4.45          """Sync domain db to disk.
    4.46 @@ -90,31 +97,36 @@ class XendDomain:
    4.47      def close(self):
    4.48          pass
    4.49  
    4.50 -    def _new_domain(self, info):
    4.51 +    def _new_domain(self, savedinfo, info):
    4.52          """Create a domain entry from saved info.
    4.53          """
    4.54 -        console = None
    4.55 -        kernel = None
    4.56 -        id = sxp.child_value(info, 'id')
    4.57 -        dom = int(id)
    4.58 -        name = sxp.child_value(info, 'name')
    4.59 -        memory = int(sxp.child_value(info, 'memory'))
    4.60 -        consoleinfo = sxp.child(info, 'console')
    4.61 -        if consoleinfo:
    4.62 -            consoleid = sxp.child_value(consoleinfo, 'id')
    4.63 -            console = self.xconsole.console_get(consoleid)
    4.64 -        if dom and console is None:
    4.65 -            # Try to connect a console.
    4.66 -            console = self.xconsole.console_create(dom)
    4.67 -        config = sxp.child(info, 'config')
    4.68 -        if config:
    4.69 -            image = sxp.child(info, 'image')
    4.70 -            if image:
    4.71 -                image = sxp.child0(image)
    4.72 -                kernel = sxp.child_value(image, 'kernel')
    4.73 -        dominfo = XendDomainInfo.XendDomainInfo(
    4.74 -            config, dom, name, memory, kernel, console)
    4.75 -        self.domain[id] = dominfo
    4.76 +##         console = None
    4.77 +##         kernel = None
    4.78 +##         id = sxp.child_value(info, 'id')
    4.79 +##         dom = int(id)
    4.80 +##         name = sxp.child_value(info, 'name')
    4.81 +##         memory = int(sxp.child_value(info, 'memory'))
    4.82 +##         consoleinfo = sxp.child(info, 'console')
    4.83 +##         if consoleinfo:
    4.84 +##             consoleid = sxp.child_value(consoleinfo, 'id')
    4.85 +##             console = self.xconsole.console_get(consoleid)
    4.86 +##         if dom and console is None:
    4.87 +##             # Try to connect a console.
    4.88 +##             console = self.xconsole.console_create(dom)
    4.89 +##         config = sxp.child(info, 'config')
    4.90 +##         if config:
    4.91 +##             image = sxp.child(info, 'image')
    4.92 +##             if image:
    4.93 +##                 image = sxp.child0(image)
    4.94 +##                 kernel = sxp.child_value(image, 'kernel')
    4.95 +##         dominfo = XendDomainInfo.XendDomainInfo(
    4.96 +##             config, dom, name, memory, kernel, console)
    4.97 +        config = sxp.child_value(savedinfo, 'config')
    4.98 +        deferred = XendDomainInfo.vm_recreate(config, info)
    4.99 +        def fn(dominfo):
   4.100 +            self.domain[dominfo.id] = dominfo
   4.101 +        deferred.addCallback(fn)
   4.102 +        return deferred
   4.103  
   4.104      def _add_domain(self, id, info, notify=1):
   4.105          self.domain[id] = info
   4.106 @@ -143,10 +155,13 @@ class XendDomain:
   4.107              doms[id] = d
   4.108              if id not in self.domain:
   4.109                  config = None
   4.110 -                image = None
   4.111 -                newinfo = XendDomainInfo.XendDomainInfo(
   4.112 -                    config, d['dom'], d['name'], d['mem_kb']/1024, image=image, info=d)
   4.113 -                self._add_domain(newinfo.id, newinfo)
   4.114 +                #image = None
   4.115 +                #newinfo = XendDomainInfo.XendDomainInfo(
   4.116 +                #    config, d['dom'], d['name'], d['mem_kb']/1024, image=image, info=d)
   4.117 +                deferred = XendDomainInfo.vm_recreate(config, d)
   4.118 +                def fn(dominfo):
   4.119 +                    self._add_domain(dominfo.id, dominfo)
   4.120 +                deferred.addCallback(fn)
   4.121          # Remove entries for domains that no longer exist.
   4.122          for d in self.domain.values():
   4.123              dominfo = doms.get(d.id)
   4.124 @@ -217,13 +232,13 @@ class XendDomain:
   4.125          self.refresh()
   4.126          return val
   4.127      
   4.128 -    def domain_halt(self, id):
   4.129 +    def domain_destroy(self, id):
   4.130          """Terminate domain immediately.
   4.131          """
   4.132          dom = int(id)
   4.133          if dom <= 0:
   4.134              return 0
   4.135 -        eserver.inject('xend.domain.halt', id)
   4.136 +        eserver.inject('xend.domain.destroy', id)
   4.137          val = xc.domain_destroy(dom=dom)
   4.138          self.refresh()
   4.139          return val       
   4.140 @@ -235,14 +250,14 @@ class XendDomain:
   4.141          pass
   4.142      
   4.143      def domain_save(self, id, dst, progress=0):
   4.144 -        """Save domain state to file, halt domain.
   4.145 +        """Save domain state to file, destroy domain.
   4.146          """
   4.147          dom = int(id)
   4.148          self.domain_pause(id)
   4.149          eserver.inject('xend.domain.save', id)
   4.150          rc = xc.linux_save(dom=dom, state_file=dst, progress=progress)
   4.151          if rc == 0:
   4.152 -            self.domain_halt(id)
   4.153 +            self.domain_destroy(id)
   4.154          return rc
   4.155      
   4.156      def domain_restore(self, src, config, progress=0):
     5.1 --- a/tools/xenmgr/lib/XendDomainInfo.py	Thu Jun 24 10:28:58 2004 +0000
     5.2 +++ b/tools/xenmgr/lib/XendDomainInfo.py	Thu Jun 24 12:00:50 2004 +0000
     5.3 @@ -60,160 +60,6 @@ class VmError(ValueError):
     5.4          return self.value
     5.5  
     5.6  
     5.7 -class XendDomainInfo:
     5.8 -    """Virtual machine object."""
     5.9 -
    5.10 -    def __init__(self, config, dom, name, memory, image=None, console=None, info=None):
    5.11 -        """Construct a virtual machine object.
    5.12 -
    5.13 -        config   configuration
    5.14 -        dom      domain id
    5.15 -        name     name
    5.16 -        memory   memory size (in MB)
    5.17 -        image    image object
    5.18 -        """
    5.19 -        #todo: add info: runtime, state, ...
    5.20 -        self.config = config
    5.21 -        self.id = str(dom)
    5.22 -        self.dom = dom
    5.23 -        self.name = name
    5.24 -        self.memory = memory
    5.25 -        self.image = image
    5.26 -        self.console = console
    5.27 -        self.devices = {}
    5.28 -        self.configs = []
    5.29 -        self.info = info
    5.30 -        self.ipaddrs = []
    5.31 -        self.block_controller = 0
    5.32 -        self.net_controller = 0
    5.33 -
    5.34 -        #todo: state: running, suspended
    5.35 -        self.state = 'running'
    5.36 -        #todo: set to migrate info if migrating
    5.37 -        self.migrate = None
    5.38 -
    5.39 -    def update(self, info):
    5.40 -        """Update with  info from xc.domain_getinfo().
    5.41 -        """
    5.42 -        self.info = info
    5.43 -
    5.44 -    def __str__(self):
    5.45 -        s = "domain"
    5.46 -        s += " id=" + self.id
    5.47 -        s += " name=" + self.name
    5.48 -        s += " memory=" + str(self.memory)
    5.49 -        if self.console:
    5.50 -            s += " console=" + self.console.id
    5.51 -        if self.image:
    5.52 -            s += " image=" + self.image
    5.53 -        s += ""
    5.54 -        return s
    5.55 -
    5.56 -    __repr__ = __str__
    5.57 -
    5.58 -    def sxpr(self):
    5.59 -        sxpr = ['domain',
    5.60 -                ['id', self.id],
    5.61 -                ['name', self.name],
    5.62 -                ['memory', self.memory] ]
    5.63 -        if self.info:
    5.64 -            run   = (self.info['running'] and 'R') or 'r'
    5.65 -            block = (self.info['blocked'] and 'B') or 'b'
    5.66 -            stop  = (self.info['paused']  and 'P') or 'p'
    5.67 -            susp  = (self.info['shutdown'] and 'S') or 's'
    5.68 -            crash = (self.info['crashed'] and 'C') or 'c'
    5.69 -            state = run + block + stop + susp + crash
    5.70 -            sxpr.append(['state', state])
    5.71 -            if self.info['shutdown']:
    5.72 -                reasons = ["poweroff", "reboot", "suspend"]
    5.73 -                reason = reasons[self.info['shutdown_reason']]
    5.74 -                sxpr.append(['shutdown_reason', reason])
    5.75 -            sxpr.append(['cpu', self.info['cpu']])
    5.76 -            sxpr.append(['cpu_time', self.info['cpu_time']/1e9])
    5.77 -        if self.console:
    5.78 -            sxpr.append(self.console.sxpr())
    5.79 -        if self.config:
    5.80 -            sxpr.append(['config', self.config])
    5.81 -        return sxpr
    5.82 -
    5.83 -    def add_device(self, type, dev):
    5.84 -        """Add a device to a virtual machine.
    5.85 -
    5.86 -        dev      device to add
    5.87 -        """
    5.88 -        dl = self.devices.get(type, [])
    5.89 -        dl.append(dev)
    5.90 -        self.devices[type] = dl
    5.91 -
    5.92 -    def get_devices(self, type):
    5.93 -        val = self.devices.get(type, [])
    5.94 -        print 'get_devices', type; sxp.show(val); print
    5.95 -        return val
    5.96 -
    5.97 -    def get_device_by_id(self, type, id):
    5.98 -        """Get the device with the given id.
    5.99 -
   5.100 -        id       device id
   5.101 -
   5.102 -        returns  device or None
   5.103 -        """
   5.104 -        return sxp.child_with_id(self.get_devices(type), id)
   5.105 -
   5.106 -    def get_device_by_index(self, type, idx):
   5.107 -        """Get the device with the given index.
   5.108 -
   5.109 -        idx       device index
   5.110 -
   5.111 -        returns  device or None
   5.112 -        """
   5.113 -        dl = self.get_devices(type)
   5.114 -        if 0 <= idx < len(dl):
   5.115 -            return dl[idx]
   5.116 -        else:
   5.117 -            return None
   5.118 -
   5.119 -    def add_config(self, val):
   5.120 -        """Add configuration data to a virtual machine.
   5.121 -
   5.122 -        val      data to add
   5.123 -        """
   5.124 -        self.configs.append(val)
   5.125 -
   5.126 -    def destroy(self):
   5.127 -        if self.dom <= 0:
   5.128 -            return 0
   5.129 -        return xc.domain_destroy(dom=self.dom)
   5.130 -
   5.131 -    def died(self):
   5.132 -        print 'died>', self.dom
   5.133 -        self.release_vifs()
   5.134 -
   5.135 -    def release_vifs(self):
   5.136 -        print 'release_vifs>', self.dom
   5.137 -        vifs = self.get_devices('vif')
   5.138 -        for v in vifs:
   5.139 -            vif = sxp.child_value(v, 'vif')
   5.140 -            bridge = sxp.child_value(v, 'bridge')
   5.141 -            XendBridge.vif_bridge_rem(self.dom, vif, bridge)
   5.142 -
   5.143 -    def show(self):
   5.144 -        """Print virtual machine info.
   5.145 -        """
   5.146 -        print "[VM dom=%d name=%s memory=%d" % (self.dom, self.name, self.memory)
   5.147 -        print "image:"
   5.148 -        sxp.show(self.image)
   5.149 -        print
   5.150 -        for dl in self.devices:
   5.151 -            for dev in dl:
   5.152 -                print "device:"
   5.153 -                sxp.show(dev)
   5.154 -                print
   5.155 -        for val in self.configs:
   5.156 -            print "config:"
   5.157 -            sxp.show(val)
   5.158 -            print
   5.159 -        print "]"
   5.160 -
   5.161  def blkdev_name_to_number(name):
   5.162      """Take the given textual block-device name (e.g., '/dev/sda1',
   5.163      'hda') and return the device number used by the OS. """
   5.164 @@ -264,7 +110,7 @@ def lookup_raw_partn(partition):
   5.165      
   5.166      return None
   5.167  
   5.168 -def lookup_disk_uname( uname ):
   5.169 +def lookup_disk_uname(uname):
   5.170      """Lookup a list of segments for a physical device.
   5.171      uname [string]:  name of the device in the format \'phy:dev\' for a physical device
   5.172      returns [list of dicts]: list of extents that make up the named device
   5.173 @@ -277,7 +123,7 @@ def lookup_disk_uname( uname ):
   5.174          segments = None
   5.175      return segments
   5.176  
   5.177 -def make_disk(dom, uname, dev, mode):
   5.178 +def make_disk(dom, uname, dev, mode, recreate=0):
   5.179      """Create a virtual disk device for a domain.
   5.180  
   5.181      @returns Deferred
   5.182 @@ -289,21 +135,21 @@ def make_disk(dom, uname, dev, mode):
   5.183          raise VmError("vbd: Multi-segment vdisk: uname=%s" % uname)
   5.184      segment = segments[0]
   5.185      vdev = blkdev_name_to_number(dev)
   5.186 -    ctrl = xend.blkif_create(dom)
   5.187 +    ctrl = xend.blkif_create(dom, recreate=recreate)
   5.188      
   5.189      def fn(ctrl):
   5.190 -        return xend.blkif_dev_create(dom, vdev, mode, segment)
   5.191 +        return xend.blkif_dev_create(dom, vdev, mode, segment, recreate=recreate)
   5.192      ctrl.addCallback(fn)
   5.193      return ctrl
   5.194          
   5.195 -def make_vif(dom, vif, vmac):
   5.196 +def make_vif(dom, vif, vmac, recreate=0):
   5.197      """Create a virtual network device for a domain.
   5.198  
   5.199      
   5.200      @returns Deferred
   5.201      """
   5.202 -    xend.netif_create(dom)
   5.203 -    d = xend.netif_dev_create(dom, vif, vmac)
   5.204 +    xend.netif_create(dom, recreate=recreate)
   5.205 +    d = xend.netif_dev_create(dom, vif, vmac, recreate=recreate)
   5.206      return d
   5.207  
   5.208  def vif_up(iplist):
   5.209 @@ -338,49 +184,6 @@ def vif_up(iplist):
   5.210      finally:
   5.211          if not nlb: set_ip_nonlocal_bind(0)
   5.212  
   5.213 -def xen_domain_create(config, ostype, name, memory, kernel, ramdisk, cmdline, vifs_n):
   5.214 -    """Create a domain. Builds the image but does not configure it.
   5.215 -
   5.216 -    config  configuration
   5.217 -    ostype  OS type
   5.218 -    name    domain name
   5.219 -    memory  domain memory (MB)
   5.220 -    kernel  kernel image
   5.221 -    ramdisk kernel ramdisk
   5.222 -    cmdline kernel commandline
   5.223 -    vifs_n  number of network interfaces
   5.224 -    returns vm
   5.225 -    """
   5.226 -    flags = 0
   5.227 -    if not os.path.isfile(kernel):
   5.228 -        raise VmError('Kernel image does not exist: %s' % kernel)
   5.229 -    if ramdisk and not os.path.isfile(ramdisk):
   5.230 -        raise VMError('Kernel ramdisk does not exist: %s' % ramdisk)
   5.231 -
   5.232 -    cpu = int(sxp.child_value(config, 'cpu', '-1'))
   5.233 -    print 'xen_domain_create> create ', memory, name, cpu
   5.234 -    dom = xc.domain_create(mem_kb= memory * 1024, name= name, cpu= cpu)
   5.235 -    if dom <= 0:
   5.236 -        raise VmError('Creating domain failed: name=%s memory=%d kernel=%s'
   5.237 -                      % (name, memory, kernel))
   5.238 -    console = xendConsole.console_create(dom)
   5.239 -    buildfn = getattr(xc, '%s_build' % ostype)
   5.240 -    
   5.241 -    print 'xen_domain_create> build ', ostype, dom, kernel, cmdline, ramdisk
   5.242 -    if len(cmdline) >= 256:
   5.243 -        print 'Warning: kernel cmdline too long'
   5.244 -    err = buildfn(dom            = dom,
   5.245 -                  image          = kernel,
   5.246 -                  control_evtchn = console.port2,
   5.247 -                  cmdline        = cmdline,
   5.248 -                  ramdisk        = ramdisk,
   5.249 -                  flags          = flags)
   5.250 -    if err != 0:
   5.251 -        raise VmError('Building domain failed: type=%s dom=%d err=%d'
   5.252 -                      % (ostype, dom, err))
   5.253 -    vm = XendDomainInfo(config, dom, name, memory, kernel, console)
   5.254 -    return vm
   5.255 -
   5.256  config_handlers = {}
   5.257  
   5.258  def add_config_handler(name, h):
   5.259 @@ -450,34 +253,27 @@ def vm_create(config):
   5.260      returns Deferred
   5.261      raises VmError for invalid configuration
   5.262      """
   5.263 -    # todo - add support for scheduling params?
   5.264      print 'vm_create>'
   5.265 -    vm = None
   5.266 -    try:
   5.267 -        name = sxp.child_value(config, 'name')
   5.268 -        memory = int(sxp.child_value(config, 'memory', '128'))
   5.269 -        image = sxp.child_value(config, 'image')
   5.270 -        
   5.271 -        image_name = sxp.name(image)
   5.272 -        image_handler = get_image_handler(image_name)
   5.273 -        if image_handler is None:
   5.274 -            raise VmError('unknown image type: ' + image_name)
   5.275 -        vm = image_handler(config, name, memory, image)
   5.276 -        deferred = vm_configure(vm, config)
   5.277 -    except StandardError, ex:
   5.278 -        # Catch errors, cleanup and re-raise.
   5.279 -        if vm:
   5.280 -            vm.destroy()
   5.281 -        raise
   5.282 -    def cbok(x):
   5.283 -        print 'vm_create> cbok', x
   5.284 -        return x
   5.285 -    deferred.addCallback(cbok)
   5.286 -    print 'vm_create<'
   5.287 -    return deferred
   5.288 +    vm = XendDomainInfo()
   5.289 +    return vm.construct(config)
   5.290 +
   5.291 +def vm_recreate(config, info):
   5.292 +    """Create the VM object for an existing domain.
   5.293 +    """
   5.294 +    vm = XendDomainInfo()
   5.295 +    vm.recreate = 1
   5.296 +    vm.setdom(info['dom'])
   5.297 +    vm.name = info['name']
   5.298 +    vm.memory = info['mem_kb']/1024
   5.299 +    if config:
   5.300 +        d = vm.construct(config)
   5.301 +    else:
   5.302 +        d = defer.Deferred()
   5.303 +        d.callback(vm)
   5.304 +    return d
   5.305  
   5.306  def vm_restore(src, config, progress=0):
   5.307 -    """Restore a VM.
   5.308 +    """Restore a VM from a disk image.
   5.309  
   5.310      src      saved state to restore
   5.311      config   configuration
   5.312 @@ -485,11 +281,14 @@ def vm_restore(src, config, progress=0):
   5.313      returns  deferred
   5.314      raises   VmError for invalid configuration
   5.315      """
   5.316 +    vm = XendDomainInfo()
   5.317 +    vm.config = config
   5.318      ostype = "linux" #todo set from config
   5.319      restorefn = getattr(xc, "%s_restore" % ostype)
   5.320      dom = restorefn(state_file=src, progress=progress)
   5.321 -    if dom < 0: return dom
   5.322 -    deferred = dom_configure(dom, config)
   5.323 +    if dom < 0:
   5.324 +        raise VMError('restore failed')
   5.325 +    deferred = vm.dom_configure(dom)
   5.326      def vifs_cb(val, vm):
   5.327          vif_up(vm.ipaddrs)
   5.328      deferred.addCallback(vifs_cb, vm)
   5.329 @@ -501,115 +300,25 @@ def dom_get(dom):
   5.330          return domlist[0]
   5.331      return None
   5.332      
   5.333 -def dom_configure(dom, config):
   5.334 -    """Configure a domain.
   5.335 -
   5.336 -    dom    domain id
   5.337 -    config configuration
   5.338 -    returns deferred
   5.339 -    """
   5.340 -    d = dom_get(dom)
   5.341 -    if not d:
   5.342 -        raise VMError("Domain not found: %d" % dom)
   5.343 -    try:
   5.344 -        name = d['name']
   5.345 -        memory = d['memory']/1024
   5.346 -        image = None
   5.347 -        vm = VM(config, dom, name, memory, image)
   5.348 -        deferred = vm_configure(vm, config)
   5.349 -    except StandardError, ex:
   5.350 -        if vm:
   5.351 -            vm.destroy()
   5.352 -        raise
   5.353 -    return deferred
   5.354  
   5.355  def append_deferred(dlist, v):
   5.356      if isinstance(v, defer.Deferred):
   5.357          dlist.append(v)
   5.358  
   5.359 -def vm_create_devices(vm, config):
   5.360 -    """Create the devices for a vm.
   5.361 -
   5.362 -    vm         virtual machine
   5.363 -    config     configuration
   5.364 -
   5.365 -    returns Deferred
   5.366 -    raises VmError for invalid devices
   5.367 -    """
   5.368 -    print '>vm_create_devices'
   5.369 -    dlist = []
   5.370 -    devices = sxp.children(config, 'device')
   5.371 -    index = {}
   5.372 -    for d in devices:
   5.373 -        dev = sxp.child0(d)
   5.374 -        if dev is None:
   5.375 -            raise VmError('invalid device')
   5.376 -        dev_name = sxp.name(dev)
   5.377 -        dev_index = index.get(dev_name, 0)
   5.378 -        dev_handler = get_device_handler(dev_name)
   5.379 -        if dev_handler is None:
   5.380 -            raise VmError('unknown device type: ' + dev_name)
   5.381 -        v = dev_handler(vm, dev, dev_index)
   5.382 -        append_deferred(dlist, v)
   5.383 -        index[dev_name] = dev_index + 1
   5.384 -    deferred = defer.DeferredList(dlist, fireOnOneErrback=1)
   5.385 -    print '<vm_create_devices'
   5.386 -    return deferred
   5.387 -
   5.388 -def config_controllers(vm, config):
   5.389 -    for c in sxp.children(config, 'controller'):
   5.390 -        name = sxp.name(c)
   5.391 -        if name == 'block':
   5.392 -            vm.block_controller = 1
   5.393 -            xend.blkif_set_control_domain(vm.dom)
   5.394 -        elif name == 'net':
   5.395 -            vm.net_controller = 1
   5.396 -            xend.netif_set_control_domain(vm.dom)
   5.397 -        else:
   5.398 -            raise VmError('invalid controller type:' + str(name))
   5.399 -    
   5.400 -def vm_configure(vm, config):
   5.401 -    """Configure a vm.
   5.402 -
   5.403 -    vm         virtual machine
   5.404 -    config     configuration
   5.405 -
   5.406 -    returns Deferred - calls callback with vm
   5.407 -    """
   5.408 -    config_controllers(vm, config)
   5.409 -    if vm.block_controller:
   5.410 -        d = defer.Deferred()
   5.411 -        d.callback(1)
   5.412 -    else:
   5.413 -        d = xend.blkif_create(vm.dom)
   5.414 -    d.addCallback(_vm_configure1, vm, config)
   5.415 -    return d
   5.416 -
   5.417 -def _vm_configure1(val, vm, config):
   5.418 -    d = vm_create_devices(vm, config)
   5.419 +def _vm_configure1(val, vm):
   5.420 +    d = vm.create_devices()
   5.421      print '_vm_configure1> made devices...'
   5.422      def cbok(x):
   5.423          print '_vm_configure1> cbok', x
   5.424          return x
   5.425      d.addCallback(cbok)
   5.426 -    d.addCallback(_vm_configure2, vm, config)
   5.427 +    d.addCallback(_vm_configure2, vm)
   5.428      print '_vm_configure1<'
   5.429      return d
   5.430  
   5.431 -def _vm_configure2(val, vm, config):
   5.432 +def _vm_configure2(val, vm):
   5.433      print '>callback _vm_configure2...'
   5.434 -    dlist = []
   5.435 -    index = {}
   5.436 -    for field in sxp.children(config):
   5.437 -        field_name = sxp.name(field)
   5.438 -        field_index = index.get(field_name, 0)
   5.439 -        field_handler = get_config_handler(field_name)
   5.440 -        # Ignore unknown fields. Warn?
   5.441 -        if field_handler:
   5.442 -            v = field_handler(vm, config, field, field_index)
   5.443 -            append_deferred(dlist, v)
   5.444 -        index[field_name] = field_index + 1
   5.445 -    d = defer.DeferredList(dlist, fireOnOneErrback=1)
   5.446 +    d = vm.configure_fields()
   5.447      def cbok(results):
   5.448          print '_vm_configure2> cbok', results
   5.449          return vm
   5.450 @@ -622,22 +331,369 @@ def _vm_configure2(val, vm, config):
   5.451      print '<_vm_configure2'
   5.452      return d
   5.453  
   5.454 -def config_devices(config, name):
   5.455 -    """Get a list of the 'device' nodes of a given type from a config.
   5.456 +class XendDomainInfo:
   5.457 +    """Virtual machine object."""
   5.458 +
   5.459 +    def __init__(self):
   5.460 +        self.recreate = 0
   5.461 +        self.config = None
   5.462 +        self.id = None
   5.463 +        self.dom = None
   5.464 +        self.name = None
   5.465 +        self.memory = None
   5.466 +        self.image = None
   5.467 +        self.ramdisk = None
   5.468 +        self.cmdline = None
   5.469 +        self.console = None
   5.470 +        self.devices = {}
   5.471 +        self.configs = []
   5.472 +        self.info = None
   5.473 +        self.ipaddrs = []
   5.474 +        self.blkif_backend = 0
   5.475 +        self.netif_backend = 0
   5.476 +        #todo: state: running, suspended
   5.477 +        self.state = 'running'
   5.478 +        #todo: set to migrate info if migrating
   5.479 +        self.migrate = None
   5.480 +
   5.481 +    def setdom(self, dom):
   5.482 +        self.dom = int(dom)
   5.483 +        self.id = str(dom)
   5.484 +        
   5.485 +    def update(self, info):
   5.486 +        """Update with  info from xc.domain_getinfo().
   5.487 +        """
   5.488 +        self.info = info
   5.489 +
   5.490 +    def __str__(self):
   5.491 +        s = "domain"
   5.492 +        s += " id=" + self.id
   5.493 +        s += " name=" + self.name
   5.494 +        s += " memory=" + str(self.memory)
   5.495 +        if self.console:
   5.496 +            s += " console=" + self.console.id
   5.497 +        if self.image:
   5.498 +            s += " image=" + self.image
   5.499 +        s += ""
   5.500 +        return s
   5.501 +
   5.502 +    __repr__ = __str__
   5.503 +
   5.504 +    def sxpr(self):
   5.505 +        sxpr = ['domain',
   5.506 +                ['id', self.id],
   5.507 +                ['name', self.name],
   5.508 +                ['memory', self.memory] ]
   5.509 +        if self.info:
   5.510 +            run   = (self.info['running'] and 'r') or '-'
   5.511 +            block = (self.info['blocked'] and 'b') or '-'
   5.512 +            stop  = (self.info['paused']  and 'p') or '-'
   5.513 +            susp  = (self.info['shutdown'] and 's') or '-'
   5.514 +            crash = (self.info['crashed'] and 'c') or '-'
   5.515 +            state = run + block + stop + susp + crash
   5.516 +            sxpr.append(['state', state])
   5.517 +            if self.info['shutdown']:
   5.518 +                reasons = ["poweroff", "reboot", "suspend"]
   5.519 +                reason = reasons[self.info['shutdown_reason']]
   5.520 +                sxpr.append(['shutdown_reason', reason])
   5.521 +            sxpr.append(['cpu', self.info['cpu']])
   5.522 +            sxpr.append(['cpu_time', self.info['cpu_time']/1e9])
   5.523 +        if self.console:
   5.524 +            sxpr.append(self.console.sxpr())
   5.525 +        if self.config:
   5.526 +            sxpr.append(['config', self.config])
   5.527 +        return sxpr
   5.528 +
   5.529 +    def construct(self, config):
   5.530 +        # todo - add support for scheduling params?
   5.531 +        self.config = config
   5.532 +        try:
   5.533 +            self.name = sxp.child_value(config, 'name')
   5.534 +            self.memory = int(sxp.child_value(config, 'memory', '128'))
   5.535 +            self.configure_backends()
   5.536 +            image = sxp.child_value(config, 'image')
   5.537 +            image_name = sxp.name(image)
   5.538 +            image_handler = get_image_handler(image_name)
   5.539 +            if image_handler is None:
   5.540 +                raise VmError('unknown image type: ' + image_name)
   5.541 +            image_handler(self, image)
   5.542 +            deferred = self.configure()
   5.543 +        except StandardError, ex:
   5.544 +            # Catch errors, cleanup and re-raise.
   5.545 +            self.destroy()
   5.546 +            raise
   5.547 +        def cbok(x):
   5.548 +            print 'vm_create> cbok', x
   5.549 +            return x
   5.550 +        deferred.addCallback(cbok)
   5.551 +        print 'vm_create<'
   5.552 +        return deferred
   5.553 +
   5.554 +    def config_devices(self, name):
   5.555 +        """Get a list of the 'device' nodes of a given type from the config.
   5.556 +
   5.557 +        name	device type
   5.558 +        return list of device configs
   5.559 +        """
   5.560 +        devices = []
   5.561 +        for d in sxp.children(self.config, 'device'):
   5.562 +            dev = sxp.child0(d)
   5.563 +            if dev is None: continue
   5.564 +            if name == sxp.name(dev):
   5.565 +                devices.append(dev)
   5.566 +        return devices
   5.567 +
   5.568 +    def add_device(self, type, dev):
   5.569 +        """Add a device to a virtual machine.
   5.570 +
   5.571 +        dev      device to add
   5.572 +        """
   5.573 +        dl = self.devices.get(type, [])
   5.574 +        dl.append(dev)
   5.575 +        self.devices[type] = dl
   5.576 +
   5.577 +    def get_devices(self, type):
   5.578 +        val = self.devices.get(type, [])
   5.579 +        return val
   5.580 +
   5.581 +    def get_device_by_id(self, type, id):
   5.582 +        """Get the device with the given id.
   5.583 +
   5.584 +        id       device id
   5.585 +
   5.586 +        returns  device or None
   5.587 +        """
   5.588 +        dl = self.get_devices(type)
   5.589 +        for d in dl:
   5.590 +            if d.getprop('id') == id:
   5.591 +                return d
   5.592 +        return None
   5.593 +
   5.594 +    def get_device_by_index(self, type, idx):
   5.595 +        """Get the device with the given index.
   5.596 +
   5.597 +        idx       device index
   5.598 +
   5.599 +        returns  device or None
   5.600 +        """
   5.601 +        dl = self.get_devices(type)
   5.602 +        if 0 <= idx < len(dl):
   5.603 +            return dl[idx]
   5.604 +        else:
   5.605 +            return None
   5.606 +
   5.607 +    def add_config(self, val):
   5.608 +        """Add configuration data to a virtual machine.
   5.609 +
   5.610 +        val      data to add
   5.611 +        """
   5.612 +        self.configs.append(val)
   5.613 +
   5.614 +    def destroy(self):
   5.615 +        if self.dom <= 0:
   5.616 +            return 0
   5.617 +        return xc.domain_destroy(dom=self.dom)
   5.618 +
   5.619 +    def died(self):
   5.620 +        print 'died>', self.dom
   5.621 +        self.release_devices()
   5.622 +
   5.623 +    def release_devices(self):
   5.624 +        print 'release_devices>', self.dom
   5.625 +        self.release_vifs()
   5.626 +        self.release_vbds()
   5.627 +        self.devices = {}
   5.628 +
   5.629 +    def release_vifs(self):
   5.630 +        print 'release_vifs>', self.dom
   5.631 +        if self.dom is None: return
   5.632 +        ctrl = xend.netif_get(self.dom)
   5.633 +        if ctrl:
   5.634 +            ctrl.destroy()
   5.635  
   5.636 -    config	configuration
   5.637 -    name	device type
   5.638 -    return list of device configs
   5.639 -    """
   5.640 -    devices = []
   5.641 -    for d in sxp.children(config, 'device'):
   5.642 -        dev = sxp.child0(d)
   5.643 -        if dev is None: continue
   5.644 -        if name == sxp.name(dev):
   5.645 -            devices.append(dev)
   5.646 -    return devices
   5.647 -        
   5.648 -def vm_image_linux(config, name, memory, image):
   5.649 +    def release_vbds(self):
   5.650 +        print 'release_vbds>', self.dom
   5.651 +        if self.dom is None: return
   5.652 +        ctrl = xend.blkif_get(self.dom)
   5.653 +        if ctrl:
   5.654 +            ctrl.destroy()
   5.655 +
   5.656 +    def show(self):
   5.657 +        """Print virtual machine info.
   5.658 +        """
   5.659 +        print "[VM dom=%d name=%s memory=%d" % (self.dom, self.name, self.memory)
   5.660 +        print "image:"
   5.661 +        sxp.show(self.image)
   5.662 +        print
   5.663 +        for dl in self.devices:
   5.664 +            for dev in dl:
   5.665 +                print "device:"
   5.666 +                sxp.show(dev)
   5.667 +                print
   5.668 +        for val in self.configs:
   5.669 +            print "config:"
   5.670 +            sxp.show(val)
   5.671 +            print
   5.672 +        print "]"
   5.673 +
   5.674 +    def init_domain(self):
   5.675 +        """Initialize the domain memory.
   5.676 +        """
   5.677 +        if self.recreate: return
   5.678 +        memory = self.memory
   5.679 +        name = self.name
   5.680 +        cpu = int(sxp.child_value(self.config, 'cpu', '-1'))
   5.681 +        print 'init_domain>', memory, name, cpu
   5.682 +        dom = xc.domain_create(mem_kb= memory * 1024, name= name, cpu= cpu)
   5.683 +        if dom <= 0:
   5.684 +            raise VmError('Creating domain failed: name=%s memory=%d'
   5.685 +                          % (name, memory))
   5.686 +        self.setdom(dom)
   5.687 +
   5.688 +    def build_domain(self, ostype, kernel, ramdisk, cmdline, vifs_n):
   5.689 +        """Build the domain boot image.
   5.690 +        """
   5.691 +        if self.recreate: return
   5.692 +        if len(cmdline) >= 256:
   5.693 +            print 'Warning: kernel cmdline too long'
   5.694 +        dom = self.dom
   5.695 +        buildfn = getattr(xc, '%s_build' % ostype)
   5.696 +        print 'build_domain>', ostype, dom, kernel, cmdline, ramdisk
   5.697 +        flags = 0
   5.698 +        if self.netif_backend: flags |= SIF_NET_BE_DOMAIN
   5.699 +        if self.blkif_backend: flags |= SIF_BLK_BE_DOMAIN
   5.700 +        err = buildfn(dom            = dom,
   5.701 +                      image          = kernel,
   5.702 +                      control_evtchn = self.console.port2,
   5.703 +                      cmdline        = cmdline,
   5.704 +                      ramdisk        = ramdisk,
   5.705 +                      flags          = flags)
   5.706 +        if err != 0:
   5.707 +            raise VmError('Building domain failed: type=%s dom=%d err=%d'
   5.708 +                          % (ostype, dom, err))
   5.709 +
   5.710 +    def create_domain(self, ostype, kernel, ramdisk, cmdline, vifs_n):
   5.711 +        """Create a domain. Builds the image but does not configure it.
   5.712 +
   5.713 +        ostype  OS type
   5.714 +        kernel  kernel image
   5.715 +        ramdisk kernel ramdisk
   5.716 +        cmdline kernel commandline
   5.717 +        vifs_n  number of network interfaces
   5.718 +        """
   5.719 +        print 'create_domain>', ostype, kernel
   5.720 +        if not self.recreate:
   5.721 +            if not os.path.isfile(kernel):
   5.722 +                raise VmError('Kernel image does not exist: %s' % kernel)
   5.723 +            if ramdisk and not os.path.isfile(ramdisk):
   5.724 +                raise VMError('Kernel ramdisk does not exist: %s' % ramdisk)
   5.725 +        print 'create-domain> init_domain...'
   5.726 +        self.init_domain()
   5.727 +        print 'create_domain>', 'dom=', self.dom
   5.728 +        self.console = xendConsole.console_create(self.dom)
   5.729 +        self.build_domain(ostype, kernel, ramdisk, cmdline, vifs_n)
   5.730 +        self.image = kernel
   5.731 +        self.ramdisk = ramdisk
   5.732 +        self.cmdline = cmdline
   5.733 +
   5.734 +    def create_devices(self):
   5.735 +        """Create the devices for a vm.
   5.736 +
   5.737 +        returns Deferred
   5.738 +        raises VmError for invalid devices
   5.739 +        """
   5.740 +        print '>create_devices'
   5.741 +        dlist = []
   5.742 +        devices = sxp.children(self.config, 'device')
   5.743 +        index = {}
   5.744 +        for d in devices:
   5.745 +            dev = sxp.child0(d)
   5.746 +            if dev is None:
   5.747 +                raise VmError('invalid device')
   5.748 +            dev_name = sxp.name(dev)
   5.749 +            dev_index = index.get(dev_name, 0)
   5.750 +            dev_handler = get_device_handler(dev_name)
   5.751 +            if dev_handler is None:
   5.752 +                raise VmError('unknown device type: ' + dev_name)
   5.753 +            v = dev_handler(self, dev, dev_index)
   5.754 +            append_deferred(dlist, v)
   5.755 +            index[dev_name] = dev_index + 1
   5.756 +        deferred = defer.DeferredList(dlist, fireOnOneErrback=1)
   5.757 +        print '<create_devices'
   5.758 +        return deferred
   5.759 +
   5.760 +    def configure_backends(self):
   5.761 +        """Set configuration flags if the vm is a backend for netif of blkif.
   5.762 +        """
   5.763 +        for c in sxp.children(self.config, 'backend'):
   5.764 +            name = sxp.name(c)
   5.765 +            if name == 'blkif':
   5.766 +                self.blkif_backend = 1
   5.767 +            elif name == 'netif':
   5.768 +                self.netif_backend = 1
   5.769 +            else:
   5.770 +                raise VmError('invalid backend type:' + str(name))
   5.771 +
   5.772 +    def create_backends(self):
   5.773 +        """Setup the netif and blkif backends.
   5.774 +        """
   5.775 +        if self.blkif_backend:
   5.776 +            xend.blkif_set_control_domain(self.dom, recreate=self.recreate)
   5.777 +        if self.netif_backend:
   5.778 +            xend.netif_set_control_domain(self.dom, recreate=self.recreate)
   5.779 +            
   5.780 +    def configure(self):
   5.781 +        """Configure a vm.
   5.782 +
   5.783 +        vm         virtual machine
   5.784 +        config     configuration
   5.785 +
   5.786 +        returns Deferred - calls callback with vm
   5.787 +        """
   5.788 +        if self.blkif_backend:
   5.789 +            d = defer.Deferred()
   5.790 +            d.callback(1)
   5.791 +        else:
   5.792 +            d = xend.blkif_create(self.dom, recreate=self.recreate)
   5.793 +        d.addCallback(_vm_configure1, self)
   5.794 +        return d
   5.795 +
   5.796 +    def dom_configure(self, dom):
   5.797 +        """Configure a domain.
   5.798 +
   5.799 +        dom    domain id
   5.800 +        returns deferred
   5.801 +        """
   5.802 +        d = dom_get(dom)
   5.803 +        if not d:
   5.804 +            raise VMError("Domain not found: %d" % dom)
   5.805 +        try:
   5.806 +            self.setdom(dom)
   5.807 +            self.name = d['name']
   5.808 +            self.memory = d['memory']/1024
   5.809 +            deferred = self.configure()
   5.810 +        except StandardError, ex:
   5.811 +            self.destroy()
   5.812 +            raise
   5.813 +        return deferred
   5.814 +
   5.815 +    def configure_fields(self):
   5.816 +        dlist = []
   5.817 +        index = {}
   5.818 +        for field in sxp.children(self.config):
   5.819 +            field_name = sxp.name(field)
   5.820 +            field_index = index.get(field_name, 0)
   5.821 +            field_handler = get_config_handler(field_name)
   5.822 +            # Ignore unknown fields. Warn?
   5.823 +            if field_handler:
   5.824 +                v = field_handler(self, self.config, field, field_index)
   5.825 +                append_deferred(dlist, v)
   5.826 +            index[field_name] = field_index + 1
   5.827 +        d = defer.DeferredList(dlist, fireOnOneErrback=1)
   5.828 +        return d
   5.829 +
   5.830 +
   5.831 +def vm_image_linux(vm, image):
   5.832      """Create a VM for a linux image.
   5.833  
   5.834      name      vm name
   5.835 @@ -658,12 +714,11 @@ def vm_image_linux(config, name, memory,
   5.836      if args:
   5.837          cmdline += " " + args
   5.838      ramdisk = sxp.child_value(image, "ramdisk", '')
   5.839 -    vifs = config_devices(config, "vif")
   5.840 -    vm = xen_domain_create(config, "linux", name, memory, kernel,
   5.841 -                           ramdisk, cmdline, len(vifs))
   5.842 +    vifs = vm.config_devices("vif")
   5.843 +    vm.create_domain("linux", kernel, ramdisk, cmdline, len(vifs))
   5.844      return vm
   5.845  
   5.846 -def vm_image_netbsd(config, name, memory, image):
   5.847 +def vm_image_netbsd(vm, image):
   5.848      """Create a VM for a bsd image.
   5.849  
   5.850      name      vm name
   5.851 @@ -685,9 +740,8 @@ def vm_image_netbsd(config, name, memory
   5.852      if args:
   5.853          cmdline += " " + args
   5.854      ramdisk = sxp.child_value(image, "ramdisk")
   5.855 -    vifs = config_devices(config, "vif")
   5.856 -    vm = xen_domain_create(config, "netbsd", name, memory, kernel,
   5.857 -                           ramdisk, cmdline, len(vifs))
   5.858 +    vifs = vm.config_devices("vif")
   5.859 +    vm.create_domain("netbsd", kernel, ramdisk, cmdline, len(vifs))
   5.860      return vm
   5.861  
   5.862  
   5.863 @@ -698,18 +752,18 @@ def vm_dev_vif(vm, val, index):
   5.864      val       vif config
   5.865      index     vif index
   5.866      """
   5.867 -    if vm.net_controller:
   5.868 -        raise VmError('vif: vif in control domain')
   5.869 +    if vm.netif_backend:
   5.870 +        raise VmError('vif: vif in netif backend domain')
   5.871      vif = index #todo
   5.872      vmac = sxp.child_value(val, "mac")
   5.873 -    defer = make_vif(vm.dom, vif, vmac)
   5.874 +    defer = make_vif(vm.dom, vif, vmac, vm.recreate)
   5.875      def fn(id):
   5.876 +        dev = xend.netif_dev(vm.dom, vif)
   5.877 +        devid = sxp.attribute(val, 'id')
   5.878 +        if devid:
   5.879 +            dev.setprop('id', devid)
   5.880          bridge = sxp.child_value(val, "bridge")
   5.881 -        bridge = XendBridge.vif_bridge_add(vm.dom, vif, bridge)
   5.882 -        dev = ['vif', ['vif', vif], ['bridge', bridge] ]
   5.883 -        netdev = xend.netif_dev(vm.dom, vif)
   5.884 -        if netdev and netdev.mac:
   5.885 -            dev += [ 'mac', netdev.mac ]
   5.886 +        dev.bridge_add(bridge)
   5.887          vm.add_device('vif', dev)
   5.888          print 'vm_dev_vif> created', dev
   5.889          return id
   5.890 @@ -723,8 +777,9 @@ def vm_dev_vbd(vm, val, index):
   5.891      val       vbd config
   5.892      index     vbd index
   5.893      """
   5.894 -    if vm.block_controller:
   5.895 -        raise VmError('vbd: vbd in control domain')
   5.896 +    if vm.blkif_backend:
   5.897 +        raise VmError('vbd: vbd in blkif backend domain')
   5.898 +    vdev = index
   5.899      uname = sxp.child_value(val, 'uname')
   5.900      if not uname:
   5.901          raise VMError('vbd: Missing uname')
   5.902 @@ -732,9 +787,10 @@ def vm_dev_vbd(vm, val, index):
   5.903      if not dev:
   5.904          raise VMError('vbd: Missing dev')
   5.905      mode = sxp.child_value(val, 'mode', 'r')
   5.906 -    defer = make_disk(vm.dom, uname, dev, mode)
   5.907 +    defer = make_disk(vm.dom, uname, dev, mode, vm.recreate)
   5.908      def fn(vbd):
   5.909 -        vm.add_device('vbd', val)
   5.910 +        dev = xend.blkif_dev(vm.dom, vdev)
   5.911 +        vm.add_device('vbd', dev)
   5.912          return vbd
   5.913      defer.addCallback(fn)
   5.914      return defer
   5.915 @@ -765,7 +821,8 @@ def vm_dev_pci(vm, val, index):
   5.916          func = parse_pci(func)
   5.917      except:
   5.918          raise VMError('pci: invalid parameter')
   5.919 -    rc = xc.physdev_pci_access_modify(dom=vm.dom, bus=bus, dev=dev, func=func, enable=1)
   5.920 +    rc = xc.physdev_pci_access_modify(dom=vm.dom, bus=bus, dev=dev,
   5.921 +                                      func=func, enable=1)
   5.922      if rc < 0:
   5.923          #todo non-fatal
   5.924          raise VMError('pci: Failed to configure device: bus=%s dev=%s func=%s' %
   5.925 @@ -833,13 +890,11 @@ def vm_field_vnet(vm, config, val, index
   5.926          if id is None:
   5.927              raise VmError('vnet: missing vif id')
   5.928          dev = vm.get_device_by_id('vif', id)
   5.929 -        if not sxp.elementp(dev, 'vif'):
   5.930 -            raise VmError('vnet: invalid vif id %s' % id)
   5.931 -        vnet = sxp.child_value(v, 'vnet', 1)
   5.932 -        mac = sxp.child_value(dev, 'mac')
   5.933 -        vif = sxp.child_value(dev, 'vif')
   5.934 -        vnet_bridge(vnet, mac, vm.dom, 0)
   5.935 -        vm.add_config([ 'vif.vnet', ['id', id], ['vnet', vnet], ['mac', mac]])
   5.936 +        #vnet = sxp.child_value(v, 'vnet', 1)
   5.937 +        #mac = sxp.child_value(dev, 'mac')
   5.938 +        #vif = sxp.child_value(dev, 'vif')
   5.939 +        #vnet_bridge(vnet, mac, vm.dom, 0)
   5.940 +        #vm.add_config([ 'vif.vnet', ['id', id], ['vnet', vnet], ['mac', mac]])
   5.941  
   5.942  # Register image handlers for linux and bsd.
   5.943  add_image_handler('linux',  vm_image_linux)
     6.1 --- a/tools/xenmgr/lib/server/SrvConsoleServer.py	Thu Jun 24 10:28:58 2004 +0000
     6.2 +++ b/tools/xenmgr/lib/server/SrvConsoleServer.py	Thu Jun 24 12:00:50 2004 +0000
     6.3 @@ -584,28 +584,31 @@ class Daemon:
     6.4          reactor.diconnectAll()
     6.5          sys.exit(0)
     6.6  
     6.7 -    def blkif_set_control_domain(self, dom):
     6.8 +    def blkif_set_control_domain(self, dom, recreate=0):
     6.9          """Set the block device backend control domain.
    6.10          """
    6.11 -        return self.blkifCF.setControlDomain(dom)
    6.12 +        return self.blkifCF.setControlDomain(dom, recreate=recreate)
    6.13      
    6.14      def blkif_get_control_domain(self, dom):
    6.15          """Get the block device backend control domain.
    6.16          """
    6.17          return self.blkifCF.getControlDomain()
    6.18      
    6.19 -    def blkif_create(self, dom):
    6.20 +    def blkif_create(self, dom, recreate=0):
    6.21          """Create a block device interface controller.
    6.22          
    6.23          Returns Deferred
    6.24          """
    6.25 -        d = self.blkifCF.createInstance(dom)
    6.26 +        d = self.blkifCF.createInstance(dom, recreate=recreate)
    6.27          return d
    6.28  
    6.29 +    def blkif_get(self, dom):
    6.30 +        return self.blkifCF.getInstanceByDom(dom)
    6.31 +
    6.32      def blkif_dev(self, dom, vdev):
    6.33          return self.blkifCF.getDomainDevice(dom, vdev)
    6.34  
    6.35 -    def blkif_dev_create(self, dom, vdev, mode, segment):
    6.36 +    def blkif_dev_create(self, dom, vdev, mode, segment, recreate=0):
    6.37          """Create a block device.
    6.38          
    6.39          Returns Deferred
    6.40 @@ -614,26 +617,29 @@ class Daemon:
    6.41          if not ctrl:
    6.42              raise ValueError('No blkif controller: %d' % dom)
    6.43          print 'blkif_dev_create>', dom, vdev, mode, segment
    6.44 -        d = ctrl.attach_device(vdev, mode, segment)
    6.45 +        d = ctrl.attachDevice(vdev, mode, segment, recreate=recreate)
    6.46          return d
    6.47  
    6.48 -    def netif_set_control_domain(self, dom):
    6.49 +    def netif_set_control_domain(self, dom, recreate=0):
    6.50          """Set the network interface backend control domain.
    6.51          """
    6.52 -        return self.netifCF.setControlDomain(dom)
    6.53 +        return self.netifCF.setControlDomain(dom, recreate=recreate)
    6.54  
    6.55      def netif_get_control_domain(self, dom):
    6.56          """Get the network interface backend control domain.
    6.57          """
    6.58          return self.netifCF.getControlDomain()
    6.59      
    6.60 -    def netif_create(self, dom):
    6.61 +    def netif_create(self, dom, recreate=0):
    6.62          """Create a network interface controller.
    6.63          
    6.64          """
    6.65 -        return self.netifCF.createInstance(dom)
    6.66 +        return self.netifCF.createInstance(dom, recreate=recreate)
    6.67  
    6.68 -    def netif_dev_create(self, dom, vif, vmac):
    6.69 +    def netif_get(self, dom):
    6.70 +        return self.netifCF.getInstanceByDom(dom)
    6.71 +
    6.72 +    def netif_dev_create(self, dom, vif, vmac, recreate=0):
    6.73          """Create a network device.
    6.74  
    6.75          todo
    6.76 @@ -641,7 +647,7 @@ class Daemon:
    6.77          ctrl = self.netifCF.getInstanceByDom(dom)
    6.78          if not ctrl:
    6.79              raise ValueError('No netif controller: %d' % dom)
    6.80 -        d = ctrl.attach_device(vif, vmac)
    6.81 +        d = ctrl.attachDevice(vif, vmac, recreate=recreate)
    6.82          return d
    6.83  
    6.84      def netif_dev(self, dom, vif):
     7.1 --- a/tools/xenmgr/lib/server/SrvDomain.py	Thu Jun 24 10:28:58 2004 +0000
     7.2 +++ b/tools/xenmgr/lib/server/SrvDomain.py	Thu Jun 24 12:00:50 2004 +0000
     7.3 @@ -32,8 +32,8 @@ class SrvDomain(SrvDir):
     7.4          req.setHeader("Location", "%s/.." % req.prePathURL())
     7.5          return val
     7.6  
     7.7 -    def op_halt(self, op, req):
     7.8 -        val = self.xd.domain_halt(self.dom.id)
     7.9 +    def op_destroy(self, op, req):
    7.10 +        val = self.xd.domain_destroy(self.dom.id)
    7.11          req.setHeader("Location", "%s/.." % req.prePathURL())
    7.12          return val
    7.13  
    7.14 @@ -196,7 +196,7 @@ class SrvDomain(SrvDir):
    7.15          req.write('<input type="submit" name="op" value="unpause">')
    7.16          req.write('<input type="submit" name="op" value="pause">')
    7.17          req.write('<input type="submit" name="op" value="shutdown">')
    7.18 -        req.write('<input type="submit" name="op" value="halt">')
    7.19 +        req.write('<input type="submit" name="op" value="destroy">')
    7.20          req.write('<br><input type="submit" name="op" value="migrate">')
    7.21          req.write('To: <input type="text" name="destination">')
    7.22          req.write('</form>')
     8.1 --- a/tools/xenmgr/lib/server/blkif.py	Thu Jun 24 10:28:58 2004 +0000
     8.2 +++ b/tools/xenmgr/lib/server/blkif.py	Thu Jun 24 12:00:50 2004 +0000
     8.3 @@ -1,3 +1,5 @@
     8.4 +from twisted.internet import defer
     8.5 +
     8.6  import channel
     8.7  import controller
     8.8  from messages import *
     8.9 @@ -22,7 +24,7 @@ class BlkifControllerFactory(controller.
    8.10          self.attached = 1
    8.11          self.registerChannel()
    8.12  
    8.13 -    def createInstance(self, dom):
    8.14 +    def createInstance(self, dom, recreate=0):
    8.15          d = self.addDeferred()
    8.16          blkif = self.getInstanceByDom(dom)
    8.17          if blkif:
    8.18 @@ -30,7 +32,10 @@ class BlkifControllerFactory(controller.
    8.19          else:
    8.20              blkif = BlkifController(self, dom)
    8.21              self.addInstance(blkif)
    8.22 -            blkif.send_be_create()
    8.23 +            if recreate:
    8.24 +                self.callDeferred(blkif)
    8.25 +            else:
    8.26 +                blkif.send_be_create()
    8.27          return d
    8.28  
    8.29      def getDomainDevices(self, dom):
    8.30 @@ -41,10 +46,11 @@ class BlkifControllerFactory(controller.
    8.31          blkif = self.getInstanceByDom(dom)
    8.32          return (blkif and blkif.getDevice(vdev)) or None
    8.33  
    8.34 -    def setControlDomain(self, dom):
    8.35 +    def setControlDomain(self, dom, recreate=0):
    8.36          if self.dom == dom: return
    8.37          self.deregisterChannel()
    8.38 -        self.attached = 0
    8.39 +        if not recreate:
    8.40 +            self.attached = 0
    8.41          self.dom = dom
    8.42          self.registerChannel()
    8.43          #
    8.44 @@ -55,6 +61,28 @@ class BlkifControllerFactory(controller.
    8.45      def getControlDomain(self):
    8.46          return self.dom
    8.47  
    8.48 +    def reattachDevice(self, dom, vdev):
    8.49 +        blkif = self.getInstanceByDom(dom)
    8.50 +        if blkif:
    8.51 +            blkif.reattachDevice(vdev)
    8.52 +        self.attached = self.devicesAttached()
    8.53 +        if self.attached:
    8.54 +            self.reattached()
    8.55 +
    8.56 +    def devicesAttached(self):
    8.57 +        """Check if all devices are attached.
    8.58 +        """
    8.59 +        attached = 1
    8.60 +        for blkif in self.getInstances():
    8.61 +            if not blkif.attached:
    8.62 +                attached = 0
    8.63 +                break
    8.64 +        return attached
    8.65 +                         
    8.66 +    def reattached(self):
    8.67 +        for blkif in self.getInstances():
    8.68 +            blkif.reattached()
    8.69 +
    8.70      def recv_be_create(self, msg, req):
    8.71          #print 'recv_be_create>'
    8.72          val = unpackMsg('blkif_be_create_t', msg)
    8.73 @@ -86,29 +114,7 @@ class BlkifControllerFactory(controller.
    8.74          if self.attached:
    8.75              self.callDeferred(0)
    8.76          else:
    8.77 -            self.reattach_device(val['domid'], val['vdevice'])
    8.78 -
    8.79 -    def reattach_device(self, dom, vdev):
    8.80 -        blkif = self.getInstanceByDom(dom)
    8.81 -        if blkif:
    8.82 -            blkif.reattach_device(vdev)
    8.83 -        self.attached = self.devices_attached()
    8.84 -        if self.attached:
    8.85 -            self.reattached()
    8.86 -
    8.87 -    def devices_attached(self):
    8.88 -        """Check if all devices are attached.
    8.89 -        """
    8.90 -        attached = 1
    8.91 -        for blkif in self.getInstances():
    8.92 -            if not blkif.attached:
    8.93 -                attached = 0
    8.94 -                break
    8.95 -        return attached
    8.96 -                         
    8.97 -    def reattached(self):
    8.98 -        for blkif in self.getInstances():
    8.99 -            blkif.reattached()
   8.100 +            self.reattachDevice(val['domid'], val['vdevice'])
   8.101  
   8.102      def recv_be_driver_status_changed(self, msg, req):
   8.103          val = unpackMsg('blkif_be_driver_status_changed_t', msg)
   8.104 @@ -117,11 +123,12 @@ class BlkifControllerFactory(controller.
   8.105              for blkif in self.getInstances():
   8.106                  blkif.detach()
   8.107  
   8.108 -class BlkDev:
   8.109 +class BlkDev(controller.Dev):
   8.110      """Info record for a block device.
   8.111      """
   8.112  
   8.113 -    def __init__(self, vdev, mode, segment):
   8.114 +    def __init__(self, ctrl, vdev, mode, segment):
   8.115 +        controller.Dev.__init__(self, ctrl)
   8.116          self.vdev = vdev
   8.117          self.mode = mode
   8.118          self.device = segment['device']
   8.119 @@ -131,6 +138,14 @@ class BlkDev:
   8.120  
   8.121      def readonly(self):
   8.122          return 'w' not in self.mode
   8.123 +
   8.124 +    def sxpr(self):
   8.125 +        print 'BlkDev>sxpr>', vars(self)
   8.126 +        val = ['blkif', ['vdev', self.vdev], ['mode', self.mode] ]
   8.127 +        return val
   8.128 +
   8.129 +    def destroy(self):
   8.130 +        self.controller.send_be_vbd_destroy(self.vdev)
   8.131          
   8.132  class BlkifController(controller.Controller):
   8.133      """Block device interface controller. Handles all block devices
   8.134 @@ -154,21 +169,43 @@ class BlkifController(controller.Control
   8.135          self.registerChannel()
   8.136          #print 'BlkifController<', 'dom=', self.dom, 'idx=', self.idx
   8.137  
   8.138 +    def lostChannel(self):
   8.139 +        print 'BlkifController>lostChannel>', 'dom=', self.dom
   8.140 +        #self.destroyDevices()
   8.141 +        controller.Controller.lostChannel(self)
   8.142 +
   8.143      def getDevices(self):
   8.144          return self.devices.values()
   8.145  
   8.146      def getDevice(self, vdev):
   8.147          return self.devices.get(vdev)
   8.148  
   8.149 -    def attach_device(self, vdev, mode, segment):
   8.150 +    def addDevice(self, vdev, mode, segment):
   8.151 +        if vdev in self.devices: return None
   8.152 +        dev = BlkDev(self, vdev, mode, segment)
   8.153 +        self.devices[vdev] = dev
   8.154 +        return dev
   8.155 +
   8.156 +    def attachDevice(self, vdev, mode, segment, recreate=0):
   8.157          """Attach a device to the specified interface.
   8.158          """
   8.159          #print 'BlkifController>attach_device>', self.dom, vdev, mode, segment
   8.160 -        if vdev in self.devices: return -1
   8.161 -        dev = BlkDev(vdev, mode, segment)
   8.162 -        self.devices[vdev] = dev
   8.163 -        self.send_be_vbd_create(vdev)
   8.164 -        return self.factory.addDeferred()
   8.165 +        dev = self.addDevice(vdev, mode, segment)
   8.166 +        if not dev: return -1
   8.167 +        if recreate:
   8.168 +            d = defer.Deferred()
   8.169 +            d.callback(self)
   8.170 +        else:
   8.171 +            self.send_be_vbd_create(vdev)
   8.172 +            d = self.factory.addDeferred()
   8.173 +        return d
   8.174 +
   8.175 +    def destroy(self):
   8.176 +        self.destroyDevices()
   8.177 +
   8.178 +    def destroyDevices(self):
   8.179 +        for dev in self.getDevices():
   8.180 +            dev.destroy()
   8.181  
   8.182      def detach(self):
   8.183          """Detach all devices, when the back-end control domain has changed.
   8.184 @@ -178,7 +215,7 @@ class BlkifController(controller.Control
   8.185              dev.attached = 0
   8.186              self.send_be_vbd_create(vdev)
   8.187  
   8.188 -    def reattach_device(self, vdev):
   8.189 +    def reattachDevice(self, vdev):
   8.190          """Reattach a device, when the back-end control domain has changed.
   8.191          """
   8.192          dev = self.devices[vdev]
   8.193 @@ -254,4 +291,13 @@ class BlkifController(controller.Control
   8.194                          'extent.sector_start'  : dev.start_sector,
   8.195                          'extent.sector_length' : dev.nr_sectors })
   8.196          self.factory.writeRequest(msg)
   8.197 +
   8.198 +    def send_be_vbd_destroy(self, vdev):
   8.199 +        dev = self.devices[vdev]
   8.200 +        msg = packMsg('blkif_be_vbd_destroy_t',
   8.201 +                      { 'domid'                : self.dom,
   8.202 +                        'blkif_handle'         : 0,
   8.203 +                        'vdevice'              : dev.vdev })
   8.204 +        del self.devices[vdev]
   8.205 +        self.factory.writeRequest(msg)
   8.206      
     9.1 --- a/tools/xenmgr/lib/server/controller.py	Thu Jun 24 10:28:58 2004 +0000
     9.2 +++ b/tools/xenmgr/lib/server/controller.py	Thu Jun 24 12:00:50 2004 +0000
     9.3 @@ -95,7 +95,7 @@ class ControllerFactory(CtrlMsgRcvr):
     9.4          if instance.idx in self.instances:
     9.5              del self.instances[instance.idx]
     9.6  
     9.7 -    def createInstance(self, dom):
     9.8 +    def createInstance(self, dom, recreate=0):
     9.9          raise NotImplementedError()
    9.10  
    9.11      def instanceClosed(self, instance):
    9.12 @@ -136,3 +136,30 @@ class Controller(CtrlMsgRcvr):
    9.13  
    9.14      def lostChannel(self):
    9.15          self.factory.instanceClosed(self)
    9.16 +
    9.17 +class Dev:
    9.18 +
    9.19 +    def __init__(self, controller):
    9.20 +        self.controller = controller
    9.21 +        self.props = {}
    9.22 +
    9.23 +    def setprop(self, k, v):
    9.24 +        self.props[k] = v
    9.25 +
    9.26 +    def getprop(self, k, v=None):
    9.27 +        return self.props.get(k, v)
    9.28 +
    9.29 +    def hasprop(self, k):
    9.30 +        return k in self.props
    9.31 +
    9.32 +    def delprop(self, k):
    9.33 +        if k in self.props:
    9.34 +            del self.props[k]
    9.35 +
    9.36 +    #def __repr__(self):
    9.37 +    #    return str(self.sxpr())
    9.38 +
    9.39 +    def sxpr(self):
    9.40 +        raise NotImplementedError()
    9.41 +
    9.42 +    
    10.1 --- a/tools/xenmgr/lib/server/messages.py	Thu Jun 24 10:28:58 2004 +0000
    10.2 +++ b/tools/xenmgr/lib/server/messages.py	Thu Jun 24 12:00:50 2004 +0000
    10.3 @@ -76,6 +76,9 @@ blkif_formats = {
    10.4      'blkif_be_vbd_grow_t':
    10.5      (CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_GROW),
    10.6  
    10.7 +    'blkif_be_vbd_destroy_t':
    10.8 +    (CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_DESTROY),
    10.9 +
   10.10      'blkif_fe_interface_status_changed_t':
   10.11      (CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED),
   10.12  
    11.1 --- a/tools/xenmgr/lib/server/netif.py	Thu Jun 24 10:28:58 2004 +0000
    11.2 +++ b/tools/xenmgr/lib/server/netif.py	Thu Jun 24 12:00:50 2004 +0000
    11.3 @@ -1,5 +1,9 @@
    11.4  import random
    11.5  
    11.6 +from twisted.internet import defer
    11.7 +
    11.8 +from xenmgr import XendBridge
    11.9 +
   11.10  import channel
   11.11  import controller
   11.12  from messages import *
   11.13 @@ -22,7 +26,7 @@ class NetifControllerFactory(controller.
   11.14          self.attached = 1
   11.15          self.registerChannel()
   11.16  
   11.17 -    def createInstance(self, dom):
   11.18 +    def createInstance(self, dom, recreate=0):
   11.19          """Create or find the network interface controller for a domain.
   11.20          """
   11.21          #print 'netif>createInstance> dom=', dom
   11.22 @@ -40,12 +44,13 @@ class NetifControllerFactory(controller.
   11.23          netif = self.getInstanceByDom(dom)
   11.24          return (netif and netif.getDevice(vif)) or None
   11.25          
   11.26 -    def setControlDomain(self, dom):
   11.27 +    def setControlDomain(self, dom, recreate=0):
   11.28          """Set the 'back-end' device driver domain.
   11.29          """
   11.30          if self.dom == dom: return
   11.31          self.deregisterChannel()
   11.32 -        self.attached = 0
   11.33 +        if not recreate:
   11.34 +            self.attached = 0
   11.35          self.dom = dom
   11.36          self.registerChannel()
   11.37          #
   11.38 @@ -98,20 +103,38 @@ class NetifControllerFactory(controller.
   11.39  ##                 print "Done notifying guests"
   11.40  ##                 recovery = False
   11.41                  
   11.42 -class NetDev:
   11.43 +class NetDev(controller.Dev):
   11.44      """Info record for a network device.
   11.45      """
   11.46  
   11.47 -    def __init__(self, vif, mac):
   11.48 +    def __init__(self, ctrl, vif, mac):
   11.49 +        controller.Dev.__init__(self, ctrl)
   11.50          self.vif = vif
   11.51          self.mac = mac
   11.52          self.evtchn = None
   11.53 +        self.bridge = None
   11.54  
   11.55      def sxpr(self):
   11.56          vif = str(self.vif)
   11.57          mac = ':'.join(map(lambda x: "%x" % x, self.mac))
   11.58 -        return ['netif', ['vif', vif], ['mac', mac]]
   11.59 -    
   11.60 +        val = ['netif', ['vif', vif], ['mac', mac]]
   11.61 +        if self.bridge:
   11.62 +            val += ['bridge', self.bridge]
   11.63 +        return val
   11.64 +
   11.65 +    def bridge_add(self, bridge):
   11.66 +        self.bridge = XendBridge.vif_bridge_add(self.controller.dom, self.vif, bridge)
   11.67 +
   11.68 +    def bridge_rem(self):
   11.69 +        if not self.bridge: return
   11.70 +        XendBridge.vif_bridge_rem(self.controller.dom, self.vif, self.bridge)
   11.71 +        self.bridge = None
   11.72 +
   11.73 +    def destroy(self):
   11.74 +        self.bridge_rem()
   11.75 +        self.controller.send_be_destroy(self.vif)
   11.76 +        
   11.77 +
   11.78  class NetifController(controller.Controller):
   11.79      """Network interface controller. Handles all network devices for a domain.
   11.80      """
   11.81 @@ -150,8 +173,7 @@ class NetifController(controller.Control
   11.82  
   11.83      def lostChannel(self):
   11.84          print 'NetifController>lostChannel>', 'dom=', self.dom
   11.85 -        #for vif in self.devices:
   11.86 -        #    self.send_be_destroy(vif)
   11.87 +        #self.destroyDevices()
   11.88          controller.Controller.lostChannel(self)
   11.89  
   11.90      def getDevices(self):
   11.91 @@ -167,11 +189,18 @@ class NetifController(controller.Control
   11.92              mac = [ int(x, 16) for x in vmac.split(':') ]
   11.93          if len(mac) != 6: raise ValueError("invalid mac")
   11.94          #print "attach_device>", "vif=", vif, "mac=", mac
   11.95 -        dev = NetDev(vif, mac)
   11.96 +        dev = NetDev(self, vif, mac)
   11.97          self.devices[vif] = dev
   11.98          return dev
   11.99  
  11.100 -    def attach_device(self, vif, vmac):
  11.101 +    def destroy(self):
  11.102 +        self.destroyDevices()
  11.103 +        
  11.104 +    def destroyDevices(self):
  11.105 +        for dev in self.getDevices():
  11.106 +            dev.destroy()
  11.107 +
  11.108 +    def attachDevice(self, vif, vmac, recreate=0):
  11.109          """Attach a network device.
  11.110          If vmac is None a random mac address is assigned.
  11.111  
  11.112 @@ -179,8 +208,12 @@ class NetifController(controller.Control
  11.113          @param vmac mac address (string)
  11.114          """
  11.115          self.addDevice(vif, vmac)
  11.116 -        d = self.factory.addDeferred()
  11.117 -        self.send_be_create(vif)
  11.118 +        if recreate:
  11.119 +            d = defer.Deferred()
  11.120 +            d.callback(self)
  11.121 +        else:
  11.122 +            d = self.factory.addDeferred()
  11.123 +            self.send_be_create(vif)
  11.124          return d
  11.125  
  11.126      def reattach_devices(self):
    12.1 --- a/tools/xenmgr/lib/xm/create.py	Thu Jun 24 10:28:58 2004 +0000
    12.2 +++ b/tools/xenmgr/lib/xm/create.py	Thu Jun 24 12:00:50 2004 +0000
    12.3 @@ -1,3 +1,6 @@
    12.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    12.5 +"""Domain creation.
    12.6 +"""
    12.7  import string
    12.8  import sys
    12.9  
   12.10 @@ -13,7 +16,7 @@ Create a domain.
   12.11  """)
   12.12  
   12.13  gopts.opt('help', short='h',
   12.14 -         fn=set_value, default=0,
   12.15 +         fn=set_true, default=0,
   12.16           use="Print this help.")
   12.17  
   12.18  gopts.opt('quiet', short='q',
   12.19 @@ -36,21 +39,19 @@ gopts.opt('load', short='L', val='FILE',
   12.20            fn=set_value, default=None,
   12.21            use='Domain saved state to load.')
   12.22  
   12.23 -def set_var(opt, k, v):
   12.24 -    opt.set(v)
   12.25 -    for d in string.split(v, ';' ):
   12.26 -        (k, v) = string.split(d, '=')
   12.27 -        opt.opts.setvar(k, v)
   12.28 -
   12.29  gopts.opt('define', short='D', val='VAR=VAL',
   12.30           fn=set_var, default=None,
   12.31 -         use="""Set variables before loading defaults, e.g. '-D vmid=3;ip=1.2.3.4'
   12.32 -         to set vmid and ip.""")
   12.33 +         use="""Set a variable before loading defaults, e.g. '-D vmid=3'
   12.34 +         to set vmid. May be repeated to set more thanone variable.""")
   12.35  
   12.36  gopts.opt('dryrun', short='n',
   12.37           fn=set_true, default=0,
   12.38           use="Dry run - print the config but don't create the domain.")
   12.39  
   12.40 +gopts.opt('name', short='N', val='NAME',
   12.41 +          fn=set_value, default=None,
   12.42 +          use="Domain name.")
   12.43 +
   12.44  gopts.opt('console', short='c',
   12.45           fn=set_true, default=0,
   12.46           use="Connect to console after domain is created.")
   12.47 @@ -71,34 +72,48 @@ gopts.opt('memory', short='m', val='MEMO
   12.48           fn=set_value, default=128,
   12.49           use="Domain memory in MB.")
   12.50  
   12.51 +gopts.opt('blkif',
   12.52 +          fn=set_true, default=0,
   12.53 +          use="Make the domain a block device backend.")
   12.54 +
   12.55 +gopts.opt('netif',
   12.56 +          fn=set_true, default=0,
   12.57 +          use="Make the domain a network interface backend.")
   12.58 +
   12.59  gopts.opt('disk', short='d', val='phy:DEV,VDEV,MODE',
   12.60           fn=append_value, default=[],
   12.61           use="""Add a disk device to a domain. The physical device is DEV, which
   12.62 -         is exported to the domain as VDEV. The disk is read-only if MODE is r,
   12.63 -         read-write if mode is 'w'.""")
   12.64 +         is exported to the domain as VDEV. The disk is read-only if MODE
   12.65 +         is 'r', read-write if MODE is 'w'.
   12.66 +         The option may be repeated to add more than one disk.
   12.67 +         """)
   12.68  
   12.69  gopts.opt('pci', val='BUS,DEV,FUNC',
   12.70           fn=append_value, default=[],
   12.71 -         use="""Add a PCI device to a domain, using given params (in hex).""")
   12.72 +         use="""Add a PCI device to a domain, using given params (in hex).
   12.73 +         For example '-pci c0,02,1a'.
   12.74 +         The option may be repeated to add more than one pci device.
   12.75 +         """)
   12.76  
   12.77  gopts.opt('ipaddr', short='i', val="IPADDR",
   12.78           fn=append_value, default=[],
   12.79           use="Add an IP address to the domain.")
   12.80  
   12.81 -gopts.opt('mac', short='M', val="MAC",
   12.82 +gopts.opt('vif', val="mac=MAC,bridge=BRIDGE",
   12.83           fn=append_value, default=[],
   12.84 -         use="""Add a network interface with the given mac address to the domain.
   12.85 -         More than one interface may be specified. Interfaces with unspecified MAC addresses
   12.86 -         are allocated a random address.""")
   12.87 +         use="""Add a network interface with the given MAC address and bridge.
   12.88 +         If mac is not specified a random MAC address is used.
   12.89 +         If bridge is not specified the default bridge is used.
   12.90 +         This option may be repeated to add more than one vif.
   12.91 +         Specifying vifs will increase the number of interfaces as needed.
   12.92 +         """)
   12.93  
   12.94 -gopts.opt('nics', val="N",
   12.95 +gopts.opt('nics', val="NUM",
   12.96           fn=set_int, default=1,
   12.97 -         use="Set the number of network interfaces.")
   12.98 -
   12.99 -gopts.opt('vnet', val='VNET',
  12.100 -         fn=append_value, default=[],
  12.101 -         use="""Define the vnets for the network interfaces.
  12.102 -         More than one vnet may be given, they are used in order.
  12.103 +         use="""Set the number of network interfaces.
  12.104 +         Use the vif option to define interface parameters, otherwise
  12.105 +         defaults are used. Specifying vifs will increase the
  12.106 +         number of interfaces as needed.
  12.107           """)
  12.108  
  12.109  gopts.opt('root', short='R', val='DEVICE',
  12.110 @@ -116,15 +131,15 @@ gopts.opt('ip', short='I', val='IPADDR',
  12.111  
  12.112  gopts.opt('gateway', val="IPADDR",
  12.113           fn=set_value, default='',
  12.114 -         use="Set kernel IP gateway.")
  12.115 +         use="Set the kernel IP gateway.")
  12.116  
  12.117  gopts.opt('netmask', val="MASK",
  12.118           fn=set_value, default = '',
  12.119 -         use="Set kernel IP netmask.")
  12.120 +         use="Set the kernel IP netmask.")
  12.121  
  12.122  gopts.opt('hostname', val="NAME",
  12.123           fn=set_value, default='',
  12.124 -         use="Set kernel IP hostname.")
  12.125 +         use="Set the kernel IP hostname.")
  12.126  
  12.127  gopts.opt('interface', val="INTF",
  12.128           fn=set_value, default="eth0",
  12.129 @@ -132,7 +147,7 @@ gopts.opt('interface', val="INTF",
  12.130  
  12.131  gopts.opt('dhcp', val="off|dhcp",
  12.132           fn=set_value, default='off',
  12.133 -         use="Set kernel dhcp option.")
  12.134 +         use="Set the kernel dhcp option.")
  12.135  
  12.136  gopts.opt('nfs_server', val="IPADDR",
  12.137           fn=set_value, default=None,
  12.138 @@ -143,19 +158,16 @@ gopts.opt('nfs_root', val="PATH",
  12.139           use="Set the path of the root NFS directory.")
  12.140  
  12.141  def strip(pre, s):
  12.142 +    """Strip prefix 'pre' if present.
  12.143 +    """
  12.144      if s.startswith(pre):
  12.145          return s[len(pre):]
  12.146      else:
  12.147          return s
  12.148  
  12.149 -def make_config(opts):
  12.150 -    
  12.151 -    config = ['config',
  12.152 -              ['name', opts.name ],
  12.153 -              ['memory', opts.memory ] ]
  12.154 -    if opts.cpu:
  12.155 -        config.append(['cpu', opts.cpu])
  12.156 -    
  12.157 +def configure_image(config, opts):
  12.158 +    """Create the image config.
  12.159 +    """
  12.160      config_image = [ opts.builder ]
  12.161      config_image.append([ 'kernel', os.path.abspath(opts.kernel) ])
  12.162      if opts.ramdisk:
  12.163 @@ -169,8 +181,10 @@ def make_config(opts):
  12.164      if opts.extra:
  12.165          config_image.append(['args', opts.extra])
  12.166      config.append(['image', config_image ])
  12.167 -    	
  12.168 -    config_devs = []
  12.169 +    
  12.170 +def configure_disks(config_devs, opts):
  12.171 +    """Create the config for disks (virtual block devices).
  12.172 +    """
  12.173      for (uname, dev, mode) in opts.disk:
  12.174          config_vbd = ['vbd',
  12.175                        ['uname', uname],
  12.176 @@ -178,18 +192,34 @@ def make_config(opts):
  12.177                        ['mode', mode ] ]
  12.178          config_devs.append(['device', config_vbd])
  12.179  
  12.180 +def configure_pci(config_devs, opts):
  12.181 +    """Create the config for pci devices.
  12.182 +    """
  12.183      for (bus, dev, func) in opts.pci:
  12.184          config_pci = ['pci', ['bus', bus], ['dev', dev], ['func', func]]
  12.185          config_devs.append(['device', config_pci])
  12.186  
  12.187 -    for idx in range(0, opts.nics):
  12.188 -        config_vif = ['vif', ['@', ['id', 'vif%d' % idx]]]
  12.189 -        if idx < len(opts.mac):
  12.190 -            config_vif.append(['mac', opts.mac[idx]])
  12.191 +def configure_vifs(config_devs, opts):
  12.192 +    """Create the config for virtual network interfaces.
  12.193 +    """
  12.194 +    vifs = opts.vif
  12.195 +    vifs_n = max(opts.nics, len(vifs))
  12.196 +
  12.197 +    for idx in range(0, vifs_n):
  12.198 +        if idx < len(vifs):
  12.199 +            d = vifs[idx]
  12.200 +            mac = d.get('mac')
  12.201 +            bridge = d.get('bridge')
  12.202 +        else:
  12.203 +            mac = None
  12.204 +            bridge = None
  12.205 +        config_vif = ['vif']
  12.206 +        if mac:
  12.207 +            config_vif.append(['mac', mac])
  12.208 +        if bridge:
  12.209 +            config_vif.append(['bridge', bridge])
  12.210          config_devs.append(['device', config_vif])
  12.211  
  12.212 -    config += config_devs
  12.213 -
  12.214  ##     if vfr_ipaddr:
  12.215  ##         config_vfr = ['vfr']
  12.216  ##         idx = 0 # No way of saying which IP is for which vif?
  12.217 @@ -197,15 +227,27 @@ def make_config(opts):
  12.218  ##             config_vfr.append(['vif', ['id', idx], ['ip', ip]])
  12.219  ##         config.append(config_vfr)
  12.220  
  12.221 -    if opts.vnet:
  12.222 -        config_vnet = ['vnet']
  12.223 -        idx = 0
  12.224 -        for vnet in opts.vnet:
  12.225 -            config_vif = ['vif', ['id', 'vif%d' % idx], ['vnet', vnet]]
  12.226 -            config_vnet.append(config_vif)
  12.227 -            idx += 1
  12.228 -        config.append(config_vnet)
  12.229 -            
  12.230 +
  12.231 +def make_config(opts):
  12.232 +    """Create the domain configuration.
  12.233 +    """
  12.234 +    
  12.235 +    config = ['vm',
  12.236 +              ['name', opts.name ],
  12.237 +              ['memory', opts.memory ] ]
  12.238 +    if opts.cpu:
  12.239 +        config.append(['cpu', opts.cpu])
  12.240 +    if opts.blkif:
  12.241 +        config.append(['backend', ['blkif']])
  12.242 +    if opts.netif:
  12.243 +        config.append(['backend', ['netif']])
  12.244 +    
  12.245 +    configure_image(config, opts)
  12.246 +    config_devs = []
  12.247 +    configure_disks(config_devs, opts)
  12.248 +    configure_pci(config_devs, opts)
  12.249 +    configure_vifs(config_devs, opts)
  12.250 +    config += config_devs
  12.251      return config
  12.252  
  12.253  def preprocess_disk(opts):
  12.254 @@ -213,7 +255,6 @@ def preprocess_disk(opts):
  12.255      disk = []
  12.256      for v in opts.disk:
  12.257          d = v.split(',')
  12.258 -        print 'disk', v, d
  12.259          if len(d) != 3:
  12.260              opts.err('Invalid disk specifier: ' + v)
  12.261          disk.append(d)
  12.262 @@ -231,6 +272,22 @@ def preprocess_pci(opts):
  12.263          pci.append(hexd)
  12.264      opts.pci = pci
  12.265  
  12.266 +def preprocess_vifs(opts):
  12.267 +    if not opts.vif: return
  12.268 +    vifs = []
  12.269 +    for vif in opts.vif:
  12.270 +        d = {}
  12.271 +        a = vif.split(',')
  12.272 +        for b in a:
  12.273 +            (k, v) = b.strip().split('=')
  12.274 +            k = k.strip()
  12.275 +            v = v.strip()
  12.276 +            if k not in ['mac', 'bridge']:
  12.277 +                opts.err('Invalid vif specifier: ' + vif)
  12.278 +            d[k] = v
  12.279 +        vifs.append(d)
  12.280 +    opts.vif = vifs
  12.281 +
  12.282  def preprocess_ip(opts):
  12.283      setip = (opts.hostname or opts.netmask
  12.284               or opts.gateway or opts.dhcp or opts.interface)
  12.285 @@ -259,6 +316,7 @@ def preprocess(opts):
  12.286          opts.err("No kernel specified")
  12.287      preprocess_disk(opts)
  12.288      preprocess_pci(opts)
  12.289 +    preprocess_vifs(opts)
  12.290      preprocess_ip(opts)
  12.291      preprocess_nfs(opts)
  12.292           
  12.293 @@ -266,8 +324,8 @@ def make_domain(opts, config):
  12.294      """Create, build and start a domain.
  12.295      Returns: [int] the ID of the new domain.
  12.296      """
  12.297 -    if opts.load:
  12.298 -        filename = os.path.abspath(opts.load)
  12.299 +    if opts.vals.load:
  12.300 +        filename = os.path.abspath(opts.vals.load)
  12.301          dominfo = server.xend_domain_restore(filename, config)
  12.302      else:
  12.303          dominfo = server.xend_domain_create(config)
  12.304 @@ -280,7 +338,7 @@ def make_domain(opts, config):
  12.305          console_port = None
  12.306      
  12.307      if server.xend_domain_unpause(dom) < 0:
  12.308 -        server.xend_domain_halt(dom)
  12.309 +        server.xend_domain_destroy(dom)
  12.310          opts.err("Failed to start domain %d" % dom)
  12.311      opts.info("Started domain %d, console on port %d"
  12.312                % (dom, console_port))
  12.313 @@ -289,16 +347,16 @@ def make_domain(opts, config):
  12.314  def main(argv):
  12.315      opts = gopts
  12.316      args = opts.parse(argv)
  12.317 -    if opts.help:
  12.318 +    if opts.vals.help:
  12.319          opts.usage()
  12.320          return
  12.321 -    if opts.config:
  12.322 +    if opts.vals.config:
  12.323          pass
  12.324      else:
  12.325          opts.load_defaults()
  12.326 -    preprocess(opts)
  12.327 -    config = make_config(opts)
  12.328 -    if opts.dryrun:
  12.329 +    preprocess(opts.vals)
  12.330 +    config = make_config(opts.vals)
  12.331 +    if opts.vals.dryrun:
  12.332          PrettyPrint.prettyprint(config)
  12.333      else:
  12.334          make_domain(opts, config)
    13.1 --- a/tools/xenmgr/lib/xm/main.py	Thu Jun 24 10:28:58 2004 +0000
    13.2 +++ b/tools/xenmgr/lib/xm/main.py	Thu Jun 24 12:00:50 2004 +0000
    13.3 @@ -10,27 +10,72 @@ from xenmgr import sxp
    13.4  from xenmgr.XendClient import server
    13.5  from xenmgr.xm import create, shutdown
    13.6  
    13.7 +class Prog:
    13.8 +    """Base class for sub-programs.
    13.9 +    """
   13.10 +
   13.11 +    """Program group it belongs to"""
   13.12 +    group = 'all'
   13.13 +    """Program name."""
   13.14 +    name = '??'
   13.15 +    """Short program info."""
   13.16 +    info = ''
   13.17 +
   13.18 +    def __init__(self, xm):
   13.19 +        self.xm = xm
   13.20 +
   13.21 +    def err(self, msg):
   13.22 +        self.xm.err(msg)
   13.23 +
   13.24 +    def help(self, args):
   13.25 +        self.shortHelp(args)
   13.26 +
   13.27 +    def shortHelp(self, args):
   13.28 +        print "%-14s %s" % (self.name, self.info)
   13.29 +
   13.30 +    def main(self, args):
   13.31 +        """Program main entry point.
   13.32 +        """
   13.33 +        pass
   13.34 +
   13.35 +
   13.36 +class ProgUnknown(Prog):
   13.37 +
   13.38 +    name = 'unknown'
   13.39 +    info = ''
   13.40 +    
   13.41 +    def help(self, args):
   13.42 +        self.xm.err("Unknown command: %s\nTry '%s help' for more information."
   13.43 +                    % (args[0], self.xm.name))
   13.44 +
   13.45 +    main = help
   13.46 +
   13.47  class Xm:
   13.48 +    """Main application.
   13.49 +    """
   13.50  
   13.51      def __init__(self):
   13.52 -        self.prog = 'xm'
   13.53 -        pass
   13.54 +        self.name = 'xm'
   13.55 +        self.unknown = ProgUnknown(self)
   13.56 +        self.progs = {}
   13.57  
   13.58      def err(self, msg):
   13.59          print >>sys.stderr, "Error:", msg
   13.60          sys.exit(1)
   13.61  
   13.62      def main(self, args):
   13.63 -        """Main entry point. Dispatches to the xm_ methods.
   13.64 +        """Main entry point. Dispatches to the progs.
   13.65          """
   13.66 -        self.prog = args[0]
   13.67 +        self.name = args[0]
   13.68          if len(args) < 2:
   13.69              self.err("Missing command\nTry '%s help' for more information."
   13.70 -                     % self.prog)
   13.71 -        prog = 'xm_' + args[1]
   13.72 +                     % self.name)
   13.73          help = self.helparg(args)
   13.74 -        fn = getattr(self, prog, self.unknown)
   13.75 -        fn(help, args[1:])
   13.76 +        p = self.getprog(args[1], self.unknown)
   13.77 +        if help:
   13.78 +            p.help(args[1:])
   13.79 +        else:
   13.80 +            p.main(args[1:])
   13.81  
   13.82      def helparg(self, args):
   13.83          for a in args:
   13.84 @@ -38,39 +83,87 @@ class Xm:
   13.85                  return 1
   13.86          return 0
   13.87  
   13.88 -    def unknown(self, help, args):
   13.89 -        if help and len(args) == 1:
   13.90 -            self.xm_help(help, args)
   13.91 -        else:
   13.92 -            self.err("Unknown command: %s\nTry '%s help' for more information."
   13.93 -                     % (args[0], self.prog))
   13.94 +    def prog(self, pklass):
   13.95 +        """Add a sub-program.
   13.96  
   13.97 -    def help(self, meth, args):
   13.98 -        """Print help on an xm_ method.
   13.99 -        Uses the method documentation string if there is one.
  13.100 +        pklass  program class (Prog subclass)
  13.101 +        """
  13.102 +        p = pklass(self)
  13.103 +        self.progs[p.name] = p
  13.104 +        return p
  13.105 +
  13.106 +    def getprog(self, name, val=None):
  13.107 +        """Get a sub-program.
  13.108 +        """
  13.109 +        return self.progs.get(name, val)
  13.110 +
  13.111 +    def proglist(self):
  13.112 +        """Get a list of sub-programs, ordered by group.
  13.113          """
  13.114 -        name = meth[3:]
  13.115 -        f = getattr(self, meth)
  13.116 -        print "%-14s %s" % (name, f.__doc__ or '')
  13.117 +        groups = {}
  13.118 +        for p in self.progs.values():
  13.119 +            l = groups.get(p.group, [])
  13.120 +            l.append(p)
  13.121 +            groups[p.group] = l
  13.122 +        kl = groups.keys()
  13.123 +        kl.sort()
  13.124 +        pl = []
  13.125 +        for k in kl:
  13.126 +            l = groups[k]
  13.127 +            l.sort()
  13.128 +            pl += l
  13.129 +        return pl
  13.130 +        
  13.131 +# Create the application object, then add the sub-program classes.
  13.132 +xm = Xm()
  13.133 +
  13.134 +class ProgHelp(Prog):
  13.135  
  13.136 -    def xm_help(self, help, args):
  13.137 -        """Print help."""
  13.138 -        for k in dir(self):
  13.139 -            if not k.startswith('xm_'): continue
  13.140 -            self.help(k, args)
  13.141 -        print "\nTry '%s CMD -h' for help on CMD" % self.prog
  13.142 -                
  13.143 -    def xm_create(self, help, args):
  13.144 -        """Create a domain."""
  13.145 +    name = "help"
  13.146 +    info = "Print help."
  13.147 +    
  13.148 +    def help(self, args):
  13.149 +        if len(args) == 2:
  13.150 +            name = args[1]
  13.151 +            p = self.xm.getprog(name)
  13.152 +            if p:
  13.153 +                p.help(args)
  13.154 +            else:
  13.155 +                print '%s: Unknown command: %s' % (self.name, name)
  13.156 +        else:
  13.157 +            for p in self.xm.proglist():
  13.158 +                p.shortHelp(args)
  13.159 +            print "\nTry '%s help CMD' for help on CMD" % self.xm.name
  13.160 +
  13.161 +    main = help
  13.162 +
  13.163 +xm.prog(ProgHelp)
  13.164 +
  13.165 +class ProgCreate(Prog):
  13.166 +
  13.167 +    group = 'domain'
  13.168 +    name = "create"
  13.169 +    info = """Create a domain."""
  13.170 +
  13.171 +    def help(self, args):
  13.172 +        create.main([args[0], '-h'])
  13.173 +
  13.174 +    def main(self, args):
  13.175          create.main(args)
  13.176  
  13.177 -    def xm_save(self, help, args):
  13.178 -        """Save domain state (and config) to file."""
  13.179 -        if help:
  13.180 -            print args[0], "DOM FILE [CONFIG]"
  13.181 -            print """\nSave domain with id DOM to FILE.
  13.182 -            Optionally save config to CONFIG."""
  13.183 -            return
  13.184 +xm.prog(ProgCreate)
  13.185 +
  13.186 +class ProgSave(Prog):
  13.187 +    group = 'domain'
  13.188 +    name = "save"
  13.189 +    info = """Save domain state (and config) to file."""
  13.190 +
  13.191 +    def help(self, args):
  13.192 +        print args[0], "DOM FILE [CONFIG]"
  13.193 +        print """\nSave domain with id DOM to FILE.
  13.194 +        Optionally save config to CONFIG."""
  13.195 +        
  13.196 +    def main(self, args):
  13.197          if len(args) < 3: self.err("%s: Missing arguments" % args[0])
  13.198          dom = args[1]
  13.199          savefile = os.path.abspath(args[2])
  13.200 @@ -83,23 +176,45 @@ class Xm:
  13.201              PrettyPrint.prettyprint(config, out=out)
  13.202              out.close()
  13.203          server.xend_domain_save(dom, savefile)
  13.204 -            
  13.205 -    def xm_restore(self, help, args):
  13.206 -        """Create a domain from a saved state."""
  13.207 -        if help:
  13.208 -            print args[0], "FILE CONFIG"
  13.209 -            print "\nRestore a domain from FILE using configuration CONFIG."
  13.210 -            return
  13.211 +
  13.212 +xm.prog(ProgSave)
  13.213 +
  13.214 +class ProgRestore(Prog):
  13.215 +    group = 'domain'
  13.216 +    name = "restore"
  13.217 +    info = """Create a domain from a saved state."""
  13.218 +
  13.219 +    def help(self, args):
  13.220 +        print args[0], "FILE CONFIG"
  13.221 +        print "\nRestore a domain from FILE using configuration CONFIG."
  13.222 +    
  13.223 +    def main(self, help, args):
  13.224          if len(args) < 3: self.err("%s: Missing arguments" % args[0])
  13.225          savefile =  os.path.abspath(args[1])
  13.226          configfile = os.path.abspath(args[2])
  13.227          info = server.xend_domain_restore(savefile, configfile)
  13.228          PrettyPrint.prettyprint(info)
  13.229  
  13.230 -    def xm_domains(self, help, args):
  13.231 -        """List domains."""
  13.232 -        if help: self.help('xm_' + args[0], args); return
  13.233 -        doms = server.xend_domains()
  13.234 +xm.prog(ProgRestore)
  13.235 +
  13.236 +class ProgList(Prog):
  13.237 +    group = 'domain'
  13.238 +    name = "list"
  13.239 +    info = """List info about domains."""
  13.240 +
  13.241 +    def help(self, args):
  13.242 +        if help:
  13.243 +            print args[0], '[DOM...]'
  13.244 +            print """\nGet information about domains.
  13.245 +            Either all domains or the domains given."""
  13.246 +            return
  13.247 +        
  13.248 +    def main(self, args):
  13.249 +        n = len(args)
  13.250 +        if n == 1:
  13.251 +            doms = server.xend_domains()
  13.252 +        else:
  13.253 +            doms = map(int, args[1:])
  13.254          doms.sort()
  13.255          print 'Dom  Name             Mem(MB)  CPU  State  Time(s)'
  13.256          for dom in doms:
  13.257 @@ -113,111 +228,167 @@ class Xm:
  13.258              d['cpu_time'] = float(sxp.child_value(info, 'cpu_time', '0'))
  13.259              print ("%(dom)-4d %(name)-16s %(mem)7d  %(cpu)3d  %(state)5s  %(cpu_time)7.1f" % d)
  13.260  
  13.261 -    def xm_domain(self, help, args):
  13.262 -        """Get information about a domain."""
  13.263 -        if help:
  13.264 -            print args[0], 'DOM'
  13.265 -            print '\nGet information about domain DOM.'
  13.266 -            return
  13.267 +xm.prog(ProgList)
  13.268 +
  13.269 +class ProgDestroy(Prog):
  13.270 +    group = 'domain'
  13.271 +    name = "destroy"
  13.272 +    info = """Terminate a domain immediately."""
  13.273 +
  13.274 +    def help(self, args):
  13.275 +        print args[0], 'DOM'
  13.276 +        print '\nTerminate domain DOM immediately.'
  13.277 +
  13.278 +    def main(self, args):
  13.279          if len(args) < 2: self.err("%s: Missing domain" % args[0])
  13.280          dom = args[1]
  13.281 -        info = server.xend_domain(dom)
  13.282 -        PrettyPrint.prettyprint(info)
  13.283 -        print
  13.284 +        server.xend_domain_destroy(dom)
  13.285 +
  13.286 +xm.prog(ProgDestroy)
  13.287  
  13.288 -    def xm_halt(self, help, args):
  13.289 -        """Terminate a domain immediately."""
  13.290 -        if help:
  13.291 -            print args[0], 'DOM'
  13.292 -            print '\nTerminate domain DOM immediately.'
  13.293 -            return
  13.294 -        if len(args) < 2: self.err("%s: Missing domain" % args[0])
  13.295 -        dom = args[1]
  13.296 -        server.xend_domain_halt(dom)
  13.297 +class ProgShutdown(Prog):
  13.298 +    group = 'domain'
  13.299 +    name = "shutdown"
  13.300 +    info = """Shutdown a domain."""
  13.301  
  13.302 -    def xm_shutdown(self, help, args):
  13.303 -        """Shutdown a domain."""
  13.304 +    def help(self, args):
  13.305 +        print args[0], 'DOM'
  13.306 +        print '\nSignal domain DOM to shutdown.'
  13.307 +    
  13.308 +    def main(self, args):
  13.309          shutdown.main(args)
  13.310  
  13.311 -    def xm_pause(self, help, args):
  13.312 -        """Pause execution of a domain."""
  13.313 -        if help:
  13.314 -            print args[0], 'DOM'
  13.315 -            print '\nPause execution of domain DOM.'
  13.316 -            return
  13.317 +xm.prog(ProgShutdown)
  13.318 +
  13.319 +class ProgPause(Prog):
  13.320 +    group = 'domain'
  13.321 +    name = "pause"
  13.322 +    info = """Pause execution of a domain."""
  13.323 +
  13.324 +    def help(self, args):
  13.325 +        print args[0], 'DOM'
  13.326 +        print '\nPause execution of domain DOM.'
  13.327 +
  13.328 +    def main(self, args):
  13.329          if len(args) < 2: self.err("%s: Missing domain" % args[0])
  13.330          dom = args[1]
  13.331          server.xend_domain_pause(dom)
  13.332  
  13.333 -    def xm_unpause(self, help, args):
  13.334 -        """Unpause a paused domain."""
  13.335 -        if help:
  13.336 -            print args[0], 'DOM'
  13.337 -            print '\nUnpause execution of domain DOM.'
  13.338 -            return
  13.339 +xm.prog(ProgPause)
  13.340 +
  13.341 +class ProgUnpause(Prog):
  13.342 +    group = 'domain'
  13.343 +    name = "unpause"
  13.344 +    info = """Unpause a paused domain."""
  13.345 +
  13.346 +    def help(self, args):
  13.347 +        print args[0], 'DOM'
  13.348 +        print '\nUnpause execution of domain DOM.'
  13.349 +
  13.350 +    def main(self, args):
  13.351          if len(args) < 2: self.err("%s: Missing domain" % args[0])
  13.352          dom = args[1]
  13.353          server.xend_domain_unpause(dom)
  13.354  
  13.355 -    def xm_pincpu(self, help, args):
  13.356 -        """Pin a domain to a cpu. """
  13.357 -        if help:
  13.358 -            print args[0],'DOM CPU'
  13.359 -            print '\nPin domain DOM to cpu CPU.'
  13.360 -            return
  13.361 +xm.prog(ProgUnpause)
  13.362 +
  13.363 +class ProgPincpu(Prog):
  13.364 +    group = 'domain'
  13.365 +    name = "pincpu"
  13.366 +    info = """Pin a domain to a cpu. """
  13.367 +
  13.368 +    def help(self, args):
  13.369 +        print args[0],'DOM CPU'
  13.370 +        print '\nPin domain DOM to cpu CPU.'
  13.371 +
  13.372 +    def main(self, args):
  13.373          if len(args) != 3: self.err("%s: Invalid argument(s)" % args[0])
  13.374          v = map(int, args[1:3])
  13.375          server.xend_domain_pincpu(*v)
  13.376  
  13.377 -    def xm_bvt(self, help, args):
  13.378 -        """Set BVT scheduler parameters."""
  13.379 -        if help:
  13.380 -            print args[0], "DOM MCUADV WARP WARPL WARPU"
  13.381 -            print '\nSet Borrowed Virtual Time scheduler parameters.'
  13.382 -            return
  13.383 +xm.prog(ProgPincpu)
  13.384 +
  13.385 +class ProgBvt(Prog):
  13.386 +    group = 'scheduler'
  13.387 +    name = "bvt"
  13.388 +    info = """Set BVT scheduler parameters."""
  13.389 +    
  13.390 +    def help(self, args):
  13.391 +        print args[0], "DOM MCUADV WARP WARPL WARPU"
  13.392 +        print '\nSet Borrowed Virtual Time scheduler parameters.'
  13.393 +
  13.394 +    def main(self, args):
  13.395          if len(args) != 6: self.err("%s: Invalid argument(s)" % args[0])
  13.396          v = map(int, args[1:6])
  13.397          server.xend_domain_cpu_bvt_set(*v)
  13.398  
  13.399 -    def xm_bvtslice(self, help, args):
  13.400 -        """Set the BVT scheduler slice."""
  13.401 -        if help:
  13.402 -            print args[0], 'SLICE'
  13.403 -            print '\nSet Borrowed Virtual Time scheduler slice.'
  13.404 -            return
  13.405 +xm.prog(ProgBvt)
  13.406 +
  13.407 +class ProgBvtslice(Prog):
  13.408 +    group = 'scheduler'
  13.409 +    name = "bvtslice"
  13.410 +    info = """Set the BVT scheduler slice."""
  13.411 +
  13.412 +    def help(self, args):
  13.413 +        print args[0], 'SLICE'
  13.414 +        print '\nSet Borrowed Virtual Time scheduler slice.'
  13.415 +
  13.416 +    def main(self, args):
  13.417          if len(args) < 2: self.err('%s: Missing slice' % args[0])
  13.418          server.xend_node_cpu_bvt_slice_set(slice)
  13.419  
  13.420 -    def xm_atropos(self, help, args):
  13.421 -        """Set atropos parameters."""
  13.422 -        if help:
  13.423 -            print args[0], "DOM PERIOD SLICE LATENCY XTRATIME"
  13.424 -            print "\nSet atropos parameters."
  13.425 -            return
  13.426 +xm.prog(ProgBvtslice)
  13.427 +
  13.428 +class ProgAtropos(Prog):
  13.429 +    group = 'scheduler'
  13.430 +    name= "atropos"
  13.431 +    info = """Set atropos parameters."""
  13.432 +
  13.433 +    def help(self, args):
  13.434 +        print args[0], "DOM PERIOD SLICE LATENCY XTRATIME"
  13.435 +        print "\nSet atropos parameters."
  13.436 +
  13.437 +    def main(self, args):
  13.438          if len(args) != 5: self.err("%s: Invalid argument(s)" % args[0])
  13.439          v = map(int, args[1:5])
  13.440          server.xend_domain_cpu_atropos_set(*v)
  13.441  
  13.442 -    def xm_rrobin(self, help, args):
  13.443 -        """Set round robin slice."""
  13.444 -        if help:
  13.445 -            print args[0], "SLICE"
  13.446 -            print "\nSet round robin scheduler slice."
  13.447 -            return
  13.448 +xm.prog(ProgAtropos)
  13.449 +
  13.450 +class ProgRrobin(Prog):
  13.451 +    group = 'scheduler'
  13.452 +    name = "rrobin"
  13.453 +    info = """Set round robin slice."""
  13.454 +
  13.455 +    def help(self, args):
  13.456 +        print args[0], "SLICE"
  13.457 +        print "\nSet round robin scheduler slice."
  13.458 +
  13.459 +    def main(self, args):
  13.460          if len(args) != 2: self.err("%s: Invalid argument(s)" % args[0])
  13.461          rrslice = int(args[1])
  13.462          server.xend_node_rrobin_set(rrslice)
  13.463  
  13.464 -    def xm_info(self, help, args):
  13.465 -        """Get information about the xen host."""
  13.466 -        if help: self.help('xm_' + args[0], args); return
  13.467 +xm.prog(ProgRrobin)
  13.468 +
  13.469 +class ProgInfo(Prog):
  13.470 +    group = 'host'
  13.471 +    name = "info"
  13.472 +    info = """Get information about the xen host."""
  13.473 +
  13.474 +    def main(self, args):
  13.475          info = server.xend_node()
  13.476          for x in info[1:]:
  13.477              print "%-23s:" % x[0], x[1]
  13.478  
  13.479 -    def xm_consoles(self, help, args):
  13.480 -        """Get information about domain consoles."""
  13.481 -        if help: self.help('xm_' + args[0], args); return
  13.482 +xm.prog(ProgInfo)
  13.483 +
  13.484 +class ProgConsoles(Prog):
  13.485 +    group = 'console'
  13.486 +    name = "consoles"
  13.487 +    info = """Get information about domain consoles."""
  13.488 +
  13.489 +    def main(self, args):
  13.490          l = server.xend_consoles()
  13.491          print "Dom Port  Id"
  13.492          for x in l:
  13.493 @@ -228,12 +399,18 @@ class Xm:
  13.494              d['id'] = sxp.child_value(info, 'id', '?')
  13.495              print "%(dom)3s %(port)4s %(id)3s" % d
  13.496  
  13.497 -    def xm_console(self, help, args):
  13.498 -        """Open a console to a domain."""
  13.499 -        if help:
  13.500 -            print "console DOM"
  13.501 -            print "\nOpen a console to domain DOM."
  13.502 -            return
  13.503 +xm.prog(ProgConsoles)
  13.504 +
  13.505 +class ProgConsole(Prog):
  13.506 +    group = 'console'
  13.507 +    name = "console"
  13.508 +    info = """Open a console to a domain."""
  13.509 +    
  13.510 +    def help(self, args):
  13.511 +        print "console DOM"
  13.512 +        print "\nOpen a console to domain DOM."
  13.513 +
  13.514 +    def main(self, args):
  13.515          if len(args) < 2: self.err("%s: Missing domain" % args[0])
  13.516          dom = args[1]
  13.517          info = server.xend_domain(dom)
  13.518 @@ -244,6 +421,7 @@ class Xm:
  13.519          from xenctl import console_client
  13.520          console_client.connect("localhost", int(port))
  13.521  
  13.522 +xm.prog(ProgConsole)
  13.523 +
  13.524  def main(args):
  13.525 -    xm = Xm()
  13.526      xm.main(args)
    14.1 --- a/tools/xenmgr/lib/xm/opts.py	Thu Jun 24 10:28:58 2004 +0000
    14.2 +++ b/tools/xenmgr/lib/xm/opts.py	Thu Jun 24 12:00:50 2004 +0000
    14.3 @@ -1,3 +1,6 @@
    14.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    14.5 +"""Object-oriented command-line option support.
    14.6 +"""
    14.7  from getopt import getopt
    14.8  import os
    14.9  import os.path
   14.10 @@ -5,8 +8,22 @@ import sys
   14.11  import types
   14.12  
   14.13  class Opt:
   14.14 +    """An individual option.
   14.15 +    """
   14.16      def __init__(self, opts, name, short=None, long=None,
   14.17                   val=None, fn=None, use=None, default=None):
   14.18 +        """Create an option.
   14.19 +
   14.20 +        opts    parent options object
   14.21 +        name    name of the field it controls
   14.22 +        short   short (1-char) command line switch (optional)
   14.23 +        long    long command-line switch. Defaults to option name.
   14.24 +        val     string used to print option args in help.
   14.25 +                If val is not specified the option has no arg.
   14.26 +        fn      function to call when the option is specified.
   14.27 +        use     usage (help) string
   14.28 +        default default value if not specified on command-line
   14.29 +        """
   14.30          self.opts = opts
   14.31          self.name = name
   14.32          self.short = short
   14.33 @@ -24,18 +41,34 @@ class Opt:
   14.34          self.fn = fn
   14.35          self.specified_opt = None
   14.36          self.specified_val = None
   14.37 +        self.value = None
   14.38          self.set(default)
   14.39  
   14.40 +    def __repr__(self):
   14.41 +        return self.name + '=' + str(self.specified_val)
   14.42 +
   14.43 +    __str__ = __repr__
   14.44 +
   14.45      def set(self, value):
   14.46 -        setattr(self.opts, self.name, value)
   14.47 +        """Set the option value.
   14.48 +        """
   14.49 +        self.opts.setopt(self.name, value)
   14.50  
   14.51      def get(self):
   14.52 -        return getattr(self.opts, self.name)
   14.53 +        """Get the option value.
   14.54 +        """
   14.55 +        return self.opts.getopt(self.name)
   14.56  
   14.57      def append(self, value):
   14.58 -        self.set(self.get().append(value))
   14.59 +        """Append a value to the option value.
   14.60 +        """
   14.61 +        v = self.get() or []
   14.62 +        v.append(value)
   14.63 +        self.set(v)
   14.64  
   14.65      def short_opt(self):
   14.66 +        """Short option spec.
   14.67 +        """
   14.68          if self.short:
   14.69              if self.val:
   14.70                  return self.short + ':'
   14.71 @@ -45,6 +78,8 @@ class Opt:
   14.72              return None
   14.73  
   14.74      def long_opt(self):
   14.75 +        """Long option spec.
   14.76 +        """
   14.77          if self.long:
   14.78              if self.val:
   14.79                  return self.long + '='
   14.80 @@ -68,6 +103,12 @@ class Opt:
   14.81              print '\tDefault', self.default or 'None'
   14.82  
   14.83      def specify(self, k, v):
   14.84 +        """Specify the option. Called when the option is set
   14.85 +        from the command line.
   14.86 +
   14.87 +        k  option switch used
   14.88 +        v  optional value given (if any)
   14.89 +        """
   14.90          if k in self.optkeys:
   14.91              if self.val is None and v:
   14.92                  self.opts.err("Option '%s' does not take a value" % k)
   14.93 @@ -80,52 +121,113 @@ class Opt:
   14.94              return 0
   14.95  
   14.96      def specified(self):
   14.97 +        """Test whether the option has been specified: set
   14.98 +        from the command line.
   14.99 +        """
  14.100          return self.specified_opt
  14.101  
  14.102 +class OptVals:
  14.103 +    """Class to hold option values.
  14.104 +    """
  14.105 +    pass
  14.106 +
  14.107  class Opts:
  14.108 +    """Container for options.
  14.109 +    """
  14.110      def __init__(self, use=None):
  14.111 -        self._usage = use
  14.112 -        self._options = []
  14.113 -        self._options_map = {}
  14.114 -        self._argv = []
  14.115 -        self._vals = {}
  14.116 -        self._globals = {}
  14.117 -        self._locals = {}
  14.118 -        self.quiet = 0
  14.119 +        """Options constructor.
  14.120 +
  14.121 +        use  usage string
  14.122 +        """
  14.123 +        self.use = use
  14.124 +        # List of options.
  14.125 +        self.options = []
  14.126 +        # Options indexed by name.
  14.127 +        self.options_map = {}
  14.128 +        # Command-line arguments.
  14.129 +        self.argv = []
  14.130 +        # Option values.
  14.131 +        self.vals = OptVals()
  14.132 +        self.vals.quiet = 0
  14.133 +        # Variables for default scripts.
  14.134 +        self.vars = {}
  14.135 +
  14.136 +    def __repr__(self):
  14.137 +        return '\n'.join(map(str, self.options))
  14.138 +
  14.139 +    __str__ = __repr__
  14.140  
  14.141      def opt(self, name, **args):
  14.142 +        """Add an option.
  14.143 +
  14.144 +        name    option name
  14.145 +        **args  keyword params for option constructor
  14.146 +        """
  14.147          x = Opt(self, name, **args)
  14.148 -        self._options.append(x)
  14.149 -        self._options_map[name] = x
  14.150 +        self.options.append(x)
  14.151 +        self.options_map[name] = x
  14.152          return x
  14.153  
  14.154 +    def setvar(self, var, val):
  14.155 +        """Set a default script variable.
  14.156 +        """
  14.157 +        self.vars[var] = val
  14.158 +
  14.159 +    def getvar(self, var):
  14.160 +        """Get a default script variable.
  14.161 +        """
  14.162 +        return self.vars.get(var)
  14.163 +
  14.164 +    def option(self, name):
  14.165 +        """Get an option (object).
  14.166 +        """
  14.167 +        return self.options_map.get(name)
  14.168 +
  14.169 +    def setopt(self, name, val):
  14.170 +        """Set an option value.
  14.171 +        An option can also be set using 'opts.vals.name = val'.
  14.172 +        """
  14.173 +        setattr(self.vals, name, val)
  14.174 +
  14.175      def getopt(self, name):
  14.176 -        return self._options_map.get(name)
  14.177 +        """Get an option value.
  14.178 +        An option value can also be got using 'opts.vals.name'.
  14.179 +        """
  14.180 +        getattr(self.vals, name)
  14.181  
  14.182      def specified(self, name):
  14.183 -        opt = self.getopt(name)
  14.184 +        """Test if an option has been specified.
  14.185 +        """
  14.186 +        opt = self.option(name)
  14.187          return opt and opt.specified()
  14.188  
  14.189 -    def setvar(self, name, val):
  14.190 -        self._globals[name] = val
  14.191 -
  14.192      def err(self, msg):
  14.193 +        """Print an error to stderr and exit.
  14.194 +        """
  14.195          print >>sys.stderr, "Error:", msg
  14.196          sys.exit(1)
  14.197  
  14.198      def info(self, msg):
  14.199 -        if self.quiet: return
  14.200 +        """Print a message to stdout (unless quiet is set).
  14.201 +        """
  14.202 +        if self.vals.quiet: return
  14.203          print msg
  14.204  
  14.205      def warn(self, msg):
  14.206 +        """Print a warning to stdout.
  14.207 +        """
  14.208          print >>sys.stderr, "Warning:", msg
  14.209  
  14.210      def parse(self, argv):
  14.211 -        self._argv = argv
  14.212 +        """Parse arguments argv using the options.
  14.213 +
  14.214 +        return remaining arguments
  14.215 +        """
  14.216 +        self.argv = argv
  14.217          (vals, args) = getopt(argv[1:], self.short_opts(), self.long_opts())
  14.218 -        self._args = args
  14.219 +        self.args = args
  14.220          for (k, v) in vals:
  14.221 -            for opt in self._options:
  14.222 +            for opt in self.options:
  14.223                  if opt.specify(k, v): break
  14.224              else:
  14.225                  print >>sys.stderr, "Error: Unknown option:", k
  14.226 @@ -133,63 +235,92 @@ class Opts:
  14.227          return args
  14.228  
  14.229      def short_opts(self):
  14.230 +        """Get short options specifier for getopt.
  14.231 +        """
  14.232          l = []
  14.233 -        for x in self._options:
  14.234 +        for x in self.options:
  14.235              y = x.short_opt()
  14.236              if not y: continue
  14.237              l.append(y)
  14.238          return ''.join(l)
  14.239  
  14.240      def long_opts(self):
  14.241 +        """Get long options specifier for getopt.
  14.242 +        """
  14.243          l = []
  14.244 -        for x in self._options:
  14.245 +        for x in self.options:
  14.246              y = x.long_opt()
  14.247              if not y: continue
  14.248              l.append(y)
  14.249 -        return ''.join(l)
  14.250 +        return l
  14.251  
  14.252      def usage(self):
  14.253 -        print 'Usage: ', self._argv[0], self._usage or 'OPTIONS'
  14.254 -        for opt in self._options:
  14.255 +        print 'Usage: ', self.argv[0], self.use or 'OPTIONS'
  14.256 +        for opt in self.options:
  14.257              opt.show()
  14.258  
  14.259      def load_defaults(self):
  14.260 -        for x in [ '' ] + self.path.split(':'):
  14.261 +        """Load a defaults script. Assumes these options set:
  14.262 +        'path'    search path
  14.263 +        'default' script name
  14.264 +        """
  14.265 +        for x in [ '' ] + self.vals.path.split(':'):
  14.266              if x:
  14.267 -                p = os.path.join(x, self.defaults)
  14.268 +                p = os.path.join(x, self.vals.defaults)
  14.269              else:
  14.270 -                p = self.defaults
  14.271 +                p = self.vals.defaults
  14.272              if os.path.exists(p):
  14.273                  self.load(p)
  14.274                  break
  14.275          else:
  14.276              self.err("Cannot open defaults file %s" % self.defaults)
  14.277  
  14.278 -    def load(self, defaults):
  14.279 -        self._globals['sys'] = sys
  14.280 -        self._globals['config_file'] = defaults
  14.281 -        execfile(defaults, self._globals, self._locals)
  14.282 +    def load(self, defaults, help=0):
  14.283 +        """Load a defaults file. Local variables in the file
  14.284 +        are used to set options with the same names.
  14.285 +        Variables are not used to set options that are already specified.
  14.286 +        """
  14.287 +        # Create global and lobal dicts for the file.
  14.288 +        # Initialize locals to the vars.
  14.289 +        # Use exec to do the standard imports and
  14.290 +        # define variables we are passing to the script.
  14.291 +        globals = {}
  14.292 +        locals = {}
  14.293 +        locals.update(self.vars)
  14.294 +        cmd = '\n'.join(["import sys",
  14.295 +                         "import os",
  14.296 +                         "import os.path",
  14.297 +                         "xm_file = '%s'" % defaults,
  14.298 +                         "xm_help = %d" % help ])
  14.299 +        exec cmd in globals, locals
  14.300 +        execfile(defaults, globals, locals)
  14.301 +        if help: return
  14.302 +        # Extract the values set by the script and set the corresponding
  14.303 +        # options, if not set on the command line.
  14.304          vtypes = [ types.StringType,
  14.305                     types.ListType,
  14.306                     types.IntType,
  14.307                     types.FloatType
  14.308                     ]
  14.309 -        for (k, v) in self._locals.items():
  14.310 +        for (k, v) in locals.items():
  14.311              if self.specified(k): continue
  14.312              if not(type(v) in vtypes): continue
  14.313 -            print 'SET ', k, v
  14.314 -            setattr(self, k, v)
  14.315 +            self.setopt(k, v)
  14.316  
  14.317  def set_true(opt, k, v):
  14.318 +    """Set an option true."""
  14.319      opt.set(1)
  14.320  
  14.321  def set_false(opt, k, v):
  14.322 +    """Set an option false."""
  14.323      opt.set(0)
  14.324  
  14.325  def set_value(opt, k, v):
  14.326 +    """Set an option to a valoue."""
  14.327      opt.set(v)
  14.328  
  14.329  def set_int(opt, k, v):
  14.330 +    """Set an option to an integer value."""
  14.331      try:
  14.332          v = int(v)
  14.333      except:
  14.334 @@ -197,4 +328,12 @@ def set_int(opt, k, v):
  14.335      opt.set(v)
  14.336  
  14.337  def append_value(opt, k, v):
  14.338 +    """Append a value to a list option."""
  14.339      opt.append(v)
  14.340 +
  14.341 +def set_var(opt, k, v):
  14.342 +    """Set a default script variable.
  14.343 +    """
  14.344 +    (var, val) = v.strip().split('=')
  14.345 +    opt.opts.setvar(var.strip(), val.strip())
  14.346 +
    15.1 --- a/tools/xenmgr/lib/xm/shutdown.py	Thu Jun 24 10:28:58 2004 +0000
    15.2 +++ b/tools/xenmgr/lib/xm/shutdown.py	Thu Jun 24 12:00:50 2004 +0000
    15.3 @@ -1,3 +1,6 @@
    15.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    15.5 +"""Domain shutdown.
    15.6 +"""
    15.7  import string
    15.8  import sys
    15.9  import time