ia64/xen-unstable

changeset 13554:5f998c3170f7

[PYGRUB] Plumb bootloader I/O through xenconsole.

- xend forwards console traffic between the running bootloader and a pty
which it writes to the store so the xenconsole client can see it.
- the xenconsole client handles the domain's console pty changing.
- xm create no longer runs the bootloader.
- pygrub gets '-i' option to explicitly request an interactive session.
- xend unlocks the domain list during bootloading so that "xm console"
can see the domain and attach to its console pty.

Signed-off-by: Tim Deegan <Tim.Deegan@xensource.com>
author Tim Deegan <Tim.Deegan@xensource.com>
date Mon Jan 22 11:49:14 2007 +0000 (2007-01-22)
parents 51ff40839470
children 1c0ca58e8c16
files tools/console/client/main.c tools/misc/xend tools/pygrub/src/pygrub tools/python/xen/xend/XendBootloader.py tools/python/xen/xend/XendDomain.py tools/python/xen/xend/XendDomainInfo.py tools/python/xen/xm/create.py
line diff
     1.1 --- a/tools/console/client/main.c	Mon Jan 22 11:49:11 2007 +0000
     1.2 +++ b/tools/console/client/main.c	Mon Jan 22 11:49:14 2007 +0000
     1.3 @@ -71,6 +71,43 @@ static void usage(const char *program) {
     1.4  	       , program);
     1.5  }
     1.6  
     1.7 +static int get_pty_fd(struct xs_handle *xs, char *path, int seconds)
     1.8 +/* Check for a pty in xenstore, open it and return its fd.
     1.9 + * Assumes there is already a watch set in the store for this path. */
    1.10 +{
    1.11 +	struct timeval tv;
    1.12 +	fd_set watch_fdset;
    1.13 +	int xs_fd = xs_fileno(xs), pty_fd = -1;
    1.14 +	int start, now;
    1.15 +	unsigned int len = 0;
    1.16 +	char *pty_path, **watch_paths;;
    1.17 +
    1.18 +	start = now = time(NULL);
    1.19 +	do {
    1.20 +		tv.tv_usec = 0;
    1.21 +		tv.tv_sec = (start + seconds) - now;
    1.22 +		FD_ZERO(&watch_fdset);
    1.23 +		FD_SET(xs_fd, &watch_fdset);
    1.24 +		if (select(xs_fd + 1, &watch_fdset, NULL, NULL, &tv)) {
    1.25 +			/* Read the watch to drain the buffer */
    1.26 +			watch_paths = xs_read_watch(xs, &len);
    1.27 +			free(watch_paths);
    1.28 +			/* We only watch for one thing, so no need to 
    1.29 +			 * disambiguate: just read the pty path */
    1.30 +			pty_path = xs_read(xs, XBT_NULL, path, &len);
    1.31 +			if (pty_path != NULL) {
    1.32 +				pty_fd = open(pty_path, O_RDWR | O_NOCTTY);
    1.33 +				if (pty_fd == -1) 
    1.34 +					err(errno, "Could not open tty `%s'", 
    1.35 +					    pty_path);
    1.36 +				free(pty_path);
    1.37 +			}
    1.38 +		}
    1.39 +	} while (pty_fd == -1 && (now = time(NULL)) < start + seconds);
    1.40 +	return pty_fd;
    1.41 +}
    1.42 +
    1.43 +
    1.44  /* don't worry too much if setting terminal attributes fail */
    1.45  static void init_term(int fd, struct termios *old)
    1.46  {
    1.47 @@ -91,18 +128,22 @@ static void restore_term(int fd, struct 
    1.48  	tcsetattr(fd, TCSAFLUSH, old);
    1.49  }
    1.50  
    1.51 -static int console_loop(int fd)
    1.52 +static int console_loop(int fd, struct xs_handle *xs, char *pty_path)
    1.53  {
    1.54 -	int ret;
    1.55 +	int ret, xs_fd = xs_fileno(xs), max_fd;
    1.56  
    1.57  	do {
    1.58  		fd_set fds;
    1.59  
    1.60  		FD_ZERO(&fds);
    1.61  		FD_SET(STDIN_FILENO, &fds);
    1.62 -		FD_SET(fd, &fds);
    1.63 +		max_fd = STDIN_FILENO;
    1.64 +		FD_SET(xs_fd, &fds);
    1.65 +		if (xs_fd > max_fd) max_fd = xs_fd;
    1.66 +		if (fd != -1) FD_SET(fd, &fds);
    1.67 +		if (fd > max_fd) max_fd = fd;
    1.68  
    1.69 -		ret = select(fd + 1, &fds, NULL, NULL, NULL);
    1.70 +		ret = select(max_fd + 1, &fds, NULL, NULL, NULL);
    1.71  		if (ret == -1) {
    1.72  			if (errno == EINTR || errno == EAGAIN) {
    1.73  				continue;
    1.74 @@ -110,6 +151,16 @@ static int console_loop(int fd)
    1.75  			return -1;
    1.76  		}
    1.77  
    1.78 +		if (FD_ISSET(xs_fileno(xs), &fds)) {
    1.79 +			int newfd = get_pty_fd(xs, pty_path, 0);
    1.80 +			close(fd);
    1.81 +                        if (newfd == -1) 
    1.82 +				/* Console PTY has become invalid */
    1.83 +				return 0;
    1.84 +			fd = newfd;
    1.85 +			continue;
    1.86 +		}
    1.87 +
    1.88  		if (FD_ISSET(STDIN_FILENO, &fds)) {
    1.89  			ssize_t len;
    1.90  			char msg[60];
    1.91 @@ -128,12 +179,13 @@ static int console_loop(int fd)
    1.92  			}
    1.93  
    1.94  			if (!write_sync(fd, msg, len)) {
    1.95 -				perror("write() failed");
    1.96 -				return -1;
    1.97 +				close(fd);
    1.98 +				fd = -1;
    1.99 +				continue;
   1.100  			}
   1.101  		}
   1.102  
   1.103 -		if (FD_ISSET(fd, &fds)) {
   1.104 +		if (fd != -1 && FD_ISSET(fd, &fds)) {
   1.105  			ssize_t len;
   1.106  			char msg[512];
   1.107  
   1.108 @@ -143,7 +195,9 @@ static int console_loop(int fd)
   1.109  				    (errno == EINTR || errno == EAGAIN)) {
   1.110  					continue;
   1.111  				}
   1.112 -				return -1;
   1.113 +				close(fd);
   1.114 +				fd = -1;
   1.115 +				continue;
   1.116  			}
   1.117  
   1.118  			if (!write_sync(STDOUT_FILENO, msg, len)) {
   1.119 @@ -168,12 +222,10 @@ int main(int argc, char **argv)
   1.120  		{ 0 },
   1.121  
   1.122  	};
   1.123 -	char *str_pty, *path;
   1.124 -	int spty;
   1.125 -	unsigned int len = 0;
   1.126 +	char *path;
   1.127 +	int spty, xsfd;
   1.128  	struct xs_handle *xs;
   1.129  	char *end;
   1.130 -	time_t now;
   1.131  
   1.132  	while((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
   1.133  		switch(ch) {
   1.134 @@ -213,7 +265,6 @@ int main(int argc, char **argv)
   1.135  	if (path == NULL)
   1.136  		err(ENOMEM, "realloc");
   1.137  	strcat(path, "/console/tty");
   1.138 -	str_pty = xs_read(xs, XBT_NULL, path, &len);
   1.139  
   1.140  	/* FIXME consoled currently does not assume domain-0 doesn't have a
   1.141  	   console which is good when we break domain-0 up.  To keep us
   1.142 @@ -224,38 +275,24 @@ int main(int argc, char **argv)
   1.143  		exit(EINVAL);
   1.144  	}
   1.145  
   1.146 -	/* Wait a little bit for tty to appear.  There is a race
   1.147 -	   condition that occurs after xend creates a domain.  This
   1.148 -	   code might be running before consoled has noticed the new
   1.149 -	   domain and setup a pty for it.
   1.150 +	/* Set a watch on this domain's console pty */
   1.151 +	if (!xs_watch(xs, path, ""))
   1.152 +		err(errno, "Can't set watch for console pty");
   1.153 +	xsfd = xs_fileno(xs);
   1.154  
   1.155 -	   A xenstore watch would slightly improve responsiveness but
   1.156 -	   a timeout would still be needed since we don't want to
   1.157 -	   block forever if given an invalid domain or worse yet, a
   1.158 -	   domain that someone else has connected to. */
   1.159 -
   1.160 -	now = time(0);
   1.161 -	while (str_pty == NULL && (now + 5) > time(0)) {
   1.162 -		struct timeval tv = { 0, 250000 };
   1.163 -		select(0, NULL, NULL, NULL, &tv); /* pause briefly */
   1.164 -
   1.165 -		str_pty = xs_read(xs, XBT_NULL, path, &len);
   1.166 -	}
   1.167 -
   1.168 -	if (str_pty == NULL) {
   1.169 +	/* Wait a little bit for tty to appear.  There is a race
   1.170 +	   condition that occurs after xend creates a domain.  This code
   1.171 +	   might be running before consoled has noticed the new domain
   1.172 +	   and setup a pty for it. */ 
   1.173 +        spty = get_pty_fd(xs, path, 5);
   1.174 +	if (spty == -1) {
   1.175  		err(errno, "Could not read tty from store");
   1.176  	}
   1.177  
   1.178 -	spty = open(str_pty, O_RDWR | O_NOCTTY);
   1.179 -	if (spty == -1) {
   1.180 -		err(errno, "Could not open tty `%s'", str_pty);
   1.181 -	}
   1.182 -	free(str_pty);
   1.183 -	free(path);
   1.184 -
   1.185  	init_term(STDIN_FILENO, &attr);
   1.186 -	console_loop(spty);
   1.187 +	console_loop(spty, xs, path);
   1.188  	restore_term(STDIN_FILENO, &attr);
   1.189  
   1.190 +	free(path);
   1.191  	return 0;
   1.192   }
     2.1 --- a/tools/misc/xend	Mon Jan 22 11:49:11 2007 +0000
     2.2 +++ b/tools/misc/xend	Mon Jan 22 11:49:14 2007 +0000
     2.3 @@ -44,7 +44,7 @@ for p in ['python%s' % sys.version[:3], 
     2.4          if os.path.exists(os.path.join(d, AUXBIN)):
     2.5              sys.path.append(d)
     2.6              import xen.util.auxbin
     2.7 -            libpath = xen.util.auxbin.libpath()
     2.8 +            libpath = os.path.join(xen.util.auxbin.libpath(), p)
     2.9              sys.path = sys.path[:-1]
    2.10              sys.path.append(libpath)
    2.11              break
     3.1 --- a/tools/pygrub/src/pygrub	Mon Jan 22 11:49:11 2007 +0000
     3.2 +++ b/tools/pygrub/src/pygrub	Mon Jan 22 11:49:14 2007 +0000
     3.3 @@ -201,7 +201,9 @@ class Grub:
     3.4              enable_cursor(False)
     3.5              self.entry_win = curses.newwin(10, 74, 2, 1)
     3.6              self.text_win = curses.newwin(10, 70, 12, 5)
     3.7 -            
     3.8 +            curses.def_prog_mode()
     3.9 +        
    3.10 +        curses.reset_prog_mode()
    3.11          self.screen.clear()
    3.12          self.screen.refresh()
    3.13  
    3.14 @@ -549,11 +551,12 @@ if __name__ == "__main__":
    3.15      sel = None
    3.16      
    3.17      def usage():
    3.18 -        print >> sys.stderr, "Usage: %s [-q|--quiet] [--output=] [--kernel=] [--ramdisk=] [--args=] [--entry=] <image>" %(sys.argv[0],)
    3.19 +        print >> sys.stderr, "Usage: %s [-q|--quiet] [-i|--interactive] [--output=] [--kernel=] [--ramdisk=] [--args=] [--entry=] <image>" %(sys.argv[0],)
    3.20  
    3.21      try:
    3.22 -        opts, args = getopt.gnu_getopt(sys.argv[1:], 'qh::',
    3.23 -                                   ["quiet", "help", "output=", "entry=", "kernel=", "ramdisk=", "args=",
    3.24 +        opts, args = getopt.gnu_getopt(sys.argv[1:], 'qih::',
    3.25 +                                   ["quiet", "interactive", "help", "output=",
    3.26 +                                    "entry=", "kernel=", "ramdisk=", "args=",
    3.27                                      "isconfig"])
    3.28      except getopt.GetoptError:
    3.29          usage()
    3.30 @@ -579,6 +582,8 @@ if __name__ == "__main__":
    3.31      for o, a in opts:
    3.32          if o in ("-q", "--quiet"):
    3.33              interactive = False
    3.34 +        elif o in ("-i", "--interactive"):
    3.35 +            interactive = True
    3.36          elif o in ("-h", "--help"):
    3.37              usage()
    3.38              sys.exit()
     4.1 --- a/tools/python/xen/xend/XendBootloader.py	Mon Jan 22 11:49:11 2007 +0000
     4.2 +++ b/tools/python/xen/xend/XendBootloader.py	Mon Jan 22 11:49:14 2007 +0000
     4.3 @@ -12,7 +12,7 @@
     4.4  # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     4.5  #
     4.6  
     4.7 -import os, select, errno, stat
     4.8 +import os, select, errno, stat, signal
     4.9  import random
    4.10  import shlex
    4.11  from xen.xend import sxp
    4.12 @@ -21,12 +21,15 @@ from xen.util import mkdir
    4.13  from XendLogging import log
    4.14  from XendError import VmError
    4.15  
    4.16 -def bootloader(blexec, disk, quiet = False, blargs = '', kernel = '',
    4.17 +import pty, ptsname, termios, fcntl
    4.18 +
    4.19 +def bootloader(blexec, disk, dom, quiet = False, blargs = '', kernel = '',
    4.20                 ramdisk = '', kernel_args = ''):
    4.21      """Run the boot loader executable on the given disk and return a
    4.22      config image.
    4.23      @param blexec  Binary to use as the boot loader
    4.24      @param disk Disk to run the boot loader on.
    4.25 +    @param dom DomainInfo representing the domain being booted.
    4.26      @param quiet Run in non-interactive mode, just booting the default.
    4.27      @param blargs Arguments to pass to the bootloader."""
    4.28      
    4.29 @@ -50,7 +53,33 @@ def bootloader(blexec, disk, quiet = Fal
    4.30                  raise
    4.31          break
    4.32  
    4.33 -    child = os.fork()
    4.34 +    # We need to present the bootloader's tty as a pty slave that xenconsole
    4.35 +    # can access.  Since the bootloader itself needs a pty slave, 
    4.36 +    # we end up with a connection like this:
    4.37 +    #
    4.38 +    # xenconsole -- (slave pty1 master) <-> (master pty2 slave) -- bootloader
    4.39 +    #
    4.40 +    # where we copy characters between the two master fds, as well as
    4.41 +    # listening on the bootloader's fifo for the results.
    4.42 +
    4.43 +    # Termios runes for very raw access to the pty master fds.
    4.44 +    attr = [ 0, 0, termios.CS8 | termios.CREAD | termios.CLOCAL,
    4.45 +             0, 0, 0, [0] * 32 ]
    4.46 +
    4.47 +    (m1, s1) = pty.openpty()
    4.48 +    termios.tcsetattr(m1, termios.TCSANOW, attr)
    4.49 +    fcntl.fcntl(m1, fcntl.F_SETFL, os.O_NDELAY);
    4.50 +    os.close(s1)
    4.51 +    slavename = ptsname.ptsname(m1)
    4.52 +    dom.storeDom("console/tty", slavename)
    4.53 +
    4.54 +    # Release the domain lock here, because we definitely don't want 
    4.55 +    # a stuck bootloader to deny service to other xend clients.
    4.56 +    from xen.xend import XendDomain
    4.57 +    domains = XendDomain.instance()
    4.58 +    domains.domains_lock.release()
    4.59 +    
    4.60 +    (child, m2) = pty.fork()
    4.61      if (not child):
    4.62          args = [ blexec ]
    4.63          if kernel:
    4.64 @@ -74,6 +103,11 @@ def bootloader(blexec, disk, quiet = Fal
    4.65              pass
    4.66          os._exit(1)
    4.67  
    4.68 +    # record that this domain is bootloading
    4.69 +    dom.bootloader_pid = child
    4.70 +
    4.71 +    termios.tcsetattr(m2, termios.TCSANOW, attr)
    4.72 +    fcntl.fcntl(m2, fcntl.F_SETFL, os.O_NDELAY);
    4.73      while True:
    4.74          try:
    4.75              r = os.open(fifo, os.O_RDONLY)
    4.76 @@ -82,17 +116,53 @@ def bootloader(blexec, disk, quiet = Fal
    4.77                  continue
    4.78          break
    4.79      ret = ""
    4.80 +    inbuf=""; outbuf="";
    4.81      while True:
    4.82 -        select.select([r], [], [])
    4.83 -        s = os.read(r, 1024)
    4.84 -        ret = ret + s
    4.85 -        if len(s) == 0:
    4.86 -            break
    4.87 -        
    4.88 +        sel = select.select([r, m1, m2], [m1, m2], [])
    4.89 +        try: 
    4.90 +            if m1 in sel[0]:
    4.91 +                s = os.read(m1, 1)
    4.92 +                inbuf += s
    4.93 +            if m2 in sel[1] and len(inbuf) != 0:
    4.94 +                os.write(m2, inbuf[0])
    4.95 +                inbuf = inbuf[1:]
    4.96 +        except OSError, e:
    4.97 +            if e.errno == errno.EIO:
    4.98 +                pass
    4.99 +        try:
   4.100 +            if m2 in sel[0]:
   4.101 +                s = os.read(m2, 1)
   4.102 +                outbuf += s
   4.103 +            if m1 in sel[1] and len(outbuf) != 0:
   4.104 +                os.write(m1, outbuf[0])
   4.105 +                outbuf = outbuf[1:]
   4.106 +        except OSError, e:
   4.107 +            if e.errno == errno.EIO:
   4.108 +                pass
   4.109 +        if r in sel[0]:
   4.110 +            s = os.read(r, 1)
   4.111 +            ret = ret + s
   4.112 +            if len(s) == 0:
   4.113 +                break
   4.114 +    del inbuf
   4.115 +    del outbuf
   4.116      os.waitpid(child, 0)
   4.117      os.close(r)
   4.118 +    os.close(m2)
   4.119 +    os.close(m1)
   4.120      os.unlink(fifo)
   4.121  
   4.122 +    # Re-acquire the lock to cover the changes we're about to make
   4.123 +    # when we return to domain creation.
   4.124 +    domains.domains_lock.acquire()    
   4.125 +
   4.126 +    if dom.bootloader_pid is None:
   4.127 +        msg = "Domain was died while the bootloader was running."
   4.128 +        log.error(msg)
   4.129 +        raise VmError, msg        
   4.130 +        
   4.131 +    dom.bootloader_pid = None
   4.132 +
   4.133      if len(ret) == 0:
   4.134          msg = "Boot loader didn't return any data!"
   4.135          log.error(msg)
   4.136 @@ -103,3 +173,12 @@ def bootloader(blexec, disk, quiet = Fal
   4.137      pin.input_eof()
   4.138      blcfg = pin.val
   4.139      return blcfg
   4.140 +
   4.141 +
   4.142 +def bootloader_tidy(dom):
   4.143 +    if hasattr(dom, "bootloader_pid") and dom.bootloader_pid is not None:
   4.144 +        pid = dom.bootloader_pid
   4.145 +        dom.bootloader_pid = None
   4.146 +        os.kill(pid, signal.SIGKILL)
   4.147 +
   4.148 +
     5.1 --- a/tools/python/xen/xend/XendDomain.py	Mon Jan 22 11:49:11 2007 +0000
     5.2 +++ b/tools/python/xen/xend/XendDomain.py	Mon Jan 22 11:49:14 2007 +0000
     5.3 @@ -115,7 +115,6 @@ class XendDomain:
     5.4                  
     5.5                  dom0info['name'] = DOM0_NAME
     5.6                  dom0 = XendDomainInfo.recreate(dom0info, True)
     5.7 -                self._add_domain(dom0)
     5.8              except IndexError:
     5.9                  raise XendError('Unable to find Domain 0')
    5.10              
    5.11 @@ -172,7 +171,6 @@ class XendDomain:
    5.12                  if dom['domid'] != DOM0_ID:
    5.13                      try:
    5.14                          new_dom = XendDomainInfo.recreate(dom, False)
    5.15 -                        self._add_domain(new_dom)
    5.16                      except Exception:
    5.17                          log.exception("Failed to create reference to running "
    5.18                                        "domain id: %d" % dom['domid'])
    5.19 @@ -397,7 +395,6 @@ class XendDomain:
    5.20              elif domid not in self.domains and dom['dying'] != 1:
    5.21                  try:
    5.22                      new_dom = XendDomainInfo.recreate(dom, False)
    5.23 -                    self._add_domain(new_dom)                    
    5.24                  except VmError:
    5.25                      log.exception("Unable to recreate domain")
    5.26                      try:
    5.27 @@ -416,10 +413,10 @@ class XendDomain:
    5.28          running_domids = [d['domid'] for d in running if d['dying'] != 1]
    5.29          for domid, dom in self.domains.items():
    5.30              if domid not in running_domids and domid != DOM0_ID:
    5.31 -                self._remove_domain(dom, domid)
    5.32 +                self.remove_domain(dom, domid)
    5.33  
    5.34  
    5.35 -    def _add_domain(self, info):
    5.36 +    def add_domain(self, info):
    5.37          """Add a domain to the list of running domains
    5.38          
    5.39          @requires: Expects to be protected by the domains_lock.
    5.40 @@ -434,7 +431,7 @@ class XendDomain:
    5.41          if info.get_uuid() in self.managed_domains:
    5.42              self._managed_domain_register(info)
    5.43  
    5.44 -    def _remove_domain(self, info, domid = None):
    5.45 +    def remove_domain(self, info, domid = None):
    5.46          """Remove the domain from the list of running domains
    5.47          
    5.48          @requires: Expects to be protected by the domains_lock.
    5.49 @@ -473,7 +470,6 @@ class XendDomain:
    5.50          try:
    5.51              security.refresh_ssidref(config)
    5.52              dominfo = XendDomainInfo.restore(config)
    5.53 -            self._add_domain(dominfo)
    5.54              return dominfo
    5.55          finally:
    5.56              self.domains_lock.release()
    5.57 @@ -848,7 +844,6 @@ class XendDomain:
    5.58                                             os.open(chkpath, os.O_RDONLY),
    5.59                                             dominfo,
    5.60                                             paused = start_paused)
    5.61 -                    self._add_domain(dominfo)
    5.62                      os.unlink(chkpath)
    5.63                  except OSError, ex:
    5.64                      raise XendError("Failed to read stored checkpoint file")
    5.65 @@ -873,7 +868,6 @@ class XendDomain:
    5.66              self._refresh()
    5.67  
    5.68              dominfo = XendDomainInfo.create(config)
    5.69 -            self._add_domain(dominfo)
    5.70              self.domain_sched_credit_set(dominfo.getDomid(),
    5.71                                           dominfo.getWeight(),
    5.72                                           dominfo.getCap())
    5.73 @@ -893,7 +887,6 @@ class XendDomain:
    5.74              self._refresh()
    5.75  
    5.76              dominfo = XendDomainInfo.create_from_dict(config_dict)
    5.77 -            self._add_domain(dominfo)
    5.78              self.domain_sched_credit_set(dominfo.getDomid(),
    5.79                                           dominfo.getWeight(),
    5.80                                           dominfo.getCap())
    5.81 @@ -950,7 +943,6 @@ class XendDomain:
    5.82                                   POWER_STATE_NAMES[dominfo.state])
    5.83              
    5.84              dominfo.start(is_managed = True)
    5.85 -            self._add_domain(dominfo)
    5.86          finally:
    5.87              self.domains_lock.release()
    5.88          dominfo.waitForDevices()
    5.89 @@ -983,7 +975,7 @@ class XendDomain:
    5.90                           (dominfo.getName(), dominfo.info.get('uuid')))
    5.91  
    5.92                  self._managed_domain_unregister(dominfo)
    5.93 -                self._remove_domain(dominfo)
    5.94 +                self.remove_domain(dominfo)
    5.95                  XendDevices.destroy_device_state(dominfo)
    5.96              except Exception, ex:
    5.97                  raise XendError(str(ex))
     6.1 --- a/tools/python/xen/xend/XendDomainInfo.py	Mon Jan 22 11:49:11 2007 +0000
     6.2 +++ b/tools/python/xen/xend/XendDomainInfo.py	Mon Jan 22 11:49:14 2007 +0000
     6.3 @@ -41,7 +41,7 @@ from xen.xend import balloon, sxp, uuid,
     6.4  from xen.xend import XendOptions, XendNode, XendConfig
     6.5  
     6.6  from xen.xend.XendConfig import scrub_password
     6.7 -from xen.xend.XendBootloader import bootloader
     6.8 +from xen.xend.XendBootloader import bootloader, bootloader_tidy
     6.9  from xen.xend.XendError import XendError, VmError
    6.10  from xen.xend.XendDevices import XendDevices
    6.11  from xen.xend.xenstore.xstransact import xstransact, complete
    6.12 @@ -101,7 +101,6 @@ def create_from_dict(config_dict):
    6.13          log.exception('Domain construction failed')
    6.14          vm.destroy()
    6.15          raise
    6.16 -
    6.17      return vm
    6.18  
    6.19  def recreate(info, priv):
    6.20 @@ -187,6 +186,11 @@ def recreate(info, priv):
    6.21  
    6.22      vm._registerWatches()
    6.23      vm.refreshShutdown(xeninfo)
    6.24 +
    6.25 +    # register the domain in the list 
    6.26 +    from xen.xend import XendDomain
    6.27 +    XendDomain.instance().add_domain(vm)
    6.28 +
    6.29      return vm
    6.30  
    6.31  
    6.32 @@ -1338,6 +1342,9 @@ class XendDomainInfo:
    6.33          # Set maximum number of vcpus in domain
    6.34          xc.domain_max_vcpus(self.domid, int(self.info['vcpus_number']))
    6.35  
    6.36 +        # register the domain in the list 
    6.37 +        from xen.xend import XendDomain
    6.38 +        XendDomain.instance().add_domain(self)
    6.39  
    6.40      def _introduceDomain(self):
    6.41          assert self.domid is not None
    6.42 @@ -1436,6 +1443,7 @@ class XendDomainInfo:
    6.43          try:
    6.44              self.unwatchShutdown()
    6.45              self._releaseDevices()
    6.46 +            bootloader_tidy(self)
    6.47  
    6.48              if self.image:
    6.49                  try:
    6.50 @@ -1536,6 +1544,9 @@ class XendDomainInfo:
    6.51          except:
    6.52              log.exception("XendDomainInfo.destroy: xc.domain_destroy failed.")
    6.53  
    6.54 +        from xen.xend import XendDomain
    6.55 +        XendDomain.instance().remove_domain(self)
    6.56 +
    6.57          self.cleanupDomain()
    6.58  
    6.59  
    6.60 @@ -1631,7 +1642,7 @@ class XendDomainInfo:
    6.61                      fn = BOOTLOADER_LOOPBACK_DEVICE
    6.62  
    6.63                  try:
    6.64 -                    blcfg = bootloader(blexec, fn, True,
    6.65 +                    blcfg = bootloader(blexec, fn, self, False,
    6.66                                         bootloader_args, kernel, ramdisk, args)
    6.67                  finally:
    6.68                      if mounted:
     7.1 --- a/tools/python/xen/xm/create.py	Mon Jan 22 11:49:11 2007 +0000
     7.2 +++ b/tools/python/xen/xm/create.py	Mon Jan 22 11:49:14 2007 +0000
     7.3 @@ -24,6 +24,7 @@ import os.path
     7.4  import sys
     7.5  import socket
     7.6  import re
     7.7 +import time
     7.8  import xmlrpclib
     7.9  
    7.10  from xen.xend import sxp
    7.11 @@ -709,26 +710,6 @@ def configure_hvm(config_image, vals):
    7.12              config_image.append([a, vals.__dict__[a]])
    7.13      config_image.append(['vncpasswd', vals.vncpasswd])
    7.14  
    7.15 -def run_bootloader(vals, config_image):
    7.16 -    if not os.access(vals.bootloader, os.F_OK):
    7.17 -        err("Bootloader '%s' does not exist" % vals.bootloader)
    7.18 -    if not os.access(vals.bootloader, os.X_OK):
    7.19 -        err("Bootloader '%s' isn't executable" % vals.bootloader)
    7.20 -    if len(vals.disk) < 1:
    7.21 -        err("No disks configured and boot loader requested")
    7.22 -    (uname, dev, mode, backend) = vals.disk[0]
    7.23 -    file = blkif.blkdev_uname_to_file(uname)
    7.24 -
    7.25 -    if vals.bootentry:
    7.26 -        warn("The bootentry option is deprecated.  Use bootargs and pass "
    7.27 -             "--entry= directly.")
    7.28 -        vals.bootargs = "--entry=%s" %(vals.bootentry,)
    7.29 -
    7.30 -    kernel = sxp.child_value(config_image, 'kernel')
    7.31 -    ramdisk = sxp.child_value(config_image, 'ramdisk')
    7.32 -    args = sxp.child_value(config_image, 'args')
    7.33 -    return bootloader(vals.bootloader, file, not vals.console_autoconnect,
    7.34 -                      vals.bootargs, kernel, ramdisk, args)
    7.35  
    7.36  def make_config(vals):
    7.37      """Create the domain configuration.
    7.38 @@ -771,14 +752,11 @@ def make_config(vals):
    7.39          if vals.bootloader == "pygrub":
    7.40              vals.bootloader = osdep.pygrub_path
    7.41  
    7.42 -        # if a kernel is specified, we're using the bootloader
    7.43 -        # non-interactively, and need to let xend run it so we preserve the
    7.44 -        # real kernel choice.
    7.45 -        if not vals.kernel:
    7.46 -            config_image = run_bootloader(vals, config_image)
    7.47          config.append(['bootloader', vals.bootloader])
    7.48          if vals.bootargs:
    7.49              config.append(['bootloader_args', vals.bootargs])
    7.50 +        else: 
    7.51 +            config.append(['bootloader_args', '-q'])        
    7.52      config.append(['image', config_image])
    7.53  
    7.54      config_devs = []
    7.55 @@ -1266,9 +1244,28 @@ def main(argv):
    7.56          if not create_security_check(config):
    7.57              raise security.ACMError('Security Configuration prevents domain from starting')
    7.58          else:
    7.59 -            dom = make_domain(opts, config)
    7.60              if opts.vals.console_autoconnect:
    7.61 -                console.execConsole(dom)        
    7.62 -             
    7.63 +                cpid = os.fork() 
    7.64 +                if cpid != 0:
    7.65 +                    for i in range(10):
    7.66 +                        # Catch failure of the create process 
    7.67 +                        time.sleep(1)
    7.68 +                        (p, rv) = os.waitpid(cpid, os.WNOHANG)
    7.69 +                        if os.WIFEXITED(rv):
    7.70 +                            if os.WEXITSTATUS(rv) != 0:
    7.71 +                                sys.exit(os.WEXITSTATUS(rv))
    7.72 +                        try:
    7.73 +                            # Acquire the console of the created dom
    7.74 +                            name = sxp.child_value(config, 'name', -1)
    7.75 +                            dom = server.xend.domain(name)
    7.76 +                            domid = int(sxp.child_value(dom, 'domid', '-1'))
    7.77 +                            console.execConsole(domid)
    7.78 +                        except:
    7.79 +                            pass
    7.80 +                    print("Could not start console\n");
    7.81 +                    sys.exit(0)
    7.82 +            dom = make_domain(opts, config)
    7.83 +
    7.84 +
    7.85  if __name__ == '__main__':
    7.86      main(sys.argv)