direct-io.hg

changeset 1673:93d9954ab06c

bitkeeper revision 1.1041.5.5 (40e97f82YUOF-rGuIapKOE73WUHZcg)

Add control over domain restart on shutdown.
author mjw@wray-m-3.hpl.hp.com
date Mon Jul 05 16:19:14 2004 +0000 (2004-07-05)
parents 025e093088ad
children d3666e462d59
files tools/examples/xmdefaults tools/examples/xmnetbsd tools/python/xen/xend/XendClient.py tools/python/xen/xend/XendDomain.py tools/python/xen/xend/XendDomainInfo.py tools/python/xen/xend/server/SrvDomain.py tools/python/xen/xm/create.py tools/python/xen/xm/shutdown.py
line diff
     1.1 --- a/tools/examples/xmdefaults	Mon Jul 05 08:29:44 2004 +0000
     1.2 +++ b/tools/examples/xmdefaults	Mon Jul 05 16:19:14 2004 +0000
     1.3 @@ -2,7 +2,6 @@
     1.4  #============================================================================
     1.5  # Python defaults setup for 'xm create'.
     1.6  # Edit this file to reflect the configuration of your system.
     1.7 -
     1.8  #============================================================================
     1.9  
    1.10  # Define script variables here.
    1.11 @@ -94,6 +93,6 @@ extra = "4 VMID=%d usr=/dev/sda6" % vmid
    1.12  #----------------------------------------------------------------------------
    1.13  # Set according to whether you want the domain  restarted when it exits.
    1.14  # The default is False.
    1.15 -#restart = True
    1.16 +#autorestart = True
    1.17  
    1.18  #============================================================================
     2.1 --- a/tools/examples/xmnetbsd	Mon Jul 05 08:29:44 2004 +0000
     2.2 +++ b/tools/examples/xmnetbsd	Mon Jul 05 16:19:14 2004 +0000
     2.3 @@ -2,24 +2,23 @@
     2.4  #============================================================================
     2.5  # Python defaults setup for 'xm create'.
     2.6  # Edit this file to reflect the configuration of your system.
     2.7 -# This file expects the variable 'vmid' to be set.
     2.8  #============================================================================
     2.9  
    2.10 -def config_usage ():
    2.11 -    print >>sys.stderr,"""
    2.12 -The config file '%s' requires the following variable to be defined:
    2.13 - vmid             -- Numeric identifier for the new domain, used to calculate
    2.14 -                     the VM's IP address and root partition. E.g. -Dvmid=1
    2.15 -""" % config_file
    2.16 -
    2.17 +# Define script variables here.
    2.18 +# xm_vars is defined automatically, use xm_vars.var() to define a variable.
    2.19  
    2.20 -try:
    2.21 -    vmid = int(vmid) # convert to integer
    2.22 -except:
    2.23 -    raise ValueError, "Variable 'vmid' must be an integer"
    2.24 +def vmid_check(var, val):
    2.25 +    val = int(val)
    2.26 +    if val <= 0:
    2.27 +        raise ValueError
    2.28 +    return val
    2.29 +    
    2.30 +xm_vars.var('vmid',
    2.31 +            use="Virtual machine id. Integer greater than 0.",
    2.32 +            check=vmid_check)
    2.33  
    2.34 -if vmid <= 0:
    2.35 -    raise ValueError, "Variable 'vmid' must be greater than 0" 
    2.36 +# This checks the script variables.
    2.37 +xm_vars.check()
    2.38  
    2.39  #----------------------------------------------------------------------------
    2.40  # Kernel image file.
    2.41 @@ -97,6 +96,6 @@ extra = "4 VMID=%d bootdev=xennet0" % vm
    2.42  #----------------------------------------------------------------------------
    2.43  # Set according to whether you want the domain  restarted when it exits.
    2.44  # The default is False.
    2.45 -#restart = True
    2.46 +#autorestart = True
    2.47  
    2.48  #============================================================================
     3.1 --- a/tools/python/xen/xend/XendClient.py	Mon Jul 05 08:29:44 2004 +0000
     3.2 +++ b/tools/python/xen/xend/XendClient.py	Mon Jul 05 16:19:14 2004 +0000
     3.3 @@ -225,9 +225,10 @@ class Xend:
     3.4          return xend_call(self.domainurl(id),
     3.5                           {'op'      : 'pause'})
     3.6  
     3.7 -    def xend_domain_shutdown(self, id):
     3.8 +    def xend_domain_shutdown(self, id, reason):
     3.9          return xend_call(self.domainurl(id),
    3.10 -                         {'op'      : 'shutdown'})
    3.11 +                         {'op'      : 'shutdown',
    3.12 +                          'reason'  : reason })
    3.13  
    3.14      def xend_domain_destroy(self, id):
    3.15          return xend_call(self.domainurl(id),
     4.1 --- a/tools/python/xen/xend/XendDomain.py	Mon Jul 05 08:29:44 2004 +0000
     4.2 +++ b/tools/python/xen/xend/XendDomain.py	Mon Jul 05 16:19:14 2004 +0000
     4.3 @@ -5,8 +5,10 @@
     4.4   Needs to be persistent for one uptime.
     4.5  """
     4.6  import sys
     4.7 +import traceback
     4.8  
     4.9  from twisted.internet import defer
    4.10 +from twisted.internet import reactor
    4.11  
    4.12  import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
    4.13  
    4.14 @@ -28,10 +30,19 @@ eserver = EventServer.instance()
    4.15  class XendDomain:
    4.16      """Index of all domains. Singleton.
    4.17      """
    4.18 -    
    4.19 +
    4.20 +    """Path to domain database."""
    4.21      dbpath = "domain"
    4.22 +
    4.23 +    """Table of domain info indexed by domain id."""
    4.24      domain = {}
    4.25      
    4.26 +    """Table of configs for domain restart, indexed by domain id."""
    4.27 +    restarts = {}
    4.28 +
    4.29 +    """Table of delayed calls."""
    4.30 +    schedule = {}
    4.31 +    
    4.32      def __init__(self):
    4.33          self.xconsole = XendConsole.instance()
    4.34          # Table of domain info indexed by domain id.
    4.35 @@ -49,6 +60,53 @@ class XendDomain:
    4.36          print 'XendDomain> virq', val
    4.37          self.reap()
    4.38  
    4.39 +    def schedule_later(self, _delay, _name, _fn, *args):
    4.40 +        """Schedule a function to be called later (if not already scheduled).
    4.41 +
    4.42 +        _delay delay in seconds
    4.43 +        _name  schedule name
    4.44 +        _fn    function
    4.45 +        args   arguments
    4.46 +        """
    4.47 +        if self.schedule.get(_name): return
    4.48 +        self.schedule[_name] = reactor.callLater(_delay, _fn, *args)
    4.49 +        
    4.50 +    def schedule_cancel(self, name):
    4.51 +        """Cancel a scheduled function call.
    4.52 +        
    4.53 +        name schedule name to cancel
    4.54 +        """
    4.55 +        callid = self.schedule.get(name)
    4.56 +        if not callid:
    4.57 +            return
    4.58 +        if callid.active():
    4.59 +            callid.cancel()
    4.60 +        del self.schedule[name]
    4.61 +
    4.62 +    def reap_schedule(self, delay=0):
    4.63 +        """Schedule reap to be called later.
    4.64 +
    4.65 +        delay delay in seconds
    4.66 +        """
    4.67 +        self.schedule_later(delay, 'reap', self.reap)
    4.68 +
    4.69 +    def reap_cancel(self):
    4.70 +        """Cancel any scheduled reap.
    4.71 +        """
    4.72 +        self.schedule_cancel('reap')
    4.73 +
    4.74 +    def refresh_schedule(self, delay=0):
    4.75 +        """Schedule refresh to be called later.
    4.76 +        
    4.77 +        delay delay in seconds
    4.78 +        """
    4.79 +        self.schedule_later(delay, 'refresh', self.refresh)
    4.80 +
    4.81 +    def refresh_cancel(self):
    4.82 +        """Cancel any scheduled refresh.
    4.83 +        """
    4.84 +        self.schedule_cancel('refresh')
    4.85 +
    4.86      def rm_all(self):
    4.87          """Remove all domain info. Used after reboot.
    4.88          """
    4.89 @@ -145,6 +203,7 @@ class XendDomain:
    4.90          """Look for domains that have crashed or stopped.
    4.91          Tidy them up.
    4.92          """
    4.93 +        self.reap_cancel()
    4.94          print 'XendDomain>reap>'
    4.95          domlist = xc.domain_getinfo()
    4.96          casualties = []
    4.97 @@ -158,12 +217,14 @@ class XendDomain:
    4.98          for d in casualties:
    4.99              id = str(d['dom'])
   4.100              print 'XendDomain>reap> died id=', id, d
   4.101 -            self.domain_destroy(id, refresh=0)
   4.102 +            self.final_domain_destroy(id)
   4.103          print 'XendDomain>reap<'
   4.104  
   4.105      def refresh(self):
   4.106          """Refresh domain list from Xen.
   4.107          """
   4.108 +        self.refresh_cancel()
   4.109 +        print 'XendDomain>refresh>'
   4.110          domlist = xc.domain_getinfo()
   4.111          # Index the domlist by id.
   4.112          # Add entries for any domains we don't know about.
   4.113 @@ -184,7 +245,7 @@ class XendDomain:
   4.114                  d.update(dominfo)
   4.115              else:
   4.116                  self._delete_domain(d.id)
   4.117 -        self.reap()
   4.118 +        self.reap_schedule(1)
   4.119  
   4.120      def refresh_domain(self, id):
   4.121          """Refresh information for a single domain.
   4.122 @@ -267,21 +328,70 @@ class XendDomain:
   4.123          """Shutdown domain (nicely).
   4.124  
   4.125          id     domain id
   4.126 -        reason shutdown type: poweroff, reboot, halt
   4.127 +        reason shutdown type: poweroff, reboot, suspend, halt
   4.128          """
   4.129          dom = int(id)
   4.130          if dom <= 0:
   4.131              return 0
   4.132 +        self.domain_restart_schedule(id, reason)
   4.133          eserver.inject('xend.domain.shutdown', [id, reason])
   4.134 +        if reason == 'halt':
   4.135 +            reason = 'poweroff'
   4.136          val = xend.domain_shutdown(dom, reason)
   4.137 -        self.refresh()
   4.138 +        self.refresh_schedule()
   4.139          return val
   4.140 -    
   4.141 -    def domain_destroy(self, id, refresh=1):
   4.142 -        """Terminate domain immediately.
   4.143 +
   4.144 +    def domain_restart_schedule(self, id, reason):
   4.145 +        """Schedule a restart for a domain if it needs one.
   4.146 +
   4.147 +        id     domain id
   4.148 +        reason shutdown reason
   4.149 +        """
   4.150 +        if id in self.restarts:
   4.151 +            # Don't schedule if already there.
   4.152 +            return
   4.153 +        restart = 0
   4.154 +        if reason in ['poweroff', 'reboot']:
   4.155 +            dominfo = self.domain.get(id)
   4.156 +            if dominfo and (dominfo.autorestart or reason == 'reboot'):
   4.157 +                restart = 1
   4.158 +                # Clear autorestart flag to avoid multiple restarts.
   4.159 +                dominfo.autorestart = 0
   4.160 +            
   4.161 +        if restart:
   4.162 +            self.restarts[id] = dominfo.config
   4.163 +            
   4.164 +    def domain_restart_cancel(self, id):
   4.165 +        """Cancel any restart scheduled for a domain.
   4.166  
   4.167          id domain id
   4.168 -        refresh send a domain destroy event if true
   4.169 +        """
   4.170 +        dominfo = self.domain.get(id)
   4.171 +        if dominfo:
   4.172 +            dominfo.autorestart = 0
   4.173 +        if id in self.restarts:
   4.174 +            del self.restarts[id]
   4.175 +
   4.176 +    def domain_restarts(self):
   4.177 +        """Execute any scheduled domain restarts for domains that have gone.
   4.178 +        """
   4.179 +        for id in self.restarts.keys():
   4.180 +            if id in self.domain:
   4.181 +                # Don't execute restart for domains still running.
   4.182 +                continue
   4.183 +            config = self.restarts[id]
   4.184 +            # Remove it from the restarts.
   4.185 +            del self.restarts[id]
   4.186 +            try:
   4.187 +                self.domain_create(config)
   4.188 +            except:
   4.189 +                print >>sys.stderr, "XendDomain> Exception restarting domain"
   4.190 +                traceback.print_exc(sys.stderr)
   4.191 +        
   4.192 +    def final_domain_destroy(self, id):
   4.193 +        """Final destruction of a domain..
   4.194 +
   4.195 +        id domain id
   4.196          """
   4.197          dom = int(id)
   4.198          if dom <= 0:
   4.199 @@ -292,15 +402,26 @@ class XendDomain:
   4.200              val = dominfo.destroy()
   4.201          else:
   4.202              val = xc.domain_destroy(dom=dom)
   4.203 -        if refresh: self.refresh()
   4.204          return val       
   4.205  
   4.206 +    def domain_destroy(self, id):
   4.207 +        """Terminate domain immediately.
   4.208 +        Camcels any restart for the domain.
   4.209 +
   4.210 +        id domain id
   4.211 +        """
   4.212 +        self.domain_restart_cancel(id)
   4.213 +        val = self.final_domain_destroy(id)
   4.214 +        self.refresh_schedule()
   4.215 +        return val
   4.216 +
   4.217      def domain_migrate(self, id, dst):
   4.218          """Start domain migration.
   4.219  
   4.220          id domain id
   4.221          """
   4.222          # Need a cancel too?
   4.223 +        # Don't forget to cancel restart for it.
   4.224          pass
   4.225  
   4.226      def domain_save(self, id, dst, progress=0):
     5.1 --- a/tools/python/xen/xend/XendDomainInfo.py	Mon Jul 05 08:29:44 2004 +0000
     5.2 +++ b/tools/python/xen/xend/XendDomainInfo.py	Mon Jul 05 16:19:14 2004 +0000
     5.3 @@ -362,6 +362,8 @@ class XendDomainInfo:
     5.4          self.state = self.STATE_OK
     5.5          #todo: set to migrate info if migrating
     5.6          self.migrate = None
     5.7 +        #Whether to auto-restart
     5.8 +        self.autorestart = 0
     5.9  
    5.10      def setdom(self, dom):
    5.11          self.dom = int(dom)
    5.12 @@ -418,6 +420,8 @@ class XendDomainInfo:
    5.13          try:
    5.14              self.name = sxp.child_value(config, 'name')
    5.15              self.memory = int(sxp.child_value(config, 'memory', '128'))
    5.16 +            if sxp.child(config, 'autorestart', None):
    5.17 +                self.autorestart = 1
    5.18              self.configure_backends()
    5.19              image = sxp.child_value(config, 'image')
    5.20              image_name = sxp.name(image)
     6.1 --- a/tools/python/xen/xend/server/SrvDomain.py	Mon Jul 05 08:29:44 2004 +0000
     6.2 +++ b/tools/python/xen/xend/server/SrvDomain.py	Mon Jul 05 16:19:14 2004 +0000
     6.3 @@ -27,7 +27,11 @@ class SrvDomain(SrvDir):
     6.4          return val
     6.5  
     6.6      def op_shutdown(self, op, req):
     6.7 -        val = self.xd.domain_shutdown(self.dom.id)
     6.8 +        #val = self.xd.domain_shutdown(self.dom.id)
     6.9 +        fn = FormFn(self.xd.domain_shutdown,
    6.10 +                    [['dom', 'int'],
    6.11 +                     ['reason', 'str']])
    6.12 +        val = fn(req.args, {'dom': self.dom.id})
    6.13          req.setResponseCode(202)
    6.14          req.setHeader("Location", "%s/.." % req.prePathURL())
    6.15          return val
     7.1 --- a/tools/python/xen/xm/create.py	Mon Jul 05 08:29:44 2004 +0000
     7.2 +++ b/tools/python/xen/xm/create.py	Mon Jul 05 16:19:14 2004 +0000
     7.3 @@ -101,6 +101,10 @@ gopts.opt('memory', short='m', val='MEMO
     7.4           fn=set_value, default=128,
     7.5           use="Domain memory in MB.")
     7.6  
     7.7 +gopts.opt('autorestart',
     7.8 +         fn=set_true, default=0,
     7.9 +         use="Whether to restart the domain on exit.")
    7.10 +
    7.11  gopts.opt('blkif',
    7.12            fn=set_true, default=0,
    7.13            use="Make the domain a block device backend.")
    7.14 @@ -271,6 +275,8 @@ def make_config(opts):
    7.15          config.append(['backend', ['blkif']])
    7.16      if opts.netif:
    7.17          config.append(['backend', ['netif']])
    7.18 +    if opts.autorestart:
    7.19 +        config.append(['autorestart'])
    7.20      
    7.21      configure_image(config, opts)
    7.22      config_devs = []
     8.1 --- a/tools/python/xen/xm/shutdown.py	Mon Jul 05 08:29:44 2004 +0000
     8.2 +++ b/tools/python/xen/xm/shutdown.py	Mon Jul 05 16:19:14 2004 +0000
     8.3 @@ -1,4 +1,5 @@
     8.4  # Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
     8.5 +
     8.6  """Domain shutdown.
     8.7  """
     8.8  import string
     8.9 @@ -10,7 +11,8 @@ from xen.xm.opts import *
    8.10  
    8.11  gopts = Opts(use="""[options] [DOM]
    8.12  
    8.13 -Shutdown one or more domains gracefully.""")
    8.14 +Shutdown one or more domains gracefully.
    8.15 +""")
    8.16  
    8.17  gopts.opt('help', short='h',
    8.18           fn=set_true, default=0,
    8.19 @@ -24,18 +26,22 @@ gopts.opt('wait', short='w',
    8.20           fn=set_true, default=0,
    8.21           use='Wait for shutdown to complete.')
    8.22  
    8.23 -gopts.opt('norestart', short='n',
    8.24 +gopts.opt('halt', short='H',
    8.25            fn=set_true, default=0,
    8.26 -          use='Prevent domain restart.')
    8.27 +          use='Shutdown without reboot.')
    8.28  
    8.29 -def shutdown(opts, doms, wait):
    8.30 +gopts.opt('reboot', short='R',
    8.31 +          fn=set_true, default=0,
    8.32 +          use='Shutdown and reboot.')
    8.33 +
    8.34 +def shutdown(opts, doms, mode, wait):
    8.35      def domains():
    8.36          return [ int(a) for a in server.xend_domains() ]
    8.37      if doms == None: doms = domains()
    8.38      if 0 in doms:
    8.39          doms.remove(0)
    8.40      for d in doms:
    8.41 -        server.xend_domain_shutdown(d)
    8.42 +        server.xend_domain_shutdown(d, mode)
    8.43      if wait:
    8.44          while doms:
    8.45              alive = domains()
    8.46 @@ -49,6 +55,21 @@ def shutdown(opts, doms, wait):
    8.47              time.sleep(1)
    8.48          opts.info("All domains terminated")
    8.49  
    8.50 +def shutdown_mode(opts):
    8.51 +    mode = 'poweroff'
    8.52 +    if opts.vals.wait:
    8.53 +        mode = 'halt'
    8.54 +        if opts.vals.reboot:
    8.55 +           opts.err("Can't specify wait and reboot") 
    8.56 +    else:
    8.57 +        if opts.vals.halt and opts.vals.reboot:
    8.58 +            opts.err("Can't specify halt and reboot")
    8.59 +        if opts.vals.halt:
    8.60 +            mode = 'halt'
    8.61 +        elif opts.vals.reboot:
    8.62 +            mode = 'reboot'
    8.63 +    return mode
    8.64 +
    8.65  def main_all(opts, args):
    8.66      shutdown(opts, None, opts.vals.wait)
    8.67  
    8.68 @@ -59,7 +80,9 @@ def main_dom(opts, args):
    8.69          domid = int(dom)
    8.70      except:
    8.71          opts.err('Invalid domain: ' + dom)
    8.72 -    shutdown(opts, [ domid ], opts.vals.wait)
    8.73 +        
    8.74 +    mode = shutdown_mode(opts)  
    8.75 +    shutdown(opts, [ domid ], mode, opts.vals.wait)
    8.76      
    8.77  def main(argv):
    8.78      opts = gopts