PSARC/2014/377 noVNC - A browser based VNC client
19557488 The noVNC client should be added to Userland
20202461 Websockify is broken on SPARC because of unnecessary byte swapping
20202582 Solaris zones nova compute driver needs console access support
#!/usr/bin/python2.6
import errno
import os
import pwd
import smf_include
import subprocess
import sys
from subprocess import CalledProcessError, check_call, Popen
from tempfile import mkstemp
SVCCFG = "/usr/sbin/svccfg"
SVCPROP = "/usr/bin/svcprop"
VNCSERVER = "/usr/bin/vncserver"
XSTARTUPHDR = "# WARNING: THIS FILE GENERATED BY SMF.\n" + \
"# DO NOT EDIT THIS FILE. EDITS WILL BE LOST.\n"
XTERM = "/usr/bin/xterm"
# Monospsce font, point size 15, white foreground on black background"
XTERMOPTS = ' -fa Monospace -fs 15 -fg white -bg black'
# Enclose command in comments to prevent xterm consuming zlogin opts
ZLOGINOPTS = ' -e "/usr/bin/pfexec /usr/sbin/zlogin -C -E $ZONENAME"\n'
XSTARTUP = XSTARTUPHDR + XTERM + XTERMOPTS + ZLOGINOPTS
def start():
check_vncserver()
homedir = os.environ.get('HOME')
if not homedir:
homedir = pwd.getpwuid(os.getuid()).pw_dir
os.putenv("HOME", homedir)
set_xstartup(homedir)
try:
fmri = os.environ['SMF_FMRI']
zonename = fmri.rsplit(':', 1)[1]
os.putenv("ZONENAME", zonename)
desktop_name = zonename + ' console'
# NOTE: 'geometry' below is that which matches the size of standard
# 80 character undecorated xterm window using font style specified in
# XTERMOPTS. Update this geometry whenever XTERMOPTS are changed.
# Avoids exposing X root window within noVNC canvas widget.
cmd = [VNCSERVER, "-name", desktop_name, "-SecurityTypes=None",
"-geometry", "964x580", "-localhost", "-autokill"]
vnc = Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
env=None)
out, err = vnc.communicate()
vncret = vnc.wait()
if vncret != 0:
print "Error starting VNC server: " + err
return smf_include.SMF_EXIT_ERR_FATAL
except Exception as e:
print e
return smf_include.SMF_EXIT_ERR_FATAL
output = err.splitlines()
for line in output:
if line.startswith("New '%s' desktop is" % desktop_name):
display = line.rpartition(' ')[2]
host, display_num = display.split(':', 1)
# set host prop
port = 5900 + int(display_num)
print "VNC port: %d" % port
# set port num prop
cmd = [SVCCFG, '-s', fmri, 'setprop', 'vnc/port', '=', 'integer:',
str(port)]
svccfg = subprocess.Popen(cmd, stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
out, err = svccfg.communicate()
retcode = svccfg.wait()
if retcode != 0:
print "Error updating 'vnc/port' property: " + err
return smf_include.SMF_EXIT_ERR_FATAL
return smf_include.SMF_EXIT_OK
def stop():
try:
# first kill the SMF contract
check_call(["/usr/bin/pkill", "-c", sys.argv[2]])
except CalledProcessError as cpe:
# 1 is returncode if no SMF contract processes were matched,
# meaning they have already terminated.
if cpe.returncode != 1:
print "failed to kill the SMF contract: %s" % cpe
return smf_include.SMF_EXIT_ERR_FATAL
try:
fmri = os.environ['SMF_FMRI']
# reset port num prop to initial zero value
cmd = [SVCCFG, '-s', fmri, 'setprop', 'vnc/port', '=', 'integer:',
'0']
svccfg = subprocess.Popen(cmd, stdout=subprocess.PIPE,
stderr=subprocess.PIPE,)
out, err = svccfg.communicate()
retcode = svccfg.wait()
if retcode != 0:
print "Error resetting 'vnc/port' property: " + err
return smf_include.SMF_EXIT_ERR_FATAL
except Exception as e:
print e
return smf_include.SMF_EXIT_ERR_FATAL
def check_vncserver():
if not os.path.exists(VNCSERVER):
print("VNC console service not available on this compute node. "
"%s is missing. Run 'pkg install x11/server/xvnc'"
% VNCSERVER)
return smf_include.SMF_EXIT_ERR_FATAL
if not os.path.exists(XTERM):
print("VNC console service not available on this compute node. "
"%s is missing. Run 'pkg install terminal/xterm'"
% XTERM)
return smf_include.SMF_EXIT_ERR_FATAL
def set_xstartup(homedir):
vncdir = os.path.join(homedir, '.vnc')
xstartup_path = os.path.join(vncdir, 'xstartup')
try:
os.mkdir(vncdir)
except OSError as ose:
if ose.errno != errno.EEXIST:
raise
# Always clobber xstartup
# stemp tuple = [fd, path]
stemp = mkstemp(dir=vncdir)
os.write(stemp[0], XSTARTUP)
os.close(stemp[0])
os.chmod(stemp[1], 0700)
os.rename(stemp[1], xstartup_path)
if __name__ == "__main__":
os.putenv("LC_ALL", "C")
smf_include.smf_main()