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
+
# 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)
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
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.")
"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,
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
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
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:
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
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.
'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>',
'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'),
),
'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'),
common_commands = [
"console",
+ "vncviewer",
"create",
"new",
"delete",
domain_commands = [
"console",
+ "vncviewer",
"create",
"new",
"delete",
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")
if console_autoconnect:
start_do_console(dom)
+ if console_autoconnect:
+ console.runVncViewer(domid, vncviewer_autopass, True)
+
try:
if serverType == SERVER_XEN_API:
server.xenapi.VM.start(get_single_vm(dom), paused)
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
"event-monitor": xm_event_monitor,
# console commands
"console": xm_console,
+ "vncviewer": xm_vncviewer,
# xenstat commands
"top": xm_top,
# domain commands