diff options
author | Alon Levy <alevy@redhat.com> | 2011-09-21 18:58:58 +0300 |
---|---|---|
committer | Alon Levy <alevy@redhat.com> | 2011-09-21 18:58:58 +0300 |
commit | f2a2652e4c9499b67e6bc215f1bc626f3b2a2f16 (patch) | |
tree | 5c245cd781670d725bfc4f9f27e90030a083c70f | |
parent | 835e329a20166167b0c8d8764375b9edc7443130 (diff) |
qmp helpers: --print-events, --reset-on-shutdown
-rwxr-xr-x | qmp_helpers.py | 96 | ||||
-rwxr-xr-x | spice2 | 15 |
2 files changed, 110 insertions, 1 deletions
diff --git a/qmp_helpers.py b/qmp_helpers.py new file mode 100755 index 0000000..f68aabc --- /dev/null +++ b/qmp_helpers.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python +""" +Various helpers for spice2, they all get a qmp port and connect to it, +and do various helpful things. +""" + +import qmp +import os +import atexit +import time +import copy + +def kill_proc(pid): + os.kill(pid, 3) + time.sleep(0.01) + try: + os.kill(pid, 3) + print "sleeping 1 second before terminating %s" % pid + time.sleep(1) + os.kill(pid, 15) + except OSError, e: + # already dead + pass + +def fork_and_handle(qmp_address, handlers): + """ qemu doesn't like multiple clients to it's qmp handler, so just do with + one """ + print "connecting to %s" % repr(qmp_address) + pid = os.fork() + if pid != 0: + # parent + atexit.register(kill_proc, pid) + return pid + q = qmp.QEMUMonitorProtocol(qmp_address) + q.connect() + while True: + for e in q.get_events(): + for handler in handlers: + handler(q, e) + q.clear_events() + time.sleep(0.1) + +def reset_on_shutdown(): + """ + {u'seconds': 1316615017, u'microseconds': 145684}: "{u'event': u'SHUTDOWN'}" + {u'seconds': 1316615017, u'microseconds': 157869}: "{u'event': u'STOP'}" + """ + class ResetOnShutdownHandler(object): + def __init__(self): + self.next = self.wait_for_shutdown + + def handler(self, q, event): + self.next(q, event) + + def wait_for_shutdown(self, q, event): + if event['event'] == 'SHUTDOWN': + self.next = self.wait_for_stop + + def wait_for_stop(self, q, event): + if event['event'] == 'STOP': + print "RESET_ON_SHUTDOWN: resetting and continuing machine" + q.cmd('system_reset') + q.cmd('cont') + return ResetOnShutdownHandler().handler + +def print_events(): + def handler(q, orig_event, d={}): + # we will mangle the event, so make a copy of it + event = copy.deepcopy(orig_event) + timestamp_sec, timestamp_usec = event['timestamp']['seconds'], event['timestamp']['microseconds'] + if not 'base' in d: + d['base'] = (timestamp_sec, timestamp_usec) + event_type = event['event'] + del event['timestamp'] + del event['event'] + data = {} + if 'data' in event: + data = event['data'] + del event['data'] + print "%4d.%04d: %s%s" % (timestamp_sec - d['base'][0], timestamp_usec / 1000, event_type, + ' %r' % event if len(event) > 0 else '') + for k, v in data.items(): + print " %12s: %r" % (k, v) + return handler + +def test_print_events(qmp_address): + print_events(qmp_address) + try: + while True: + time.sleep(10) + except: + pass + +if __name__ == '__main__': + import sys + test_print_events(sys.argv[1]) @@ -12,6 +12,8 @@ import time import shutil import itertools +import qmp_helpers + try: import argparse except: @@ -753,7 +755,7 @@ def wait_for_port(port): ################################################################################ - +default_qmp_port = 20000 # TODO - port allocation (=PortPromisedRange(20000, 100)) def parseargs(): """ Parse command line. Some of the parameters are pre populated: @@ -1162,6 +1164,17 @@ def main(): os.setuid(args.uid) os.setgid(args.gid) test_process = start_process(args=cmdline, show_output=True) + # some qmp using apps require some forking + qmp_handlers = [] + if args.qmp_port: + wait_for_port(args.qmp_port) + qmp_address = ('localhost', args.qmp_port) + if args.print_events: + qmp_handlers.append(qmp_helpers.print_events()) + if args.reset_on_shutdown: + qmp_handlers.append(qmp_helpers.reset_on_shutdown()) + if len(qmp_handlers) > 0: + qmp_helpers.fork_and_handle(qmp_address, qmp_handlers) if args.xephyr: display = xephyr_get_display() else: |