diff options
author | Alon Levy <alevy@redhat.com> | 2011-07-14 17:32:41 +0300 |
---|---|---|
committer | Alon Levy <alevy@redhat.com> | 2011-07-14 17:32:41 +0300 |
commit | 8d979278000400598519c11996fecf928c584151 (patch) | |
tree | 2105bae38374ac6a9abe8f78ba70d5328836b11e |
initial
-rwxr-xr-x | spice2 | 665 |
1 files changed, 665 insertions, 0 deletions
@@ -0,0 +1,665 @@ +#!/usr/bin/python + +import signal +import os +import sys +import subprocess +import argparse +import atexit +import socket +import datetime +import re +import time +import shutil + +try: + import guestfs + import hivex +except: + print "missing guestfs or hivex" + guestfs = None + +HOME = os.environ['HOME'] +################################################################################ +qemu_exec_name = "qemu-system-x86_64" +images = { + 'windevel': '/store/images/windbg_winxp.img', + 'winxp': '/store/images/winxp_sp3_qxl_after_cirrus.img', + 'win7': '/home/alon/images2/win7x86_qxl_tests.img', + 'kindle': '/home/alon/images2/win7_kindle.img', + 'win2008r2': '/media/PassportExt4/images/win2008r2_qxl.qcow2', + 'f14ccid': '/media/PassportExt4/images/F14_CCID.testing.qcow2', + 'winxp.inst': '/store/images/winxp_installation_test.qcow2', +} + +spicy_exe = os.path.join(HOME, 'spice/upstream/bin/spicy') +spicec_exe = os.path.join(HOME, 'spice/upstream/bin/spicec') +spicy_teuf_exe = os.path.join(HOME, 'src/spice_upstream/teuf-spice-gtk/gtk/spicy') +qemus = {'rhel6':'rhel6', 'upstream':'upstream'} +qemu_default = 'upstream' + +defaults = dict( + win7=dict( + qemu='upstream', + args='--port 8888 --clients 1 --tablet --guestdebug 2 --qxldebug 1 --windbg-client 9000'.split() + ), + windevel=dict( + qemu='rhel6', + args='--port 6666 --clients 1 --windbg-server 9000'.split() + ), + f14ccid=dict( + qemu='upstream', + args='--port 9999 --clients 1 --tablet --guestdebug 4 --qxldebug 1 --smartcard'.split() + ), +) + +spice_src_path = os.path.join(HOME, 'src/spice_upstream/spice') + +qxl_win_root = os.path.join(HOME, 'shared_win/qxl/dist') + +################################################################################ + +win_tests = dict( +shutdown=dict(contents=""" +shutdown /p +"""), +suspend=dict(contents=r""" +%s +shutdown /p +""" % (""" +c:\suspend.exe +rem ping -n 2 localhost +""" * 20), files=[HOME+'/shared_win/spice_upstream/util/suspend/suspend.exe']), +resolution1=dict(contents=r""" +set RESCHANGE="c:\reschange.exe" +%s +shutdown /p +""" % (""" +%RESCHANGE% -mon 800,600,32,0,0 +%RESCHANGE% -mon 600,800,32,0,0 +%RESCHANGE% -mon 1024,768,32,0,0 +%RESCHANGE% -mon 768,1024,32,0,0 +%RESCHANGE% -mon 1024,768,32,0,0 +""" * 60), files=[HOME+'/shared_win/spice_upstream/util/reschange/reschange.exe']), +resolution2=dict(contents=r""" +set RESCHANGE="c:\reschange.exe" +%s +shutdown /p +""" % (""" +%RESCHANGE% -attach -mon 1024,768,32,0,0 -mon 800,600,32,1024,0 +%RESCHANGE% -attach -mon 1024,768,32,0,0 +%RESCHANGE% -attach -mon 1024,768,32,0,0 -mon 800,600,32,1024,0 +%RESCHANGE% -attach -mon 1024,768,32,0,0 +""" * 60), files=[HOME+'/shared_win/spice_upstream/util/reschange/reschange.exe']), +) + +################################################################################ + +red = "\x1b[101m%s\x1b[0m" +path = os.environ['PATH'] + +################################################################################ + +def set_title(x): + sys.stdout.write("\033]0;%s\007" % str(x)) + +def file_in_use(x): + return not os.system('lsof -t %s > /dev/null' % x) + +def which(x): + for f in path.split(':'): + full_path = os.path.join(f, x) + if os.path.exists(full_path): + return full_path + return None + +def oldness(f): + if not os.path.exists(f): + return 'file doesn\'t exist' + d = datetime.datetime.now() - datetime.datetime.fromtimestamp(os.stat(f).st_mtime) + if d.days > 0: + return '%d days' % d.days + elif d.seconds > 3600: + return '%d hours' % int(d.seconds / 3600) + elif d.seconds > 60: + return '%d minutes' % int(d.seconds / 60) + return '%d seconds' % d.seconds + +lddpath = which('ldd') +def get_lib(fname, rexp): + l = os.popen('%s "%s"' % (lddpath, fname)).readlines() + refs_raw=[x.split('=>') for x in l if '=>' in x] + refs=[(r[0].strip().split()[0], r[1].strip().split()[0]) for r in refs_raw] + ref = [r[1] for r in refs if re.match(rexp, r[0])] + if len(ref) == 0: + return 'library not found' + return ref[0] + +vncviewer = which('vncviewer') + +def make_iso(iso_name, root, title): + cmd = 'mkisofs -J -R -V %s_%s -o %s %s' % (title, datetime.datetime.now().strtime('%Y%m%d_%H%M'), iso_name, root) + print cmd + os.system(cmd) + +def print_qemu_and_spice_versions(which, qemuexe, bios_dir): + base = which + ' ' + spice_lib = get_lib(qemuexe, 'libspice-server.*') + bios_bin = os.path.join(bios_dir, 'bios.bin') + print red % (base * (80 / len(base))) + print "QEMU age: %s (%s)" % (oldness(qemuexe), qemuexe) + print "spice age: %s (%s)" % (oldness(spice_lib), spice_lib) + print "bios.bin age: %s (%s)" % (oldness(bios_bin), bios_dir) + print red % (base * (80 / len(base))) + +def get_temp_name(prefix, postfix): + global temp_files + i = [0] + def make_name(i): + name = '%s_%03d%s' % (prefix, i[0], postfix) + i[0] += 1 + return name + filename = make_name(i) + while os.path.exists(filename): + filename = make_name(i) + return filename + +def create_qcow_with_backing_file(target_base, backing_file, erase_at_exit): + filename = get_temp_name(target_base, '.qcow2') + os.system('qemu-img create -f qcow2 -o backing_file="%s" %s' % (backing_file, filename)) + if erase_at_exit: + temp_files.append(filename) + return filename + +def get_image(args): + image_base_fullpath = args.image + if not os.path.exists(image_base_fullpath): + print "missing image %s" % image_base_fullpath + sys.exit(1) + if not args.second and file_in_use(image_base_fullpath): + print "image in use and --second not in arguments" + sys.exit(1) + if args.backing_file: + base_image_name = os.path.basename(args.image) + image_fullpath = create_qcow_with_backing_file( + target_base='/tmp/'+base_image_name, + backing_file=image_base_fullpath, + erase_at_exit=args.erase_temp_backing_file) + else: + image_fullpath = image_base_fullpath + print "image %s" % image_fullpath + return image_fullpath + +def build_test_cmdline(args): + test_progs = { + 'streaming': 'test_display_streaming', + 'display': 'test_display_no_ssl', + 'playback': 'test_playback', + 'sockets': 'test_just_sockets_no_ssl', + 'replay': 'replay', + } + parts = (['/usr/bin/libtool', '--mode=execute', 'cgdb', '--args'] if args.cgdb else []) + [os.path.join(spice_src_path, 'server/tests', test_progs[args.test])] + if args.test == 'replay' and args.replay_file: + parts.append(args.replay_file) + # tests have this port hardcoded + args.port = 5912 + return ' '.join(parts) + +def build_cmdline(args): + if args.test: + return build_test_cmdline(args) + qemu = args.qemu + if qemu not in qemus: + print "missing qemu %r" % qemu + sys.exit(1) + args.image_fullpath = image_fullpath = get_image(args) + install_root = qemus[qemu] + root = os.path.join(HOME, 'spice', install_root) + libdir = os.path.join(root, 'lib') + bindir = os.path.join(root, 'bin') + bios_dir = os.path.join(root, 'share/qemu') + qemuexe = os.path.join(bindir, qemu_exec_name) + os.environ['LD_LIBRARY_PATH'] = libdir + os.environ['PATH'] = bindir + ':' + os.environ['PATH'] + if args.record_cmd: + print "recording cmd ring to %r" % args.record_cmd + os.environ['SPICE_WORKER_RECORD_FILENAME'] = args.record_cmd + os.system('echo $LD_LIBRARY_PATH') + cmdline = ["%(qemuexe)s -chardev stdio,id=muxstdio,mux=on -spice disable-ticketing,port=%(spice_port)s -vga %(vga)s %(guest_debug_option)s %(qxl_debug_option)s %(cmdlog_option)s -drive file=%(image_fullpath)s,cache=%(cache)s -snapshot -mon chardev=muxstdio -enable-kvm -net nic,model=virtio -L %(bios_dir)s -m %(memory)d %(smp_option)s -cpu %(cpu)s %(no_shutdown)s" % dict( + qemuexe = qemuexe, + vga = args.vga, + spice_port = args.spice_port, + cache = args.cache, + image_fullpath = image_fullpath, + bios_dir = bios_dir, + guest_debug_option = '' if args.guestdebug == 0 else '-global qxl-vga.guestdebug=%d' % args.guestdebug, + qxl_debug_option = '' if args.qxldebug == 0 else '-global qxl-vga.debug=%d' % args.qxldebug, + cmdlog_option = '' if args.cmdlog == 0 else '-global qxl-vga.cmdlog=%d' % args.cmdlog, + memory = args.memory, + smp_option = '' if args.cpus == 1 else '-smp %d' % args.cpus, + no_shutdown = '-no-shutdown' if args.no_shutdown else '', + cpu = args.cpu, + )] + if args.qxl > 1: + cmdline.append((' -device qxl,guestdebug=%d,cmdlog=%d,debug=%d' % (args.guestdebug, + args.cmdlog, args.qxldebug)) * (args.qxl - 1)) + if args.revision: + cmdline.append(' -global qxl-vga.revision=%d' % args.revision) + if args.tablet: + cmdline.append(' -usb -device usb-tablet') + else: + cmdline.append(' -device virtio-serial -chardev spicevmc,name=vdagent,id=vdagent -device virtserialport,chardev=vdagent,name=com.redhat.spice.0') + # user networking + if args.smb: + cmdline.append(' -net user,smb=%s,smbserver=10.0.2.2' % args.smb) + else: + cmdline.append(' -net user') + # windbg (TODO - better then serial) + if args.windbg_server: + cmdline.append(' -serial tcp::%d,server,nowait' % args.windbg_server) + if args.windbg_client: + if port_is_available(args.windbg_client): + cmdline.append(' -serial tcp:localhost:%d' % args.windbg_client) + else: + print "nothing listening on %d, do you want to start something there? (p.s. maybe systemd service?)" % args.windbg_client + # smartcard + if args.smartcard: + ccid_debug = 1 + passthru_debug = 1 + cmdline.extend([' -chardev spicevmc,id=smartcard,debug=3,name=smartcard', + " -device usb-ccid,debug=%s,id=ccid" % ccid_debug, + " -device ccid-card-passthru,debug=%s,chardev=smartcard" % (passthru_debug), + ]) + # bios debugging + if args.debugbios: + cmdline.append(' -device isa-debugcon,iobase=0x402,chardev=muxstdio') + # incoming migration + if args.incoming: + cmdline.append(' -incoming tcp:localhost:%d' % args.incoming) + if args.freeze: + cmdline.append(' -S') + # vnc server + if args.vnc_port: + if (args.vnc_port < 5900): + print "vnc_port must be >= 5900" + cmdline.append(' -vnc %s:%s' % (args.spice_host, args.vnc_port - 5900)) + + # cdrom + if args.winqxl_cdrom: + if args.cdrom: + print "winqxl-cdrom and cdrom are mutually exclusive" + sys.exit(1) + if not os.path.exists(qxl_win_root): + print "you need to edit qxl_win_root path in %s for this option" % ( + sys.argv[0]) + sys.exit(1) + make_iso('/tmp/winqxl.iso', qxl_win_root, title='qxl') + args.cdrom = '/tmp/winqxl.iso' + if args.cdrom: + if not os.path.exists(args.cdrom): + print "missing cdrom image %r" % args.cdrom + sys.exit(1) + cmdline.append(' -cdrom "%s"' % args.cdrom) + + ###### + cmdline = ''.join(cmdline) + + print_qemu_and_spice_versions(qemuexe=qemuexe, which=qemu, bios_dir=bios_dir) + # wrap in various tools + if args.cgdb: + cgdb = which('cgdb') + cmdline = '%s --args %s' % (cgdb, cmdline) + if args.memcheck: + print "wrapping with valgrind memcheck" + cmdline = 'valgrind --error-limit=no --leak-check=full --suppressions=%(HOME)s/bin/kvm.supp --log-file=/tmp/kvm_%(time_str)s.valgrind %(cmdline)s' % { + 'cmdline':cmdline, + 'time_str': time.strftime('%Y%m%d_%H%M%S',time.gmtime()), + 'HOME': HOME + } + if args.time: + print "wrapping in time" + cmdline = '/usr/bin/time --verbose %s' % cmdline + return cmdline + +def run_xephyr(display, size=(1024,768+40)): + return start_process(('Xephyr -screen %dx%d :%d.0' % + (size[0], size[1], display)).split()) + +def run_client(host, port, oldclient, smartcard, certs, dbdir, display=None): + s_opts = '' + old_display = None + if display is not None: + old_display = os.environ['DISPLAY'] + os.environ['DISPLAY'] = ':%d.0' % display + if smartcard and certs: + if oldclient: + s_opts = '--smartcard --smartcard-certs %s --smartcard-db %s' % ( + ','.join(certs), dbdir) + else: + s_opts = '--certificates=%s --certificate-db=%s' % ( + ','.join(certs), dbdir) + + p = start_process( + args=('%(exe)s -h %(host)s -p %(port)s %(smartcard)s' % dict( + host=host, port=port, exe=spicec_exe if oldclient else spicy_exe, + smartcard=s_opts)).split(), kill=True) + if old_display: + os.environ['DISPLAY'] = old_display + return p + +def run_vnc_client(host, port): + return start_process(args=('%s %s::%s' % (vncviewer, host, port)).split(), kill=True) + +def port_is_available(port): + s = socket.socket(socket.AF_INET) + ret = False + try: + s.connect(('localhost', port)) + s.close() + ret = True + except: + pass + return ret + +def wait_for_port(port): + # TODO: do this without actually opening the port - maybe just look at /proc/qemu_process_id/fd? + s = socket.socket(socket.AF_INET) + while True: + try: + s.connect(('localhost', port)) + s.close() + break + except: + time.sleep(1) + pass + +################################################################################ + + + +def parseargs(): + # if provided with a name of the form image.qemu take that + # instead of --image <image> , --qemu <qemu> + # but still let --image and --qemu override it + image, qemu = None, None + name = sys.argv[0] + parts = name.split('.') + default_args = [] + if len(parts) == 1: + # this used to be a bunch of bash scripts until I found it prevented + # from ever quoting a space + image = os.path.basename(parts[0]) + if len(parts) == 2: + image, qemu = parts + image = os.path.basename(image) + if image: + if image in defaults: + default_args = defaults[image]['args'] + if image not in images: + print "missing image %r" % image + sys.exit(1) + image = images[image] + parser = argparse.ArgumentParser(description='Process some integers.') + parser.add_argument('--record-cmd', dest='record_cmd', help='record qxl command ring') + parser.add_argument('--copy-in', dest='copy_in', action='append') + parser.add_argument('--nobacking-file', default=True, action='store_false', dest='backing_file', help='use the image as a backing file for the actual image') + parser.add_argument('--startup', dest='startup') + parser.add_argument('--wintest', dest='wintest', choices=win_tests.keys()) + parser.add_argument('--cache', dest='cache', choices=['unsafe','off','writeback','writethrough'], default='unsafe') + parser.add_argument('--shutdown', dest='no_shutdown', action='store_false', default=True) + parser.add_argument('--time', dest='time', action='store_true', default=False) + parser.add_argument('--runonce', dest='runonce') + parser.add_argument('--clear-runonce', dest='clear_runonce', default=False, action='store_true') + parser.add_argument('--showcmdline', dest='showcmdline', default=False, action='store_true') + parser.add_argument('--vga', dest='vga', choices=['qxl', 'cirrus'], default='qxl') + parser.add_argument('--memcheck', dest='memcheck', default=False, action='store_true') + parser.add_argument('--oldclient', dest='oldclient', default=False, action='store_true') + parser.add_argument('--clients', dest='clients', default=0, type=int) + parser.add_argument('--port', dest='spice_port', type=int, action='store', default=6666) + parser.add_argument('--host', dest='spice_host', default='127.0.0.1') + parser.add_argument('--qxl', dest='qxl', type=int, default=1) + parser.add_argument('--tablet', dest='tablet', action='store_true', default=False) + parser.add_argument('--notablet', dest='tablet', action='store_false') + parser.add_argument('--xephyr', dest='xephyr', action='store_true', default=False) + parser.add_argument('--smb', dest='smb', default=None) + parser.add_argument('--cgdb', dest='cgdb', default=False, action='store_true') + parser.add_argument('--guestdebug', dest='guestdebug', type=int, default=0) + parser.add_argument('--qxldebug', dest='qxldebug', type=int, default=0) + parser.add_argument('--cmdlog', dest='cmdlog', type=int, default=0) + parser.add_argument('--windbg-server', dest='windbg_server', type=int, default=None) + parser.add_argument('--windbg-client', dest='windbg_client', type=int, default=None) + parser.add_argument('--memory', dest='memory', type=int, default=512) + parser.add_argument('--cpus', dest='cpus', type=int, default=2) + parser.add_argument('--nosmartcard', dest='smartcard', action='store_false', default=False) + parser.add_argument('--smartcard', dest='smartcard', action='store_true', default=False) + parser.add_argument('--smartcard-dbdir', dest='dbdir') + parser.add_argument('--smartcard-certs', dest='certs', action='append') + parser.add_argument('--debugbios', dest='debugbios', action='store_true', default=False) + parser.add_argument('--image', dest='image', default=image) + parser.add_argument('--cdrom', dest='cdrom', default=None) + parser.add_argument('--winqxl-cdrom', dest='winqxl_cdrom', default=False, action='store_true') + parser.add_argument('--qemu', dest='qemu', default=None, choices=qemus.keys() + [None]) + parser.add_argument('--incoming', dest='incoming', type=int, default=None) + parser.add_argument('--title', dest='title', default=None) + parser.add_argument('--second', dest='second', default=False, action='store_true') + parser.add_argument('--revision', dest='revision', default=None, type=int) + parser.add_argument('--freeze', dest='freeze', default=False, action='store_true') + parser.add_argument('--vncport', dest='vnc_port', type=int) + parser.add_argument('--vncclients', dest='vnc_clients', type=int, default=1) + parser.add_argument('--cpu', dest='cpu', choices=['host'], default='host', help='qemu cpu flag') + parser.add_argument('--keep-temp-backing-file', dest='erase_temp_backing_file', default=True, action='store_false') + # convenient to run tests via the same framework, though this is not using + # any of of the qemu flags, just the client running parts. + parser.add_argument('--test', dest='test', choices=['streaming', 'display', 'playback', 'replay']) + parser.add_argument('--replay-file', dest='replay_file') + args = parser.parse_args(default_args + sys.argv[1:]) + if len(parts) == 1 and not args.test and not args.image: + if image not in defaults: + print "symlink %r not in %r" % (image, defaults.keys()) + sys.exit(1) + if not args.qemu: + args.qemu = defaults[image]['qemu'] + if not args.qemu: + args.qemu = qemu_default + return args + +def set_runonce_registry(g, root, runonce_paths): + print "setting RunOnce to %r" % runonce_paths + systemroot = g.inspect_get_windows_systemroot(root) + path = "%s/system32/config/software" % systemroot # equivalent to HKLM\\Software + path = g.case_sensitive_path(path) + g.download (path, "/tmp/software") + h = hivex.Hivex("/tmp/software", write=True) + p = h.root() + for k in r'Microsoft\Windows\CurrentVersion\RunOnce'.split('\\'): + p = h.node_get_child(p, k) + # 1 - hive_t_REG_SZ - unknown + h.node_set_values(p, [{'key': 'Spice2RunOnce', 't': 1, 'value': runonce_path.encode('utf-16le')} for runonce_path in runonce_paths]) + h.commit(None) + g.upload("/tmp/software", path) + +def get_guestfs(image): + if not guestfs: + print "missing guestfs" + sys.exit(1) + g = guestfs.GuestFS() + g.add_drive_opts(image) + g.launch() + roots = g.inspect_os () + root = roots[0] + g.mount_options("", root, "/") + return g + +def set_runonce(image, program): + g = get_guestfs(image) + if program is None: + values = [] + else: + runonce_base = 'runonce.bat' + if os.path.exists(program): + runonce_base = os.path.basename(program) + g.upload(filename=program, remotefilename='/' + runonce_base) + else: + g.write('/' + runonce_base, program) + values = ['c:\\' + runonce_base] + set_runonce_registry(g, root, values) + g.sync() + g.umount_all() + del g + +def copy_file_in(g, image, path, dest): + if g == None: + g = get_guestfs(image) + if not os.path.exists(path): + print "%s does not exist" % path + sys.exit(1) + print "copying %r contents to c:\\" % (path) + g.upload(path, os.path.join(dest, os.path.basename(path))) + +def copy_dir_in(g, image, path): + if not os.path.isdir(path): + print "expected %r to be a path" % path + sys.exit(1) + if g == None: + g = get_guestfs(image) + print "copying %r contents to c:\\" % (path) + temp_name = shutil.make_archive('/tmp/spice2.copy_in', 'tar', path + '/') + dest = '/' + os.path.basename(path) + if not g.is_dir(dest): + print "mkdir %r in image" % dest + g.mkdir(dest) + g.tar_in(tarfile=temp_name, directory=dest) + os.unlink(temp_name) + return g + +startup = '/ProgramData/Microsoft/Windows/Start Menu/Programs/Startup' +def set_startup_from_file(g, image, path): + if not os.path.exists(path): + print "startup parameter is either a filename or a path" + print "copying file %s to Startup on %s" % (path, image) + filename = os.path.basename(path) + dest = os.path.join(startup, filename) + if g == None: + g = get_guestfs(image) + g.upload(filename=path, remotefilename=dest) + return g + +def set_startup_from_contents(g, image, filename, contents): + dest = os.path.join(startup, filename) + if g == None: + g = get_guestfs(image) + g.write(dest, contents) + return g + +################################################################################ +processes = [] +temp_files = [] + +def start_process(args, kill=False, **kw): + global processes + p = subprocess.Popen(args, **kw) + p.spice_kill = kill + processes.append(p) + return p + +def cleanup(): + for p in processes: + print "killing pid %s" % p.pid + try: + p.kill() + p.kill() # qemu started with --no-shutdown, needs two signals + p.wait() + except OSError, e: + pass + for m in temp_files: + if not os.path.exists(m): + continue + print "removing %s" % m + os.unlink(m) + os.system('reset -I') + +def if_processes_are_dead_then_exit(*args): + if all((p.poll() is not None or p.spice_kill) for p in processes): + cleanup() + sys.exit(0) + #print '|'.join(('%d: %s, %s' % (p.pid, p.poll(), p.spice_kill)) for p in processes) + +def ignore_ctrlc(): + signal.signal(signal.SIGINT, if_processes_are_dead_then_exit) + +################################################################################ +clients = [] +vnc_clients = [] + +def main(): + args = parseargs() + cmdline = build_cmdline(args) + atexit.register(cleanup) + if args.runonce: + set_runonce(args.image_fullpath, args.runonce) + elif args.clear_runonce: + set_runonce(args.image_fullpath, None) + g = None + if args.startup: + g = set_startup_from_file(g, args.image_fullpath, args.startup) + if args.wintest: + g = set_startup_from_contents(g, image=args.image_fullpath, filename='startup.bat', + contents=win_tests[args.wintest]['contents']) + # NOTE: can just use autoplay and a suitable cdrom iso for these, faster then guestfs by far. + for filename in win_tests[args.wintest].get('files', []): + g = copy_file_in(g, args.image_fullpath, filename, '/') + if args.copy_in: + for p in args.copy_in: + g = copy_dir_in(g, args.image_fullpath, p) + if g: + g.sync() + g.umount_all() + del g + set_title("%s%s" % ( + 'I ' if args.incoming else '', + args.title if args.title else os.path.basename(sys.argv[0]) + )) + print cmdline + if args.showcmdline: + return + ignore_ctrlc() + test_process = start_process(args=cmdline.split()) + def default_get_display(): + while True: + yield None + def xephyr_get_display(): + i = 2 + while True: + yield i + i += 1 + if args.xephyr: + display = xephyr_get_display() + else: + display = default_get_display() + if args.clients > 0: + print "starting clients" + cur_display = display.next() + if cur_display: + run_xephyr(display=cur_display) + wait_for_port(args.spice_port) + for i in xrange(args.clients): + client_process = run_client( + host=args.spice_host, port=args.spice_port, + oldclient=args.oldclient, smartcard=args.smartcard, + certs=args.certs, dbdir=args.dbdir, + display=cur_display) + clients.append(client_process) + print "waiting for test_process" + if args.vnc_port and args.vnc_clients > 0: + if not vncviewer: + print "vncviewer not in path - not starting" + else: + print "starting vnc clients" + wait_for_port(args.vnc_port) + for i in xrange(args.vnc_clients): + client_process = run_vnc_client(host=args.spice_host, port=args.vnc_port) + vnc_clients.append(client_process) + test_process.wait() + +if __name__ == '__main__': + main() |