ia64/xen-unstable

changeset 1893:a50fb088d983

bitkeeper revision 1.1108.1.17 (410130f82d--8rFf_j0nL2KMhoKYvg)

Make rebooting a domain use the same domain id and console,
without disconnecting any connected console.
author mjw@wray-m-3.hpl.hp.com
date Fri Jul 23 15:38:32 2004 +0000 (2004-07-23)
parents de62fd103f99
children a66ccef56a68
files tools/python/xen/xend/XendConsole.py tools/python/xen/xend/XendDomain.py tools/python/xen/xend/XendDomainInfo.py tools/python/xen/xend/server/SrvConsole.py tools/python/xen/xend/server/SrvConsoleDir.py tools/python/xen/xend/server/SrvDaemon.py tools/python/xen/xend/server/SrvDomain.py tools/python/xen/xend/server/console.py tools/python/xen/xend/server/controller.py tools/python/xen/xm/create.py
line diff
     1.1 --- a/tools/python/xen/xend/XendConsole.py	Fri Jul 23 13:10:03 2004 +0000
     1.2 +++ b/tools/python/xen/xend/XendConsole.py	Fri Jul 23 15:38:32 2004 +0000
     1.3 @@ -8,6 +8,7 @@ import sxp
     1.4  import XendRoot
     1.5  xroot = XendRoot.instance()
     1.6  import XendDB
     1.7 +from XendError import XendError
     1.8  
     1.9  import EventServer
    1.10  eserver = EventServer.instance()
    1.11 @@ -15,160 +16,38 @@ eserver = EventServer.instance()
    1.12  from xen.xend.server import SrvDaemon
    1.13  daemon = SrvDaemon.instance()
    1.14  
    1.15 -class XendConsoleInfo:
    1.16 -    """Console information record.
    1.17 -    """
    1.18 -
    1.19 -    def __init__(self, console, dom1, port1, dom2, port2, conn=None):
    1.20 -        self.console = console
    1.21 -        self.dom1  = int(dom1)
    1.22 -        self.port1 = int(port1)
    1.23 -        self.dom2  = int(dom2)
    1.24 -        self.port2 = int(port2)
    1.25 -        self.conn  = conn
    1.26 -        #self.id = "%d.%d-%d.%d" % (self.dom1, self.port1, self.dom2, self.port2)
    1.27 -        self.id = str(port1)
    1.28 -
    1.29 -    def __str__(self):
    1.30 -        s = "console"
    1.31 -        s += " id=%s" % self.id
    1.32 -        s += " src=%d.%d" % (self.dom1, self.port1)
    1.33 -        s += " dst=%d.%d" % (self.dom2, self.port2)
    1.34 -        s += " port=%s" % self.console
    1.35 -        if self.conn:
    1.36 -            s += " conn=%s:%s" % (self.conn[0], self.conn[1])
    1.37 -        return s
    1.38 -
    1.39 -    def sxpr(self):
    1.40 -        sxpr = ['console',
    1.41 -                ['id', self.id],
    1.42 -                ['src', self.dom1, self.port1],
    1.43 -                ['dst', self.dom2, self.port2],
    1.44 -                ['port', self.console],
    1.45 -                ]
    1.46 -        if self.conn:
    1.47 -            sxpr.append(['connected', self.conn[0], self.conn[1]])
    1.48 -        return sxpr
    1.49 -
    1.50 -    def connection(self):
    1.51 -        return self.conn
    1.52 -
    1.53 -    def update(self, consinfo):
    1.54 -        conn = sxp.child(consinfo, 'connected')
    1.55 -        if conn:
    1.56 -            self.conn = conn[1:]
    1.57 -        else:
    1.58 -            self.conn = None
    1.59 -
    1.60 -    def uri(self):
    1.61 -        """Get the uri to use to connect to the console.
    1.62 -        This will be a telnet: uri.
    1.63 -
    1.64 -        return uri
    1.65 -        """
    1.66 -        host = socket.gethostname()
    1.67 -        return "telnet://%s:%s" % (host, self.console)
    1.68 -
    1.69  class XendConsole:
    1.70  
    1.71 -    dbpath = "console"
    1.72 -
    1.73      def  __init__(self):
    1.74 -        self.db = XendDB.XendDB(self.dbpath)
    1.75 -        self.console = {}
    1.76 -        self.console_db = self.db.fetchall("")
    1.77 -        if xroot.get_rebooted():
    1.78 -            print 'XendConsole> rebooted: removing all console info'
    1.79 -            self.rm_all()
    1.80 +        pass
    1.81          eserver.subscribe('xend.domain.died', self.onDomainDied)
    1.82          eserver.subscribe('xend.domain.destroy', self.onDomainDied)
    1.83  
    1.84 -    def rm_all(self):
    1.85 -        """Remove all console info. Used after reboot.
    1.86 -        """
    1.87 -        for (k, v) in self.console_db.items():
    1.88 -            self._delete_console(k)
    1.89 -
    1.90 -    def refresh(self):
    1.91 -        consoles = daemon.consoles()
    1.92 -        cons = {}
    1.93 -        for consinfo in consoles:
    1.94 -            id = str(sxp.child_value(consinfo, 'id'))
    1.95 -            cons[id] = consinfo
    1.96 -            if id not in self.console:
    1.97 -                self._new_console(consinfo)
    1.98 -        for c in self.console.values():
    1.99 -            consinfo = cons.get(c.id)
   1.100 -            if consinfo:
   1.101 -                c.update(consinfo)
   1.102 -            else:
   1.103 -                self._delete_console(c.id)
   1.104 -
   1.105      def onDomainDied(self, event, val):
   1.106 -        dom = int(val)
   1.107 -        #print 'XendConsole>onDomainDied', 'event', event, "dom=", dom
   1.108 -        for c in self.consoles():
   1.109 -            #print 'onDomainDied', "dom=", dom, "dom1=", c.dom1, "dom2=", c.dom2
   1.110 -            if (c.dom1 == dom) or (c.dom2 == dom):
   1.111 -                'XendConsole>onDomainDied', 'delete console dom=', dom
   1.112 -                ctrl = daemon.get_domain_console(dom)
   1.113 -                if ctrl:
   1.114 -                    ctrl.close()
   1.115 -                self._delete_console(c.id)
   1.116 -
   1.117 -    def sync(self):
   1.118 -        self.db.saveall("", self.console_db)
   1.119 -
   1.120 -    def sync_console(self, id):
   1.121 -        self.db.save(id, self.console_db[id])
   1.122 -
   1.123 -    def _new_console(self, consinfo):
   1.124 -        # todo: xen needs a call to get current domain id.
   1.125 -        dom1 = 0
   1.126 -        port1 = sxp.child_value(consinfo, 'local_port')
   1.127 -        dom2 = sxp.child_value(consinfo, 'domain')
   1.128 -        port2 = sxp.child_value(consinfo, 'remote_port')
   1.129 -        console = sxp.child_value(consinfo, 'console_port')
   1.130 -        info = XendConsoleInfo(console, dom1, int(port1), int(dom2), int(port2))
   1.131 -        info.update(consinfo)
   1.132 -        self._add_console(info.id, info)
   1.133 -        return info
   1.134 -
   1.135 -    def _add_console(self, id, info):
   1.136 -        self.console[id] = info
   1.137 -        self.console_db[id] = info.sxpr()
   1.138 -        self.sync_console(id)
   1.139 -
   1.140 -    def _delete_console(self, id):
   1.141 -        if id in self.console:
   1.142 -            del self.console[id]
   1.143 -        if id in self.console_db:
   1.144 -            del self.console_db[id]
   1.145 -            self.db.delete(id)
   1.146 +        pass
   1.147  
   1.148      def console_ls(self):
   1.149 -        self.refresh()
   1.150 -        return self.console.keys()
   1.151 +        return [ c.console_port for c in self.consoles() ]
   1.152  
   1.153      def consoles(self):
   1.154 -        self.refresh()
   1.155 -        return self.console.values()
   1.156 +        return daemon.get_consoles()
   1.157      
   1.158      def console_create(self, dom, console_port=None):
   1.159          consinfo = daemon.console_create(dom, console_port=console_port)
   1.160 -        info = self._new_console(consinfo)
   1.161 -        return info
   1.162 +        return consinfo
   1.163      
   1.164      def console_get(self, id):
   1.165 -        self.refresh()
   1.166 -        return self.console.get(id)
   1.167 -
   1.168 -    def console_delete(self, id):
   1.169 -        self._delete_console(id)
   1.170 +        id = int(id)
   1.171 +        for c in self.consoles():
   1.172 +            if c.console_port == id:
   1.173 +                return c
   1.174 +        return None
   1.175  
   1.176      def console_disconnect(self, id):
   1.177 -        id = int(id)
   1.178 -        daemon.console_disconnect(id)
   1.179 +        console = self.console_get(id)
   1.180 +        if not console:
   1.181 +            raise XendError('Invalid console id')
   1.182 +        console.disconnect()
   1.183  
   1.184  def instance():
   1.185      global inst
     2.1 --- a/tools/python/xen/xend/XendDomain.py	Fri Jul 23 13:10:03 2004 +0000
     2.2 +++ b/tools/python/xen/xend/XendDomain.py	Fri Jul 23 15:38:32 2004 +0000
     2.3 @@ -18,7 +18,6 @@ import XendRoot
     2.4  xroot = XendRoot.instance()
     2.5  import XendDB
     2.6  import XendDomainInfo
     2.7 -import XendConsole
     2.8  import XendMigrate
     2.9  import EventServer
    2.10  from XendError import XendError
    2.11 @@ -42,14 +41,13 @@ class XendDomain:
    2.12      """Table of domain info indexed by domain id."""
    2.13      domain = {}
    2.14      
    2.15 -    """Table of configs for domain restart, indexed by domain id."""
    2.16 +    """Table of domains to restart, indexed by domain id."""
    2.17      restarts = {}
    2.18  
    2.19      """Table of delayed calls."""
    2.20      schedule = {}
    2.21      
    2.22      def __init__(self):
    2.23 -        self.xconsole = XendConsole.instance()
    2.24          # Table of domain info indexed by domain id.
    2.25          self.db = XendDB.XendDB(self.dbpath)
    2.26          self.domain_db = self.db.fetchall("")
    2.27 @@ -322,6 +320,19 @@ class XendDomain:
    2.28          deferred.addCallback(fn)
    2.29          return deferred
    2.30  
    2.31 +    def domain_restart(self, dominfo):
    2.32 +        """Restart a domain.
    2.33 +
    2.34 +        @param dominfo: domain object
    2.35 +        @return: deferred
    2.36 +        """
    2.37 +        deferred = dominfo.restart()
    2.38 +        def fn(dominfo):
    2.39 +            self._add_domain(dominfo.id, dominfo)
    2.40 +            return dominfo
    2.41 +        deferred.addCallback(fn)
    2.42 +        return deferred        
    2.43 +
    2.44      def domain_configure(self, id, config):
    2.45          """Configure an existing domain. This is intended for internal
    2.46          use by domain restore and migrate.
    2.47 @@ -405,7 +416,7 @@ class XendDomain:
    2.48          if reason == 'halt':
    2.49              self.domain_restart_cancel(id)
    2.50          else:
    2.51 -            self.domain_restart_schedule(id, reason, set=1)
    2.52 +            self.domain_restart_schedule(id, reason, force=1)
    2.53          eserver.inject('xend.domain.shutdown', [id, reason])
    2.54          if reason == 'halt':
    2.55              reason = 'poweroff'
    2.56 @@ -413,25 +424,22 @@ class XendDomain:
    2.57          self.refresh_schedule()
    2.58          return val
    2.59  
    2.60 -    def domain_restart_schedule(self, id, reason, set=0):
    2.61 +    def domain_restart_schedule(self, id, reason, force=0):
    2.62          """Schedule a restart for a domain if it needs one.
    2.63  
    2.64          @param id:     domain id
    2.65          @param reason: shutdown reason
    2.66          """
    2.67 -        log.debug('domain_restart_schedule> %s %s %d', id, reason, set)
    2.68 +        log.debug('domain_restart_schedule> %s %s %d', id, reason, force)
    2.69          dominfo = self.domain.get(id)
    2.70          if not dominfo:
    2.71              return
    2.72          if id in self.restarts:
    2.73              return
    2.74 -        if set and reason == 'reboot':
    2.75 -            dominfo.restart_mode = XendDomainInfo.RESTART_ALWAYS
    2.76 -        restart = dominfo.restart_needed(reason)
    2.77 +        restart = (force and reason == 'reboot') or dominfo.restart_needed(reason)
    2.78          if restart:
    2.79 -            # Avoid multiple restarts.
    2.80 -            dominfo.restart_mode = XendDomainInfo.RESTART_NEVER
    2.81 -            self.restarts[id] = dominfo.config
    2.82 +            dominfo.restarting()
    2.83 +            self.restarts[id] = dominfo
    2.84              log.info('Scheduling restart for domain: id=%s name=%s', id, dominfo.name)
    2.85              self.domain_restarts_schedule()
    2.86              
    2.87 @@ -440,10 +448,9 @@ class XendDomain:
    2.88  
    2.89          @param id: domain id
    2.90          """
    2.91 -        dominfo = self.domain.get(id)
    2.92 +        dominfo = self.restarts.get(id)
    2.93          if dominfo:
    2.94 -            dominfo.restart_mode = XendDomainInfo.RESTART_NEVER
    2.95 -        if id in self.restarts:
    2.96 +            dominfo.restart_cancel()
    2.97              del self.restarts[id]
    2.98  
    2.99      def domain_restarts(self):
   2.100 @@ -454,17 +461,17 @@ class XendDomain:
   2.101              if id in self.domain:
   2.102                  # Don't execute restart for domains still running.
   2.103                  continue
   2.104 -            config = self.restarts[id]
   2.105 +            dominfo = self.restarts[id]
   2.106              # Remove it from the restarts.
   2.107              del self.restarts[id]
   2.108              try:
   2.109 -                log.info('domain_restarts> restart: id=%s config=%s', id, str(config))
   2.110 +                log.info('domain_restarts> restart: id=%s config=%s', id, str(dominfo.config))
   2.111                  def cbok(dominfo):
   2.112                      log.info('Restarted domain %s as %s', id, dominfo.id)
   2.113                      self.domain_unpause(dominfo.id)
   2.114                  def cberr(err):
   2.115                      log.exception("Delayed exception restarting domain")
   2.116 -                deferred = self.domain_create(config)
   2.117 +                deferred = self.domain_restart(dominfo)
   2.118                  deferred.addCallback(cbok)
   2.119                  deferred.addErrback(cberr)
   2.120              except:
   2.121 @@ -500,7 +507,7 @@ class XendDomain:
   2.122          if reason == 'halt':
   2.123              self.domain_restart_cancel(id)
   2.124          elif reason == 'reboot':
   2.125 -            self.domain_restart_schedule(id, reason, set=1)
   2.126 +            self.domain_restart_schedule(id, reason, force=1)
   2.127          val = self.final_domain_destroy(id)
   2.128          self.refresh_schedule()
   2.129          return val
     3.1 --- a/tools/python/xen/xend/XendDomainInfo.py	Fri Jul 23 13:10:03 2004 +0000
     3.2 +++ b/tools/python/xen/xend/XendDomainInfo.py	Fri Jul 23 15:38:32 2004 +0000
     3.3 @@ -62,6 +62,9 @@ restart_modes = [
     3.4      RESTART_NEVER,
     3.5      ]
     3.6  
     3.7 +STATE_RESTART_PENDING = 'pending'
     3.8 +STATE_RESTART_BOOTING = 'booting'
     3.9 +
    3.10  def shutdown_reason(code):
    3.11      """Get a shutdown reason from a code.
    3.12  
    3.13 @@ -277,6 +280,7 @@ def vm_recreate(savedinfo, info):
    3.14      else:
    3.15          d = defer.Deferred()
    3.16          d.callback(vm)
    3.17 +    vm.recreate = 0
    3.18      return d
    3.19  
    3.20  def vm_restore(src, progress=0):
    3.21 @@ -360,8 +364,8 @@ class XendDomainInfo:
    3.22          self.state = self.STATE_OK
    3.23          #todo: set to migrate info if migrating
    3.24          self.migrate = None
    3.25 -        #Whether to auto-restart
    3.26          self.restart_mode = RESTART_ONREBOOT
    3.27 +        self.restart_state = None
    3.28          self.console_port = None
    3.29  
    3.30      def setdom(self, dom):
    3.31 @@ -380,7 +384,7 @@ class XendDomainInfo:
    3.32          s += " name=" + self.name
    3.33          s += " memory=" + str(self.memory)
    3.34          if self.console:
    3.35 -            s += " console=" + self.console.id
    3.36 +            s += " console=" + str(self.console.console_port)
    3.37          if self.image:
    3.38              s += " image=" + self.image
    3.39          s += ""
    3.40 @@ -536,6 +540,8 @@ class XendDomainInfo:
    3.41          devices have been released.
    3.42          """
    3.43          if self.dom is None: return 0
    3.44 +        if self.restart_state == STATE_RESTART_PENDING and self.console:
    3.45 +            self.console.deregisterChannel()
    3.46          chan = xend.getDomChannel(self.dom)
    3.47          if chan:
    3.48              log.debug("Closing channel to domain %d", self.dom)
    3.49 @@ -603,7 +609,8 @@ class XendDomainInfo:
    3.50          memory = self.memory
    3.51          name = self.name
    3.52          cpu = int(sxp.child_value(self.config, 'cpu', '-1'))
    3.53 -        dom = xc.domain_create(mem_kb= memory * 1024, name= name, cpu= cpu)
    3.54 +        dom = self.dom or 0
    3.55 +        dom = xc.domain_create(dom= dom, mem_kb= memory * 1024, name= name, cpu= cpu)
    3.56          if dom <= 0:
    3.57              raise VmError('Creating domain failed: name=%s memory=%d'
    3.58                            % (name, memory))
    3.59 @@ -627,7 +634,7 @@ class XendDomainInfo:
    3.60          if self.blkif_backend: flags |= SIF_BLK_BE_DOMAIN
    3.61          err = buildfn(dom            = dom,
    3.62                        image          = kernel,
    3.63 -                      control_evtchn = self.console.port2,
    3.64 +                      control_evtchn = self.console.getRemotePort(),
    3.65                        cmdline        = cmdline,
    3.66                        ramdisk        = ramdisk,
    3.67                        flags          = flags)
    3.68 @@ -650,7 +657,10 @@ class XendDomainInfo:
    3.69              if ramdisk and not os.path.isfile(ramdisk):
    3.70                  raise VmError('Kernel ramdisk does not exist: %s' % ramdisk)
    3.71          self.init_domain()
    3.72 -        self.console = xendConsole.console_create(self.dom, console_port=self.console_port)
    3.73 +        if self.console:
    3.74 +            self.console.registerChannel()
    3.75 +        else:
    3.76 +            self.console = xendConsole.console_create(self.dom, console_port=self.console_port)
    3.77          self.build_domain(ostype, kernel, ramdisk, cmdline, vifs_n)
    3.78          self.image = kernel
    3.79          self.ramdisk = ramdisk
    3.80 @@ -737,6 +747,20 @@ class XendDomainInfo:
    3.81              return reason == 'reboot'
    3.82          return 0
    3.83  
    3.84 +    def restart_cancel(self):
    3.85 +        self.restart_state = None
    3.86 +
    3.87 +    def restarting(self):
    3.88 +        self.restart_state = STATE_RESTART_PENDING
    3.89 +
    3.90 +    def restart(self):
    3.91 +        try:
    3.92 +            self.restart_state = STATE_RESTART_BOOTING
    3.93 +            d = self.construct(self.config)
    3.94 +        finally:
    3.95 +            self.restart_state = None
    3.96 +        return d
    3.97 +
    3.98      def configure_backends(self):
    3.99          """Set configuration flags if the vm is a backend for netif of blkif.
   3.100          """
     4.1 --- a/tools/python/xen/xend/server/SrvConsole.py	Fri Jul 23 13:10:03 2004 +0000
     4.2 +++ b/tools/python/xen/xend/server/SrvConsole.py	Fri Jul 23 15:38:32 2004 +0000
     4.3 @@ -14,7 +14,7 @@ class SrvConsole(SrvDir):
     4.4          self.xc = XendConsole.instance()
     4.5  
     4.6      def op_disconnect(self, op, req):
     4.7 -        val = self.xc.console_disconnect(self.info.id)
     4.8 +        val = self.xc.console_disconnect(self.info.console_port)
     4.9          return val
    4.10  
    4.11      def render_POST(self, req):
    4.12 @@ -31,7 +31,7 @@ class SrvConsole(SrvDir):
    4.13                  #self.ls()
    4.14                  req.write('<p>%s</p>' % self.info)
    4.15                  req.write('<p><a href="%s">Connect to domain %d</a></p>'
    4.16 -                          % (self.info.uri(), self.info.dom2))
    4.17 +                          % (self.info.uri(), self.info.dom))
    4.18                  self.form(req)
    4.19                  req.write('</body></html>')
    4.20              return ''
    4.21 @@ -40,6 +40,6 @@ class SrvConsole(SrvDir):
    4.22  
    4.23      def form(self, req):
    4.24          req.write('<form method="post" action="%s">' % req.prePathURL())
    4.25 -        if self.info.connection():
    4.26 +        if self.info.connected():
    4.27              req.write('<input type="submit" name="op" value="disconnect">')
    4.28          req.write('</form>')
     5.1 --- a/tools/python/xen/xend/server/SrvConsoleDir.py	Fri Jul 23 13:10:03 2004 +0000
     5.2 +++ b/tools/python/xen/xend/server/SrvConsoleDir.py	Fri Jul 23 15:38:32 2004 +0000
     5.3 @@ -55,8 +55,9 @@ class SrvConsoleDir(SrvDir):
     5.4              sxp.show(consoles, out=req)
     5.5          else:
     5.6              consoles = self.xconsole.consoles()
     5.7 -            consoles.sort(lambda x, y: cmp(x.id, y.id))
     5.8 +            consoles.sort(lambda x, y: cmp(x.console_port, y.console_port))
     5.9              req.write('<ul>')
    5.10              for c in consoles:
    5.11 -                req.write('<li><a href="%s%s"> %s</a></li>' % (url, c.id, c))
    5.12 +                cid = str(c.console_port)
    5.13 +                req.write('<li><a href="%s%s"> %s</a></li>' % (url, cid, cid))
    5.14              req.write('</ul>')
     6.1 --- a/tools/python/xen/xend/server/SrvDaemon.py	Fri Jul 23 13:10:03 2004 +0000
     6.2 +++ b/tools/python/xen/xend/server/SrvDaemon.py	Fri Jul 23 15:38:32 2004 +0000
     6.3 @@ -121,7 +121,7 @@ class MgmtProtocol(protocol.DatagramProt
     6.4          console_port = sxp.child_value(req, 'console_port')
     6.5          if console_port:
     6.6              console_port = int(console_port)
     6.7 -        resp = self.daemon.console_create(dom, console_port)
     6.8 +        resp = self.daemon.console_create(dom, console_port).sxpr()
     6.9          print name, resp
    6.10          return resp
    6.11  
    6.12 @@ -730,11 +730,14 @@ class Daemon:
    6.13          console = self.consoleCF.getInstanceByDom(dom)
    6.14          if console is None:
    6.15              console = self.consoleCF.createInstance(dom, console_port)
    6.16 -        return console.sxpr()
    6.17 +        return console
    6.18  
    6.19      def consoles(self):
    6.20          return [ c.sxpr() for c in self.consoleCF.getInstances() ]
    6.21  
    6.22 +    def get_consoles(self):
    6.23 +        return self.consoleCF.getInstances()
    6.24 +
    6.25      def get_console(self, id):
    6.26          return self.consoleCF.getInstance(id)
    6.27  
     7.1 --- a/tools/python/xen/xend/server/SrvDomain.py	Fri Jul 23 13:10:03 2004 +0000
     7.2 +++ b/tools/python/xen/xend/server/SrvDomain.py	Fri Jul 23 15:38:32 2004 +0000
     7.3 @@ -204,7 +204,7 @@ class SrvDomain(SrvDir):
     7.4              req.write('<p>%s</p>' % self.dom)
     7.5              if self.dom.console:
     7.6                  cinfo = self.dom.console
     7.7 -                cid = cinfo.id
     7.8 +                cid = str(cinfo.console_port)
     7.9                  #todo: Local xref: need to know server prefix.
    7.10                  req.write('<p><a href="/xend/console/%s">Console %s</a></p>'
    7.11                            % (cid, cid))
     8.1 --- a/tools/python/xen/xend/server/console.py	Fri Jul 23 13:10:03 2004 +0000
     8.2 +++ b/tools/python/xen/xend/server/console.py	Fri Jul 23 15:38:32 2004 +0000
     8.3 @@ -1,5 +1,7 @@
     8.4  # Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
     8.5  
     8.6 +import socket
     8.7 +
     8.8  from twisted.internet import reactor
     8.9  from twisted.internet import protocol
    8.10  
    8.11 @@ -124,17 +126,38 @@ class ConsoleController(controller.Contr
    8.12          self.listen()
    8.13  
    8.14      def sxpr(self):
    8.15 -        val =['console',
    8.16 -              ['status',       self.status ],
    8.17 -              ['id',           self.idx ],
    8.18 -              ['domain',       self.dom ],
    8.19 -              ['local_port',   self.channel.getLocalPort() ],
    8.20 -              ['remote_port',  self.channel.getRemotePort() ],
    8.21 -              ['console_port', self.console_port ] ]
    8.22 +        val = ['console',
    8.23 +               ['status', self.status ],
    8.24 +               ['id',     self.idx    ],
    8.25 +               ['domain', self.dom    ] ]
    8.26 +        val.append(['local_port',   self.getLocalPort()  ])
    8.27 +        val.append(['remote_port',  self.getRemotePort() ])
    8.28 +        val.append(['console_port', self.console_port    ])
    8.29          if self.addr:
    8.30              val.append(['connected', self.addr[0], self.addr[1]])
    8.31          return val
    8.32  
    8.33 +    def getLocalPort(self):
    8.34 +        if self.channel:
    8.35 +            return self.channel.getLocalPort()
    8.36 +        else:
    8.37 +            return 0
    8.38 +
    8.39 +    def getRemotePort(self):
    8.40 +        if self.channel:
    8.41 +            return self.channel.getRemotePort()
    8.42 +        else:
    8.43 +            return 0
    8.44 +
    8.45 +    def uri(self):
    8.46 +        """Get the uri to use to connect to the console.
    8.47 +        This will be a telnet: uri.
    8.48 +
    8.49 +        return uri
    8.50 +        """
    8.51 +        host = socket.gethostname()
    8.52 +        return "telnet://%s:%d" % (host, self.console_port)
    8.53 +
    8.54      def ready(self):
    8.55          return not (self.closed() or self.rbuf.empty())
    8.56  
    8.57 @@ -222,7 +245,7 @@ class ConsoleController(controller.Contr
    8.58          Writes as much to the channel as it can.
    8.59          """
    8.60          work = 0
    8.61 -        while not self.wbuf.empty() and self.channel.writeReady():
    8.62 +        while self.channel and not self.wbuf.empty() and self.channel.writeReady():
    8.63              msg = xu.message(CMSG_CONSOLE, 0, 0)
    8.64              msg.append_payload(self.wbuf.read(msg.MAX_PAYLOAD))
    8.65              work += self.channel.writeRequest(msg, notify=0)
    8.66 @@ -240,7 +263,7 @@ class ConsoleController(controller.Contr
    8.67          if self.closed(): return -1
    8.68          if conn != self.conn: return 0
    8.69          self.wbuf.write(data)
    8.70 -        if self.produceRequests():
    8.71 +        if self.channel and self.produceRequests():
    8.72              self.channel.notify()
    8.73          return 0
    8.74  
     9.1 --- a/tools/python/xen/xend/server/controller.py	Fri Jul 23 13:10:03 2004 +0000
     9.2 +++ b/tools/python/xen/xend/server/controller.py	Fri Jul 23 15:38:32 2004 +0000
     9.3 @@ -199,7 +199,7 @@ class CtrlMsgRcvr:
     9.4          """
     9.5          if self.channel:
     9.6              self.channel.deregisterDevice(self)
     9.7 -            del self.channel
     9.8 +            self.channel = None
     9.9  
    9.10      def produceRequests(self):
    9.11          """Produce any queued requests.
    10.1 --- a/tools/python/xen/xm/create.py	Fri Jul 23 13:10:03 2004 +0000
    10.2 +++ b/tools/python/xen/xm/create.py	Fri Jul 23 15:38:32 2004 +0000
    10.3 @@ -405,7 +405,7 @@ def make_domain(opts, config):
    10.4      dom = int(sxp.child_value(dominfo, 'id'))
    10.5      console_info = sxp.child(dominfo, 'console')
    10.6      if console_info:
    10.7 -        console_port = int(sxp.child_value(console_info, 'port'))
    10.8 +        console_port = int(sxp.child_value(console_info, 'console_port'))
    10.9      else:
   10.10          console_port = None
   10.11