[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] Allow xm to spawn vnc viewer
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1217431365 -3600 # Node ID 21dd1fdb73d83e3c648d9f79e4e0028290dcc4c7 # Parent 9ee2e41a68a1fc05d7fd15f00d87ebd0e1818b93 Allow xm to spawn vnc viewer The new merged qemu no longer has the ability to spawn a vnc viewer process in the bowels of the xend/qemu stack. In this patch we provide support for this use case in a different manner - one more akin to the mechanism used for `xm console' and `xm create -c'. We introduce new xm options: xm create --vncviewer [--vncviewer-autopass] xm vncviewer [--vncviewer-autopass] These spawn a VNC viewer, obtaining the relevant information (including the port number and if you tell it your viewer supports it the password to use) directly from xenstore. Like xm console it waits in the foreground for the vnc port to become available; the timeout case isn't handled as well as it might be - it just causes the whole program (xm) to die with `Alarm clock' but this is difficult to deal with given the current structure of the xs Python lowlevel interface, which doesn't provide a timeout on the call to wait for a xenstore watch. Signed-off-by: Ian Jackson <ian.jackson@xxxxxxxxxxxxx> --- tools/python/xen/util/utils.py | 44 +++++++++++++++++++++++++++ tools/python/xen/xm/console.py | 65 +++++++++++++++++++++++++++++++++++++++-- tools/python/xen/xm/create.py | 65 +++++++++++------------------------------ tools/python/xen/xm/main.py | 59 ++++++++++++++++++++++++++++++++++++- 4 files changed, 183 insertions(+), 50 deletions(-) diff -r 9ee2e41a68a1 -r 21dd1fdb73d8 tools/python/xen/util/utils.py --- a/tools/python/xen/util/utils.py Wed Jul 30 15:25:09 2008 +0100 +++ b/tools/python/xen/util/utils.py Wed Jul 30 16:22:45 2008 +0100 @@ -1,6 +1,50 @@ import traceback import traceback import sys +import os def exception_string(e): (ty,v,tb) = sys.exc_info() return traceback.format_exception_only(ty,v) + +def daemonize(prog, args, stdin_tmpfile=None): + """Runs a program as a daemon with the list of arguments. Returns the PID + of the daemonized program, or returns 0 on error. + """ + r, w = os.pipe() + pid = os.fork() + + if pid == 0: + os.close(r) + w = os.fdopen(w, 'w') + os.setsid() + try: + pid2 = os.fork() + except: + pid2 = None + if pid2 == 0: + os.chdir("/") + null_fd = os.open("/dev/null", os.O_RDWR) + if stdin_tmpfile is not None: + os.dup2(stdin_tmpfile.fileno(), 0) + else: + os.dup2(null_fd, 0) + os.dup2(null_fd, 1) + os.dup2(null_fd, 2) + for fd in range(3, 256): + try: + os.close(fd) + except: + pass + os.execvp(prog, args) + os._exit(1) + else: + w.write(str(pid2 or 0)) + w.close() + os._exit(0) + os.close(w) + r = os.fdopen(r) + daemon_pid = int(r.read()) + r.close() + os.waitpid(pid, 0) + return daemon_pid + diff -r 9ee2e41a68a1 -r 21dd1fdb73d8 tools/python/xen/xm/console.py --- a/tools/python/xen/xm/console.py Wed Jul 30 15:25:09 2008 +0100 +++ b/tools/python/xen/xm/console.py Wed Jul 30 16:22:45 2008 +0100 @@ -15,10 +15,71 @@ # Copyright (C) 2005 XenSource Ltd #============================================================================ +import xen.util.auxbin +import xen.lowlevel.xs +import os +import sys +import signal +from xen.util import utils XENCONSOLE = "xenconsole" -import xen.util.auxbin - def execConsole(domid): xen.util.auxbin.execute(XENCONSOLE, [str(domid)]) + + +class OurXenstoreConnection: + def __init__(self): + self.handle = xen.lowlevel.xs.xs() + def read_eventually(self, path): + watch = None + trans = None + try: + signal.alarm(10) + watch = self.handle.watch(path, None) + while True: + result = self.handle.read('0', path) + if result is not None: + return result + self.handle.read_watch() + self.handle.unwatch(path, watch) + signal.alarm(0) + except: + signal.alarm(0) + if watch is not None: self.handle.unwatch(path, watch) + raise + def read_maybe(self, path): + return self.handle.read('0', path) + +def runVncViewer(domid, do_autopass, do_daemonize=False): + xs = OurXenstoreConnection() + d = '/local/domain/%d/' % domid + vnc_port = xs.read_eventually(d + 'console/vnc-port') + vfb_backend = xs.read_maybe(d + 'device/vfb/0/backend') + vnc_listen = None + vnc_password = None + vnc_password_tmpfile = None + cmdl = ['vncviewer'] + if vfb_backend is not None: + vnc_listen = xs.read_maybe(vfb_backend + '/vnclisten') + if do_autopass: + vnc_password = xs.read_maybe(vfb_backend + '/vncpasswd') + if vnc_password is not None: + cmdl.append('-autopass') + vnc_password_tmpfile = os.tmpfile() + print >>vnc_password_tmpfile, vnc_password + vnc_password_tmpfile.seek(0) + vnc_password_tmpfile.flush() + if vnc_listen is None: + vnc_listen = 'localhost' + cmdl.append('%s:%d' % (vnc_listen, int(vnc_port) - 5900)) + if do_daemonize: + pid = utils.daemonize('vncviewer', cmdl, vnc_password_tmpfile) + if pid == 0: + puts >>sys.stderr, 'failed to invoke vncviewer' + os._exit(-1) + else: + print 'invoking ', ' '.join(cmdl) + if vnc_password_tmpfile is not None: + os.dup2(vnc_password_tmpfile.fileno(), 0) + os.execvp('vncviewer', cmdl) diff -r 9ee2e41a68a1 -r 21dd1fdb73d8 tools/python/xen/xm/create.py --- a/tools/python/xen/xm/create.py Wed Jul 30 15:25:09 2008 +0100 +++ b/tools/python/xen/xm/create.py Wed Jul 30 16:22:45 2008 +0100 @@ -36,10 +36,12 @@ from xen.util import vscsi_util from xen.util import vscsi_util import xen.util.xsm.xsm as security from xen.xm.main import serverType, SERVER_XEN_API, get_single_vm +from xen.util import utils from xen.xm.opts import * from main import server +from main import domain_name_to_domid import console @@ -118,6 +120,14 @@ gopts.opt('console_autoconnect', short=' fn=set_true, default=0, use="Connect to the console after the domain is created.") +gopts.opt('vncviewer', + fn=set_true, default=0, + use="Connect to the VNC display after the domain is created.") + +gopts.opt('vncviewer-autopass', + fn=set_true, default=0, + use="Pass VNC password to viewer via stdin and -autopass.") + gopts.var('vncpasswd', val='NAME', fn=set_value, default=None, use="Password for VNC console on HVM domain.") @@ -128,7 +138,7 @@ gopts.var('vncviewer', val='no|yes', "The address of the vncviewer is passed to the domain on the " "kernel command line using 'VNC_SERVER=<host>:<port>'. The port " "used by vnc is 5500 + DISPLAY. A display value with a free port " - "is chosen if possible.\nOnly valid when vnc=1.") + "is chosen if possible.\nOnly valid when vnc=1.\nDEPRECATED") gopts.var('vncconsole', val='no|yes', fn=set_bool, default=None, @@ -1108,44 +1118,6 @@ def choose_vnc_display(): return None vncpid = None -def daemonize(prog, args): - """Runs a program as a daemon with the list of arguments. Returns the PID - of the daemonized program, or returns 0 on error. - """ - r, w = os.pipe() - pid = os.fork() - - if pid == 0: - os.close(r) - w = os.fdopen(w, 'w') - os.setsid() - try: - pid2 = os.fork() - except: - pid2 = None - if pid2 == 0: - os.chdir("/") - for fd in range(0, 256): - try: - os.close(fd) - except: - pass - os.open("/dev/null", os.O_RDWR) - os.dup2(0, 1) - os.dup2(0, 2) - os.execvp(prog, args) - os._exit(1) - else: - w.write(str(pid2 or 0)) - w.close() - os._exit(0) - os.close(w) - r = os.fdopen(r) - daemon_pid = int(r.read()) - r.close() - os.waitpid(pid, 0) - return daemon_pid - def spawn_vnc(display): """Spawns a vncviewer that listens on the specified display. On success, returns the port that the vncviewer is listening on and sets the global @@ -1154,7 +1126,7 @@ def spawn_vnc(display): vncargs = (["vncviewer", "-log", "*:stdout:0", "-listen", "%d" % (VNC_BASE_PORT + display) ]) global vncpid - vncpid = daemonize("vncviewer", vncargs) + vncpid = utils.daemonize("vncviewer", vncargs) if vncpid == 0: return 0 @@ -1362,6 +1334,11 @@ def main(argv): elif not opts.is_xml: dom = make_domain(opts, config) + if opts.vals.vncviewer: + domid = domain_name_to_domid(sxp.child_value(config, 'name', -1)) + vncviewer_autopass = getattr(opts.vals,'vncviewer-autopass', False) + console.runVncViewer(domid, vncviewer_autopass, True) + def do_console(domain_name): cpid = os.fork() if cpid != 0: @@ -1373,13 +1350,7 @@ def do_console(domain_name): if os.WEXITSTATUS(rv) != 0: sys.exit(os.WEXITSTATUS(rv)) try: - # Acquire the console of the created dom - if serverType == SERVER_XEN_API: - domid = server.xenapi.VM.get_domid( - get_single_vm(domain_name)) - else: - dom = server.xend.domain(domain_name) - domid = int(sxp.child_value(dom, 'domid', '-1')) + domid = domain_name_to_domid(domain_name) console.execConsole(domid) except: pass diff -r 9ee2e41a68a1 -r 21dd1fdb73d8 tools/python/xen/xm/main.py --- a/tools/python/xen/xm/main.py Wed Jul 30 15:25:09 2008 +0100 +++ b/tools/python/xen/xm/main.py Wed Jul 30 16:22:45 2008 +0100 @@ -64,6 +64,9 @@ from xen.xend import XendOptions from xen.xend import XendOptions xoptions = XendOptions.instance() +import signal +signal.signal(signal.SIGINT, signal.SIG_DFL) + # getopt.gnu_getopt is better, but only exists in Python 2.3+. Use # getopt.getopt if gnu_getopt is not available. This will mean that options # may only be specified before positional arguments. @@ -97,6 +100,8 @@ SUBCOMMAND_HELP = { 'console' : ('[-q|--quiet] <Domain>', 'Attach to <Domain>\'s console.'), + 'vncviewer' : ('[--[vncviewer-]autopass] <Domain>', + 'Attach to <Domain>\'s VNC server.'), 'create' : ('<ConfigFile> [options] [vars]', 'Create a domain based on <ConfigFile>.'), 'destroy' : ('<Domain>', @@ -243,6 +248,10 @@ SUBCOMMAND_OPTIONS = { 'console': ( ('-q', '--quiet', 'Do not print an error message if the domain does not exist'), ), + 'vncviewer': ( + ('', '--autopass', 'Pass VNC password to viewer via stdin and -autopass'), + ('', '--vncviewer-autopass', '(consistency alias for --autopass)'), + ), 'dmesg': ( ('-c', '--clear', 'Clear dmesg buffer as well as printing it'), ), @@ -260,6 +269,8 @@ SUBCOMMAND_OPTIONS = { 'start': ( ('-p', '--paused', 'Do not unpause domain after starting it'), ('-c', '--console_autoconnect', 'Connect to the console after the domain is created'), + ('', '--vncviewer', 'Connect to display via VNC after the domain is created'), + ('', '--vncviewer-autopass', 'Pass VNC password to viewer via stdin and -autopass'), ), 'resume': ( ('-p', '--paused', 'Do not unpause domain after resuming it'), @@ -277,6 +288,7 @@ SUBCOMMAND_OPTIONS = { common_commands = [ "console", + "vncviewer", "create", "new", "delete", @@ -304,6 +316,7 @@ common_commands = [ domain_commands = [ "console", + "vncviewer", "create", "new", "delete", @@ -1185,14 +1198,20 @@ def xm_start(args): paused = False console_autoconnect = False + vncviewer = False + vncviewer_autopass = False try: - (options, params) = getopt.gnu_getopt(args, 'cp', ['console_autoconnect','paused']) + (options, params) = getopt.gnu_getopt(args, 'cp', ['console_autoconnect','paused','vncviewer','vncviewer-autopass']) for (k, v) in options: if k in ('-p', '--paused'): paused = True if k in ('-c', '--console_autoconnect'): console_autoconnect = True + if k in ('--vncviewer'): + vncviewer = True + if k in ('--vncviewer-autopass'): + vncviewer_autopass = True if len(params) != 1: raise OptionError("Expects 1 argument") @@ -1204,6 +1223,9 @@ def xm_start(args): if console_autoconnect: start_do_console(dom) + + if console_autoconnect: + console.runVncViewer(domid, vncviewer_autopass, True) try: if serverType == SERVER_XEN_API: @@ -1783,6 +1805,40 @@ def xm_console(args): console.execConsole(domid) +def domain_name_to_domid(domain_name): + if serverType == SERVER_XEN_API: + domid = server.xenapi.VM.get_domid( + get_single_vm(domain_name)) + else: + dom = server.xend.domain(domain_name) + domid = int(sxp.child_value(dom, 'domid', '-1')) + return domid + +def xm_vncviewer(args): + autopass = False; + + try: + (options, params) = getopt.gnu_getopt(args, '', ['autopass','vncviewer-autopass']) + except getopt.GetoptError, opterr: + err(opterr) + usage('vncviewer') + + for (k, v) in options: + if k in ['--autopass','--vncviewer-autopass']: + autopass = True + else: + assert False + + if len(params) != 1: + err('No domain given (or several parameters specified)') + usage('vncviewer') + + dom = params[0] + domid = domain_name_to_domid(dom) + + console.runVncViewer(domid, autopass) + + def xm_uptime(args): short_mode = 0 @@ -2617,6 +2673,7 @@ commands = { "event-monitor": xm_event_monitor, # console commands "console": xm_console, + "vncviewer": xm_vncviewer, # xenstat commands "top": xm_top, # domain commands _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |